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"
|
2025-03-10 13:17:37 +01:00
|
|
|
#include "subd/interpolation.h"
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "subd/patch.h"
|
2025-03-23 19:35:33 +01:00
|
|
|
#include "subd/split.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
#include "util/tbb.h"
|
2013-11-28 01:28:57 +01:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
CCL_NAMESPACE_BEGIN
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-10 13:17:37 +01:00
|
|
|
EdgeDice::EdgeDice(const SubdParams ¶ms_,
|
|
|
|
|
const int num_verts,
|
|
|
|
|
const int num_triangles,
|
|
|
|
|
SubdAttributeInterpolation &interpolation)
|
|
|
|
|
: params(params_), interpolation(interpolation)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2013-11-28 00:13:32 +01:00
|
|
|
Mesh *mesh = params.mesh;
|
|
|
|
|
|
2025-03-09 03:59:40 +01:00
|
|
|
mesh->num_subd_added_verts = num_verts - mesh->get_verts().size();
|
2025-03-23 19:35:33 +01:00
|
|
|
mesh->resize_mesh(num_verts, 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
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
mesh_triangles = mesh->triangles.data();
|
|
|
|
|
mesh_shader = mesh->shader.data();
|
|
|
|
|
mesh_smooth = mesh->smooth.data();
|
2025-03-09 03:07:29 +01:00
|
|
|
mesh_P = mesh->verts.data();
|
|
|
|
|
mesh_N = attr_vN->data_float3();
|
2019-08-14 01:53:09 -04:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
if (params.ptex) {
|
|
|
|
|
Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
|
|
|
|
|
Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV);
|
|
|
|
|
|
2025-03-09 03:07:29 +01:00
|
|
|
mesh_ptex_face_id = attr_ptex_face_id->data_float();
|
|
|
|
|
mesh_ptex_uv = attr_ptex_uv->data_float2();
|
|
|
|
|
}
|
2025-03-10 13:17:37 +01:00
|
|
|
|
|
|
|
|
interpolation.setup();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
float3 EdgeDice::eval_projected(const SubPatch &sub, const float2 uv)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
float3 P;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
sub.patch->eval(&P, nullptr, nullptr, nullptr, uv.x, uv.y);
|
|
|
|
|
if (params.camera) {
|
|
|
|
|
P = transform_perspective(¶ms.camera->worldtoraster, P);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return P;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float EdgeDice::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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float EdgeDice::scale_factor(const SubPatch &sub, const int Mu, const int Mv)
|
|
|
|
|
{
|
|
|
|
|
/* estimate area as 4x largest of 4 quads */
|
|
|
|
|
float3 P[3][3];
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
|
|
|
P[i][j] = eval_projected(sub, sub.map_uv(make_float2(i * 0.5f, j * 0.5f)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* solve for scaling factor */
|
|
|
|
|
const float Atri = params.dicing_rate * params.dicing_rate * 0.5f;
|
|
|
|
|
const float Ntris = Apatch / Atri;
|
|
|
|
|
|
|
|
|
|
// XXX does the -sqrt solution matter
|
|
|
|
|
// XXX max(D, 0.0) is highly suspicious, need to test cases
|
|
|
|
|
// where D goes negative
|
2025-05-15 00:40:42 +02:00
|
|
|
const float N = 0.5f * (Ntris - (sub.edges[0].edge->T + sub.edges[2].edge->T +
|
|
|
|
|
sub.edges[3].edge->T + sub.edges[1].edge->T));
|
2025-03-23 19:35:33 +01:00
|
|
|
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);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
return S;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EdgeDice::set_vertex(const SubPatch &sub, const int index, const float2 uv)
|
|
|
|
|
{
|
2019-08-14 01:53:09 -04:00
|
|
|
assert(index < params.mesh->verts.size());
|
2013-11-28 01:28:57 +01:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
float3 P;
|
|
|
|
|
float3 N;
|
|
|
|
|
|
|
|
|
|
sub.patch->eval(&P, nullptr, nullptr, &N, uv.x, uv.y);
|
|
|
|
|
|
2019-08-14 01:53:09 -04:00
|
|
|
mesh_P[index] = P;
|
|
|
|
|
mesh_N[index] = N;
|
2025-03-10 13:17:37 +01:00
|
|
|
|
|
|
|
|
for (const SubdAttribute &attr : interpolation.vertex_attributes) {
|
|
|
|
|
attr.interp(sub.patch->patch_index, sub.face_index, sub.corner, &index, &uv, 1);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-15 00:40:42 +02:00
|
|
|
void EdgeDice::set_triangle(const SubPatch &sub,
|
2025-03-23 19:35:33 +01:00
|
|
|
const int triangle_index,
|
2025-03-09 03:07:29 +01:00
|
|
|
const int v0,
|
|
|
|
|
const int v1,
|
|
|
|
|
const int v2,
|
|
|
|
|
const float2 uv0,
|
|
|
|
|
const float2 uv1,
|
|
|
|
|
const float2 uv2)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2025-03-23 19:35:33 +01:00
|
|
|
assert(triangle_index * 3 < params.mesh->triangles.size());
|
2016-05-29 11:16:27 +02:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
const Patch *patch = sub.patch;
|
2025-03-09 03:07:29 +01:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
mesh_triangles[triangle_index * 3 + 0] = v0;
|
|
|
|
|
mesh_triangles[triangle_index * 3 + 1] = v1;
|
|
|
|
|
mesh_triangles[triangle_index * 3 + 2] = v2;
|
|
|
|
|
mesh_shader[triangle_index] = patch->shader;
|
2025-04-17 17:59:54 +02:00
|
|
|
mesh_smooth[triangle_index] = patch->smooth;
|
2025-03-09 03:07:29 +01:00
|
|
|
|
|
|
|
|
if (mesh_ptex_face_id) {
|
2025-03-23 19:35:33 +01:00
|
|
|
mesh_ptex_face_id[triangle_index] = patch->patch_index;
|
2025-03-09 03:07:29 +01:00
|
|
|
}
|
|
|
|
|
if (mesh_ptex_uv) {
|
2025-03-23 19:35:33 +01:00
|
|
|
mesh_ptex_uv[triangle_index * 3 + 0] = uv0;
|
|
|
|
|
mesh_ptex_uv[triangle_index * 3 + 0] = uv1;
|
|
|
|
|
mesh_ptex_uv[triangle_index * 3 + 0] = uv2;
|
2025-03-09 03:07:29 +01:00
|
|
|
}
|
2025-03-10 13:17:37 +01:00
|
|
|
|
|
|
|
|
/* TODO: batch together multiple triangles. */
|
|
|
|
|
float2 uv[3] = {uv0, uv1, uv2};
|
|
|
|
|
for (const SubdAttribute &attr : interpolation.triangle_attributes) {
|
|
|
|
|
attr.interp(sub.patch->patch_index, sub.face_index, sub.corner, &triangle_index, uv, 1);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
void EdgeDice::add_grid_triangles_and_stitch(const SubPatch &sub, const int Mu, const int Mv)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2025-03-09 03:07:29 +01:00
|
|
|
const float du = 1.0f / (float)Mu;
|
|
|
|
|
const float dv = 1.0f / (float)Mv;
|
2025-03-23 19:35:33 +01:00
|
|
|
const int grid_vertex_offset = sub.inner_grid_vert_offset;
|
|
|
|
|
int triangle_index = sub.triangles_offset;
|
2025-03-09 03:07:29 +01:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
/* Create inner grid. */
|
|
|
|
|
for (int j = 1; j < Mv; j++) {
|
|
|
|
|
for (int i = 1; i < Mu; i++) {
|
|
|
|
|
const float u = i * du;
|
|
|
|
|
const float v = j * dv;
|
|
|
|
|
const int center_i = grid_vertex_offset + (i - 1) + (j - 1) * (Mu - 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
set_vertex(sub, center_i, sub.map_uv(make_float2(u, v)));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
if (i < Mu - 1 && j < Mv - 1) {
|
|
|
|
|
const int i1 = grid_vertex_offset + (i - 1) + (j - 1) * (Mu - 1);
|
|
|
|
|
const int i2 = grid_vertex_offset + i + (j - 1) * (Mu - 1);
|
|
|
|
|
const int i3 = grid_vertex_offset + i + j * (Mu - 1);
|
|
|
|
|
const int i4 = grid_vertex_offset + (i - 1) + j * (Mu - 1);
|
|
|
|
|
|
|
|
|
|
const float2 uv1 = sub.map_uv(make_float2(u, v));
|
|
|
|
|
const float2 uv2 = sub.map_uv(make_float2(u + du, v));
|
|
|
|
|
const float2 uv3 = sub.map_uv(make_float2(u + du, v + dv));
|
|
|
|
|
const float2 uv4 = sub.map_uv(make_float2(u, v + dv));
|
|
|
|
|
|
2025-05-15 00:40:42 +02:00
|
|
|
set_triangle(sub, triangle_index++, i1, i2, i3, uv1, uv2, uv3);
|
|
|
|
|
set_triangle(sub, triangle_index++, i1, i3, i4, uv1, uv3, uv4);
|
2025-03-23 19:35:33 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2025-03-23 19:35:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Stitch inner grid to edges. */
|
|
|
|
|
for (int edge = 0; edge < 4; edge++) {
|
|
|
|
|
const int outer_T = sub.edges[edge].edge->T;
|
|
|
|
|
const int inner_T = ((edge % 2) == 0) ? Mu - 2 : Mv - 2;
|
|
|
|
|
|
|
|
|
|
float2 inner_uv, outer_uv, inner_uv_step, outer_uv_step;
|
|
|
|
|
switch (edge) {
|
|
|
|
|
case 0:
|
|
|
|
|
inner_uv = make_float2(du, dv);
|
|
|
|
|
outer_uv = make_float2(0.0f, 0.0f);
|
|
|
|
|
inner_uv_step = make_float2(du, 0.0f);
|
|
|
|
|
outer_uv_step = make_float2(1.0f / (float)outer_T, 0.0f);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
inner_uv = make_float2(1.0f - du, dv);
|
|
|
|
|
outer_uv = make_float2(1.0f, 0.0f);
|
|
|
|
|
inner_uv_step = make_float2(0.0f, dv);
|
|
|
|
|
outer_uv_step = make_float2(0.0f, 1.0f / (float)outer_T);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
inner_uv = make_float2(1.0f - du, 1.0f - dv);
|
|
|
|
|
outer_uv = make_float2(1.0f, 1.0f);
|
|
|
|
|
inner_uv_step = make_float2(-du, 0.0f);
|
|
|
|
|
outer_uv_step = make_float2(-1.0f / (float)outer_T, 0.0f);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
default:
|
|
|
|
|
inner_uv = make_float2(du, 1.0f - dv);
|
|
|
|
|
outer_uv = make_float2(0.0f, 1.0f);
|
|
|
|
|
inner_uv_step = make_float2(0.0f, -dv);
|
|
|
|
|
outer_uv_step = make_float2(0.0f, -1.0f / (float)outer_T);
|
|
|
|
|
break;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
/* Stitch together two arrays of verts with triangles. At each step, 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. */
|
|
|
|
|
for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) {
|
|
|
|
|
const int v0 = sub.get_vert_along_grid_edge(edge, i);
|
|
|
|
|
const int v1 = sub.get_vert_along_edge(edge, j);
|
|
|
|
|
int v2;
|
|
|
|
|
|
|
|
|
|
const float2 uv0 = sub.map_uv(inner_uv);
|
|
|
|
|
const float2 uv1 = sub.map_uv(outer_uv);
|
|
|
|
|
float2 uv2;
|
|
|
|
|
|
|
|
|
|
if (j == outer_T) {
|
|
|
|
|
v2 = sub.get_vert_along_grid_edge(edge, ++i);
|
|
|
|
|
inner_uv += inner_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(inner_uv);
|
|
|
|
|
}
|
|
|
|
|
else if (i == inner_T) {
|
2019-08-14 01:53:09 -04:00
|
|
|
v2 = sub.get_vert_along_edge(edge, ++j);
|
2025-03-09 03:07:29 +01:00
|
|
|
outer_uv += outer_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(outer_uv);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2025-03-23 19:35:33 +01:00
|
|
|
/* Length of diagonals. */
|
|
|
|
|
const int v2_a = sub.get_vert_along_edge(edge, j + 1);
|
|
|
|
|
const int v2_b = sub.get_vert_along_grid_edge(edge, i + 1);
|
|
|
|
|
|
|
|
|
|
const float len_a = len_squared(mesh_P[v0] - mesh_P[v2_a]);
|
|
|
|
|
const float len_b = len_squared(mesh_P[v1] - mesh_P[v2_b]);
|
|
|
|
|
|
|
|
|
|
/* Use smallest diagonal. */
|
|
|
|
|
if (len_a < len_b) {
|
|
|
|
|
v2 = v2_a;
|
|
|
|
|
outer_uv += outer_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(outer_uv);
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v2 = v2_b;
|
|
|
|
|
inner_uv += inner_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(inner_uv);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-05-15 00:40:42 +02:00
|
|
|
set_triangle(sub, triangle_index++, v0, v1, v2, uv0, uv1, uv2);
|
2025-03-23 19:35:33 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
void EdgeDice::add_triangle_strip(const SubPatch &sub, const int left_edge, const int right_edge)
|
2025-03-08 14:34:03 +01:00
|
|
|
{
|
|
|
|
|
/* Stitch triangles from side to side, edge in the other direction has T = 1. */
|
|
|
|
|
const int left_T = sub.edges[left_edge].edge->T;
|
|
|
|
|
const int right_T = sub.edges[right_edge].edge->T;
|
|
|
|
|
|
|
|
|
|
float2 left_uv, right_uv, left_uv_step, right_uv_step;
|
|
|
|
|
if (right_edge == 0) {
|
|
|
|
|
left_uv = make_float2(0.0f, 1.0f);
|
|
|
|
|
right_uv = make_float2(0.0f, 0.0f);
|
|
|
|
|
left_uv_step = make_float2(1.0f / (float)left_T, 0.0f);
|
|
|
|
|
right_uv_step = make_float2(1.0f / (float)right_T, 0.0f);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
left_uv = make_float2(0.0f, 0.0f);
|
|
|
|
|
right_uv = make_float2(1.0f, 0.0f);
|
|
|
|
|
left_uv_step = make_float2(0.0f, 1.0f / (float)left_T);
|
|
|
|
|
right_uv_step = make_float2(0.0f, 1.0f / (float)right_T);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Stitch together two arrays of verts with triangles. at each step, 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. */
|
2025-03-23 19:35:33 +01:00
|
|
|
int triangle_index = sub.triangles_offset;
|
|
|
|
|
|
2025-03-08 14:34:03 +01:00
|
|
|
for (size_t i = 0, j = 0; i < left_T || j < right_T;) {
|
|
|
|
|
const int v0 = sub.get_vert_along_edge_reverse(left_edge, i);
|
|
|
|
|
const int v1 = sub.get_vert_along_edge(right_edge, j);
|
|
|
|
|
int v2;
|
|
|
|
|
|
|
|
|
|
const float2 uv0 = sub.map_uv(left_uv);
|
|
|
|
|
const float2 uv1 = sub.map_uv(right_uv);
|
|
|
|
|
float2 uv2;
|
|
|
|
|
|
|
|
|
|
if (j == right_T) {
|
|
|
|
|
v2 = sub.get_vert_along_edge_reverse(left_edge, ++i);
|
|
|
|
|
left_uv += left_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(left_uv);
|
|
|
|
|
}
|
|
|
|
|
else if (i == left_T) {
|
|
|
|
|
v2 = sub.get_vert_along_edge(right_edge, ++j);
|
|
|
|
|
right_uv += right_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(right_uv);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Length of diagonals. */
|
2025-03-23 19:35:33 +01:00
|
|
|
const int v2_a = sub.get_vert_along_edge(right_edge, j + 1);
|
|
|
|
|
const int v2_b = sub.get_vert_along_edge_reverse(left_edge, i + 1);
|
|
|
|
|
|
|
|
|
|
const float len_a = len_squared(mesh_P[v0] - mesh_P[v2_a]);
|
|
|
|
|
const float len_b = len_squared(mesh_P[v1] - mesh_P[v2_b]);
|
2025-03-08 14:34:03 +01:00
|
|
|
|
|
|
|
|
/* Use smallest diagonal. */
|
2025-03-23 19:35:33 +01:00
|
|
|
if (len_a < len_b) {
|
|
|
|
|
v2 = v2_a;
|
2025-03-08 14:34:03 +01:00
|
|
|
right_uv += right_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(right_uv);
|
2025-03-23 19:35:33 +01:00
|
|
|
j++;
|
2025-03-08 14:34:03 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2025-03-23 19:35:33 +01:00
|
|
|
v2 = v2_b;
|
2025-03-08 14:34:03 +01:00
|
|
|
left_uv += left_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(left_uv);
|
2025-03-23 19:35:33 +01:00
|
|
|
i++;
|
2025-03-08 14:34:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-15 00:40:42 +02:00
|
|
|
set_triangle(sub, triangle_index++, v0, v1, v2, uv0, uv1, uv2);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-15 17:18:50 +02:00
|
|
|
void EdgeDice::quad_set_sides(const SubPatch &sub)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2025-03-23 19:35:33 +01:00
|
|
|
for (int edge = 0; edge < 4; edge++) {
|
|
|
|
|
const int t = sub.edges[edge].edge->T;
|
|
|
|
|
const int i_start = (sub.edges[edge].own_vertex) ? 0 : 1;
|
|
|
|
|
const int i_end = (sub.edges[edge].own_edge) ? t : 1;
|
|
|
|
|
|
|
|
|
|
/* set verts on the edge of the patch */
|
|
|
|
|
for (int i = i_start; i < i_end; i++) {
|
|
|
|
|
const float f = i / (float)t;
|
|
|
|
|
|
|
|
|
|
float2 uv;
|
|
|
|
|
switch (edge) {
|
|
|
|
|
case 0:
|
|
|
|
|
uv = make_float2(f, 0.0f);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
uv = make_float2(1.0f, f);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
uv = make_float2(1.0f - f, 1.0f);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
default:
|
|
|
|
|
uv = make_float2(0.0f, 1.0f - f);
|
|
|
|
|
break;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2025-03-23 19:35:33 +01:00
|
|
|
|
|
|
|
|
const int vert_index = sub.get_vert_along_edge(edge, i);
|
|
|
|
|
set_vertex(sub, vert_index, sub.map_uv(uv));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-15 17:18:50 +02:00
|
|
|
void EdgeDice::quad_dice(const SubPatch &sub)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2025-03-08 14:34:03 +01:00
|
|
|
/* Compute inner grid size with scale factor. */
|
2025-05-15 00:40:42 +02:00
|
|
|
const int Mu = max(sub.edges[0].edge->T, sub.edges[2].edge->T);
|
|
|
|
|
const int Mv = max(sub.edges[3].edge->T, sub.edges[1].edge->T);
|
2025-03-08 14:34:03 +01:00
|
|
|
|
|
|
|
|
if (Mv == 1) {
|
|
|
|
|
/* No inner grid, stitch triangles from side to side. */
|
2025-03-23 19:35:33 +01:00
|
|
|
add_triangle_strip(sub, 2, 0);
|
2025-03-08 14:34:03 +01:00
|
|
|
}
|
|
|
|
|
else if (Mu == 1) {
|
|
|
|
|
/* No inner grid, stitch triangles from side to side. */
|
2025-03-23 19:35:33 +01:00
|
|
|
add_triangle_strip(sub, 3, 1);
|
2025-03-08 14:34:03 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2025-03-23 19:35:33 +01:00
|
|
|
#if 0
|
|
|
|
|
/* Doesn't work very well, especially at grazing angles. */
|
2025-03-08 14:34:03 +01:00
|
|
|
const float S = scale_factor(sub, ef, Mu, Mv);
|
|
|
|
|
const int grid_Mu = max((int)ceilf(S * Mu), 1); // XXX handle 0 & 1?
|
|
|
|
|
const int grid_Mv = max((int)ceilf(S * Mv), 1); // XXX handle 0 & 1?
|
2025-03-23 19:35:33 +01:00
|
|
|
add_grid_triangles_and_stitch(sub, grid_Mu, grid_Mv);
|
|
|
|
|
#else
|
|
|
|
|
add_grid_triangles_and_stitch(sub, Mu, Mv);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-04-15 17:18:50 +02:00
|
|
|
void EdgeDice::tri_set_sides(const SubPatch &sub)
|
|
|
|
|
{
|
|
|
|
|
for (int edge = 0; edge < 3; edge++) {
|
|
|
|
|
const int t = sub.edges[edge].edge->T;
|
|
|
|
|
const int i_start = (sub.edges[edge].own_vertex) ? 0 : 1;
|
|
|
|
|
const int i_end = (sub.edges[edge].own_edge) ? t : 1;
|
|
|
|
|
|
|
|
|
|
/* set verts on the edge of the patch */
|
|
|
|
|
for (int i = i_start; i < i_end; i++) {
|
|
|
|
|
const float f = i / (float)t;
|
|
|
|
|
|
|
|
|
|
float2 uv;
|
|
|
|
|
switch (edge) {
|
|
|
|
|
case 0:
|
|
|
|
|
uv = make_float2(f, 0.0f);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
uv = make_float2(1.0f - f, f);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
default:
|
|
|
|
|
uv = make_float2(0.0f, 1.0f - f);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int vert_index = sub.get_vert_along_edge(edge, i);
|
|
|
|
|
set_vertex(sub, vert_index, sub.map_uv(uv));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EdgeDice::tri_dice(const SubPatch &sub)
|
|
|
|
|
{
|
|
|
|
|
const int M = max(max(sub.edges[0].edge->T, sub.edges[1].edge->T), sub.edges[2].edge->T);
|
|
|
|
|
const float d = 1.0f / (float)(M + 1);
|
|
|
|
|
|
|
|
|
|
int triangle_index = sub.triangles_offset;
|
|
|
|
|
|
|
|
|
|
if (M == 1) {
|
|
|
|
|
/* Single triangle. */
|
|
|
|
|
set_triangle(sub,
|
|
|
|
|
triangle_index++,
|
|
|
|
|
sub.edges[0].start_vert_index(),
|
|
|
|
|
sub.edges[1].start_vert_index(),
|
|
|
|
|
sub.edges[2].start_vert_index(),
|
|
|
|
|
sub.map_uv(make_float2(0.0f, 0.0f)),
|
|
|
|
|
sub.map_uv(make_float2(1.0f, 0.0f)),
|
|
|
|
|
sub.map_uv(make_float2(0.0f, 1.0f)));
|
|
|
|
|
assert(triangle_index == sub.triangles_offset + sub.calc_num_triangles());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (M == 2) {
|
|
|
|
|
/* Edges have 2 segments or less. */
|
|
|
|
|
int num_split = 0;
|
|
|
|
|
int split_0 = -1;
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
if (sub.edges[i].edge->T == 2) {
|
|
|
|
|
num_split++;
|
|
|
|
|
if (split_0 == -1) {
|
|
|
|
|
split_0 = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* When two edges have 2 segments, we assume split_0 is the first of two consecutive edges. */
|
|
|
|
|
if (split_0 == 0 && sub.edges[2].edge->T == 2) {
|
|
|
|
|
split_0 = 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int split_1 = (split_0 + 1) % 3;
|
|
|
|
|
const int split_2 = (split_0 + 2) % 3;
|
|
|
|
|
|
|
|
|
|
const int v[3] = {sub.edges[0].start_vert_index(),
|
|
|
|
|
sub.edges[1].start_vert_index(),
|
|
|
|
|
sub.edges[2].start_vert_index()};
|
|
|
|
|
const int mid_v[3] = {sub.get_vert_along_edge(0, 1),
|
|
|
|
|
sub.get_vert_along_edge(1, 1),
|
|
|
|
|
sub.get_vert_along_edge(2, 1)};
|
|
|
|
|
const float2 uv[3] = {sub.map_uv(make_float2(0.0f, 0.0f)),
|
|
|
|
|
sub.map_uv(make_float2(1.0f, 0.0f)),
|
|
|
|
|
sub.map_uv(make_float2(0.0f, 1.0f))};
|
|
|
|
|
const float2 mid_uv[3] = {sub.map_uv(make_float2(0.5f, 0.0f)),
|
|
|
|
|
sub.map_uv(make_float2(0.5f, 0.5f)),
|
|
|
|
|
sub.map_uv(make_float2(0.0f, 0.5f))};
|
|
|
|
|
|
|
|
|
|
if (num_split == 3) {
|
|
|
|
|
/* All edges have two segments
|
|
|
|
|
* /\
|
|
|
|
|
* /--\
|
|
|
|
|
* / \/ \
|
|
|
|
|
* ------- */
|
|
|
|
|
set_triangle(sub, triangle_index++, v[0], mid_v[0], mid_v[2], uv[0], mid_uv[0], mid_uv[2]);
|
|
|
|
|
set_triangle(sub, triangle_index++, v[1], mid_v[1], mid_v[0], uv[1], mid_uv[1], mid_uv[0]);
|
|
|
|
|
set_triangle(sub, triangle_index++, v[2], mid_v[2], mid_v[1], uv[2], mid_uv[2], mid_uv[1]);
|
|
|
|
|
set_triangle(
|
|
|
|
|
sub, triangle_index++, mid_v[0], mid_v[1], mid_v[2], mid_uv[0], mid_uv[1], mid_uv[2]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* One edge has two segments.
|
|
|
|
|
* / \
|
|
|
|
|
* / | \
|
|
|
|
|
* / | \
|
|
|
|
|
* ------- */
|
|
|
|
|
set_triangle(sub,
|
|
|
|
|
triangle_index++,
|
|
|
|
|
v[split_0],
|
|
|
|
|
mid_v[split_0],
|
|
|
|
|
v[split_2],
|
|
|
|
|
uv[split_0],
|
|
|
|
|
mid_uv[split_0],
|
|
|
|
|
uv[split_2]);
|
|
|
|
|
if (num_split == 1) {
|
|
|
|
|
set_triangle(sub,
|
|
|
|
|
triangle_index++,
|
|
|
|
|
mid_v[split_0],
|
|
|
|
|
v[split_1],
|
|
|
|
|
v[split_2],
|
|
|
|
|
mid_uv[split_0],
|
|
|
|
|
uv[split_1],
|
|
|
|
|
uv[split_2]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Two edges have two segments.
|
|
|
|
|
* /|\
|
|
|
|
|
* / | \
|
|
|
|
|
* / |/ \
|
|
|
|
|
* ------- */
|
|
|
|
|
set_triangle(sub,
|
|
|
|
|
triangle_index++,
|
|
|
|
|
mid_v[split_0],
|
|
|
|
|
v[split_1],
|
|
|
|
|
mid_v[split_1],
|
|
|
|
|
mid_uv[split_0],
|
|
|
|
|
uv[split_1],
|
|
|
|
|
mid_uv[split_1]);
|
|
|
|
|
set_triangle(sub,
|
|
|
|
|
triangle_index++,
|
|
|
|
|
mid_v[split_0],
|
|
|
|
|
mid_v[split_1],
|
|
|
|
|
v[split_2],
|
|
|
|
|
mid_uv[split_0],
|
|
|
|
|
mid_uv[split_1],
|
|
|
|
|
uv[split_2]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(triangle_index == sub.triangles_offset + sub.calc_num_triangles());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int inner_M = M - 2;
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < inner_M; j++) {
|
|
|
|
|
for (int i = 0; i < j + 1; i++) {
|
|
|
|
|
const int i_next = i + 1;
|
|
|
|
|
const int j_next = j + 1;
|
|
|
|
|
|
|
|
|
|
const float2 inner_uv = make_float2(d, d);
|
|
|
|
|
|
|
|
|
|
const int v0 = sub.get_inner_grid_vert_triangle(i, j);
|
|
|
|
|
const int v1 = sub.get_inner_grid_vert_triangle(i_next, j_next);
|
|
|
|
|
const int v2 = sub.get_inner_grid_vert_triangle(i, j_next);
|
|
|
|
|
|
|
|
|
|
const float2 uv0 = sub.map_uv(inner_uv + make_float2(i, j - i) * d);
|
|
|
|
|
const float2 uv1 = sub.map_uv(inner_uv + make_float2(i_next, j - i) * d);
|
|
|
|
|
const float2 uv2 = sub.map_uv(inner_uv + make_float2(i, j_next - i) * d);
|
|
|
|
|
|
|
|
|
|
set_vertex(sub, v0, uv0);
|
|
|
|
|
if (j == inner_M - 1) {
|
|
|
|
|
set_vertex(sub, v1, uv1);
|
|
|
|
|
set_vertex(sub, v2, uv2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_triangle(sub, triangle_index++, v0, v1, v2, uv0, uv1, uv2);
|
|
|
|
|
|
|
|
|
|
if (i < j) {
|
|
|
|
|
const int v3 = sub.get_inner_grid_vert_triangle(i_next, j);
|
|
|
|
|
const float2 uv3 = sub.map_uv(inner_uv + make_float2(i_next, j - i_next) * d);
|
|
|
|
|
|
|
|
|
|
set_vertex(sub, v3, uv3);
|
|
|
|
|
|
|
|
|
|
set_triangle(sub, triangle_index++, v0, v3, v1, uv0, uv3, uv1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(triangle_index == sub.triangles_offset + inner_M * inner_M);
|
|
|
|
|
|
|
|
|
|
/* Stitch inner grid to edges. */
|
|
|
|
|
for (int edge = 0; edge < 3; edge++) {
|
|
|
|
|
const int outer_T = sub.edges[edge].edge->T;
|
|
|
|
|
const int inner_T = inner_M;
|
|
|
|
|
|
|
|
|
|
float2 inner_uv, outer_uv, inner_uv_step, outer_uv_step;
|
|
|
|
|
switch (edge) {
|
|
|
|
|
case 0:
|
|
|
|
|
inner_uv = make_float2(d, d);
|
|
|
|
|
outer_uv = make_float2(0.0f, 0.0f);
|
|
|
|
|
inner_uv_step = make_float2(d, 0.0f);
|
|
|
|
|
outer_uv_step = make_float2(1.0f / (float)outer_T, 0.0f);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
inner_uv = make_float2(1.0f - 2.0f * d, d);
|
|
|
|
|
outer_uv = make_float2(1.0f, 0.0f);
|
|
|
|
|
inner_uv_step = make_float2(-d, d);
|
|
|
|
|
outer_uv_step = make_float2(-1.0f / (float)outer_T, 1.0f / (float)outer_T);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
default:
|
|
|
|
|
inner_uv = make_float2(d, 1.0f - 2.0f * d);
|
|
|
|
|
outer_uv = make_float2(0.0f, 1.0f);
|
|
|
|
|
inner_uv_step = make_float2(0.0f, -d);
|
|
|
|
|
outer_uv_step = make_float2(0.0f, -1.0f / (float)outer_T);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Stitch together two arrays of verts with triangles. At each step, 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. */
|
|
|
|
|
for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) {
|
|
|
|
|
const int v0 = sub.get_vert_along_grid_edge(edge, i);
|
|
|
|
|
const int v1 = sub.get_vert_along_edge(edge, j);
|
|
|
|
|
int v2;
|
|
|
|
|
|
|
|
|
|
const float2 uv0 = sub.map_uv(inner_uv);
|
|
|
|
|
const float2 uv1 = sub.map_uv(outer_uv);
|
|
|
|
|
float2 uv2;
|
|
|
|
|
|
|
|
|
|
if (j == outer_T) {
|
|
|
|
|
v2 = sub.get_vert_along_grid_edge(edge, ++i);
|
|
|
|
|
inner_uv += inner_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(inner_uv);
|
|
|
|
|
}
|
|
|
|
|
else if (i == inner_T) {
|
|
|
|
|
v2 = sub.get_vert_along_edge(edge, ++j);
|
|
|
|
|
outer_uv += outer_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(outer_uv);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Length of diagonals. */
|
|
|
|
|
const int v2_a = sub.get_vert_along_edge(edge, j + 1);
|
|
|
|
|
const int v2_b = sub.get_vert_along_grid_edge(edge, i + 1);
|
|
|
|
|
|
|
|
|
|
const float len_a = len_squared(mesh_P[v0] - mesh_P[v2_a]);
|
|
|
|
|
const float len_b = len_squared(mesh_P[v1] - mesh_P[v2_b]);
|
|
|
|
|
|
|
|
|
|
/* Use smallest diagonal. */
|
|
|
|
|
if (len_a < len_b) {
|
|
|
|
|
v2 = v2_a;
|
|
|
|
|
outer_uv += outer_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(outer_uv);
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v2 = v2_b;
|
|
|
|
|
inner_uv += inner_uv_step;
|
|
|
|
|
uv2 = sub.map_uv(inner_uv);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_triangle(sub, triangle_index++, v0, v1, v2, uv0, uv1, uv2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(triangle_index == sub.triangles_offset + sub.calc_num_triangles());
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-23 19:35:33 +01:00
|
|
|
void EdgeDice::dice(const DiagSplit &split)
|
|
|
|
|
{
|
|
|
|
|
const size_t num_subpatches = split.get_num_subpatches();
|
2025-03-10 13:17:37 +01:00
|
|
|
|
|
|
|
|
/* Vertex coordinates for sides. Needs to be done first because tessellation depends
|
|
|
|
|
* on these coordinates and they are unique assigned to a subpatch for determinism. */
|
|
|
|
|
parallel_for(blocked_range<size_t>(0, num_subpatches, 8), [&](const blocked_range<size_t> &r) {
|
|
|
|
|
for (size_t i = r.begin(); i != r.end(); i++) {
|
2025-04-15 17:18:50 +02:00
|
|
|
const SubPatch &subpatch = split.get_subpatch(i);
|
|
|
|
|
if (subpatch.shape == SubPatch::TRIANGLE) {
|
|
|
|
|
tri_set_sides(subpatch);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
quad_set_sides(subpatch);
|
|
|
|
|
}
|
2025-03-10 13:17:37 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* Inner vertex coordinates and triangles. */
|
|
|
|
|
parallel_for(blocked_range<size_t>(0, num_subpatches, 8), [&](const blocked_range<size_t> &r) {
|
|
|
|
|
for (size_t i = r.begin(); i != r.end(); i++) {
|
2025-04-15 17:18:50 +02:00
|
|
|
const SubPatch &subpatch = split.get_subpatch(i);
|
|
|
|
|
if (subpatch.shape == SubPatch::TRIANGLE) {
|
|
|
|
|
tri_dice(subpatch);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
quad_dice(subpatch);
|
|
|
|
|
}
|
2025-03-10 13:17:37 +01:00
|
|
|
}
|
|
|
|
|
});
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_END
|