mirror of
https://github.com/blender/blender
synced 2026-10-25 03:07:01 +03:00
HIP-RT handles visibility at the TLAS instance level, and the motion triangle intersection was using software intersect that accesses the visibility flag, which is redundant. Curve and point primitives were fully relying on the instance visibility mask. The change allows to free the prim_visibility array once the BVH build is finished, to save up GPU memory. This is not done as part of this commit as there seems to be more arrays that are only needed during the build process. It would be easier to have a dedicated patch for this.
190 lines
6.8 KiB
C
190 lines
6.8 KiB
C
/* SPDX-FileCopyrightText: 2014-2022 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
/* Triangle/Ray intersections.
|
|
*
|
|
* For BVH ray intersection we use a precomputed triangle storage to accelerate
|
|
* intersection at the cost of more memory usage.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "kernel/globals.h"
|
|
|
|
#include "kernel/geom/geom_intersect.h"
|
|
#include "kernel/geom/object.h"
|
|
#include "kernel/geom/triangle.h"
|
|
|
|
#include "util/math_float3.h"
|
|
#include "util/math_intersect.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
ccl_device_inline bool triangle_intersect(KernelGlobals kg,
|
|
ccl_private Intersection *isect,
|
|
const float3 P,
|
|
const float3 dir,
|
|
const float tmin,
|
|
const float tmax,
|
|
const uint visibility,
|
|
const int object,
|
|
const int prim,
|
|
const int prim_addr)
|
|
{
|
|
const int position_offset = kernel_data_fetch(objects, object).position_offset;
|
|
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
|
|
const float3 tri_a = kernel_data_fetch(tri_verts, position_offset + tri_vindex.x);
|
|
const float3 tri_b = kernel_data_fetch(tri_verts, position_offset + tri_vindex.y);
|
|
const float3 tri_c = kernel_data_fetch(tri_verts, position_offset + tri_vindex.z);
|
|
|
|
float t;
|
|
float u;
|
|
float v;
|
|
if (ray_triangle_intersect(P, dir, tmin, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
|
|
#if defined(__VISIBILITY_FLAG__) && !defined(__KERNEL_HIPRT__)
|
|
/* Visibility flag test. we do it here under the assumption that most triangles are culled by
|
|
* node flags.
|
|
* Note that HIP-RT performs visibility check on the instance level. */
|
|
if (kernel_data_fetch(prim_visibility, prim_addr) & visibility)
|
|
#endif
|
|
{
|
|
isect->object = object;
|
|
isect->prim = prim;
|
|
isect->type = PRIMITIVE_TRIANGLE;
|
|
isect->u = u;
|
|
isect->v = v;
|
|
isect->t = t;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Special ray intersection routines for subsurface scattering. In that case we
|
|
* only want to intersect with primitives in the same object, and if case of
|
|
* multiple hits we pick a single random primitive as the intersection point.
|
|
* Returns whether traversal should be stopped.
|
|
*/
|
|
|
|
#ifdef __BVH_LOCAL__
|
|
ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
|
|
ccl_private LocalIntersection *local_isect,
|
|
const float3 P,
|
|
const float3 dir,
|
|
const int object,
|
|
const int prim,
|
|
const float tmin,
|
|
const float tmax,
|
|
ccl_private uint *lcg_state,
|
|
const int max_hits)
|
|
{
|
|
const int position_offset = kernel_data_fetch(objects, object).position_offset;
|
|
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
|
|
const float3 tri_a = kernel_data_fetch(tri_verts, position_offset + tri_vindex.x);
|
|
const float3 tri_b = kernel_data_fetch(tri_verts, position_offset + tri_vindex.y);
|
|
const float3 tri_c = kernel_data_fetch(tri_verts, position_offset + tri_vindex.z);
|
|
|
|
float t;
|
|
float u;
|
|
float v;
|
|
if (!ray_triangle_intersect(P, dir, tmin, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
|
|
return false;
|
|
}
|
|
|
|
/* If no actual hit information is requested, just return here. */
|
|
if (max_hits == 0) {
|
|
return true;
|
|
}
|
|
|
|
const int hit_index = local_intersect_get_record_index(local_isect, t, lcg_state, max_hits);
|
|
if (hit_index == -1) {
|
|
return false;
|
|
}
|
|
|
|
/* Record intersection. */
|
|
ccl_private Intersection *isect = &local_isect->hits[hit_index];
|
|
isect->prim = prim;
|
|
isect->object = object;
|
|
isect->type = PRIMITIVE_TRIANGLE;
|
|
isect->u = u;
|
|
isect->v = v;
|
|
isect->t = t;
|
|
|
|
/* Record geometric normal. */
|
|
local_isect->Ng[hit_index] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
|
|
|
|
return false;
|
|
}
|
|
#endif /* __BVH_LOCAL__ */
|
|
|
|
/**
|
|
* Use the barycentric coordinates to get the intersection location
|
|
*/
|
|
ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg,
|
|
ccl_private ShaderData *sd,
|
|
const int isect_prim,
|
|
const float u,
|
|
const float v)
|
|
{
|
|
const int position_offset = kernel_data_fetch(objects, sd->object).position_offset;
|
|
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, isect_prim);
|
|
const float3 tri_a = kernel_data_fetch(tri_verts, position_offset + tri_vindex.x);
|
|
const float3 tri_b = kernel_data_fetch(tri_verts, position_offset + tri_vindex.y);
|
|
const float3 tri_c = kernel_data_fetch(tri_verts, position_offset + tri_vindex.z);
|
|
|
|
/* This appears to give slightly better precision than interpolating with w = (1 - u - v). */
|
|
float3 P = tri_a + u * (tri_b - tri_a) + v * (tri_c - tri_a);
|
|
|
|
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
|
const Transform tfm = object_get_transform(kg, sd);
|
|
P = transform_point(&tfm, P);
|
|
}
|
|
|
|
return P;
|
|
}
|
|
|
|
/**
|
|
* Use the barycentric coordinates to get the intersection location,
|
|
* but with vertex coordinates specified.
|
|
*/
|
|
ccl_device_inline float3 triangle_point_from_uv_and_verts(KernelGlobals kg,
|
|
ccl_private ShaderData *sd,
|
|
const float u,
|
|
const float v,
|
|
const float3 verts[3])
|
|
{
|
|
/* This appears to give slightly better precision than interpolating with w = (1 - u - v). */
|
|
float3 P = verts[0] + u * (verts[1] - verts[0]) + v * (verts[2] - verts[0]);
|
|
|
|
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
|
const Transform tfm = object_get_transform(kg, sd);
|
|
P = transform_point(&tfm, P);
|
|
}
|
|
|
|
return P;
|
|
}
|
|
|
|
ccl_device_inline void triangle_shader_setup(KernelGlobals kg, ccl_private ShaderData *sd)
|
|
{
|
|
sd->shader = kernel_data_fetch(tri_shader, sd->prim);
|
|
|
|
sd->P = triangle_point_from_uv(kg, sd, sd->prim, sd->u, sd->v);
|
|
|
|
/* Normals. */
|
|
const float3 Ng = triangle_normal(kg, sd);
|
|
sd->Ng = Ng;
|
|
sd->N = Ng;
|
|
|
|
/* Smooth normal. */
|
|
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
|
sd->N = triangle_smooth_normal(kg, Ng, sd->object, sd->object_flag, sd->prim, sd->u, sd->v);
|
|
}
|
|
|
|
#ifdef __DPDU__
|
|
/* dPdu/dPdv */
|
|
triangle_dPdudv(kg, sd->object, sd->prim, &sd->dPdu, &sd->dPdv);
|
|
#endif
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|