Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f13d52e
A round prim's side normals point straight out of its surface
RyeMutt Oct 20, 2026
229feac
A side joins its normals only across a seam its own positions close
RyeMutt Oct 20, 2026
e1098be
A cap faces away from its wall whatever its first triangle is
RyeMutt Oct 20, 2026
8c1037b
Prim normals come out of generation unit length, never zero
RyeMutt Oct 20, 2026
2e7574f
A flexible prim's partial build rewrites its faces in place, tangents…
RyeMutt Oct 20, 2026
9f9952f
A hole stays inside its wall
RyeMutt Oct 20, 2026
6293125
The sculpt sphere placeholder is laid out as the sphere stitching exp…
RyeMutt Oct 20, 2026
d219c7b
A side's normal pass takes each edge once, and a hole clamps only to …
RyeMutt Oct 20, 2026
414577f
A cap with no area is held to a finite normal that faces out
RyeMutt Oct 20, 2026
5551f6c
Prim and sculpt tangents take meshoptimizer's weighting, eight lanes …
RyeMutt Oct 20, 2026
0439c77
Prim generation's per-vertex loops run on the SIMD kernels
RyeMutt Oct 20, 2026
3491dbd
A circle path ends on one station, and Lengyel's fallback tangent lie…
RyeMutt Oct 20, 2026
65f5954
Media zoom faces the face, not the camera
RyeMutt Oct 20, 2026
20ddd28
Flexible prims take cheap tangents, and small prims skip what they do…
RyeMutt Oct 20, 2026
51ca024
A circle2 path's point count is the stations it builds
RyeMutt Oct 20, 2026
a72e3a1
The tangent check holds no vertex to meshoptimizer's where it welds i…
taylnos Oct 23, 2026
8dc82e9
Merge remote-tracking branch 'public/develop' into rye/prim-normals
RyeMutt Oct 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions indra/llmath/alsimdkernels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ void transform_directions_keep_w(const LLMatrix4a& m, const LLVector4a* src, LLV
kernels::transform_impl<ALSimdWide, false, W_LANE::KEEP>(m, src, dst, n, 0.f);
}

void transform_directions_offset(const LLMatrix4a& m, const LLVector4a& offset, const LLVector4a* src, LLVector4a* dst, size_t n)
{
kernels::transform_offset_impl<ALSimdWide>(m, offset, src, dst, n);
}

void transform_texcoords(const F32* src, F32* dst, size_t n,
const LLVector4a& trans, const LLVector4a& rot0, const LLVector4a& rot1,
const LLVector4a& scale, const LLVector4a& offset)
Expand Down Expand Up @@ -95,4 +100,37 @@ void morph_apply(const MorphApply& m)
kernels::morph_apply_impl(m);
}

namespace
{
// grid_tangents' lanes, each thread's own.
std::vector<F32>& tangent_scratch()
{
thread_local std::vector<F32> scratch;
return scratch;
}
}

void grid_tangents(const LLVector4a* positions, const LLVector4a* normals, const LLVector2* uvs, size_t columns, size_t rows,
LLVector4a* tangents)
{
kernels::grid_tangents_impl<ALSimdLanes>(positions, normals, uvs, columns, rows, tangents, tangent_scratch());
}

void indexed_tangents(const LLVector4a* positions, const LLVector4a* normals, const LLVector2* uvs, size_t vertex_count,
const U16* indices, size_t index_count, LLVector4a* tangents)
{
kernels::indexed_tangents_impl<ALSimdLanes>(positions, normals, uvs, vertex_count, indices, index_count, tangents);
}

bool grid_tangents_central(const LLVector4a* positions, const LLVector4a* normals, size_t columns, size_t rows, bool joins, F32 same, F32 sign,
F32 w, LLVector4a* tangents)
{
return kernels::grid_tangents_central_impl<ALSimdLanes>(positions, normals, columns, rows, joins, same, sign, w, tangents);
}

bool normalize3_or_mark(LLVector4a* v, size_t n)
{
return kernels::normalize3_or_mark_impl<ALSimdLanes>(v, n);
}

} // namespace alsimd
54 changes: 52 additions & 2 deletions indra/llmath/alsimdkernels.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* @file alsimdkernels.h
* @brief Batch kernels over arrays of vectors: transforms, dequantization,
* index offsets, skinning and bounds, at the register width the
* build was compiled for.
* index offsets, skinning, bounds and tangents, at the register
* width the build was compiled for.
*
* $LicenseInfo:firstyear=2026&license=viewerlgpl$
* Alchemy Viewer Source Code
Expand Down Expand Up @@ -54,6 +54,12 @@ void transform_directions(const LLMatrix4a& m, const LLVector4a* src, LLVector4a
// The same, with lane w of every result taken from its source.
void transform_directions_keep_w(const LLMatrix4a& m, const LLVector4a* src, LLVector4a* dst, size_t n);

// Every direction through the upper three rows, then offset added: a point
// turned and scaled about the origin and then moved, rounded as
// LLMatrix4a::rotate and an add round it, where transform_points folds the
// move into the rows' sum.
void transform_directions_offset(const LLMatrix4a& m, const LLVector4a& offset, const LLVector4a* src, LLVector4a* dst, size_t n);

// Two texture coordinates per vector, <s0, t0, s1, t1>: translated by
// trans, rotated by rot0 and rot1 (<cos, -sin, cos, -sin> and <sin, cos,
// sin, cos>), scaled, then offset. n counts vectors.
Expand Down Expand Up @@ -120,6 +126,50 @@ struct MorphApply

void morph_apply(const MorphApply& m);

// Every vertex's tangent by meshoptimizer's default weighting, summed into
// the vertex itself rather than into groups of its corners. A triangle's
// tangent is dP/du by the chain rule. It adds nothing where the triangle
// has no area, in positions or in UVs, to within rounding: twice the area
// under 1e-5 of the sum of the squares of the two edges from its first
// corner, as when two corners are one point. At each corner it is put in
// the plane of that corner's normal, renormalized, and weighted by the
// angle between the corner's edges in that plane times the product of
// their lengths there. Each vertex's sum is put back in its normal's plane
// and normalized; where nothing was added it is +x in that plane, or +y
// where the normal is within 45 degrees of x. w is the sign of the UV
// area of the vertex's triangles in index order, the sign of the most of
// them where they differ; a vertex in none of them takes the face's, and
// -1 where the face has none either. The normals are taken as unit length.
//
// The grid form is a grid of columns by rows, vertex s + columns * t, each
// quad two triangles: bottom left, top right, top left and bottom left,
// bottom right, top right, as LLVolumeFace::createSide indexes them. It
// needs no index buffer, and keeps the grid as lanes in a scratch buffer
// of each thread's, which grows to the largest grid the thread has made
// tangents for.
void grid_tangents(const LLVector4a* positions, const LLVector4a* normals, const LLVector2* uvs, size_t columns, size_t rows,
LLVector4a* tangents);

// The same over triangles from an index buffer.
void indexed_tangents(const LLVector4a* positions, const LLVector4a* normals, const LLVector2* uvs, size_t vertex_count,
const U16* indices, size_t index_count, LLVector4a* tangents);

// A grid's tangents along its rows, cheaply: each vertex's is the chord
// from its left neighbour in its row to its right one, times sign, put in
// the plane of its normal and normalized, with w set to w. At a row's
// ends the chord reaches across the seam to the column beside the other
// end where joins is set, and is one-sided where it is not. A chord whose
// part in that plane is shorter than `same`, or nearly along the normal,
// gives no direction: the vertex is left with w 0, for the caller to fill.
// Returns whether any was. The grid is laid out as grid_tangents takes it.
bool grid_tangents_central(const LLVector4a* positions, const LLVector4a* normals, size_t columns, size_t rows, bool joins, F32 same, F32 sign,
F32 w, LLVector4a* tangents);

// Every vector at unit length in x, y and z, w scaled with them, where its
// squared length in x, y and z is above FLT_MIN; elsewhere (0, 0, 0, 1).
// Returns whether any was set so.
bool normalize3_or_mark(LLVector4a* v, size_t n);

} // namespace alsimd

#endif // AL_SIMDKERNELS_H
Loading
Loading