Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raytracing pipeline demo #173

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

kevyuu
Copy link

@kevyuu kevyuu commented Jan 22, 2025

Implement a demo to cover various ray tracing pipeline use cases.

  • multiple closest hit and any hit shaders
  • multiple miss shaders
  • multiple callable shaders

@kevyuu kevyuu force-pushed the raytracing_pipeline_demo branch from 9e2eb0f to bcbd729 Compare January 22, 2025 17:07
Comment on lines -135 to +138
void mouseProcess(const nbl::ui::IMouseEventChannel::range_t& events)
// return whether camera is moved by mouse
bool mouseProcess(const nbl::ui::IMouseEventChannel::range_t& events)
{
bool cameraMoved = false;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these your changes?

coordinate with @AnastaZIuk

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is my changes.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this bool is not a reliable way to find out if the camera moved during a frame (nor is the keyboard one)

I'd perform any such checks in endInputProcessing by comparing matrices (or pos and target) before and after setting position and target

@kevyuu kevyuu force-pushed the raytracing_pipeline_demo branch from 8f16aad to 34a3fa9 Compare January 24, 2025 16:44
Fletterio and others added 14 commits January 24, 2025 23:44
- Multiple HitGroup. Each with closesthit and anythit shader
- Multiple Miss Shader Group.

Signed-off-by: kevyuu <[email protected]>
Signed-off-by: kevyuu <[email protected]>
Signed-off-by: kevyuu <[email protected]>
Signed-off-by: Ali Cheraghi <[email protected]>
Signed-off-by: kevyuu <[email protected]>
Signed-off-by: kevyuu <[email protected]>
Copy link
Member

@devshgraphicsprogramming devshgraphicsprogramming left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main.cpp I'll review later

Comment on lines +66 to +86
enum E_LIGHT_TYPE : uint16_t
{
ELT_DIRECTIONAL,
ELT_POINT,
ELT_SPOT,
ELT_COUNT
};

struct Light
{
float32_t3 direction;
float32_t3 position;
float32_t outerCutoff;
uint16_t type;


#ifndef __HLSL_VERSION
bool operator==(const Light&) const = default;
#endif

};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep example simple, do just directional light

Comment on lines +1 to +34
// Generate a random unsigned int from two unsigned int values, using 16 pairs
// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis,
// "GPU Random Numbers via the Tiny Encryption Algorithm"
uint32_t tea(uint32_t val0, uint32_t val1)
{
uint32_t v0 = val0;
uint32_t v1 = val1;
uint32_t s0 = 0;

for(uint32_t n = 0; n < 16; n++)
{
s0 += 0x9e3779b9;
v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4);
v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e);
}

return v0;
}

// Generate a random unsigned int in [0, 2^24) given the previous RNG state
// using the Numerical Recipes linear congruential generator
uint32_t lcg(inout uint32_t prev)
{
uint32_t LCG_A = 1664525u;
uint32_t LCG_C = 1013904223u;
prev = (LCG_A * prev + LCG_C);
return prev & 0x00FFFFFF;
}

// Generate a random float32_t in [0, 1) given the previous RNG state
float32_t rnd(inout uint32_t prev)
{
return (float32_t(lcg(prev)) / float32_t(0x01000000));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you may want to rework them into something resembling xoroshiro.hlsl in the Nabla repo and pcg.hlsl from the HLSL BxDF PR https://github.com/Devsh-Graphics-Programming/Nabla/pull/811/files#diff-717f65cfd315d91ced5e7da9f817f786fb1f8c1b1c06a570df4f61be3660a643

Comment on lines +23 to +27
uint32_t seed = p.seed;
if (geom.material.dissolve == 0.0)
IgnoreHit();
else if (rnd(seed) > geom.material.dissolve)
IgnoreHit();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok so you stochastically do alpha, btw for this to add up, you'd need to "boost" the color (throughput in the color payload) by the probability of the path taken, so:

  • if you ignore the hit, you mul by 1.f/(1.f-dissolve)
  • if you don't ignore the hit, you mul by 1.f/dissolve

basically same as importance sampling. Nvm they cancel out and you never multiplied them into the throughput.

For the shadow ray there is a more performant way actually, instead of importance sampling the mix

this*alpha+next*(1-alpha)

you can recognise that the shadow ray doesn't have to be a boolean and you can multiply the dissolve into it same you would an alpha value (you do need to create the BLAS with the no-duplicate hit flag though).

Also at this point you can make two separate anyhit HLSL shader sources.

Comment on lines +20 to +21
if (geom.material.illum != 4)
return;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can build your TLAS with instance flags that prevent ANY_HIT being called on them (or what it only BLAS?).

This is useful because you don't end up executing the vk::RawBufferLoad for the things that are not transparent to check if they are transparent (saving Bandwidth in the meantime).


struct [raypayload] ShadowPayload
{
bool isShadowed : read(caller) : write(caller,miss);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I've mentioned in the comment in your anyhit shader, its better to have a float32_t opacity and have the anyhit multiply into it, which allows for transparent shadows, you have to use the 4 bytes in your payload anyway.

Comment on lines +11 to +14
struct Attrib
{
float3 HitAttribute;
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you never fill this out?

[[vk::binding(0, 0)]] RaytracingAccelerationStructure topLevelAS;

[shader("closesthit")]
void main(inout ColorPayload p, in BuiltInTriangleIntersectionAttributes attribs)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuiltInTriangleIntersectionAttributes? but its not a triangle?

Comment on lines +14 to +17
SProceduralGeomInfo sphere = vk::RawBufferLoad < SProceduralGeomInfo > (pc.proceduralGeomInfoBuffer + primID * sizeof(SProceduralGeomInfo));

// Computing the normal at hit position
float32_t3 worldNormal = normalize(worldPosition - sphere.center);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you already had to load and compute some of this in the intersection shader, is it not possible to pass it in the payload/custom attribs to the closest hit shader?

Comment on lines +40 to +47
uint flags =
RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_OPAQUE |
RAY_FLAG_SKIP_CLOSEST_HIT_SHADER;

ShadowPayload shadowPayload;
shadowPayload.isShadowed = true;
shadowPayload.seed = p.seed;
TraceRay(topLevelAS, flags, 0xFF, ERT_OCCLUSION, 0, EMT_OCCLUSION, rayDesc, shadowPayload);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw if you follow my advice on transparent shadows, the flags will have to change

P.S. do IgnoreHit() and modifying the payload mix? (Idea is that accepted hit will not cause the invocation of a miss shader or any more anyhits).

rayDesc.TMin = 0.01;
rayDesc.TMax = cLight.outLightDistance;

uint flags = RAY_FLAG_SKIP_CLOSEST_HIT_SHADER;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reason for not having RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH here?

float32_t3 direction;
float32_t3 position;
float32_t outerCutoff;
uint16_t type;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use 16-bit types in PushConstants. they require a feature to be enabled and no AMD GPU supports them afaik

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants