raytracing refactors, lightmap caustics fix

This commit is contained in:
Turanszki Janos
2021-04-02 19:36:19 +02:00
parent 105ed78ef9
commit 03f305b300
5 changed files with 155 additions and 165 deletions
+40 -49
View File
@@ -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;
}
}
+64 -64
View File
@@ -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++;
+48 -49
View File
@@ -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);
+1 -1
View File
@@ -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);