mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Fix #154166: Cycles: Raycast + Bump artifacts
The raycast node disables self intersection when the ray start is the surface position. However, this fails when evaluating bump. This commit adds an extra offset to the ray start (tmin) when evaluating bump. Co-authored-by: Brecht Van Lommel <brecht@blender.org> Pull Request: https://projects.blender.org/blender/blender/pulls/154222
This commit is contained in:
parent
c806cc465c
commit
7da2065b9d
12 changed files with 66 additions and 18 deletions
|
|
@ -759,25 +759,21 @@ bool OSLRenderServices::trace(TraceOpt &options,
|
|||
|
||||
ray.P = make_float3(P.x, P.y, P.z);
|
||||
ray.D = make_float3(R.x, R.y, R.z);
|
||||
ray.tmin = 0.0f;
|
||||
ray.tmax = (options.maxdist == 1.0e30f) ? FLT_MAX : options.maxdist - options.mindist;
|
||||
ray.tmin = options.mindist;
|
||||
ray.tmax = (options.maxdist == 1.0e30f) ? FLT_MAX : options.maxdist;
|
||||
ray.time = sd->time;
|
||||
ray.self.object = OBJECT_NONE;
|
||||
ray.self.prim = PRIM_NONE;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
|
||||
if (options.mindist == 0.0f) {
|
||||
if (ray.tmin == 0.0f) {
|
||||
/* avoid self-intersections */
|
||||
if (ray.P == sd->P) {
|
||||
ray.self.object = sd->object;
|
||||
ray.self.prim = sd->prim;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* offset for minimum distance */
|
||||
ray.P += options.mindist * ray.D;
|
||||
}
|
||||
|
||||
/* ray differentials */
|
||||
differential3 dP;
|
||||
|
|
|
|||
|
|
@ -8,14 +8,29 @@ shader node_raycast(point Position = P,
|
|||
normal Direction = N,
|
||||
float Length = 1.0,
|
||||
int only_local = 0,
|
||||
float bump_filter_width = 0.0,
|
||||
output float IsHit = 0.0,
|
||||
output float SelfHit = 0.0,
|
||||
output float HitDistance = Length,
|
||||
output point HitPosition = point(0.0, 0.0, 0.0),
|
||||
output normal HitNormal = normal(0.0, 0.0, 0.0))
|
||||
{
|
||||
if (trace(
|
||||
Position, Direction, "maxdist", Length, "traceset", only_local ? "__only_local__" : ""))
|
||||
float mindist = 0.0;
|
||||
if (bump_filter_width > 0.0) {
|
||||
/* If evaluating for bump mapping at a shifted position, increase min
|
||||
* distance by slightly more than the shift distance to avoid self
|
||||
* intersections. */
|
||||
mindist = bump_filter_width * max(length(Dx(P)), length(Dy(P))) * 1.1;
|
||||
}
|
||||
|
||||
if (trace(Position,
|
||||
Direction,
|
||||
"maxdist",
|
||||
Length,
|
||||
"mindist",
|
||||
mindist,
|
||||
"traceset",
|
||||
only_local ? "__only_local__" : ""))
|
||||
{
|
||||
IsHit = 1.0;
|
||||
getmessage("trace", "hitself", SelfHit);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ ccl_device RaycastResult svm_raycast(KernelGlobals kg,
|
|||
float3 position,
|
||||
float3 direction,
|
||||
float distance,
|
||||
bool only_local)
|
||||
bool only_local,
|
||||
float bump_filter_width)
|
||||
{
|
||||
RaycastResult result;
|
||||
result.distance = -1.0f;
|
||||
|
|
@ -49,13 +50,23 @@ ccl_device RaycastResult svm_raycast(KernelGlobals kg,
|
|||
return result;
|
||||
}
|
||||
|
||||
const bool avoid_self_intersection = isequal(position, sd->P);
|
||||
float tmin = 0.0f;
|
||||
bool avoid_self_intersection = false;
|
||||
if (bump_filter_width > 0.0f) {
|
||||
/* If evaluating for bump mapping at a shifted position, increase min
|
||||
* distance by slightly more than the shift distance to avoid self
|
||||
* intersections. */
|
||||
tmin = bump_filter_width * sd->dP * 1.1f;
|
||||
}
|
||||
else {
|
||||
avoid_self_intersection = isequal(position, sd->P);
|
||||
}
|
||||
|
||||
/* Create ray. */
|
||||
Ray ray;
|
||||
ray.P = position;
|
||||
ray.D = direction;
|
||||
ray.tmin = 0.0f;
|
||||
ray.tmin = tmin;
|
||||
ray.tmax = distance;
|
||||
ray.time = sd->time;
|
||||
ray.self.object = avoid_self_intersection ? sd->object : OBJECT_NONE;
|
||||
|
|
@ -99,12 +110,13 @@ ccl_device_inline
|
|||
# else
|
||||
ccl_device_noinline
|
||||
# endif
|
||||
void
|
||||
int
|
||||
svm_node_raycast(KernelGlobals kg,
|
||||
ConstIntegratorGenericState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const uint4 node)
|
||||
const uint4 node,
|
||||
int offset)
|
||||
{
|
||||
uint position_offset;
|
||||
uint direction_offset;
|
||||
|
|
@ -128,13 +140,17 @@ ccl_device_noinline
|
|||
float3 hit_position = make_float3(0.0f);
|
||||
float3 hit_normal = make_float3(0.0f);
|
||||
|
||||
uint4 data_node = read_node(kg, &offset);
|
||||
|
||||
IF_KERNEL_NODES_FEATURE(RAYTRACE)
|
||||
{
|
||||
uint only_local = node.w;
|
||||
const uint only_local = node.w;
|
||||
const float bump_filter_width = __uint_as_float(data_node.x);
|
||||
|
||||
float3 position = stack_load_float3(stack, position_offset);
|
||||
float3 direction = stack_load_float3(stack, direction_offset);
|
||||
RaycastResult result = svm_raycast(kg, state, sd, position, direction, distance, only_local);
|
||||
RaycastResult result = svm_raycast(
|
||||
kg, state, sd, position, direction, distance, only_local, bump_filter_width);
|
||||
|
||||
if (result.distance >= 0.0f) {
|
||||
is_hit = 1.0f;
|
||||
|
|
@ -160,6 +176,8 @@ ccl_device_noinline
|
|||
if (stack_valid(hit_normal_offset)) {
|
||||
stack_store_float3(stack, hit_normal_offset, hit_normal);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
#endif /* __SHADER_RAYTRACE__ */
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
|
|||
svm_node_ao<node_feature_mask>(kg, state, sd, stack, node);
|
||||
break;
|
||||
SVM_CASE(NODE_RAYCAST)
|
||||
svm_node_raycast<node_feature_mask>(kg, state, sd, stack, node);
|
||||
offset = svm_node_raycast<node_feature_mask>(kg, state, sd, stack, node, offset);
|
||||
break;
|
||||
#endif
|
||||
SVM_CASE(NODE_AOV_START)
|
||||
|
|
|
|||
|
|
@ -8100,11 +8100,13 @@ void RaycastNode::compile(SVMCompiler &compiler)
|
|||
compiler.stack_assign(hit_position_out),
|
||||
compiler.stack_assign(hit_normal_out)),
|
||||
only_local);
|
||||
compiler.add_node(__float_as_uint((bump == SHADER_BUMP_CENTER) ? 0.0f : bump_filter_width));
|
||||
}
|
||||
|
||||
void RaycastNode::compile(OSLCompiler &compiler)
|
||||
{
|
||||
compiler.parameter(this, "only_local");
|
||||
compiler.parameter("bump_filter_width", (bump == SHADER_BUMP_CENTER) ? 0.0f : bump_filter_width);
|
||||
compiler.add(this, "node_raycast");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a63f5f6c3c1866c63da28bfff8d9aadd850863225f5ece71e7bc954a4537efe5
|
||||
size 20803
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4d960bddd7a224162467d1e79f1ed33898e85a040557dc1ed68c94f6fafdc7cb
|
||||
size 26302
|
||||
3
tests/files/render/raycast/raycast_bump.blend
Normal file
3
tests/files/render/raycast/raycast_bump.blend
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e3b9bd75e9afbe0cf486b05bdb190c65e3f8994c59db9a043b00e593ef75e70a
|
||||
size 133815
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b8f0b7a04f7c214a49b91dc8a745fa23420fa31ae36032e21d81c7b6d9bac2b4
|
||||
size 746
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b8f0b7a04f7c214a49b91dc8a745fa23420fa31ae36032e21d81c7b6d9bac2b4
|
||||
size 746
|
||||
|
|
@ -42,6 +42,8 @@ BLOCKLIST = [
|
|||
"light_path_is_diffuse_ray.blend",
|
||||
# Blocked due to stochastic diffuse/transmission layering resulting in non-deterministic surfel lighting.
|
||||
"principled_bsdf_transmission.blend",
|
||||
# Blocked due to platform-dependent noise differences (likely floating-point/fast-math differences).
|
||||
"raycast_bump.blend",
|
||||
]
|
||||
|
||||
BLOCKLIST_METAL = [
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ def main():
|
|||
parser = create_argparse()
|
||||
args = parser.parse_args()
|
||||
|
||||
blocklist = ["raycast_hit.blend", "raycast_normal.blend", "raycast_position.blend"]
|
||||
blocklist = ["raycast_hit.blend", "raycast_normal.blend", "raycast_position.blend", "raycast_bump.blend"]
|
||||
if args.gpu_backend == "vulkan":
|
||||
blocklist += BLOCKLIST_VULKAN
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue