yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
13dd01489
master
1// main.cpp 2 3// This file implements an example of hardware ray-tracing using 4// Slang shaders and the `slang-rhi` graphics API. 5 6#include "core/slang-basic.h" 7#include "examples/example-base/example-base.h" 8#include "platform/vector-math.h" 9#include "platform/window.h" 10#include "slang-com-ptr.h" 11#include "slang-rhi.h" 12#include "slang-rhi/acceleration-structure-utils.h" 13#include "slang-rhi/shader-cursor.h" 14#include "slang.h" 15 16using namespace rhi ; 17using namespace Slang ; 18 19static const ExampleResources resourceBase ("ray-tracing-pipeline" ); 20 21struct Uniforms 22{ 23float screenWidth ,screenHeight ; 24float focalLength = 24.0f ,frameHeight = 24.0f ; 25float cameraDir [4 ]; 26float cameraUp [4 ]; 27float cameraRight [4 ]; 28float cameraPosition [4 ]; 29float lightDir [4 ]; 30}; 31 32struct Vertex 33{ 34float position [3 ]; 35}; 36 37// Define geometry data for our test scene. 38// The scene contains a floor plane, and a cube placed on top of it at the center. 39static const int kVertexCount = 24 ; 40static const Vertex kVertexData [kVertexCount ]= { 41// Floor plane 42 {{-100.0f ,0 ,100.0f }}, 43 {{100.0f ,0 ,100.0f }}, 44 {{100.0f ,0 ,-100.0f }}, 45 {{-100.0f ,0 ,-100.0f }}, 46// Cube face (+y). 47 {{-1.0f ,2.0 ,1.0f }}, 48 {{1.0f ,2.0 ,1.0f }}, 49 {{1.0f ,2.0 ,-1.0f }}, 50 {{-1.0f ,2.0 ,-1.0f }}, 51// Cube face (+z). 52 {{-1.0f ,0.0 ,1.0f }}, 53 {{1.0f ,0.0 ,1.0f }}, 54 {{1.0f ,2.0 ,1.0f }}, 55 {{-1.0f ,2.0 ,1.0f }}, 56// Cube face (-z). 57 {{-1.0f ,0.0 ,-1.0f }}, 58 {{-1.0f ,2.0 ,-1.0f }}, 59 {{1.0f ,2.0 ,-1.0f }}, 60 {{1.0f ,0.0 ,-1.0f }}, 61// Cube face (-x). 62 {{-1.0f ,0.0 ,-1.0f }}, 63 {{-1.0f ,0.0 ,1.0f }}, 64 {{-1.0f ,2.0 ,1.0f }}, 65 {{-1.0f ,2.0 ,-1.0f }}, 66// Cube face (+x). 67 {{1.0f ,2.0 ,-1.0f }}, 68 {{1.0f ,2.0 ,1.0f }}, 69 {{1.0f ,0.0 ,1.0f }}, 70 {{1.0f ,0.0 ,-1.0f }}, 71}; 72static const int kIndexCount = 36 ; 73static const int kIndexData [kIndexCount ]= {0 ,1 ,2 ,0 ,2 ,3 ,4 ,5 ,6 ,4 ,6 ,7 , 748 ,9 ,10 ,8 ,10 ,11 ,12 ,13 ,14 ,12 ,14 ,15 , 7516 ,17 ,18 ,16 ,18 ,19 ,20 ,21 ,22 ,20 ,22 ,23 }; 76 77struct Primitive 78{ 79float data [4 ]; 80float color [4 ]; 81}; 82static const int kPrimitiveCount = 12 ; 83static const Primitive kPrimitiveData [kPrimitiveCount ]= { 84 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.75f ,0.8f ,0.85f ,1.0f }}, 85 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.75f ,0.8f ,0.85f ,1.0f }}, 86 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 87 {{0.0f ,1.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 88 {{0.0f ,0.0f ,1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 89 {{0.0f ,0.0f ,1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 90 {{0.0f ,0.0f ,-1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 91 {{0.0f ,0.0f ,-1.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 92 {{-1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 93 {{-1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 94 {{1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 95 {{1.0f ,0.0f ,0.0f ,0.0f }, {0.95f ,0.85f ,0.05f ,1.0f }}, 96}; 97 98 99// We need to use a rasterization pipeline to copy the ray-traced image 100// to the swapchain. To do so we need to render a full-screen triangle. 101// We will define a small helper type that defines the data for such a triangle. 102// 103struct FullScreenTriangle 104{ 105struct Vertex 106 { 107float position [2 ]; 108 }; 109 110enum 111 { 112kVertexCount = 3 113 }; 114 115static const Vertex kVertices [kVertexCount ]; 116}; 117const FullScreenTriangle ::Vertex FullScreenTriangle ::kVertices [FullScreenTriangle ::kVertexCount ]= { 118 {{-1 ,-1 }}, 119 {{-1 ,3 }}, 120 {{3 ,-1 }}, 121}; 122 123// The example application will be implemented as a `struct`, so that 124// we can scope the resources it allocates without using global variables. 125// 126struct RayTracing :public WindowedAppBase 127{ 128 129 130Uniforms gUniforms = {}; 131 132 133// Many Slang API functions return detailed diagnostic information 134// (error messages, warnings, etc.) as a "blob" of data, or return 135// a null blob pointer instead if there were no issues. 136// 137// For convenience, we define a subroutine that will dump the information 138// in a diagnostic blob if one is produced, and skip it otherwise. 139// 140void diagnoseIfNeeded (slang::IBlob * diagnosticsBlob ) 141 { 142if (diagnosticsBlob != nullptr ) 143 { 144printf ("%s" , (const char * )diagnosticsBlob -> getBufferPointer ()); 145#ifdef _WIN32 146_Win32OutputDebugString ((const char * )diagnosticsBlob -> getBufferPointer ()); 147#endif 148 } 149 } 150 151// Load and compile shader code from souce. 152Result loadShaderProgram ( 153IDevice * device , 154bool isRayTracingPipeline , 155IShaderProgram ** outProgram ) 156 { 157ComPtr < slang::ISession > slangSession ; 158slangSession = device -> getSlangSession (); 159 160ComPtr < slang::IBlob > diagnosticsBlob ; 161Slang ::String path = resourceBase .resolveResource ("shaders.slang" ); 162 slang::IModule * module = 163slangSession -> loadModule (path .getBuffer (),diagnosticsBlob .writeRef ()); 164diagnoseIfNeeded (diagnosticsBlob ); 165if (!module ) 166return SLANG_FAIL ; 167 168Slang ::List < slang::IComponentType *> componentTypes ; 169componentTypes .add (module ); 170if (isRayTracingPipeline ) 171 { 172ComPtr < slang::IEntryPoint > entryPoint ; 173SLANG_RETURN_ON_FAIL ( 174module -> findEntryPointByName ("rayGenShader" ,entryPoint .writeRef ())); 175componentTypes .add (entryPoint ); 176SLANG_RETURN_ON_FAIL (module -> findEntryPointByName ("missShader" ,entryPoint .writeRef ())); 177componentTypes .add (entryPoint ); 178SLANG_RETURN_ON_FAIL ( 179module -> findEntryPointByName ("closestHitShader" ,entryPoint .writeRef ())); 180componentTypes .add (entryPoint ); 181SLANG_RETURN_ON_FAIL ( 182module -> findEntryPointByName ("shadowRayHitShader" ,entryPoint .writeRef ())); 183componentTypes .add (entryPoint ); 184 } 185else 186 { 187ComPtr < slang::IEntryPoint > entryPoint ; 188SLANG_RETURN_ON_FAIL (module -> findEntryPointByName ("vertexMain" ,entryPoint .writeRef ())); 189componentTypes .add (entryPoint ); 190SLANG_RETURN_ON_FAIL ( 191module -> findEntryPointByName ("fragmentMain" ,entryPoint .writeRef ())); 192componentTypes .add (entryPoint ); 193 } 194 195ComPtr < slang::IComponentType > linkedProgram ; 196SlangResult result = slangSession -> createCompositeComponentType ( 197componentTypes .getBuffer (), 198componentTypes .getCount (), 199linkedProgram .writeRef (), 200diagnosticsBlob .writeRef ()); 201diagnoseIfNeeded (diagnosticsBlob ); 202SLANG_RETURN_ON_FAIL (result ); 203 204if (isTestMode ()) 205 { 206printEntrypointHashes (componentTypes .getCount ()- 1 ,1 ,linkedProgram ); 207 } 208 209ShaderProgramDesc programDesc = {}; 210programDesc .slangGlobalScope = linkedProgram ; 211SLANG_RETURN_ON_FAIL (device -> createShaderProgram (programDesc ,outProgram )); 212 213return SLANG_OK ; 214 } 215 216ComPtr < IRenderPipeline > gPresentPipeline ; 217ComPtr < IRayTracingPipeline > gRenderPipeline ; 218ComPtr < IBuffer > gFullScreenVertexBuffer ; 219ComPtr < IBuffer > gVertexBuffer ; 220ComPtr < IBuffer > gIndexBuffer ; 221ComPtr < IBuffer > gPrimitiveBuffer ; 222ComPtr < IBuffer > gTransformBuffer ; 223ComPtr < IBuffer > gInstanceBuffer ; 224ComPtr < IAccelerationStructure > gBLAS ; 225ComPtr < IAccelerationStructure > gTLAS ; 226ComPtr < ITexture > gResultTexture ; 227ComPtr < IShaderTable > gShaderTable ; 228 229uint64_t lastTime = 0 ; 230 231// glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); 232// glm::vec3 lightColor = glm::vec3(1, 1, 1); 233 234 glm::vec3 cameraPosition = glm::vec3 (-2.53f ,2.72f ,4.3f ); 235float cameraOrientationAngles [2 ]= {-0.475f ,-0.35f };// Spherical angles (theta, phi). 236 237float translationScale = 0.5f ; 238float rotationScale = 0.01f ; 239 240// In order to control camera movement, we will 241// use good old WASD 242bool wPressed = false; 243bool aPressed = false; 244bool sPressed = false; 245bool dPressed = false; 246 247bool isMouseDown = false; 248float lastMouseX = 0.0f ; 249float lastMouseY = 0.0f ; 250 251void setKeyState (platform::KeyCode key ,bool state ) 252 { 253switch (key ) 254 { 255default : 256break ; 257case platform::KeyCode ::W : 258wPressed = state ; 259break ; 260case platform::KeyCode ::A : 261aPressed = state ; 262break ; 263case platform::KeyCode ::S : 264sPressed = state ; 265break ; 266case platform::KeyCode ::D : 267dPressed = state ; 268break ; 269 } 270 } 271void onKeyDown (platform::KeyEventArgs args ) {setKeyState (args .key , true); } 272void onKeyUp (platform::KeyEventArgs args ) {setKeyState (args .key , false); } 273 274void onMouseDown (platform::MouseEventArgs args ) 275 { 276isMouseDown = true; 277lastMouseX = (float )args .x ; 278lastMouseY = (float )args .y ; 279 } 280 281void onMouseMove (platform::MouseEventArgs args ) 282 { 283if (isMouseDown ) 284 { 285float deltaX = args .x - lastMouseX ; 286float deltaY = args .y - lastMouseY ; 287 288cameraOrientationAngles [0 ]+= - deltaX * rotationScale ; 289cameraOrientationAngles [1 ]+= - deltaY * rotationScale ; 290lastMouseX = (float )args .x ; 291lastMouseY = (float )args .y ; 292 } 293 } 294void onMouseUp (platform::MouseEventArgs args ) {isMouseDown = false; } 295 296Slang ::Result initialize () 297 { 298SLANG_RETURN_ON_FAIL (initializeBase ("Ray Tracing Pipeline" ,1024 ,768 ,getDeviceType ())); 299if (!isTestMode ()) 300 { 301gWindow -> events .mouseMove = [this ](const platform::MouseEventArgs & e ) 302 {onMouseMove (e ); }; 303gWindow -> events .mouseUp = [this ](const platform::MouseEventArgs & e ) {onMouseUp (e ); }; 304gWindow -> events .mouseDown = [this ](const platform::MouseEventArgs & e ) 305 {onMouseDown (e ); }; 306gWindow -> events .keyDown = [this ](const platform::KeyEventArgs & e ) {onKeyDown (e ); }; 307gWindow -> events .keyUp = [this ](const platform::KeyEventArgs & e ) {onKeyUp (e ); }; 308 } 309 310BufferDesc vertexBufferDesc ; 311vertexBufferDesc .size = kVertexCount * sizeof (Vertex ); 312vertexBufferDesc .usage = BufferUsage ::AccelerationStructureBuildInput ; 313vertexBufferDesc .defaultState = ResourceState ::AccelerationStructureBuildInput ; 314gVertexBuffer = gDevice -> createBuffer (vertexBufferDesc ,& kVertexData [0 ]); 315if (!gVertexBuffer ) 316return SLANG_FAIL ; 317 318BufferDesc indexBufferDesc ; 319indexBufferDesc .size = kIndexCount * sizeof (int32_t ); 320indexBufferDesc .usage = BufferUsage ::AccelerationStructureBuildInput ; 321indexBufferDesc .defaultState = ResourceState ::AccelerationStructureBuildInput ; 322gIndexBuffer = gDevice -> createBuffer (indexBufferDesc ,& kIndexData [0 ]); 323if (!gIndexBuffer ) 324return SLANG_FAIL ; 325 326BufferDesc primitiveBufferDesc ; 327primitiveBufferDesc .size = kPrimitiveCount * sizeof (Primitive ); 328primitiveBufferDesc .elementSize = sizeof (Primitive ); 329primitiveBufferDesc .usage = BufferUsage ::ShaderResource ; 330primitiveBufferDesc .defaultState = ResourceState ::ShaderResource ; 331gPrimitiveBuffer = gDevice -> createBuffer (primitiveBufferDesc ,& kPrimitiveData [0 ]); 332if (!gPrimitiveBuffer ) 333return SLANG_FAIL ; 334 335BufferDesc transformBufferDesc ; 336transformBufferDesc .size = sizeof (float )* 12 ; 337transformBufferDesc .usage = BufferUsage ::AccelerationStructureBuildInput ; 338transformBufferDesc .defaultState = ResourceState ::AccelerationStructureBuildInput ; 339float transformData [12 ]= 340 {1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f }; 341gTransformBuffer = gDevice -> createBuffer (transformBufferDesc ,& transformData ); 342if (!gTransformBuffer ) 343return SLANG_FAIL ; 344// Build bottom level acceleration structure. 345 { 346AccelerationStructureBuildInput buildInput = {}; 347buildInput .type = AccelerationStructureBuildInputType ::Triangles ; 348buildInput .triangles .vertexBuffers [0 ]= gVertexBuffer ; 349buildInput .triangles .vertexBufferCount = 1 ; 350buildInput .triangles .vertexFormat = Format ::RGB32Float ; 351buildInput .triangles .vertexCount = kVertexCount ; 352buildInput .triangles .vertexStride = sizeof (Vertex ); 353buildInput .triangles .indexBuffer = gIndexBuffer ; 354buildInput .triangles .indexFormat = IndexFormat ::Uint32 ; 355buildInput .triangles .indexCount = kIndexCount ; 356buildInput .triangles .preTransformBuffer = gTransformBuffer ; 357buildInput .triangles .flags = AccelerationStructureGeometryFlags ::Opaque ; 358 359AccelerationStructureBuildDesc buildDesc = {}; 360buildDesc .inputs = & buildInput ; 361buildDesc .inputCount = 1 ; 362buildDesc .flags = AccelerationStructureBuildFlags ::AllowCompaction ; 363 364// Query buffer size for acceleration structure build. 365AccelerationStructureSizes sizes ; 366SLANG_RETURN_ON_FAIL (gDevice -> getAccelerationStructureSizes (buildDesc ,& sizes )); 367 368// Allocate buffers for acceleration structure. 369BufferDesc scratchBufferDesc ; 370scratchBufferDesc .usage = BufferUsage ::UnorderedAccess ; 371scratchBufferDesc .defaultState = ResourceState ::UnorderedAccess ; 372scratchBufferDesc .size = sizes .scratchSize ; 373ComPtr < IBuffer > scratchBuffer = gDevice -> createBuffer (scratchBufferDesc ); 374if (!scratchBuffer ) 375return SLANG_FAIL ; 376 377// Build acceleration structure. 378ComPtr < IQueryPool > compactedSizeQuery ; 379QueryPoolDesc queryPoolDesc ; 380queryPoolDesc .count = 1 ; 381queryPoolDesc .type = QueryType ::AccelerationStructureCompactedSize ; 382SLANG_RETURN_ON_FAIL ( 383gDevice -> createQueryPool (queryPoolDesc ,compactedSizeQuery .writeRef ())); 384 385ComPtr < IAccelerationStructure > draftAS ; 386AccelerationStructureDesc draftCreateDesc ; 387draftCreateDesc .size = sizes .accelerationStructureSize ; 388SLANG_RETURN_ON_FAIL ( 389gDevice -> createAccelerationStructure (draftCreateDesc ,draftAS .writeRef ())); 390 391compactedSizeQuery -> reset (); 392 393auto commandEncoder = gQueue -> createCommandEncoder (); 394AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; 395compactedSizeQueryDesc .queryPool = compactedSizeQuery ; 396compactedSizeQueryDesc .queryType = QueryType ::AccelerationStructureCompactedSize ; 397commandEncoder -> buildAccelerationStructure ( 398buildDesc , 399draftAS , 400nullptr , 401scratchBuffer , 4021 , 403& compactedSizeQueryDesc ); 404gQueue -> submit (commandEncoder -> finish ()); 405gQueue -> waitOnHost (); 406 407uint64_t compactedSize = 0 ; 408compactedSizeQuery -> getResult (0 ,1 ,& compactedSize ); 409AccelerationStructureDesc createDesc ; 410createDesc .size = compactedSize ; 411gDevice -> createAccelerationStructure (createDesc ,gBLAS .writeRef ()); 412 413commandEncoder = gQueue -> createCommandEncoder (); 414commandEncoder -> copyAccelerationStructure ( 415gBLAS , 416draftAS , 417AccelerationStructureCopyMode ::Compact ); 418gQueue -> submit (commandEncoder -> finish ()); 419gQueue -> waitOnHost (); 420 } 421 422// Build top level acceleration structure. 423 { 424AccelerationStructureInstanceDescType nativeInstanceDescType = 425getAccelerationStructureInstanceDescType (gDevice ); 426Size nativeInstanceDescSize = 427getAccelerationStructureInstanceDescSize (nativeInstanceDescType ); 428 429 std::vector < AccelerationStructureInstanceDescGeneric > instanceDescs ; 430instanceDescs .resize (1 ); 431float transformMatrix []= 432 {1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f ,0.0f ,0.0f ,0.0f ,1.0f ,0.0f }; 433memcpy (& instanceDescs [0 ].transform [0 ][0 ],transformMatrix ,sizeof (float )* 12 ); 434 435instanceDescs [0 ].instanceID = 0 ; 436instanceDescs [0 ].instanceMask = 0xFF ; 437instanceDescs [0 ].instanceContributionToHitGroupIndex = 0 ; 438instanceDescs [0 ].flags = AccelerationStructureInstanceFlags ::TriangleFacingCullDisable ; 439instanceDescs [0 ].accelerationStructure = gBLAS -> getHandle (); 440 441 std::vector < uint8_t > nativeInstanceDescs (instanceDescs .size ()* nativeInstanceDescSize ); 442convertAccelerationStructureInstanceDescs ( 443instanceDescs .size (), 444nativeInstanceDescType , 445nativeInstanceDescs .data (), 446nativeInstanceDescSize , 447instanceDescs .data (), 448sizeof (AccelerationStructureInstanceDescGeneric )); 449 450BufferDesc instanceBufferDesc ; 451instanceBufferDesc .size = 452instanceDescs .size ()* sizeof (AccelerationStructureInstanceDescGeneric ); 453instanceBufferDesc .usage = BufferUsage ::ShaderResource ; 454instanceBufferDesc .defaultState = ResourceState ::ShaderResource ; 455gInstanceBuffer = gDevice -> createBuffer (instanceBufferDesc ,nativeInstanceDescs .data ()); 456if (!gInstanceBuffer ) 457return SLANG_FAIL ; 458 459AccelerationStructureBuildInput buildInput = {}; 460buildInput .type = AccelerationStructureBuildInputType ::Instances ; 461buildInput .instances .instanceBuffer = gInstanceBuffer ; 462buildInput .instances .instanceCount = 1 ; 463buildInput .instances .instanceStride = nativeInstanceDescSize ; 464 465AccelerationStructureBuildDesc buildDesc = {}; 466buildDesc .inputs = & buildInput ; 467buildDesc .inputCount = 1 ; 468 469// Query buffer size for acceleration structure build. 470AccelerationStructureSizes sizes ; 471SLANG_RETURN_ON_FAIL (gDevice -> getAccelerationStructureSizes (buildDesc ,& sizes )); 472 473BufferDesc scratchBufferDesc ; 474scratchBufferDesc .usage = BufferUsage ::UnorderedAccess ; 475scratchBufferDesc .defaultState = ResourceState ::UnorderedAccess ; 476scratchBufferDesc .size = sizes .scratchSize ; 477ComPtr < IBuffer > scratchBuffer = gDevice -> createBuffer (scratchBufferDesc ); 478 479AccelerationStructureDesc createDesc ; 480createDesc .size = sizes .accelerationStructureSize ; 481SLANG_RETURN_ON_FAIL ( 482gDevice -> createAccelerationStructure (createDesc ,gTLAS .writeRef ())); 483 484auto commandEncoder = gQueue -> createCommandEncoder (); 485commandEncoder 486-> buildAccelerationStructure (buildDesc ,gTLAS ,nullptr ,scratchBuffer ,0 ,nullptr ); 487gQueue -> submit (commandEncoder -> finish ()); 488gQueue -> waitOnHost (); 489 } 490 491BufferDesc fullScreenVertexBufferDesc ; 492fullScreenVertexBufferDesc .size = 493FullScreenTriangle ::kVertexCount * sizeof (FullScreenTriangle ::Vertex ); 494fullScreenVertexBufferDesc .usage = BufferUsage ::VertexBuffer ; 495fullScreenVertexBufferDesc .defaultState = ResourceState ::VertexBuffer ; 496gFullScreenVertexBuffer = 497gDevice -> createBuffer (fullScreenVertexBufferDesc ,& FullScreenTriangle ::kVertices [0 ]); 498if (!gFullScreenVertexBuffer ) 499return SLANG_FAIL ; 500 501InputElementDesc inputElements []= { 502 {"POSITION" ,0 ,Format ::RG32Float , offsetof(FullScreenTriangle ::Vertex ,position )}, 503 }; 504auto inputLayout = gDevice -> createInputLayout ( 505sizeof (FullScreenTriangle ::Vertex ), 506& inputElements [0 ], 507SLANG_COUNT_OF (inputElements )); 508if (!inputLayout ) 509return SLANG_FAIL ; 510 511ComPtr < IShaderProgram > shaderProgram ; 512SLANG_RETURN_ON_FAIL (loadShaderProgram (gDevice , false,shaderProgram .writeRef ())); 513ColorTargetDesc colorTarget ; 514colorTarget .format = Format ::RGBA16Float ; 515RenderPipelineDesc desc ; 516desc .inputLayout = inputLayout ; 517desc .program = shaderProgram ; 518desc .targetCount = 1 ; 519desc .targets = & colorTarget ; 520desc .depthStencil .depthTestEnable = false; 521desc .depthStencil .depthWriteEnable = false; 522desc .primitiveTopology = PrimitiveTopology ::TriangleList ; 523gPresentPipeline = gDevice -> createRenderPipeline (desc ); 524if (!gPresentPipeline ) 525return SLANG_FAIL ; 526 527const char * hitgroupNames []= {"hitgroup0" ,"hitgroup1" }; 528 529ComPtr < IShaderProgram > rayTracingProgram ; 530SLANG_RETURN_ON_FAIL (loadShaderProgram (gDevice , true,rayTracingProgram .writeRef ())); 531RayTracingPipelineDesc rtpDesc = {}; 532rtpDesc .program = rayTracingProgram ; 533rtpDesc .hitGroupCount = 2 ; 534HitGroupDesc hitGroups [2 ]; 535hitGroups [0 ].closestHitEntryPoint = "closestHitShader" ; 536hitGroups [0 ].hitGroupName = hitgroupNames [0 ]; 537hitGroups [1 ].closestHitEntryPoint = "shadowRayHitShader" ; 538hitGroups [1 ].hitGroupName = hitgroupNames [1 ]; 539rtpDesc .hitGroups = hitGroups ; 540rtpDesc .maxRayPayloadSize = 64 ; 541rtpDesc .maxRecursion = 2 ; 542SLANG_RETURN_ON_FAIL ( 543gDevice -> createRayTracingPipeline (rtpDesc ,gRenderPipeline .writeRef ())); 544if (!gRenderPipeline ) 545return SLANG_FAIL ; 546 547ShaderTableDesc shaderTableDesc = {}; 548const char * raygenName = "rayGenShader" ; 549const char * missName = "missShader" ; 550shaderTableDesc .program = rayTracingProgram ; 551shaderTableDesc .hitGroupCount = 2 ; 552shaderTableDesc .hitGroupNames = hitgroupNames ; 553shaderTableDesc .rayGenShaderCount = 1 ; 554shaderTableDesc .rayGenShaderEntryPointNames = & raygenName ; 555shaderTableDesc .missShaderCount = 1 ; 556shaderTableDesc .missShaderEntryPointNames = & missName ; 557SLANG_RETURN_ON_FAIL (gDevice -> createShaderTable (shaderTableDesc ,gShaderTable .writeRef ())); 558 559createResultTexture (); 560return SLANG_OK ; 561 } 562 563void createResultTexture () 564 { 565TextureDesc resultTextureDesc = {}; 566resultTextureDesc .type = TextureType ::Texture2D ; 567resultTextureDesc .mipCount = 1 ; 568resultTextureDesc .size .width = windowWidth ; 569resultTextureDesc .size .height = windowHeight ; 570resultTextureDesc .size .depth = 1 ; 571resultTextureDesc .usage = TextureUsage ::UnorderedAccess |TextureUsage ::ShaderResource ; 572resultTextureDesc .defaultState = ResourceState ::UnorderedAccess ; 573resultTextureDesc .format = Format ::RGBA16Float ; 574gResultTexture = gDevice -> createTexture (resultTextureDesc ); 575 } 576 577virtual void windowSizeChanged ()override 578 { 579WindowedAppBase ::windowSizeChanged (); 580createResultTexture (); 581 } 582 583 glm::vec3 getVectorFromSphericalAngles (float theta ,float phi ) 584 { 585auto sinTheta = sin (theta ); 586auto cosTheta = cos (theta ); 587auto sinPhi = sin (phi ); 588auto cosPhi = cos (phi ); 589return glm::vec3 (- sinTheta * cosPhi ,sinPhi ,- cosTheta * cosPhi ); 590 } 591void updateUniforms () 592 { 593gUniforms .screenWidth = (float )windowWidth ; 594gUniforms .screenHeight = (float )windowHeight ; 595if (!lastTime ) 596lastTime = getCurrentTime (); 597uint64_t currentTime = getCurrentTime (); 598float deltaTime = float (double (currentTime - lastTime ) /double (getTimerFrequency ())); 599lastTime = currentTime ; 600 601auto camDir = 602getVectorFromSphericalAngles (cameraOrientationAngles [0 ],cameraOrientationAngles [1 ]); 603auto camUp = getVectorFromSphericalAngles ( 604cameraOrientationAngles [0 ], 605cameraOrientationAngles [1 ]+ glm::pi < float > ()* 0.5f ); 606auto camRight = glm::cross (camDir ,camUp ); 607 608 glm::vec3 movement = glm::vec3 (0 ); 609if (wPressed ) 610movement += camDir ; 611if (sPressed ) 612movement -= camDir ; 613if (aPressed ) 614movement -= camRight ; 615if (dPressed ) 616movement += camRight ; 617 618cameraPosition += deltaTime * translationScale * movement ; 619 620memcpy (gUniforms .cameraDir ,& camDir ,sizeof (float )* 3 ); 621memcpy (gUniforms .cameraUp ,& camUp ,sizeof (float )* 3 ); 622memcpy (gUniforms .cameraRight ,& camRight ,sizeof (float )* 3 ); 623memcpy (gUniforms .cameraPosition ,& cameraPosition ,sizeof (float )* 3 ); 624auto lightDir = glm::normalize (glm::vec3 (1.0f ,3.0f ,2.0f )); 625memcpy (gUniforms .lightDir ,& lightDir ,sizeof (float )* 3 ); 626 } 627 628virtual void renderFrame (ITexture * texture )override 629 { 630updateUniforms (); 631 { 632auto commandEncoder = gQueue -> createCommandEncoder (); 633auto rayTracingPassEncoder = commandEncoder -> beginRayTracingPass (); 634auto rootObject = rayTracingPassEncoder -> bindPipeline (gRenderPipeline ,gShaderTable ); 635auto cursor = ShaderCursor (rootObject ); 636cursor ["resultTexture" ].setBinding (gResultTexture ); 637cursor ["uniforms" ].setData (& gUniforms ,sizeof (Uniforms )); 638cursor ["sceneBVH" ].setBinding (gTLAS ); 639cursor ["primitiveBuffer" ].setBinding (gPrimitiveBuffer ); 640rayTracingPassEncoder -> dispatchRays (0 ,windowWidth ,windowHeight ,1 ); 641rayTracingPassEncoder -> end (); 642gQueue -> submit (commandEncoder -> finish ()); 643 } 644 645 { 646auto commandEncoder = gQueue -> createCommandEncoder (); 647 648ComPtr < ITextureView > textureView = gDevice -> createTextureView (texture , {}); 649RenderPassColorAttachment colorAttachment = {}; 650colorAttachment .view = textureView ; 651colorAttachment .loadOp = LoadOp ::Clear ; 652 653RenderPassDesc renderPassDesc = {}; 654renderPassDesc .colorAttachments = & colorAttachment ; 655renderPassDesc .colorAttachmentCount = 1 ; 656 657auto renderPassEncoder = commandEncoder -> beginRenderPass (renderPassDesc ); 658 659RenderState renderState = {}; 660renderState .viewports [0 ]= Viewport ::fromSize (windowWidth ,windowHeight ); 661renderState .viewportCount = 1 ; 662renderState .scissorRects [0 ]= ScissorRect ::fromSize (windowWidth ,windowHeight ); 663renderState .scissorRectCount = 1 ; 664renderState .vertexBuffers [0 ]= gFullScreenVertexBuffer ; 665renderState .vertexBufferCount = 1 ; 666renderPassEncoder -> setRenderState (renderState ); 667 668auto rootObject = renderPassEncoder -> bindPipeline (gPresentPipeline ); 669auto cursor = ShaderCursor (rootObject ); 670cursor ["t" ].setBinding (gResultTexture ); 671 672DrawArguments drawArgs = {}; 673drawArgs .vertexCount = 3 ; 674renderPassEncoder -> draw (drawArgs ); 675renderPassEncoder -> end (); 676gQueue -> submit (commandEncoder -> finish ()); 677 } 678 679if (!isTestMode ()) 680 { 681// With that, we are done drawing for one frame, and ready for the next. 682// 683gSurface -> present (); 684 } 685 } 686}; 687 688// This macro instantiates an appropriate main function to 689// run the application defined above. 690EXAMPLE_MAIN (innerMain < RayTracing > );