forked from bartvdbraak/blender
7636aeffe1
* Add M_2PI_F and M_4PI_F constants and use them inside the codebase.
670 lines
18 KiB
C++
670 lines
18 KiB
C++
/*
|
|
* Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com>
|
|
*
|
|
* Modifications copyright (c) 2011, Blender Foundation. All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include "subd_build.h"
|
|
#include "subd_edge.h"
|
|
#include "subd_face.h"
|
|
#include "subd_ring.h"
|
|
#include "subd_mesh.h"
|
|
#include "subd_patch.h"
|
|
#include "subd_stencil.h"
|
|
#include "subd_vert.h"
|
|
|
|
#include "util_algorithm.h"
|
|
#include "util_debug.h"
|
|
#include "util_math.h"
|
|
#include "util_string.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* Subd Builder */
|
|
|
|
SubdBuilder *SubdBuilder::create(bool linear)
|
|
{
|
|
if(linear)
|
|
return new SubdLinearBuilder();
|
|
else
|
|
return new SubdAccBuilder();
|
|
}
|
|
|
|
/* Gregory ACC Stencil */
|
|
|
|
class GregoryAccStencil {
|
|
public:
|
|
SubdFaceRing *ring;
|
|
StencilMask stencil[20];
|
|
|
|
GregoryAccStencil(SubdFaceRing *ring_)
|
|
{
|
|
ring = ring_;
|
|
|
|
for(int i = 0; i < 20; i++)
|
|
stencil[i].resize(ring->num_verts());
|
|
}
|
|
|
|
StencilMask& get(int i)
|
|
{
|
|
assert(i < 20);
|
|
return stencil[i];
|
|
}
|
|
|
|
float& get(int i, SubdVert *vert)
|
|
{
|
|
assert(i < 20);
|
|
return stencil[i][ring->vert_index(vert)];
|
|
}
|
|
};
|
|
|
|
static float pseudoValence(SubdVert *vert)
|
|
{
|
|
float valence = (float)vert->valence();
|
|
|
|
if(vert->is_boundary()) {
|
|
/* we treat boundary verts as being half a closed mesh. corners are
|
|
* special case. n = 4 for corners and n = 2*(n-1) for boundaries. */
|
|
if(valence == 2) return 4;
|
|
return (valence - 1)*2;
|
|
}
|
|
|
|
return valence;
|
|
}
|
|
|
|
/* Subd ACC Builder */
|
|
|
|
SubdAccBuilder::SubdAccBuilder()
|
|
{
|
|
}
|
|
|
|
SubdAccBuilder::~SubdAccBuilder()
|
|
{
|
|
}
|
|
|
|
Patch *SubdAccBuilder::run(SubdFace *face)
|
|
{
|
|
SubdFaceRing ring(face, face->edge);
|
|
GregoryAccStencil stencil(&ring);
|
|
float3 position[20];
|
|
|
|
computeCornerStencil(&ring, &stencil);
|
|
computeEdgeStencil(&ring, &stencil);
|
|
computeInteriorStencil(&ring, &stencil);
|
|
|
|
ring.evaluate_stencils(position, stencil.stencil, 20);
|
|
|
|
if(face->num_edges() == 3) {
|
|
GregoryTrianglePatch *patch = new GregoryTrianglePatch();
|
|
memcpy(patch->hull, position, sizeof(float3)*20);
|
|
return patch;
|
|
}
|
|
else if(face->num_edges() == 4) {
|
|
GregoryQuadPatch *patch = new GregoryQuadPatch();
|
|
memcpy(patch->hull, position, sizeof(float3)*20);
|
|
return patch;
|
|
}
|
|
|
|
assert(0); /* n-gons should have been split already */
|
|
return NULL;
|
|
}
|
|
|
|
/* Gregory Patch */
|
|
|
|
void SubdAccBuilder::computeCornerStencil(SubdFaceRing *ring, GregoryAccStencil *stencil)
|
|
{
|
|
const int cornerIndices[7] = {8, 11, 19, 16, 6, 9, 12};
|
|
int primitiveOffset = ring->is_quad()? 0: 4;
|
|
|
|
SubdEdge *firstEdge = ring->firstEdge();
|
|
|
|
/* compute corner control points */
|
|
int v = 0;
|
|
|
|
for(SubdFace::EdgeIterator it(firstEdge); !it.isDone(); it.advance(), v++) {
|
|
SubdVert *vert = it.current()->from();
|
|
int valence = vert->valence();
|
|
int cid = cornerIndices[primitiveOffset+v];
|
|
|
|
if(vert->is_boundary()) {
|
|
/* compute vertex limit position */
|
|
SubdEdge *edge0 = vert->edge;
|
|
SubdEdge *edge1 = vert->edge->prev;
|
|
|
|
assert(edge0->face == NULL);
|
|
assert(edge0->to() != vert);
|
|
assert(edge1->face == NULL);
|
|
assert(edge1->from() != vert);
|
|
|
|
stencil->get(cid, vert) = 2.0f/3.0f;
|
|
stencil->get(cid, edge0->to()) = 1.0f/6.0f;
|
|
stencil->get(cid, edge1->from()) = 1.0f/6.0f;
|
|
|
|
assert(stencil->get(cid).is_normalized());
|
|
}
|
|
else {
|
|
stencil->get(cid, vert) = 3.0f*valence*valence;
|
|
|
|
for(SubdVert::EdgeIterator eit(vert->edge); !eit.isDone(); eit.advance()) {
|
|
SubdEdge *edge = eit.current();
|
|
assert(vert->co == edge->from()->co);
|
|
|
|
stencil->get(cid, edge->to()) = 12.0f;
|
|
|
|
if(SubdFaceRing::is_triangle(edge->face)) {
|
|
/* distribute weight to all verts */
|
|
stencil->get(cid, vert) += 1.0f;
|
|
stencil->get(cid, edge->to()) += 1.0f;
|
|
stencil->get(cid, edge->next->to()) += 1.0f;
|
|
}
|
|
else
|
|
stencil->get(cid, edge->next->to()) = 3.0f;
|
|
}
|
|
|
|
/* normalize stencil. */
|
|
stencil->get(cid).normalize();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SubdAccBuilder::computeEdgeStencil(SubdFaceRing *ring, GregoryAccStencil *stencil)
|
|
{
|
|
const int cornerIndices[7] = {8, 11, 19, 16, 6, 9, 12};
|
|
const int edge1Indices[7] = {9, 13, 18, 14, 7, 10, 13};
|
|
const int edge2Indices[7] = {12, 10, 15, 17, 14, 8, 11};
|
|
int primitiveOffset = ring->is_quad()? 0: 4;
|
|
|
|
float tangentScales[14] = {
|
|
0.0f, 0.0f, 0.0f, 0.667791f, 1.0f,
|
|
1.11268f, 1.1284f, 1.10289f, 1.06062f,
|
|
1.01262f, 0.963949f, 0.916926f, 0.872541f, 0.831134f
|
|
};
|
|
|
|
SubdEdge *firstEdge = ring->firstEdge();
|
|
|
|
/* compute corner / edge control points */
|
|
int v = 0;
|
|
|
|
for(SubdFace::EdgeIterator it(firstEdge); !it.isDone(); it.advance(), v++) {
|
|
SubdVert *vert = it.current()->from();
|
|
int valence = vert->valence();
|
|
int cid = cornerIndices[primitiveOffset+v];
|
|
|
|
int i1 = 0, i2 = 0, j = 0;
|
|
|
|
for(SubdVert::EdgeIterator eit(vert->edge); !eit.isDone(); eit.advance(), j++) {
|
|
SubdEdge *edge = eit.current();
|
|
|
|
/* find index of "our" edge for edge control points */
|
|
if(edge == it.current())
|
|
i1 = j;
|
|
if(edge == it.current()->prev->pair)
|
|
i2 = j;
|
|
}
|
|
|
|
if(vert->is_boundary()) {
|
|
int num_verts = ring->num_verts();
|
|
StencilMask r0(num_verts);
|
|
StencilMask r1(num_verts);
|
|
|
|
computeBoundaryTangentStencils(ring, vert, r0, r1);
|
|
|
|
int k = valence - 1;
|
|
float omega = M_PI_F / k;
|
|
|
|
int eid1 = edge1Indices[primitiveOffset + v];
|
|
int eid2 = edge2Indices[primitiveOffset + v];
|
|
|
|
if(it.current()->is_boundary()) {
|
|
assert(it.current()->from() == vert);
|
|
|
|
stencil->get(eid1, vert) = 2.0f / 3.0f;
|
|
stencil->get(eid1, it.current()->to()) = 1.0f / 3.0f;
|
|
|
|
assert(stencil->get(eid1).is_normalized());
|
|
|
|
if(valence == 2) {
|
|
for(int i = 0; i < num_verts; i++)
|
|
stencil->get(eid1)[i] += r0[i] * 0.0001f;
|
|
}
|
|
}
|
|
else {
|
|
stencil->get(eid1) = stencil->get(cid);
|
|
|
|
/* compute index of it.current() around vert */
|
|
int idx = 0;
|
|
|
|
for(SubdVert::EdgeIterator eit(vert->edges()); !eit.isDone(); eit.advance(), idx++)
|
|
if(eit.current() == it.current())
|
|
break;
|
|
|
|
assert(idx != valence);
|
|
|
|
float c = cosf(idx * omega);
|
|
float s = sinf(idx * omega);
|
|
|
|
for(int i = 0; i < num_verts; i++)
|
|
stencil->get(eid1)[i] += (r0[i] * s + r1[i] * c) / 3.0f;
|
|
}
|
|
|
|
if(it.current()->prev->is_boundary()) {
|
|
assert(it.current()->prev->pair->from() == vert);
|
|
|
|
stencil->get(eid2, vert) = 2.0f / 3.0f;
|
|
stencil->get(eid2, it.current()->prev->pair->to()) = 1.0f / 3.0f;
|
|
|
|
assert(stencil->get(eid2).is_normalized());
|
|
|
|
if(valence == 2) {
|
|
for(int i = 0; i < num_verts; i++)
|
|
stencil->get(eid2)[i] += r0[i] * 0.0001f;
|
|
}
|
|
}
|
|
else {
|
|
stencil->get(eid2) = stencil->get(cid);
|
|
|
|
/* compute index of it.current() around vert */
|
|
int idx = 0;
|
|
|
|
for(SubdVert::EdgeIterator eit(vert->edges()); !eit.isDone(); eit.advance(), idx++)
|
|
if(eit.current() == it.current()->prev->pair)
|
|
break;
|
|
|
|
assert(idx != valence);
|
|
|
|
float c = cosf(idx * omega);
|
|
float s = sinf(idx * omega);
|
|
|
|
for(int i = 0; i < num_verts; i++)
|
|
stencil->get(eid2)[i] += (r0[i] * s + r1[i] * c) / 3;
|
|
}
|
|
}
|
|
else {
|
|
float costerm = cosf(M_PI_F / valence);
|
|
float sqrtterm = sqrtf(4.0f + costerm*costerm);
|
|
|
|
/* float tangentScale = 1.0f; */
|
|
float tangentScale = tangentScales[min(valence, 13U)];
|
|
|
|
float alpha = (1.0f + costerm / sqrtterm) / (3.0f * valence) * tangentScale;
|
|
float beta = 1.0f / (3.0f * valence * sqrtterm) * tangentScale;
|
|
|
|
|
|
int eid1 = edge1Indices[primitiveOffset + v];
|
|
int eid2 = edge2Indices[primitiveOffset + v];
|
|
|
|
stencil->get(eid1) = stencil->get(cid);
|
|
stencil->get(eid2) = stencil->get(cid);
|
|
|
|
j = 0;
|
|
for(SubdVert::EdgeIterator eit(vert->edges()); !eit.isDone(); eit.advance(), j++) {
|
|
SubdEdge *edge = eit.current();
|
|
assert(vert->co == edge->from()->co);
|
|
|
|
float costerm1_a = cosf(M_PI_F * 2 * (j-i1) / valence);
|
|
float costerm1_b = cosf(M_PI_F * (2 * (j-i1)-1) / valence); /* -1 instead of +1 b/c of edge->next->to() */
|
|
|
|
float costerm2_a = cosf(M_PI_F * 2 * (j-i2) / valence);
|
|
float costerm2_b = cosf(M_PI_F * (2 * (j-i2)-1) / valence); /* -1 instead of +1 b/c of edge->next->to() */
|
|
|
|
|
|
stencil->get(eid1, edge->to()) += alpha * costerm1_a;
|
|
stencil->get(eid2, edge->to()) += alpha * costerm2_a;
|
|
|
|
if(SubdFaceRing::is_triangle(edge->face)) {
|
|
/* @@ this probably does not provide watertight results!! (1/3 + 1/3 + 1/3 != 1) */
|
|
|
|
/* distribute weight to all verts */
|
|
stencil->get(eid1, vert) += beta * costerm1_b / 3.0f;
|
|
stencil->get(eid1, edge->to()) += beta * costerm1_b / 3.0f;
|
|
stencil->get(eid1, edge->next->to()) += beta * costerm1_b / 3.0f;
|
|
|
|
stencil->get(eid2, vert) += beta * costerm2_b / 3.0f;
|
|
stencil->get(eid2, edge->to()) += beta * costerm2_b / 3.0f;
|
|
stencil->get(eid2, edge->next->to()) += beta * costerm2_b / 3.0f;
|
|
}
|
|
else {
|
|
stencil->get(eid1, edge->next->to()) += beta * costerm1_b;
|
|
stencil->get(eid2, edge->next->to()) += beta * costerm2_b;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SubdAccBuilder::computeInteriorStencil(SubdFaceRing *ring, GregoryAccStencil *stencil)
|
|
{
|
|
static int corner1Indices[7] = {8, 11, 19, 16, 6, 9, 12};
|
|
static int corner2Indices[7] = {11, 19, 16, 8, 9, 12, 6};
|
|
static int edge1Indices[7] = {9, 13, 18, 14, 7, 10, 13};
|
|
static int edge2Indices[7] = {10, 15, 17, 12, 8, 11, 14};
|
|
static int interior1Indices[7] = {1, 3, 6, 4, 1, 3, 5};
|
|
static int interior2Indices[7] = {2, 7, 5, 0, 2, 4, 0};
|
|
|
|
int primitiveOffset = ring->is_quad()? 0: 4;
|
|
|
|
SubdFace * face = ring->face();
|
|
SubdEdge *firstEdge = ring->firstEdge();
|
|
|
|
/* interior control points */
|
|
int v = 0;
|
|
for(SubdFace::EdgeIterator it(firstEdge); !it.isDone(); it.advance(), v++) {
|
|
SubdEdge *edge = it.current();
|
|
|
|
if(edge->is_boundary()) {
|
|
float valence1 = pseudoValence(edge->from());
|
|
float valence2 = pseudoValence(edge->to());
|
|
|
|
float weights1[4];
|
|
float weights2[4];
|
|
|
|
if(ring->is_quad()) {
|
|
weights1[0] = 3 * valence1;
|
|
weights1[1] = 6;
|
|
weights1[2] = 3;
|
|
weights1[3] = 6;
|
|
|
|
weights2[0] = 6;
|
|
weights2[1] = 3 * valence2;
|
|
weights2[2] = 6;
|
|
weights2[3] = 3;
|
|
}
|
|
else {
|
|
assert(ring->is_triangle());
|
|
weights1[0] = 3 * valence1 + 1;
|
|
weights1[1] = 7;
|
|
weights1[2] = 7;
|
|
|
|
weights2[0] = 7;
|
|
weights2[1] = 3 * valence2 + 1;
|
|
weights2[2] = 7;
|
|
}
|
|
|
|
int idx1 = interior1Indices[primitiveOffset+v];
|
|
int idx2 = interior2Indices[primitiveOffset+v];
|
|
|
|
int i = 0;
|
|
for(SubdFace::EdgeIterator it_sub(face->edges(edge)); !it_sub.isDone(); it_sub.advance(), i++) {
|
|
SubdVert *vert = it_sub.current()->from();
|
|
stencil->get(idx1, vert) += weights1[i];
|
|
stencil->get(idx2, vert) += weights2[i];
|
|
}
|
|
|
|
stencil->get(idx1).normalize();
|
|
stencil->get(idx2).normalize();
|
|
}
|
|
else {
|
|
SubdVert *e0 = edge->from();
|
|
float costerm0 = cosf(M_2PI_F / pseudoValence(e0));
|
|
|
|
SubdVert *f0 = edge->to();
|
|
float costerm1 = cosf(M_2PI_F / pseudoValence(f0));
|
|
|
|
/* p0 +------+ q0
|
|
* | |
|
|
* f0 +======+ e0 <=== current edge
|
|
* | |
|
|
* p1 +------+ q1
|
|
*/
|
|
|
|
SubdVert *q0 = edge->next->to();
|
|
SubdVert *p0 = edge->prev->from();
|
|
|
|
SubdVert *p1 = edge->pair->next->to();
|
|
SubdVert *q1 = edge->pair->prev->from();
|
|
|
|
|
|
StencilMask x(ring->num_verts());
|
|
StencilMask y(ring->num_verts());
|
|
|
|
for(int i = 0; i < ring->num_verts(); i++) {
|
|
x[i] =
|
|
(costerm1 * stencil->get(corner1Indices[primitiveOffset+v])[i] -
|
|
(2*costerm0 + costerm1) * stencil->get(edge1Indices[primitiveOffset+v])[i] +
|
|
2*costerm0 * stencil->get(edge2Indices[primitiveOffset+v])[i]) / 3.0f;
|
|
}
|
|
|
|
/* y = (2*( midedgeA1 - midedgeB1) + 4*(centroidA - centroidB))/18.0f; */
|
|
y[ring->vert_index(p0)] = 1;
|
|
y[ring->vert_index(p1)] = -1;
|
|
|
|
/* add centroidA */
|
|
if(ring->is_triangle()) {
|
|
y[ring->vert_index(p0)] += 4.0f / 3.0f;
|
|
y[ring->vert_index(e0)] += 4.0f / 3.0f;
|
|
y[ring->vert_index(f0)] += 4.0f / 3.0f;
|
|
}
|
|
else {
|
|
y[ring->vert_index(p0)] += 1;
|
|
y[ring->vert_index(q0)] += 1;
|
|
y[ring->vert_index(e0)] += 1;
|
|
y[ring->vert_index(f0)] += 1;
|
|
}
|
|
|
|
/* sub centroidB */
|
|
if(SubdFaceRing::is_triangle(edge->pair->face)) {
|
|
y[ring->vert_index(p1)] -= 4.0f / 3.0f;
|
|
y[ring->vert_index(e0)] -= 4.0f / 3.0f;
|
|
y[ring->vert_index(f0)] -= 4.0f / 3.0f;
|
|
|
|
}
|
|
else {
|
|
y[ring->vert_index(p1)] -= 1;
|
|
y[ring->vert_index(q1)] -= 1;
|
|
y[ring->vert_index(e0)] -= 1;
|
|
y[ring->vert_index(f0)] -= 1;
|
|
}
|
|
|
|
y /= 18.0f;
|
|
|
|
if(ring->is_triangle()) {
|
|
x *= 3.0f / 4.0f;
|
|
y *= 3.0f / 4.0f;
|
|
}
|
|
|
|
/* this change makes the triangle boundaries smoother, but distorts the quads next to them */
|
|
#if 0
|
|
if(ring->is_triangle() || SubdFaceRing::is_triangle(edge->pair->face)) {
|
|
y *= 4.0f / 3.0f;
|
|
}
|
|
#endif
|
|
|
|
stencil->get(interior1Indices[primitiveOffset+v]) = stencil->get(edge1Indices[primitiveOffset+v]);
|
|
stencil->get(interior1Indices[primitiveOffset+v]) += x;
|
|
stencil->get(interior1Indices[primitiveOffset+v]) += y;
|
|
|
|
for(int i = 0; i < ring->num_verts(); i++) {
|
|
x[i] =
|
|
(costerm0 * stencil->get(corner2Indices[primitiveOffset+v])[i] -
|
|
(2*costerm1 + costerm0) * stencil->get(edge2Indices[primitiveOffset+v])[i] +
|
|
2*costerm1 * stencil->get(edge1Indices[primitiveOffset+v])[i]) / 3.0f;
|
|
}
|
|
|
|
/* y = (2*( midedgeA2 - midedgeB2) + 4*(centroidA - centroidB))/18.0f; */
|
|
y = 0.0f;
|
|
|
|
/* (2*( midedgeA2 - midedgeB2) */
|
|
y[ring->vert_index(q0)] = 1;
|
|
y[ring->vert_index(q1)] = -1;
|
|
|
|
/* add centroidA */
|
|
if(ring->is_triangle()) {
|
|
y[ring->vert_index(p0)] += 4.0f / 3.0f;
|
|
y[ring->vert_index(e0)] += 4.0f / 3.0f;
|
|
y[ring->vert_index(f0)] += 4.0f / 3.0f;
|
|
}
|
|
else {
|
|
y[ring->vert_index(p0)] += 1;
|
|
y[ring->vert_index(q0)] += 1;
|
|
y[ring->vert_index(e0)] += 1;
|
|
y[ring->vert_index(f0)] += 1;
|
|
}
|
|
|
|
/* sub centroidB */
|
|
if(SubdFaceRing::is_triangle(edge->pair->face)) {
|
|
y[ring->vert_index(p1)] -= 4.0f / 3.0f;
|
|
y[ring->vert_index(e0)] -= 4.0f / 3.0f;
|
|
y[ring->vert_index(f0)] -= 4.0f / 3.0f;
|
|
|
|
}
|
|
else {
|
|
y[ring->vert_index(p1)] -= 1;
|
|
y[ring->vert_index(q1)] -= 1;
|
|
y[ring->vert_index(e0)] -= 1;
|
|
y[ring->vert_index(f0)] -= 1;
|
|
}
|
|
|
|
y /= 18.0f;
|
|
|
|
if(ring->is_triangle()) {
|
|
x *= 3.0f / 4.0f;
|
|
y *= 3.0f / 4.0f;
|
|
}
|
|
|
|
/* this change makes the triangle boundaries smoother, but distorts the quads next to them. */
|
|
#if 0
|
|
if(ring->is_triangle() || SubdFaceRing::is_triangle(edge->pair->face))
|
|
y *= 4.0f / 3.0f;
|
|
#endif
|
|
|
|
stencil->get(interior2Indices[primitiveOffset+v]) = stencil->get(edge2Indices[primitiveOffset+v]);
|
|
stencil->get(interior2Indices[primitiveOffset+v]) += x;
|
|
stencil->get(interior2Indices[primitiveOffset+v]) += y;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SubdAccBuilder::computeBoundaryTangentStencils(SubdFaceRing *ring, SubdVert *vert, StencilMask & r0, StencilMask & r1)
|
|
{
|
|
assert(vert->is_boundary());
|
|
assert(r0.size() == ring->num_verts());
|
|
assert(r1.size() == ring->num_verts());
|
|
|
|
SubdEdge *edge0 = vert->edge;
|
|
assert(edge0->face == NULL);
|
|
assert(edge0->to() != vert);
|
|
|
|
SubdEdge *edgek = vert->edge->prev;
|
|
assert(edgek->face == NULL);
|
|
assert(edgek->from() != vert);
|
|
|
|
int valence = vert->valence();
|
|
|
|
int k = valence - 1;
|
|
float omega = M_PI_F / k;
|
|
float s = sinf(omega);
|
|
float c = cosf(omega);
|
|
|
|
float factor = 1.0f / (3 * k + c);
|
|
|
|
float gamma = -4 * s * factor;
|
|
r0[ring->vert_index(vert)] = gamma;
|
|
/* r1[ring->vert_index(vert)] = 0; */
|
|
|
|
float salpha0 = -((1 + 2 * c) * sqrtf(1 + c)) * factor / sqrtf(1 - c);
|
|
float calpha0 = 1.0f / 2.0f;
|
|
|
|
r0[ring->vert_index(edge0->to())] = salpha0;
|
|
r1[ring->vert_index(edge0->to())] = calpha0;
|
|
|
|
float salphak = salpha0;
|
|
float calphak = -1.0f / 2.0f;
|
|
|
|
r0[ring->vert_index(edgek->from())] = salphak;
|
|
r1[ring->vert_index(edgek->from())] = calphak;
|
|
|
|
int j = 0;
|
|
for(SubdVert::EdgeIterator it(vert->edges()); !it.isDone(); it.advance(), j++) {
|
|
SubdEdge *edge = it.current();
|
|
|
|
if(j == k) break;
|
|
|
|
SubdVert *p = edge->to();
|
|
SubdVert *q = edge->pair->prev->from();
|
|
|
|
float alphaj = 4 * sinf(j * omega) * factor;
|
|
float betaj = (sinf(j * omega) + sinf((j + 1) * omega)) * factor;
|
|
|
|
if(j != 0)
|
|
r0[ring->vert_index(p)] += alphaj;
|
|
|
|
if(edge->pair->prev->prev->prev == edge->pair) {
|
|
r0[ring->vert_index(vert)] += betaj / 3.0f;
|
|
r0[ring->vert_index(edge->pair->from())] += betaj / 3.0f;
|
|
r0[ring->vert_index(q)] += betaj / 3.0f;
|
|
}
|
|
else
|
|
r0[ring->vert_index(q)] += betaj;
|
|
}
|
|
|
|
if(valence == 2) {
|
|
/* r0 perpendicular to r1 */
|
|
r0[ring->vert_index(vert)] = -4.0f / 3.0f;
|
|
r0[ring->vert_index(edgek->from())] = 1.0f / 2.0f;
|
|
r0[ring->vert_index(edge0->to())] = 1.0f / 2.0f;
|
|
r0[ring->vert_index(edge0->next->to())] = 1.0f / 3.0f;
|
|
}
|
|
}
|
|
|
|
/* Subd Linear Builder */
|
|
|
|
SubdLinearBuilder::SubdLinearBuilder()
|
|
{
|
|
}
|
|
|
|
SubdLinearBuilder::~SubdLinearBuilder()
|
|
{
|
|
}
|
|
|
|
Patch *SubdLinearBuilder::run(SubdFace *face)
|
|
{
|
|
Patch *patch;
|
|
float3 *hull;
|
|
|
|
if(face->num_edges() == 3) {
|
|
LinearTrianglePatch *lpatch = new LinearTrianglePatch();
|
|
hull = lpatch->hull;
|
|
patch = lpatch;
|
|
}
|
|
else if(face->num_edges() == 4) {
|
|
LinearQuadPatch *lpatch = new LinearQuadPatch();
|
|
hull = lpatch->hull;
|
|
patch = lpatch;
|
|
}
|
|
else {
|
|
assert(0); /* n-gons should have been split already */
|
|
return NULL;
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
for(SubdFace::EdgeIterator it(face->edge); !it.isDone(); it.advance())
|
|
hull[i++] = it.current()->from()->co;
|
|
|
|
if(face->num_edges() == 4)
|
|
swap(hull[2], hull[3]);
|
|
|
|
return patch;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|
|
|