-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Expand file tree
/
Copy pathRaytracing.hlsl
More file actions
172 lines (141 loc) · 5.94 KB
/
Copy pathRaytracing.hlsl
File metadata and controls
172 lines (141 loc) · 5.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#ifndef RAYTRACING_HLSL
#define RAYTRACING_HLSL
#define HLSL
#include "RaytracingHlslCompat.h"
RaytracingAccelerationStructure Scene : register(t0, space0);
RWTexture2D<float4> RenderTarget : register(u0);
ByteAddressBuffer Indices : register(t1, space0);
StructuredBuffer<Vertex> Vertices : register(t2, space0);
ConstantBuffer<SceneConstantBuffer> g_sceneCB : register(b0);
ConstantBuffer<CubeConstantBuffer> g_cubeCB : register(b1);
// Load three 16 bit indices from a byte addressed buffer.
uint3 Load3x16BitIndices(uint offsetBytes)
{
uint3 indices;
// ByteAdressBuffer loads must be aligned at a 4 byte boundary.
// Since we need to read three 16 bit indices: { 0, 1, 2 }
// aligned at a 4 byte boundary as: { 0 1 } { 2 0 } { 1 2 } { 0 1 } ...
// we will load 8 bytes (~ 4 indices { a b | c d }) to handle two possible index triplet layouts,
// based on first index's offsetBytes being aligned at the 4 byte boundary or not:
// Aligned: { 0 1 | 2 - }
// Not aligned: { - 0 | 1 2 }
const uint dwordAlignedOffset = offsetBytes & ~3;
const uint2 four16BitIndices = Indices.Load2(dwordAlignedOffset);
// Aligned: { 0 1 | 2 - } => retrieve first three 16bit indices
if (dwordAlignedOffset == offsetBytes)
{
indices.x = four16BitIndices.x & 0xffff;
indices.y = (four16BitIndices.x >> 16) & 0xffff;
indices.z = four16BitIndices.y & 0xffff;
}
else // Not aligned: { - 0 | 1 2 } => retrieve last three 16bit indices
{
indices.x = (four16BitIndices.x >> 16) & 0xffff;
indices.y = four16BitIndices.y & 0xffff;
indices.z = (four16BitIndices.y >> 16) & 0xffff;
}
return indices;
}
typedef BuiltInTriangleIntersectionAttributes MyAttributes;
struct RayPayload
{
float4 color;
};
// Retrieve hit world position.
float3 HitWorldPosition()
{
return WorldRayOrigin() + RayTCurrent() * WorldRayDirection();
}
// Retrieve attribute at a hit position interpolated from vertex attributes using the hit's barycentrics.
float3 HitAttribute(float3 vertexAttribute[3], BuiltInTriangleIntersectionAttributes attr)
{
return vertexAttribute[0] +
attr.barycentrics.x * (vertexAttribute[1] - vertexAttribute[0]) +
attr.barycentrics.y * (vertexAttribute[2] - vertexAttribute[0]);
}
// Generate a ray in world space for a camera pixel corresponding to an index from the dispatched 2D grid.
inline void GenerateCameraRay(uint2 index, out float3 origin, out float3 direction)
{
float2 xy = index + 0.5f; // center in the middle of the pixel.
float2 screenPos = xy / DispatchRaysDimensions().xy * 2.0 - 1.0;
// Invert Y for DirectX-style coordinates.
screenPos.y = -screenPos.y;
// Unproject the pixel coordinate into a ray.
float4 world = mul(float4(screenPos, 0, 1), g_sceneCB.projectionToWorld);
world.xyz /= world.w;
origin = g_sceneCB.cameraPosition.xyz;
direction = normalize(world.xyz - origin);
}
// Diffuse lighting calculation.
float4 CalculateDiffuseLighting(float3 hitPosition, float3 normal)
{
float3x3 o2w = (float3x3)ObjectToWorld3x4();
float3 normalWorldSpace = normalize(mul(o2w, normal));
float3 pixelToLight = normalize(g_sceneCB.lightPosition.xyz - hitPosition);
// Diffuse contribution.
float fNDotL = max(0.0f, dot(pixelToLight, normalWorldSpace));
return g_cubeCB.albedo * g_sceneCB.lightDiffuseColor * fNDotL;
}
[shader("raygeneration")]
void MyRaygenShader()
{
float3 rayDir;
float3 origin;
// Generate a ray for a camera pixel corresponding to an index from the dispatched 2D grid.
GenerateCameraRay(DispatchRaysIndex().xy, origin, rayDir);
// Trace the ray.
// Set the ray's extents.
RayDesc ray;
ray.Origin = origin;
ray.Direction = rayDir;
// Set TMin to a non-zero small value to avoid aliasing issues due to floating - point errors.
// TMin should be kept small to prevent missing geometry at close contact areas.
ray.TMin = 0.001;
ray.TMax = 10000.0;
RayPayload payload = { float4(0, 0, 0, 0) };
TraceRay(Scene, RAY_FLAG_CULL_BACK_FACING_TRIANGLES, ~0, 0, 1, 0, ray, payload);
// Write the raytraced color to the output texture.
RenderTarget[DispatchRaysIndex().xy] = payload.color;
}
[shader("closesthit")]
void MyClosestHitShader(inout RayPayload payload, in MyAttributes attr)
{
float3 hitPosition = HitWorldPosition();
// Get the base index of the triangle's first 16 bit index.
uint indexSizeInBytes = 2;
uint indicesPerTriangle = 3;
uint triangleIndexStride = indicesPerTriangle * indexSizeInBytes;
uint baseIndex = PrimitiveIndex() * triangleIndexStride;
// Load up 3 16 bit indices for the triangle.
const uint3 indices = Load3x16BitIndices(baseIndex);
// Retrieve corresponding vertex normals for the triangle vertices.
float3 vertexNormals[3] = {
Vertices[indices[0]].normal,
Vertices[indices[1]].normal,
Vertices[indices[2]].normal
};
// Compute the triangle's normal.
// This is redundant and done for illustration purposes
// as all the per-vertex normals are the same and match triangle's normal in this sample.
float3 triangleNormal = HitAttribute(vertexNormals, attr);
float4 diffuseColor = CalculateDiffuseLighting(hitPosition, triangleNormal);
float4 color = g_sceneCB.lightAmbientColor + diffuseColor;
payload.color = color;
}
[shader("miss")]
void MyMissShader(inout RayPayload payload)
{
float4 background = float4(0.0f, 0.2f, 0.4f, 1.0f);
payload.color = background;
}
#endif // RAYTRACING_HLSL