24 N_(
"Calculation using the MikkTSpace library, consistent with tangents used elsewhere in "
30 N_(
"Significantly faster method that approximates tangents interpolated across face corners "
31 "with matching UVs. For a value actually tangential to the surface, use the cross product "
33 {0,
nullptr, 0,
nullptr,
nullptr},
40 b.add_output<
decl::Vector>(
"Tangent").field_source_reference_all();
50 const float x1 = p2.x - p1.x;
51 const float x2 = p3.x - p1.x;
52 const float y1 = p2.y - p1.y;
53 const float y2 = p3.y - p1.y;
54 const float z1 = p2.z - p1.z;
55 const float z2 = p3.z - p1.z;
56 const float s1 = uv2.x - uv1.x;
57 const float s2 = uv3.x - uv1.x;
58 const float t1 = uv2.y - uv1.y;
59 const float t2 = uv3.y - uv1.y;
61 const float3 tangent((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
76 for (const int tri_i : range) {
77 const int3 &tri = corner_tris[tri_i];
78 const float3 tangent = compute_triangle_tangent(positions[corner_verts[tri[0]]],
79 positions[corner_verts[tri[1]]],
80 positions[corner_verts[tri[2]]],
85 r_corner_tangents[tri[0]] = tangent;
86 r_corner_tangents[tri[1]] = tangent;
87 r_corner_tangents[tri[2]] = tangent;
93 struct SharedCorners {
95 Vector<int, 10> corners;
96 float3 tangent_sum = float3(0.0f);
99 for (
const int vert : range) {
100 const Span<int> corners = vert_to_corners_map[vert];
102 shared_corners.clear();
103 for (
const int corner : corners) {
104 const float2 uv = uvs[corner].xy();
106 const float3 &tri_tangent = r_corner_tangents[corner];
108 for (SharedCorners &shared_corner : shared_corners) {
110 shared_corner.corners.append(corner);
111 shared_corner.tangent_sum += tri_tangent;
117 shared_corners.append({uv, {corner}, tri_tangent});
120 for (
const SharedCorners &shared_corner : shared_corners) {
122 for (
const int corner : shared_corner.corners) {
123 r_corner_tangents[corner] = tangent;
139 uv_field_(std::move(uv))
152 evaluator.
add(uv_field_);
162 mesh.vert_to_corner_map(),
172 for (const int64_t corner : range) {
173 uvs_float2[corner] = uvs[corner].xy();
180 mesh.corner_tri_faces(),
184 mesh.corner_normals(),
187 for (const int64_t corner : range) {
188 corner_tangents[corner] = mikk_tangents[0][corner].xyz();
202 uv_field_.node().for_each_field_input_recursive(
fn);
209 return method_ == other_endpoint->method_ && uv_field_ == other_endpoint->uv_field_;
221 return AttrDomain::Corner;
229 params.set_output(
"Tangent",
230 Field<float3>(std::make_shared<TangentFieldInput>(method, uv_field)));
239 ntype.
ui_description =
"Generate tangent directions based on a UV map";
#define NOD_REGISTER_NODE(REGISTER_FUNC)
unsigned long long int uint64_t
constexpr int64_t size() const
constexpr int64_t size() const
constexpr IndexRange index_range() const
static VArray from_container(ContainerT container)
GAttributeReader lookup(const StringRef attribute_id) const
int add(GField field, GVArray *varray_ptr)
const GVArray & get_evaluated(const int field_index) const
FieldNode(FieldNodeType node_type)
Array< Array< float4 > > calc_uv_tangents(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int3 > corner_tris, Span< int > corner_tri_faces, Span< bool > sharp_faces, Span< float3 > vert_normals, Span< float3 > face_normals, Span< float3 > corner_normals, Span< Span< float2 > > uv_maps)
void node_register_type(bNodeType &ntype)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T distance_manhattan(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
static void calc_uv_tangents_simple(const Span< float3 > positions, const Span< int > corner_verts, const Span< int3 > corner_tris, const GroupedSpan< int > vert_to_corners_map, const Span< float3 > uvs, MutableSpan< float3 > r_corner_tangents)
static EnumPropertyItem method_items[]
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static void node_register()
static float3 compute_triangle_tangent(const float3 &p1, const float3 &p2, const float3 &p3, const float2 &uv1, const float2 &uv2, const float2 &uv3)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
uint64_t get_default_hash(const T &v, const Args &...args)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
std::string ui_description
NodeGeometryExecFunction geometry_node_execute
NodeDeclareFunction declare