diff --git a/libs/yocto/yocto_math.h b/libs/yocto/yocto_math.h index 31184f64f..0946a5938 100644 --- a/libs/yocto/yocto_math.h +++ b/libs/yocto/yocto_math.h @@ -1258,6 +1258,67 @@ inline pair quad_tangents_fromuv(vec3f p0, vec3f p1, vec3f p2, } // namespace yocto +// ----------------------------------------------------------------------------- +// COMPUTATION OF PER_VERTEX PROPERTIES +// ----------------------------------------------------------------------------- +namespace yocto { + +// Compute per-vertex normals/tangents for lines/triangles/quads. +inline vector lines_tangents( + const vector& lines, const vector& positions); +inline vector triangles_normals( + const vector& triangles, const vector& positions); +inline vector quads_normals( + const vector& quads, const vector& positions); +// Update normals and tangents +inline void lines_tangents(vector& tangents, const vector& lines, + const vector& positions); +inline void triangles_normals(vector& normals, + const vector& triangles, const vector& positions); +inline void quads_normals(vector& normals, const vector& quads, + const vector& positions); + +// Compute per-vertex tangent space for triangle meshes. +// Tangent space is defined by a four component vector. +// The first three components are the tangent with respect to the u texcoord. +// The fourth component is the sign of the tangent wrt the v texcoord. +// Tangent frame is useful in normal mapping. +inline vector triangle_tangent_spaces(const vector& triangles, + const vector& positions, const vector& normals, + const vector& texcoords); + +} // namespace yocto + +// ----------------------------------------------------------------------------- +// COMPUTATION OF VERTEX PROPERTIES +// ----------------------------------------------------------------------------- +namespace yocto { + +// Flip vertex normals +inline vector flip_normals(const vector& normals); +// Flip face orientation +inline vector flip_triangles(const vector& triangles); +inline vector flip_quads(const vector& quads); +// Align vertex positions. Alignment is 0: none, 1: min, 2: max, 3: center. +inline vector align_vertices( + const vector& positions, vec3i alignment); + +} // namespace yocto + +// ----------------------------------------------------------------------------- +// SHAPE ELEMENT CONVERSION +// ----------------------------------------------------------------------------- +namespace yocto { + +// Convert quads to triangles +inline vector quads_to_triangles(const vector& quads); +// Convert triangles to quads by creating degenerate quads +inline vector triangles_to_quads(const vector& triangles); +// Convert beziers to lines using 3 lines for each bezier. +inline vector bezier_to_lines(vector& lines); + +} // namespace yocto + // ----------------------------------------------------------------------------- // USER INTERFACE UTILITIES // ----------------------------------------------------------------------------- @@ -3013,6 +3074,217 @@ inline pair quad_tangents_fromuv(vec3f p0, vec3f p1, vec3f p2, } // namespace yocto +// ----------------------------------------------------------------------------- +// IMPLEMENTATION OF COMPUTATION OF PER-VERTEX PROPERTIES +// ----------------------------------------------------------------------------- +namespace yocto { + +// Compute per-vertex tangents for lines. +inline vector lines_tangents( + const vector& lines, const vector& positions) { + auto tangents = vector{positions.size()}; + for (auto& tangent : tangents) tangent = {0, 0, 0}; + for (auto& l : lines) { + auto tangent = line_tangent(positions[l.x], positions[l.y]); + auto length = line_length(positions[l.x], positions[l.y]); + tangents[l.x] += tangent * length; + tangents[l.y] += tangent * length; + } + for (auto& tangent : tangents) tangent = normalize(tangent); + return tangents; +} + +// Compute per-vertex normals for triangles. +inline vector triangles_normals( + const vector& triangles, const vector& positions) { + auto normals = vector{positions.size()}; + for (auto& normal : normals) normal = {0, 0, 0}; + for (auto& t : triangles) { + auto normal = triangle_normal( + positions[t.x], positions[t.y], positions[t.z]); + auto area = triangle_area(positions[t.x], positions[t.y], positions[t.z]); + normals[t.x] += normal * area; + normals[t.y] += normal * area; + normals[t.z] += normal * area; + } + for (auto& normal : normals) normal = normalize(normal); + return normals; +} + +// Compute per-vertex normals for quads. +inline vector quads_normals( + const vector& quads, const vector& positions) { + auto normals = vector{positions.size()}; + for (auto& normal : normals) normal = {0, 0, 0}; + for (auto& q : quads) { + auto normal = quad_normal( + positions[q.x], positions[q.y], positions[q.z], positions[q.w]); + auto area = quad_area( + positions[q.x], positions[q.y], positions[q.z], positions[q.w]); + normals[q.x] += normal * area; + normals[q.y] += normal * area; + normals[q.z] += normal * area; + if (q.z != q.w) normals[q.w] += normal * area; + } + for (auto& normal : normals) normal = normalize(normal); + return normals; +} + +// Compute per-vertex tangents for lines. +inline void lines_tangents(vector& tangents, const vector& lines, + const vector& positions) { + if (tangents.size() != positions.size()) { + throw std::out_of_range("array should be the same length"); + } + for (auto& tangent : tangents) tangent = {0, 0, 0}; + for (auto& l : lines) { + auto tangent = line_tangent(positions[l.x], positions[l.y]); + auto length = line_length(positions[l.x], positions[l.y]); + tangents[l.x] += tangent * length; + tangents[l.y] += tangent * length; + } + for (auto& tangent : tangents) tangent = normalize(tangent); +} + +// Compute per-vertex normals for triangles. +inline void triangles_normals(vector& normals, + const vector& triangles, const vector& positions) { + if (normals.size() != positions.size()) { + throw std::out_of_range("array should be the same length"); + } + for (auto& normal : normals) normal = {0, 0, 0}; + for (auto& t : triangles) { + auto normal = triangle_normal( + positions[t.x], positions[t.y], positions[t.z]); + auto area = triangle_area(positions[t.x], positions[t.y], positions[t.z]); + normals[t.x] += normal * area; + normals[t.y] += normal * area; + normals[t.z] += normal * area; + } + for (auto& normal : normals) normal = normalize(normal); +} + +// Compute per-vertex normals for quads. +inline void quads_normals(vector& normals, const vector& quads, + const vector& positions) { + if (normals.size() != positions.size()) { + throw std::out_of_range("array should be the same length"); + } + for (auto& normal : normals) normal = {0, 0, 0}; + for (auto& q : quads) { + auto normal = quad_normal( + positions[q.x], positions[q.y], positions[q.z], positions[q.w]); + auto area = quad_area( + positions[q.x], positions[q.y], positions[q.z], positions[q.w]); + normals[q.x] += normal * area; + normals[q.y] += normal * area; + normals[q.z] += normal * area; + if (q.z != q.w) normals[q.w] += normal * area; + } + for (auto& normal : normals) normal = normalize(normal); +} + +// Compute per-vertex tangent frame for triangle meshes. +// Tangent space is defined by a four component vector. +// The first three components are the tangent with respect to the U texcoord. +// The fourth component is the sign of the tangent wrt the V texcoord. +// Tangent frame is useful in normal mapping. +inline vector triangles_tangent_spaces(const vector& triangles, + const vector& positions, const vector& normals, + const vector& texcoords) { + auto tangu = vector(positions.size(), vec3f{0, 0, 0}); + auto tangv = vector(positions.size(), vec3f{0, 0, 0}); + for (auto t : triangles) { + auto tutv = triangle_tangents_fromuv(positions[t.x], positions[t.y], + positions[t.z], texcoords[t.x], texcoords[t.y], texcoords[t.z]); + for (auto vid : {t.x, t.y, t.z}) tangu[vid] += normalize(tutv.first); + for (auto vid : {t.x, t.y, t.z}) tangv[vid] += normalize(tutv.second); + } + for (auto& t : tangu) t = normalize(t); + for (auto& t : tangv) t = normalize(t); + + auto tangent_spaces = vector(positions.size()); + for (auto& tangent : tangent_spaces) tangent = vec4f{0, 0, 0, 0}; + for (auto i = 0; i < positions.size(); i++) { + tangu[i] = orthonormalize(tangu[i], normals[i]); + auto s = (dot(cross(normals[i], tangu[i]), tangv[i]) < 0) ? -1.0f : 1.0f; + tangent_spaces[i] = {tangu[i].x, tangu[i].y, tangu[i].z, s}; + } + return tangent_spaces; +} + +} // namespace yocto + +// ----------------------------------------------------------------------------- +// COMPUTATION OF PER VERTEX PROPERTIES +// ----------------------------------------------------------------------------- +namespace yocto { + +// Flip vertex normals +inline vector flip_normals(const vector& normals) { + auto flipped = normals; + for (auto& n : flipped) n = -n; + return flipped; +} +// Flip face orientation +inline vector flip_triangles(const vector& triangles) { + auto flipped = triangles; + for (auto& t : flipped) swap(t.y, t.z); + return flipped; +} +inline vector flip_quads(const vector& quads) { + auto flipped = quads; + for (auto& q : flipped) { + if (q.z != q.w) { + swap(q.y, q.w); + } else { + swap(q.y, q.z); + q.w = q.z; + } + } + return flipped; +} + +} // namespace yocto + +// ----------------------------------------------------------------------------- +// IMPLEMENTATION OF SHAPE ELEMENT CONVERSION +// ----------------------------------------------------------------------------- +namespace yocto { + +// Convert quads to triangles +inline vector quads_to_triangles(const vector& quads) { + auto triangles = vector{}; + triangles.reserve(quads.size() * 2); + for (auto& q : quads) { + triangles.push_back({q.x, q.y, q.w}); + if (q.z != q.w) triangles.push_back({q.z, q.w, q.y}); + } + return triangles; +} + +// Convert triangles to quads by creating degenerate quads +inline vector triangles_to_quads(const vector& triangles) { + auto quads = vector{}; + quads.reserve(triangles.size()); + for (auto& t : triangles) quads.push_back({t.x, t.y, t.z, t.z}); + return quads; +} + +// Convert beziers to lines using 3 lines for each bezier. +inline vector bezier_to_lines(const vector& beziers) { + auto lines = vector{}; + lines.reserve(beziers.size() * 3); + for (auto b : beziers) { + lines.push_back({b.x, b.y}); + lines.push_back({b.y, b.z}); + lines.push_back({b.z, b.w}); + } + return lines; +} + +} // namespace yocto + // ----------------------------------------------------------------------------- // USER INTERFACE UTILITIES // ----------------------------------------------------------------------------- diff --git a/libs/yocto/yocto_shape.h b/libs/yocto/yocto_shape.h index ad8939870..242fc9692 100644 --- a/libs/yocto/yocto_shape.h +++ b/libs/yocto/yocto_shape.h @@ -68,67 +68,6 @@ using std::vector; #define inline inline __device__ __forceinline__ #endif -// ----------------------------------------------------------------------------- -// COMPUTATION OF PER_VERTEX PROPERTIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Compute per-vertex normals/tangents for lines/triangles/quads. -inline vector lines_tangents( - const vector& lines, const vector& positions); -inline vector triangles_normals( - const vector& triangles, const vector& positions); -inline vector quads_normals( - const vector& quads, const vector& positions); -// Update normals and tangents -inline void lines_tangents(vector& tangents, const vector& lines, - const vector& positions); -inline void triangles_normals(vector& normals, - const vector& triangles, const vector& positions); -inline void quads_normals(vector& normals, const vector& quads, - const vector& positions); - -// Compute per-vertex tangent space for triangle meshes. -// Tangent space is defined by a four component vector. -// The first three components are the tangent with respect to the u texcoord. -// The fourth component is the sign of the tangent wrt the v texcoord. -// Tangent frame is useful in normal mapping. -inline vector triangle_tangent_spaces(const vector& triangles, - const vector& positions, const vector& normals, - const vector& texcoords); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// COMPUTATION OF VERTEX PROPERTIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Flip vertex normals -inline vector flip_normals(const vector& normals); -// Flip face orientation -inline vector flip_triangles(const vector& triangles); -inline vector flip_quads(const vector& quads); -// Align vertex positions. Alignment is 0: none, 1: min, 2: max, 3: center. -inline vector align_vertices( - const vector& positions, vec3i alignment); - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// SHAPE ELEMENT CONVERSION -// ----------------------------------------------------------------------------- -namespace yocto { - -// Convert quads to triangles -inline vector quads_to_triangles(const vector& quads); -// Convert triangles to quads by creating degenerate quads -inline vector triangles_to_quads(const vector& triangles); -// Convert beziers to lines using 3 lines for each bezier. -inline vector bezier_to_lines(vector& lines); - -} // namespace yocto - // ----------------------------------------------------------------------------- // // @@ -137,217 +76,6 @@ inline vector bezier_to_lines(vector& lines); // // ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// IMPLEMENTATION OF COMPUTATION OF PER-VERTEX PROPERTIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Compute per-vertex tangents for lines. -inline vector lines_tangents( - const vector& lines, const vector& positions) { - auto tangents = vector{positions.size()}; - for (auto& tangent : tangents) tangent = {0, 0, 0}; - for (auto& l : lines) { - auto tangent = line_tangent(positions[l.x], positions[l.y]); - auto length = line_length(positions[l.x], positions[l.y]); - tangents[l.x] += tangent * length; - tangents[l.y] += tangent * length; - } - for (auto& tangent : tangents) tangent = normalize(tangent); - return tangents; -} - -// Compute per-vertex normals for triangles. -inline vector triangles_normals( - const vector& triangles, const vector& positions) { - auto normals = vector{positions.size()}; - for (auto& normal : normals) normal = {0, 0, 0}; - for (auto& t : triangles) { - auto normal = triangle_normal( - positions[t.x], positions[t.y], positions[t.z]); - auto area = triangle_area(positions[t.x], positions[t.y], positions[t.z]); - normals[t.x] += normal * area; - normals[t.y] += normal * area; - normals[t.z] += normal * area; - } - for (auto& normal : normals) normal = normalize(normal); - return normals; -} - -// Compute per-vertex normals for quads. -inline vector quads_normals( - const vector& quads, const vector& positions) { - auto normals = vector{positions.size()}; - for (auto& normal : normals) normal = {0, 0, 0}; - for (auto& q : quads) { - auto normal = quad_normal( - positions[q.x], positions[q.y], positions[q.z], positions[q.w]); - auto area = quad_area( - positions[q.x], positions[q.y], positions[q.z], positions[q.w]); - normals[q.x] += normal * area; - normals[q.y] += normal * area; - normals[q.z] += normal * area; - if (q.z != q.w) normals[q.w] += normal * area; - } - for (auto& normal : normals) normal = normalize(normal); - return normals; -} - -// Compute per-vertex tangents for lines. -inline void lines_tangents(vector& tangents, const vector& lines, - const vector& positions) { - if (tangents.size() != positions.size()) { - throw std::out_of_range("array should be the same length"); - } - for (auto& tangent : tangents) tangent = {0, 0, 0}; - for (auto& l : lines) { - auto tangent = line_tangent(positions[l.x], positions[l.y]); - auto length = line_length(positions[l.x], positions[l.y]); - tangents[l.x] += tangent * length; - tangents[l.y] += tangent * length; - } - for (auto& tangent : tangents) tangent = normalize(tangent); -} - -// Compute per-vertex normals for triangles. -inline void triangles_normals(vector& normals, - const vector& triangles, const vector& positions) { - if (normals.size() != positions.size()) { - throw std::out_of_range("array should be the same length"); - } - for (auto& normal : normals) normal = {0, 0, 0}; - for (auto& t : triangles) { - auto normal = triangle_normal( - positions[t.x], positions[t.y], positions[t.z]); - auto area = triangle_area(positions[t.x], positions[t.y], positions[t.z]); - normals[t.x] += normal * area; - normals[t.y] += normal * area; - normals[t.z] += normal * area; - } - for (auto& normal : normals) normal = normalize(normal); -} - -// Compute per-vertex normals for quads. -inline void quads_normals(vector& normals, const vector& quads, - const vector& positions) { - if (normals.size() != positions.size()) { - throw std::out_of_range("array should be the same length"); - } - for (auto& normal : normals) normal = {0, 0, 0}; - for (auto& q : quads) { - auto normal = quad_normal( - positions[q.x], positions[q.y], positions[q.z], positions[q.w]); - auto area = quad_area( - positions[q.x], positions[q.y], positions[q.z], positions[q.w]); - normals[q.x] += normal * area; - normals[q.y] += normal * area; - normals[q.z] += normal * area; - if (q.z != q.w) normals[q.w] += normal * area; - } - for (auto& normal : normals) normal = normalize(normal); -} - -// Compute per-vertex tangent frame for triangle meshes. -// Tangent space is defined by a four component vector. -// The first three components are the tangent with respect to the U texcoord. -// The fourth component is the sign of the tangent wrt the V texcoord. -// Tangent frame is useful in normal mapping. -inline vector triangles_tangent_spaces(const vector& triangles, - const vector& positions, const vector& normals, - const vector& texcoords) { - auto tangu = vector(positions.size(), vec3f{0, 0, 0}); - auto tangv = vector(positions.size(), vec3f{0, 0, 0}); - for (auto t : triangles) { - auto tutv = triangle_tangents_fromuv(positions[t.x], positions[t.y], - positions[t.z], texcoords[t.x], texcoords[t.y], texcoords[t.z]); - for (auto vid : {t.x, t.y, t.z}) tangu[vid] += normalize(tutv.first); - for (auto vid : {t.x, t.y, t.z}) tangv[vid] += normalize(tutv.second); - } - for (auto& t : tangu) t = normalize(t); - for (auto& t : tangv) t = normalize(t); - - auto tangent_spaces = vector(positions.size()); - for (auto& tangent : tangent_spaces) tangent = vec4f{0, 0, 0, 0}; - for (auto i : range(positions.size())) { - tangu[i] = orthonormalize(tangu[i], normals[i]); - auto s = (dot(cross(normals[i], tangu[i]), tangv[i]) < 0) ? -1.0f : 1.0f; - tangent_spaces[i] = {tangu[i].x, tangu[i].y, tangu[i].z, s}; - } - return tangent_spaces; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// COMPUTATION OF PER VERTEX PROPETIES -// ----------------------------------------------------------------------------- -namespace yocto { - -// Flip vertex normals -inline vector flip_normals(const vector& normals) { - auto flipped = normals; - for (auto& n : flipped) n = -n; - return flipped; -} -// Flip face orientation -inline vector flip_triangles(const vector& triangles) { - auto flipped = triangles; - for (auto& t : flipped) swap(t.y, t.z); - return flipped; -} -inline vector flip_quads(const vector& quads) { - auto flipped = quads; - for (auto& q : flipped) { - if (q.z != q.w) { - swap(q.y, q.w); - } else { - swap(q.y, q.z); - q.w = q.z; - } - } - return flipped; -} - -} // namespace yocto - -// ----------------------------------------------------------------------------- -// IMPLEMENTATION OF SHAPE ELEMENT CONVERSION -// ----------------------------------------------------------------------------- -namespace yocto { - -// Convert quads to triangles -inline vector quads_to_triangles(const vector& quads) { - auto triangles = vector{}; - triangles.reserve(quads.size() * 2); - for (auto& q : quads) { - triangles.push_back({q.x, q.y, q.w}); - if (q.z != q.w) triangles.push_back({q.z, q.w, q.y}); - } - return triangles; -} - -// Convert triangles to quads by creating degenerate quads -inline vector triangles_to_quads(const vector& triangles) { - auto quads = vector{}; - quads.reserve(triangles.size()); - for (auto& t : triangles) quads.push_back({t.x, t.y, t.z, t.z}); - return quads; -} - -// Convert beziers to lines using 3 lines for each bezier. -inline vector bezier_to_lines(const vector& beziers) { - auto lines = vector{}; - lines.reserve(beziers.size() * 3); - for (auto b : beziers) { - lines.push_back({b.x, b.y}); - lines.push_back({b.y, b.z}); - lines.push_back({b.z, b.w}); - } - return lines; -} - -} // namespace yocto - // ----------------------------------------------------------------------------- // CUDA SUPPORT // -----------------------------------------------------------------------------