From 7f4d7c7f71a1efa90399c84544887f0af812f5eb Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Wed, 25 Dec 2024 14:59:08 +0100 Subject: [PATCH] Ray Tracing doesnt look like shit anymore --- res/shaders/lib/MaterialParameter.slang | 22 +- res/shaders/raytracing/ClosestHit.slang | 24 +- res/shaders/raytracing/Miss.slang | 9 +- res/shaders/raytracing/RayGen.slang | 215 ++++++++++++++++-- res/shaders/raytracing/RayTracingData.slang | 22 +- src/Editor/Window/PlayView.cpp | 4 + src/Editor/main.cpp | 2 +- src/Engine/Asset/LevelAsset.cpp | 5 +- src/Engine/Graphics/Enums.h | 11 + .../Graphics/RenderPass/RayTracingPass.cpp | 69 +++++- .../Graphics/RenderPass/RayTracingPass.h | 3 + src/Engine/Graphics/StaticMeshVertexData.cpp | 1 + src/Engine/Graphics/VertexData.cpp | 6 +- src/Engine/Graphics/Vulkan/Buffer.cpp | 2 +- src/Engine/Graphics/Vulkan/Command.cpp | 4 +- src/Engine/Graphics/Vulkan/Graphics.cpp | 10 +- src/Engine/Graphics/Vulkan/RayTracing.cpp | 2 +- src/Engine/Graphics/slang-compile.cpp | 15 +- src/Engine/MinimalEngine.h | 1 + src/Engine/Window/GameView.cpp | 19 +- src/Engine/Window/GameView.h | 1 + 21 files changed, 360 insertions(+), 87 deletions(-) diff --git a/res/shaders/lib/MaterialParameter.slang b/res/shaders/lib/MaterialParameter.slang index a60bb3f..2497619 100644 --- a/res/shaders/lib/MaterialParameter.slang +++ b/res/shaders/lib/MaterialParameter.slang @@ -31,7 +31,7 @@ struct FragmentParameter float4 qTangent : QTANGENT; float3 position_WS : POSITIONWS; float3 position_TS : POSITIONTS; - float3 viewDir_TS : VIEWDIRTS; + float3 cameraPos_TS : CAMPOSTS; float3 vertexColor : COLOR; float4 texCoords0 : TEXCOORDS0; float4 texCoords1 : TEXCOORDS1; @@ -58,10 +58,15 @@ struct FragmentParameter float3x3 worldToTangent = transpose(constructTBNFromQTangent(qTangent)); LightingParameter result; result.worldToTangent = worldToTangent; - result.viewDir_TS = viewDir_TS; + result.viewDir_TS = cameraPos_TS - position_TS; result.position_TS = position_TS; return result; } + + float3x3 getTangentToWorld() + { + return constructTBNFromQTangent(qTangent); + } #endif static FragmentParameter interpolate(FragmentParameter f0, FragmentParameter f1, FragmentParameter f2, float3 barycentricCoords) { @@ -71,10 +76,11 @@ struct FragmentParameter result.qTangent = f0.qTangent * barycentricCoords.x + f1.qTangent * barycentricCoords.y + f2.qTangent * barycentricCoords.z; result.position_WS = f0.position_WS * barycentricCoords.x + f1.position_WS * barycentricCoords.y + f2.position_WS * barycentricCoords.z; result.vertexColor = f0.vertexColor * barycentricCoords.x + f1.vertexColor * barycentricCoords.y + f2.vertexColor * barycentricCoords.z; - //for(uint i = 0; i < MAX_TEXCOORDS; ++i) - //{ - // result.texCoords[i] = f0.texCoords[i] * barycentricCoords.x + f1.texCoords[i] * barycentricCoords.y + f2.texCoords[i] * barycentricCoords.z; - //} + result.texCoords0 = f0.texCoords0 * barycentricCoords.x + f1.texCoords0 * barycentricCoords.y + f2.texCoords0 * barycentricCoords.z; + result.texCoords1 = f0.texCoords1 * barycentricCoords.x + f1.texCoords1 * barycentricCoords.y + f2.texCoords1 * barycentricCoords.z; + result.texCoords2 = f0.texCoords2 * barycentricCoords.x + f1.texCoords2 * barycentricCoords.y + f2.texCoords2 * barycentricCoords.z; + result.texCoords3 = f0.texCoords3 * barycentricCoords.x + f1.texCoords3 * barycentricCoords.y + f2.texCoords3 * barycentricCoords.z; + #endif return result; } @@ -99,11 +105,11 @@ struct VertexAttributes result.position_CS = clipPos; #ifndef POS_ONLY result.qTangent = qTangent; - float3x3 tbn = transpose(constructTBNFromQTangent(qTangent)); + float3x3 tbn = constructTBNFromQTangent(qTangent); result.position_TS = mul(tbn, worldPos.xyz); result.vertexColor = vertexColor; result.position_WS = worldPos.xyz; - result.viewDir_TS = mul(tbn, pViewParams.cameraPosition_WS.xyz - worldPos.xyz); + result.cameraPos_TS = mul(tbn, pViewParams.cameraPosition_WS.xyz); result.texCoords0 = float4(texCoords[0], texCoords[1]); result.texCoords1 = float4(texCoords[2], texCoords[3]); result.texCoords2 = float4(texCoords[4], texCoords[5]); diff --git a/res/shaders/raytracing/ClosestHit.slang b/res/shaders/raytracing/ClosestHit.slang index eba2d88..4fc7c07 100644 --- a/res/shaders/raytracing/ClosestHit.slang +++ b/res/shaders/raytracing/ClosestHit.slang @@ -36,23 +36,13 @@ void closestHit(inout RayPayload hitValue, in BuiltInTriangleIntersectionAttribu FragmentParameter params = FragmentParameter.interpolate(f0, f1, f2, barycentricCoords); - LightingParameter lightingParams = params.getLightingParameter(); MaterialParameter materialParams = params.getMaterialParameter(); - let brdf = Material.prepare(materialParams); + let brdf = Material.prepare(materialParams); + - float3 result = float3(0, 0, 0); - for(int i = 0; i < pLightEnv.numDirectionalLights; ++i) - { - result += pLightEnv.directionalLights[i].illuminate(lightingParams, brdf); - } - for(uint i = 0; i < pLightEnv.numPointLights; ++i) - { - result += pLightEnv.pointLights[i].illuminate(lightingParams, brdf); - } - result += brdf.evaluateAmbient(); - - hitValue.color = result; - hitValue.alpha = brdf.getAlpha(); - hitValue.intersection_WS = WorldRayOrigin() + RayTCurrent() * WorldRayDirection(); - hitValue.normal_WS = mul(params.getTangentToWorld(), brdf.getTangentNormal()); + hitValue.material.color = float4(brdf.baseColor, 1); + hitValue.material.emissive = float3(0, 0, 0); + hitValue.shading.position = WorldRayOrigin() + RayTCurrent() * WorldRayDirection(); + hitValue.shading.normal = cross(f2.position_WS - f0.position_WS, f1.position_WS - f0.position_WS); + hitValue.shading.normalLight = dot(hitValue.shading.normal, WorldRayDirection()) < 0 ? hitValue.shading.normal : -hitValue.shading.normal; } \ No newline at end of file diff --git a/res/shaders/raytracing/Miss.slang b/res/shaders/raytracing/Miss.slang index ce70e09..11c5001 100644 --- a/res/shaders/raytracing/Miss.slang +++ b/res/shaders/raytracing/Miss.slang @@ -3,8 +3,9 @@ import RayTracingData; [shader("miss")] void miss(inout RayPayload p) { - p.color = float3(0, 1, 0); - p.alpha = 1; - p.intersection_WS = float3(0, 0, 0); - p.normal_WS = float3(0, 0, 0); + p.shading.position = WorldRayDirection() * 1000.0f; + p.shading.normal = -WorldRayDirection(); + p.shading.normalLight = -WorldRayDirection(); + p.material.color = float4(0, 0, 0, 0); + p.material.emissive = float3(pRayTracingParams.skyBox.Sample(pRayTracingParams.skyBoxSampler, WorldRayDirection()).xyz); } \ No newline at end of file diff --git a/res/shaders/raytracing/RayGen.slang b/res/shaders/raytracing/RayGen.slang index ea07ab6..1fda7a8 100644 --- a/res/shaders/raytracing/RayGen.slang +++ b/res/shaders/raytracing/RayGen.slang @@ -1,36 +1,213 @@ import Common; +import LightEnv; import RayTracingData; +struct Ray +{ + float3 o; + float3 d; +} + +const static float S_O = 6.9; +const static float f = 0.035; +const static float A = 0.4; +const static float ka = 0; +const static float ks = 0; +const static float3 fogEmm = float3(0, 0.01, 0.01); + +struct SampleParams +{ + uint pass; + uint samplesPerPixel; +}; +layout(push_constant) +ConstantBuffer pSamps; + +float3 rand01(uint3 x){ // pseudo-random number generator + for (int i=3; i-->0;) x = ((x>>8U)^x.yzx)*1103515245U; + return float3(x)*(1.0/float(0xffffffffU)); +} + +float3 nextEventEstimation(float3 accmat, float3 w, float3 x, float3 nl, float kt, bool useAtt, float3 rnd) { + float3 result = float3(0); + // Direct Illumination: Next Event Estimation over any present lights + /*for(int i = meshLights.length(); i-->0;) { + MeshDescriptor mesh = meshes[meshLights[i]]; + for(int j = 0; j < mesh.numIndices; j+=3) { + float3 A = float3(vertices[mesh.vertexOffset + indices[mesh.indexOffset + j + 0]]); + float3 B = float3(vertices[mesh.vertexOffset + indices[mesh.indexOffset + j + 1]]); + float3 C = float3(vertices[mesh.vertexOffset + indices[mesh.indexOffset + j + 2]]); + float b1 = 1 - sqrt(rnd.x); + float b2 = (1 - rnd.y) * sqrt(rnd.x); + float b3 = rnd.y * sqrt(rnd.x); + float3 P = A * b1 + B * b2 + C * b3; + float3 omega = P - x; + float3 l = normalize(omega); + float v = 0.f; + if(intersect(Ray(x,l), matls, paramsls, sphereId, triId) && triId == j) { + v = 1.0f; + } + float3 e1 = C - A; + float3 e2 = B - A; + float area = length(cross(e1, e2)) / 2; + float rayLen = length(omega); + float cosTheta = dot(nl, l); + float cosThetaDash = dot(paramsls.n, -l); + float factor = area * (cosThetaDash / (rayLen * rayLen)); + if(useAtt) { + float tau = phase(w, l) * exp(-kt * length(x - paramsls.x)); + result += tau * matls.e * max(cosTheta, 0) * factor; + } else { + result += accmat * (matls.e * max(cosTheta, 0) * factor) / pi; + } + } + }*/ + return result; +} [shader("raygeneration")] void raygen() { - uint3 LaunchID = DispatchRaysIndex(); - uint3 LaunchSize = DispatchRaysDimensions(); + uint2 pix = DispatchRaysIndex().xy; + uint2 imgdim = DispatchRaysDimensions().xy; - const float2 pixelCenter = float2(LaunchID.xy) + float2(0.5, 0.5); - const float2 inUV = pixelCenter / float2(LaunchSize.xy); - float2 d = float2(inUV.x, 1 - inUV.y) * 2.0 - 1.0; - float4 target = mul(pViewParams.inverseProjection, float4(d.x, d.y, 1, 1)); + //-- define cam + Ray cam = Ray(pViewParams.cameraPosition_WS.xyz, pViewParams.cameraForward_WS.xyz); + float3 cx = -normalize(cross(cam.d, abs(cam.d.y) < 0.9 ? float3(0, 1, 0) : float3(0, 0, 1))), cy = cross(cam.d, cx); + const float2 sdim = float2(0.036, 0.024); + + float S_I = (S_O * f) / (S_O - f); + + //-- sample sensor + float2 rnd2 = 2*rand01(uint3(pix, pSamps.pass)).xy; // vvv tent filter sample + float2 tent = float2(rnd2.x<1 ? sqrt(rnd2.x)-1 : 1-sqrt(2-rnd2.x), rnd2.y<1 ? sqrt(rnd2.y)-1 : 1-sqrt(2-rnd2.y)); + float2 s = ((pix + 0.5 * (0.5 + float2((pSamps.pass/2)%2, pSamps.pass%2) + tent)) / float2(imgdim) - 0.5) * sdim; + float3 spos = cam.o + cx*s.x + cy*s.y, lc = cam.o + cam.d * 0.035; // sample on 3d sensor plane + float3 accrad=float3(0), accmat=float3(1); // initialize accumulated radiance and bxdf + Ray r = Ray(lc, normalize(lc - spos)); // construct ray + + + //-- setup lens + float3 lensP = lc; + float3 lensN = -cam.d; + float3 lensX = cross(lensN, float3(0, 1, 0)); // the exact vector doesnt matter + float3 lensY = cross(lensN, lensX); + uint3 rndSeed = uint3(pix, pSamps.pass); + float2 rnd01 = rand01(rndSeed).xy; + + float3 lensSample = lensP + rnd01.x * A * lensX + rnd01.y * A * lensY; + + float3 focalPoint = cam.o + (S_O + S_I) * cam.d; + float t = dot(focalPoint - r.o, lensN) / dot(r.d, lensN); + float3 focus = r.o + t * r.d; RayDesc rayDesc; - rayDesc.Origin = mul(pViewParams.inverseViewMatrix, float4(0, 0, 0, 1)).xyz; - rayDesc.Direction = mul(pViewParams.inverseViewMatrix, float4(normalize(target.xyz), 0)).xyz; + rayDesc.Origin = lensSample; + rayDesc.Direction = normalize(focus - lensSample); rayDesc.TMin = 0.001; rayDesc.TMax = 10000.0; - const uint maxRays = 12; - float3 color = float3(0, 0, 0); - float alpha; - for(uint i = 0; i < maxRays; ++i) { - RayPayload payload; + const uint maxDepth = 12; + float emissive = 1; + RayPayload payload; + for(uint depth = 0; depth < maxDepth; ++depth) { TraceRay(pRayTracingParams.scene, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 0, 0, rayDesc, payload); - color = color.rgb * alpha + payload.color * payload.alpha; - alpha = alpha + payload.alpha; - rayDesc.Origin = payload.intersection_WS; - if(alpha > 0.9){ + float3 rnd = rand01(uint3(pix, pSamps.pass*maxDepth + depth)); + //float kt = ka + ks; + //float s = -log(rnd.z) / kt; + //float3 xs = r.o + s * r.d; + //if (s < t) { + // float p = kt * rnd.z; + // if (depth > 5) { + // if (rnd.z >= p) break; + // else accmat /= p; + // } + // float3 ldirect = nextEventEstimation(accmat, r.d, xs, -r.d, kt, true, rnd); + // accrad += (fogEmm + ks * ldirect) / kt; + // accmat *= ks / kt; + // rayDesc.Origin = xs; + // rayDesc.Direction = float3( + // cos(2*PI*rnd.x)*sqrt(1-rnd.y*rnd.y), + // sin(2*PI*rnd.x)*sqrt(1-rnd.y*rnd.y), + // rnd.y + // ); + // continue; + //} + float p = max(max(payload.material.color.x, payload.material.color.y), payload.material.color.z); + if(depth > 5) { + if (rnd.z >= p) break; + else accmat /= p; + } + accrad += accmat * payload.material.emissive * emissive; + accmat *= payload.material.color.xyz; + if (payload.material.color.w == 0) { break; } - } + //-- Ideal DIFFUSE reflection + else if (payload.material.color.w == 1) { + //if(bool(useNEE)) { + // accrad += nextEventEstimation(accmat, r.d, params.x, params.nl, kt, false, rnd); + //} + for(uint i = 0; i < pLightEnv.numDirectionalLights; ++i) { + float3 x = payload.shading.position; + float3 l = -pLightEnv.directionalLights[i].direction.xyz; + float3 nl = l; + rayDesc.Origin = x; + rayDesc.Direction = l; + TraceRay(pRayTracingParams.scene, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 0, 0, rayDesc, payload); - pRayTracingParams.image[int2(LaunchID.xy)] = float4(color, alpha); + // we have missed all geometry, so directional light is affecting us + if(payload.material.color.w == 0) { + float omega = 2 * PI; + accrad += accmat / PI * max(dot(l, nl), 0) * pLightEnv.directionalLights[i].color.xyz * omega; + } + } + //for(uint i = 0; i < pLightEnv.numPointLights; ++i) { + // float3 x = payload.shading.position; + // float3 l = pLightEnv.pointLights[i].position_WS.xyz - payload.shading.position; + // float3 nl = -payload.shading.normal; + // rayDesc.Origin = x; + // rayDesc.Direction = l; + // TraceRay(pRayTracingParams.scene, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 0, 0, rayDesc, payload); +// + // // hitting only after the light + // if(length(payload.shading.position - x) > length(pLightEnv.pointLights[i].position_WS.xyz - x)) + // { + // float omega = 2 * PI; + // accrad += accmat / PI * max(dot(l,nl),0) * pLightEnv.pointLights[i].colorRange.xyz * omega; + // } + //} + // Indirect Illumination: cosine-weighted importance sampling + float r1 = 2 * PI * rnd.x, r2 = rnd.y, r2s = sqrt(r2); + float3 w = payload.shading.normalLight, u = normalize((cross(abs(w.x)>0.1 ? float3(0,1,0) : float3(1,0,0), w))), v = cross(w,u); + rayDesc.Origin = payload.shading.position; + rayDesc.Direction = normalize(u*cos(r1)*r2s + v * sin(r1)*r2s + w * sqrt(1 - r2)); + emissive = 0; // in the next bounce, consider reflective part only! + } + //-- Ideal SPECULAR reflection + else if (payload.material.color.w == 2) { + rayDesc.Origin = payload.shading.position; + rayDesc.Direction = reflect(r.d,payload.shading.normal); + emissive = 1; + } + //-- Ideal dielectric REFRACTION + else if (payload.material.color.w == 3) { + bool into = all(payload.shading.normal==payload.shading.normalLight); + float cos2t, nc=1, nt=1.5, nnt = into ? nc/nt : nt/nc, ddn = dot(r.d,payload.shading.normalLight); + if ((cos2t = 1 - nnt * nnt*(1 - ddn * ddn)) >= 0) { // Fresnel reflection/refraction + float3 tdir = normalize(r.d*nnt - payload.shading.normal * ((into ? 1 : -1)*(ddn*nnt + sqrt(cos2t)))); + float a = nt - nc, b = nt + nc, R0 = a*a/(b*b), c = 1 - (into ? -ddn : dot(tdir,payload.shading.normal)); + float Re = R0 + (1 - R0)*c*c*c*c*c, Tr = 1 - Re, P = 0.25 + 0.5*Re, RP = Re/P, TP = Tr/(1-P); + rayDesc.Origin = payload.shading.position; + rayDesc.Direction = rnd.x < P ? reflect(r.d,payload.shading.normal) : tdir; // pick reflection with probability P + accmat *= rnd.x < P ? RP : TP; // energy compensation + } else { + rayDesc.Origin = payload.shading.position; + rayDesc.Direction = reflect(r.d,payload.shading.normal); // Total internal reflection + } + emissive = 1; + } + } + if(pSamps.pass == 0) pRayTracingParams.radianceAccumulator[pix] = float4(0); + pRayTracingParams.radianceAccumulator[pix] += float4(accrad / pSamps.samplesPerPixel, 0); + pRayTracingParams.image[pix] = float4(clamp(pRayTracingParams.radianceAccumulator[pix].xyz, 0, 1), 1); } diff --git a/res/shaders/raytracing/RayTracingData.slang b/res/shaders/raytracing/RayTracingData.slang index 16ba583..de7876d 100644 --- a/res/shaders/raytracing/RayTracingData.slang +++ b/res/shaders/raytracing/RayTracingData.slang @@ -3,8 +3,11 @@ import MaterialParameter; struct RayTracingParams { RaytracingAccelerationStructure scene; + RWTexture2D radianceAccumulator; RWTexture2D image; StructuredBuffer indexBuffer; + TextureCube skyBox; + SamplerState skyBoxSampler; }; layout(set=5) ParameterBlock pRayTracingParams; @@ -15,10 +18,21 @@ struct CallablePayload float3 color; }; +struct ShadingParams +{ + float3 position; + float3 normal; + float3 normalLight; +}; + +struct MaterialParams +{ + float4 color; + float3 emissive; +} + struct RayPayload { - float3 color; - float alpha; - float3 intersection_WS; - float3 normal_WS; + ShadingParams shading; + MaterialParams material; }; \ No newline at end of file diff --git a/src/Editor/Window/PlayView.cpp b/src/Editor/Window/PlayView.cpp index 600451d..10d9770 100644 --- a/src/Editor/Window/PlayView.cpp +++ b/src/Editor/Window/PlayView.cpp @@ -1,5 +1,6 @@ #include "PlayView.h" #include "Window/Window.h" +#include "Component/Mesh.h" using namespace Seele; using namespace Seele::Editor; @@ -45,4 +46,7 @@ void PlayView::keyCallback(KeyCode code, InputAction action, KeyModifier modifie std::cout << cam.getCameraPosition() << std::endl; std::cout << tra.getRotation() << std::endl; } + if (code == KeyCode::KEY_R && action == InputAction::RELEASE) { + getGlobals().useRayTracing = !getGlobals().useRayTracing; + } } diff --git a/src/Editor/main.cpp b/src/Editor/main.cpp index e957624..1e99107 100644 --- a/src/Editor/main.cpp +++ b/src/Editor/main.cpp @@ -93,7 +93,7 @@ int main() { // .filePath = sourcePath / "import/models/culling.fbx", //}); AssetImporter::importTexture(TextureImportArgs{ - .filePath = sourcePath / "import/textures/skyboxsun5deg_tn.jpg", + .filePath = sourcePath / "import/textures/skybox.jpg", .type = TextureImportType::TEXTURE_CUBEMAP, }); // AssetImporter::importMesh(MeshImportArgs{ diff --git a/src/Engine/Asset/LevelAsset.cpp b/src/Engine/Asset/LevelAsset.cpp index 173d424..27ce4c8 100644 --- a/src/Engine/Asset/LevelAsset.cpp +++ b/src/Engine/Asset/LevelAsset.cpp @@ -1,4 +1,5 @@ #include "LevelAsset.h" +#include "Serialization/Serialization.h" using namespace Seele; @@ -8,6 +9,6 @@ LevelAsset::LevelAsset(std::string_view folderPath, std::string_view name) : Ass LevelAsset::~LevelAsset() {} -void LevelAsset::save(ArchiveBuffer&) const {} +void LevelAsset::save(ArchiveBuffer& buffer) const { } -void LevelAsset::load(ArchiveBuffer&) {} +void LevelAsset::load(ArchiveBuffer& buffer) { } diff --git a/src/Engine/Graphics/Enums.h b/src/Engine/Graphics/Enums.h index 7b3e5ad..db8538c 100644 --- a/src/Engine/Graphics/Enums.h +++ b/src/Engine/Graphics/Enums.h @@ -1487,6 +1487,17 @@ typedef enum SeBufferUsageFlagBits { SE_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, SE_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400, SE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = 0x00020000, + + SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000, + SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000, + SE_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400, + SE_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00008000, + SE_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00010000, + SE_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 0x00200000, + SE_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00400000, + SE_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 0x04000000, + SE_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 0x00800000, + SE_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT = 0x01000000, SE_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } SeBufferUsageFlagBits; typedef SeFlags SeBufferUsageFlags; diff --git a/src/Engine/Graphics/RenderPass/RayTracingPass.cpp b/src/Engine/Graphics/RenderPass/RayTracingPass.cpp index 73c8bb3..f740f81 100644 --- a/src/Engine/Graphics/RenderPass/RayTracingPass.cpp +++ b/src/Engine/Graphics/RenderPass/RayTracingPass.cpp @@ -9,6 +9,11 @@ using namespace Seele; +struct SampleParams { + uint32 pass; + uint32 samplesPerPixel; +}; + RayTracingPass::RayTracingPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics, scene) { paramsLayout = graphics->createDescriptorLayout("pRayTracingParams"); paramsLayout->addDescriptorBinding(Gfx::DescriptorBinding{ @@ -21,8 +26,20 @@ RayTracingPass::RayTracingPass(Gfx::PGraphics graphics, PScene scene) : RenderPa }); paramsLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 2, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE, + }); + paramsLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 3, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, }); + paramsLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 4, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }); + paramsLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 5, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, + }); paramsLayout->create(); pipelineLayout = graphics->createPipelineLayout("RayTracing"); pipelineLayout->addDescriptorLayout(viewParamsLayout); @@ -31,15 +48,30 @@ RayTracingPass::RayTracingPass(Gfx::PGraphics graphics, PScene scene) : RenderPa pipelineLayout->addDescriptorLayout(scene->getLightEnvironment()->getDescriptorLayout()); pipelineLayout->addDescriptorLayout(StaticMeshVertexData::getInstance()->getVertexDataLayout()); pipelineLayout->addDescriptorLayout(StaticMeshVertexData::getInstance()->getInstanceDataLayout()); + pipelineLayout->addPushConstants(Gfx::SePushConstantRange{ + .stageFlags = Gfx::SE_SHADER_STAGE_RAYGEN_BIT_KHR, + .offset = 0, + .size = sizeof(SampleParams), + }); graphics->getShaderCompiler()->registerRenderPass("RayTracing", Gfx::PassConfig{ .baseLayout = pipelineLayout, .mainFile = "ClosestHit", .useMaterial = true, .rayTracing = true, }); + skyBox = AssetRegistry::findTexture("", "skybox")->getTexture().cast(); + skyBoxSampler = graphics->createSampler({}); } -void RayTracingPass::beginFrame(const Component::Camera& cam) { RenderPass::beginFrame(cam); } +static uint32 i = 0; +static Component::Camera lastCam; +void RayTracingPass::beginFrame(const Component::Camera& cam) { + RenderPass::beginFrame(cam); + if (lastCam.getCameraPosition() != cam.getCameraPosition() || lastCam.getCameraForward() != cam.getCameraForward()) { + lastCam = cam; + i = 0; + } +} void RayTracingPass::render() { Array callableGroups; @@ -104,8 +136,11 @@ void RayTracingPass::render() { }); Gfx::PDescriptorSet desc = paramsLayout->allocateDescriptorSet(); desc->updateAccelerationStructure(0, 0, tlas); - desc->updateTexture(1, 0, texture); - desc->updateBuffer(2, 0, StaticMeshVertexData::getInstance()->getIndexBuffer()); + desc->updateTexture(1, 0, radianceAccumulator); + desc->updateTexture(2, 0, texture); + desc->updateBuffer(3, 0, StaticMeshVertexData::getInstance()->getIndexBuffer()); + desc->updateTexture(4, 0, skyBox); + desc->updateSampler(5, 0, skyBoxSampler); desc->writeChanges(); Gfx::ORenderCommand command = graphics->createRenderCommand("RayTracing"); @@ -115,7 +150,22 @@ void RayTracingPass::render() { command->bindDescriptor({viewParamsSet, StaticMeshVertexData::getInstance()->getInstanceDataSet(), StaticMeshVertexData::getInstance()->getVertexDataSet(), Material::getDescriptorSet(), scene->getLightEnvironment()->getDescriptorSet(), desc}); - command->traceRays(texture->getWidth(), texture->getHeight(), 1); + SampleParams sampleParams = { + .pass = 0, + .samplesPerPixel = 10000, + }; + // for (uint32 i = 0; i < sampleParams.samplesPerPixel; ++i) + { + sampleParams.pass = i; + command->pushConstants(Gfx::SE_SHADER_STAGE_RAYGEN_BIT_KHR, 0, sizeof(SampleParams), &sampleParams); + command->traceRays(texture->getWidth(), texture->getHeight(), 1); + radianceAccumulator->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); + texture->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); + } + i++; + std::cout << i << std::endl; texture->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, Gfx::SE_ACCESS_TRANSFER_READ_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT); Array commands; @@ -130,6 +180,15 @@ void RayTracingPass::render() { void RayTracingPass::endFrame() {} void RayTracingPass::publishOutputs() { + radianceAccumulator = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, + .width = viewport->getOwner()->getFramebufferWidth(), + .height = viewport->getOwner()->getFramebufferHeight(), + .usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT, + }); + radianceAccumulator->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT | Gfx::SE_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); texture = graphics->createTexture2D(TextureCreateInfo{ .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, .width = viewport->getOwner()->getFramebufferWidth(), @@ -140,7 +199,7 @@ void RayTracingPass::publishOutputs() { Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT | Gfx::SE_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); ShaderCompilationInfo compileInfo = { - .name = "RT", + .name = "RayGenMiss", .modules = {"RayGen", "Miss"}, .entryPoints = {{"raygen", "RayGen"}, {"miss", "Miss"}}, .defines = {{"RAY_TRACING", "1"}}, diff --git a/src/Engine/Graphics/RenderPass/RayTracingPass.h b/src/Engine/Graphics/RenderPass/RayTracingPass.h index 7a16606..5866142 100644 --- a/src/Engine/Graphics/RenderPass/RayTracingPass.h +++ b/src/Engine/Graphics/RenderPass/RayTracingPass.h @@ -17,7 +17,10 @@ class RayTracingPass : public RenderPass { private: Gfx::ODescriptorLayout paramsLayout; Gfx::OPipelineLayout pipelineLayout; + Gfx::OTexture2D radianceAccumulator; Gfx::OTexture2D texture; + Gfx::PTextureCube skyBox; + Gfx::OSampler skyBoxSampler; Gfx::ORayGenShader rayGen; Gfx::OMissShader miss; Gfx::PRayTracingPipeline pipeline; diff --git a/src/Engine/Graphics/StaticMeshVertexData.cpp b/src/Engine/Graphics/StaticMeshVertexData.cpp index 8c875ce..feb6f01 100644 --- a/src/Engine/Graphics/StaticMeshVertexData.cpp +++ b/src/Engine/Graphics/StaticMeshVertexData.cpp @@ -149,6 +149,7 @@ void StaticMeshVertexData::updateBuffers() { .size = verticesAllocated * sizeof(Vector), .data = (uint8*)posData.data(), }, + .usage = Gfx::SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, .name = "Positions", }); normals = graphics->createShaderBuffer(ShaderBufferCreateInfo{ diff --git a/src/Engine/Graphics/VertexData.cpp b/src/Engine/Graphics/VertexData.cpp index ff677ce..5920cc5 100644 --- a/src/Engine/Graphics/VertexData.cpp +++ b/src/Engine/Graphics/VertexData.cpp @@ -249,12 +249,8 @@ void VertexData::commitMeshes() { .name = "PrimitiveIndicesBuffer", }); updateBuffers(); - vertexIndices.clear(); - primitiveIndices.clear(); - indices.clear(); - meshlets.clear(); dirty = false; - // graphics->buildBottomLevelAccelerationStructures(std::move(dataToBuild)); + graphics->buildBottomLevelAccelerationStructures(std::move(dataToBuild)); } MeshId VertexData::allocateVertexData(uint64 numVertices) { diff --git a/src/Engine/Graphics/Vulkan/Buffer.cpp b/src/Engine/Graphics/Vulkan/Buffer.cpp index 9986710..cfcf814 100644 --- a/src/Engine/Graphics/Vulkan/Buffer.cpp +++ b/src/Engine/Graphics/Vulkan/Buffer.cpp @@ -488,7 +488,7 @@ IndexBuffer::IndexBuffer(PGraphics graphics, const IndexBufferCreateInfo& create : Gfx::IndexBuffer(graphics->getFamilyMapping(), createInfo), Vulkan::Buffer(graphics, createInfo.sourceData.size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, createInfo.sourceData.owner, false, createInfo.name) { getAlloc()->updateContents(createInfo.sourceData.offset, createInfo.sourceData.size, createInfo.sourceData.data); //getAlloc()->pipelineBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_INDEX_READ_BIT, diff --git a/src/Engine/Graphics/Vulkan/Command.cpp b/src/Engine/Graphics/Vulkan/Command.cpp index 76a5f4a..1b3dbd9 100644 --- a/src/Engine/Graphics/Vulkan/Command.cpp +++ b/src/Engine/Graphics/Vulkan/Command.cpp @@ -175,6 +175,8 @@ RenderCommand::~RenderCommand() { vkFreeCommandBuffers(graphics->getDevice(), ow void RenderCommand::begin(PRenderPass renderPass, PFramebuffer framebuffer, VkQueryPipelineStatisticFlags pipelineFlags) { threadId = std::this_thread::get_id(); + pipeline = nullptr; + rtPipeline = nullptr; ready = false; VkCommandBufferInheritanceInfo inheritanceInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, @@ -323,7 +325,7 @@ void RenderCommand::bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) { void RenderCommand::pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) { assert(threadId == std::this_thread::get_id()); - vkCmdPushConstants(handle, pipeline->getLayout(), stage, offset, size, data); + vkCmdPushConstants(handle, pipeline == nullptr ? rtPipeline->getLayout() : pipeline->getLayout(), stage, offset, size, data); } void RenderCommand::draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) { diff --git a/src/Engine/Graphics/Vulkan/Graphics.cpp b/src/Engine/Graphics/Vulkan/Graphics.cpp index 57565fe..3c1499b 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.cpp +++ b/src/Engine/Graphics/Vulkan/Graphics.cpp @@ -507,7 +507,7 @@ void Graphics::buildBottomLevelAccelerationStructures(Array .pNext = nullptr, .vertexFormat = VK_FORMAT_R32G32B32_SFLOAT, .vertexData = vertexDataAddress, - .vertexStride = sizeof(Vector4), + .vertexStride = sizeof(Vector), .maxVertex = static_cast(blas->getVertexCount()), .indexType = VK_INDEX_TYPE_UINT32, .indexData = indexDataAddress, @@ -790,7 +790,7 @@ void Graphics::pickPhysicalDevice() { }; meshShaderFeatures = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT, - .pNext = nullptr, + .pNext = &accelerationFeatures, .taskShader = true, .meshShader = true, .meshShaderQueries = true, @@ -923,9 +923,9 @@ void Graphics::createDevice(GraphicsInitializer initializer) { #ifdef __APPLE__ initializer.deviceExtensions.add("VK_KHR_portability_subset"); #endif - // initializer.deviceExtensions.add(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); - // initializer.deviceExtensions.add(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); - // initializer.deviceExtensions.add(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); + initializer.deviceExtensions.add(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); + initializer.deviceExtensions.add(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); + initializer.deviceExtensions.add(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); VkDeviceCreateInfo deviceInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = &features, diff --git a/src/Engine/Graphics/Vulkan/RayTracing.cpp b/src/Engine/Graphics/Vulkan/RayTracing.cpp index 7eee20f..7cbc370 100644 --- a/src/Engine/Graphics/Vulkan/RayTracing.cpp +++ b/src/Engine/Graphics/Vulkan/RayTracing.cpp @@ -23,7 +23,7 @@ BottomLevelAS::BottomLevelAS(PGraphics graphics, const Gfx::BottomLevelASCreateI }; VertexData* vertexData = createInfo.mesh->vertexData; MeshData meshData = vertexData->getMeshData(createInfo.mesh->id); - vertexOffset = vertexData->getMeshOffset(createInfo.mesh->id) * sizeof(Vector4); + vertexOffset = vertexData->getMeshOffset(createInfo.mesh->id) * sizeof(Vector); vertexCount = vertexData->getMeshVertexCount(createInfo.mesh->id); indexOffset = meshData.firstIndex * sizeof(uint32); primitiveCount = meshData.numIndices / 3; diff --git a/src/Engine/Graphics/slang-compile.cpp b/src/Engine/Graphics/slang-compile.cpp index 974d1a4..a7453d5 100644 --- a/src/Engine/Graphics/slang-compile.cpp +++ b/src/Engine/Graphics/slang-compile.cpp @@ -142,15 +142,18 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg for (size_t i = 0; i < signature->getParameterCount(); ++i) { auto param = signature->getParameterByIndex(i); layout->addMapping(param->getName(), param->getBindingIndex()); - //std::cout << param->getName() << ": " << param->getBindingIndex() << std::endl; + std::cout << param->getName() << ": " << param->getBindingIndex() << std::endl; } // workaround - // layout->addMapping("pVertexData", 1); - // layout->addMapping("pMaterial", 4); - // layout->addMapping("pLightEnv", 3); - // layout->addMapping("pRayTracingParams", 5); - // layout->addMapping("pScene", 2); + if (info.name == "RayGenMiss") + { + layout->addMapping("pVertexData", 1); + layout->addMapping("pResources", 4); + layout->addMapping("pLightEnv", 3); + layout->addMapping("pRayTracingParams", 5); + layout->addMapping("pScene", 2); + } // layout->addMapping("pWaterMaterial", 1); } diff --git a/src/Engine/MinimalEngine.h b/src/Engine/MinimalEngine.h index 42b8803..bd07972 100644 --- a/src/Engine/MinimalEngine.h +++ b/src/Engine/MinimalEngine.h @@ -148,6 +148,7 @@ struct Globals { bool usePositionOnly = true; bool useDepthCulling = true; bool useLightCulling = true; + bool useRayTracing = false; bool running = true; }; Globals& getGlobals(); diff --git a/src/Engine/Window/GameView.cpp b/src/Engine/Window/GameView.cpp index 96539cd..5b381f1 100644 --- a/src/Engine/Window/GameView.cpp +++ b/src/Engine/Window/GameView.cpp @@ -8,9 +8,9 @@ #include "Graphics/RenderPass/CachedDepthPass.h" #include "Graphics/RenderPass/DepthCullingPass.h" #include "Graphics/RenderPass/LightCullingPass.h" +#include "Graphics/RenderPass/RayTracingPass.h" #include "Graphics/RenderPass/RenderGraphResources.h" #include "Graphics/RenderPass/VisibilityPass.h" -#include "Graphics/RenderPass/RayTracingPass.h" #include "System/CameraUpdater.h" #include "System/LightGather.h" #include "System/MeshUpdater.h" @@ -28,11 +28,12 @@ GameView::GameView(Gfx::PGraphics graphics, PWindow window, const ViewportCreate renderGraph.addPass(new VisibilityPass(graphics, scene)); renderGraph.addPass(new LightCullingPass(graphics, scene)); renderGraph.addPass(new BasePass(graphics, scene)); - - //renderGraph.addPass(new RayTracingPass(graphics, scene)); - renderGraph.setViewport(viewport); renderGraph.createRenderPass(); + + rayTracingGraph.addPass(new RayTracingPass(graphics, scene)); + rayTracingGraph.setViewport(viewport); + rayTracingGraph.createRenderPass(); } GameView::~GameView() {} @@ -66,7 +67,11 @@ void GameView::render() { if (c.mainCamera) cam = c; }); - renderGraph.render(cam); + if (getGlobals().useRayTracing) { + rayTracingGraph.render(cam); + } else { + renderGraph.render(cam); + } } void GameView::applyArea(URect) { renderGraph.setViewport(viewport); } @@ -84,9 +89,7 @@ void GameView::reloadGame() { systemGraph->addSystem(new System::CameraUpdater(scene)); } -void GameView::keyCallback(KeyCode code, InputAction action, KeyModifier modifier) { - keyboardSystem->keyCallback(code, action, modifier); -} +void GameView::keyCallback(KeyCode code, InputAction action, KeyModifier modifier) { keyboardSystem->keyCallback(code, action, modifier); } void GameView::mouseMoveCallback(double xPos, double yPos) { keyboardSystem->mouseCallback(xPos, yPos); } diff --git a/src/Engine/Window/GameView.h b/src/Engine/Window/GameView.h index 7fb949d..a898651 100644 --- a/src/Engine/Window/GameView.h +++ b/src/Engine/Window/GameView.h @@ -28,6 +28,7 @@ class GameView : public View { OScene scene; GameInterface gameInterface; RenderGraph renderGraph; + RenderGraph rayTracingGraph; PSystemGraph systemGraph; System::PKeyboardInput keyboardSystem;