raytracing refactors, lightmap caustics fix
This commit is contained in:
@@ -15,26 +15,22 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
return;
|
||||
}
|
||||
float3 result = 0;
|
||||
float3 energy = 1;
|
||||
|
||||
// Compute screen coordinates:
|
||||
float2 screenUV = float2((pixel + xTracePixelOffset) * xTraceResolution_rcp.xy * 2.0f - 1.0f) * float2(1, -1);
|
||||
float2 uv = float2((pixel + xTracePixelOffset) * xTraceResolution_rcp.xy * 2 - 1) * float2(1, -1);
|
||||
float seed = xTraceRandomSeed;
|
||||
|
||||
// Create starting ray:
|
||||
Ray ray = CreateCameraRay(screenUV);
|
||||
RayDesc ray = CreateCameraRay(uv);
|
||||
|
||||
uint bounces = xTraceUserData.x;
|
||||
const uint bouncelimit = 16;
|
||||
for (uint bounce = 0; ((bounce < min(bounces, bouncelimit)) && any(ray.energy)); ++bounce)
|
||||
for (uint bounce = 0; ((bounce < min(bounces, bouncelimit)) && any(energy)); ++bounce)
|
||||
{
|
||||
ray.Update();
|
||||
ray.Direction = normalize(ray.Direction);
|
||||
|
||||
#ifdef RTAPI
|
||||
RayDesc apiray;
|
||||
apiray.TMin = 0.001;
|
||||
apiray.TMax = FLT_MAX;
|
||||
apiray.Origin = ray.origin;
|
||||
apiray.Direction = ray.direction;
|
||||
RayQuery<
|
||||
RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES
|
||||
> q;
|
||||
@@ -46,7 +42,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
RAY_FLAG_FORCE_OPAQUE |
|
||||
0, // uint RayFlags
|
||||
0xFF, // uint InstanceInclusionMask
|
||||
apiray // RayDesc Ray
|
||||
ray // RayDesc Ray
|
||||
);
|
||||
q.Proceed();
|
||||
if (q.CommittedStatus() != COMMITTED_TRIANGLE_HIT)
|
||||
@@ -62,16 +58,16 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
if (IsStaticSky())
|
||||
{
|
||||
// We have envmap information in a texture:
|
||||
envColor = DEGAMMA_SKY(texture_globalenvmap.SampleLevel(sampler_linear_clamp, ray.direction, 0).rgb);
|
||||
envColor = DEGAMMA_SKY(texture_globalenvmap.SampleLevel(sampler_linear_clamp, ray.Direction, 0).rgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
envColor = GetDynamicSkyColor(ray.direction);
|
||||
envColor = GetDynamicSkyColor(ray.Direction);
|
||||
}
|
||||
result += max(0, ray.energy * envColor);
|
||||
result += max(0, energy * envColor);
|
||||
|
||||
// Erase the ray's energy
|
||||
ray.energy = 0.0f;
|
||||
energy = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -80,7 +76,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
|
||||
#ifdef RTAPI
|
||||
// ray origin updated for next bounce:
|
||||
ray.origin = q.WorldRayOrigin() + q.WorldRayDirection() * q.CommittedRayT();
|
||||
ray.Origin = q.WorldRayOrigin() + q.WorldRayDirection() * q.CommittedRayT();
|
||||
|
||||
ShaderMesh mesh = bindless_buffers[q.CommittedInstanceID()].Load<ShaderMesh>(0);
|
||||
ShaderMeshSubset subset = bindless_subsets[mesh.subsetbuffer][q.CommittedGeometryIndex()];
|
||||
@@ -98,7 +94,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
|
||||
#else
|
||||
// ray origin updated for next bounce:
|
||||
ray.origin = hit.position;
|
||||
ray.Origin = ray.Origin + ray.Direction * hit.distance;
|
||||
|
||||
EvaluateObjectSurface(
|
||||
hit,
|
||||
@@ -108,24 +104,24 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
|
||||
#endif // RTAPI
|
||||
|
||||
surface.P = ray.origin;
|
||||
surface.P = ray.Origin;
|
||||
surface.V = normalize(g_xCamera_CamPos - surface.P);
|
||||
surface.update();
|
||||
|
||||
float3 current_energy = ray.energy;
|
||||
float3 current_energy = energy;
|
||||
result += max(0, current_energy * surface.emissiveColor.rgb * surface.emissiveColor.a);
|
||||
|
||||
|
||||
float roulette;
|
||||
|
||||
const float blendChance = 1 - surface.opacity;
|
||||
roulette = rand(seed, screenUV);
|
||||
roulette = rand(seed, uv);
|
||||
if (roulette < blendChance)
|
||||
{
|
||||
// Alpha blending
|
||||
|
||||
// The ray penetrates the surface, so push DOWN along normal to avoid self-intersection:
|
||||
ray.origin = trace_bias_position(ray.origin, -surface.N);
|
||||
ray.Origin = trace_bias_position(ray.Origin, -surface.N);
|
||||
|
||||
// Add a new bounce iteration, otherwise the transparent effect can disappear:
|
||||
bounces++;
|
||||
@@ -135,54 +131,54 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
else
|
||||
{
|
||||
const float refractChance = surface.transmission;
|
||||
roulette = rand(seed, screenUV);
|
||||
roulette = rand(seed, uv);
|
||||
if (roulette < refractChance)
|
||||
{
|
||||
// Refraction
|
||||
const float3 R = refract(ray.direction, surface.N, 1 - material.refraction);
|
||||
ray.direction = lerp(R, SampleHemisphere_cos(R, seed, screenUV), surface.roughnessBRDF);
|
||||
ray.energy *= surface.albedo;
|
||||
const float3 R = refract(ray.Direction, surface.N, 1 - material.refraction);
|
||||
ray.Direction = lerp(R, SampleHemisphere_cos(R, seed, uv), surface.roughnessBRDF);
|
||||
energy *= surface.albedo;
|
||||
|
||||
// The ray penetrates the surface, so push DOWN along normal to avoid self-intersection:
|
||||
ray.origin = trace_bias_position(ray.origin, -surface.N);
|
||||
ray.Origin = trace_bias_position(ray.Origin, -surface.N);
|
||||
|
||||
// Add a new bounce iteration, otherwise the transparent effect can disappear:
|
||||
bounces++;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float3 F = F_Schlick(surface.f0, saturate(dot(-ray.direction, surface.N)));
|
||||
const float3 F = F_Schlick(surface.f0, saturate(dot(-ray.Direction, surface.N)));
|
||||
const float specChance = dot(F, 0.333);
|
||||
|
||||
roulette = rand(seed, screenUV);
|
||||
roulette = rand(seed, uv);
|
||||
if (roulette < specChance)
|
||||
{
|
||||
// Specular reflection
|
||||
const float3 R = reflect(ray.direction, surface.N);
|
||||
ray.direction = lerp(R, SampleHemisphere_cos(R, seed, screenUV), surface.roughnessBRDF);
|
||||
ray.energy *= F / specChance;
|
||||
const float3 R = reflect(ray.Direction, surface.N);
|
||||
ray.Direction = lerp(R, SampleHemisphere_cos(R, seed, uv), surface.roughnessBRDF);
|
||||
energy *= F / specChance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Diffuse reflection
|
||||
ray.direction = SampleHemisphere_cos(surface.N, seed, screenUV);
|
||||
ray.energy *= surface.albedo / (1 - specChance);
|
||||
ray.Direction = SampleHemisphere_cos(surface.N, seed, uv);
|
||||
energy *= surface.albedo / (1 - specChance);
|
||||
}
|
||||
|
||||
if (dot(ray.direction, surface.facenormal) <= 0)
|
||||
if (dot(ray.Direction, surface.facenormal) <= 0)
|
||||
{
|
||||
// Don't allow normal map to bend over the face normal more than 90 degrees to avoid light leaks
|
||||
// In this case, we will not allow more bounces,
|
||||
// but the current light sampling is still fine to avoid abrupt cutoff
|
||||
ray.energy = 0;
|
||||
energy = 0;
|
||||
}
|
||||
|
||||
// Ray reflects from surface, so push UP along normal to avoid self-intersection:
|
||||
ray.origin = trace_bias_position(ray.origin, surface.N);
|
||||
ray.Origin = trace_bias_position(ray.Origin, surface.N);
|
||||
}
|
||||
}
|
||||
|
||||
surface.P = ray.origin;
|
||||
surface.P = ray.Origin;
|
||||
|
||||
float3 lightColor = 0;
|
||||
SurfaceToLight surfaceToLight = (SurfaceToLight)0;
|
||||
@@ -291,24 +287,19 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
{
|
||||
float3 shadow = surfaceToLight.NdotL * current_energy;
|
||||
|
||||
float3 sampling_offset = float3(rand(seed, screenUV), rand(seed, screenUV), rand(seed, screenUV)) * 2 - 1; // todo: should be specific to light surface
|
||||
float3 sampling_offset = float3(rand(seed, uv), rand(seed, uv), rand(seed, uv)) * 2 - 1; // todo: should be specific to light surface
|
||||
|
||||
Ray newRay;
|
||||
newRay.origin = surface.P;
|
||||
newRay.direction = L + sampling_offset * 0.025;
|
||||
newRay.energy = 0;
|
||||
newRay.Update();
|
||||
RayDesc newRay;
|
||||
newRay.Origin = surface.P;
|
||||
newRay.Direction = normalize(L + sampling_offset * 0.025);
|
||||
newRay.TMin = 0.001;
|
||||
newRay.TMax = dist;
|
||||
#ifdef RTAPI
|
||||
RayDesc apiray;
|
||||
apiray.TMin = 0.001;
|
||||
apiray.TMax = dist;
|
||||
apiray.Origin = newRay.origin;
|
||||
apiray.Direction = newRay.direction;
|
||||
q.TraceRayInline(
|
||||
scene_acceleration_structure, // RaytracingAccelerationStructure AccelerationStructure
|
||||
0, // uint RayFlags
|
||||
0xFF, // uint InstanceInclusionMask
|
||||
apiray // RayDesc Ray
|
||||
newRay // RayDesc Ray
|
||||
);
|
||||
while (q.Proceed())
|
||||
{
|
||||
@@ -342,7 +333,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
}
|
||||
shadow = q.CommittedStatus() == COMMITTED_TRIANGLE_HIT ? 0 : shadow;
|
||||
#else
|
||||
shadow = TraceRay_Any(newRay, dist, groupIndex) ? 0 : shadow;
|
||||
shadow = TraceRay_Any(newRay, groupIndex) ? 0 : shadow;
|
||||
#endif // RTAPI
|
||||
if (any(shadow))
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
float4 main(float4 pos : SV_POSITION, float2 clipspace : TEXCOORD) : SV_Target
|
||||
{
|
||||
Ray ray = CreateCameraRay(clipspace);
|
||||
RayDesc ray = CreateCameraRay(clipspace);
|
||||
|
||||
uint hitCount = TraceRay_DebugBVH(ray);
|
||||
|
||||
@@ -28,4 +28,4 @@ float4 main(float4 pos : SV_POSITION, float2 clipspace : TEXCOORD) : SV_Target
|
||||
float4 heatmap = float4(lerp(a, b, l - floor(l)), 0.8f);
|
||||
|
||||
return heatmap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,38 +13,28 @@ inline float3 trace_bias_position(in float3 P, in float3 N)
|
||||
return P + N * 0.0001;
|
||||
}
|
||||
|
||||
struct Ray
|
||||
#ifdef HLSL5
|
||||
struct RayDesc
|
||||
{
|
||||
float3 origin;
|
||||
float3 direction;
|
||||
float3 direction_rcp;
|
||||
float3 energy;
|
||||
|
||||
inline void Update()
|
||||
{
|
||||
direction_rcp = rcp(direction);
|
||||
}
|
||||
float3 Origin;
|
||||
float TMin;
|
||||
float3 Direction;
|
||||
float TMax;
|
||||
};
|
||||
#endif // HLSL5
|
||||
|
||||
inline Ray CreateRay(float3 origin, float3 direction)
|
||||
{
|
||||
Ray ray;
|
||||
ray.origin = origin;
|
||||
ray.direction = normalize(direction);
|
||||
ray.energy = float3(1, 1, 1);
|
||||
ray.Update();
|
||||
return ray;
|
||||
}
|
||||
|
||||
inline Ray CreateCameraRay(float2 clipspace)
|
||||
inline RayDesc CreateCameraRay(float2 clipspace)
|
||||
{
|
||||
float4 unprojected = mul(g_xCamera_InvVP, float4(clipspace, 0, 1));
|
||||
unprojected.xyz /= unprojected.w;
|
||||
|
||||
const float3 origin = g_xCamera_CamPos;
|
||||
const float3 direction = normalize(unprojected.xyz - origin);
|
||||
RayDesc ray;
|
||||
ray.Origin = g_xCamera_CamPos;
|
||||
ray.Direction = normalize(unprojected.xyz - ray.Origin);
|
||||
ray.TMin = 0.001;
|
||||
ray.TMax = FLT_MAX;
|
||||
|
||||
return CreateRay(origin, direction);
|
||||
return ray;
|
||||
}
|
||||
|
||||
#ifdef RTAPI
|
||||
@@ -211,19 +201,17 @@ STRUCTUREDBUFFER(bvhNodeBuffer, BVHNode, TEXSLOT_ONDEMAND5);
|
||||
|
||||
struct RayHit
|
||||
{
|
||||
float distance;
|
||||
float3 position;
|
||||
uint primitiveID;
|
||||
float2 bary;
|
||||
float distance;
|
||||
uint primitiveID;
|
||||
};
|
||||
|
||||
inline RayHit CreateRayHit()
|
||||
{
|
||||
RayHit hit;
|
||||
hit.distance = FLT_MAX;
|
||||
hit.position = 0;
|
||||
hit.primitiveID = 0xFFFFFFFF;
|
||||
hit.bary = 0;
|
||||
hit.distance = FLT_MAX;
|
||||
hit.primitiveID = ~0u;
|
||||
return hit;
|
||||
}
|
||||
|
||||
@@ -330,7 +318,7 @@ void EvaluateObjectSurface(
|
||||
}
|
||||
|
||||
inline void IntersectTriangle(
|
||||
in Ray ray,
|
||||
in RayDesc ray,
|
||||
inout RayHit bestHit,
|
||||
in BVHPrimitive prim,
|
||||
uint primitiveID
|
||||
@@ -338,7 +326,7 @@ inline void IntersectTriangle(
|
||||
{
|
||||
float3 v0v1 = prim.v1() - prim.v0();
|
||||
float3 v0v2 = prim.v2() - prim.v0();
|
||||
float3 pvec = cross(ray.direction, v0v2);
|
||||
float3 pvec = cross(ray.Direction, v0v2);
|
||||
float det = dot(v0v1, pvec);
|
||||
#ifdef RAY_BACKFACE_CULLING
|
||||
// if the determinant is negative the triangle is backfacing
|
||||
@@ -352,60 +340,57 @@ inline void IntersectTriangle(
|
||||
#endif
|
||||
float invDet = 1 / det;
|
||||
|
||||
float3 tvec = ray.origin - prim.v0();
|
||||
float3 tvec = ray.Origin - prim.v0();
|
||||
float u = dot(tvec, pvec) * invDet;
|
||||
if (u < 0 || u > 1)
|
||||
return;
|
||||
|
||||
float3 qvec = cross(tvec, v0v1);
|
||||
float v = dot(ray.direction, qvec) * invDet;
|
||||
float v = dot(ray.Direction, qvec) * invDet;
|
||||
if (v < 0 || u + v > 1)
|
||||
return;
|
||||
|
||||
float t = dot(v0v2, qvec) * invDet;
|
||||
|
||||
if (t > 0 && t < bestHit.distance)
|
||||
if (t >= ray.TMin && t <= bestHit.distance)
|
||||
{
|
||||
bestHit.distance = t;
|
||||
bestHit.position = ray.origin + t * ray.direction;
|
||||
bestHit.primitiveID = primitiveID;
|
||||
bestHit.bary = float2(u, v);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IntersectTriangleANY(
|
||||
in Ray ray,
|
||||
in float maxDistance,
|
||||
in RayDesc ray,
|
||||
in BVHPrimitive prim,
|
||||
uint primitiveID
|
||||
)
|
||||
{
|
||||
float3 v0v1 = prim.v1() - prim.v0();
|
||||
float3 v0v2 = prim.v2() - prim.v0();
|
||||
float3 pvec = cross(ray.direction, v0v2);
|
||||
float3 pvec = cross(ray.Direction, v0v2);
|
||||
float det = dot(v0v1, pvec);
|
||||
// ray and triangle are parallel if det is close to 0
|
||||
if (abs(det) < 0.000001)
|
||||
return false;
|
||||
float invDet = 1 / det;
|
||||
|
||||
float3 tvec = ray.origin - prim.v0();
|
||||
float3 tvec = ray.Origin - prim.v0();
|
||||
float u = dot(tvec, pvec) * invDet;
|
||||
if (u < 0 || u > 1)
|
||||
return false;
|
||||
|
||||
float3 qvec = cross(tvec, v0v1);
|
||||
float v = dot(ray.direction, qvec) * invDet;
|
||||
float v = dot(ray.Direction, qvec) * invDet;
|
||||
if (v < 0 || u + v > 1)
|
||||
return false;
|
||||
|
||||
float t = dot(v0v2, qvec) * invDet;
|
||||
|
||||
if (t > 0 && t < maxDistance)
|
||||
if (t >= ray.TMin && t <= ray.TMax)
|
||||
{
|
||||
RayHit hit;
|
||||
hit.distance = t;
|
||||
hit.position = ray.origin + t * ray.direction;
|
||||
hit.primitiveID = primitiveID;
|
||||
hit.bary = float2(u, v);
|
||||
|
||||
@@ -440,14 +425,19 @@ inline bool IntersectTriangleANY(
|
||||
}
|
||||
|
||||
|
||||
inline bool IntersectNode(in Ray ray, in BVHNode box, in float primitive_best_distance)
|
||||
inline bool IntersectNode(
|
||||
in RayDesc ray,
|
||||
in BVHNode box,
|
||||
in float3 rcpDirection,
|
||||
in float primitive_best_distance
|
||||
)
|
||||
{
|
||||
const float t0 = (box.min.x - ray.origin.x) * ray.direction_rcp.x;
|
||||
const float t1 = (box.max.x - ray.origin.x) * ray.direction_rcp.x;
|
||||
const float t2 = (box.min.y - ray.origin.y) * ray.direction_rcp.y;
|
||||
const float t3 = (box.max.y - ray.origin.y) * ray.direction_rcp.y;
|
||||
const float t4 = (box.min.z - ray.origin.z) * ray.direction_rcp.z;
|
||||
const float t5 = (box.max.z - ray.origin.z) * ray.direction_rcp.z;
|
||||
const float t0 = (box.min.x - ray.Origin.x) * rcpDirection.x;
|
||||
const float t1 = (box.max.x - ray.Origin.x) * rcpDirection.x;
|
||||
const float t2 = (box.min.y - ray.Origin.y) * rcpDirection.y;
|
||||
const float t3 = (box.max.y - ray.Origin.y) * rcpDirection.y;
|
||||
const float t4 = (box.min.z - ray.Origin.z) * rcpDirection.z;
|
||||
const float t5 = (box.max.z - ray.Origin.z) * rcpDirection.z;
|
||||
const float tmin = max(max(min(t0, t1), min(t2, t3)), min(t4, t5)); // close intersection point's distance on ray
|
||||
const float tmax = min(min(max(t0, t1), max(t2, t3)), max(t4, t5)); // far intersection point's distance on ray
|
||||
|
||||
@@ -460,14 +450,18 @@ inline bool IntersectNode(in Ray ray, in BVHNode box, in float primitive_best_di
|
||||
return true;
|
||||
}
|
||||
}
|
||||
inline bool IntersectNode(in Ray ray, in BVHNode box)
|
||||
inline bool IntersectNode(
|
||||
in RayDesc ray,
|
||||
in BVHNode box,
|
||||
in float3 rcpDirection
|
||||
)
|
||||
{
|
||||
const float t0 = (box.min.x - ray.origin.x) * ray.direction_rcp.x;
|
||||
const float t1 = (box.max.x - ray.origin.x) * ray.direction_rcp.x;
|
||||
const float t2 = (box.min.y - ray.origin.y) * ray.direction_rcp.y;
|
||||
const float t3 = (box.max.y - ray.origin.y) * ray.direction_rcp.y;
|
||||
const float t4 = (box.min.z - ray.origin.z) * ray.direction_rcp.z;
|
||||
const float t5 = (box.max.z - ray.origin.z) * ray.direction_rcp.z;
|
||||
const float t0 = (box.min.x - ray.Origin.x) * rcpDirection.x;
|
||||
const float t1 = (box.max.x - ray.Origin.x) * rcpDirection.x;
|
||||
const float t2 = (box.min.y - ray.Origin.y) * rcpDirection.y;
|
||||
const float t3 = (box.max.y - ray.Origin.y) * rcpDirection.y;
|
||||
const float t4 = (box.min.z - ray.Origin.z) * rcpDirection.z;
|
||||
const float t5 = (box.max.z - ray.Origin.z) * rcpDirection.z;
|
||||
const float tmin = max(max(min(t0, t1), min(t2, t3)), min(t4, t5)); // close intersection point's distance on ray
|
||||
const float tmax = min(min(max(t0, t1), max(t2, t3)), max(t4, t5)); // far intersection point's distance on ray
|
||||
|
||||
@@ -476,8 +470,10 @@ inline bool IntersectNode(in Ray ray, in BVHNode box)
|
||||
|
||||
|
||||
// Returns the closest hit primitive if any (useful for generic trace). If nothing was hit, then rayHit.distance will be equal to FLT_MAX
|
||||
inline RayHit TraceRay_Closest(Ray ray, uint groupIndex = 0)
|
||||
inline RayHit TraceRay_Closest(RayDesc ray, uint groupIndex = 0)
|
||||
{
|
||||
const float3 rcpDirection = rcp(ray.Direction);
|
||||
|
||||
RayHit bestHit = CreateRayHit();
|
||||
|
||||
#ifndef RAYTRACE_STACK_SHARED
|
||||
@@ -498,7 +494,7 @@ inline RayHit TraceRay_Closest(Ray ray, uint groupIndex = 0)
|
||||
|
||||
BVHNode node = bvhNodeBuffer[nodeIndex];
|
||||
|
||||
if (IntersectNode(ray, node, bestHit.distance))
|
||||
if (IntersectNode(ray, node, rcpDirection, bestHit.distance))
|
||||
{
|
||||
if (nodeIndex >= leafNodeOffset)
|
||||
{
|
||||
@@ -533,8 +529,10 @@ inline RayHit TraceRay_Closest(Ray ray, uint groupIndex = 0)
|
||||
}
|
||||
|
||||
// Returns true immediately if any primitives were hit, flase if nothing was hit (useful for opaque shadows):
|
||||
inline bool TraceRay_Any(Ray ray, float maxDistance, uint groupIndex = 0)
|
||||
inline bool TraceRay_Any(RayDesc ray, uint groupIndex = 0)
|
||||
{
|
||||
const float3 rcpDirection = rcp(ray.Direction);
|
||||
|
||||
bool shadow = false;
|
||||
|
||||
#ifndef RAYTRACE_STACK_SHARED
|
||||
@@ -555,7 +553,7 @@ inline bool TraceRay_Any(Ray ray, float maxDistance, uint groupIndex = 0)
|
||||
|
||||
BVHNode node = bvhNodeBuffer[nodeIndex];
|
||||
|
||||
if (IntersectNode(ray, node))
|
||||
if (IntersectNode(ray, node, rcpDirection))
|
||||
{
|
||||
if (nodeIndex >= leafNodeOffset)
|
||||
{
|
||||
@@ -563,7 +561,7 @@ inline bool TraceRay_Any(Ray ray, float maxDistance, uint groupIndex = 0)
|
||||
const uint primitiveID = node.LeftChildIndex;
|
||||
const BVHPrimitive prim = primitiveBuffer[primitiveID];
|
||||
|
||||
if (IntersectTriangleANY(ray, maxDistance, prim, primitiveID))
|
||||
if (IntersectTriangleANY(ray, prim, primitiveID))
|
||||
{
|
||||
shadow = true;
|
||||
break;
|
||||
@@ -595,8 +593,10 @@ inline bool TraceRay_Any(Ray ray, float maxDistance, uint groupIndex = 0)
|
||||
|
||||
// Returns number of BVH nodes that were hit (useful for debug):
|
||||
// returns 0xFFFFFFFF when there was a stack overflow
|
||||
inline uint TraceRay_DebugBVH(Ray ray)
|
||||
inline uint TraceRay_DebugBVH(RayDesc ray)
|
||||
{
|
||||
const float3 rcpDirection = rcp(ray.Direction);
|
||||
|
||||
uint hit_counter = 0;
|
||||
|
||||
// Emulated stack for tree traversal:
|
||||
@@ -615,7 +615,7 @@ inline uint TraceRay_DebugBVH(Ray ray)
|
||||
|
||||
BVHNode node = bvhNodeBuffer[nodeIndex];
|
||||
|
||||
if (IntersectNode(ray, node))
|
||||
if (IntersectNode(ray, node, rcpDirection))
|
||||
{
|
||||
hit_counter++;
|
||||
|
||||
|
||||
@@ -19,15 +19,19 @@ float4 main(Input input) : SV_TARGET
|
||||
|
||||
float2 uv = input.uv;
|
||||
float seed = xTraceRandomSeed;
|
||||
float3 direction = SampleHemisphere_cos(surface.N, seed, uv);
|
||||
Ray ray = CreateRay(trace_bias_position(input.pos3D, surface.N), direction);
|
||||
RayDesc ray;
|
||||
ray.Origin = trace_bias_position(input.pos3D, surface.N);
|
||||
ray.Direction = SampleHemisphere_cos(surface.N, seed, uv);
|
||||
ray.TMin = 0.001;
|
||||
ray.TMax = FLT_MAX;
|
||||
float3 result = 0;
|
||||
float3 energy = 1;
|
||||
|
||||
uint bounces = xTraceUserData.x;
|
||||
const uint bouncelimit = 16;
|
||||
for (uint bounce = 0; ((bounce < min(bounces, bouncelimit)) && any(ray.energy)); ++bounce)
|
||||
for (uint bounce = 0; ((bounce < min(bounces, bouncelimit)) && any(energy)); ++bounce)
|
||||
{
|
||||
surface.P = ray.origin;
|
||||
surface.P = ray.Origin;
|
||||
|
||||
[loop]
|
||||
for (uint iterator = 0; iterator < g_xFrame_LightArrayCount; iterator++)
|
||||
@@ -141,21 +145,16 @@ float4 main(Input input) : SV_TARGET
|
||||
|
||||
if (NdotL > 0 && dist > 0)
|
||||
{
|
||||
float3 shadow = NdotL * ray.energy;
|
||||
float3 shadow = NdotL * energy;
|
||||
|
||||
float3 sampling_offset = float3(rand(seed, uv), rand(seed, uv), rand(seed, uv)) * 2 - 1;
|
||||
|
||||
Ray newRay;
|
||||
newRay.origin = trace_bias_position(surface.P, surface.N);
|
||||
newRay.direction = L + sampling_offset * 0.025f;
|
||||
newRay.energy = 0;
|
||||
newRay.Update();
|
||||
RayDesc newRay;
|
||||
newRay.Origin = trace_bias_position(surface.P, surface.N);
|
||||
newRay.Direction = normalize(L + sampling_offset * 0.025f);
|
||||
newRay.TMin = 0.001;
|
||||
newRay.TMax = dist;
|
||||
#ifdef RTAPI
|
||||
RayDesc apiray;
|
||||
apiray.TMin = 0.001;
|
||||
apiray.TMax = dist;
|
||||
apiray.Origin = newRay.origin;
|
||||
apiray.Direction = newRay.direction;
|
||||
RayQuery<
|
||||
RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES
|
||||
> q;
|
||||
@@ -163,7 +162,7 @@ float4 main(Input input) : SV_TARGET
|
||||
scene_acceleration_structure, // RaytracingAccelerationStructure AccelerationStructure
|
||||
0, // uint RayFlags
|
||||
0xFF, // uint InstanceInclusionMask
|
||||
apiray // RayDesc Ray
|
||||
newRay // RayDesc Ray
|
||||
);
|
||||
while (q.Proceed())
|
||||
{
|
||||
@@ -197,7 +196,7 @@ float4 main(Input input) : SV_TARGET
|
||||
}
|
||||
shadow = q.CommittedStatus() == COMMITTED_TRIANGLE_HIT ? 0 : shadow;
|
||||
#else
|
||||
shadow = TraceRay_Any(newRay, dist) ? 0 : shadow;
|
||||
shadow = TraceRay_Any(newRay) ? 0 : shadow;
|
||||
#endif // RTAPI
|
||||
if (any(shadow))
|
||||
{
|
||||
@@ -207,20 +206,24 @@ float4 main(Input input) : SV_TARGET
|
||||
}
|
||||
|
||||
// Sample primary ray (scene materials, sky, etc):
|
||||
ray.Direction = normalize(ray.Direction);
|
||||
|
||||
#ifdef RTAPI
|
||||
RayDesc apiray;
|
||||
apiray.TMin = 0.001;
|
||||
apiray.TMax = FLT_MAX;
|
||||
apiray.Origin = ray.origin;
|
||||
apiray.Direction = ray.direction;
|
||||
RayQuery<
|
||||
RAY_FLAG_FORCE_OPAQUE |
|
||||
RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES
|
||||
> q;
|
||||
q.TraceRayInline(scene_acceleration_structure, 0, 0xFF, apiray);
|
||||
q.TraceRayInline(
|
||||
scene_acceleration_structure, // RaytracingAccelerationStructure AccelerationStructure
|
||||
#ifdef RAY_BACKFACE_CULLING
|
||||
RAY_FLAG_CULL_BACK_FACING_TRIANGLES |
|
||||
#endif // RAY_BACKFACE_CULLING
|
||||
RAY_FLAG_FORCE_OPAQUE |
|
||||
0, // uint RayFlags
|
||||
0xFF, // uint InstanceInclusionMask
|
||||
ray // RayDesc Ray
|
||||
);
|
||||
q.Proceed();
|
||||
if(q.CommittedStatus() != COMMITTED_TRIANGLE_HIT)
|
||||
if (q.CommittedStatus() != COMMITTED_TRIANGLE_HIT)
|
||||
#else
|
||||
RayHit hit = TraceRay_Closest(ray);
|
||||
|
||||
@@ -233,25 +236,24 @@ float4 main(Input input) : SV_TARGET
|
||||
if (IsStaticSky())
|
||||
{
|
||||
// We have envmap information in a texture:
|
||||
envColor = DEGAMMA_SKY(texture_globalenvmap.SampleLevel(sampler_linear_clamp, ray.direction, 0).rgb);
|
||||
envColor = DEGAMMA_SKY(texture_globalenvmap.SampleLevel(sampler_linear_clamp, ray.Direction, 0).rgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
envColor = GetDynamicSkyColor(ray.direction, true, true, false, true);
|
||||
envColor = GetDynamicSkyColor(ray.Direction, true, true, false, true);
|
||||
}
|
||||
result += max(0, ray.energy * envColor);
|
||||
result += max(0, energy * envColor);
|
||||
|
||||
// Erase the ray's energy
|
||||
ray.energy = 0;
|
||||
energy = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ShaderMaterial material;
|
||||
|
||||
#ifdef RTAPI
|
||||
|
||||
// ray origin updated for next bounce:
|
||||
ray.origin = q.WorldRayOrigin() + q.WorldRayDirection() * q.CommittedRayT();
|
||||
ray.Origin = q.WorldRayOrigin() + q.WorldRayDirection() * q.CommittedRayT();
|
||||
|
||||
ShaderMesh mesh = bindless_buffers[q.CommittedInstanceID()].Load<ShaderMesh>(0);
|
||||
ShaderMeshSubset subset = bindless_subsets[mesh.subsetbuffer][q.CommittedGeometryIndex()];
|
||||
@@ -268,9 +270,8 @@ float4 main(Input input) : SV_TARGET
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
// Non-RTAPI path: sampling from texture atlas
|
||||
ray.origin = hit.position;
|
||||
// ray origin updated for next bounce:
|
||||
ray.Origin = ray.Origin + ray.Direction * hit.distance;
|
||||
|
||||
EvaluateObjectSurface(
|
||||
hit,
|
||||
@@ -282,22 +283,20 @@ float4 main(Input input) : SV_TARGET
|
||||
|
||||
surface.update();
|
||||
|
||||
result += max(0, ray.energy * surface.emissiveColor.rgb * surface.emissiveColor.a);
|
||||
|
||||
// Calculate chances of reflection types:
|
||||
const float refractChance = material.transmission;
|
||||
const float refractChance = surface.transmission;
|
||||
|
||||
// Roulette-select the ray's path
|
||||
float roulette = rand(seed, uv);
|
||||
if (roulette < refractChance)
|
||||
{
|
||||
// Refraction
|
||||
const float3 R = refract(ray.direction, surface.N, 1 - material.refraction);
|
||||
ray.direction = lerp(R, SampleHemisphere_cos(R, seed, uv), surface.roughnessBRDF);
|
||||
ray.energy *= surface.albedo;
|
||||
const float3 R = refract(ray.Direction, surface.N, 1 - material.refraction);
|
||||
ray.Direction = lerp(R, SampleHemisphere_cos(R, seed, uv), surface.roughnessBRDF);
|
||||
energy *= surface.albedo;
|
||||
|
||||
// The ray penetrates the surface, so push DOWN along normal to avoid self-intersection:
|
||||
ray.origin = trace_bias_position(ray.origin, -surface.N);
|
||||
ray.Origin = trace_bias_position(ray.Origin, -surface.N);
|
||||
|
||||
// Add a new bounce iteration, otherwise the transparent effect can disappear:
|
||||
bounces++;
|
||||
@@ -305,29 +304,29 @@ float4 main(Input input) : SV_TARGET
|
||||
else
|
||||
{
|
||||
// Calculate chances of reflection types:
|
||||
const float3 F = F_Schlick(surface.f0, saturate(dot(-ray.direction, surface.N)));
|
||||
const float3 F = F_Schlick(surface.f0, saturate(dot(-ray.Direction, surface.N)));
|
||||
const float specChance = dot(F, 0.333f);
|
||||
|
||||
roulette = rand(seed, uv);
|
||||
if (roulette < specChance)
|
||||
{
|
||||
// Specular reflection
|
||||
const float3 R = reflect(ray.direction, surface.N);
|
||||
ray.direction = lerp(R, SampleHemisphere_cos(R, seed, uv), surface.roughnessBRDF);
|
||||
ray.energy *= F / specChance;
|
||||
const float3 R = reflect(ray.Direction, surface.N);
|
||||
ray.Direction = lerp(R, SampleHemisphere_cos(R, seed, uv), surface.roughnessBRDF);
|
||||
energy *= F / specChance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Diffuse reflection
|
||||
ray.direction = SampleHemisphere_cos(surface.N, seed, uv);
|
||||
ray.energy *= surface.albedo / (1 - specChance);
|
||||
ray.Direction = SampleHemisphere_cos(surface.N, seed, uv);
|
||||
energy *= surface.albedo / (1 - specChance);
|
||||
}
|
||||
|
||||
// Ray reflects from surface, so push UP along normal to avoid self-intersection:
|
||||
ray.origin = trace_bias_position(ray.origin, surface.N);
|
||||
ray.Origin = trace_bias_position(ray.Origin, surface.N);
|
||||
}
|
||||
|
||||
ray.Update();
|
||||
result += max(0, energy * surface.emissiveColor.rgb * surface.emissiveColor.a);
|
||||
}
|
||||
|
||||
return float4(result, xTraceAccumulationFactor);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wiVersion
|
||||
// minor features, major updates, breaking compatibility changes
|
||||
const int minor = 55;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 10;
|
||||
const int revision = 11;
|
||||
|
||||
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user