Toy with raytracing
This commit is contained in:
parent
d1c6fbe61f
commit
523aaedecf
6 changed files with 139 additions and 46 deletions
|
|
@ -645,13 +645,17 @@ void VkLevelMesh::RaytraceScene(const VkRenderPassKey& renderPassKey, VulkanComm
|
|||
float f = 1.0f / std::tan(fovy * (pi::pif() / 360.0f));
|
||||
|
||||
ViewerPushConstants pushconstants;
|
||||
pushconstants.ViewToWorld = viewToWorld;
|
||||
pushconstants.CameraPos = cameraPos;
|
||||
pushconstants.ProjX = f / aspect;
|
||||
pushconstants.ProjY = f;
|
||||
pushconstants.SunDir = FVector3(Mesh->SunDirection.X, Mesh->SunDirection.Z, Mesh->SunDirection.Y);
|
||||
pushconstants.SunColor = Mesh->SunColor;
|
||||
pushconstants.SunIntensity = Mesh->SunIntensity;
|
||||
pushconstants.ViewX = (viewToWorld * FVector4(1.0f, 0.0f, 0.0f, 1.0f)).XYZ() - cameraPos;
|
||||
pushconstants.ViewY = (viewToWorld * FVector4(0.0f, 1.0f, 0.0f, 1.0f)).XYZ() - cameraPos;
|
||||
pushconstants.ViewZ = (viewToWorld * FVector4(0.0f, 0.0f, 1.0f, 1.0f)).XYZ() - cameraPos;
|
||||
pushconstants.ResolutionScaleX = 2.0f / fb->GetWidth();
|
||||
pushconstants.ResolutionScaleY = 2.0f / fb->GetHeight();
|
||||
|
||||
commands->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, Viewer.PipelineLayout.get(), 0, Viewer.DescriptorSet.get());
|
||||
commands->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, Viewer.PipelineLayout.get(), 1, fb->GetDescriptorSetManager()->GetBindlessSet());
|
||||
|
|
|
|||
|
|
@ -55,13 +55,18 @@ struct LightInfo
|
|||
|
||||
struct ViewerPushConstants
|
||||
{
|
||||
VSMatrix ViewToWorld;
|
||||
FVector3 CameraPos;
|
||||
float ProjX;
|
||||
FVector3 SunDir;
|
||||
float ProjY;
|
||||
FVector3 SunColor;
|
||||
float SunIntensity;
|
||||
FVector3 ViewX;
|
||||
float ResolutionScaleX;
|
||||
FVector3 ViewY;
|
||||
float ResolutionScaleY;
|
||||
FVector3 ViewZ;
|
||||
float Unused;
|
||||
};
|
||||
|
||||
static_assert(sizeof(LightInfo) == sizeof(float) * 20);
|
||||
|
|
|
|||
|
|
@ -30,11 +30,16 @@ layout(set = 1, binding = 0) uniform sampler2D textures[];
|
|||
|
||||
layout(push_constant) uniform PushConstants
|
||||
{
|
||||
mat4 ViewToWorld;
|
||||
vec3 CameraPos;
|
||||
float ProjX;
|
||||
vec3 SunDir;
|
||||
float ProjY;
|
||||
vec3 SunColor;
|
||||
float SunIntensity;
|
||||
vec3 ViewX;
|
||||
float ResolutionScaleX;
|
||||
vec3 ViewY;
|
||||
float ResolutionScaleY;
|
||||
vec3 ViewZ;
|
||||
float Unused;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,54 +6,131 @@
|
|||
#include <shaders/lightmap/trace_light.glsl>
|
||||
#include <shaders/lightmap/trace_ambient_occlusion.glsl>
|
||||
|
||||
layout(location = 0) in vec3 FragRay;
|
||||
layout(location = 0) out vec4 fragcolor;
|
||||
|
||||
vec3 skyColor(vec3 direction)
|
||||
{
|
||||
if (direction.y > 0.0f)
|
||||
return mix(vec3(0.6, 0.25, 0.15), vec3(0.8, 0.5, 0.5), direction.y);
|
||||
else
|
||||
return vec3(0.03);
|
||||
}
|
||||
|
||||
uint stepRNG(uint rngState)
|
||||
{
|
||||
return rngState * 747796405 + 1;
|
||||
}
|
||||
|
||||
float stepAndOutputRNGFloat(inout uint rngState)
|
||||
{
|
||||
rngState = stepRNG(rngState);
|
||||
uint word = ((rngState >> ((rngState >> 28) + 4)) ^ rngState) * 277803737;
|
||||
word = (word >> 22) ^ word;
|
||||
return float(word) / 4294967295.0f;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 incoming = vec3(0.1);
|
||||
const int NUM_SAMPLES = 64;//64;
|
||||
const int MAX_BOUNCES = 8;//32;
|
||||
|
||||
vec3 origin = CameraPos;
|
||||
vec3 L = normalize(FragRay);
|
||||
TraceResult result = TraceFirstHit(origin, 0.0, L, 10000.0);
|
||||
if (result.primitiveIndex != -1)
|
||||
uint rngState = uint(gl_FragCoord.x) + 8720 * uint(gl_FragCoord.y);
|
||||
vec3 summedPixelColor = vec3(0.0);
|
||||
|
||||
for(int sampleIdx = 0; sampleIdx < NUM_SAMPLES; sampleIdx++)
|
||||
{
|
||||
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||
vec3 surfacepos = origin + L * result.t;
|
||||
vec3 rayOrigin = CameraPos;
|
||||
|
||||
if (surface.Sky == 0.0)
|
||||
const vec2 randomPixelCenter = gl_FragCoord.xy - 0.5 + vec2(stepAndOutputRNGFloat(rngState), stepAndOutputRNGFloat(rngState));
|
||||
vec4 viewpos = vec4(randomPixelCenter * vec2(ResolutionScaleX, ResolutionScaleY) - 1.0, -1.0, 1.0);
|
||||
viewpos.x /= ProjX;
|
||||
viewpos.y /= ProjY;
|
||||
vec3 rayDirection = normalize(ViewX * viewpos.x + ViewY * viewpos.y - ViewZ);
|
||||
|
||||
vec3 accumulatedRayColor = vec3(1.0);
|
||||
for(int tracedSegments = 0; tracedSegments < MAX_BOUNCES; tracedSegments++)
|
||||
{
|
||||
incoming += TraceSunLight(surfacepos, surface.Normal);
|
||||
|
||||
uint LightStart = surface.LightStart;
|
||||
uint LightEnd = surface.LightEnd;
|
||||
for (uint j = LightStart; j < LightEnd; j++)
|
||||
TraceResult result = TraceFirstHit(rayOrigin, 0.0, rayDirection, 100000.0);
|
||||
if (result.primitiveIndex != -1)
|
||||
{
|
||||
incoming += TraceLight(surfacepos, surface.Normal, lights[lightIndexes[j]], 0.0, false);
|
||||
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||
if (surface.Sky == 0.0)
|
||||
{
|
||||
vec4 color;
|
||||
if (surface.TextureIndex != 0)
|
||||
{
|
||||
vec2 uv = GetSurfaceUV(result.primitiveIndex, result.primitiveWeights);
|
||||
color = texture(textures[surface.TextureIndex], uv);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hit a surface without a texture
|
||||
color = vec4(0.0);
|
||||
}
|
||||
|
||||
vec3 worldPos = GetSurfacePos(result.primitiveIndex, result.primitiveWeights);
|
||||
vec3 lightRayOrigin = worldPos + 0.001 * surface.Normal;
|
||||
|
||||
if (color.a > 0.5)
|
||||
{
|
||||
accumulatedRayColor *= color.rgb;
|
||||
|
||||
/*
|
||||
uint LightStart = surface.LightStart;
|
||||
uint LightEnd = surface.LightEnd;
|
||||
if (LightStart != LightEnd && stepAndOutputRNGFloat(rngState) < 0.5)
|
||||
{
|
||||
// This is total BS - pretend we hit the lights 50% of the time
|
||||
// We need some kind of physical representation for the lights
|
||||
|
||||
vec3 incoming = vec3(0.0);
|
||||
//incoming += TraceSunLight(lightRayOrigin, surface.Normal);
|
||||
for (uint j = LightStart; j < LightEnd; j++)
|
||||
incoming += TraceLight(lightRayOrigin, surface.Normal, lights[lightIndexes[j]], 0.0, false);
|
||||
summedPixelColor += accumulatedRayColor * incoming;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
rayOrigin = worldPos + 0.001 * surface.Normal;
|
||||
|
||||
// Mirror reflect 10% of the time to create a glossy surface
|
||||
/*if (stepAndOutputRNGFloat(rngState) < 0.1)
|
||||
{
|
||||
// Mirror reflection:
|
||||
rayDirection = reflect(rayDirection, surface.Normal);
|
||||
}
|
||||
else*/
|
||||
{
|
||||
// Lambertian diffuse reflection:
|
||||
// Generate a random point on a sphere of radius 1 centered at the normal
|
||||
const float theta = 6.2831853 * stepAndOutputRNGFloat(rngState); // Random in [0, 2pi]
|
||||
const float u = 2.0 * stepAndOutputRNGFloat(rngState) - 1.0; // Random in [-1, 1]
|
||||
const float r = sqrt(1.0 - u * u);
|
||||
rayDirection = surface.Normal + vec3(r * cos(theta), r * sin(theta), u);
|
||||
rayDirection = normalize(rayDirection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transparent
|
||||
rayOrigin = worldPos - 0.001 * surface.Normal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hit the sky
|
||||
summedPixelColor += accumulatedRayColor * skyColor(rayDirection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ray hit nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// incoming *= TraceAmbientOcclusion(surfacepos, surface.Normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
incoming = SunColor;
|
||||
}
|
||||
|
||||
if (surface.TextureIndex != 0)
|
||||
{
|
||||
vec2 uv = GetSurfaceUV(result.primitiveIndex, result.primitiveWeights);
|
||||
vec4 color = texture(textures[surface.TextureIndex], uv);
|
||||
incoming *= color.rgb;
|
||||
}
|
||||
else
|
||||
{
|
||||
incoming = vec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
incoming = vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
fragcolor = vec4(incoming, 1.0);
|
||||
fragcolor = vec4(summedPixelColor / float(NUM_SAMPLES), 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,15 @@ SurfaceInfo GetSurface(int primitiveIndex)
|
|||
return surfaces[surfaceIndices[primitiveIndex]];
|
||||
}
|
||||
|
||||
vec3 GetSurfacePos(int primitiveIndex, vec3 primitiveWeights)
|
||||
{
|
||||
int index = primitiveIndex * 3;
|
||||
return
|
||||
vertices[elements[index + 1]].pos * primitiveWeights.x +
|
||||
vertices[elements[index + 2]].pos * primitiveWeights.y +
|
||||
vertices[elements[index + 0]].pos * primitiveWeights.z;
|
||||
}
|
||||
|
||||
vec2 GetSurfaceUV(int primitiveIndex, vec3 primitiveWeights)
|
||||
{
|
||||
int index = primitiveIndex * 3;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
#include <shaders/lightmap/binding_viewer.glsl>
|
||||
|
||||
layout(location = 0) out vec3 FragRay;
|
||||
|
||||
vec2 positions[4] = vec2[](
|
||||
vec2(0.0, 0.0),
|
||||
vec2(1.0, 0.0),
|
||||
|
|
@ -12,10 +10,5 @@ vec2 positions[4] = vec2[](
|
|||
|
||||
void main()
|
||||
{
|
||||
vec4 viewpos = vec4(positions[gl_VertexIndex] * 2.0 - 1.0, -1.0, 1.0);
|
||||
viewpos.x /= ProjX;
|
||||
viewpos.y = -viewpos.y / ProjY;
|
||||
FragRay = ((ViewToWorld * viewpos).xyz - CameraPos);
|
||||
|
||||
gl_Position = vec4((positions[gl_VertexIndex] * 2.0 - 1.0) * vec2(1.0, -1.0), 1.0, 1.0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue