forked from bartvdbraak/blender
b9ce231060
More information in this post: http://code.blender.org/ Thanks to all contributes for giving their permission!
287 lines
7.0 KiB
C++
287 lines
7.0 KiB
C++
/*
|
|
* Copyright 2011-2013 Blender Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License
|
|
*/
|
|
|
|
/* Parts adapted from code in the public domain in NVidia Mesh Tools. */
|
|
|
|
#include "mesh.h"
|
|
|
|
#include "subd_patch.h"
|
|
|
|
#include "util_math.h"
|
|
#include "util_types.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* De Casteljau Evaluation */
|
|
|
|
static float3 decasteljau_quadratic(float t, const float3 cp[3])
|
|
{
|
|
float3 d0 = cp[0] + t*(cp[1] - cp[0]);
|
|
float3 d1 = cp[1] + t*(cp[2] - cp[1]);
|
|
|
|
return d0 + t*(d1 - d0);
|
|
}
|
|
|
|
static void decasteljau_cubic(float3 *P, float3 *dt, float t, const float3 cp[4])
|
|
{
|
|
float3 d0 = cp[0] + t*(cp[1] - cp[0]);
|
|
float3 d1 = cp[1] + t*(cp[2] - cp[1]);
|
|
float3 d2 = cp[2] + t*(cp[3] - cp[2]);
|
|
|
|
d0 += t*(d1 - d0);
|
|
d1 += t*(d2 - d1);
|
|
|
|
*P = d0 + t*(d1 - d0);
|
|
if(dt) *dt = d1 - d0;
|
|
}
|
|
|
|
static void decasteljau_bicubic(float3 *P, float3 *du, float3 *dv, const float3 cp[16], float u, float v)
|
|
{
|
|
float3 ucp[4], utn[4];
|
|
|
|
/* interpolate over u */
|
|
decasteljau_cubic(ucp+0, utn+0, u, cp);
|
|
decasteljau_cubic(ucp+1, utn+1, u, cp+4);
|
|
decasteljau_cubic(ucp+2, utn+2, u, cp+8);
|
|
decasteljau_cubic(ucp+3, utn+3, u, cp+12);
|
|
|
|
/* interpolate over v */
|
|
decasteljau_cubic(P, dv, v, ucp);
|
|
if(du) decasteljau_cubic(du, NULL, v, utn);
|
|
}
|
|
|
|
static float3 decasteljau_tangent(const float3 cp[12], float u, float v)
|
|
{
|
|
float3 ucp[3];
|
|
|
|
decasteljau_cubic(ucp+0, NULL, v, cp);
|
|
decasteljau_cubic(ucp+1, NULL, v, cp+4);
|
|
decasteljau_cubic(ucp+2, NULL, v, cp+8);
|
|
|
|
return decasteljau_quadratic(u, ucp);
|
|
}
|
|
|
|
/* Linear Quad Patch */
|
|
|
|
void LinearQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
|
|
{
|
|
float3 d0 = interp(hull[0], hull[1], u);
|
|
float3 d1 = interp(hull[2], hull[3], u);
|
|
|
|
*P = interp(d0, d1, v);
|
|
|
|
if(dPdu && dPdv) {
|
|
*dPdu = interp(hull[1] - hull[0], hull[3] - hull[2], v);
|
|
*dPdv = interp(hull[2] - hull[0], hull[3] - hull[1], u);
|
|
}
|
|
}
|
|
|
|
BoundBox LinearQuadPatch::bound()
|
|
{
|
|
BoundBox bbox = BoundBox::empty;
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
bbox.grow(hull[i]);
|
|
|
|
return bbox;
|
|
}
|
|
|
|
/* Linear Triangle Patch */
|
|
|
|
void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
|
|
{
|
|
*P = u*hull[0] + v*hull[1] + (1.0f - u - v)*hull[2];
|
|
|
|
if(dPdu && dPdv) {
|
|
*dPdu = hull[0] - hull[2];
|
|
*dPdv = hull[1] - hull[2];
|
|
}
|
|
}
|
|
|
|
BoundBox LinearTrianglePatch::bound()
|
|
{
|
|
BoundBox bbox = BoundBox::empty;
|
|
|
|
for(int i = 0; i < 3; i++)
|
|
bbox.grow(hull[i]);
|
|
|
|
return bbox;
|
|
}
|
|
|
|
/* Bicubic Patch */
|
|
|
|
void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
|
|
{
|
|
decasteljau_bicubic(P, dPdu, dPdv, hull, u, v);
|
|
}
|
|
|
|
BoundBox BicubicPatch::bound()
|
|
{
|
|
BoundBox bbox = BoundBox::empty;
|
|
|
|
for(int i = 0; i < 16; i++)
|
|
bbox.grow(hull[i]);
|
|
|
|
return bbox;
|
|
}
|
|
|
|
/* Bicubic Patch with Tangent Fields */
|
|
|
|
void BicubicTangentPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
|
|
{
|
|
decasteljau_bicubic(P, NULL, NULL, hull, u, v);
|
|
|
|
if(dPdu) *dPdu = decasteljau_tangent(utan, u, v);
|
|
if(dPdv) *dPdv = decasteljau_tangent(vtan, v, u);
|
|
}
|
|
|
|
BoundBox BicubicTangentPatch::bound()
|
|
{
|
|
BoundBox bbox = BoundBox::empty;
|
|
|
|
for(int i = 0; i < 16; i++)
|
|
bbox.grow(hull[i]);
|
|
|
|
return bbox;
|
|
}
|
|
|
|
/* Gregory Patch */
|
|
|
|
static float no_zero_div(float f)
|
|
{
|
|
if(f == 0.0f) return 1.0f;
|
|
return f;
|
|
}
|
|
|
|
void GregoryQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
|
|
{
|
|
float3 bicubic[16];
|
|
|
|
float U = 1 - u;
|
|
float V = 1 - v;
|
|
|
|
/* 8 9 10 11
|
|
* 12 0\1 2/3 13
|
|
* 14 4/5 6\7 15
|
|
* 16 17 18 19
|
|
*/
|
|
|
|
bicubic[5] = (u*hull[1] + v*hull[0])/no_zero_div(u + v);
|
|
bicubic[6] = (U*hull[2] + v*hull[3])/no_zero_div(U + v);
|
|
bicubic[9] = (u*hull[5] + V*hull[4])/no_zero_div(u + V);
|
|
bicubic[10] = (U*hull[6] + V*hull[7])/no_zero_div(U + V);
|
|
|
|
// Map gregory control points to bezier control points.
|
|
bicubic[0] = hull[8];
|
|
bicubic[1] = hull[9];
|
|
bicubic[2] = hull[10];
|
|
bicubic[3] = hull[11];
|
|
bicubic[4] = hull[12];
|
|
bicubic[7] = hull[13];
|
|
bicubic[8] = hull[14];
|
|
bicubic[11] = hull[15];
|
|
bicubic[12] = hull[16];
|
|
bicubic[13] = hull[17];
|
|
bicubic[14] = hull[18];
|
|
bicubic[15] = hull[19];
|
|
|
|
decasteljau_bicubic(P, dPdu, dPdv, bicubic, u, v);
|
|
}
|
|
|
|
BoundBox GregoryQuadPatch::bound()
|
|
{
|
|
BoundBox bbox = BoundBox::empty;
|
|
|
|
for(int i = 0; i < 20; i++)
|
|
bbox.grow(hull[i]);
|
|
|
|
return bbox;
|
|
}
|
|
|
|
void GregoryTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
|
|
{
|
|
/* 6
|
|
*
|
|
* 14 0/1 7
|
|
*
|
|
* 13 5/4 3\2 8
|
|
*
|
|
* 12 11 10 9
|
|
*/
|
|
|
|
float w = 1 - u - v;
|
|
float uu = u * u;
|
|
float vv = v * v;
|
|
float ww = w * w;
|
|
float uuu = uu * u;
|
|
float vvv = vv * v;
|
|
float www = ww * w;
|
|
|
|
float U = 1 - u;
|
|
float V = 1 - v;
|
|
float W = 1 - w;
|
|
|
|
float3 C0 = ( v*U * hull[5] + u*V * hull[4] ) / no_zero_div(v*U + u*V);
|
|
float3 C1 = ( w*V * hull[3] + v*W * hull[2] ) / no_zero_div(w*V + v*W);
|
|
float3 C2 = ( u*W * hull[1] + w*U * hull[0] ) / no_zero_div(u*W + w*U);
|
|
|
|
*P =
|
|
(hull[12] * www + 3*hull[11] * ww*u + 3*hull[10] * w*uu + hull[ 9]*uuu) * (w + u) +
|
|
(hull[ 9] * uuu + 3*hull[ 8] * uu*v + 3*hull[ 7] * u*vv + hull[ 6]*vvv) * (u + v) +
|
|
(hull[ 6] * vvv + 3*hull[14] * vv*w + 3*hull[13] * v*ww + hull[12]*www) * (v + w) -
|
|
(hull[12] * www*w + hull[ 9] * uuu*u + hull[ 6] * vvv*v) +
|
|
12*(C0 * u*v*ww + C1 * uu*v*w + C2 * u*vv*w);
|
|
|
|
if(dPdu || dPdv) {
|
|
float3 E1 = (hull[12]*www + 3*hull[11]*ww*u + 3*hull[10]*w*uu + hull[ 9]*uuu);
|
|
float3 E2 = (hull[ 9]*uuu + 3*hull[ 8]*uu*v + 3*hull[ 7]*u*vv + hull[ 6]*vvv);
|
|
float3 E3 = (hull[ 6]*vvv + 3*hull[14]*vv*w + 3*hull[13]*v*ww + hull[12]*www);
|
|
|
|
if(dPdu) {
|
|
float3 E1u = 3*( - hull[12]*ww + hull[11]*(ww-2*u*w) + hull[10]*(2*u*w-uu) + hull[ 9]*uu);
|
|
float3 E2u = 3*( hull[ 9]*uu + 2*hull[ 8]*u*v + hull[ 7]*vv );
|
|
float3 E3u = 3*( - hull[14]*vv - 2*hull[13]*v*w - hull[12]*ww);
|
|
float3 Su = 4*( -hull[12]*www + hull[9]*uuu);
|
|
float3 Cu = 12*( C0*(ww*v-2*u*v*w) + C1*(2*u*v*w-uu*v) + C2*vv*(w-u) );
|
|
|
|
*dPdu = E1u*(w+u) + (E2+E2u*(u+v)) + (E3u*(v+w)-E3) - Su + Cu;
|
|
}
|
|
|
|
if(dPdv) {
|
|
float3 E1v = 3*(-hull[12]*ww - 2*hull[11]*w*u - hull[10]*uu );
|
|
float3 E2v = 3*( hull[ 8]*uu + 2*hull[ 7]*u*v + hull[ 6]*vv);
|
|
float3 E3v = 3*( hull[ 6]*vv + hull[14]*(2*w*v-vv) + hull[13]*(ww-2*w*v) - hull[12]*ww);
|
|
float3 Sv = 4*(-hull[12]*www + hull[ 6]*vvv);
|
|
float3 Cv = 12*(C0*(u*ww-2*u*v*w) + C1*uu*(w-v) + C2*(2*u*v*w-u*vv));
|
|
|
|
*dPdv = ((E1v*(w+u)-E1) + (E2+E2v*(u+v)) + E3v*(v+w) - Sv + Cv );
|
|
}
|
|
}
|
|
}
|
|
|
|
BoundBox GregoryTrianglePatch::bound()
|
|
{
|
|
BoundBox bbox = BoundBox::empty;
|
|
|
|
for(int i = 0; i < 20; i++)
|
|
bbox.grow(hull[i]);
|
|
|
|
return bbox;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|
|
|