1 //
2 // Copyright 2014 DreamWorks Animation LLC.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "../sdc/crease.h"
25
26 namespace OpenSubdiv {
27 namespace OPENSUBDIV_VERSION {
28
29 namespace Sdc {
30
31 //
32 // Declarations of creasing constants and non-inline methods:
33 //
34 float const Crease::SHARPNESS_SMOOTH = 0.0f;
35 float const Crease::SHARPNESS_INFINITE = 10.0f;
36
37
38 //
39 // Creasing queries dependent on sharpness values:
40 //
41 Crease::Rule
DetermineVertexVertexRule(float vertexSharpness,int sharpEdgeCount) const42 Crease::DetermineVertexVertexRule(float vertexSharpness, int sharpEdgeCount) const {
43
44 if (IsSharp(vertexSharpness)) return Crease::RULE_CORNER;
45
46 return (sharpEdgeCount > 2) ? Crease::RULE_CORNER : (Crease::Rule)(1 << sharpEdgeCount);
47 }
48
49 Crease::Rule
DetermineVertexVertexRule(float vertexSharpness,int incidentEdgeCount,float const * incidentEdgeSharpness) const50 Crease::DetermineVertexVertexRule(float vertexSharpness,
51 int incidentEdgeCount,
52 float const* incidentEdgeSharpness) const {
53
54 if (IsSharp(vertexSharpness)) return Crease::RULE_CORNER;
55
56 int sharpEdgeCount = 0;
57 for (int i = 0; i < incidentEdgeCount; ++i) {
58 sharpEdgeCount += IsSharp(incidentEdgeSharpness[i]);
59 }
60 return (sharpEdgeCount > 2) ? Crease::RULE_CORNER : (Crease::Rule)(1 << sharpEdgeCount);
61 }
62
63 float
ComputeFractionalWeightAtVertex(float parentVertexSharpness,float childVertexSharpness,int incidentEdgeCount,float const * parentSharpness,float const * childSharpness) const64 Crease::ComputeFractionalWeightAtVertex(float parentVertexSharpness,
65 float childVertexSharpness,
66 int incidentEdgeCount,
67 float const* parentSharpness,
68 float const* childSharpness) const {
69
70 int transitionCount = 0;
71 float transitionSum = 0.0f;
72
73 if (IsSharp(parentVertexSharpness) && IsSmooth(childVertexSharpness)) {
74 transitionCount = 1;
75 transitionSum = parentVertexSharpness;
76 }
77
78 //
79 // We need the child-edge sharpness values for non-simple methods to ensure
80 // that the sharpness went from a non-zero value (potentially greater than
81 // 1.0) to zero...
82 //
83 if (IsUniform() || (childSharpness == 0)) {
84 for (int i = 0; i < incidentEdgeCount; ++i) {
85 if (IsSharp(parentSharpness[i]) && (parentSharpness[i] <= 1.0f)) {
86 transitionSum += parentSharpness[i];
87 transitionCount ++;
88 }
89 }
90 } else {
91 for (int i = 0; i < incidentEdgeCount; ++i) {
92 if (IsSharp(parentSharpness[i]) && IsSmooth(childSharpness[i])) {
93 transitionSum += parentSharpness[i];
94 transitionCount ++;
95 }
96 }
97 }
98 if (transitionCount == 0) return 0.0f;
99 float fractionalWeight = transitionSum / (float)transitionCount;
100 return (fractionalWeight > 1.0f) ? 1.0f : fractionalWeight;
101 }
102
103 //
104 // Subdividing edge sharpness values (vertex sharpness is inline):
105 //
106 float
SubdivideEdgeSharpnessAtVertex(float edgeSharpness,int incEdgeCountAtVertex,float const * incEdgeSharpness) const107 Crease::SubdivideEdgeSharpnessAtVertex(float edgeSharpness,
108 int incEdgeCountAtVertex,
109 float const * incEdgeSharpness) const {
110
111 if (IsUniform() || (incEdgeCountAtVertex < 2)) {
112 return decrementSharpness(edgeSharpness);
113 }
114
115 if (IsSmooth(edgeSharpness)) return Crease::SHARPNESS_SMOOTH;
116 if (IsInfinite(edgeSharpness)) return Crease::SHARPNESS_INFINITE;
117
118 float sharpSum = 0.0f;
119 int sharpCount = 0;
120 for (int i = 0; i < incEdgeCountAtVertex; ++i) {
121 if (IsSemiSharp(incEdgeSharpness[i])) {
122 sharpCount ++;
123 sharpSum += incEdgeSharpness[i];
124 }
125 }
126 if (sharpCount > 1) {
127 // Chaikin rule is 3/4 original sharpness + 1/4 average of the others
128
129 float avgSharpnessAtVertex = (sharpSum - edgeSharpness) / (float)(sharpCount - 1);
130
131 edgeSharpness = (0.75f * edgeSharpness) + (0.25f * avgSharpnessAtVertex);
132 }
133 edgeSharpness -= 1.0f;
134 return IsSharp(edgeSharpness) ? edgeSharpness : Crease::SHARPNESS_SMOOTH;
135 }
136
137 void
SubdivideEdgeSharpnessesAroundVertex(int edgeCount,float const * parentSharpness,float * childSharpness) const138 Crease::SubdivideEdgeSharpnessesAroundVertex(int edgeCount,
139 float const* parentSharpness,
140 float * childSharpness) const {
141
142 if (IsUniform() || (edgeCount < 2)) {
143 for (int i = 0; i < edgeCount; ++i) {
144 childSharpness[i] = decrementSharpness(parentSharpness[i]);
145 }
146 return;
147 }
148
149 //
150 // Chaikin creasing is most efficiently computed for all edges around a vertex at
151 // once as the subdivided value for each creased edge depends on the average of
152 // the other edges around the vertex. So we can sum up the sharpness around the
153 // vertex once and use that for each edge, rather than iterating around the vertex
154 // for each incident edge.
155 //
156 if (_options.GetCreasingMethod() == Options::CREASE_CHAIKIN) {
157 float sharpSum = 0.0f;
158 int sharpCount = 0;
159 for (int i = 0; i < edgeCount; ++i) {
160 if (IsSemiSharp(parentSharpness[i])) {
161 sharpCount ++;
162 sharpSum += parentSharpness[i];
163 }
164 }
165
166 //
167 // The smooth case is most common -- specialize for it first:
168 //
169 if (sharpCount == 0) {
170 for (int i = 0; i < edgeCount; ++i) {
171 childSharpness[i] = parentSharpness[i];
172 }
173 } else {
174 for (int i = 0; i < edgeCount; ++i) {
175 float const& pSharp = parentSharpness[i];
176 float& cSharp = childSharpness[i];
177
178 if (IsSmooth(pSharp)) {
179 cSharp = Crease::SHARPNESS_SMOOTH;
180 } else if (IsInfinite(pSharp)) {
181 cSharp = Crease::SHARPNESS_INFINITE;
182 } else if (sharpCount == 1) {
183 // Need special case here anyway to avoid divide by zero below...
184 cSharp = decrementSharpness(pSharp);
185 } else {
186 float pOtherAverage = (sharpSum - pSharp) / (float)(sharpCount - 1);
187
188 // Chaikin rule is 3/4 original sharpness + 1/4 average of the others
189 cSharp = ((0.75f * pSharp) + (0.25f * pOtherAverage)) - 1.0f;
190 if (IsSmooth(cSharp)) cSharp = Crease::SHARPNESS_SMOOTH;
191 }
192 }
193 }
194 }
195 }
196
197 } // end namespace sdc
198
199 } // end namespace OPENSUBDIV_VERSION
200 } // end namespace OpenSubdiv
201