Skip to content
Snippets Groups Projects
Commit 485fde0b authored by Mara Vogt's avatar Mara Vogt
Browse files

[#92] AO by using rtx together with a working camera

parent adebb749
Branches
Tags
1 merge request!75Resolve "RTX-Module"
Pipeline #27333 passed
...@@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) ...@@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# adding source files to the project # adding source files to the project
add_executable(rtx src/main.cpp) add_executable(rtx src/main.cpp src/teapot.hpp)
# this should fix the execution path to load local files from the project (for MSVC) # this should fix the execution path to load local files from the project (for MSVC)
if(MSVC) if(MSVC)
......
#version 460 #version 460
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
#extension GL_EXT_nonuniform_qualifier : enable #extension GL_EXT_scalar_block_layout : require
#define M_PI 3.1415926535897932384626433832795 hitAttributeEXT vec2 attributes;
//Mat struct
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 emission;
};
struct Light {
vec3 position;
float intensity;
};
hitAttributeEXT vec2 hitCoordinate;
layout(location = 0) rayPayloadInEXT Payload { layout(location = 0) rayPayloadInEXT Payload {
vec3 rayOrigin; float hitSky;
vec3 rayDirection; vec3 worldPosition;
vec3 previousNormal; vec3 worldNormal;
vec3 directColor;
vec3 indirectColor;
int rayDepth;
int rayActive;
} payload; } payload;
layout(location = 1) rayPayloadEXT bool isShadow;
layout(binding = 2, set = 0) uniform accelerationStructureEXT tlas; // top level acceleration structure (for the noobs here (you!)) layout(binding = 2, set = 0) uniform accelerationStructureEXT tlas; // top level acceleration structure (for the noobs here (you!))
layout( push_constant ) uniform constants { layout(binding = 3, set = 0, scalar) buffer rtxVertices
vec4 camera_position; // as origin for ray generation
vec4 camera_right; // for computing ray direction
vec4 camera_up; // for computing ray direction
vec4 camera_forward; // for computing ray direction
uint frameCount; // what is this? the actual frame?
}camera;
layout(binding = 3, set = 0) buffer rtxVertices
{ {
float vertices[]; float vertices[];
} rtxVertexBuffer; };
layout(binding = 4, set = 0) buffer rtxIndices layout(binding = 4, set = 0, scalar) buffer rtxIndices
{ {
uint indices[]; uint indices[];
} rtxIndexBuffer; };
/*
layout(binding = 0, set = 1) buffer MaterialIndexBuffer { uint data[]; } materialIndexBuffer;
layout(binding = 1, set = 1) buffer MaterialBuffer { Material data[]; } materialBuffer;
*/
float random(vec2 uv, float seed) {
return fract(sin(mod(dot(uv, vec2(12.9898, 78.233)) + 1113.1 * seed, M_PI)) * 43758.5453);;
}
vec3 uniformSampleHemisphere(vec2 uv) {
float z = uv.x;
float r = sqrt(max(0, 1.0 - z * z));
float phi = 2.0 * M_PI * uv.y;
return vec3(r * cos(phi), z, r * sin(phi));
}
vec3 alignHemisphereWithCoordinateSystem(vec3 hemisphere, vec3 up) {
vec3 right = normalize(cross(up, vec3(0.0072f, 1.0f, 0.0034f)));
vec3 forward = cross(right, up);
return hemisphere.x * right + hemisphere.y * up + hemisphere.z * forward;
}
void main() { void main() {
payload.worldPosition = vec3(1.0, 0.0, 0.5);
if (payload.rayActive == 0) {
return;
}
Material ivory = {vec3(1,0,0), vec3(0.4, 0.4, 0.3), vec3(50.,50.,50.), vec3(0.6, 0.3, 0.1)};
Material mirror = {vec3(1,0,0), vec3(1.0, 1.0, 1.0), vec3(1425.,1425.,1425.), vec3(0.0, 10.0, 0.8)};
Light rtxLight1 = {vec3(5, 5, 5), 1.5};
Light rtxLight2 = {vec3(-5, -5, -2.5), 3};
Light rtxLight3 = {vec3(-5, -5, 5), 1.7};
ivec3 rtindices = ivec3(rtxIndexBuffer.indices[3 * gl_PrimitiveID + 0], rtxIndexBuffer.indices[3 * gl_PrimitiveID + 1], rtxIndexBuffer.indices[3 * gl_PrimitiveID + 2]);
vec3 barycentric = vec3(1.0 - hitCoordinate.x - hitCoordinate.y, hitCoordinate.x, hitCoordinate.y);
vec3 vertexA = vec3(rtxVertexBuffer.vertices[3 * rtindices.x + 0], rtxVertexBuffer.vertices[3 * rtindices.x + 1], rtxVertexBuffer.vertices[3 * rtindices.x + 2]);
vec3 vertexB = vec3(rtxVertexBuffer.vertices[3 * rtindices.y + 0], rtxVertexBuffer.vertices[3 * rtindices.y + 1], rtxVertexBuffer.vertices[3 * rtindices.y + 2]);
vec3 vertexC = vec3(rtxVertexBuffer.vertices[3 * rtindices.z + 0], rtxVertexBuffer.vertices[3 * rtindices.z + 1], rtxVertexBuffer.vertices[3 * rtindices.z + 2]);
vec3 position = vertexA * barycentric.x + vertexB * barycentric.y + vertexC * barycentric.z;
vec3 geometricNormal = normalize(cross(vertexB - vertexA, vertexC - vertexA));
//vec3 surfaceColor = materialBuffer.data[materialIndexBuffer.data[gl_PrimitiveID]].diffuse;
vec3 surfaceColor = ivory.diffuse;
if(payload.rayOrigin == rtxLight1.position || payload.rayOrigin == rtxLight2.position || payload.rayOrigin == rtxLight3.position){
if (payload.rayDepth == 0) {
//payload.directColor = materialBuffer.data[materialIndexBuffer.data[gl_PrimitiveID]].emission;
payload.directColor = ivory.emission;
}
else {
//payload.indirectColor += (1.0 / payload.rayDepth) * materialBuffer.data[materialIndexBuffer.data[gl_PrimitiveID]].emission * dot(payload.previousNormal, payload.rayDirection);
payload.indirectColor += (1.0 / payload.rayDepth) * ivory.emission * dot(payload.previousNormal, payload.rayDirection);
}
} else {
int randomIndex = int(random(gl_LaunchIDEXT.xy, camera.frameCount) * 2 + 40);
vec3 lightColor = vec3(0.6, 0.6, 0.6);
ivec3 lightIndices = ivec3(1,1,1);
/*
vec3 lightVertexA = vec3(rtxVertexBuffer.vertices[3 * lightIndices.x + 0], rtxVertexBuffer.vertices[3 * lightIndices.x + 1], rtxVertexBuffer.vertices[3 * lightIndices.x + 2]);
vec3 lightVertexB = vec3(rtxVertexBuffer.vertices[3 * lightIndices.y + 0], rtxVertexBuffer.vertices[3 * lightIndices.y + 1], rtxVertexBuffer.vertices[3 * lightIndices.y + 2]);
vec3 lightVertexC = vec3(rtxVertexBuffer.vertices[3 * lightIndices.z + 0], rtxVertexBuffer.vertices[3 * lightIndices.z + 1], rtxVertexBuffer.vertices[3 * lightIndices.z + 2]);
*/
vec2 uv = vec2(random(gl_LaunchIDEXT.xy, camera.frameCount), random(gl_LaunchIDEXT.xy, camera.frameCount + 1));
if (uv.x + uv.y > 1.0f) {
uv.x = 1.0f - uv.x;
uv.y = 1.0f - uv.y;
}
vec3 lightBarycentric = vec3(1.0 - uv.x - uv.y, uv.x, uv.y);
//vec3 lightPosition = rtxLight.position.x * lightBarycentric.x + rtxLight.position.y * lightBarycentric.y + rtxLight.position.z * lightBarycentric.z;
vec3 lightPosition;
if(payload.rayOrigin == rtxLight1.position){
lightPosition = vec3(dot(rtxLight1.position, lightBarycentric));
}else if(payload.rayOrigin == rtxLight2.position){
lightPosition = vec3(dot(rtxLight2.position, lightBarycentric));
}else{
lightPosition = vec3(dot(rtxLight3.position, lightBarycentric));
}
vec3 positionToLightDirection = normalize(lightPosition - position); ivec3 indicesVec = ivec3(indices[3 * gl_PrimitiveID + 0], indices[3 * gl_PrimitiveID + 1], indices[3 * gl_PrimitiveID + 2]);
vec3 shadowRayOrigin = position; // current triangle
vec3 shadowRayDirection = positionToLightDirection; const vec3 v0 = vec3(vertices[3 * indicesVec.x + 0],vertices[3 * indicesVec.x + 1],vertices[3 * indicesVec.x + 2]);
float shadowRayDistance = length(lightPosition - position) - 0.001f; const vec3 v1 = vec3(vertices[3 * indicesVec.y + 0],vertices[3 * indicesVec.y + 1],vertices[3 * indicesVec.y + 2]);
const vec3 v2 = vec3(vertices[3 * indicesVec.z + 0],vertices[3 * indicesVec.z + 1],vertices[3 * indicesVec.z + 2]);
uint shadowRayFlags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; // use barycentric coordinates to compute intersection
const vec3 barycentrics = vec3(1.0 - attributes.x - attributes.y, attributes.xy);
const vec3 objectPosition = v0 * barycentrics.x + v1 * barycentrics.y + v2 * barycentrics.z;
isShadow = true; payload.worldPosition = gl_ObjectToWorldEXT * vec4(objectPosition, 1.0);
traceRayEXT(tlas, shadowRayFlags, 0xFF, 0, 0, 1, shadowRayOrigin, 0.001, shadowRayDirection, shadowRayDistance, 1);
// TODO: always true because light sources are dumb const vec3 objectNormal = cross(v1 - v0, v2 - v0);
//if (!isShadow) {
if (payload.rayDepth == 0) {
payload.directColor = surfaceColor * lightColor * dot(geometricNormal, positionToLightDirection);
}
else {
payload.indirectColor += (1.0 / payload.rayDepth) * surfaceColor * lightColor * dot(payload.previousNormal, payload.rayDirection) * dot(geometricNormal, positionToLightDirection);
}
//}
//else {
// if (payload.rayDepth == 0) {
// payload.directColor = vec3(0.4, 0.4, 0.3);
// }
// else {
// payload.rayActive = 0;
// }
//}
}
vec3 hemisphere = uniformSampleHemisphere(vec2(random(gl_LaunchIDEXT.xy, camera.frameCount), random(gl_LaunchIDEXT.xy, camera.frameCount + 1))); payload.worldNormal = normalize((objectNormal * gl_WorldToObjectEXT).xyz);
vec3 alignedHemisphere = alignHemisphereWithCoordinateSystem(hemisphere, geometricNormal);
payload.rayOrigin = position; payload.worldNormal = faceforward(payload.worldNormal, gl_WorldRayDirectionEXT, payload.worldNormal);
payload.rayDirection = alignedHemisphere;
payload.previousNormal = geometricNormal;
payload.rayDepth += 1; payload.hitSky = 0.0f;
//payload.directColor=vec3(1,0,0);
} }
...@@ -5,14 +5,10 @@ ...@@ -5,14 +5,10 @@
// A location for a ray payload (we can have multiple of these) // A location for a ray payload (we can have multiple of these)
layout(location = 0) rayPayloadEXT Payload { layout(location = 0) rayPayloadEXT Payload {
vec3 rayOrigin; float hitSky;
vec3 rayDirection; vec3 worldPosition;
vec3 previousNormal; vec3 worldNormal;
vec3 directColor; } payload;
vec3 indirectColor;
int rayDepth;
int rayActive;
} payload;
layout(binding = 0, set = 0, rgba16) uniform image2D outImg; // the output image -> maybe use 16 bit values? layout(binding = 0, set = 0, rgba16) uniform image2D outImg; // the output image -> maybe use 16 bit values?
layout(binding = 1, set = 0) uniform accelerationStructureEXT tlas; // top level acceleration structure (for the noobs here (you!)) layout(binding = 1, set = 0) uniform accelerationStructureEXT tlas; // top level acceleration structure (for the noobs here (you!))
...@@ -23,42 +19,132 @@ layout( push_constant ) uniform constants { ...@@ -23,42 +19,132 @@ layout( push_constant ) uniform constants {
vec4 camera_up; // for computing ray direction vec4 camera_up; // for computing ray direction
vec4 camera_forward; // for computing ray direction vec4 camera_forward; // for computing ray direction
uint frameCount; // what is this? the actual frame? uint frameCount; // resets when camera moves, otherwise frameCount++
}camera; }camera;
float random(vec2 uv, float seed) { float random(vec2 uv, float seed) {
return fract(sin(mod(dot(uv, vec2(12.9898, 78.233)) + 1113.1 * seed, M_PI)) * 43758.5453); return fract(sin(mod(dot(uv, vec2(12.9898, 78.233)) + 1113.1 * seed, M_PI)) * 43758.5453);;
} }
void main(){ void GetPixelInfo(out bool hitSky, out vec3 pos, out vec3 norm){
vec2 uv = gl_LaunchIDEXT.xy + vec2(random(gl_LaunchIDEXT.xy, 0), random(gl_LaunchIDEXT.xy, 1)); // Use a camera model to generate a ray for this pixel.
uv /= vec2(gl_LaunchSizeEXT.xy); //const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + 0.5;
uv = (uv * 2.0f - 1.0f) * vec2(1.0f, -1.0f); //const uvec2 resolution = gl_LaunchSizeEXT.xy;
vec2 uv = gl_LaunchIDEXT.xy + vec2(random(gl_LaunchIDEXT.xy, 0), random(gl_LaunchIDEXT.xy, 1));
uv /= vec2(gl_LaunchSizeEXT.xy);
uv = vec2(1.0, -1.0) * (uv * 2.0 - 1.0);
//const float fovVerticalSlope = 1.0 / 5.0;
const vec3 orig = camera.camera_position.xyz;
const vec3 dir = normalize((-1) * uv.x * camera.camera_right + uv.y * camera.camera_up + camera.camera_forward).xyz;
// Trace a ray into the scene; get back data in the payload.
traceRayEXT(tlas, // Acceleration structure
gl_RayFlagsOpaqueEXT, // Ray flags, here saying "ignore intersection shaders"
0xFF, // 8-bit instance mask, here saying "trace against all instances"
0, // SBT record offset
0, // SBT record stride for offset
0, // Miss index
orig, // Ray origin
0.0, // Minimum t-value
dir, // Ray direction
1000.0, // Maximum t-value
0); // Location of payload
// Read the values from the payload:
hitSky = (payload.hitSky > 0.0);
pos = payload.worldPosition;
norm = payload.worldNormal;
}
float ShadowRay(vec3 orig, vec3 dir){
payload.hitSky = 0.0f; // Assume ray is occluded
traceRayEXT(tlas, // Acceleration structure
gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT | gl_RayFlagsTerminateOnFirstHitEXT, // Ray flags, here saying "ignore any hit shaders and closest hit shaders, and terminate the ray on the first found intersection"
0xFF, // 8-bit instance mask, here saying "trace against all instances"
0, // SBT record offset
0, // SBT record stride for offset
0, // Miss index
orig, // Ray origin
0.0, // Minimum t-value
dir, // Ray direction
1000.0, // Maximum t-value
0); // Location of payload
return payload.hitSky;
}
vec3 OffsetPositionAlongNormal(vec3 worldPosition, vec3 normal){
// Convert the normal to an integer offset.
const float int_scale = 256.0f;
const ivec3 of_i = ivec3(int_scale * normal);
payload.rayOrigin = camera.camera_position.xyz; // Offset each component of worldPosition using its binary representation.
payload.rayDirection = normalize((-1) * uv.x * camera.camera_right + uv.y * camera.camera_up + camera.camera_forward).xyz ; // Handle the sign bits correctly.
payload.previousNormal = vec3(0.0, 0.0, 0.0); const vec3 p_i = vec3( //
intBitsToFloat(floatBitsToInt(worldPosition.x) + ((worldPosition.x < 0) ? -of_i.x : of_i.x)),
intBitsToFloat(floatBitsToInt(worldPosition.y) + ((worldPosition.y < 0) ? -of_i.y : of_i.y)),
intBitsToFloat(floatBitsToInt(worldPosition.z) + ((worldPosition.z < 0) ? -of_i.z : of_i.z)));
payload.directColor = vec3(0.0, 0.0, 0.0); // Use a floating-point offset instead for points near (0,0,0), the origin.
payload.indirectColor = vec3(0.0, 0.0, 0.0); const float origin = 1.0f / 32.0f;
payload.rayDepth = 0; const float floatScale = 1.0f / 65536.0f;
return vec3( //
abs(worldPosition.x) < origin ? worldPosition.x + floatScale * normal.x : p_i.x,
abs(worldPosition.y) < origin ? worldPosition.y + floatScale * normal.y : p_i.y,
abs(worldPosition.z) < origin ? worldPosition.z + floatScale * normal.z : p_i.z);
}
uint rngState = gl_LaunchIDEXT.x * 2000 + gl_LaunchIDEXT.y;
payload.rayActive = 1; float StepAndOutputRNGFloat(){
// Condensed version of pcg_output_rxs_m_xs_32_32, with simple conversion to floating-point [0,1].
rngState = rngState * 747796405 + 1;
uint word = ((rngState >> ((rngState >> 28) + 4)) ^ rngState) * 277803737;
word = (word >> 22) ^ word;
return float(word) / 4294967295.0f;
}
for (int x = 0; x < 16; x++) { // Gets a randomly chosen cosine-weighted direction within the unit hemisphere
traceRayEXT(tlas, gl_RayFlagsOpaqueEXT, 0xFF, 0, 0, 0, payload.rayOrigin, 0.001, payload.rayDirection, 10000.0, 0); // defined by the surface normal.
} vec3 GetRandCosDir(vec3 norm){
// To generate a cosine-weighted normal, generate a random point on a sphere:
float theta = 6.2831853 * StepAndOutputRNGFloat(); // Random in [0, 2pi]
float z = 2 * StepAndOutputRNGFloat() - 1.0; // Random in [-1, 1]
float r = sqrt(1.0 - z * z);
vec3 ptOnSphere = vec3(r * cos(theta), r * sin(theta), z);
// Then add the normal to it and normalize to make it cosine-weighted on a
// hemisphere:
return normalize(ptOnSphere + norm);
}
void main(){
uvec2 pixel = gl_LaunchIDEXT.xy;
bool pixelIsSky; // Does the pixel show the sky (not an object)?
vec3 pos, norm; // AO rays from where?
GetPixelInfo(pixelIsSky, pos, norm);
if(pixelIsSky){
// Don't compute ambient occlusion for the sky
imageStore(outImg, ivec2(pixel), vec4(0.8,0.8,0.8,1.0));
return;
}
vec4 color = vec4(payload.directColor + payload.indirectColor, 1.0); // Compute ambient occlusion
pos = OffsetPositionAlongNormal(pos, norm); // Avoid self-intersection
float aoColor = 0.0;
for(uint i = 0; i < 64; i++){ // Use 64 rays.
aoColor += ShadowRay(pos, GetRandCosDir(norm)) / 64.0;
}
vec4 aoColorVec = vec4(aoColor);
if (camera.frameCount > 0) {
vec4 previousColor = imageLoad(outImg, ivec2(gl_LaunchIDEXT.xy));
previousColor *= camera.frameCount;
if (camera.frameCount > 0) { aoColorVec += previousColor;
vec4 previousColor = imageLoad(outImg, ivec2(gl_LaunchIDEXT.xy)); aoColorVec /= (camera.frameCount + 1);
previousColor *= camera.frameCount; }
imageStore(outImg, ivec2(pixel), aoColorVec);
color += previousColor;
color /= (camera.frameCount + 1);
}
//color=vec4(0.0001*camera.frameCount,0,0,1);//DEBUG //color=vec4(0.0001*camera.frameCount,0,0,1);//DEBUG
//color=vec4(1,0,0,1);//DEBUG //color=vec4(1,0,0,1);//DEBUG
imageStore(outImg, ivec2(gl_LaunchIDEXT.xy), color); //imageStore(outImg, ivec2(gl_LaunchIDEXT.xy), color);
} }
...@@ -2,17 +2,11 @@ ...@@ -2,17 +2,11 @@
#extension GL_EXT_ray_tracing : require #extension GL_EXT_ray_tracing : require
layout(location = 0) rayPayloadInEXT Payload { layout(location = 0) rayPayloadInEXT Payload {
vec3 rayOrigin; float hitSky;
vec3 rayDirection; vec3 worldPosition;
vec3 previousNormal; vec3 worldNormal;
vec3 directColor;
vec3 indirectColor;
int rayDepth;
int rayActive;
} payload; } payload;
void main() { void main() {
payload.rayActive = 0; payload.hitSky = 1.0f;
} }
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment