Cycles: Change normal map node to work with undisplaced normal and tangent
This fits better with the way normal and displacement maps are typically combined. Previously there was a mixing of displaced normal and undisplaced tangent, which was broken behavior. Additionally, to undisplaced_N and undisplaced_tangent attributes must now always be used to get undisplaced coordinates. The regular N and tangent attributes now always include displacement. Ref #142022 Pull Request: https://projects.blender.org/blender/blender/pulls/143109
This commit is contained in:
@@ -793,6 +793,11 @@ bool OSLRenderServices::get_object_standard_attribute(
|
||||
#endif
|
||||
if (name == u_normal_map_normal) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
const AttributeDescriptor desc = find_attribute(
|
||||
kg, sd->object, sd->prim, ATTR_STD_NORMAL_UNDISPLACED);
|
||||
if (desc.offset != ATTR_STD_NOT_FOUND) {
|
||||
return get_object_attribute(kg, sd, desc, type, derivatives, val);
|
||||
}
|
||||
const float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
return set_attribute(f, type, derivatives, val);
|
||||
}
|
||||
|
||||
@@ -879,6 +879,11 @@ ccl_device_inline bool get_object_standard_attribute(KernelGlobals kg,
|
||||
|
||||
else if (name == DeviceStrings::u_normal_map_normal) {
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
const AttributeDescriptor desc = find_attribute(
|
||||
kg, sd->object, sd->prim, ATTR_STD_NORMAL_UNDISPLACED);
|
||||
if (desc.offset != ATTR_STD_NOT_FOUND) {
|
||||
return get_object_attribute(kg, sd, desc, type, derivatives, val);
|
||||
}
|
||||
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
return set_attribute(f, type, derivatives, val);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
shader node_normal_map(float Strength = 1.0,
|
||||
color Color = color(0.5, 0.5, 1.0),
|
||||
string space = "tangent",
|
||||
string attr_name = "geom:tangent",
|
||||
string attr_sign_name = "geom:tangent_sign",
|
||||
string attr_name = "geom:undisplaced_tangent",
|
||||
string attr_sign_name = "geom:undisplaced_tangent_sign",
|
||||
output normal Normal = N)
|
||||
{
|
||||
color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
|
||||
|
||||
@@ -361,7 +361,15 @@ ccl_device_noinline void svm_node_normal_map(KernelGlobals kg,
|
||||
float3 normal;
|
||||
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
normal = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
const AttributeDescriptor attr_undisplaced_normal = find_attribute(
|
||||
kg, sd->object, sd->prim, ATTR_STD_NORMAL_UNDISPLACED);
|
||||
if (attr_undisplaced_normal.offset != ATTR_STD_NOT_FOUND) {
|
||||
normal =
|
||||
primitive_surface_attribute<float3>(kg, sd, attr_undisplaced_normal, false, false).val;
|
||||
}
|
||||
else {
|
||||
normal = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
normal = sd->Ng;
|
||||
|
||||
@@ -870,6 +870,8 @@ enum AttributeStandard {
|
||||
ATTR_STD_UV,
|
||||
ATTR_STD_UV_TANGENT,
|
||||
ATTR_STD_UV_TANGENT_SIGN,
|
||||
ATTR_STD_UV_TANGENT_UNDISPLACED,
|
||||
ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED,
|
||||
ATTR_STD_VERTEX_COLOR,
|
||||
ATTR_STD_GENERATED,
|
||||
ATTR_STD_GENERATED_TRANSFORM,
|
||||
|
||||
@@ -320,6 +320,10 @@ const char *Attribute::standard_name(AttributeStandard std)
|
||||
return "tangent";
|
||||
case ATTR_STD_UV_TANGENT_SIGN:
|
||||
return "tangent_sign";
|
||||
case ATTR_STD_UV_TANGENT_UNDISPLACED:
|
||||
return "undisplaced_tangent";
|
||||
case ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED:
|
||||
return "undisplaced_tangent_sign";
|
||||
case ATTR_STD_VERTEX_COLOR:
|
||||
return "vertex_color";
|
||||
case ATTR_STD_POSITION_UNDEFORMED:
|
||||
@@ -520,9 +524,11 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
|
||||
attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER);
|
||||
break;
|
||||
case ATTR_STD_UV_TANGENT:
|
||||
case ATTR_STD_UV_TANGENT_UNDISPLACED:
|
||||
attr = add(name, TypeVector, ATTR_ELEMENT_CORNER);
|
||||
break;
|
||||
case ATTR_STD_UV_TANGENT_SIGN:
|
||||
case ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED:
|
||||
attr = add(name, TypeFloat, ATTR_ELEMENT_CORNER);
|
||||
break;
|
||||
case ATTR_STD_VERTEX_COLOR:
|
||||
|
||||
@@ -798,7 +798,10 @@ void GeometryManager::device_update(Device *device,
|
||||
/* Apply generated attribute if needed or remove if not needed */
|
||||
mesh->update_generated(scene);
|
||||
/* Apply tangents for generated and UVs (if any need them) or remove if not needed */
|
||||
mesh->update_tangents(scene);
|
||||
mesh->update_tangents(scene, true);
|
||||
if (!mesh->has_true_displacement()) {
|
||||
mesh->update_tangents(scene, false);
|
||||
}
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
|
||||
@@ -550,13 +550,6 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
for (AttributeRequest &req : attributes.requests) {
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
/* Keep "N" attribute undisplaced for backwards compatibility in Blender 4.5. */
|
||||
if (attr && attr->std == ATTR_STD_VERTEX_NORMAL) {
|
||||
if (Attribute *undisplaced_attr = geom->attributes.find(ATTR_STD_NORMAL_UNDISPLACED)) {
|
||||
attr = undisplaced_attr;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
|
||||
|
||||
@@ -115,7 +115,13 @@ struct MikkMeshWrapper {
|
||||
float *tangent_sign;
|
||||
};
|
||||
|
||||
static void mikk_compute_tangents(Attribute *attr_uv, Mesh *mesh, const bool need_sign)
|
||||
static void mikk_compute_tangents(Attribute *attr_uv,
|
||||
Mesh *mesh,
|
||||
const bool need_sign,
|
||||
const AttributeStandard tangent_std,
|
||||
const AttributeStandard tangent_sign_std,
|
||||
const char *tangent_postfix,
|
||||
const char *tangent_sign_postfix)
|
||||
{
|
||||
/* Create tangent attributes. */
|
||||
AttributeSet &attributes = mesh->attributes;
|
||||
@@ -129,11 +135,11 @@ static void mikk_compute_tangents(Attribute *attr_uv, Mesh *mesh, const bool nee
|
||||
const float3 *normal = attr_vN->data_float3();
|
||||
const float2 *uv = (attr_uv) ? attr_uv->data_float2() : nullptr;
|
||||
|
||||
const ustring name = ustring((attr_uv) ? attr_uv->name.string() + ".tangent" :
|
||||
Attribute::standard_name(ATTR_STD_UV_TANGENT));
|
||||
const ustring name = ustring((attr_uv) ? attr_uv->name.string() + tangent_postfix :
|
||||
Attribute::standard_name(tangent_std));
|
||||
Attribute *attr;
|
||||
if (attr_uv == nullptr || attr_uv->std == ATTR_STD_UV) {
|
||||
attr = attributes.add(ATTR_STD_UV_TANGENT, name);
|
||||
attr = attributes.add(tangent_std, name);
|
||||
}
|
||||
else {
|
||||
attr = attributes.add(name, TypeVector, ATTR_ELEMENT_CORNER);
|
||||
@@ -142,12 +148,11 @@ static void mikk_compute_tangents(Attribute *attr_uv, Mesh *mesh, const bool nee
|
||||
/* Create bitangent sign attribute. */
|
||||
float *tangent_sign = nullptr;
|
||||
if (need_sign) {
|
||||
const ustring name_sign = ustring((attr_uv) ?
|
||||
attr_uv->name.string() + ".tangent_sign" :
|
||||
Attribute::standard_name(ATTR_STD_UV_TANGENT_SIGN));
|
||||
const ustring name_sign = ustring((attr_uv) ? attr_uv->name.string() + tangent_sign_postfix :
|
||||
Attribute::standard_name(tangent_sign_std));
|
||||
Attribute *attr_sign;
|
||||
if (attr_uv == nullptr || attr_uv->std == ATTR_STD_UV) {
|
||||
attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
|
||||
attr_sign = attributes.add(tangent_sign_std, name_sign);
|
||||
}
|
||||
else {
|
||||
attr_sign = attributes.add(name_sign, TypeFloat, ATTR_ELEMENT_CORNER);
|
||||
@@ -754,9 +759,7 @@ void Mesh::add_undisplaced(Scene *scene)
|
||||
std::copy_n(verts.data(), size, attr->data_float3());
|
||||
}
|
||||
|
||||
/* Keep "N" attribute undisplaced for backwards compatibility in Blender 4.5. */
|
||||
if (((need_attribute(scene, ATTR_STD_VERTEX_NORMAL) && has_true_displacement()) ||
|
||||
need_attribute(scene, ATTR_STD_NORMAL_UNDISPLACED)) &&
|
||||
if (need_attribute(scene, ATTR_STD_NORMAL_UNDISPLACED) &&
|
||||
!attributes.find(ATTR_STD_NORMAL_UNDISPLACED))
|
||||
{
|
||||
/* Copy vertex normal to attribute */
|
||||
@@ -789,7 +792,7 @@ void Mesh::update_generated(Scene *scene)
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::update_tangents(Scene *scene)
|
||||
void Mesh::update_tangents(Scene *scene, bool undisplaced)
|
||||
{
|
||||
if (!num_triangles()) {
|
||||
return;
|
||||
@@ -800,9 +803,22 @@ void Mesh::update_tangents(Scene *scene)
|
||||
ccl::set<ustring> uv_maps;
|
||||
Attribute *attr_std_uv = attributes.find(ATTR_STD_UV);
|
||||
|
||||
AttributeStandard tangent_std = (undisplaced) ? ATTR_STD_UV_TANGENT_UNDISPLACED :
|
||||
ATTR_STD_UV_TANGENT;
|
||||
AttributeStandard tangent_sign_std = (undisplaced) ? ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED :
|
||||
ATTR_STD_UV_TANGENT_SIGN;
|
||||
const char *tangent_postfix = (undisplaced) ? ".undisplaced_tangent" : ".tangent";
|
||||
const char *tangent_sign_postfix = (undisplaced) ? ".undisplaced_tangent_sign" : ".tangent_sign";
|
||||
|
||||
/* standard UVs */
|
||||
if (need_attribute(scene, ATTR_STD_UV_TANGENT) && !attributes.find(ATTR_STD_UV_TANGENT)) {
|
||||
mikk_compute_tangents(attr_std_uv, this, true); /* sign */
|
||||
if (need_attribute(scene, tangent_std) && !attributes.find(tangent_std)) {
|
||||
mikk_compute_tangents(attr_std_uv,
|
||||
this,
|
||||
true,
|
||||
tangent_std,
|
||||
tangent_sign_std,
|
||||
tangent_postfix,
|
||||
tangent_sign_postfix); /* sign */
|
||||
}
|
||||
|
||||
/* now generate for any other UVs requested */
|
||||
@@ -811,10 +827,16 @@ void Mesh::update_tangents(Scene *scene)
|
||||
continue;
|
||||
}
|
||||
|
||||
const ustring tangent_name = ustring(attr.name.string() + ".tangent");
|
||||
const ustring tangent_name = ustring(attr.name.string() + tangent_postfix);
|
||||
|
||||
if (need_attribute(scene, tangent_name) && !attributes.find(tangent_name)) {
|
||||
mikk_compute_tangents(&attr, this, true); /* sign */
|
||||
mikk_compute_tangents(&attr,
|
||||
this,
|
||||
true,
|
||||
tangent_std,
|
||||
tangent_sign_std,
|
||||
tangent_postfix,
|
||||
tangent_sign_postfix); /* sign */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ class Mesh : public Geometry {
|
||||
void add_vertex_normals();
|
||||
void add_undisplaced(Scene *scene);
|
||||
void update_generated(Scene *scene);
|
||||
void update_tangents(Scene *scene);
|
||||
void update_tangents(Scene *scene, bool undisplaced);
|
||||
|
||||
void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
|
||||
|
||||
|
||||
@@ -323,6 +323,8 @@ bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progres
|
||||
}
|
||||
}
|
||||
|
||||
mesh->update_tangents(scene, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "scene/shader_nodes.h"
|
||||
#include "kernel/svm/types.h"
|
||||
#include "kernel/types.h"
|
||||
#include "scene/colorspace.h"
|
||||
#include "scene/constant_fold.h"
|
||||
#include "scene/film.h"
|
||||
@@ -7382,13 +7383,15 @@ void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
attributes->add(ATTR_STD_UV_TANGENT);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_UNDISPLACED);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED);
|
||||
}
|
||||
else {
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".undisplaced_tangent").c_str()));
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".undisplaced_tangent_sign").c_str()));
|
||||
}
|
||||
|
||||
attributes->add(ATTR_STD_NORMAL_UNDISPLACED);
|
||||
}
|
||||
|
||||
ShaderNode::attributes(shader, attributes);
|
||||
@@ -7404,13 +7407,14 @@ void NormalMapNode::compile(SVMCompiler &compiler)
|
||||
|
||||
if (space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
|
||||
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
|
||||
attr = compiler.attribute(ATTR_STD_UV_TANGENT_UNDISPLACED);
|
||||
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED);
|
||||
}
|
||||
else {
|
||||
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
||||
attr = compiler.attribute(
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent").c_str()));
|
||||
attr_sign = compiler.attribute(
|
||||
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent_sign").c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7427,13 +7431,15 @@ void NormalMapNode::compile(OSLCompiler &compiler)
|
||||
{
|
||||
if (space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
compiler.parameter("attr_name", ustring("geom:tangent"));
|
||||
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
|
||||
compiler.parameter("attr_name", ustring("geom:undisplaced_tangent"));
|
||||
compiler.parameter("attr_sign_name", ustring("geom:undisplaced_tangent_sign"));
|
||||
}
|
||||
else {
|
||||
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
||||
compiler.parameter("attr_sign_name",
|
||||
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
||||
compiler.parameter("attr_name",
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent").c_str()));
|
||||
compiler.parameter(
|
||||
"attr_sign_name",
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent_sign").c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7656,12 +7662,12 @@ void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *att
|
||||
{
|
||||
if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
attributes->add(ATTR_STD_UV_TANGENT);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_UNDISPLACED);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED);
|
||||
}
|
||||
else {
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".undisplaced_tangent").c_str()));
|
||||
attributes->add(ustring((string(attribute.c_str()) + ".undisplaced_tangent_sign").c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7679,13 +7685,14 @@ void VectorDisplacementNode::compile(SVMCompiler &compiler)
|
||||
|
||||
if (space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
|
||||
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
|
||||
attr = compiler.attribute(ATTR_STD_UV_TANGENT_UNDISPLACED);
|
||||
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN_UNDISPLACED);
|
||||
}
|
||||
else {
|
||||
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
||||
attr = compiler.attribute(
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent").c_str()));
|
||||
attr_sign = compiler.attribute(
|
||||
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent_sign").c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7704,13 +7711,15 @@ void VectorDisplacementNode::compile(OSLCompiler &compiler)
|
||||
{
|
||||
if (space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
compiler.parameter("attr_name", ustring("geom:tangent"));
|
||||
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
|
||||
compiler.parameter("attr_name", ustring("geom:undisplaced_tangent"));
|
||||
compiler.parameter("attr_sign_name", ustring("geom:undisplaced_tangent_sign"));
|
||||
}
|
||||
else {
|
||||
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
||||
compiler.parameter("attr_sign_name",
|
||||
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
||||
compiler.parameter("attr_name",
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent").c_str()));
|
||||
compiler.parameter(
|
||||
"attr_sign_name",
|
||||
ustring((string(attribute.c_str()) + ".undisplaced_tangent_sign").c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user