2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/camera.h"
|
|
|
|
|
#include "scene/mesh.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "subd/dice.h"
|
|
|
|
|
#include "subd/patch.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
/* EdgeDice Base */
|
|
|
|
|
|
2013-11-28 00:13:32 +01:00
|
|
|
EdgeDice::EdgeDice(const SubdParams ¶ms_) : params(params_)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-26 17:53:55 +01:00
|
|
|
mesh_P = nullptr;
|
|
|
|
|
mesh_N = nullptr;
|
2011-04-27 11:58:34 +00:00
|
|
|
vert_offset = 0;
|
|
|
|
|
|
2013-11-28 00:13:32 +01:00
|
|
|
params.mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
|
2013-11-28 01:28:57 +01:00
|
|
|
|
|
|
|
|
if (params.ptex) {
|
|
|
|
|
params.mesh->attributes.add(ATTR_STD_PTEX_UV);
|
|
|
|
|
params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void EdgeDice::reserve(const int num_verts, const int num_triangles)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2013-11-28 00:13:32 +01:00
|
|
|
Mesh *mesh = params.mesh;
|
|
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
vert_offset = mesh->get_verts().size();
|
2016-06-02 20:57:04 -04:00
|
|
|
tri_offset = mesh->num_triangles();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
mesh->resize_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles());
|
|
|
|
|
mesh->reserve_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles() + num_triangles);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
mesh_P = mesh->verts.data() + vert_offset;
|
|
|
|
|
mesh_N = attr_vN->data_float3() + vert_offset;
|
|
|
|
|
|
|
|
|
|
params.mesh->num_subd_verts += num_verts;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void EdgeDice::set_vert(Patch *patch, const int index, const float2 uv)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
float3 P;
|
|
|
|
|
float3 N;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-12-26 17:53:55 +01:00
|
|
|
patch->eval(&P, nullptr, nullptr, &N, uv.x, uv.y);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
assert(index < params.mesh->verts.size());
|
2013-11-28 01:28:57 +01:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
mesh_P[index] = P;
|
|
|
|
|
mesh_N[index] = N;
|
|
|
|
|
params.mesh->vert_patch_uv[index + vert_offset] = make_float2(uv.x, uv.y);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void EdgeDice::add_triangle(Patch *patch, const int v0, const int v1, const int v2)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-29 11:16:27 +02:00
|
|
|
Mesh *mesh = params.mesh;
|
|
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
mesh->add_triangle(v0 + vert_offset, v1 + vert_offset, v2 + vert_offset, patch->shader, true);
|
2016-07-16 19:42:28 -04:00
|
|
|
params.mesh->triangle_patch[params.mesh->num_triangles() - 1] = patch->patch_index;
|
2013-11-28 01:28:57 +01:00
|
|
|
|
2013-11-28 00:13:32 +01:00
|
|
|
tri_offset++;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void EdgeDice::stitch_triangles(Subpatch &sub, const int edge)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-08-14 01:53:09 -04:00
|
|
|
int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
|
|
|
|
|
int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
|
|
|
|
|
Mu = max(Mu, 2);
|
|
|
|
|
Mv = max(Mv, 2);
|
|
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const int outer_T = sub.edges[edge].T;
|
|
|
|
|
const int inner_T = ((edge % 2) == 0) ? Mv - 2 : Mu - 2;
|
2019-08-14 01:53:09 -04:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (inner_T < 0 || outer_T < 0) {
|
2011-04-27 11:58:34 +00:00
|
|
|
return; // XXX avoid crashes for Mu or Mv == 1, missing polygons
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* stitch together two arrays of verts with triangles. at each step,
|
2012-06-09 17:22:52 +00:00
|
|
|
* we compare using the next verts on both sides, to find the split
|
|
|
|
|
* direction with the smallest diagonal, and use that in order to keep
|
|
|
|
|
* the triangle shape reasonable. */
|
2019-08-14 01:53:09 -04:00
|
|
|
for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) {
|
2024-12-29 17:32:00 +01:00
|
|
|
int v0;
|
|
|
|
|
int v1;
|
|
|
|
|
int v2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
v0 = sub.get_vert_along_grid_edge(edge, i);
|
|
|
|
|
v1 = sub.get_vert_along_edge(edge, j);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
if (j == outer_T) {
|
|
|
|
|
v2 = sub.get_vert_along_grid_edge(edge, ++i);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-08-14 01:53:09 -04:00
|
|
|
else if (i == inner_T) {
|
|
|
|
|
v2 = sub.get_vert_along_edge(edge, ++j);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* length of diagonals */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float len1 = len_squared(mesh_P[sub.get_vert_along_grid_edge(edge, i)] -
|
|
|
|
|
mesh_P[sub.get_vert_along_edge(edge, j + 1)]);
|
|
|
|
|
const float len2 = len_squared(mesh_P[sub.get_vert_along_edge(edge, j)] -
|
|
|
|
|
mesh_P[sub.get_vert_along_grid_edge(edge, i + 1)]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* use smallest diagonal */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (len1 < len2) {
|
2019-08-14 01:53:09 -04:00
|
|
|
v2 = sub.get_vert_along_edge(edge, ++j);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2019-08-14 01:53:09 -04:00
|
|
|
v2 = sub.get_vert_along_grid_edge(edge, ++i);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
add_triangle(sub.patch, v1, v0, v2);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* QuadDice */
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
QuadDice::QuadDice(const SubdParams ¶ms_) : EdgeDice(params_) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
float2 QuadDice::map_uv(Subpatch &sub, const float u, float v)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* map UV from subpatch to patch parametric coordinates */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float2 d0 = interp(sub.c00, sub.c01, v);
|
|
|
|
|
const float2 d1 = interp(sub.c10, sub.c11, v);
|
2011-04-27 11:58:34 +00:00
|
|
|
return interp(d0, d1, u);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
float3 QuadDice::eval_projected(Subpatch &sub, const float u, float v)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const float2 uv = map_uv(sub, u, v);
|
2011-04-27 11:58:34 +00:00
|
|
|
float3 P;
|
|
|
|
|
|
2024-12-26 17:53:55 +01:00
|
|
|
sub.patch->eval(&P, nullptr, nullptr, nullptr, uv.x, uv.y);
|
2023-09-17 09:01:48 +10:00
|
|
|
if (params.camera) {
|
2013-11-28 00:13:32 +01:00
|
|
|
P = transform_perspective(¶ms.camera->worldtoraster, P);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
return P;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void QuadDice::set_vert(Subpatch &sub, const int index, const float u, float v)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-08-14 01:53:09 -04:00
|
|
|
EdgeDice::set_vert(sub.patch, index, map_uv(sub, u, v));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void QuadDice::set_side(Subpatch &sub, const int edge)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const int t = sub.edges[edge].T;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
/* set verts on the edge of the patch */
|
2019-08-14 01:53:09 -04:00
|
|
|
for (int i = 0; i < t; i++) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const float f = i / (float)t;
|
2019-08-14 01:53:09 -04:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
float u;
|
|
|
|
|
float v;
|
2019-08-14 01:53:09 -04:00
|
|
|
switch (edge) {
|
|
|
|
|
case 0:
|
|
|
|
|
u = 0;
|
|
|
|
|
v = f;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
u = f;
|
|
|
|
|
v = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
u = 1;
|
|
|
|
|
v = 1.0f - f;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
2019-09-13 16:18:18 +02:00
|
|
|
default:
|
2019-08-14 01:53:09 -04:00
|
|
|
u = 1.0f - f;
|
|
|
|
|
v = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
set_vert(sub, sub.get_vert_along_edge(edge, i), u, v);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float QuadDice::quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d)
|
|
|
|
|
{
|
|
|
|
|
return triangle_area(a, b, d) + triangle_area(a, d, c);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
float QuadDice::scale_factor(Subpatch &sub, const int Mu, const int Mv)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* estimate area as 4x largest of 4 quads */
|
|
|
|
|
float3 P[3][3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
for (int j = 0; j < 3; j++) {
|
2011-04-27 11:58:34 +00:00
|
|
|
P[i][j] = eval_projected(sub, i * 0.5f, j * 0.5f);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const float A1 = quad_area(P[0][0], P[1][0], P[0][1], P[1][1]);
|
|
|
|
|
const float A2 = quad_area(P[1][0], P[2][0], P[1][1], P[2][1]);
|
|
|
|
|
const float A3 = quad_area(P[0][1], P[1][1], P[0][2], P[1][2]);
|
|
|
|
|
const float A4 = quad_area(P[1][1], P[2][1], P[1][2], P[2][2]);
|
|
|
|
|
const float Apatch = max(A1, max(A2, max(A3, A4))) * 4.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* solve for scaling factor */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float Atri = params.dicing_rate * params.dicing_rate * 0.5f;
|
|
|
|
|
const float Ntris = Apatch / Atri;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
// XXX does the -sqrt solution matter
|
|
|
|
|
// XXX max(D, 0.0) is highly suspicious, need to test cases
|
|
|
|
|
// where D goes negative
|
2024-12-29 17:32:00 +01:00
|
|
|
const float N = 0.5f * (Ntris - (sub.edge_u0.T + sub.edge_u1.T + sub.edge_v0.T + sub.edge_v1.T));
|
|
|
|
|
const float D = 4.0f * N * Mu * Mv + (Mu + Mv) * (Mu + Mv);
|
|
|
|
|
const float S = (Mu + Mv + sqrtf(max(D, 0.0f))) / (2 * Mu * Mv);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
return S;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void QuadDice::add_grid(Subpatch &sub, const int Mu, const int Mv, const int offset)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* create inner grid */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float du = 1.0f / (float)Mu;
|
|
|
|
|
const float dv = 1.0f / (float)Mv;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
for (int j = 1; j < Mv; j++) {
|
|
|
|
|
for (int i = 1; i < Mu; i++) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const float u = i * du;
|
|
|
|
|
const float v = j * dv;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
set_vert(sub, offset + (i - 1) + (j - 1) * (Mu - 1), u, v);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (i < Mu - 1 && j < Mv - 1) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const int i1 = offset + (i - 1) + (j - 1) * (Mu - 1);
|
|
|
|
|
const int i2 = offset + i + (j - 1) * (Mu - 1);
|
|
|
|
|
const int i3 = offset + i + j * (Mu - 1);
|
|
|
|
|
const int i4 = offset + (i - 1) + j * (Mu - 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-28 00:13:32 +01:00
|
|
|
add_triangle(sub.patch, i1, i2, i3);
|
|
|
|
|
add_triangle(sub.patch, i1, i3, i4);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
void QuadDice::dice(Subpatch &sub)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* compute inner grid size with scale factor */
|
2019-08-14 01:53:09 -04:00
|
|
|
int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
|
|
|
|
|
int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-06-12 09:04:10 +10:00
|
|
|
#if 0 /* Doesn't work very well, especially at grazing angles. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float S = scale_factor(sub, ef, Mu, Mv);
|
2016-04-11 22:49:09 +02:00
|
|
|
#else
|
2024-12-29 17:32:00 +01:00
|
|
|
const float S = 1.0f;
|
2016-04-11 22:49:09 +02:00
|
|
|
#endif
|
|
|
|
|
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1?
|
|
|
|
|
Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1?
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
/* inner grid */
|
|
|
|
|
add_grid(sub, Mu, Mv, sub.inner_grid_vert_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
/* sides */
|
|
|
|
|
set_side(sub, 0);
|
|
|
|
|
set_side(sub, 1);
|
|
|
|
|
set_side(sub, 2);
|
|
|
|
|
set_side(sub, 3);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
stitch_triangles(sub, 0);
|
|
|
|
|
stitch_triangles(sub, 1);
|
|
|
|
|
stitch_triangles(sub, 2);
|
|
|
|
|
stitch_triangles(sub, 3);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_END
|