mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2025-02-07 08:01:09 +00:00
added sunlight and volumetric lighting
fixed depth linearization
This commit is contained in:
parent
a01c88707d
commit
30150e889e
63 changed files with 5867 additions and 765 deletions
|
@ -111,6 +111,9 @@ add: Cinematic Rendering Pipeline CVars
|
|||
3 - camera and object blur
|
||||
crp_mblur_exposure <0.0 to 1.0> (default: 0.5) is the exposure time in percentage of frame time
|
||||
miscellaneous:
|
||||
crp_sunlight <0|1> enables sunlight on non-lightmapped surfaces
|
||||
crp_volLight <0|1> enables volumetric lighting
|
||||
fog volumes are lit by ambient light, dynamic lights and sunlight
|
||||
crp_drawNormals <0|1> (default: 0) draws vertex normals as colorized wireframe lines
|
||||
crp_updateRTAS <0|1> (default: 1) enables raytracing acceleration structure builds every frame
|
||||
|
||||
|
@ -133,15 +136,17 @@ chg: reworked renderer with 2 new rendering pipelines
|
|||
- removed all the Direct3D 11 and OpenGL code, now using Direct3D 12
|
||||
- much improved input latency when V-Sync is enabled
|
||||
- improved frame-time consistency ("frame pacing")
|
||||
- fog handling has been completely overhauled (faster, simpler, decoupled from surfaces)
|
||||
- MSAA and alpha-to-coverage have been removed
|
||||
- Gameplay Rendering Pipeline (GRP)
|
||||
- improved performance and better worst case input latency
|
||||
- added SMAA for anti-aliasing (gamma-corrected and not applied to UI for best results)
|
||||
- added VRS (Variable Rate Shading) support
|
||||
- overhauled fog handling (faster, simpler, decoupled from surfaces)
|
||||
- Cinematic Rendering Pipeline (CRP)
|
||||
- order-independent transparency
|
||||
- depth of field (scatter-as-gather or accumulation)
|
||||
- shadowed point lights and sunlight
|
||||
- volumetric lighting
|
||||
- all corresponding CVars have the "crp_" prefix
|
||||
|
||||
chg: removed cl_drawMouseLag, r_backend, r_frameSleep, r_gpuMipGen, r_alphaToCoverage, r_alphaToCoverageMipBoost
|
||||
|
|
|
@ -49,8 +49,6 @@ struct DOFDebugRC
|
|||
uint32_t debugMode; // 1: colorized coc, 2: constant intensity far field
|
||||
uint32_t tcScale;
|
||||
float focusDist;
|
||||
float linearDepthA; // main view, to unproject to WS
|
||||
float linearDepthB;
|
||||
float maxNearCocCS;
|
||||
float maxFarCocCS;
|
||||
};
|
||||
|
@ -325,7 +323,6 @@ void AccumDepthOfField::DrawDebug()
|
|||
rc.maxFarCocCS = maxFarCocCS;
|
||||
rc.tcScale = GetResolutionScale();
|
||||
R_MultMatrix(modelViewMatrix, projMatrix, rc.mvp);
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
R_MultMatrix(backEnd.viewParms.world.modelMatrix, backEnd.viewParms.projectionMatrix, mvp);
|
||||
R_InvMatrix(mvp, rc.invMvp);
|
||||
|
||||
|
|
|
@ -39,8 +39,6 @@ struct DOFDebugRC
|
|||
uint32_t colorTextureIndex;
|
||||
uint32_t depthTextureIndex;
|
||||
uint32_t debugMode;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
|
@ -56,8 +54,6 @@ struct DOFSplitRC
|
|||
uint32_t farColorTextureIndex;
|
||||
uint32_t nearCocTextureIndex;
|
||||
uint32_t farCocTextureIndex;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
|
@ -239,7 +235,6 @@ void GatherDepthOfField::DrawDebug()
|
|||
rc.colorTextureIndex = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
||||
rc.debugMode = crp_dof_overlay->integer;
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.focusNearMin = crp_gatherDof_focusNearDist->value - 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusNearMax = crp_gatherDof_focusNearDist->value + 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusFarMin = crp_gatherDof_focusFarDist->value - 0.5f * crp_gatherDof_focusFarRange->value;
|
||||
|
@ -272,7 +267,6 @@ void GatherDepthOfField::DrawSplit()
|
|||
rc.farColorTextureIndex = GetTextureIndexUAV(farColorTexture, 0);
|
||||
rc.nearCocTextureIndex = GetTextureIndexUAV(nearCocTexture, 0);
|
||||
rc.farCocTextureIndex = GetTextureIndexUAV(farCocTexture, 0);
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.focusNearMin = crp_gatherDof_focusNearDist->value - 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusNearMax = crp_gatherDof_focusNearDist->value + 0.5f * crp_gatherDof_focusNearRange->value;
|
||||
rc.focusFarMin = crp_gatherDof_focusFarDist->value - 0.5f * crp_gatherDof_focusFarRange->value;
|
||||
|
|
|
@ -22,6 +22,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
#include "crp_local.h"
|
||||
#include "shaders/crp/scene_view.h.hlsli"
|
||||
#include "compshaders/crp/fullscreen.h"
|
||||
#include "compshaders/crp/dl_draw.h"
|
||||
#include "compshaders/crp/dl_denoising.h"
|
||||
|
@ -31,13 +32,18 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
struct DynamicLightsRC
|
||||
{
|
||||
DynamicLight light;
|
||||
uint32_t blueNoiseTextureIndex;
|
||||
};
|
||||
|
||||
|
||||
struct DenoiseRC
|
||||
{
|
||||
vec3_t lightPosition;
|
||||
uint32_t textureIndex;
|
||||
uint32_t vshadowTextureIndex;
|
||||
uint32_t vshadowSamplerIndex;
|
||||
float vshadowWorldScale;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
@ -60,27 +66,27 @@ void DynamicLights::Init()
|
|||
{
|
||||
GraphicsPipelineDesc desc("Dynamic Lights Denoising");
|
||||
MakeFullScreenPipeline(desc, ShaderByteCode(g_dl_denoising_ps));
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE, crp.renderTargetFormat);
|
||||
denoisingPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicLights::Draw()
|
||||
void DynamicLights::DrawBegin()
|
||||
{
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.lightTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
CmdClearColorTarget(crp.lightTexture, colorBlack);
|
||||
}
|
||||
|
||||
void DynamicLights::DrawPointLight(const dlight_t& light)
|
||||
{
|
||||
if(r_dynamiclight->integer == 0 ||
|
||||
(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) != 0 ||
|
||||
!IsViewportFullscreen(backEnd.viewParms))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!crp.raytracing.CanRaytrace() ||
|
||||
!IsViewportFullscreen(backEnd.viewParms) ||
|
||||
!crp.raytracing.CanRaytrace() ||
|
||||
backEnd.refdef.num_dlights <= 0)
|
||||
{
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.lightTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
CmdClearColorTarget(crp.lightTexture, colorBlack);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -94,12 +100,15 @@ void DynamicLights::Draw()
|
|||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.shadingPositionTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.normalTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.noisyLightTexture, ResourceStates::RenderTargetBit);
|
||||
CmdTextureBarrier(crp.sunlightTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
DynamicLightsRC rc = {};
|
||||
VectorCopy(light.origin, rc.light.position);
|
||||
VectorCopy(light.color, rc.light.color);
|
||||
rc.light.radius = light.radius;
|
||||
rc.blueNoiseTextureIndex = GetTextureIndexSRV(crp.blueNoise2D);
|
||||
CmdBindRenderTargets(1, &crp.noisyLightTexture, NULL);
|
||||
CmdBindRenderTargets(1, &crp.sunlightTexture, NULL);
|
||||
CmdBindPipeline(pipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
|
@ -112,12 +121,17 @@ void DynamicLights::Draw()
|
|||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.shadingPositionTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.noisyLightTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.sunlightTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.volumetricLight.pointShadowTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.lightTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
DenoiseRC rc = {};
|
||||
rc.textureIndex = GetTextureIndexSRV(crp.noisyLightTexture);
|
||||
VectorCopy(light.origin, rc.lightPosition);
|
||||
rc.textureIndex = GetTextureIndexSRV(crp.sunlightTexture);
|
||||
rc.vshadowTextureIndex = GetTextureIndexSRV(crp.volumetricLight.pointShadowTexture);
|
||||
rc.vshadowSamplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
rc.vshadowWorldScale = crp.volumetricLight.pointShadowVolumeScale;
|
||||
CmdBindRenderTargets(1, &crp.lightTexture, NULL);
|
||||
CmdBindPipeline(denoisingPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - fog volumes
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
#include "compshaders/crp/fog_outside.h"
|
||||
#include "compshaders/crp/fog_inside.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct FogRC
|
||||
{
|
||||
float modelViewMatrix[16];
|
||||
float projectionMatrix[16];
|
||||
float boxMin[4];
|
||||
float boxMax[4];
|
||||
float color[4];
|
||||
float depth;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
uint32_t depthTextureIndex;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void Fog::Init()
|
||||
{
|
||||
{
|
||||
const uint32_t indices[] =
|
||||
{
|
||||
0, 1, 2, 2, 1, 3,
|
||||
4, 0, 6, 6, 0, 2,
|
||||
7, 5, 6, 6, 5, 4,
|
||||
3, 1, 7, 7, 1, 5,
|
||||
4, 5, 0, 0, 5, 1,
|
||||
3, 7, 2, 2, 7, 6
|
||||
};
|
||||
|
||||
BufferDesc desc("box index", sizeof(indices), ResourceStates::IndexBufferBit);
|
||||
desc.shortLifeTime = true;
|
||||
boxIndexBuffer = CreateBuffer(desc);
|
||||
|
||||
uint8_t* mapped = BeginBufferUpload(boxIndexBuffer);
|
||||
memcpy(mapped, indices, sizeof(indices));
|
||||
EndBufferUpload(boxIndexBuffer);
|
||||
}
|
||||
{
|
||||
const float vertices[] =
|
||||
{
|
||||
0.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
1.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
BufferDesc desc("box vertex", sizeof(vertices), ResourceStates::VertexBufferBit);
|
||||
desc.shortLifeTime = true;
|
||||
boxVertexBuffer = CreateBuffer(desc);
|
||||
|
||||
uint8_t* mapped = BeginBufferUpload(boxVertexBuffer);
|
||||
memcpy(mapped, vertices, sizeof(vertices));
|
||||
EndBufferUpload(boxVertexBuffer);
|
||||
}
|
||||
{
|
||||
GraphicsPipelineDesc desc("fog outside");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_outside_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_outside_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_BACK_SIDED;
|
||||
desc.rasterizer.polygonOffset = false;
|
||||
desc.rasterizer.clampDepth = true;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
fogOutsidePipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
{
|
||||
GraphicsPipelineDesc desc("fog inside");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_inside_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_inside_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_FRONT_SIDED;
|
||||
desc.rasterizer.polygonOffset = false;
|
||||
desc.rasterizer.clampDepth = true;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
fogInsidePipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void Fog::Draw()
|
||||
{
|
||||
// @NOTE: fog 0 is invalid, it must be skipped
|
||||
if(tr.world == NULL ||
|
||||
tr.world->numfogs <= 1 ||
|
||||
(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPED_RENDER_PASS("Fog", 0.25f, 0.125f, 0.0f);
|
||||
|
||||
srp.renderMode = RenderMode::World;
|
||||
|
||||
const uint32_t stride = sizeof(vec3_t);
|
||||
CmdBindVertexBuffers(1, &boxVertexBuffer, &stride, NULL);
|
||||
CmdBindIndexBuffer(boxIndexBuffer, IndexType::UInt32, 0);
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.depthTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
|
||||
int insideIndex = -1;
|
||||
for(int f = 1; f < tr.world->numfogs; ++f)
|
||||
{
|
||||
const fog_t& fog = tr.world->fogs[f];
|
||||
|
||||
bool inside = true;
|
||||
for(int a = 0; a < 3; ++a)
|
||||
{
|
||||
if(backEnd.viewParms.orient.origin[a] <= fog.bounds[0][a] ||
|
||||
backEnd.viewParms.orient.origin[a] >= fog.bounds[1][a])
|
||||
{
|
||||
inside = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(inside)
|
||||
{
|
||||
insideIndex = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FogRC rc = {};
|
||||
memcpy(rc.modelViewMatrix, backEnd.viewParms.world.modelMatrix, sizeof(rc.modelViewMatrix));
|
||||
memcpy(rc.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(rc.projectionMatrix));
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
||||
|
||||
CmdBindPipeline(fogOutsidePipeline);
|
||||
for(int f = 1; f < tr.world->numfogs; ++f)
|
||||
{
|
||||
if(f == insideIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const fog_t& fog = tr.world->fogs[f];
|
||||
VectorScale(fog.parms.color, tr.identityLight, rc.color);
|
||||
rc.depth = fog.parms.depthForOpaque;
|
||||
VectorCopy(fog.bounds[0], rc.boxMin);
|
||||
VectorCopy(fog.bounds[1], rc.boxMax);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDrawIndexed(36, 0, 0);
|
||||
}
|
||||
|
||||
if(insideIndex > 0)
|
||||
{
|
||||
CmdBindPipeline(fogInsidePipeline);
|
||||
|
||||
const fog_t& fog = tr.world->fogs[insideIndex];
|
||||
VectorScale(fog.parms.color, tr.identityLight, rc.color);
|
||||
rc.depth = fog.parms.depthForOpaque;
|
||||
VectorCopy(fog.bounds[0], rc.boxMin);
|
||||
VectorCopy(fog.bounds[1], rc.boxMax);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDrawIndexed(36, 0, 0);
|
||||
}
|
||||
}
|
|
@ -32,14 +32,6 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct LinearizeDepthRC
|
||||
{
|
||||
uint32_t depthTextureIndex;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float zFarInv;
|
||||
};
|
||||
|
||||
struct DecodeNormalsRC
|
||||
{
|
||||
uint32_t normalTextureIndex;
|
||||
|
@ -114,14 +106,8 @@ void GBufferViz::DrawGUI()
|
|||
CmdTextureBarrier(renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
LinearizeDepthRC rc = {};
|
||||
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.zFarInv = 1.0f / backEnd.viewParms.zFar;
|
||||
|
||||
CmdBindRenderTargets(1, &renderTarget, NULL);
|
||||
CmdBindPipeline(linearizeDepthPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
else if(textureIndex == GBufferTexture::Normal)
|
||||
|
@ -205,6 +191,12 @@ void GBufferViz::DrawGUI()
|
|||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Light", &textureIndex, GBufferTexture::Light);
|
||||
|
||||
ImGui::RadioButton("Sunlight", &textureIndex, GBufferTexture::Sunlight);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Sunlight Visibility", &textureIndex, GBufferTexture::SunlightVisibility);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Sunlight Penumbra", &textureIndex, GBufferTexture::SunlightPenumbra);
|
||||
|
||||
ImGui::RadioButton("Motion Raw", &textureIndex, GBufferTexture::MotionVectorRaw);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Motion MB", &textureIndex, GBufferTexture::MotionVectorMB);
|
||||
|
@ -232,6 +224,9 @@ void GBufferViz::DrawGUI()
|
|||
case GBufferTexture::ShadingPositionDelta: texture = renderTarget; break;
|
||||
case GBufferTexture::MotionVectorRaw: texture = renderTarget; break;
|
||||
case GBufferTexture::MotionVectorMB: texture = renderTarget; break;
|
||||
case GBufferTexture::SunlightVisibility: texture = crp.sunlight.visibilityTexture; break;
|
||||
case GBufferTexture::SunlightPenumbra: texture = crp.sunlight.penumbraTexture; break;
|
||||
case GBufferTexture::Sunlight: texture = crp.sunlightTexture; break;
|
||||
default: Q_assert(!"Invalid G-Buffer texture index"); texture = crp.lightTexture; break;
|
||||
}
|
||||
ImGui::Image((ImTextureID)GetTextureIndexSRV(texture), resolution);
|
||||
|
|
|
@ -42,6 +42,8 @@ extern cvar_t* crp_accumDof_samples;
|
|||
extern cvar_t* crp_accumDof_preview;
|
||||
extern cvar_t* crp_mblur;
|
||||
extern cvar_t* crp_mblur_exposure;
|
||||
extern cvar_t* crp_sunlight;
|
||||
extern cvar_t* crp_volLight;
|
||||
extern cvar_t* crp_drawNormals;
|
||||
extern cvar_t* crp_updateRTAS;
|
||||
extern cvar_t* crp_debug0;
|
||||
|
@ -169,25 +171,14 @@ private:
|
|||
bool batchDepthHack;
|
||||
};
|
||||
|
||||
struct Fog
|
||||
{
|
||||
void Init();
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
HBuffer boxIndexBuffer;
|
||||
HBuffer boxVertexBuffer;
|
||||
HPipeline fogInsidePipeline;
|
||||
HPipeline fogOutsidePipeline;
|
||||
};
|
||||
|
||||
struct TranspResolve
|
||||
{
|
||||
void Init();
|
||||
void Draw(const drawSceneViewCommand_t& cmd);
|
||||
|
||||
private:
|
||||
HPipeline pipeline;
|
||||
HPipeline noVolPipeline;
|
||||
HPipeline volPipeline;
|
||||
};
|
||||
|
||||
struct ToneMap
|
||||
|
@ -305,6 +296,9 @@ private:
|
|||
ShadingPositionDelta,
|
||||
MotionVectorRaw,
|
||||
MotionVectorMB,
|
||||
SunlightVisibility,
|
||||
SunlightPenumbra,
|
||||
Sunlight,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
@ -322,7 +316,8 @@ private:
|
|||
struct DynamicLights
|
||||
{
|
||||
void Init();
|
||||
void Draw();
|
||||
void DrawBegin();
|
||||
void DrawPointLight(const dlight_t& light);
|
||||
bool WantRTASUpdate(const trRefdef_t& scene);
|
||||
|
||||
private:
|
||||
|
@ -416,6 +411,150 @@ private:
|
|||
uint32_t staticTLASInstanceCount = 0;
|
||||
};
|
||||
|
||||
struct SunlightEditor
|
||||
{
|
||||
void Init();
|
||||
void ProcessWorld(world_t& world);
|
||||
void DrawOverlay();
|
||||
void DrawGUI();
|
||||
|
||||
private:
|
||||
HPipeline pipeline;
|
||||
bool windowActive = false;
|
||||
bool drawOverlay = false;
|
||||
const shader_t* skyShader = NULL;
|
||||
};
|
||||
|
||||
struct Sunlight
|
||||
{
|
||||
void Init();
|
||||
void Draw();
|
||||
bool WantRTASUpdate(const trRefdef_t& scene);
|
||||
|
||||
//private:
|
||||
HPipeline visibilityPipeline;
|
||||
HPipeline blurPipeline;
|
||||
HTexture visibilityTexture;
|
||||
HTexture penumbraTexture;
|
||||
};
|
||||
|
||||
struct VolumetricLight
|
||||
{
|
||||
void Init();
|
||||
void ProcessWorld(world_t& world);
|
||||
void DrawBegin();
|
||||
void DrawPointLight(const dlight_t& light);
|
||||
void DrawSunlight();
|
||||
void DrawEnd();
|
||||
void DrawDebug();
|
||||
void DrawGUI();
|
||||
bool WantRTASUpdate(const trRefdef_t& scene);
|
||||
bool ShouldDraw();
|
||||
bool ShouldDrawDebug();
|
||||
bool LoadFogFile(const char* filePath);
|
||||
void SaveFogFile(const char* filePath);
|
||||
|
||||
// GUI/user-friendly data layout
|
||||
struct Fog
|
||||
{
|
||||
vec3_t scatterColor;
|
||||
vec3_t emissiveColor;
|
||||
vec3_t boxMin;
|
||||
vec3_t boxMax;
|
||||
float extinction;
|
||||
float albedo; // scatter / extinction
|
||||
float emissive;
|
||||
float anisotropy;
|
||||
float noiseStrength;
|
||||
float noiseSpatialPeriod;
|
||||
float noiseTimePeriod;
|
||||
bool isGlobalFog;
|
||||
bool isHeightFog;
|
||||
};
|
||||
|
||||
#if defined(VL_CPU_PARTICLES)
|
||||
HPipeline particleDispatchPipeline;
|
||||
HPipeline particlePreProcessExtinctionPipeline;
|
||||
HPipeline particlePreProcessFrustumPipeline;
|
||||
HPipeline extinctionParticlePipeline;
|
||||
HPipeline frustumParticlePipeline;
|
||||
HBuffer particleBuffer; // should be double buffered...
|
||||
HBuffer particleHitBuffer; // for each tile, is there at least 1 particle?
|
||||
HBuffer particleTileBuffer; // array of tiles, each tile has a uint3 index
|
||||
HBuffer particleDispatchBuffer; // indirect dispatch buffer
|
||||
HBuffer particleDispatchClearBuffer; // indirect dispatch buffer with values (0, 1, 1)
|
||||
uint32_t particleCount;
|
||||
#endif
|
||||
|
||||
Fog fogs[64];
|
||||
uint32_t fogCount = 0;
|
||||
HPipeline extinctionFogPipeline;
|
||||
HPipeline frustumAmbientPipeline;
|
||||
HPipeline frustumAnisotropyPipeline;
|
||||
HPipeline frustumFogPipeline;
|
||||
HPipeline frustumPointLightScatterPipeline;
|
||||
HPipeline frustumRaymarchPipeline;
|
||||
HPipeline frustumSunlightVisPipeline;
|
||||
HPipeline frustumTemporalPipeline;
|
||||
HPipeline pointLightShadowPipeline;
|
||||
HPipeline sunlightScatterPipeline;
|
||||
HPipeline sunlightShadowPipeline;
|
||||
HPipeline ambientVizPipeline;
|
||||
HPipeline extinctionVizPipeline;
|
||||
HPipeline sunShadowVizPipeline;
|
||||
HTexture materialTextureA; // frustum, RGB = scatter, A = absorption
|
||||
HTexture materialTextureB; // frustum, RGB = emissive, A = anisotropy (g)
|
||||
HTexture materialTextureC; // frustum, R = anisotropy (g) weight sum
|
||||
HTexture sunlightVisTexture; // frustum, R = sunlight visibility
|
||||
HTexture prevSunlightVisTexture; // frustum, R = sunlight visibility
|
||||
HTexture scatterExtTexture; // frustum, RGB = in-scattering, A = extinction
|
||||
HTexture scatterTransTexture; // frustum, RGB = in-scattering, A = transmittance
|
||||
HTexture extinctionTextures[4]; // cube, R = extinction
|
||||
HTexture pointShadowTexture; // cube, R = transmittance
|
||||
HTexture sunShadowTextures[4]; // cube, R = transmittance
|
||||
HTexture ambientLightTextureA; // box, can be NULL, RGB = ambient.rgb, A = directional.r
|
||||
HTexture ambientLightTextureB; // box, can be NULL, RG = directional.gb, B = longitude, A = latitude
|
||||
uvec3_t frustumSize; // frustum volume pixel counts
|
||||
uvec3_t frustumTileScale; // by how much do we divide
|
||||
uvec3_t frustumTileSize; // frustum volume tile pixel counts
|
||||
uvec3_t extinctionSize; // extinction volume pixel counts
|
||||
uvec3_t extinctionTileScale; // by how much do we divide
|
||||
uvec3_t extinctionTileSize; // extinction volume tile pixel counts
|
||||
uint32_t shadowPixelCount; // @TODO: transform into uvec3_t as well
|
||||
uint32_t jitterCounter;
|
||||
uint32_t depthMip; // has to match the X/Y scale of frustumSize
|
||||
vec4_t extinctionVolumeScale; // how many world units per pixel
|
||||
float pointShadowVolumeScale; // how many world units per pixel
|
||||
vec4_t sunShadowVolumeScale; // how many world units per pixel
|
||||
uvec3_t sunShadowSize; // sunlight shadow volume pixel counts
|
||||
vec3_t ambientColor;
|
||||
float ambientIntensity;
|
||||
vec3_t debugCameraPosition;
|
||||
float debugBoxScale = 1.0f;
|
||||
float debugExtinctionScale = 50.0f;
|
||||
int debugExtinctionCascadeIndex = 0;
|
||||
int debugSunShadowCascadeIndex = 0;
|
||||
bool drawExtinctionDebug = false;
|
||||
bool drawSunShadowDebug = false;
|
||||
bool drawAmbientDebug = false;
|
||||
bool lockCameraPosition = false;
|
||||
bool firstFrame = true;
|
||||
bool windowActive = false;
|
||||
vec3_t mapBoxMin;
|
||||
vec3_t mapBoxMax;
|
||||
vec3_t lightGridCenter;
|
||||
float debugSphereScale = 0.5f;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SunlightData
|
||||
{
|
||||
vec3_t direction;
|
||||
vec3_t color;
|
||||
float intensity;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct BaseBufferId
|
||||
{
|
||||
enum Id
|
||||
|
@ -498,6 +637,7 @@ struct CRP : IRenderPipeline
|
|||
void Blit(HTexture destination, HTexture source, const char* passName, bool hdr, const vec2_t tcScale, const vec2_t tcBias);
|
||||
void BlitRenderTarget(HTexture destination, const char* passName);
|
||||
void DrawSceneView(const drawSceneViewCommand_t& cmd);
|
||||
void DrawSceneView3D(const drawSceneViewCommand_t& cmd);
|
||||
void UploadSceneViewData();
|
||||
void BuildDepthPyramid();
|
||||
|
||||
|
@ -513,7 +653,7 @@ struct CRP : IRenderPipeline
|
|||
HTexture normalTexture;
|
||||
HTexture motionVectorTexture; // raw, for TAA/denoisers/etc
|
||||
HTexture motionVectorMBTexture; // mangled, for motion blur only
|
||||
HTexture noisyLightTexture;
|
||||
HTexture sunlightTexture;
|
||||
HTexture lightTexture;
|
||||
HTexture shadingPositionTexture;
|
||||
HTexture renderTarget;
|
||||
|
@ -557,14 +697,19 @@ struct CRP : IRenderPipeline
|
|||
GatherDepthOfField gatherDof;
|
||||
AccumDepthOfField accumDof;
|
||||
MotionBlur motionBlur;
|
||||
Fog fog;
|
||||
Magnifier magnifier;
|
||||
DynamicLights dynamicLights;
|
||||
Sunlight sunlight;
|
||||
VolumetricLight volumetricLight;
|
||||
Raytracing raytracing;
|
||||
GBufferViz gbufferViz;
|
||||
SunlightEditor sunlightEditor;
|
||||
SunlightData sunlightData;
|
||||
};
|
||||
|
||||
HPipeline CreateComputePipeline(const char* name, const ShaderByteCode& shader);
|
||||
void MakeFullScreenPipeline(GraphicsPipelineDesc& desc, const ShaderByteCode& pixelShader);
|
||||
void DirectionToAzimuthInclination(float* sc, const float* dir);
|
||||
void AzimuthInclinationToDirection(float* dir, const float* sc);
|
||||
|
||||
extern CRP crp;
|
||||
|
|
|
@ -76,6 +76,8 @@ cvar_t* crp_accumDof_samples;
|
|||
cvar_t* crp_accumDof_preview;
|
||||
cvar_t* crp_mblur;
|
||||
cvar_t* crp_mblur_exposure;
|
||||
cvar_t* crp_sunlight;
|
||||
cvar_t* crp_volLight;
|
||||
cvar_t* crp_drawNormals;
|
||||
cvar_t* crp_updateRTAS;
|
||||
cvar_t* crp_debug0;
|
||||
|
@ -181,6 +183,14 @@ static const cvarTableItem_t crp_cvars[] =
|
|||
"This is the exposure time in percentage of frame time.",
|
||||
"Motion blur exposure", CVARCAT_GRAPHICS, "Exposure time in percentage of frame time", ""
|
||||
},
|
||||
{
|
||||
&crp_sunlight, "crp_sunlight", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "sunlight",
|
||||
"Sunlight", CVARCAT_GRAPHICS, "Sunlight on non-lightmapped surfaces", ""
|
||||
},
|
||||
{
|
||||
&crp_volLight, "crp_volLight", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "volumetric light",
|
||||
"Volumetric light", CVARCAT_GRAPHICS, "Sunlight scattering through the air", ""
|
||||
},
|
||||
{
|
||||
&crp_drawNormals, "crp_drawNormals", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "draws vertex normals",
|
||||
"Draw vertex normals", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", ""
|
||||
|
@ -256,6 +266,24 @@ static HTexture LoadTexture(const char* name, int flags, textureWrap_t glWrapCla
|
|||
return image->texture;
|
||||
}
|
||||
|
||||
static void SunToZMatrix(matrix3x3_t rot)
|
||||
{
|
||||
float sc[2];
|
||||
DirectionToAzimuthInclination(sc, crp.sunlightData.direction);
|
||||
const float azi = -(sc[0] + M_PI / 2.0f);
|
||||
const float ele = M_PI - sc[1];
|
||||
const float rol = 0.0f;
|
||||
rot[0] = cosf(rol) * cosf(azi) - sinf(rol) * cosf(ele) * sinf(azi);
|
||||
rot[3] = sinf(rol) * cosf(azi) + cosf(rol) * cosf(ele) * sinf(azi);
|
||||
rot[6] = sinf(ele) * sinf(azi);
|
||||
rot[1] = -cosf(rol) * sinf(azi) - sinf(rol) * cosf(ele) * cosf(azi);
|
||||
rot[4] = -sinf(rol) * sinf(azi) + cosf(rol) * cosf(ele) * cosf(azi);
|
||||
rot[7] = sinf(ele) * cosf(azi);
|
||||
rot[2] = sinf(rol) * sinf(ele);
|
||||
rot[5] = -cosf(rol) * sinf(ele);
|
||||
rot[8] = cosf(ele);
|
||||
}
|
||||
|
||||
HPipeline CreateComputePipeline(const char* name, const ShaderByteCode& shader)
|
||||
{
|
||||
ComputePipelineDesc desc(name);
|
||||
|
@ -504,7 +532,7 @@ void CRP::Init()
|
|||
desc.SetClearColor(colorBlack);
|
||||
lightTexture = RHI::CreateTexture(desc);
|
||||
desc.name = "GBuffer raw direct light";
|
||||
noisyLightTexture = RHI::CreateTexture(desc);
|
||||
sunlightTexture = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -548,6 +576,7 @@ void CRP::Init()
|
|||
sceneViewBuffer = CreateBuffer(desc);
|
||||
}
|
||||
|
||||
raytracing.Init();
|
||||
ui.Init(true, ShaderByteCode(g_ui_vs), ShaderByteCode(g_ui_ps), renderTargetFormat, RHI_MAKE_NULL_HANDLE(), NULL);
|
||||
imgui.Init(true, ShaderByteCode(g_imgui_vs), ShaderByteCode(g_imgui_ps), renderTargetFormat, RHI_MAKE_NULL_HANDLE(), NULL);
|
||||
nuklear.Init(true, ShaderByteCode(g_nuklear_vs), ShaderByteCode(g_nuklear_ps), renderTargetFormat, RHI_MAKE_NULL_HANDLE(), NULL);
|
||||
|
@ -560,11 +589,12 @@ void CRP::Init()
|
|||
gatherDof.Init();
|
||||
accumDof.Init();
|
||||
motionBlur.Init();
|
||||
fog.Init();
|
||||
magnifier.Init();
|
||||
dynamicLights.Init();
|
||||
raytracing.Init();
|
||||
sunlight.Init();
|
||||
volumetricLight.Init();
|
||||
gbufferViz.Init();
|
||||
sunlightEditor.Init();
|
||||
|
||||
srp.firstInit = false;
|
||||
}
|
||||
|
@ -592,7 +622,10 @@ void CRP::BeginFrame()
|
|||
imgui.BeginFrame();
|
||||
|
||||
// must be run outside of the RHI::BeginFrame/RHI::EndFrame pair
|
||||
const bool rtasUpdate = dynamicLights.WantRTASUpdate(tr.rtRefdef);
|
||||
const bool rtasUpdate =
|
||||
dynamicLights.WantRTASUpdate(tr.rtRefdef) ||
|
||||
sunlight.WantRTASUpdate(tr.rtRefdef) ||
|
||||
volumetricLight.WantRTASUpdate(tr.rtRefdef);
|
||||
raytracing.BeginFrame(rtasUpdate);
|
||||
|
||||
RHI::BeginFrame();
|
||||
|
@ -632,6 +665,8 @@ void CRP::EndFrame()
|
|||
srp.DrawGUI();
|
||||
gbufferViz.DrawGUI();
|
||||
magnifier.DrawGUI();
|
||||
sunlightEditor.DrawGUI();
|
||||
volumetricLight.DrawGUI();
|
||||
imgui.Draw(renderTarget);
|
||||
toneMap.DrawToneMap();
|
||||
magnifier.Draw();
|
||||
|
@ -718,6 +753,8 @@ void CRP::EndTextureUpload()
|
|||
void CRP::ProcessWorld(world_t& world)
|
||||
{
|
||||
raytracing.ProcessWorld(world);
|
||||
sunlightEditor.ProcessWorld(world);
|
||||
volumetricLight.ProcessWorld(world);
|
||||
}
|
||||
|
||||
void CRP::ProcessModel(model_t&)
|
||||
|
@ -841,6 +878,45 @@ void CRP::TessellationOverflow()
|
|||
tess.numVertexes = 0;
|
||||
}
|
||||
|
||||
void CRP::DrawSceneView3D(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
const int lightCount = backEnd.refdef.num_dlights;
|
||||
|
||||
prepass.Draw(cmd);
|
||||
BuildDepthPyramid();
|
||||
dynamicLights.DrawBegin();
|
||||
if(volumetricLight.ShouldDraw())
|
||||
{
|
||||
volumetricLight.DrawBegin();
|
||||
if(raytracing.CanRaytrace())
|
||||
{
|
||||
{
|
||||
SCOPED_RENDER_PASS("VL/DL Point Lights", 1.0f, 1.0f, 1.0f);
|
||||
for(int i = 0; i < lightCount; i++)
|
||||
{
|
||||
volumetricLight.DrawPointLight(backEnd.refdef.dlights[i]);
|
||||
dynamicLights.DrawPointLight(backEnd.refdef.dlights[i]);
|
||||
}
|
||||
}
|
||||
volumetricLight.DrawSunlight();
|
||||
}
|
||||
volumetricLight.DrawEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
SCOPED_RENDER_PASS("DL Point Lights", 1.0f, 1.0f, 1.0f);
|
||||
for(int i = 0; i < lightCount; i++)
|
||||
{
|
||||
dynamicLights.DrawPointLight(backEnd.refdef.dlights[i]);
|
||||
}
|
||||
}
|
||||
sunlight.Draw();
|
||||
opaque.Draw(cmd);
|
||||
volumetricLight.DrawDebug();
|
||||
transp.Draw(cmd);
|
||||
transpResolve.Draw(cmd);
|
||||
}
|
||||
|
||||
void CRP::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
const viewParms_t& vp = cmd.viewParms;
|
||||
|
@ -880,12 +956,7 @@ void CRP::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
CmdTextureBarrier(renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
CmdClearColorTarget(renderTarget, cmd.clearColor, &rect);
|
||||
prepass.Draw(newCmd);
|
||||
dynamicLights.Draw();
|
||||
opaque.Draw(newCmd);
|
||||
fog.Draw();
|
||||
transp.Draw(newCmd);
|
||||
transpResolve.Draw(newCmd);
|
||||
DrawSceneView3D(newCmd);
|
||||
accumDof.Accumulate();
|
||||
|
||||
// geometry allocation is a linear allocation instead of a ring buffer
|
||||
|
@ -908,12 +979,7 @@ void CRP::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
backEnd.viewParms = cmd.viewParms;
|
||||
UploadSceneViewData();
|
||||
|
||||
prepass.Draw(cmd);
|
||||
dynamicLights.Draw();
|
||||
opaque.Draw(cmd);
|
||||
fog.Draw();
|
||||
transp.Draw(cmd);
|
||||
transpResolve.Draw(cmd);
|
||||
DrawSceneView3D(cmd);
|
||||
CmdSetViewportAndScissor(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight);
|
||||
gatherDof.Draw();
|
||||
if(freezeFrame == FreezeFrame::PendingBeforeMB &&
|
||||
|
@ -932,6 +998,8 @@ void CRP::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
}
|
||||
motionBlur.Draw();
|
||||
}
|
||||
|
||||
sunlightEditor.DrawOverlay();
|
||||
}
|
||||
|
||||
void CRP::UploadSceneViewData()
|
||||
|
@ -944,62 +1012,91 @@ void CRP::UploadSceneViewData()
|
|||
|
||||
SCOPED_DEBUG_LABEL("Scene View Upload", 1.0f, 1.0f, 1.0f);
|
||||
|
||||
const trRefdef_t& refdef = backEnd.refdef;
|
||||
const viewParms_t& vp = backEnd.viewParms;
|
||||
const HBuffer uploadBuffer = sceneViewUploadBuffers[GetFrameIndex()];
|
||||
const uint32_t uploadByteOffset = sceneViewIndex * SceneViewConst::StructBytes;
|
||||
|
||||
SceneView& dest = *(SceneView*)(MapBuffer(uploadBuffer) + uploadByteOffset);
|
||||
if(!vp.isPortal && IsViewportFullscreen(vp))
|
||||
{
|
||||
Q_assert(tr.currZFar == vp.zFar);
|
||||
Q_assert(tr.currZNear == vp.zNear);
|
||||
}
|
||||
|
||||
SceneView scene = {};
|
||||
|
||||
#if defined(_DEBUG)
|
||||
scene.debug[0] = crp_debug0->value;
|
||||
scene.debug[1] = crp_debug1->value;
|
||||
scene.debug[2] = crp_debug2->value;
|
||||
scene.debug[3] = crp_debug3->value;
|
||||
#endif
|
||||
|
||||
scene.frameSeed = (float)rand() / (float)RAND_MAX;
|
||||
|
||||
// @NOTE: yes, world.modelMatrix is actually the view matrix
|
||||
// it's the model-view matrix for the world entity, thus the view matrix
|
||||
memcpy(dest.projectionMatrix, vp.projectionMatrix, sizeof(dest.projectionMatrix));
|
||||
R_InvMatrix(dest.projectionMatrix, dest.invProjectionMatrix);
|
||||
memcpy(dest.viewMatrix, vp.world.modelMatrix, sizeof(dest.viewMatrix));
|
||||
R_InvMatrix(dest.viewMatrix, dest.invViewMatrix);
|
||||
memcpy(scene.projectionMatrix, vp.projectionMatrix, sizeof(scene.projectionMatrix));
|
||||
R_InvMatrix(scene.projectionMatrix, scene.invProjectionMatrix);
|
||||
memcpy(scene.viewMatrix, vp.world.modelMatrix, sizeof(scene.viewMatrix));
|
||||
R_InvMatrix(scene.viewMatrix, scene.invViewMatrix);
|
||||
|
||||
memcpy(dest.prevViewProjMatrix, tr.prevViewProjMatrix, sizeof(dest.prevViewProjMatrix));
|
||||
memcpy(dest.prevViewMatrix, tr.prevViewMatrix, sizeof(dest.prevViewMatrix));
|
||||
memcpy(dest.prevProjectionMatrix, tr.prevProjMatrix, sizeof(dest.prevProjectionMatrix));
|
||||
memcpy(scene.prevViewProjMatrix, tr.prevViewProjMatrix, sizeof(scene.prevViewProjMatrix));
|
||||
memcpy(scene.prevViewMatrix, tr.prevViewMatrix, sizeof(scene.prevViewMatrix));
|
||||
memcpy(scene.prevProjectionMatrix, tr.prevProjMatrix, sizeof(scene.prevProjectionMatrix));
|
||||
|
||||
RB_CreateClipPlane(dest.clipPlane);
|
||||
#if defined(_DEBUG)
|
||||
dest.debug[0] = crp_debug0->value;
|
||||
dest.debug[1] = crp_debug1->value;
|
||||
dest.debug[2] = crp_debug2->value;
|
||||
dest.debug[3] = crp_debug3->value;
|
||||
#else
|
||||
const uint32_t deadBeef = 0xDEADBEEF;
|
||||
dest.debug[0] = *(const float*)&deadBeef;
|
||||
dest.debug[1] = *(const float*)&deadBeef;
|
||||
dest.debug[2] = *(const float*)&deadBeef;
|
||||
dest.debug[3] = *(const float*)&deadBeef;
|
||||
#endif
|
||||
dest.sceneViewIndex = sceneViewIndex;
|
||||
dest.frameIndex = tr.frameCount;
|
||||
dest.depthTextureIndex = GetTextureIndexSRV(depthTexture);
|
||||
dest.normalTextureIndex = GetTextureIndexSRV(normalTexture);
|
||||
dest.shadingPositionTextureIndex = GetTextureIndexSRV(shadingPositionTexture);
|
||||
dest.motionVectorTextureIndex = GetTextureIndexSRV(motionVectorTexture);
|
||||
dest.motionVectorMBTextureIndex = GetTextureIndexSRV(motionVectorMBTexture);
|
||||
dest.lightTextureIndex = GetTextureIndexSRV(lightTexture);
|
||||
dest.tlasBufferIndex = raytracing.GetTLASBufferIndex();
|
||||
dest.tlasInstanceBufferIndex = raytracing.GetInstanceBufferIndex();
|
||||
dest.lightCount = refdef.num_dlights;
|
||||
RB_LinearDepthConstants(&dest.linearDepthA, &dest.linearDepthB);
|
||||
dest.zNear = vp.zNear;
|
||||
dest.zFar = vp.zFar;
|
||||
// we want the first Z slice to be closest to the sun to simplify ray marching
|
||||
vec3_t zDown;
|
||||
VectorSet(zDown, 0, 0, -1);
|
||||
SunToZMatrix(scene.sunToZMatrix);
|
||||
R_InvMatrix3x3(scene.sunToZMatrix, scene.zToSunMatrix);
|
||||
|
||||
for(int i = 0; i < refdef.num_dlights; i++)
|
||||
RB_CreateClipPlane(scene.clipPlane);
|
||||
VectorCopy(vp.world.viewOrigin, scene.cameraPosition);
|
||||
VectorCopy(tr.prevCameraPosition, scene.prevCameraPosition);
|
||||
VectorCopy(vp.orient.axis[0], scene.cameraForward);
|
||||
VectorCopy(vp.orient.axis[1], scene.cameraLeft);
|
||||
VectorCopy(vp.orient.axis[2], scene.cameraUp);
|
||||
scene.sceneViewIndex = sceneViewIndex;
|
||||
scene.frameIndex = tr.frameCount;
|
||||
scene.depthTextureIndex = GetTextureIndexSRV(depthTexture);
|
||||
scene.depthMinMaxTextureIndex = GetTextureIndexSRV(depthMinMaxTexture);
|
||||
scene.normalTextureIndex = GetTextureIndexSRV(normalTexture);
|
||||
scene.shadingPositionTextureIndex = GetTextureIndexSRV(shadingPositionTexture);
|
||||
scene.motionVectorTextureIndex = GetTextureIndexSRV(motionVectorTexture);
|
||||
scene.motionVectorMBTextureIndex = GetTextureIndexSRV(motionVectorMBTexture);
|
||||
scene.lightTextureIndex = GetTextureIndexSRV(lightTexture);
|
||||
scene.sunlightTextureIndex = GetTextureIndexSRV(sunlightTexture);
|
||||
scene.tlasBufferIndex = raytracing.GetTLASBufferIndex();
|
||||
scene.tlasInstanceBufferIndex = raytracing.GetInstanceBufferIndex();
|
||||
RB_LinearDepthConstants(scene.linearDepthConstants);
|
||||
scene.zNear = vp.zNear;
|
||||
scene.zFar = vp.zFar;
|
||||
scene.prevZNear = tr.prevZNear;
|
||||
scene.prevZFar = tr.prevZFar;
|
||||
|
||||
VectorCopy(sunlightData.direction, scene.sunDirection);
|
||||
VectorCopy(sunlightData.color, scene.sunColor);
|
||||
scene.sunIntensity = sunlightData.intensity;
|
||||
|
||||
VectorCopy(volumetricLight.ambientColor, scene.ambientColor);
|
||||
scene.ambientIntensity = volumetricLight.ambientIntensity;
|
||||
|
||||
Vector4Copy(volumetricLight.extinctionVolumeScale, scene.extinctionWorldScale);
|
||||
for(int c = 0; c < 4; c++)
|
||||
{
|
||||
const dlight_t& srcLight = refdef.dlights[i];
|
||||
DynamicLight& destLight = dest.lights[i];
|
||||
VectorCopy(srcLight.origin, destLight.position);
|
||||
VectorCopy(srcLight.color, destLight.color);
|
||||
destLight.radius = srcLight.radius;
|
||||
destLight.padding = 0.0f;
|
||||
scene.extinctionTextureIndices[c] = GetTextureIndexSRV(volumetricLight.extinctionTextures[c]);
|
||||
}
|
||||
|
||||
Vector4Copy(volumetricLight.sunShadowVolumeScale, scene.sunVShadowWorldScale);
|
||||
for(int c = 0; c < 4; c++)
|
||||
{
|
||||
scene.sunVShadowTextureIndices[c] = GetTextureIndexSRV(volumetricLight.sunShadowTextures[c]);
|
||||
}
|
||||
|
||||
scene.linearClampSamplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
|
||||
SceneView* const mappedScene = (SceneView*)(MapBuffer(uploadBuffer) + uploadByteOffset);
|
||||
memcpy(mappedScene, &scene, sizeof(scene));
|
||||
UnmapBuffer(uploadBuffer);
|
||||
|
||||
CmdBeginBarrier();
|
||||
|
|
|
@ -100,6 +100,7 @@ void WorldOpaque::Draw(const drawSceneViewCommand_t& cmd)
|
|||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.depthTexture, ResourceStates::DepthReadBit);
|
||||
CmdTextureBarrier(crp.lightTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.sunlightTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdBufferBarrier(srp.traceRenderBuffer, ResourceStates::UnorderedAccessBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
|
|
210
code/renderer/crp_sun_editor.cpp
Normal file
210
code/renderer/crp_sun_editor.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - sunlight editor
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
#include "../client/cl_imgui.h"
|
||||
#include "compshaders/crp/fullscreen.h"
|
||||
#include "compshaders/crp/sun_overlay.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct SunOverlayRC
|
||||
{
|
||||
vec3_t direction;
|
||||
float angle;
|
||||
vec3_t color;
|
||||
float padding;
|
||||
float textureWidth;
|
||||
float textureHeight;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
static bool LoadSunFile(const char* filePath)
|
||||
{
|
||||
bool success = false;
|
||||
void* data = NULL;
|
||||
if(ri.FS_ReadFile(filePath, &data) == sizeof(crp.sunlightData) &&
|
||||
data != NULL)
|
||||
{
|
||||
memcpy(&crp.sunlightData, data, sizeof(crp.sunlightData));
|
||||
success = true;
|
||||
}
|
||||
if(data != NULL)
|
||||
{
|
||||
ri.FS_FreeFile(data);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void SaveSunFile(const char* filePath)
|
||||
{
|
||||
FS_EnableCNQ3FolderWrites(qtrue);
|
||||
ri.FS_WriteFile(filePath, &crp.sunlightData, sizeof(crp.sunlightData));
|
||||
FS_EnableCNQ3FolderWrites(qfalse);
|
||||
}
|
||||
|
||||
static void LoadSunFromShader(const shader_t* skyShader)
|
||||
{
|
||||
vec2_t angles;
|
||||
angles[0] = DEG2RAD(skyShader->sunAzimuth);
|
||||
angles[1] = DEG2RAD(skyShader->sunInclination);
|
||||
VectorCopy(skyShader->sunColor, crp.sunlightData.color);
|
||||
crp.sunlightData.intensity = 1.0f;
|
||||
AzimuthInclinationToDirection(crp.sunlightData.direction, angles);
|
||||
}
|
||||
|
||||
void DirectionToAzimuthInclination(float* sc, const float* dir)
|
||||
{
|
||||
// 0=azimuth/phi, 1=inclination/theta
|
||||
sc[0] = atan2f(dir[1], dir[0]);
|
||||
sc[1] = atan2f(sqrtf(dir[0] * dir[0] + dir[1] * dir[1]), dir[2]);
|
||||
}
|
||||
|
||||
void AzimuthInclinationToDirection(float* dir, const float* sc)
|
||||
{
|
||||
// 0=azimuth/phi, 1=inclination/theta
|
||||
dir[0] = sinf(sc[1]) * cosf(sc[0]);
|
||||
dir[1] = sinf(sc[1]) * sinf(sc[0]);
|
||||
dir[2] = cosf(sc[1]);
|
||||
}
|
||||
|
||||
|
||||
void SunlightEditor::Init()
|
||||
{
|
||||
{
|
||||
GraphicsPipelineDesc desc("G-Buffer Depth");
|
||||
MakeFullScreenPipeline(desc, ShaderByteCode(g_sun_overlay_ps));
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void SunlightEditor::ProcessWorld(world_t& world)
|
||||
{
|
||||
skyShader = NULL;
|
||||
for(int i = 0; i < tr.numShaders; i++)
|
||||
{
|
||||
if(tr.shaders[i]->isSunDataValid)
|
||||
{
|
||||
skyShader = tr.shaders[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!LoadSunFile(va("sun/%s.sun", world.baseName)) &&
|
||||
skyShader != NULL)
|
||||
{
|
||||
LoadSunFromShader(skyShader);
|
||||
}
|
||||
}
|
||||
|
||||
void SunlightEditor::DrawOverlay()
|
||||
{
|
||||
if(!drawOverlay || !IsViewportFullscreen(backEnd.viewParms))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
SCOPED_RENDER_PASS("Sun Overlay", 1.0f, 1.0f, 1.0f);
|
||||
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
SunOverlayRC rc = {};
|
||||
rc.angle = 0.0f;
|
||||
VectorCopy(crp.sunlightData.color, rc.color);
|
||||
VectorCopy(crp.sunlightData.direction, rc.direction);
|
||||
rc.textureWidth = glConfig.vidWidth;
|
||||
rc.textureHeight = glConfig.vidHeight;
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(pipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
void SunlightEditor::DrawGUI()
|
||||
{
|
||||
if(tr.world == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GUI_AddMainMenuItem(GUI_MainMenu::Tools, "Edit Sunlight", "", &windowActive);
|
||||
|
||||
if(!windowActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(ImGui::Begin("Sunlight", &windowActive, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::Checkbox("Draw Sun", &drawOverlay);
|
||||
|
||||
float angles[2];
|
||||
DirectionToAzimuthInclination(angles, crp.sunlightData.direction);
|
||||
ImGui::NewLine();
|
||||
ImGui::SliderAngle("Azimuth", &angles[0], 0.0f, 360.0f);
|
||||
ImGui::SliderAngle("Inclination", &angles[1], 0.0f, 180.0f);
|
||||
AzimuthInclinationToDirection(crp.sunlightData.direction, angles);
|
||||
ImGui::ColorEdit3("Color", crp.sunlightData.color);
|
||||
ImGui::SliderFloat("Light intensity", &crp.sunlightData.intensity, 0.0f, 10.0f);
|
||||
|
||||
ImGui::NewLine();
|
||||
if(ImGui::Button("Save Config..."))
|
||||
{
|
||||
OpenSaveFileDialog("sun", ".sun");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Open Config..."))
|
||||
{
|
||||
OpenOpenFileDialog("sun", ".sun");
|
||||
}
|
||||
if(skyShader != NULL)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Import from Sky Shader"))
|
||||
{
|
||||
LoadSunFromShader(skyShader);
|
||||
}
|
||||
}
|
||||
|
||||
if(SaveFileDialog())
|
||||
{
|
||||
SaveSunFile(GetSaveFileDialogPath());
|
||||
}
|
||||
|
||||
if(OpenFileDialog())
|
||||
{
|
||||
LoadSunFile(GetOpenFileDialogPath());
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
137
code/renderer/crp_sunlight.cpp
Normal file
137
code/renderer/crp_sunlight.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - sunlight on opaque surfaces
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
#include "compshaders/crp/fullscreen.h"
|
||||
#include "compshaders/crp/sun_visibility.h"
|
||||
#include "compshaders/crp/sun_blur.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct SunBlurRC
|
||||
{
|
||||
uint32_t visibilityTextureIndex;
|
||||
uint32_t penumbraTextureIndex;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void Sunlight::Init()
|
||||
{
|
||||
if(!rhiInfo.hasInlineRaytracing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("Sunlight Visibility");
|
||||
MakeFullScreenPipeline(desc, ShaderByteCode(g_sun_visibility_ps));
|
||||
desc.AddRenderTarget(0, TextureFormat::R8_UNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::R8_UNorm);
|
||||
visibilityPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("Sunlight Blur");
|
||||
MakeFullScreenPipeline(desc, ShaderByteCode(g_sun_blur_ps));
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
blurPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("sunlight visibility", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.shortLifeTime = true;
|
||||
desc.format = TextureFormat::R8_UNorm;
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
visibilityTexture = CreateTexture(desc);
|
||||
desc.name = "sunlight penumbra";
|
||||
penumbraTexture = CreateTexture(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void Sunlight::Draw()
|
||||
{
|
||||
if(crp_sunlight->integer == 0 ||
|
||||
(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) != 0 ||
|
||||
!crp.raytracing.CanRaytrace() ||
|
||||
!IsViewportFullscreen(backEnd.viewParms))
|
||||
{
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.sunlightTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
CmdClearColorTarget(crp.sunlightTexture, colorBlack);
|
||||
return;
|
||||
}
|
||||
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
{
|
||||
SCOPED_RENDER_PASS("Sunlight Visibility", 1.0f, 1.0f, 1.0f);
|
||||
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.shadingPositionTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(visibilityTexture, ResourceStates::RenderTargetBit);
|
||||
CmdTextureBarrier(penumbraTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
const HTexture renderTargets[] = { visibilityTexture, penumbraTexture };
|
||||
CmdBindRenderTargets(ARRAY_LEN(renderTargets), renderTargets, NULL);
|
||||
CmdBindPipeline(visibilityPipeline);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_RENDER_PASS("Sunlight Blur", 1.0f, 1.0f, 1.0f);
|
||||
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
CmdBeginBarrier();
|
||||
for(int c = 0; c < 4; c++)
|
||||
{
|
||||
CmdTextureBarrier(crp.volumetricLight.sunShadowTextures[c], ResourceStates::PixelShaderAccessBit);
|
||||
}
|
||||
CmdTextureBarrier(visibilityTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(penumbraTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.shadingPositionTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.normalTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.sunlightTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
SunBlurRC rc = {};
|
||||
rc.penumbraTextureIndex = GetTextureIndexSRV(penumbraTexture);
|
||||
rc.visibilityTextureIndex = GetTextureIndexSRV(visibilityTexture);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.sunlightTexture, NULL);
|
||||
CmdBindPipeline(blurPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool Sunlight::WantRTASUpdate(const trRefdef_t& scene)
|
||||
{
|
||||
return crp_sunlight->integer != 0;
|
||||
}
|
|
@ -44,7 +44,7 @@ struct TranspDrawPixelRC
|
|||
uint32_t shaderTrace;
|
||||
uint16_t hFadeDistance;
|
||||
uint16_t hFadeOffset;
|
||||
uint32_t depthFadeScaleBias; // color bias: 4 - color scale: 4
|
||||
uint32_t depthFadeScaleBiasPO; // polygon offset: 1 - enable: 1 - color bias: 4 - color scale: 4
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
@ -137,6 +137,11 @@ void WorldTransp::Draw(const drawSceneViewCommand_t& cmd)
|
|||
Q_assert(shader != NULL);
|
||||
Q_assert(!shader->isOpaque);
|
||||
|
||||
if(shader->isFog)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool shaderChanged = shader != oldShader;
|
||||
const bool entityChanged = entityNum != oldEntityNum;
|
||||
if(shaderChanged || entityChanged)
|
||||
|
@ -290,6 +295,7 @@ void WorldTransp::EndBatch()
|
|||
const uint32_t alphaTest = AlphaTestShaderConstFromStateBits(stage->stateBits);
|
||||
const uint32_t enableShaderTrace = tr.traceWorldShader && s == 0 ? 1 : 0;
|
||||
const uint32_t enableDepthFade = shader->dfType != DFT_NONE ? 1 : 0;
|
||||
const uint32_t polygonOffset = shader->polygonOffset ? 1 : 0;
|
||||
Q_assert(sampIdx < ARRAY_LEN(crp.samplers));
|
||||
|
||||
TranspDrawPixelRC pixelRC = {};
|
||||
|
@ -304,7 +310,7 @@ void WorldTransp::EndBatch()
|
|||
pixelRC.shaderTrace = ((uint32_t)shader->index << 1) | enableShaderTrace;
|
||||
pixelRC.hFadeDistance = f32tof16(shader->dfInvDist);
|
||||
pixelRC.hFadeOffset = f32tof16(shader->dfBias);
|
||||
pixelRC.depthFadeScaleBias = (enableDepthFade << 8) | (uint32_t)r_depthFadeScaleAndBias[shader->dfType];
|
||||
pixelRC.depthFadeScaleBiasPO = (polygonOffset << 9) | (enableDepthFade << 8) | (uint32_t)r_depthFadeScaleAndBias[shader->dfType];
|
||||
CmdSetGraphicsRootConstants(sizeof(vertexRC), sizeof(pixelRC), &pixelRC);
|
||||
|
||||
db.DrawStage(vertexCount, indexCount);
|
||||
|
|
|
@ -24,24 +24,24 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "crp_local.h"
|
||||
#include "compshaders/crp/fullscreen.h"
|
||||
#include "compshaders/crp/transp_resolve.h"
|
||||
#include "compshaders/crp/transp_resolve_vol.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct TranspResolveRC
|
||||
{
|
||||
float scissorMinX;
|
||||
float scissorMinY;
|
||||
float scissorMaxX;
|
||||
float scissorMaxY;
|
||||
uint32_t renderTargetTexture;
|
||||
uint32_t shaderIndexBuffer;
|
||||
uint32_t indexTexture;
|
||||
uint32_t fragmentBuffer;
|
||||
uint16_t centerPixelX;
|
||||
uint16_t centerPixelY;
|
||||
uint32_t depthTexture;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float scissorMinX;
|
||||
float scissorMinY;
|
||||
float scissorMaxX;
|
||||
float scissorMaxY;
|
||||
uint32_t scatterTexture;
|
||||
uint32_t scatterSampler;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -51,16 +51,26 @@ void TranspResolve::Init()
|
|||
GraphicsPipelineDesc desc("OIT Resolve");
|
||||
MakeFullScreenPipeline(desc, ShaderByteCode(g_transp_resolve_ps));
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
pipeline = CreateGraphicsPipeline(desc);
|
||||
noVolPipeline = CreateGraphicsPipeline(desc);
|
||||
|
||||
desc.pixelShader = ShaderByteCode(g_transp_resolve_vol_ps);
|
||||
volPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
void TranspResolve::Draw(const drawSceneViewCommand_t& cmd)
|
||||
{
|
||||
if(cmd.numTranspSurfs <= 0)
|
||||
if(cmd.numTranspSurfs <= 0 && crp_volLight->integer == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const bool vlEnabled = crp.volumetricLight.ShouldDraw();
|
||||
HPipeline pipeline = noVolPipeline;
|
||||
if(vlEnabled)
|
||||
{
|
||||
pipeline = volPipeline;
|
||||
}
|
||||
|
||||
srp.renderMode = RenderMode::World;
|
||||
|
||||
SCOPED_RENDER_PASS("OIT Resolve", 1.0f, 0.5f, 0.5f);
|
||||
|
@ -70,6 +80,10 @@ void TranspResolve::Draw(const drawSceneViewCommand_t& cmd)
|
|||
crp.SwapRenderTargets();
|
||||
|
||||
CmdBeginBarrier();
|
||||
if(vlEnabled)
|
||||
{
|
||||
CmdTextureBarrier(crp.volumetricLight.scatterTransTexture, ResourceStates::PixelShaderAccessBit);
|
||||
}
|
||||
CmdTextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.GetWriteRenderTarget(), ResourceStates::RenderTargetBit);
|
||||
CmdTextureBarrier(crp.oitIndexTexture, ResourceStates::UnorderedAccessBit);
|
||||
|
@ -79,18 +93,21 @@ void TranspResolve::Draw(const drawSceneViewCommand_t& cmd)
|
|||
CmdEndBarrier();
|
||||
|
||||
TranspResolveRC rc = {};
|
||||
rc.scissorMinX = backEnd.viewParms.viewportX;
|
||||
rc.scissorMinY = backEnd.viewParms.viewportY;
|
||||
rc.scissorMaxX = rc.scissorMinX + backEnd.viewParms.viewportWidth - 1;
|
||||
rc.scissorMaxY = rc.scissorMinY + backEnd.viewParms.viewportHeight - 1;
|
||||
rc.fragmentBuffer = GetBufferIndexUAV(crp.oitFragmentBuffer);
|
||||
rc.indexTexture = GetTextureIndexUAV(crp.oitIndexTexture, 0);
|
||||
rc.renderTargetTexture = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.shaderIndexBuffer = GetBufferIndexUAV(srp.traceRenderBuffer);
|
||||
rc.centerPixelX = glConfig.vidWidth / 2;
|
||||
rc.centerPixelY = glConfig.vidHeight / 2;
|
||||
rc.depthTexture = GetTextureIndexSRV(crp.depthTexture);
|
||||
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
||||
rc.scissorMinX = backEnd.viewParms.viewportX;
|
||||
rc.scissorMinY = backEnd.viewParms.viewportY;
|
||||
rc.scissorMaxX = rc.scissorMinX + backEnd.viewParms.viewportWidth - 1;
|
||||
rc.scissorMaxY = rc.scissorMinY + backEnd.viewParms.viewportHeight - 1;
|
||||
if(vlEnabled)
|
||||
{
|
||||
rc.scatterTexture = GetTextureIndexSRV(crp.volumetricLight.scatterTransTexture);
|
||||
}
|
||||
rc.scatterSampler = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(pipeline);
|
||||
|
|
1545
code/renderer/crp_volumetric_light.cpp
Normal file
1545
code/renderer/crp_volumetric_light.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -48,6 +48,11 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#define GLS_DSTBLEND_BITS 0x000000f0u
|
||||
|
||||
#define GLS_BLEND_BITS 0x000000ffu
|
||||
#define GLS_BLEND_ADDITIVE (GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE)
|
||||
#define GLS_BLEND_STD_ALPHA (GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
#define GLS_BLEND_PMUL_ALPHA (GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA)
|
||||
#define GLS_BLEND_FILTER (GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO)
|
||||
#define GLS_BLEND_FILTER_V2 (GLS_SRCBLEND_ZERO | GLS_DSTBLEND_SRC_COLOR)
|
||||
|
||||
#define GLS_DEPTHMASK_TRUE 0x00000100u // enable depth writes
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "dof.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
|
@ -35,14 +36,13 @@ cbuffer RootConstants
|
|||
uint debugMode; // 1: colorized coc, 2: constant intensity far field
|
||||
int tcScale;
|
||||
float focusDist;
|
||||
float linearDepthA; // main view, to unproject to WS
|
||||
float linearDepthB;
|
||||
float maxNearCocCS;
|
||||
float maxFarCocCS;
|
||||
};
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
|
||||
|
@ -50,7 +50,7 @@ float4 ps(VOut input) : SV_Target
|
|||
int3 tcDepth = int3(input.position.xy / tcScale, 0);
|
||||
float3 color = colorTexture.Load(tcColor).rgb;
|
||||
float depthZW = depthTexture.Load(tcDepth);
|
||||
float depth = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depth = scene.LinearDepth(depthZW);
|
||||
bool nearField = depth < focusDist;
|
||||
float4 result;
|
||||
if(debugMode == 1)
|
||||
|
|
|
@ -58,9 +58,10 @@ float4 ps(VOut input) : SV_Target
|
|||
{
|
||||
SceneView scene = GetSceneView();
|
||||
Texture2D lightTexture = ResourceDescriptorHeap[scene.lightTextureIndex];
|
||||
Texture2D sunlightTexture = ResourceDescriptorHeap[scene.sunlightTextureIndex];
|
||||
|
||||
uint3 tc = uint3(input.position.xy, 0);
|
||||
float3 color = lightTexture.Load(tc).rgb;
|
||||
float3 color = lightTexture.Load(tc).rgb + sunlightTexture.Load(tc).rgb;
|
||||
float4 result = float4(color, 0);
|
||||
|
||||
return result;
|
||||
|
|
|
@ -30,6 +30,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#define ATEST_GE_HALF 3u
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
|
||||
bool FailsAlphaTest(float alpha, uint alphaTest)
|
||||
{
|
||||
if(alphaTest == ATEST_GT_0)
|
||||
|
@ -41,4 +42,10 @@ bool FailsAlphaTest(float alpha, uint alphaTest)
|
|||
else // ATEST_NONE
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PassesAlphaTest(float alpha, uint alphaTest)
|
||||
{
|
||||
return !FailsAlphaTest(alpha, alphaTest);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,6 +33,24 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#define PI_D4 (PI / 4.0)
|
||||
#define PI_M2 (PI * 2.0)
|
||||
|
||||
#define INT8_MIN 0x80
|
||||
#define INT16_MIN 0x8000
|
||||
#define INT32_MIN 0x80000000
|
||||
#define INT64_MIN 0x8000000000000000
|
||||
|
||||
#define INT8_MAX 0x7F
|
||||
#define INT16_MAX 0x7FFF
|
||||
#define INT32_MAX 0x7FFFFFFF
|
||||
#define INT64_MAX 0x7FFFFFFFFFFFFFFF
|
||||
|
||||
#define UINT8_MAX 0xFF
|
||||
#define UINT16_MAX 0xFFFF
|
||||
#define UINT32_MAX 0xFFFFFFFF
|
||||
#define UINT64_MAX 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
|
||||
typedef RaytracingAccelerationStructure RTAS;
|
||||
|
||||
|
||||
float DegToRad(float deg)
|
||||
{
|
||||
|
@ -59,22 +77,29 @@ float4 MakeGreyscale(float4 input, float amount)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
f = far clip plane distance
|
||||
n = near clip plane distance
|
||||
exp = exponential depth value (as stored in the Z-buffer)
|
||||
|
||||
2 * f * n B
|
||||
linear(exp) = ----------------------- = -------
|
||||
(f + n) - exp * (f - n) exp - A
|
||||
|
||||
f + n -2 * f * n
|
||||
with A = ----- and B = ----------
|
||||
f - n f - n
|
||||
*/
|
||||
float LinearDepth(float zwDepth, float A, float B)
|
||||
float LinearDepth(float zwDepth, float zNear, float zFar)
|
||||
{
|
||||
return B / (zwDepth - A);
|
||||
float n = zNear;
|
||||
float f = zFar;
|
||||
float zw = zwDepth;
|
||||
float zl = (f * n) / (n + zw * (f - n));
|
||||
|
||||
return zl;
|
||||
}
|
||||
|
||||
float LinearDepth(float zwDepth, float3 constants)
|
||||
{
|
||||
return constants.x / (constants.y + zwDepth * constants.z);
|
||||
}
|
||||
|
||||
float PostProjectionDepth(float viewDepth, float zNear, float zFar)
|
||||
{
|
||||
float n = zNear;
|
||||
float f = zFar;
|
||||
float zv = viewDepth;
|
||||
float zw = (n * (f - zv)) / ((f - n) * zv);
|
||||
|
||||
return zw;
|
||||
}
|
||||
|
||||
float4 FSTrianglePosFromVertexId(uint id)
|
||||
|
@ -138,6 +163,16 @@ float EaseInQuad(float x)
|
|||
return x * x;
|
||||
}
|
||||
|
||||
float EaseInExp(float x)
|
||||
{
|
||||
return x == 0.0 ? 0.0 : pow(2.0, 10.0 * x - 10.0);
|
||||
}
|
||||
|
||||
float EaseOutExp(float x)
|
||||
{
|
||||
return x == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * x);
|
||||
}
|
||||
|
||||
float smoothstep01(float x)
|
||||
{
|
||||
return smoothstep(0.0, 1.0, x);
|
||||
|
@ -285,24 +320,34 @@ float InterleavedGradientNoise(float2 uv)
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
bool IsValueInRange(T p, T min, T max)
|
||||
bool IsInRange(T p, T min, T max)
|
||||
{
|
||||
return all(p >= min) && all(p <= max);
|
||||
}
|
||||
|
||||
bool IsValue01(float2 p)
|
||||
bool Is01(float2 p)
|
||||
{
|
||||
return IsValueInRange(p, float2(0, 0), float2(1, 1));
|
||||
return IsInRange(p, float2(0, 0), float2(1, 1));
|
||||
}
|
||||
|
||||
bool IsValue01(float3 p)
|
||||
bool Is01(float3 p)
|
||||
{
|
||||
return IsValueInRange(p, float3(0, 0, 0), float3(1, 1, 1));
|
||||
return IsInRange(p, float3(0, 0, 0), float3(1, 1, 1));
|
||||
}
|
||||
|
||||
bool IsValue01(float4 p)
|
||||
bool Is01(float4 p)
|
||||
{
|
||||
return IsValueInRange(p, float4(0, 0, 0, 0), float4(1, 1, 1, 1));
|
||||
return IsInRange(p, float4(0, 0, 0, 0), float4(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
bool IsInTexture(int2 tc, int2 textureSize)
|
||||
{
|
||||
return all(tc >= int2(0, 0)) && all(tc < textureSize);
|
||||
}
|
||||
|
||||
bool IsInTexture(int3 tc, int3 textureSize)
|
||||
{
|
||||
return all(tc >= int3(0, 0, 0)) && all(tc < textureSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -323,6 +368,24 @@ uint2 GetTextureSize(RWTexture2D<T> texture0)
|
|||
return size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint3 GetTextureSize(Texture3D<T> texture0)
|
||||
{
|
||||
uint3 size;
|
||||
texture0.GetDimensions(size.x, size.y, size.z);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint3 GetTextureSize(RWTexture3D<T> texture0)
|
||||
{
|
||||
uint3 size;
|
||||
texture0.GetDimensions(size.x, size.y, size.z);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// by Sakib Saikia, https://sakibsaikia.github.io/graphics/2022/01/04/Nan-Checks-In-HLSL.html
|
||||
bool IsNan(float x)
|
||||
{
|
||||
|
@ -343,7 +406,14 @@ float AnimateBlueNoise(float blueNoise, uint frameIndex)
|
|||
|
||||
float2 NDCToTC(float2 ndc)
|
||||
{
|
||||
float2 tc = ndc * float2(0.5, -0.5) + 0.5;
|
||||
float2 tc = ndc * float2(0.5, -0.5) + float2(0.5, 0.5);
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
float3 NDCToTC(float3 ndc)
|
||||
{
|
||||
float3 tc = ndc * float3(0.5, -0.5, 0.5) + float3(0.5, 0.5, 0.5);
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
@ -355,6 +425,13 @@ float2 TCToNDC(float2 tc)
|
|||
return ndc;
|
||||
}
|
||||
|
||||
float3 TCToNDC(float3 tc)
|
||||
{
|
||||
float3 ndc = (2.0 * tc - 1.0) * float3(1, -1, 1);
|
||||
|
||||
return ndc;
|
||||
}
|
||||
|
||||
// returns the longest vector
|
||||
float2 vmax(float2 a, float2 b)
|
||||
{
|
||||
|
@ -397,6 +474,176 @@ float2 PolarToCartesian(float2 polar)
|
|||
return cartesian;
|
||||
}
|
||||
|
||||
// Beer-Lambert law
|
||||
float Transmittance(float distance, float extinction)
|
||||
{
|
||||
float transmittance = exp(-distance * extinction);
|
||||
|
||||
return transmittance;
|
||||
}
|
||||
|
||||
// phase function for Mie scattering
|
||||
// g is in the range [-1;1]
|
||||
// -1: backward scattering
|
||||
// 0: isotropic
|
||||
// 1: forward scattering
|
||||
float HenyeyGreenstein(float cosTheta, float g)
|
||||
{
|
||||
float g2 = g * g;
|
||||
float num = 1.0 - g2;
|
||||
float denom = 4.0 * PI * pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5);
|
||||
float result = num / denom;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint FlattenIndex(uint3 tileIndex, uint3 tileResolution)
|
||||
{
|
||||
return
|
||||
tileIndex.x +
|
||||
tileIndex.y * tileResolution.x +
|
||||
tileIndex.z * tileResolution.x * tileResolution.y;
|
||||
}
|
||||
|
||||
int FlattenIndex(int3 tileIndex, int3 tileResolution)
|
||||
{
|
||||
return
|
||||
tileIndex.x +
|
||||
tileIndex.y * tileResolution.x +
|
||||
tileIndex.z * tileResolution.x * tileResolution.y;
|
||||
}
|
||||
|
||||
uint3 UnflattenIndex(uint flatIndex, uint3 tileResolution)
|
||||
{
|
||||
uint h = tileResolution.y;
|
||||
uint wh = tileResolution.x * h;
|
||||
uint z = flatIndex / wh;
|
||||
flatIndex -= z * wh;
|
||||
uint y = flatIndex / h;
|
||||
uint x = flatIndex - y * h;
|
||||
uint3 result = uint3(x, y, z);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int3 UnflattenIndex(int flatIndex, int3 tileResolution)
|
||||
{
|
||||
int h = tileResolution.y;
|
||||
int wh = tileResolution.x * h;
|
||||
int z = flatIndex / wh;
|
||||
flatIndex -= z * wh;
|
||||
int y = flatIndex / h;
|
||||
int x = flatIndex - y * h;
|
||||
int3 result = int3(x, y, z);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClearBoundingBox(out int3 boxMin, out int3 boxMax)
|
||||
{
|
||||
boxMin = int3(INT32_MAX, INT32_MAX, INT32_MAX);
|
||||
boxMax = int3(INT32_MIN, INT32_MIN, INT32_MIN);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ExpandBoundingBox(inout T boxMin, inout T boxMax, T newPoint)
|
||||
{
|
||||
boxMin = min(boxMin, newPoint);
|
||||
boxMax = max(boxMax, newPoint);
|
||||
}
|
||||
|
||||
// Credit: Riku Salminen
|
||||
// dispatch the draw call with 36 indices
|
||||
float3 CubeFromVertexID(uint vertexId)
|
||||
{
|
||||
int tri = int(vertexId) / 3;
|
||||
int idx = int(vertexId) % 3;
|
||||
int face = tri / 2;
|
||||
int top = tri % 2;
|
||||
|
||||
int dir = face % 3;
|
||||
int pos = face / 3;
|
||||
|
||||
int nz = dir >> 1;
|
||||
int ny = dir & 1;
|
||||
int nx = 1 ^ (ny | nz);
|
||||
|
||||
float3 d = float3(nx, ny, nz);
|
||||
float flip = 1 - 2 * pos;
|
||||
|
||||
float3 n = flip * d;
|
||||
float3 u = -d.yzx;
|
||||
float3 v = flip * d.zxy;
|
||||
|
||||
float mirror = -1 + 2 * top;
|
||||
float3 xyz = n + mirror * (1 - 2 * (idx & 1)) * u + mirror * (1 - 2 * (idx >> 1)) * v;
|
||||
|
||||
return xyz;
|
||||
}
|
||||
|
||||
// dispatch the draw call with 6 indices
|
||||
float2 QuadFromVertexID(uint vertexId)
|
||||
{
|
||||
float2 position;
|
||||
position.x = (vertexId >= 1 && vertexId <= 3) ? 1.0 : -1.0;
|
||||
position.y = (vertexId >= 2 && vertexId <= 4) ? -1.0 : 1.0;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
float3 AABoxIndexToWorldSpace(int3 index, float3 centerPosition, float3 textureSize, float3 worldScale)
|
||||
{
|
||||
float3 position = centerPosition + worldScale * (float3(index)+float3(0.5, 0.5, 0.5) - 0.5 * textureSize);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
float3 AABoxTCToWorldSpace(float3 tc, float3 centerPosition, float3 textureSize, float3 worldScale)
|
||||
{
|
||||
float3 position = centerPosition + worldScale * textureSize * (tc - float3(0.5, 0.5, 0.5));
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
float3 AABoxWorldSpaceToTC(float3 position, float3 centerPosition, float3 textureSize, float3 worldScale)
|
||||
{
|
||||
float3 boxSize = worldScale * textureSize;
|
||||
float3 boxMin = centerPosition - 0.5 * boxSize;
|
||||
float3 tc = (position - boxMin) / boxSize;
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
int3 AABoxWorldSpaceToIndex(float3 position, float3 centerPosition, float3 textureSize, float3 worldScale)
|
||||
{
|
||||
float3 boxSize = worldScale * textureSize;
|
||||
float3 boxMin = centerPosition - 0.5 * boxSize;
|
||||
float3 indexF = (position - boxMin) / worldScale;
|
||||
int3 index = int3(indexF);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
float3 AABoxIndexToWorldSpace(int3 index, float3 centerPosition, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxIndexToWorldSpace(index, centerPosition, textureSize, worldScale.xxx);
|
||||
}
|
||||
|
||||
float3 AABoxTCToWorldSpace(float3 tc, float3 centerPosition, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxTCToWorldSpace(tc, centerPosition, textureSize, worldScale.xxx);
|
||||
}
|
||||
|
||||
float3 AABoxWorldSpaceToTC(float3 position, float3 centerPosition, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxWorldSpaceToTC(position, centerPosition, textureSize, worldScale.xxx);
|
||||
}
|
||||
|
||||
int3 AABoxWorldSpaceToIndex(float3 position, float3 centerPosition, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxWorldSpaceToIndex(position, centerPosition, textureSize, worldScale.xxx);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T min3(T v0, T v1, T v2)
|
||||
{
|
||||
|
@ -420,3 +667,49 @@ T max4(T v0, T v1, T v2, T v3)
|
|||
{
|
||||
return max(max(v0, v1), max(v2, v3));
|
||||
}
|
||||
|
||||
// credit: Inigo Quilez
|
||||
// returns t == -1 when nothing was hit
|
||||
float RaytraceSphere(float3 rayOrigin, float3 rayDir, float3 spherePos, float sphereRadius)
|
||||
{
|
||||
float3 oc = rayOrigin - spherePos;
|
||||
float b = dot(oc, rayDir);
|
||||
float c = dot(oc, oc) - sphereRadius * sphereRadius;
|
||||
float h = b * b - c;
|
||||
if(h < 0.0)
|
||||
{
|
||||
return -1.0;
|
||||
}
|
||||
h = sqrt(h);
|
||||
float t = -b - h;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
float3 DirectionFromLongLat(float longitude01, float latitude01)
|
||||
{
|
||||
float lon = longitude01 * PI_M2;
|
||||
float lat = latitude01 * PI_M2;
|
||||
float sinLat, cosLat;
|
||||
sincos(lat, sinLat, cosLat);
|
||||
float sinLon, cosLon;
|
||||
sincos(lon, sinLon, cosLon);
|
||||
float3 direction = float3(cosLat * sinLon, sinLat * sinLon, cosLon);
|
||||
|
||||
return direction;
|
||||
}
|
||||
|
||||
float3 AmbientColor(float4 payloadA, float4 payloadB, float3 normal, float3 fallbackColor)
|
||||
{
|
||||
float3 ambColor = payloadA.rgb;
|
||||
float3 localColor = float3(payloadA.a, payloadB.rg);
|
||||
float3 localDir = DirectionFromLongLat(payloadB.b, payloadB.a);
|
||||
float localScale = dot(localDir, normal) * 0.5 + 0.5; // wraps around
|
||||
float3 interpColor = ambColor + localColor * localScale;
|
||||
float brightNew = Brightness(interpColor);
|
||||
float brightFall = Brightness(fallbackColor);
|
||||
float t = saturate(brightNew / max(brightFall, 0.001));
|
||||
float3 color = lerp(fallbackColor, interpColor, t);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,11 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 lightPosition;
|
||||
uint textureIndex;
|
||||
uint vshadowTextureIndex;
|
||||
uint vshadowSamplerIndex;
|
||||
float vshadowWorldScale;
|
||||
};
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
|
@ -36,6 +40,8 @@ float4 ps(VOut input) : SV_Target
|
|||
SceneView scene = GetSceneView();
|
||||
Texture2D shadingPositionTexture = ResourceDescriptorHeap[scene.shadingPositionTextureIndex];
|
||||
Texture2D texture0 = ResourceDescriptorHeap[textureIndex];
|
||||
Texture3D<float> vshadowTexture = ResourceDescriptorHeap[vshadowTextureIndex];
|
||||
SamplerState vshadowSampler = SamplerDescriptorHeap[vshadowSamplerIndex];
|
||||
int2 textureMax = GetTextureSize(texture0) - int2(1, 1);
|
||||
|
||||
int2 tcFrag = int2(input.position.xy);
|
||||
|
@ -48,7 +54,7 @@ float4 ps(VOut input) : SV_Target
|
|||
for(int x = -4; x <= 4; x++)
|
||||
{
|
||||
int2 tc = tcFrag + int2(x, y);
|
||||
if(!IsValueInRange(tcFrag, int2(0, 0), textureMax))
|
||||
if(!IsInRange(tcFrag, int2(0, 0), textureMax))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -68,7 +74,7 @@ float4 ps(VOut input) : SV_Target
|
|||
for(int x = -blurRadius; x <= blurRadius; x++)
|
||||
{
|
||||
int2 tc = tcFrag + int2(x, y);
|
||||
if(!IsValueInRange(tcFrag, int2(0, 0), textureMax))
|
||||
if(!IsInRange(tcFrag, int2(0, 0), textureMax))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -87,7 +93,12 @@ float4 ps(VOut input) : SV_Target
|
|||
{
|
||||
accum /= weightSum;
|
||||
}
|
||||
float4 result = float4(accum, 1);
|
||||
|
||||
float3 vshadowTC = AABoxWorldSpaceToTC(positionFrag, lightPosition, GetTextureSize(vshadowTexture), vshadowWorldScale);
|
||||
float transmittance = vshadowTexture.SampleLevel(vshadowSampler, vshadowTC, 0);
|
||||
accum *= transmittance;
|
||||
|
||||
float4 result = float4(accum, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -25,73 +25,14 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "fullscreen.hlsli"
|
||||
#include "raytracing.h.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#include "alpha_test.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
DynamicLight light;
|
||||
uint blueNoiseTextureIndex;
|
||||
};
|
||||
|
||||
#define CLASS_OPAQUE 0u
|
||||
#define CLASS_INVISIBLE 1u
|
||||
#define CLASS_TRANSLUCENT 2u
|
||||
|
||||
uint ClassifyNonOpaqueTriangle(inout float3 light, StructuredBuffer<TLASInstance> tlasInstanceBuffer, uint instanceId, uint meshId, uint triangleId, float2 bary2, bool frontFace)
|
||||
{
|
||||
TLASInstance instance = tlasInstanceBuffer[instanceId];
|
||||
#if 0
|
||||
// @TODO: is this needed or not?
|
||||
// cull mode: 0 is front-sided, 1 is back-sided
|
||||
if((frontFace && instance.cullMode == 1) ||
|
||||
(!frontFace && instance.cullMode == 0))
|
||||
{
|
||||
return CLASS_INVISIBLE;
|
||||
}
|
||||
#endif
|
||||
StructuredBuffer<BLASMesh> meshBuffer = ResourceDescriptorHeap[instance.meshBufferIndex];
|
||||
BLASMesh mesh = meshBuffer[meshId];
|
||||
float3 barycentrics = float3(1.0 - bary2.x - bary2.y, bary2.x, bary2.y);
|
||||
StructuredBuffer<BLASVertex> vertexBuffer = ResourceDescriptorHeap[instance.vertexBufferIndex];
|
||||
StructuredBuffer<uint> indexBuffer = ResourceDescriptorHeap[instance.indexBufferIndex];
|
||||
uint firstIndex = mesh.firstIndex + triangleId * 3;
|
||||
uint vtxIdx0 = mesh.firstVertex + indexBuffer[firstIndex + 0];
|
||||
uint vtxIdx1 = mesh.firstVertex + indexBuffer[firstIndex + 1];
|
||||
uint vtxIdx2 = mesh.firstVertex + indexBuffer[firstIndex + 2];
|
||||
BLASVertex v0 = vertexBuffer[vtxIdx0];
|
||||
BLASVertex v1 = vertexBuffer[vtxIdx1];
|
||||
BLASVertex v2 = vertexBuffer[vtxIdx2];
|
||||
float2 texCoords = trilerp(v0.texCoords, v1.texCoords, v2.texCoords, barycentrics);
|
||||
float4 vertexColor = trilerp(UnpackColor(v0.color), UnpackColor(v1.color), UnpackColor(v2.color), barycentrics);
|
||||
Texture2D texture0 = ResourceDescriptorHeap[mesh.textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[mesh.samplerIndex];
|
||||
float4 textureColor = texture0.SampleLevel(sampler0, texCoords, 0);
|
||||
float4 hitColor = vertexColor * textureColor;
|
||||
if(mesh.alphaTestMode == 0)
|
||||
{
|
||||
float3 blended;
|
||||
if(mesh.blendBits == (GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE))
|
||||
{
|
||||
blended = lerp(light, hitColor.rgb, Brightness(hitColor.rgb));
|
||||
}
|
||||
else
|
||||
{
|
||||
blended = Blend(hitColor, float4(light, 1), mesh.blendBits).rgb;
|
||||
}
|
||||
if(all(blended == light))
|
||||
{
|
||||
return CLASS_INVISIBLE;
|
||||
}
|
||||
light = blended;
|
||||
return CLASS_TRANSLUCENT;
|
||||
}
|
||||
if(FailsAlphaTest(hitColor.a, mesh.alphaTestMode))
|
||||
{
|
||||
return CLASS_INVISIBLE;
|
||||
}
|
||||
return CLASS_OPAQUE;
|
||||
}
|
||||
|
||||
float2 MapSquareToDisk(float2 square01)
|
||||
{
|
||||
float radius = sqrt(square01.x);
|
||||
|
@ -115,142 +56,50 @@ float3 GetRayDirectionForSphereLight(float2 square01, float3 surfacePos, float3
|
|||
return result;
|
||||
}
|
||||
|
||||
// true when fully in shadow
|
||||
bool TraceShadowRay(
|
||||
out float t, inout float3 light,
|
||||
RaytracingAccelerationStructure rtas, StructuredBuffer<TLASInstance> instBuffer,
|
||||
float3 position, float3 direction, float dist)
|
||||
{
|
||||
RayDesc ray;
|
||||
ray.Origin = position;
|
||||
ray.Direction = direction;
|
||||
ray.TMin = 0.0;
|
||||
ray.TMax = dist;
|
||||
|
||||
t = 0.0;
|
||||
float translucentT = 0.0;
|
||||
RayQuery<RAY_FLAG_NONE> q;
|
||||
q.TraceRayInline(rtas, RAY_FLAG_NONE, 0xFF, ray);
|
||||
while(q.Proceed())
|
||||
{
|
||||
if(q.CandidateType() == CANDIDATE_NON_OPAQUE_TRIANGLE)
|
||||
{
|
||||
uint type = ClassifyNonOpaqueTriangle(
|
||||
light,
|
||||
instBuffer,
|
||||
q.CandidateInstanceIndex(),
|
||||
q.CandidateGeometryIndex(),
|
||||
q.CandidatePrimitiveIndex(),
|
||||
q.CandidateTriangleBarycentrics(),
|
||||
q.CandidateTriangleFrontFace());
|
||||
if(type == CLASS_OPAQUE)
|
||||
{
|
||||
q.CommitNonOpaqueTriangleHit();
|
||||
}
|
||||
else if(type == CLASS_TRANSLUCENT)
|
||||
{
|
||||
translucentT = q.CandidateTriangleRayT();
|
||||
t = translucentT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(q.CommittedStatus() == COMMITTED_TRIANGLE_HIT)
|
||||
{
|
||||
t = q.CommittedRayT();
|
||||
}
|
||||
|
||||
if(q.CommittedStatus() == COMMITTED_TRIANGLE_HIT && t > translucentT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// true when fully in shadow
|
||||
bool TraceShadowRayOpaqueOnly(
|
||||
out float t, inout float3 light,
|
||||
RaytracingAccelerationStructure rtas, StructuredBuffer<TLASInstance> instBuffer,
|
||||
float3 position, float3 direction, float dist)
|
||||
{
|
||||
RayDesc ray;
|
||||
ray.Origin = position;
|
||||
ray.Direction = direction;
|
||||
ray.TMin = 0.0;
|
||||
ray.TMax = dist;
|
||||
|
||||
t = 0.0;
|
||||
bool keepLight = false;
|
||||
RayQuery<RAY_FLAG_CULL_NON_OPAQUE> q;
|
||||
q.TraceRayInline(rtas, RAY_FLAG_NONE, 0xFF, ray);
|
||||
q.Proceed();
|
||||
if(q.CommittedStatus() == COMMITTED_TRIANGLE_HIT)
|
||||
{
|
||||
t = q.CommittedRayT();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
RaytracingAccelerationStructure rtas = ResourceDescriptorHeap[scene.tlasBufferIndex];
|
||||
Texture2D<float2> normalTexture = ResourceDescriptorHeap[scene.normalTextureIndex];
|
||||
Texture2D shadingPositionTexture = ResourceDescriptorHeap[scene.shadingPositionTextureIndex];
|
||||
uint3 tc = uint3(input.position.xy, 0);
|
||||
float3 positionWS = shadingPositionTexture.Load(tc).xyz;
|
||||
float3 lightPosition = light.position;
|
||||
float dist = distance(positionWS, lightPosition);
|
||||
float radius = light.radius;
|
||||
if(dist >= radius)
|
||||
{
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
RTAS rtas = ResourceDescriptorHeap[scene.tlasBufferIndex];
|
||||
Texture2D<float2> normalTexture = ResourceDescriptorHeap[scene.normalTextureIndex];
|
||||
StructuredBuffer<TLASInstance> tlasInstanceBuffer = ResourceDescriptorHeap[scene.tlasInstanceBufferIndex];
|
||||
Texture2D blueNoiseTexture = ResourceDescriptorHeap[blueNoiseTextureIndex];
|
||||
|
||||
uint2 blueNoiseTextureSize;
|
||||
blueNoiseTexture.GetDimensions(blueNoiseTextureSize.x, blueNoiseTextureSize.y);
|
||||
|
||||
uint3 tc = uint3(input.position.xy, 0);
|
||||
uint2 blueNoiseTextureSize = GetTextureSize(blueNoiseTexture);
|
||||
float3 normalWS = normalize(OctDecode(normalTexture.Load(tc)));
|
||||
float3 positionWS = shadingPositionTexture.Load(tc).xyz;
|
||||
float innerRadius = radius / 100.0;
|
||||
float intensity = saturate(1.0 - dist / radius);
|
||||
float3 lightDir = normalize(lightPosition - positionWS);
|
||||
float3 lightRaw = light.color * intensity * max(dot(normalWS, lightDir), 0.0);
|
||||
const uint SampleCount = 4;
|
||||
|
||||
float3 lightAccum = float3(0, 0, 0);
|
||||
float error = 0.0;
|
||||
float3 pixelAccum = float3(0, 0, 0);
|
||||
for(uint i = 0; i < scene.lightCount; i++)
|
||||
for(uint r = 0; r < SampleCount; r++)
|
||||
{
|
||||
float3 lightPosition = scene.lights[i].position;
|
||||
float dist = distance(positionWS, lightPosition);
|
||||
float radius = scene.lights[i].radius;
|
||||
if(dist >= radius)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float innerRadius = radius / 100.0;
|
||||
float intensity = saturate(1.0 - dist / radius);
|
||||
float3 lightDir = normalize(lightPosition - positionWS);
|
||||
float3 lightRaw = scene.lights[i].color * intensity * max(dot(normalWS, lightDir), 0.0);
|
||||
const uint SampleCount = 4;
|
||||
|
||||
float3 lightAccum = float3(0, 0, 0);
|
||||
for(uint r = 0; r < SampleCount; r++)
|
||||
{
|
||||
float3 light = lightRaw;
|
||||
uint2 pos = uint2(input.position.xy) + uint2(r * 17, r * 13 + 7);
|
||||
uint2 tc = pos % blueNoiseTextureSize;
|
||||
float2 square01 = blueNoiseTexture.Load(uint3(tc, 0)).xy;
|
||||
float3 dir = GetRayDirectionForSphereLight(square01, positionWS, lightPosition, innerRadius);
|
||||
float t;
|
||||
bool inShadow = TraceShadowRay(t, light, rtas, tlasInstanceBuffer, positionWS, dir, dist);
|
||||
error = max(error, t / radius);
|
||||
if(inShadow)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
lightAccum += light;
|
||||
}
|
||||
|
||||
pixelAccum += lightAccum / float(SampleCount);
|
||||
float3 light = lightRaw;
|
||||
uint2 pos = uint2(input.position.xy) + uint2(r * 17, r * 13 + 7);
|
||||
uint2 tc = pos % blueNoiseTextureSize;
|
||||
float2 square01 = blueNoiseTexture.Load(uint3(tc, 0)).xy;
|
||||
float3 dir = GetRayDirectionForSphereLight(square01, positionWS, lightPosition, innerRadius);
|
||||
float t;
|
||||
float vis = TraceVisibilityWithATt(t, rtas, tlasInstanceBuffer, positionWS, dir, dist);
|
||||
error = max(error, t / radius);
|
||||
lightAccum += light * vis;
|
||||
}
|
||||
lightAccum /= float(SampleCount);
|
||||
|
||||
float4 result = float4(pixelAccum, saturate(error));
|
||||
float4 result = float4(lightAccum, saturate(error));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "fullscreen.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
#include "dof.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
|
@ -32,8 +33,6 @@ cbuffer RootConstants : register(b0)
|
|||
uint colorTextureIndex;
|
||||
uint depthTextureIndex;
|
||||
uint debugMode;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
|
@ -43,12 +42,13 @@ cbuffer RootConstants : register(b0)
|
|||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
uint3 tc = uint3(input.position.x, input.position.y, 0);
|
||||
float3 color = colorTexture.Load(tc).rgb;
|
||||
float depthZW = depthTexture.Load(tc);
|
||||
float depth = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depth = scene.LinearDepth(depthZW);
|
||||
float coc = CircleOfConfusion(depth, focusNearMin, focusNearMax, focusFarMin, focusFarMax);
|
||||
float nearField = coc < 0.0;
|
||||
float4 result;
|
||||
|
|
|
@ -23,6 +23,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
#include "common.hlsli"
|
||||
#include "gatherdof.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
|
@ -33,8 +34,6 @@ cbuffer RootConstants : register(b0)
|
|||
uint farColorTextureIndex;
|
||||
uint nearCocTextureIndex;
|
||||
uint farCocTextureIndex;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float focusNearMin;
|
||||
float focusNearMax;
|
||||
float focusFarMin;
|
||||
|
@ -54,6 +53,7 @@ void cs(uint3 dtid : SV_DispatchThreadID)
|
|||
return;
|
||||
}
|
||||
|
||||
SceneView scene = GetSceneView();
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
RWTexture2D<float4> nearColorTexture = ResourceDescriptorHeap[nearColorTextureIndex];
|
||||
RWTexture2D<float4> farColorTexture = ResourceDescriptorHeap[farColorTextureIndex];
|
||||
|
@ -62,7 +62,7 @@ void cs(uint3 dtid : SV_DispatchThreadID)
|
|||
|
||||
float4 color = colorTexture[tc];
|
||||
float depthZW = depthTexture[tc];
|
||||
float depth = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depth = scene.LinearDepth(depthZW);
|
||||
float coc = CircleOfConfusion(depth, focusNearMin, focusNearMax, focusFarMin, focusFarMax);
|
||||
float nearCoc = max(-coc, 0.0);
|
||||
float farCoc = max(coc, 0.0);
|
||||
|
|
|
@ -23,23 +23,17 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint depthTextureIndex;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float zFarInv;
|
||||
};
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[scene.depthTextureIndex];
|
||||
uint3 tc = uint3(input.position.xy, 0);
|
||||
float depthZW = depthTexture.Load(tc);
|
||||
float depth = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depth01 = depth * zFarInv;
|
||||
float depth = scene.LinearDepth(depthZW);
|
||||
float depth01 = depth / scene.zFar;
|
||||
float4 result = float4(depth01.xxx, 1);
|
||||
|
||||
return result;
|
||||
|
|
|
@ -171,7 +171,7 @@ float4 ps(VOut input) : SV_Target
|
|||
float2 TC1 = input.texCoords + i1 * tcStep;
|
||||
|
||||
[branch]
|
||||
if(!IsValue01(TC0) || !IsValue01(TC1))
|
||||
if(!Is01(TC0) || !Is01(TC1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ float4 ps(VOut input) : SV_Target
|
|||
dirn = Vcn;
|
||||
}
|
||||
|
||||
if(!IsValue01(tc))
|
||||
if(!Is01(tc))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -47,8 +47,8 @@ struct OIT_Fragment
|
|||
uint next;
|
||||
uint shaderTrace; // shader index: 14 - enable: 1
|
||||
uint depthFadeDistOffset; // offset: fp16 - distance: fp16
|
||||
uint depthFadeScaleBias; // enable: 1 - color bias: 4 - color scale: 4
|
||||
// @TODO: move the 9 bits from depthFadeScaleBias into shaderTrace
|
||||
uint depthFadeScaleBiasPO; // polygon offset: 1 - enable: 1 - color bias: 4 - color scale: 4
|
||||
// @TODO: move the 10 bits from depthFadeScaleBiasPO into shaderTrace
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
|
|
@ -56,3 +56,118 @@ struct TLASInstance
|
|||
#if defined(__cplusplus)
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "alpha_test.h.hlsli"
|
||||
|
||||
bool IsTriangleHitOpaque(StructuredBuffer<TLASInstance> tlasInstanceBuffer, uint instanceId, uint meshId, uint triangleId, float2 bary2, bool frontFace)
|
||||
{
|
||||
TLASInstance instance = tlasInstanceBuffer[instanceId];
|
||||
StructuredBuffer<BLASMesh> meshBuffer = ResourceDescriptorHeap[instance.meshBufferIndex];
|
||||
BLASMesh mesh = meshBuffer[meshId];
|
||||
[branch] if(mesh.alphaTestMode == 0)
|
||||
{
|
||||
return false; // translucent -> ignored
|
||||
}
|
||||
|
||||
float3 barycentrics = float3(1.0 - bary2.x - bary2.y, bary2.x, bary2.y);
|
||||
StructuredBuffer<BLASVertex> vertexBuffer = ResourceDescriptorHeap[instance.vertexBufferIndex];
|
||||
StructuredBuffer<uint> indexBuffer = ResourceDescriptorHeap[instance.indexBufferIndex];
|
||||
uint firstIndex = mesh.firstIndex + triangleId * 3;
|
||||
uint vtxIdx0 = mesh.firstVertex + indexBuffer[firstIndex + 0];
|
||||
uint vtxIdx1 = mesh.firstVertex + indexBuffer[firstIndex + 1];
|
||||
uint vtxIdx2 = mesh.firstVertex + indexBuffer[firstIndex + 2];
|
||||
BLASVertex v0 = vertexBuffer[vtxIdx0];
|
||||
BLASVertex v1 = vertexBuffer[vtxIdx1];
|
||||
BLASVertex v2 = vertexBuffer[vtxIdx2];
|
||||
float2 texCoords = trilerp(v0.texCoords, v1.texCoords, v2.texCoords, barycentrics);
|
||||
float4 vertexColor = trilerp(UnpackColor(v0.color), UnpackColor(v1.color), UnpackColor(v2.color), barycentrics);
|
||||
Texture2D texture0 = ResourceDescriptorHeap[mesh.textureIndex];
|
||||
SamplerState sampler0 = SamplerDescriptorHeap[mesh.samplerIndex];
|
||||
float4 textureColor = texture0.SampleLevel(sampler0, texCoords, 0);
|
||||
float4 hitColor = vertexColor * textureColor;
|
||||
bool isOpaque = PassesAlphaTest(hitColor.a, mesh.alphaTestMode);
|
||||
|
||||
return isOpaque;
|
||||
}
|
||||
|
||||
float TraceVisibilityWithATt(
|
||||
out float t, RTAS rtas, StructuredBuffer<TLASInstance> instBuffer,
|
||||
float3 position, float3 direction, float dist)
|
||||
{
|
||||
RayDesc ray;
|
||||
ray.Origin = position;
|
||||
ray.Direction = direction;
|
||||
ray.TMin = 0.0;
|
||||
ray.TMax = dist;
|
||||
|
||||
t = 0.0;
|
||||
RayQuery<RAY_FLAG_NONE> q;
|
||||
q.TraceRayInline(rtas, RAY_FLAG_NONE, 0xFF, ray);
|
||||
while(q.Proceed())
|
||||
{
|
||||
if(q.CandidateType() == CANDIDATE_NON_OPAQUE_TRIANGLE)
|
||||
{
|
||||
bool isOpaque = IsTriangleHitOpaque(
|
||||
instBuffer,
|
||||
q.CandidateInstanceIndex(),
|
||||
q.CandidateGeometryIndex(),
|
||||
q.CandidatePrimitiveIndex(),
|
||||
q.CandidateTriangleBarycentrics(),
|
||||
q.CandidateTriangleFrontFace());
|
||||
if(isOpaque)
|
||||
{
|
||||
q.CommitNonOpaqueTriangleHit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(q.CommittedStatus() == COMMITTED_TRIANGLE_HIT)
|
||||
{
|
||||
t = q.CommittedRayT();
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float TraceVisibilityWithAT(
|
||||
RTAS rtas, StructuredBuffer<TLASInstance> instBuffer,
|
||||
float3 position, float3 direction, float dist)
|
||||
{
|
||||
float t;
|
||||
return TraceVisibilityWithATt(t, rtas, instBuffer, position, direction, dist);
|
||||
}
|
||||
|
||||
float TraceVisibilityWithoutATt(
|
||||
out float t, RTAS rtas,
|
||||
float3 position, float3 direction, float dist)
|
||||
{
|
||||
RayDesc ray;
|
||||
ray.Origin = position;
|
||||
ray.Direction = direction;
|
||||
ray.TMin = 0.0;
|
||||
ray.TMax = dist;
|
||||
|
||||
t = 0.0;
|
||||
RayQuery<RAY_FLAG_CULL_NON_OPAQUE> q;
|
||||
q.TraceRayInline(rtas, RAY_FLAG_NONE, 0xFF, ray);
|
||||
q.Proceed();
|
||||
if(q.CommittedStatus() == COMMITTED_TRIANGLE_HIT)
|
||||
{
|
||||
t = q.CommittedRayT();
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float TraceVisibilityWithoutAT(RTAS rtas, float3 position, float3 direction, float dist)
|
||||
{
|
||||
float t;
|
||||
return TraceVisibilityWithoutATt(t, rtas, position, direction, dist);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,10 +25,29 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
#include "typedefs.h.hlsli"
|
||||
#if !defined(__cplusplus)
|
||||
# include "common.hlsli"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# pragma pack(push, 4)
|
||||
#endif
|
||||
|
||||
// @TODO: move out
|
||||
struct Particle
|
||||
{
|
||||
float3 position;
|
||||
float radius;
|
||||
float3 scattering; // or emissive
|
||||
float absorption;
|
||||
float anisotropy;
|
||||
uint isEmissive;
|
||||
};
|
||||
|
||||
// @TODO: move out
|
||||
#define MAX_PARTICLES 8192
|
||||
|
||||
// @TODO: move out
|
||||
struct DynamicLight
|
||||
{
|
||||
float3 position;
|
||||
|
@ -37,8 +56,164 @@ struct DynamicLight
|
|||
float padding;
|
||||
};
|
||||
|
||||
// @TODO: move out
|
||||
#define SCENE_VIEW_MAX_LIGHTS 32
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
struct ExtinctionCascade
|
||||
{
|
||||
// copied over
|
||||
Texture3D<float> textures[4];
|
||||
SamplerState linearClampSampler;
|
||||
float4 worldScale;
|
||||
float3 cameraPosition;
|
||||
float3 textureSize;
|
||||
// set by SetSamplingVolume
|
||||
uint lowestMipLevel;
|
||||
float mipLerp;
|
||||
|
||||
void SetSamplingVolume(float voxelSize)
|
||||
{
|
||||
float mipLevel = max(log2(voxelSize / worldScale.x), 0.0);
|
||||
if(mipLevel <= 2.0)
|
||||
{
|
||||
lowestMipLevel = uint(floor(mipLevel));
|
||||
mipLerp = frac(mipLevel);
|
||||
}
|
||||
else if(voxelSize >= worldScale.w)
|
||||
{
|
||||
lowestMipLevel = 3;
|
||||
mipLerp = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float base = worldScale.w / worldScale.z;
|
||||
float mipLevelFrac = log2(voxelSize / worldScale.z) / log2(base);
|
||||
lowestMipLevel = 2;
|
||||
mipLerp = mipLevelFrac;
|
||||
}
|
||||
}
|
||||
|
||||
float ExtinctionAt(float3 position)
|
||||
{
|
||||
float ext;
|
||||
if(ExtinctionAtMip(position, 0, ext))
|
||||
{
|
||||
return ext;
|
||||
}
|
||||
if(ExtinctionAtMip(position, 1, ext))
|
||||
{
|
||||
return ext;
|
||||
}
|
||||
if(ExtinctionAtMip(position, 2, ext))
|
||||
{
|
||||
return ext;
|
||||
}
|
||||
|
||||
float3 tc = AABoxWorldSpaceToTC(position, cameraPosition, textureSize, worldScale.w);
|
||||
ext = textures[3].SampleLevel(linearClampSampler, tc, 0);
|
||||
return ext;
|
||||
}
|
||||
|
||||
bool ExtinctionAtMip(float3 position, uint mip, out float ext)
|
||||
{
|
||||
if(lowestMipLevel == mip)
|
||||
{
|
||||
float3 tc0 = AABoxWorldSpaceToTC(position, cameraPosition, textureSize, worldScale[mip + 0]);
|
||||
if(Is01(tc0)) // @TODO: make sure it's at least a half-texel inside
|
||||
{
|
||||
float3 tc1 = AABoxWorldSpaceToTC(position, cameraPosition, textureSize, worldScale[mip + 1]);
|
||||
float ext0 = textures[mip + 0].SampleLevel(linearClampSampler, tc0, 0);
|
||||
float ext1 = textures[mip + 1].SampleLevel(linearClampSampler, tc1, 0);
|
||||
ext = lerp(ext0, ext1, mipLerp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
struct SunVShadowCascade
|
||||
{
|
||||
// copied over
|
||||
Texture3D<float> textures[4];
|
||||
SamplerState linearClampSampler;
|
||||
float4 worldScale;
|
||||
float3 cameraPosition;
|
||||
float3 textureSize;
|
||||
float3x3 zToSunMatrix;
|
||||
// set by SetSamplingVolume
|
||||
uint lowestMipLevel;
|
||||
float mipLerp;
|
||||
|
||||
void SetSamplingVolume(float voxelSize)
|
||||
{
|
||||
float mipLevel = max(log2(voxelSize / worldScale.x), 0.0);
|
||||
if(mipLevel <= 2.0)
|
||||
{
|
||||
lowestMipLevel = uint(floor(mipLevel));
|
||||
mipLerp = frac(mipLevel);
|
||||
}
|
||||
else if(voxelSize >= worldScale.w)
|
||||
{
|
||||
lowestMipLevel = 3;
|
||||
mipLerp = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float base = worldScale.w / worldScale.z;
|
||||
float mipLevelFrac = log2(voxelSize / worldScale.z) / log2(base);
|
||||
lowestMipLevel = 2;
|
||||
mipLerp = mipLevelFrac;
|
||||
}
|
||||
}
|
||||
|
||||
float TransmittanceAt(float3 positionWS)
|
||||
{
|
||||
float3 positionSS = cameraPosition + mul(zToSunMatrix, positionWS - cameraPosition);
|
||||
|
||||
float ext;
|
||||
if(TransmittanceAtMip(positionSS, 0, ext))
|
||||
{
|
||||
return ext;
|
||||
}
|
||||
if(TransmittanceAtMip(positionSS, 1, ext))
|
||||
{
|
||||
return ext;
|
||||
}
|
||||
if(TransmittanceAtMip(positionSS, 2, ext))
|
||||
{
|
||||
return ext;
|
||||
}
|
||||
|
||||
float3 tc = AABoxWorldSpaceToTC(positionSS, cameraPosition, textureSize, worldScale.w);
|
||||
ext = textures[3].SampleLevel(linearClampSampler, tc, 0);
|
||||
return ext;
|
||||
}
|
||||
|
||||
bool TransmittanceAtMip(float3 position, uint mip, out float ext)
|
||||
{
|
||||
if(lowestMipLevel == mip)
|
||||
{
|
||||
float3 tc0 = AABoxWorldSpaceToTC(position, cameraPosition, textureSize, worldScale[mip + 0]);
|
||||
if(Is01(tc0)) // @TODO: make sure it's at least a half-texel inside
|
||||
{
|
||||
float3 tc1 = AABoxWorldSpaceToTC(position, cameraPosition, textureSize, worldScale[mip + 1]);
|
||||
float ext0 = textures[mip + 0].SampleLevel(linearClampSampler, tc0, 0);
|
||||
float ext1 = textures[mip + 1].SampleLevel(linearClampSampler, tc1, 0);
|
||||
ext = lerp(ext0, ext1, mipLerp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct SceneView
|
||||
{
|
||||
matrix projectionMatrix;
|
||||
|
@ -48,29 +223,252 @@ struct SceneView
|
|||
matrix prevViewProjMatrix;
|
||||
matrix prevViewMatrix;
|
||||
matrix prevProjectionMatrix;
|
||||
float3x3 zToSunMatrix;
|
||||
float3x3 sunToZMatrix;
|
||||
float4 clipPlane;
|
||||
float4 debug;
|
||||
float3 cameraPosition;
|
||||
float sunIntensity;
|
||||
float3 sunDirection;
|
||||
float zNear;
|
||||
float3 sunColor;
|
||||
float zFar;
|
||||
float3 prevCameraPosition;
|
||||
float prevZNear;
|
||||
float3 cameraForward;
|
||||
float prevZFar;
|
||||
float3 cameraLeft;
|
||||
float padding0;
|
||||
float3 cameraUp;
|
||||
float padding1;
|
||||
float3 linearDepthConstants;
|
||||
float frameSeed;
|
||||
float3 ambientColor;
|
||||
float ambientIntensity;
|
||||
float4 extinctionWorldScale;
|
||||
uint4 extinctionTextureIndices;
|
||||
float4 sunVShadowWorldScale;
|
||||
uint4 sunVShadowTextureIndices;
|
||||
uint sceneViewIndex;
|
||||
uint frameIndex;
|
||||
uint depthTextureIndex;
|
||||
uint depthMinMaxTextureIndex;
|
||||
uint normalTextureIndex;
|
||||
uint shadingPositionTextureIndex;
|
||||
uint motionVectorTextureIndex;
|
||||
uint motionVectorMBTextureIndex;
|
||||
uint lightTextureIndex;
|
||||
uint sunlightTextureIndex;
|
||||
uint tlasBufferIndex;
|
||||
uint tlasInstanceBufferIndex;
|
||||
uint lightCount;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float zNear;
|
||||
float zFar;
|
||||
DynamicLight lights[SCENE_VIEW_MAX_LIGHTS];
|
||||
uint linearClampSamplerIndex;
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
float LinearDepth(float zwDepth)
|
||||
{
|
||||
return linearDepthB / (zwDepth - linearDepthA);
|
||||
return ::LinearDepth(zwDepth, linearDepthConstants);
|
||||
}
|
||||
|
||||
float3 CamerayRay(float2 ndc)
|
||||
{
|
||||
float4 pointNDC = float4(ndc, 0.5, 1);
|
||||
float4 pointWSw = mul(invViewMatrix, mul(invProjectionMatrix, pointNDC));
|
||||
float3 pointWS = pointWSw.xyz / pointWSw.w;
|
||||
float3 dir = pointWS - cameraPosition;
|
||||
float3 ray = normalize(dir);
|
||||
|
||||
return ray;
|
||||
}
|
||||
|
||||
#if 1 // exponential depth distribution like The Last of Us Part II
|
||||
|
||||
float TLOU2SliceToViewDepth(float slice, float C)
|
||||
{
|
||||
const float Q = 1.0;
|
||||
float viewDepth = exp2((slice + Q * C) / C) - exp2(Q);
|
||||
|
||||
return viewDepth;
|
||||
}
|
||||
|
||||
float TLOU2ViewDepthToSlice(float viewDepth, float C)
|
||||
{
|
||||
const float Q = 1.0;
|
||||
float slice = C * (log2(exp2(Q) + viewDepth) - Q);
|
||||
|
||||
return slice;
|
||||
}
|
||||
|
||||
float TLOU2CFromSliceAndViewDepth(float slice, float viewDepth)
|
||||
{
|
||||
const float Q = 1.0;
|
||||
float C = slice / (log2(viewDepth + exp2(Q)) - Q);
|
||||
|
||||
return C;
|
||||
}
|
||||
|
||||
float FroxelViewDepthToZ01Ex(float viewDepth, float sliceCount, float zn, float zf)
|
||||
{
|
||||
float depthRange = zf - zn;
|
||||
float C = TLOU2CFromSliceAndViewDepth(sliceCount - 1.0, depthRange);
|
||||
float slice = TLOU2ViewDepthToSlice(viewDepth - zn, C);
|
||||
float depth01 = slice / sliceCount;
|
||||
|
||||
return depth01;
|
||||
}
|
||||
|
||||
float FroxelZ01ToViewDepth(float depth01, float sliceCount)
|
||||
{
|
||||
float depthRange = zFar - zNear;
|
||||
float C = TLOU2CFromSliceAndViewDepth(sliceCount - 1.0, depthRange);
|
||||
float slice = depth01 * sliceCount;
|
||||
float viewDepth = zNear + TLOU2SliceToViewDepth(slice, C);
|
||||
|
||||
return viewDepth;
|
||||
}
|
||||
|
||||
#else // linear depth distribution
|
||||
|
||||
float FroxelViewDepthToZ01Ex(float viewDepth, float sliceCount, float zn, float zf)
|
||||
{
|
||||
float depth01 = (viewDepth - zn) / (zf - zn);
|
||||
|
||||
return depth01;
|
||||
}
|
||||
|
||||
float FroxelZ01ToViewDepth(float depth01, float sliceCount)
|
||||
{
|
||||
float viewDepth = zNear + (zFar - zNear) * depth01;
|
||||
|
||||
return viewDepth;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
float FroxelViewDepthToZ01(float viewDepth, float sliceCount)
|
||||
{
|
||||
float depth01 = FroxelViewDepthToZ01Ex(viewDepth, sliceCount, zNear, zFar);
|
||||
|
||||
return depth01;
|
||||
}
|
||||
|
||||
float FroxelViewDepthToZ01PrevFrame(float viewDepth, float sliceCount)
|
||||
{
|
||||
float depth01 = FroxelViewDepthToZ01Ex(viewDepth, sliceCount, prevZNear, prevZFar);
|
||||
|
||||
return depth01;
|
||||
}
|
||||
|
||||
float3 FroxelTCToWorldSpace(float3 tc, float3 textureSize)
|
||||
{
|
||||
float pointDepth = FroxelZ01ToViewDepth(tc.z, textureSize.z);
|
||||
float2 xyNDC = TCToNDC(tc.xy);
|
||||
float zNDC = PostProjectionDepth(pointDepth, zNear, zFar);
|
||||
float4 pointNDC = float4(xyNDC, zNDC, 1);
|
||||
float4 pointWSw = mul(invViewMatrix, mul(invProjectionMatrix, pointNDC));
|
||||
float3 pointWS = pointWSw.xyz / pointWSw.w;
|
||||
|
||||
return pointWS;
|
||||
}
|
||||
|
||||
float3 FroxelIndexToWorldSpace(int3 index, float3 textureSize)
|
||||
{
|
||||
float3 tc = (float3(index) + float3(0.5, 0.5, 0.5)) / textureSize;
|
||||
float3 pointWS = FroxelTCToWorldSpace(tc, textureSize);
|
||||
|
||||
return pointWS;
|
||||
}
|
||||
|
||||
float3 FroxelWorldSpaceToTC(float3 positionWS, float3 textureSize)
|
||||
{
|
||||
float4 positionVSw = mul(viewMatrix, float4(positionWS, 1));
|
||||
float viewDepth = -positionVSw.z / positionVSw.w;
|
||||
float z01 = FroxelViewDepthToZ01(viewDepth, textureSize.z);
|
||||
float4 positionCSw = mul(projectionMatrix, positionVSw);
|
||||
float2 xy01 = NDCToTC(positionCSw.xy / positionCSw.w);
|
||||
float3 tc = float3(xy01, z01);
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
int3 FroxelWorldSpaceToIndex(float3 positionWS, float3 textureSize)
|
||||
{
|
||||
float3 tc = FroxelWorldSpaceToTC(positionWS, textureSize);
|
||||
int3 index = int3(tc * textureSize);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// @TODO: validate new logic
|
||||
float3 FroxelReproject01(int3 currIndex, float3 textureSize)
|
||||
{
|
||||
float3 currTC = (float3(currIndex) + float3(0.5, 0.5, 0.5)) / textureSize;
|
||||
float currDepth = FroxelZ01ToViewDepth(currTC.z, textureSize.z);
|
||||
float2 xyNDC = TCToNDC(currTC.xy);
|
||||
float zNDC = PostProjectionDepth(currDepth, zNear, zFar);
|
||||
float4 currNDC = float4(xyNDC, zNDC, 1);
|
||||
float4 positionWSw = mul(invViewMatrix, mul(invProjectionMatrix, currNDC));
|
||||
float3 positionWS = positionWSw.xyz / positionWSw.w;
|
||||
float4 prevVSw = mul(prevViewMatrix, float4(positionWS, 1));
|
||||
float prevDepth = -prevVSw.z / prevVSw.w;
|
||||
float z01 = FroxelViewDepthToZ01(prevDepth, textureSize.z);
|
||||
float4 prevCSw = mul(prevProjectionMatrix, prevVSw);
|
||||
float2 xy01 = NDCToTC(prevCSw.xy / prevCSw.w);
|
||||
float3 prevTC = float3(xy01, z01);
|
||||
|
||||
return prevTC;
|
||||
}
|
||||
|
||||
float3 ExtinctionIndexToWorldSpace(int3 index, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxIndexToWorldSpace(index, cameraPosition, textureSize, worldScale);
|
||||
}
|
||||
|
||||
float3 ExtinctionTCToWorldSpace(float3 tc, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxTCToWorldSpace(tc, cameraPosition, textureSize, worldScale);
|
||||
}
|
||||
|
||||
float3 ExtinctionWorldSpaceToTC(float3 position, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxWorldSpaceToTC(position, cameraPosition, textureSize, worldScale);
|
||||
}
|
||||
|
||||
int3 ExtinctionWorldSpaceToIndex(float3 position, float3 textureSize, float worldScale)
|
||||
{
|
||||
return AABoxWorldSpaceToIndex(position, cameraPosition, textureSize, worldScale);
|
||||
}
|
||||
|
||||
ExtinctionCascade GetExtinctionCascade(float voxelSize)
|
||||
{
|
||||
ExtinctionCascade cascade;
|
||||
cascade.textures[0] = ResourceDescriptorHeap[extinctionTextureIndices.x];
|
||||
cascade.textures[1] = ResourceDescriptorHeap[extinctionTextureIndices.y];
|
||||
cascade.textures[2] = ResourceDescriptorHeap[extinctionTextureIndices.z];
|
||||
cascade.textures[3] = ResourceDescriptorHeap[extinctionTextureIndices.w];
|
||||
cascade.linearClampSampler = SamplerDescriptorHeap[linearClampSamplerIndex];
|
||||
cascade.worldScale = extinctionWorldScale;
|
||||
cascade.cameraPosition = cameraPosition;
|
||||
cascade.textureSize = GetTextureSize(cascade.textures[0]);
|
||||
cascade.SetSamplingVolume(voxelSize);
|
||||
|
||||
return cascade;
|
||||
}
|
||||
|
||||
SunVShadowCascade GetSunVShadowCascade(float voxelSize)
|
||||
{
|
||||
SunVShadowCascade cascade;
|
||||
cascade.textures[0] = ResourceDescriptorHeap[sunVShadowTextureIndices.x];
|
||||
cascade.textures[1] = ResourceDescriptorHeap[sunVShadowTextureIndices.y];
|
||||
cascade.textures[2] = ResourceDescriptorHeap[sunVShadowTextureIndices.z];
|
||||
cascade.textures[3] = ResourceDescriptorHeap[sunVShadowTextureIndices.w];
|
||||
cascade.linearClampSampler = SamplerDescriptorHeap[linearClampSamplerIndex];
|
||||
cascade.worldScale = sunVShadowWorldScale;
|
||||
cascade.cameraPosition = cameraPosition;
|
||||
cascade.textureSize = GetTextureSize(cascade.textures[0]);
|
||||
cascade.zToSunMatrix = zToSunMatrix;
|
||||
cascade.SetSamplingVolume(voxelSize);
|
||||
|
||||
return cascade;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
|
146
code/renderer/shaders/crp/simplex_noise.hlsli
Normal file
146
code/renderer/shaders/crp/simplex_noise.hlsli
Normal file
|
@ -0,0 +1,146 @@
|
|||
// --------------------------------------------------------------------
|
||||
// Optimized implementation of simplex noise.
|
||||
// Based on stegu's simplex noise: https://github.com/stegu/webgl-noise.
|
||||
// Contact : atyuwen@gmail.com
|
||||
// Author : Yuwen Wu (https://atyuwen.github.io/)
|
||||
// License : Distributed under the MIT License.
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Permuted congruential generator (only top 16 bits are well shuffled).
|
||||
// References: 1. Mark Jarzynski and Marc Olano, "Hash Functions for GPU Rendering".
|
||||
// 2. UnrealEngine/Random.ush. https://github.com/EpicGames/UnrealEngine
|
||||
uint pcg3d16(uint3 p)
|
||||
{
|
||||
uint3 v = p * 1664525u + 1013904223u;
|
||||
v.x += v.y*v.z; v.y += v.z*v.x; v.z += v.x*v.y;
|
||||
v.x += v.y*v.z;
|
||||
return v.x;
|
||||
}
|
||||
uint pcg4d16(uint4 p)
|
||||
{
|
||||
uint4 v = p * 1664525u + 1013904223u;
|
||||
v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;
|
||||
v.x += v.y*v.w;
|
||||
return v.x;
|
||||
}
|
||||
|
||||
// Get random gradient from hash value.
|
||||
float3 gradient3d(uint hash)
|
||||
{
|
||||
float3 g = float3(hash.xxx & uint3(0x80000, 0x40000, 0x20000));
|
||||
return g * float3(1.0 / 0x40000, 1.0 / 0x20000, 1.0 / 0x10000) - 1.0;
|
||||
}
|
||||
float4 gradient4d(uint hash)
|
||||
{
|
||||
float4 g = float4(hash.xxxx & uint4(0x80000, 0x40000, 0x20000, 0x10000));
|
||||
return g * float4(1.0 / 0x40000, 1.0 / 0x20000, 1.0 / 0x10000, 1.0 / 0x8000) - 1.0;
|
||||
}
|
||||
|
||||
// 3D Simplex Noise. Approximately 71 instruction slots used.
|
||||
// Assume p is in the range [-32768, 32767].
|
||||
float SimplexNoise3D(float3 p)
|
||||
{
|
||||
const float2 C = float2(1.0 / 6.0, 1.0 / 3.0);
|
||||
const float4 D = float4(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
// First corner
|
||||
float3 i = floor(p + dot(p, C.yyy));
|
||||
float3 x0 = p - i + dot(i, C.xxx);
|
||||
|
||||
// Other corners
|
||||
float3 g = step(x0.yzx, x0.xyz);
|
||||
float3 l = 1.0 - g;
|
||||
float3 i1 = min(g.xyz, l.zxy);
|
||||
float3 i2 = max(g.xyz, l.zxy);
|
||||
|
||||
// x0 = x0 - 0.0 + 0.0 * C.xxx;
|
||||
// x1 = x0 - i1 + 1.0 * C.xxx;
|
||||
// x2 = x0 - i2 + 2.0 * C.xxx;
|
||||
// x3 = x0 - 1.0 + 3.0 * C.xxx;
|
||||
float3 x1 = x0 - i1 + C.xxx;
|
||||
float3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||
float3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||
|
||||
i = i + 32768.5;
|
||||
uint hash0 = pcg3d16((uint3)i);
|
||||
uint hash1 = pcg3d16((uint3)(i + i1));
|
||||
uint hash2 = pcg3d16((uint3)(i + i2));
|
||||
uint hash3 = pcg3d16((uint3)(i + 1 ));
|
||||
|
||||
float3 p0 = gradient3d(hash0);
|
||||
float3 p1 = gradient3d(hash1);
|
||||
float3 p2 = gradient3d(hash2);
|
||||
float3 p3 = gradient3d(hash3);
|
||||
|
||||
// Mix final noise value.
|
||||
float4 m = saturate(0.5 - float4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)));
|
||||
float4 mt = m * m;
|
||||
float4 m4 = mt * mt;
|
||||
return 62.6 * dot(m4, float4(dot(x0, p0), dot(x1, p1), dot(x2, p2), dot(x3, p3)));
|
||||
}
|
||||
|
||||
// 4D Simplex Noise. Approximately 113 instruction slots used.
|
||||
// Assume p is in the range [-32768, 32767].
|
||||
float SimplexNoise4D(float4 p)
|
||||
{
|
||||
const float4 F4 = 0.309016994374947451;
|
||||
const float4 C = float4( 0.138196601125011, // (5 - sqrt(5))/20 G4
|
||||
0.276393202250021, // 2 * G4
|
||||
0.414589803375032, // 3 * G4
|
||||
-0.447213595499958); // -1 + 4 * G4
|
||||
|
||||
// First corner
|
||||
float4 i = floor(p + dot(p, F4) );
|
||||
float4 x0 = p - i + dot(i, C.xxxx);
|
||||
|
||||
// Other corners
|
||||
|
||||
// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
|
||||
float4 i0;
|
||||
float3 isX = step( x0.yzw, x0.xxx );
|
||||
float3 isYZ = step( x0.zww, x0.yyz );
|
||||
// i0.x = dot( isX, float3( 1.0 ) );
|
||||
i0.x = isX.x + isX.y + isX.z;
|
||||
i0.yzw = 1.0 - isX;
|
||||
// i0.y += dot( isYZ.xy, float2( 1.0 ) );
|
||||
i0.y += isYZ.x + isYZ.y;
|
||||
i0.zw += 1.0 - isYZ.xy;
|
||||
i0.z += isYZ.z;
|
||||
i0.w += 1.0 - isYZ.z;
|
||||
|
||||
// i0 now contains the unique values 0,1,2,3 in each channel
|
||||
float4 i3 = saturate( i0 );
|
||||
float4 i2 = saturate( i0 - 1.0 );
|
||||
float4 i1 = saturate( i0 - 2.0 );
|
||||
|
||||
// x0 = x0 - 0.0 + 0.0 * C.xxxx
|
||||
// x1 = x0 - i1 + 1.0 * C.xxxx
|
||||
// x2 = x0 - i2 + 2.0 * C.xxxx
|
||||
// x3 = x0 - i3 + 3.0 * C.xxxx
|
||||
// x4 = x0 - 1.0 + 4.0 * C.xxxx
|
||||
float4 x1 = x0 - i1 + C.xxxx;
|
||||
float4 x2 = x0 - i2 + C.yyyy;
|
||||
float4 x3 = x0 - i3 + C.zzzz;
|
||||
float4 x4 = x0 + C.wwww;
|
||||
|
||||
i = i + 32768.5;
|
||||
uint hash0 = pcg4d16((uint4)i);
|
||||
uint hash1 = pcg4d16((uint4)(i + i1));
|
||||
uint hash2 = pcg4d16((uint4)(i + i2));
|
||||
uint hash3 = pcg4d16((uint4)(i + i3));
|
||||
uint hash4 = pcg4d16((uint4)(i + 1 ));
|
||||
|
||||
float4 p0 = gradient4d(hash0);
|
||||
float4 p1 = gradient4d(hash1);
|
||||
float4 p2 = gradient4d(hash2);
|
||||
float4 p3 = gradient4d(hash3);
|
||||
float4 p4 = gradient4d(hash4);
|
||||
|
||||
// Mix contributions from the five corners
|
||||
float3 m0 = saturate(0.6 - float3(dot(x0,x0), dot(x1,x1), dot(x2,x2)));
|
||||
float2 m1 = saturate(0.6 - float2(dot(x3,x3), dot(x4,x4) ));
|
||||
float3 m03 = m0 * m0 * m0;
|
||||
float2 m13 = m1 * m1 * m1;
|
||||
return (dot(m03, float3(dot(p0, x0), dot(p1, x1), dot(p2, x2)))
|
||||
+ dot(m13, float2(dot(p3, x3), dot(p4, x4)))) * 9.0;
|
||||
}
|
118
code/renderer/shaders/crp/sun_blur.hlsl
Normal file
118
code/renderer/shaders/crp/sun_blur.hlsl
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// sunlight soft shadows
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint visibilityTextureIndex;
|
||||
uint penumbraTextureIndex;
|
||||
};
|
||||
|
||||
static const int Radius = 7;
|
||||
static const float PenumbraRadiusWS = 64.0;
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
Texture2D shadingPositionTexture = ResourceDescriptorHeap[scene.shadingPositionTextureIndex];
|
||||
Texture2D<float2> normalTexture = ResourceDescriptorHeap[scene.normalTextureIndex];
|
||||
Texture2D<float> visibilityTexture = ResourceDescriptorHeap[visibilityTextureIndex];
|
||||
Texture2D<float> penumbraTexture = ResourceDescriptorHeap[penumbraTextureIndex];
|
||||
SunVShadowCascade cascade = scene.GetSunVShadowCascade(scene.sunVShadowWorldScale.x);
|
||||
|
||||
int2 fragTC = int2(input.position.xy);
|
||||
uint3 tc = uint3(input.position.xy, 0);
|
||||
float3 positionWS = shadingPositionTexture.Load(tc).xyz;
|
||||
float3 normalWS = normalize(OctDecode(normalTexture.Load(tc)));
|
||||
float penumbraSize = penumbraTexture.Load(tc) * PenumbraRadiusWS;
|
||||
int2 textureSize = int2(GetTextureSize(visibilityTexture));
|
||||
|
||||
// run a PCSS-style blocker search
|
||||
if(penumbraSize == 0.0)
|
||||
{
|
||||
float count = 0.0;
|
||||
for(int y = -Radius; y <= Radius; y++)
|
||||
{
|
||||
for(int x = -Radius; x <= Radius; x++)
|
||||
{
|
||||
int2 TCs2 = fragTC + int2(x, y);
|
||||
if(!IsInTexture(TCs2, textureSize))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint3 TCs = uint3(TCs2, 0);
|
||||
float size = penumbraTexture.Load(TCs) * PenumbraRadiusWS;
|
||||
penumbraSize += size;
|
||||
count += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if(count > 0.0)
|
||||
{
|
||||
penumbraSize /= count;
|
||||
}
|
||||
}
|
||||
if(penumbraSize == 0.0)
|
||||
{
|
||||
penumbraSize = PenumbraRadiusWS;
|
||||
}
|
||||
|
||||
float visSum = 0.0;
|
||||
float weightSum = 0.0;
|
||||
for(int y = -Radius; y <= Radius; y++)
|
||||
{
|
||||
for(int x = -Radius; x <= Radius; x++)
|
||||
{
|
||||
int2 TCs2 = fragTC + int2(x, y);
|
||||
if(!IsInTexture(TCs2, textureSize))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint3 TCs = uint3(TCs2, 0);
|
||||
float Vs = visibilityTexture.Load(TCs);
|
||||
float3 Ns = normalize(OctDecode(normalTexture.Load(TCs)));
|
||||
float3 Ps = shadingPositionTexture.Load(TCs).xyz;
|
||||
float normalWeight = max(dot(normalWS, Ns), 0.0);
|
||||
float distanceWeight = max(1.0 - distance(positionWS, Ps) / penumbraSize, 0.0);
|
||||
float weight = normalWeight * distanceWeight;
|
||||
weightSum += weight;
|
||||
visSum += weight * Vs;
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: all light intensities are 50x for light scattering?
|
||||
float visOpaque = weightSum > 0.0 ? visSum / weightSum : 0.0;
|
||||
float visVolume = cascade.TransmittanceAt(positionWS);
|
||||
float vis = visOpaque * visVolume;
|
||||
float lambert = max(dot(normalWS, scene.sunDirection), 0.0);
|
||||
float3 color = vis * scene.sunColor * min(scene.sunIntensity / 10.0, 5.0) * lambert;
|
||||
float4 result = float4(color, 1);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -18,22 +18,44 @@ You should have received a copy of the GNU General Public License
|
|||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// fog volume (AABB) seen from inside
|
||||
// draws the sun's position
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fog.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 direction;
|
||||
float angle; // @TODO:
|
||||
float3 color;
|
||||
float padding;
|
||||
float2 textureSize;
|
||||
};
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
float depthZW = depthTexture.Load(int3(input.position.xy, 0));
|
||||
float depthBuff = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depthFrag = input.depthVS;
|
||||
float depthMin = min(depthBuff, depthFrag);
|
||||
float fogOpacity = saturate(depthMin / depth);
|
||||
float4 result = float4(color.rgb, fogOpacity);
|
||||
SceneView scene = GetSceneView();
|
||||
float3 positionWS = scene.cameraPosition + scene.zFar * direction;
|
||||
float4 positionCS = mul(scene.projectionMatrix, mul(scene.viewMatrix, float4(positionWS, 1)));
|
||||
float3 positionNDC = positionCS.xyz / positionCS.w;
|
||||
if(positionNDC.z < 0.0)
|
||||
{
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
float2 positionPx = NDCToTC(positionNDC.xy) * textureSize;
|
||||
float2 fragmentPx = input.texCoords * textureSize;
|
||||
if(distance(positionPx, fragmentPx) < 12.0)
|
||||
{
|
||||
return float4(saturate(color), 1);
|
||||
}
|
||||
if(distance(positionPx, fragmentPx) < 14.0)
|
||||
{
|
||||
return float4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
67
code/renderer/shaders/crp/sun_visibility.hlsl
Normal file
67
code/renderer/shaders/crp/sun_visibility.hlsl
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// sunlight visibility and penumbra size
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#include "raytracing.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
};
|
||||
|
||||
static const float PenumbraRadiusWS = 64.0;
|
||||
|
||||
struct POut
|
||||
{
|
||||
float visible : SV_Target0;
|
||||
float penumbra : SV_Target1;
|
||||
};
|
||||
|
||||
POut ps(VOut input)
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
RTAS rtas = ResourceDescriptorHeap[scene.tlasBufferIndex];
|
||||
Texture2D shadingPositionTexture = ResourceDescriptorHeap[scene.shadingPositionTextureIndex];
|
||||
StructuredBuffer<TLASInstance> tlasInstanceBuffer = ResourceDescriptorHeap[scene.tlasInstanceBufferIndex];
|
||||
|
||||
uint3 tc = uint3(input.position.xy, 0);
|
||||
float3 positionWS = shadingPositionTexture.Load(tc).xyz;
|
||||
float t;
|
||||
float vis = TraceVisibilityWithATt(t, rtas, tlasInstanceBuffer, positionWS, scene.sunDirection, 10000.0);
|
||||
|
||||
POut output;
|
||||
if(vis == 0.0) // in shadow
|
||||
{
|
||||
output.visible = 0.0;
|
||||
output.penumbra = saturate((t * 0.01) / PenumbraRadiusWS);
|
||||
}
|
||||
else
|
||||
{
|
||||
output.visible = 1.0;
|
||||
output.penumbra = 0.0;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
|
@ -43,7 +43,7 @@ cbuffer RootConstants
|
|||
uint stateBits;
|
||||
uint shaderTrace;
|
||||
uint depthFadeDistOffset; // offset: fp16 - distance: fp16
|
||||
uint depthFadeScaleBias; // enable: 1 - color bias: 4 - color scale: 4
|
||||
uint depthFadeScaleBiasPO; // polygon offset: 1 - enable: 1 - color bias: 4 - color scale: 4
|
||||
};
|
||||
|
||||
struct VIn
|
||||
|
@ -83,6 +83,29 @@ VOut vs(VIn input)
|
|||
return output;
|
||||
}
|
||||
|
||||
bool IsFragmentUseless(uint blendBits, float4 color)
|
||||
{
|
||||
const float epsilon = 1.0 / 255.0;
|
||||
|
||||
if(blendBits == GLS_BLEND_ADDITIVE &&
|
||||
all(color.rgb < epsilon.xxx))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if((blendBits == GLS_BLEND_STD_ALPHA || blendBits == GLS_BLEND_PMUL_ALPHA) &&
|
||||
color.a < epsilon)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if((blendBits == GLS_BLEND_FILTER || blendBits == GLS_BLEND_FILTER_V2) &&
|
||||
all(color.rgb > (1.0 - epsilon).xxx) && all(color.rgb < (1.0 + epsilon).xxx))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[earlydepthstencil]
|
||||
void ps(VOut input)
|
||||
{
|
||||
|
@ -95,6 +118,11 @@ void ps(VOut input)
|
|||
}
|
||||
|
||||
dst = MakeGreyscale(dst, greyscale);
|
||||
uint blendBits = stateBits & GLS_BLEND_BITS;
|
||||
if(IsFragmentUseless(blendBits, dst))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWStructuredBuffer<OIT_Counter> counter = ResourceDescriptorHeap[counterBuffer];
|
||||
uint fragmentIndex;
|
||||
|
@ -112,7 +140,7 @@ void ps(VOut input)
|
|||
fragment.next = prevFragmentIndex;
|
||||
fragment.shaderTrace = shaderTrace;
|
||||
fragment.depthFadeDistOffset = depthFadeDistOffset;
|
||||
fragment.depthFadeScaleBias = depthFadeScaleBias;
|
||||
fragment.depthFadeScaleBiasPO = depthFadeScaleBiasPO;
|
||||
fragments[fragmentIndex] = fragment;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 Gian 'myT' Schellenbaum
|
||||
Copyright (C) 2023-2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
|
@ -22,23 +22,23 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "oit.h.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "oit.h.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#include "../common/state_bits.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float2 scissorRectMin;
|
||||
float2 scissorRectMax;
|
||||
uint renderTargetTexture;
|
||||
uint shaderIndexBuffer;
|
||||
uint indexTexture;
|
||||
uint fragmentBuffer;
|
||||
uint centerPixel; // y: 16 - x: 16
|
||||
uint depthTexture;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float2 scissorRectMin;
|
||||
float2 scissorRectMax;
|
||||
uint scatterTextureIndex;
|
||||
uint scatterSamplerIndex;
|
||||
};
|
||||
|
||||
uint GetShaderStage(uint stateBits)
|
||||
|
@ -76,20 +76,19 @@ float GetBitAsFloat(uint bits, uint bitIndex)
|
|||
return (bits & (1u << bitIndex)) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
float4 DepthFadeFragmentColor(float4 color, OIT_Fragment fragment, float storedDepthZW)
|
||||
float4 DepthFadeFragmentColor(float4 color, OIT_Fragment fragment, float opaqueViewDepth)
|
||||
{
|
||||
if(((fragment.depthFadeScaleBias >> 8) & 1) == 0)
|
||||
if(((fragment.depthFadeScaleBiasPO >> 8) & 1) == 0)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
#define BIT(Index) GetBitAsFloat(fragment.depthFadeScaleBias, Index)
|
||||
#define BIT(Index) GetBitAsFloat(fragment.depthFadeScaleBiasPO, Index)
|
||||
float4 dst = color;
|
||||
float2 distOffset = UnpackHalf2(fragment.depthFadeDistOffset);
|
||||
float4 fadeColorScale = float4(BIT(0), BIT(1), BIT(2), BIT(3));
|
||||
float4 fadeColorBias = float4(BIT(4), BIT(5), BIT(6), BIT(7));
|
||||
float zwDepth = storedDepthZW; // stored depth, z/w
|
||||
float depthS = LinearDepth(zwDepth, linearDepthA, linearDepthB); // stored depth, linear
|
||||
float depthS = opaqueViewDepth; // stored depth, linear
|
||||
float depthP = fragment.depth - distOffset.y; // fragment depth, linear
|
||||
float fadeScale = Contrast((depthS - depthP) * distOffset.x, 2.0);
|
||||
dst = lerp(dst * fadeColorScale + fadeColorBias, dst, fadeScale);
|
||||
|
@ -98,96 +97,253 @@ float4 DepthFadeFragmentColor(float4 color, OIT_Fragment fragment, float storedD
|
|||
return dst;
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
float FragmentImpact(float4 fragColor, uint blendBits)
|
||||
{
|
||||
Texture2D renderTarget = ResourceDescriptorHeap[renderTargetTexture];
|
||||
int2 tc = int2(input.position.x, input.position.y);
|
||||
float4 color = renderTarget.Load(int3(tc.x, tc.y, 0));
|
||||
if(any(input.position.xy < scissorRectMin) ||
|
||||
any(input.position.xy > scissorRectMax))
|
||||
if(blendBits == GLS_BLEND_ADDITIVE)
|
||||
{
|
||||
return color;
|
||||
return Brightness(fragColor.rgb);
|
||||
}
|
||||
|
||||
RWTexture2D<uint> index = ResourceDescriptorHeap[indexTexture];
|
||||
RWStructuredBuffer<OIT_Fragment> fragments = ResourceDescriptorHeap[fragmentBuffer];
|
||||
Texture2D depthTex = ResourceDescriptorHeap[depthTexture];
|
||||
uint fragmentIndex = index[tc];
|
||||
uint i;
|
||||
OIT_Fragment sorted[OIT_MAX_FRAGMENTS_PER_PIXEL];
|
||||
uint fragmentCount = 0;
|
||||
|
||||
// grab this pixel's fragments
|
||||
while(fragmentIndex != 0 && fragmentCount < OIT_MAX_FRAGMENTS_PER_PIXEL)
|
||||
if(blendBits == GLS_BLEND_STD_ALPHA || blendBits == GLS_BLEND_PMUL_ALPHA)
|
||||
{
|
||||
sorted[fragmentCount] = fragments[fragmentIndex];
|
||||
fragmentIndex = sorted[fragmentCount].next;
|
||||
++fragmentCount;
|
||||
return fragColor.a;
|
||||
}
|
||||
|
||||
// sort the fragments using an insertion sort
|
||||
for(i = 1; i < fragmentCount; ++i)
|
||||
if(blendBits == GLS_BLEND_FILTER || blendBits == GLS_BLEND_FILTER_V2)
|
||||
{
|
||||
OIT_Fragment insert = sorted[i];
|
||||
uint stage = GetShaderStage(insert.stateBits);
|
||||
uint j = i;
|
||||
while(j > 0 && IsBehind(insert.depth, sorted[j - 1].depth, stage, GetShaderStage(sorted[j - 1].stateBits)))
|
||||
{
|
||||
sorted[j] = sorted[j - 1];
|
||||
--j;
|
||||
}
|
||||
sorted[j] = insert;
|
||||
return abs(1.0 - Brightness(fragColor.rgb));
|
||||
}
|
||||
|
||||
// blend the results
|
||||
int lastFragmentIndex = -1;
|
||||
float storedDepthZW = depthTex.Load(int3(input.position.xy, 0)).x; // stored depth, z/w
|
||||
float dstDepth = 1.0;
|
||||
for(i = 0; i < fragmentCount; ++i)
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
struct OIT_Resolve
|
||||
{
|
||||
bool InitScissorRect(VOut input)
|
||||
{
|
||||
OIT_Fragment frag = sorted[i];
|
||||
uint stateBits = frag.stateBits;
|
||||
float fragDepth = frag.depth;
|
||||
if((stateBits & (GLS_DEPTHFUNC_EQUAL | GLS_DEPTHTEST_DISABLE)) == GLS_DEPTHFUNC_EQUAL &&
|
||||
fragDepth != dstDepth)
|
||||
renderTarget = ResourceDescriptorHeap[renderTargetTexture];
|
||||
tcPx = int3(input.position.xy, 0);
|
||||
opaqueColor = renderTarget.Load(tcPx);
|
||||
if(any(input.position.xy < scissorRectMin) ||
|
||||
any(input.position.xy > scissorRectMax))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float4 fragColor = UnpackColor(frag.color);
|
||||
float4 prevColor = color;
|
||||
fragColor = DepthFadeFragmentColor(fragColor, frag, storedDepthZW);
|
||||
color = Blend(fragColor, color, frag.stateBits);
|
||||
if((stateBits & GLS_DEPTHMASK_TRUE) != 0u &&
|
||||
fragDepth < dstDepth)
|
||||
{
|
||||
dstDepth = fragDepth;
|
||||
}
|
||||
|
||||
// we have to not include the alpha channel in this test for it to be correct
|
||||
if(any(color.rgb != prevColor.rgb))
|
||||
{
|
||||
lastFragmentIndex = (int)i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// write out the fragment shader ID of the closest visible fragment of the center pixel
|
||||
if(lastFragmentIndex >= 0)
|
||||
void Init(VOut input)
|
||||
{
|
||||
OIT_Fragment closest = sorted[lastFragmentIndex];
|
||||
uint shaderTrace = closest.shaderTrace;
|
||||
if(shaderTrace & 1)
|
||||
scene = GetSceneView();
|
||||
#if defined(VOLUMETRIC_LIGHT)
|
||||
scatterTexture = ResourceDescriptorHeap[scatterTextureIndex];
|
||||
scatterSampler = SamplerDescriptorHeap[scatterSamplerIndex];
|
||||
#endif
|
||||
|
||||
RWTexture2D<uint> index = ResourceDescriptorHeap[indexTexture];
|
||||
RWStructuredBuffer<OIT_Fragment> fragments = ResourceDescriptorHeap[fragmentBuffer];
|
||||
Texture2D depthTex = ResourceDescriptorHeap[scene.depthTextureIndex];
|
||||
uint fragmentIndex = index[tcPx.xy];
|
||||
fragmentCount = 0;
|
||||
float storedDepthZW = depthTex.Load(tcPx).x; // stored depth, z/w
|
||||
opaqueViewDepth = scene.LinearDepth(storedDepthZW);
|
||||
|
||||
// grab this pixel's fragments
|
||||
while(fragmentIndex != 0 && fragmentCount < OIT_MAX_FRAGMENTS_PER_PIXEL)
|
||||
{
|
||||
uint2 fragmentCoords = uint2(input.position.xy);
|
||||
uint2 centerCoords = uint2(centerPixel & 0xFFFF, centerPixel >> 16);
|
||||
if(all(fragmentCoords == centerCoords))
|
||||
sorted[fragmentCount] = fragments[fragmentIndex];
|
||||
fragmentIndex = sorted[fragmentCount].next;
|
||||
invisible[fragmentCount] = false;
|
||||
++fragmentCount;
|
||||
}
|
||||
|
||||
// sort the fragments using an insertion sort
|
||||
for(uint i = 1; i < fragmentCount; ++i)
|
||||
{
|
||||
OIT_Fragment insert = sorted[i];
|
||||
uint stage = GetShaderStage(insert.stateBits);
|
||||
uint j = i;
|
||||
while(j > 0 && IsBehind(insert.depth, sorted[j - 1].depth, stage, GetShaderStage(sorted[j - 1].stateBits)))
|
||||
{
|
||||
RWByteAddressBuffer shaderIdBuf = ResourceDescriptorHeap[shaderIndexBuffer];
|
||||
uint shaderIndex = shaderTrace >> 1;
|
||||
shaderIdBuf.Store(0, shaderIndex);
|
||||
sorted[j] = sorted[j - 1];
|
||||
--j;
|
||||
}
|
||||
sorted[j] = insert;
|
||||
}
|
||||
}
|
||||
|
||||
void Resolve(VOut input, float impactThreshold)
|
||||
{
|
||||
color = opaqueColor;
|
||||
smallestImpact = 666.0;
|
||||
|
||||
#if defined(VOLUMETRIC_LIGHT)
|
||||
// initialize volume traversal
|
||||
float3 volumeSize = GetTextureSize(scatterTexture);
|
||||
float opaqueFroxelDepth01 = scene.FroxelViewDepthToZ01(opaqueViewDepth, volumeSize.z);
|
||||
// @TODO: do the depth bias only when global fog is enabled or a CVar is set
|
||||
opaqueFroxelDepth01 = max(opaqueFroxelDepth01 - 1.0 / volumeSize.z, 0.0);
|
||||
float3 scatterTC = float3(input.texCoords, opaqueFroxelDepth01);
|
||||
float4 scatterData = scatterTexture.SampleLevel(scatterSampler, scatterTC, 0);
|
||||
{
|
||||
float4 closerScatterData = float4(0, 0, 0, 1);
|
||||
for(uint i = 0; i < fragmentCount; ++i)
|
||||
{
|
||||
// @TODO: fix this loop to account for the depth test
|
||||
OIT_Fragment frag = sorted[i];
|
||||
float fragDepth = frag.depth;
|
||||
float froxelDepth01 = scene.FroxelViewDepthToZ01(fragDepth, volumeSize.z);
|
||||
float3 scatterTC = float3(input.texCoords, froxelDepth01);
|
||||
closerScatterData = scatterTexture.SampleLevel(scatterSampler, scatterTC, 0);
|
||||
break;
|
||||
}
|
||||
float3 inScattering = scatterData.rgb - closerScatterData.rgb;
|
||||
float transmittance = scatterData.a / max(closerScatterData.a, 0.000001);
|
||||
color.rgb = color.rgb * transmittance + inScattering;
|
||||
scatterData = closerScatterData;
|
||||
}
|
||||
#endif
|
||||
|
||||
// blend the results
|
||||
lastFragmentIndex = -1;
|
||||
float dstDepth = 1.0;
|
||||
for(uint i = 0; i < fragmentCount; ++i)
|
||||
{
|
||||
OIT_Fragment frag = sorted[i];
|
||||
uint stateBits = frag.stateBits;
|
||||
float fragDepth = frag.depth;
|
||||
if((stateBits & (GLS_DEPTHFUNC_EQUAL | GLS_DEPTHTEST_DISABLE)) == GLS_DEPTHFUNC_EQUAL &&
|
||||
fragDepth != dstDepth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float4 fragColor = UnpackColor(frag.color);
|
||||
float4 prevColor = color;
|
||||
fragColor = DepthFadeFragmentColor(fragColor, frag, opaqueViewDepth);
|
||||
color = Blend(fragColor, color, frag.stateBits);
|
||||
if((stateBits & GLS_DEPTHMASK_TRUE) != 0u &&
|
||||
fragDepth < dstDepth)
|
||||
{
|
||||
dstDepth = fragDepth;
|
||||
}
|
||||
|
||||
// we have to not include the alpha channel in this test for it to be correct
|
||||
if(any(color.rgb != prevColor.rgb))
|
||||
{
|
||||
lastFragmentIndex = (int)i;
|
||||
}
|
||||
|
||||
#if defined(VOLUMETRIC_LIGHT)
|
||||
float fragmentImpact = FragmentImpact(fragColor, stateBits & GLS_BLEND_BITS);
|
||||
invisible[i] = fragmentImpact < impactThreshold;
|
||||
smallestImpact = min(smallestImpact, fragmentImpact);
|
||||
float4 closerScatterData = float4(0, 0, 0, 1);
|
||||
for(uint j = i + 1; j < fragmentCount; ++j)
|
||||
{
|
||||
// @TODO: fix this loop to account for the depth test
|
||||
OIT_Fragment frag = sorted[j];
|
||||
float fragDepth = frag.depth;
|
||||
float froxelDepth01 = scene.FroxelViewDepthToZ01(fragDepth, volumeSize.z);
|
||||
float3 scatterTC = float3(input.texCoords, froxelDepth01);
|
||||
closerScatterData = scatterTexture.SampleLevel(scatterSampler, scatterTC, 0);
|
||||
break;
|
||||
}
|
||||
float3 inScattering = scatterData.rgb - closerScatterData.rgb;
|
||||
float transmittance = scatterData.a / max(closerScatterData.a, 0.000001);
|
||||
color.rgb = color.rgb * transmittance + inScattering;
|
||||
scatterData = closerScatterData;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveInvisible()
|
||||
{
|
||||
uint newCount = 0;
|
||||
for(uint i = 0; i < fragmentCount; ++i)
|
||||
{
|
||||
if(invisible[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(newCount != i)
|
||||
{
|
||||
sorted[newCount] = sorted[i];
|
||||
}
|
||||
newCount++;
|
||||
}
|
||||
fragmentCount = newCount;
|
||||
}
|
||||
|
||||
void WriteShaderID(VOut input)
|
||||
{
|
||||
// write out the fragment shader ID of the closest visible fragment of the center pixel
|
||||
if(lastFragmentIndex >= 0)
|
||||
{
|
||||
OIT_Fragment closest = sorted[lastFragmentIndex];
|
||||
uint shaderTrace = closest.shaderTrace;
|
||||
if(shaderTrace & 1)
|
||||
{
|
||||
uint2 fragmentCoords = uint2(input.position.xy);
|
||||
uint2 centerCoords = uint2(centerPixel & 0xFFFF, centerPixel >> 16);
|
||||
if(all(fragmentCoords == centerCoords))
|
||||
{
|
||||
RWByteAddressBuffer shaderIdBuf = ResourceDescriptorHeap[shaderIndexBuffer];
|
||||
uint shaderIndex = shaderTrace >> 1;
|
||||
shaderIdBuf.Store(0, shaderIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SceneView scene;
|
||||
Texture2D renderTarget;
|
||||
int3 tcPx;
|
||||
float4 opaqueColor;
|
||||
float4 color;
|
||||
OIT_Fragment sorted[OIT_MAX_FRAGMENTS_PER_PIXEL];
|
||||
bool invisible[OIT_MAX_FRAGMENTS_PER_PIXEL];
|
||||
uint fragmentCount;
|
||||
int lastFragmentIndex;
|
||||
float opaqueViewDepth;
|
||||
float smallestImpact;
|
||||
#if defined(VOLUMETRIC_LIGHT)
|
||||
Texture3D<float4> scatterTexture;
|
||||
SamplerState scatterSampler;
|
||||
#endif
|
||||
};
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
OIT_Resolve resolve;
|
||||
if(resolve.InitScissorRect(input))
|
||||
{
|
||||
return resolve.opaqueColor;
|
||||
}
|
||||
|
||||
resolve.Init(input);
|
||||
|
||||
#if defined(VOLUMETRIC_LIGHT)
|
||||
// To fight off discontinuities between adjacent pixels,
|
||||
// we interpolate between the result computed normally
|
||||
// and computed by rejecting low-impact fragments
|
||||
// using a t value that only depends on the low-impact fragments.
|
||||
// It's far from perfect but once we get rid of most sprites
|
||||
// in favor of particles, we should be fine.
|
||||
const float VL_ImpactThreshold = 4.0 / 255.0;
|
||||
resolve.Resolve(input, VL_ImpactThreshold);
|
||||
float diff = resolve.smallestImpact;
|
||||
float4 color = resolve.color;
|
||||
resolve.RemoveInvisible();
|
||||
resolve.Resolve(input, 0.0);
|
||||
float4 color2 = resolve.color;
|
||||
color = lerp(color2, color, saturate(diff / VL_ImpactThreshold));
|
||||
#else
|
||||
resolve.Resolve(input, 666.0);
|
||||
float4 color = resolve.color;
|
||||
#endif
|
||||
|
||||
resolve.WriteShaderID(input);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -25,11 +25,18 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
typedef ivec2_t int2;
|
||||
typedef ivec3_t int3;
|
||||
typedef ivec4_t int4;
|
||||
typedef uint32_t uint;
|
||||
typedef uvec2_t uint2;
|
||||
typedef uvec3_t uint3;
|
||||
typedef uvec4_t uint4;
|
||||
typedef vec2_t float2;
|
||||
typedef vec3_t float3;
|
||||
typedef vec4_t float4;
|
||||
typedef matrix4x4_t matrix;
|
||||
typedef matrix3x3_t float3x3;
|
||||
typedef color4ub_t color4ub;
|
||||
#else
|
||||
typedef uint color4ub;
|
||||
|
|
206
code/renderer/shaders/crp/vl_common.h.hlsli
Normal file
206
code/renderer/shaders/crp/vl_common.h.hlsli
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: shared data structures and functions
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "typedefs.h.hlsli"
|
||||
#if !defined(__cplusplus)
|
||||
#include "common.hlsli"
|
||||
#include "simplex_noise.hlsli"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct FogVolume
|
||||
{
|
||||
float3 scatter;
|
||||
float absorption;
|
||||
float3 emissive;
|
||||
float anisotropy;
|
||||
float3 boxMin;
|
||||
float noiseMin;
|
||||
float3 boxMax;
|
||||
float noiseMax;
|
||||
float noiseScale;
|
||||
float noiseTimeScale;
|
||||
uint isHeightFog;
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
bool IsPointInside(float3 position)
|
||||
{
|
||||
return IsInRange(position, boxMin, boxMax);
|
||||
}
|
||||
|
||||
float DensityAt(float3 position, float time)
|
||||
{
|
||||
float4 positionTime = float4(position * noiseScale, time * noiseTimeScale);
|
||||
float density = noiseMin + (noiseMax - noiseMin) * SimplexNoise4D(positionTime);
|
||||
if(isHeightFog)
|
||||
{
|
||||
float maxHeight = boxMax.z - boxMin.z;
|
||||
float height = position.z - boxMin.z;
|
||||
density *= 1.0 - EaseOutCubic(height / maxHeight);
|
||||
}
|
||||
|
||||
return density;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
|
||||
// defines voxel sampling offsets for super-sampled fog injection
|
||||
|
||||
#if defined(VOXEL_SUPERSAMPLING_1X)
|
||||
static const int VoxelSampleCount = 1;
|
||||
static const float3 VoxelSamples[1] =
|
||||
{
|
||||
float3(0, 0, 0)
|
||||
};
|
||||
#elif defined(VOXEL_SUPERSAMPLING_2X)
|
||||
static const float Offset = 0.1666666666666666666666666666666;
|
||||
static const int VoxelSampleCount = 9;
|
||||
static const float3 VoxelSamples[9] =
|
||||
{
|
||||
float3(0, 0, 0),
|
||||
float3(-Offset, -Offset, -Offset),
|
||||
float3(-Offset, -Offset, +Offset),
|
||||
float3(-Offset, +Offset, -Offset),
|
||||
float3(-Offset, +Offset, +Offset),
|
||||
float3(+Offset, -Offset, -Offset),
|
||||
float3(+Offset, -Offset, +Offset),
|
||||
float3(+Offset, +Offset, -Offset),
|
||||
float3(+Offset, +Offset, +Offset)
|
||||
};
|
||||
#elif defined(VOXEL_SUPERSAMPLING_3X)
|
||||
static const int VoxelSampleCount = 27;
|
||||
static const float3 VoxelSamples[27] =
|
||||
{
|
||||
float3(-0.25, -0.25, -0.25),
|
||||
float3(-0.25, -0.25, 0),
|
||||
float3(-0.25, -0.25, 0.25),
|
||||
float3(-0.25, 0, -0.25),
|
||||
float3(-0.25, 0, 0),
|
||||
float3(-0.25, 0, 0.25),
|
||||
float3(-0.25, 0.25, -0.25),
|
||||
float3(-0.25, 0.25, 0),
|
||||
float3(-0.25, 0.25, 0.25),
|
||||
float3(0, -0.25, -0.25),
|
||||
float3(0, -0.25, 0),
|
||||
float3(0, -0.25, 0.25),
|
||||
float3(0, 0, -0.25),
|
||||
float3(0, 0, 0),
|
||||
float3(0, 0, 0.25),
|
||||
float3(0, 0.25, -0.25),
|
||||
float3(0, 0.25, 0),
|
||||
float3(0, 0.25, 0.25),
|
||||
float3(0.25, -0.25, -0.25),
|
||||
float3(0.25, -0.25, 0),
|
||||
float3(0.25, -0.25, 0.25),
|
||||
float3(0.25, 0, -0.25),
|
||||
float3(0.25, 0, 0),
|
||||
float3(0.25, 0, 0.25),
|
||||
float3(0.25, 0.25, -0.25),
|
||||
float3(0.25, 0.25, 0),
|
||||
float3(0.25, 0.25, 0.25)
|
||||
};
|
||||
#elif defined(VOXEL_SUPERSAMPLING_4X)
|
||||
static const int VoxelSampleCount = 65;
|
||||
static const float3 VoxelSamples[65] =
|
||||
{
|
||||
float3(0, 0, 0),
|
||||
float3(-0.3, -0.3, -0.3),
|
||||
float3(-0.3, -0.3, -0.1),
|
||||
float3(-0.3, -0.3, 0.1),
|
||||
float3(-0.3, -0.3, 0.3),
|
||||
float3(-0.3, -0.1, -0.3),
|
||||
float3(-0.3, -0.1, -0.1),
|
||||
float3(-0.3, -0.1, 0.1),
|
||||
float3(-0.3, -0.1, 0.3),
|
||||
float3(-0.3, 0.1, -0.3),
|
||||
float3(-0.3, 0.1, -0.1),
|
||||
float3(-0.3, 0.1, 0.1),
|
||||
float3(-0.3, 0.1, 0.3),
|
||||
float3(-0.3, 0.3, -0.3),
|
||||
float3(-0.3, 0.3, -0.1),
|
||||
float3(-0.3, 0.3, 0.1),
|
||||
float3(-0.3, 0.3, 0.3),
|
||||
float3(-0.1, -0.3, -0.3),
|
||||
float3(-0.1, -0.3, -0.1),
|
||||
float3(-0.1, -0.3, 0.1),
|
||||
float3(-0.1, -0.3, 0.3),
|
||||
float3(-0.1, -0.1, -0.3),
|
||||
float3(-0.1, -0.1, -0.1),
|
||||
float3(-0.1, -0.1, 0.1),
|
||||
float3(-0.1, -0.1, 0.3),
|
||||
float3(-0.1, 0.1, -0.3),
|
||||
float3(-0.1, 0.1, -0.1),
|
||||
float3(-0.1, 0.1, 0.1),
|
||||
float3(-0.1, 0.1, 0.3),
|
||||
float3(-0.1, 0.3, -0.3),
|
||||
float3(-0.1, 0.3, -0.1),
|
||||
float3(-0.1, 0.3, 0.1),
|
||||
float3(-0.1, 0.3, 0.3),
|
||||
float3(0.1, -0.3, -0.3),
|
||||
float3(0.1, -0.3, -0.1),
|
||||
float3(0.1, -0.3, 0.1),
|
||||
float3(0.1, -0.3, 0.3),
|
||||
float3(0.1, -0.1, -0.3),
|
||||
float3(0.1, -0.1, -0.1),
|
||||
float3(0.1, -0.1, 0.1),
|
||||
float3(0.1, -0.1, 0.3),
|
||||
float3(0.1, 0.1, -0.3),
|
||||
float3(0.1, 0.1, -0.1),
|
||||
float3(0.1, 0.1, 0.1),
|
||||
float3(0.1, 0.1, 0.3),
|
||||
float3(0.1, 0.3, -0.3),
|
||||
float3(0.1, 0.3, -0.1),
|
||||
float3(0.1, 0.3, 0.1),
|
||||
float3(0.1, 0.3, 0.3),
|
||||
float3(0.3, -0.3, -0.3),
|
||||
float3(0.3, -0.3, -0.1),
|
||||
float3(0.3, -0.3, 0.1),
|
||||
float3(0.3, -0.3, 0.3),
|
||||
float3(0.3, -0.1, -0.3),
|
||||
float3(0.3, -0.1, -0.1),
|
||||
float3(0.3, -0.1, 0.1),
|
||||
float3(0.3, -0.1, 0.3),
|
||||
float3(0.3, 0.1, -0.3),
|
||||
float3(0.3, 0.1, -0.1),
|
||||
float3(0.3, 0.1, 0.1),
|
||||
float3(0.3, 0.1, 0.3),
|
||||
float3(0.3, 0.3, -0.3),
|
||||
float3(0.3, 0.3, -0.1),
|
||||
float3(0.3, 0.3, 0.1),
|
||||
float3(0.3, 0.3, 0.3),
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
101
code/renderer/shaders/crp/vl_debug_ambient.hlsl
Normal file
101
code/renderer/shaders/crp/vl_debug_ambient.hlsl
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: visualize the bsp light grid as a bunch of raytraced spheres
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 centerPosition;
|
||||
float sphereScale;
|
||||
float3 worldScale;
|
||||
uint lightGridTextureAIndex;
|
||||
uint lightGridTextureBIndex;
|
||||
}
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float3 positionWS : POSITIONWS;
|
||||
float4 sphere : SPHERE;
|
||||
int3 voxelIndex : VOXELINDEX;
|
||||
};
|
||||
|
||||
VOut vs(uint vertexId : SV_VertexID)
|
||||
{
|
||||
Texture3D lightGridTexture = ResourceDescriptorHeap[lightGridTextureAIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
uint3 textureSize = GetTextureSize(lightGridTexture);
|
||||
uint flatVoxelIndex = vertexId / 6;
|
||||
uint vertexIndex = vertexId % 6;
|
||||
int3 voxelIndex = int3(UnflattenIndex(flatVoxelIndex, textureSize));
|
||||
float3 voxelCenter = AABoxIndexToWorldSpace(voxelIndex, centerPosition, float3(textureSize), worldScale);
|
||||
float2 quadPosition = QuadFromVertexID(vertexIndex);
|
||||
float radius = 0.5 * sphereScale * min3(worldScale.x, worldScale.y, worldScale.z);
|
||||
float3 up = scene.cameraUp;
|
||||
float3 forward = normalize(voxelCenter - scene.cameraPosition);
|
||||
float3 right = normalize(cross(forward, up));
|
||||
up = cross(right, forward);
|
||||
float3x3 rotMat = float3x3(right, up, forward);
|
||||
float distToSphere = length(scene.cameraPosition - voxelCenter);
|
||||
float sinAngle = radius / distToSphere;
|
||||
float cosAngle = sqrt(1.0 - sinAngle * sinAngle);
|
||||
float tanAngle = sinAngle / cosAngle;
|
||||
float quadScale = tanAngle * distToSphere * 2.0;
|
||||
float3 positionWS = voxelCenter + quadScale * mul(float3(quadPosition, 0), rotMat);
|
||||
float4 positionVS = mul(scene.viewMatrix, float4(positionWS, 1));
|
||||
float4 position = mul(scene.projectionMatrix, positionVS);
|
||||
|
||||
VOut output;
|
||||
output.position = position;
|
||||
output.positionWS = positionWS;
|
||||
output.sphere = float4(voxelCenter, radius);
|
||||
output.voxelIndex = voxelIndex;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture3D lightGridTextureA = ResourceDescriptorHeap[lightGridTextureAIndex];
|
||||
Texture3D lightGridTextureB = ResourceDescriptorHeap[lightGridTextureBIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
float3 rayDir = normalize(input.positionWS - scene.cameraPosition);
|
||||
float t = RaytraceSphere(scene.cameraPosition, rayDir, input.sphere.xyz, input.sphere.w);
|
||||
if(t < 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 payloadA = lightGridTextureA[input.voxelIndex];
|
||||
float4 payloadB = lightGridTextureB[input.voxelIndex];
|
||||
float3 hitPosition = scene.cameraPosition + rayDir * t;
|
||||
float3 normal = normalize(hitPosition - input.sphere.xyz);
|
||||
float3 color = AmbientColor(payloadA, payloadB, normal, scene.ambientColor);
|
||||
float4 result = float4(color * 0.5, 1);
|
||||
|
||||
return result;
|
||||
}
|
89
code/renderer/shaders/crp/vl_debug_extinction.hlsl
Normal file
89
code/renderer/shaders/crp/vl_debug_extinction.hlsl
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: visualize the extinction volume as little cubes
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 color;
|
||||
float worldScale;
|
||||
float3 cameraPosition;
|
||||
float boxScale;
|
||||
float extinctionScale;
|
||||
uint extinctionTextureIndex;
|
||||
}
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float3 positionInCube : POSITIONINCUBE;
|
||||
int3 voxelIndex : VOXELINDEX;
|
||||
};
|
||||
|
||||
VOut vs(uint vertexId : SV_VertexID)
|
||||
{
|
||||
RWTexture3D<float> extinctionTexture = ResourceDescriptorHeap[extinctionTextureIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
uint3 extinctionSize = GetTextureSize(extinctionTexture);
|
||||
uint flatVoxelIndex = vertexId / 36;
|
||||
uint vertexIndex = vertexId % 36;
|
||||
int3 voxelIndex = int3(UnflattenIndex(flatVoxelIndex, extinctionSize));
|
||||
float3 voxelCenter = AABoxIndexToWorldSpace(voxelIndex, cameraPosition, float3(extinctionSize), worldScale);
|
||||
float3 positionInCube = CubeFromVertexID(vertexIndex);
|
||||
float3 positionWS = voxelCenter + 0.5 * boxScale * worldScale * positionInCube;
|
||||
float4 positionVS = mul(scene.viewMatrix, float4(positionWS, 1));
|
||||
float4 position = mul(scene.projectionMatrix, positionVS);
|
||||
|
||||
VOut output;
|
||||
output.position = position;
|
||||
output.voxelIndex = voxelIndex;
|
||||
output.positionInCube = positionInCube;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
RWTexture3D<float> extinctionTexture = ResourceDescriptorHeap[extinctionTextureIndex];
|
||||
|
||||
float alpha = saturate(extinctionScale * extinctionTexture[input.voxelIndex]);
|
||||
if(alpha == 0.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
float threshold = 0.9;
|
||||
float3 position = abs(input.positionInCube);
|
||||
bool3 limits = position >= float3(threshold, threshold, threshold);
|
||||
if(dot(uint3(limits), uint3(1, 1, 1)) >= 2)
|
||||
{
|
||||
alpha = 0.0;
|
||||
}
|
||||
|
||||
float4 result = float4(color * 0.5 * alpha, 1);
|
||||
|
||||
return result;
|
||||
}
|
89
code/renderer/shaders/crp/vl_debug_shadow_sun.hlsl
Normal file
89
code/renderer/shaders/crp/vl_debug_shadow_sun.hlsl
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: visualize the sun shadow volume as little cubes
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 color;
|
||||
float worldScale;
|
||||
float3 cameraPosition;
|
||||
float boxScale;
|
||||
uint shadowTextureIndex;
|
||||
}
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float3 positionInCube : POSITIONINCUBE;
|
||||
int3 voxelIndex : VOXELINDEX;
|
||||
};
|
||||
|
||||
VOut vs(uint vertexId : SV_VertexID)
|
||||
{
|
||||
RWTexture3D<float> shadowTexture = ResourceDescriptorHeap[shadowTextureIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
uint3 shadowSize = GetTextureSize(shadowTexture);
|
||||
uint flatVoxelIndex = vertexId / 36;
|
||||
uint vertexIndex = vertexId % 36;
|
||||
int3 voxelIndex = int3(UnflattenIndex(flatVoxelIndex, shadowSize));
|
||||
float3 voxelCenterSS = AABoxIndexToWorldSpace(voxelIndex, cameraPosition, float3(shadowSize), worldScale);
|
||||
float3 positionInCube = CubeFromVertexID(vertexIndex);
|
||||
float3 positionSS = voxelCenterSS + 0.5 * boxScale * worldScale * positionInCube;
|
||||
float3 positionWS = cameraPosition + mul(scene.sunToZMatrix, positionSS - cameraPosition);
|
||||
float4 positionVS = mul(scene.viewMatrix, float4(positionWS, 1));
|
||||
float4 position = mul(scene.projectionMatrix, positionVS);
|
||||
|
||||
VOut output;
|
||||
output.position = position;
|
||||
output.voxelIndex = voxelIndex;
|
||||
output.positionInCube = positionInCube;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
RWTexture3D<float> shadowTexture = ResourceDescriptorHeap[shadowTextureIndex];
|
||||
|
||||
float transmittance = saturate(shadowTexture[input.voxelIndex]);
|
||||
if(transmittance == 1.0)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
float threshold = 0.9;
|
||||
float3 position = abs(input.positionInCube);
|
||||
bool3 limits = position >= float3(threshold, threshold, threshold);
|
||||
float edge = 0.0;
|
||||
if(dot(uint3(limits), uint3(1, 1, 1)) >= 2)
|
||||
{
|
||||
edge = 1.0;
|
||||
}
|
||||
float4 result = float4(saturate(0.5 * color * transmittance + edge.xxx), 1);
|
||||
|
||||
return result;
|
||||
}
|
73
code/renderer/shaders/crp/vl_extinction_injection_fog.hlsl
Normal file
73
code/renderer/shaders/crp/vl_extinction_injection_fog.hlsl
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: inject fog into the extinction volume
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#define VOXEL_SUPERSAMPLING_1X
|
||||
#include "vl_common.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
FogVolume fog;
|
||||
float time;
|
||||
uint extinctionTextureIndex;
|
||||
float worldScale;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float> extinctionTexture = ResourceDescriptorHeap[extinctionTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(extinctionTexture);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
float3 textureSizeF = float3(textureSize);
|
||||
float3 tcBase = (float3(id) + float3(0.5, 0.5, 0.5)) / textureSizeF;
|
||||
|
||||
float scale = 0.0;
|
||||
float counter = 0.0;
|
||||
for(int s = 0; s < VoxelSampleCount; s++)
|
||||
{
|
||||
float3 tcOffset = VoxelSamples[s] / textureSizeF;
|
||||
float3 tc = tcBase + tcOffset;
|
||||
float3 position = scene.ExtinctionIndexToWorldSpace(id, textureSizeF, worldScale);
|
||||
if(fog.IsPointInside(position))
|
||||
{
|
||||
scale += fog.DensityAt(position, time);
|
||||
counter += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if(scale > 0.0 && counter > 0.0)
|
||||
{
|
||||
scale /= counter;
|
||||
float extinction = (Brightness(fog.scatter) + fog.absorption) * scale;
|
||||
extinctionTexture[id] += extinction;
|
||||
}
|
||||
}
|
100
code/renderer/shaders/crp/vl_extinction_injection_particles.hlsl
Normal file
100
code/renderer/shaders/crp/vl_extinction_injection_particles.hlsl
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: inject particles into the extinction volume
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#define VOXEL_SUPERSAMPLING_2X
|
||||
#include "vl_common.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint3 tileScale;
|
||||
uint particleBufferIndex;
|
||||
uint particleCount;
|
||||
uint extinctionTextureIndex;
|
||||
uint tileBufferIndex;
|
||||
uint tileCount;
|
||||
float extinctionWorldScale;
|
||||
}
|
||||
|
||||
[numthreads(512, 1, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID, uint gidx : SV_GroupIndex)
|
||||
{
|
||||
uint tileIndex = dtid.x / 512;
|
||||
if(tileIndex >= tileCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWStructuredBuffer<uint3> tileBuffer = ResourceDescriptorHeap[tileBufferIndex];
|
||||
RWTexture3D<float> extinctionTexture = ResourceDescriptorHeap[extinctionTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(extinctionTexture);
|
||||
uint3 tileCornerIndex = tileBuffer[tileIndex];
|
||||
uint3 tileThreadIndex = UnflattenIndex(gidx, tileScale);
|
||||
uint3 id = tileCornerIndex * tileScale + tileThreadIndex;
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StructuredBuffer<Particle> particleBuffer = ResourceDescriptorHeap[particleBufferIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
float3 textureSizeF = float3(textureSize);
|
||||
float3 tcBase = (float3(id) + float3(0.5, 0.5, 0.5)) / textureSizeF;
|
||||
float accumExtinction = 0.0;
|
||||
for(uint i = 0; i < particleCount; i++)
|
||||
{
|
||||
Particle particle = particleBuffer[i];
|
||||
float extinction = particle.absorption;
|
||||
[flatten]
|
||||
if(particle.isEmissive == 0)
|
||||
{
|
||||
extinction += Brightness(particle.scattering);
|
||||
}
|
||||
|
||||
float particleCoverage = 0.0;
|
||||
for(uint s = 0; s < VoxelSampleCount; s++)
|
||||
{
|
||||
float3 tcSample = tcBase + VoxelSamples[s] / textureSizeF;
|
||||
float3 position = scene.ExtinctionTCToWorldSpace(tcSample, textureSizeF, extinctionWorldScale);
|
||||
float dist = distance(position, particle.position);
|
||||
if(dist >= particle.radius)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float coverage = sqrt(saturate(1.0 - dist / particle.radius));
|
||||
particleCoverage += coverage;
|
||||
}
|
||||
particleCoverage /= float(VoxelSampleCount);
|
||||
|
||||
accumExtinction += particleCoverage * extinction;
|
||||
}
|
||||
|
||||
if(accumExtinction > 0.0)
|
||||
{
|
||||
extinctionTexture[id] += accumExtinction;
|
||||
}
|
||||
}
|
|
@ -18,26 +18,32 @@ You should have received a copy of the GNU General Public License
|
|||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// fog volume (AABB) seen from outside
|
||||
// volumetric lighting: normalize the Henyey-Greenstein anisotropy factor g
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fog.hlsli"
|
||||
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
cbuffer RootConstants
|
||||
{
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[depthTextureIndex];
|
||||
float depthZW = depthTexture.Load(int3(input.position.xy, 0));
|
||||
float depthBuff = LinearDepth(depthZW, linearDepthA, linearDepthB);
|
||||
float depthFrag = input.depthVS;
|
||||
if(depthFrag > depthBuff)
|
||||
uint materialTextureBIndex;
|
||||
uint materialTextureCIndex;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float4> materialTextureB = ResourceDescriptorHeap[materialTextureBIndex];
|
||||
uint3 textureSize = GetTextureSize(materialTextureB);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
float fogOpacity = saturate((depthBuff - depthFrag) / depth);
|
||||
float4 result = float4(color.rgb, fogOpacity);
|
||||
|
||||
return result;
|
||||
RWTexture3D<float> materialTextureC = ResourceDescriptorHeap[materialTextureCIndex];
|
||||
float weightSum = materialTextureC[id];
|
||||
if(weightSum > 0.0)
|
||||
{
|
||||
materialTextureB[id].a /= weightSum;
|
||||
}
|
||||
}
|
77
code/renderer/shaders/crp/vl_frustum_injection_fog.hlsl
Normal file
77
code/renderer/shaders/crp/vl_frustum_injection_fog.hlsl
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: inject fog into the material textures
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#define VOXEL_SUPERSAMPLING_1X
|
||||
#include "vl_common.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
FogVolume fog;
|
||||
float time;
|
||||
uint materialTextureAIndex;
|
||||
uint materialTextureBIndex;
|
||||
uint materialTextureCIndex;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float4> materialTextureA = ResourceDescriptorHeap[materialTextureAIndex];
|
||||
uint3 textureSize = GetTextureSize(materialTextureA);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWTexture3D<float4> materialTextureB = ResourceDescriptorHeap[materialTextureBIndex];
|
||||
RWTexture3D<float> materialTextureC = ResourceDescriptorHeap[materialTextureCIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
float3 textureSizeF = float3(textureSize);
|
||||
float3 tcBase = (float3(id) + float3(0.5, 0.5, 0.5)) / textureSizeF;
|
||||
|
||||
float scale = 0.0;
|
||||
float counter = 0.0;
|
||||
for(int s = 0; s < VoxelSampleCount; s++)
|
||||
{
|
||||
float3 tcOffset = VoxelSamples[s] / textureSizeF;
|
||||
float3 tc = tcBase + tcOffset;
|
||||
float3 position = scene.FroxelTCToWorldSpace(tc, textureSizeF);
|
||||
if(fog.IsPointInside(position))
|
||||
{
|
||||
scale += fog.DensityAt(position, time);
|
||||
counter += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if(scale > 0.0 && counter > 0.0)
|
||||
{
|
||||
scale /= counter;
|
||||
materialTextureA[id] += float4(fog.scatter * scale, fog.absorption * scale);
|
||||
materialTextureB[id] += float4(fog.emissive * scale, fog.anisotropy);
|
||||
materialTextureC[id] += 1.0;
|
||||
}
|
||||
}
|
116
code/renderer/shaders/crp/vl_frustum_injection_particles.hlsl
Normal file
116
code/renderer/shaders/crp/vl_frustum_injection_particles.hlsl
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: inject particles into the material textures
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#define VOXEL_SUPERSAMPLING_2X
|
||||
#include "vl_common.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint3 tileScale;
|
||||
uint particleBufferIndex;
|
||||
uint particleCount;
|
||||
uint materialTextureAIndex;
|
||||
uint materialTextureBIndex;
|
||||
uint materialTextureCIndex;
|
||||
uint tileBufferIndex;
|
||||
uint tileCount;
|
||||
}
|
||||
|
||||
[numthreads(1024, 1, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID, uint gidx : SV_GroupIndex)
|
||||
{
|
||||
uint tileIndex = dtid.x / 1024;
|
||||
if(tileIndex >= tileCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWStructuredBuffer<uint3> tileBuffer = ResourceDescriptorHeap[tileBufferIndex];
|
||||
RWTexture3D<float4> materialTextureA = ResourceDescriptorHeap[materialTextureAIndex];
|
||||
uint3 textureSize = GetTextureSize(materialTextureA);
|
||||
uint3 tileCornerIndex = tileBuffer[tileIndex];
|
||||
uint3 tileThreadIndex = UnflattenIndex(gidx, tileScale);
|
||||
uint3 id = tileCornerIndex * tileScale + tileThreadIndex;
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWTexture3D<float4> materialTextureB = ResourceDescriptorHeap[materialTextureBIndex];
|
||||
RWTexture3D<float> materialTextureC = ResourceDescriptorHeap[materialTextureCIndex];
|
||||
StructuredBuffer<Particle> particleBuffer = ResourceDescriptorHeap[particleBufferIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
float3 textureSizeF = float3(textureSize);
|
||||
float3 tcBase = (float3(id) + float3(0.5, 0.5, 0.5)) / textureSizeF;
|
||||
float4 accumScatterAbs = float4(0, 0, 0, 0);
|
||||
float4 accumEmissiveAniso = float4(0, 0, 0, 0);
|
||||
float accumCoverage = 0.0;
|
||||
for(uint i = 0; i < particleCount; i++)
|
||||
{
|
||||
Particle particle = particleBuffer[i];
|
||||
float3 scattering;
|
||||
float3 emissive;
|
||||
[flatten]
|
||||
if(particle.isEmissive != 0)
|
||||
{
|
||||
scattering = float3(0, 0, 0);
|
||||
emissive = particle.scattering;
|
||||
}
|
||||
else
|
||||
{
|
||||
scattering = particle.scattering;
|
||||
emissive = float3(0, 0, 0);
|
||||
}
|
||||
|
||||
float particleCoverage = 0.0;
|
||||
for(uint s = 0; s < VoxelSampleCount; s++)
|
||||
{
|
||||
float3 tcSample = tcBase + VoxelSamples[s] / textureSizeF;
|
||||
float3 position = scene.FroxelTCToWorldSpace(tcSample, textureSizeF);
|
||||
float dist = distance(position, particle.position);
|
||||
if(dist >= particle.radius)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float coverage = sqrt(saturate(1.0 - dist / particle.radius));
|
||||
particleCoverage += coverage;
|
||||
}
|
||||
particleCoverage /= float(VoxelSampleCount);
|
||||
|
||||
accumScatterAbs += particleCoverage * float4(scattering, particle.absorption);
|
||||
accumEmissiveAniso += particleCoverage * float4(emissive, particle.anisotropy);
|
||||
accumCoverage += particleCoverage;
|
||||
}
|
||||
|
||||
if(accumCoverage > 0.0)
|
||||
{
|
||||
materialTextureA[id] += accumScatterAbs;
|
||||
materialTextureB[id] += accumEmissiveAniso;
|
||||
materialTextureC[id] += accumCoverage;
|
||||
}
|
||||
}
|
86
code/renderer/shaders/crp/vl_frustum_inscatter_ambient.hlsl
Normal file
86
code/renderer/shaders/crp/vl_frustum_inscatter_ambient.hlsl
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: accumulates in-scattered ambient light
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 centerPosition;
|
||||
uint materialTextureAIndex;
|
||||
float3 worldScale;
|
||||
uint scatterExtTextureIndex;
|
||||
uint ambientLightTextureAIndex;
|
||||
uint ambientLightTextureBIndex;
|
||||
uint ambientSamplerIndex;
|
||||
uint isLightGridAvailable;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float4> scatterExtTexture = ResourceDescriptorHeap[scatterExtTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(scatterExtTexture);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(isLightGridAvailable != 0)
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
RWTexture3D<float4> materialTextureA = ResourceDescriptorHeap[materialTextureAIndex];
|
||||
Texture3D ambientLightTextureA = ResourceDescriptorHeap[ambientLightTextureAIndex];
|
||||
Texture3D ambientLightTextureB = ResourceDescriptorHeap[ambientLightTextureBIndex];
|
||||
SamplerState ambientSampler = SamplerDescriptorHeap[ambientSamplerIndex];
|
||||
float3 ambientTextureSize = float3(GetTextureSize(ambientLightTextureA));
|
||||
|
||||
float3 positionWS = scene.FroxelIndexToWorldSpace(id, textureSize);
|
||||
float3 normalWS = normalize(scene.cameraPosition - positionWS);
|
||||
float4 scatterAbs = materialTextureA[id];
|
||||
float3 scattering = scatterAbs.rgb;
|
||||
float extinction = Brightness(scattering) + scatterAbs.a;
|
||||
float3 ambientTC = AABoxWorldSpaceToTC(positionWS, centerPosition, ambientTextureSize, worldScale);
|
||||
float4 ambientA = ambientLightTextureA.SampleLevel(ambientSampler, ambientTC, 0);
|
||||
float4 ambientB = ambientLightTextureB.SampleLevel(ambientSampler, ambientTC, 0);
|
||||
float3 ambientColor = AmbientColor(ambientA, ambientB, normalWS, scene.ambientColor);
|
||||
float3 inScattering = scattering * ambientColor * scene.ambientIntensity;
|
||||
|
||||
scatterExtTexture[id] = float4(inScattering, extinction);
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
RWTexture3D<float4> materialTextureA = ResourceDescriptorHeap[materialTextureAIndex];
|
||||
|
||||
float3 positionWS = scene.FroxelIndexToWorldSpace(id, textureSize);
|
||||
float3 normalWS = normalize(scene.cameraPosition - positionWS);
|
||||
float4 scatterAbs = materialTextureA[id];
|
||||
float3 scattering = scatterAbs.rgb;
|
||||
float extinction = Brightness(scattering) + scatterAbs.a;
|
||||
float3 inScattering = scattering * scene.ambientColor * scene.ambientIntensity;
|
||||
|
||||
scatterExtTexture[id] = float4(inScattering, extinction);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: accumulates in-scattered light from a local point light
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#include "raytracing.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
DynamicLight light;
|
||||
uint materialTextureAIndex;
|
||||
uint materialTextureBIndex;
|
||||
uint scatterExtTextureIndex;
|
||||
uint transmittanceTextureIndex;
|
||||
uint transmittanceSamplerIndex;
|
||||
float shadowWorldScale;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float4> scatterExtTexture = ResourceDescriptorHeap[scatterExtTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(scatterExtTexture);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWTexture3D<float4> materialTextureA = ResourceDescriptorHeap[materialTextureAIndex];
|
||||
RWTexture3D<float4> materialTextureB = ResourceDescriptorHeap[materialTextureBIndex];
|
||||
Texture3D<float> transmittanceTexture = ResourceDescriptorHeap[transmittanceTextureIndex];
|
||||
SamplerState transmittanceSampler = SamplerDescriptorHeap[transmittanceSamplerIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
float3 froxelPosition = scene.FroxelIndexToWorldSpace(id, float3(textureSize));
|
||||
float3 lightPosition = light.position;
|
||||
float dist = distance(froxelPosition, lightPosition);
|
||||
float radius = light.radius;
|
||||
if(dist >= radius)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float3 scattering = materialTextureA[id].rgb;
|
||||
float anisotropy = materialTextureB[id].a;
|
||||
RTAS rtas = ResourceDescriptorHeap[scene.tlasBufferIndex];
|
||||
float3 lightDir = normalize(lightPosition - froxelPosition);
|
||||
float vis = TraceVisibilityWithoutAT(rtas, froxelPosition, lightDir, dist);
|
||||
float3 shadowTC = AABoxWorldSpaceToTC(froxelPosition, lightPosition, GetTextureSize(transmittanceTexture), shadowWorldScale);
|
||||
float trans = transmittanceTexture.SampleLevel(transmittanceSampler, shadowTC, 0);
|
||||
float intensity = saturate(1.0 - dist / radius);
|
||||
float3 lightRaw = light.color * intensity * 50.0; // @TODO:
|
||||
float2 froxelTC = (float2(id.xy) + float2(0.5, 0.5)) / float2(textureSize.xy);
|
||||
float2 froxelNDC = TCToNDC(froxelTC);
|
||||
float3 cameraRay = scene.CamerayRay(froxelNDC);
|
||||
float cosTheta = dot(-lightDir, -cameraRay);
|
||||
float phase = HenyeyGreenstein(cosTheta, anisotropy);
|
||||
float3 inScattering = vis * lightRaw * trans * scattering * phase;
|
||||
|
||||
scatterExtTexture[id].rgb += inScattering;
|
||||
}
|
86
code/renderer/shaders/crp/vl_frustum_inscatter_sunlight.hlsl
Normal file
86
code/renderer/shaders/crp/vl_frustum_inscatter_sunlight.hlsl
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: accumulates in-scattered sunlight
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#include "raytracing.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint materialTextureAIndex;
|
||||
uint materialTextureBIndex;
|
||||
uint scatterExtTextureIndex;
|
||||
uint sunlightVisTextureIndex;
|
||||
}
|
||||
|
||||
float FroxelSize(uint3 index, float3 textureSize, SceneView scene)
|
||||
{
|
||||
float3 tcBase = (float3(index) + float3(0.5, 0.5, 0.5)) / textureSize;
|
||||
float3 halfTexel = float3(0.5, 0.5, 0.5) / textureSize;
|
||||
float3 posL = scene.FroxelTCToWorldSpace(tcBase + float3(-halfTexel.x, 0, 0), textureSize);
|
||||
float3 posR = scene.FroxelTCToWorldSpace(tcBase + float3( halfTexel.x, 0, 0), textureSize);
|
||||
float w = distance(posL, posR);
|
||||
float3 posU = scene.FroxelTCToWorldSpace(tcBase + float3(0, halfTexel.y, 0), textureSize);
|
||||
float3 posD = scene.FroxelTCToWorldSpace(tcBase + float3(0, -halfTexel.y, 0), textureSize);
|
||||
float h = distance(posU, posD);
|
||||
float3 posF = scene.FroxelTCToWorldSpace(tcBase + float3(0, 0, halfTexel.z), textureSize);
|
||||
float3 posB = scene.FroxelTCToWorldSpace(tcBase + float3(0, 0, -halfTexel.z), textureSize);
|
||||
float d = distance(posF, posB);
|
||||
float size = max3(w, h, d);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float4> scatterExtTexture = ResourceDescriptorHeap[scatterExtTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(scatterExtTexture);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWTexture3D<float4> materialTextureA = ResourceDescriptorHeap[materialTextureAIndex];
|
||||
RWTexture3D<float4> materialTextureB = ResourceDescriptorHeap[materialTextureBIndex];
|
||||
RWTexture3D<float> sunlightVisTexture = ResourceDescriptorHeap[sunlightVisTextureIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
float froxelSize = FroxelSize(id, float3(textureSize), scene);
|
||||
SunVShadowCascade cascade = scene.GetSunVShadowCascade(froxelSize);
|
||||
|
||||
float3 positionWS = scene.FroxelIndexToWorldSpace(id, textureSize);
|
||||
float visOpaque = sunlightVisTexture[id];
|
||||
float visVolume = cascade.TransmittanceAt(positionWS);
|
||||
float vis = visOpaque * visVolume;
|
||||
float2 tc = (float2(id.xy) + float2(0.5, 0.5)) / float2(textureSize.xy);
|
||||
float2 ndc = TCToNDC(tc);
|
||||
float3 cameraRay = scene.CamerayRay(ndc);
|
||||
float cosTheta = dot(-scene.sunDirection, -cameraRay);
|
||||
float3 scattering = materialTextureA[id].rgb;
|
||||
float anisotropy = materialTextureB[id].a;
|
||||
float phase = HenyeyGreenstein(cosTheta, anisotropy);
|
||||
float3 inScattering = vis * scene.sunColor * scene.sunIntensity * scattering * phase;
|
||||
|
||||
scatterExtTexture[id].rgb += inScattering;
|
||||
}
|
73
code/renderer/shaders/crp/vl_frustum_raymarch.hlsl
Normal file
73
code/renderer/shaders/crp/vl_frustum_raymarch.hlsl
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: raymarch froxels
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint scatterTextureIndex;
|
||||
uint resolveTextureIndex;
|
||||
uint materialTextureBIndex;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float4> scatterTexture = ResourceDescriptorHeap[scatterTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(scatterTexture);
|
||||
if(any(id.xy >= textureSize.xy))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// integScatter is computed using Frostbite's analytical solution:
|
||||
// Int(S * T(Z) * dZ) == S * (1 - T(Z)) / extinction
|
||||
|
||||
SceneView scene = GetSceneView();
|
||||
RWTexture3D<float4> resolveTexture = ResourceDescriptorHeap[resolveTextureIndex];
|
||||
RWTexture3D<float4> materialTextureB = ResourceDescriptorHeap[materialTextureBIndex];
|
||||
uint3 index0 = uint3(id.xy, 0);
|
||||
float3 tc0 = (float3(index0) + float3(0.5, 0.5, 0)) / textureSize; // near edge of first voxel
|
||||
float3 prevPosition = scene.FroxelTCToWorldSpace(tc0, float3(textureSize));
|
||||
float3 accumScatter = float3(0, 0, 0);
|
||||
float accumTrans = 1.0;
|
||||
for(uint d = 0; d < textureSize.z; d++)
|
||||
{
|
||||
uint3 index = uint3(id.xy, d);
|
||||
float3 tc = (float3(index) + float3(0.5, 0.5, 1)) / textureSize; // far edge of current voxel
|
||||
float4 froxelScatterExt = scatterTexture[index];
|
||||
float3 emissive = materialTextureB[index].rgb;
|
||||
float3 froxelScatter = froxelScatterExt.rgb + emissive;
|
||||
float froxelExtinction = froxelScatterExt.a;
|
||||
float3 currPosition = scene.FroxelTCToWorldSpace(tc, float3(textureSize));
|
||||
float depthStep = distance(currPosition, prevPosition);
|
||||
float froxelTrans = Transmittance(depthStep, froxelExtinction);
|
||||
float3 integScatter = froxelScatter * (1.0 - froxelTrans) / (froxelExtinction == 0.0 ? 1.0 : froxelExtinction);
|
||||
accumScatter += accumTrans * integScatter;
|
||||
accumTrans *= froxelTrans;
|
||||
resolveTexture[index] = float4(accumScatter, accumTrans);
|
||||
prevPosition = currPosition;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: opaque sunlight visibility
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
#include "raytracing.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 jitter;
|
||||
uint visTextureIndex;
|
||||
uint depthMip;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float> visTexture = ResourceDescriptorHeap[visTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(visTexture);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SceneView scene = GetSceneView();
|
||||
RTAS rtas = ResourceDescriptorHeap[scene.tlasBufferIndex];
|
||||
Texture2D<float2> depthMinMaxTexture = ResourceDescriptorHeap[scene.depthMinMaxTextureIndex];
|
||||
|
||||
float2 tc = (float2(id.xy) + float2(0.5, 0.5)) / float2(textureSize.xy);
|
||||
float2 ndc = TCToNDC(tc);
|
||||
float3 cameraRay = scene.CamerayRay(ndc);
|
||||
float3 froxelPosition =
|
||||
scene.FroxelIndexToWorldSpace(id, float3(textureSize)) +
|
||||
jitter.x * scene.cameraLeft +
|
||||
jitter.y * scene.cameraUp +
|
||||
jitter.z * cameraRay;
|
||||
float vis = TraceVisibilityWithoutAT(rtas, froxelPosition, scene.sunDirection, 10000.0);
|
||||
|
||||
// this helps fix dark spots around opaque geometry set against the skybox
|
||||
float storedDepth = depthMinMaxTexture.mips[depthMip][id.xy].x;
|
||||
float4 positionCS = mul(scene.projectionMatrix, mul(scene.viewMatrix, float4(froxelPosition, 1)));
|
||||
float froxelDepth = positionCS.z / positionCS.w;
|
||||
if(froxelDepth < storedDepth)
|
||||
{
|
||||
vis = 0.0;
|
||||
}
|
||||
|
||||
visTexture[id] = vis;
|
||||
}
|
62
code/renderer/shaders/crp/vl_frustum_temporal.hlsl
Normal file
62
code/renderer/shaders/crp/vl_frustum_temporal.hlsl
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: temporal reprojection
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint currTextureIndex;
|
||||
uint prevTextureIndex;
|
||||
uint prevTextureSamplerIndex;
|
||||
float alpha;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float> currTexture = ResourceDescriptorHeap[currTextureIndex];
|
||||
uint3 textureSize = GetTextureSize(currTexture);
|
||||
if(any(id >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SceneView scene = GetSceneView();
|
||||
Texture3D<float> prevTexture = ResourceDescriptorHeap[prevTextureIndex];
|
||||
SamplerState prevTextureSampler = SamplerDescriptorHeap[prevTextureSamplerIndex];
|
||||
|
||||
float3 tc = scene.FroxelReproject01(id, float3(textureSize));
|
||||
float currValue = currTexture[id];
|
||||
float3 halfPixelSize = float3(0.5, 0.5, 0.5) / float3(textureSize);
|
||||
if(IsInRange(tc, halfPixelSize, float3(1, 1, 1) - halfPixelSize))
|
||||
{
|
||||
float prevValue = prevTexture.SampleLevel(prevTextureSampler, tc, 0);
|
||||
float finalValue = lerp(currValue, prevValue, alpha);
|
||||
if(finalValue != currValue)
|
||||
{
|
||||
currTexture[id] = finalValue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,36 +18,38 @@ You should have received a copy of the GNU General Public License
|
|||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// fog volume (AABB) rendering - shared code
|
||||
// volumetric lighting: update indirect dispatch buffer for particle injection
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
matrix modelViewMatrix;
|
||||
matrix projectionMatrix;
|
||||
float4 boxMin;
|
||||
float4 boxMax;
|
||||
float4 color;
|
||||
float depth;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
uint depthTextureIndex;
|
||||
};
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float depthVS : DEPTHVS;
|
||||
};
|
||||
|
||||
VOut vs(float3 positionOS : POSITION)
|
||||
{
|
||||
float3 positionWS = boxMin.xyz + positionOS * (boxMax.xyz - boxMin.xyz);
|
||||
float4 positionVS = mul(modelViewMatrix, float4(positionWS, 1));
|
||||
|
||||
VOut output;
|
||||
output.position = mul(projectionMatrix, positionVS);
|
||||
output.depthVS = -positionVS.z;
|
||||
|
||||
return output;
|
||||
uint3 tileResolution;
|
||||
uint tileBufferIndex;
|
||||
uint dispatchBufferIndex;
|
||||
uint particleTileBufferIndex;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
if(any(id >= tileResolution))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RWByteAddressBuffer dispatchBuffer = ResourceDescriptorHeap[dispatchBufferIndex];
|
||||
RWByteAddressBuffer tileHitBuffer = ResourceDescriptorHeap[tileBufferIndex];
|
||||
RWStructuredBuffer<uint3> tileWorkBuffer = ResourceDescriptorHeap[particleTileBufferIndex];
|
||||
|
||||
uint tileIndex = FlattenIndex(id, tileResolution);
|
||||
uint hasParticle = tileHitBuffer.Load(tileIndex * 4);
|
||||
if(hasParticle != 0)
|
||||
{
|
||||
uint workIndex;
|
||||
dispatchBuffer.InterlockedAdd(0, 1, workIndex);
|
||||
tileWorkBuffer[workIndex] = id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: pre-process particles for extinction volume injection
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint3 fullResolution;
|
||||
uint tileBufferIndex;
|
||||
uint3 tileResolution;
|
||||
uint particleBufferIndex;
|
||||
uint3 tileScale;
|
||||
uint particleCount;
|
||||
float extinctionWorldScale;
|
||||
}
|
||||
|
||||
[numthreads(64, 1, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
uint particleIndex = id.x;
|
||||
if(particleIndex >= particleCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StructuredBuffer<Particle> particleBuffer = ResourceDescriptorHeap[particleBufferIndex];
|
||||
RWByteAddressBuffer tileBuffer = ResourceDescriptorHeap[tileBufferIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
Particle particle = particleBuffer[particleIndex];
|
||||
float3 P = particle.position;
|
||||
float r = particle.radius;
|
||||
int3 boxMin = scene.ExtinctionWorldSpaceToIndex(P - float3(r, r, r), fullResolution, extinctionWorldScale);
|
||||
int3 boxMax = scene.ExtinctionWorldSpaceToIndex(P + float3(r, r, r), fullResolution, extinctionWorldScale);
|
||||
boxMin /= int3(tileScale);
|
||||
boxMax /= int3(tileScale);
|
||||
boxMin = max(boxMin, int3(0, 0, 0));
|
||||
boxMax = min(boxMax, int3(tileResolution) - int3(1, 1, 1));
|
||||
for(int x = boxMin.x; x <= boxMax.x; x++)
|
||||
{
|
||||
for(int y = boxMin.y; y <= boxMax.y; y++)
|
||||
{
|
||||
for(int z = boxMin.z; z <= boxMax.z; z++)
|
||||
{
|
||||
uint3 tileIndex = uint3(x, y, z);
|
||||
uint index = FlattenIndex(tileIndex, tileResolution);
|
||||
tileBuffer.Store(index * 4, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: pre-process particles for frustum volume injection
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint3 fullResolution;
|
||||
uint tileBufferIndex;
|
||||
uint3 tileResolution;
|
||||
uint particleBufferIndex;
|
||||
uint3 tileScale;
|
||||
uint particleCount;
|
||||
}
|
||||
|
||||
[numthreads(64, 1, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
uint particleIndex = id.x;
|
||||
if(particleIndex >= particleCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StructuredBuffer<Particle> particleBuffer = ResourceDescriptorHeap[particleBufferIndex];
|
||||
RWByteAddressBuffer tileBuffer = ResourceDescriptorHeap[tileBufferIndex];
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
Particle particle = particleBuffer[particleIndex];
|
||||
float3 P = particle.position;
|
||||
float r = particle.radius * 1.0625;
|
||||
float3 left = scene.cameraLeft;
|
||||
float3 up = scene.cameraUp;
|
||||
float3 fwd = scene.cameraForward;
|
||||
int3 boxMin;
|
||||
int3 boxMax;
|
||||
ClearBoundingBox(boxMin, boxMax);
|
||||
ExpandBoundingBox(boxMin, boxMax, scene.FroxelWorldSpaceToIndex(P + r * left, fullResolution));
|
||||
ExpandBoundingBox(boxMin, boxMax, scene.FroxelWorldSpaceToIndex(P - r * left, fullResolution));
|
||||
ExpandBoundingBox(boxMin, boxMax, scene.FroxelWorldSpaceToIndex(P + r * up, fullResolution));
|
||||
ExpandBoundingBox(boxMin, boxMax, scene.FroxelWorldSpaceToIndex(P - r * up, fullResolution));
|
||||
ExpandBoundingBox(boxMin, boxMax, scene.FroxelWorldSpaceToIndex(P + r * fwd, fullResolution));
|
||||
ExpandBoundingBox(boxMin, boxMax, scene.FroxelWorldSpaceToIndex(P - r * fwd, fullResolution));
|
||||
boxMin /= int3(tileScale);
|
||||
boxMax /= int3(tileScale);
|
||||
boxMin = max(boxMin, int3(0, 0, 0));
|
||||
boxMax = min(boxMax, int3(tileResolution) - int3(1, 1, 1));
|
||||
for(int x = boxMin.x; x <= boxMax.x; x++)
|
||||
{
|
||||
for(int y = boxMin.y; y <= boxMax.y; y++)
|
||||
{
|
||||
for(int z = boxMin.z; z <= boxMax.z; z++)
|
||||
{
|
||||
uint3 tileIndex = uint3(x, y, z);
|
||||
uint index = FlattenIndex(tileIndex, tileResolution);
|
||||
tileBuffer.Store(index * 4, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
code/renderer/shaders/crp/vl_shadow_point_light.hlsl
Normal file
65
code/renderer/shaders/crp/vl_shadow_point_light.hlsl
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: point light shadow volume
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float3 lightPosition;
|
||||
float extinctionWorldScale;
|
||||
float shadowWorldScale;
|
||||
uint shadowTextureIndex;
|
||||
}
|
||||
|
||||
[numthreads(4, 4, 4)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float> shadowTexture = ResourceDescriptorHeap[shadowTextureIndex];
|
||||
uint3 shadowSize = GetTextureSize(shadowTexture);
|
||||
if(any(id >= shadowSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SceneView scene = GetSceneView();
|
||||
float3 voxelPosition = AABoxIndexToWorldSpace(id, lightPosition, shadowSize, shadowWorldScale);
|
||||
float dist = distance(voxelPosition, lightPosition);
|
||||
float stepDist = extinctionWorldScale;
|
||||
uint stepCount = uint(dist / stepDist);
|
||||
float3 step = normalize(lightPosition - voxelPosition) * stepDist;
|
||||
ExtinctionCascade cascade = scene.GetExtinctionCascade(stepDist);
|
||||
|
||||
float transmittance = 1.0;
|
||||
float3 extinctionPositionWS = voxelPosition;
|
||||
for(uint i = 0; i < stepCount; i++)
|
||||
{
|
||||
float extinction = cascade.ExtinctionAt(extinctionPositionWS);
|
||||
float trans = Transmittance(stepDist, extinction);
|
||||
transmittance *= saturate(trans);
|
||||
extinctionPositionWS += step;
|
||||
}
|
||||
|
||||
shadowTexture[id] = transmittance;
|
||||
}
|
75
code/renderer/shaders/crp/vl_shadow_sun.hlsl
Normal file
75
code/renderer/shaders/crp/vl_shadow_sun.hlsl
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// volumetric lighting: sunlight shadow volume
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint shadowTextureIndex;
|
||||
uint sourceTextureIndex;
|
||||
float shadowWorldScale;
|
||||
float sourceWorldScale;
|
||||
}
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
RWTexture3D<float> shadowTexture = ResourceDescriptorHeap[shadowTextureIndex];
|
||||
uint3 shadowSize = GetTextureSize(shadowTexture);
|
||||
if(any(id.xy >= shadowSize.xy))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SceneView scene = GetSceneView();
|
||||
ExtinctionCascade cascade = scene.GetExtinctionCascade(shadowWorldScale);
|
||||
|
||||
float3 cameraPosition = scene.cameraPosition;
|
||||
float accumTrans = 1.0;
|
||||
if(sourceTextureIndex != 0)
|
||||
{
|
||||
SamplerState linearClampSampler = SamplerDescriptorHeap[scene.linearClampSamplerIndex];
|
||||
Texture3D<float> sourceTexture = ResourceDescriptorHeap[sourceTextureIndex];
|
||||
int3 index = int3(id.xy, -1);
|
||||
float3 destPositionSS = AABoxIndexToWorldSpace(index, cameraPosition, shadowSize, shadowWorldScale);
|
||||
float3 destPositionWS = cameraPosition + mul(scene.sunToZMatrix, destPositionSS - cameraPosition);
|
||||
float3 sourcePositionSS = cameraPosition + mul(scene.zToSunMatrix, destPositionWS - cameraPosition);
|
||||
float3 sourceSize = float3(GetTextureSize(sourceTexture));
|
||||
float3 tc = AABoxWorldSpaceToTC(sourcePositionSS, cameraPosition, sourceSize, sourceWorldScale);
|
||||
float transmittance = sourceTexture.SampleLevel(linearClampSampler, tc, 0);
|
||||
accumTrans = transmittance;
|
||||
}
|
||||
|
||||
for(uint d = 0; d < shadowSize.z; d++)
|
||||
{
|
||||
uint3 index = uint3(id.xy, d);
|
||||
float3 voxelPositionSS = AABoxIndexToWorldSpace(index, cameraPosition, shadowSize, shadowWorldScale);
|
||||
float3 voxelPositionWS = cameraPosition + mul(scene.sunToZMatrix, voxelPositionSS - cameraPosition);
|
||||
float extinction = max(cascade.ExtinctionAt(voxelPositionWS), 0.0);
|
||||
float transmittance = saturate(Transmittance(shadowWorldScale, extinction));
|
||||
accumTrans *= transmittance;
|
||||
shadowTexture[index] = accumTrans;
|
||||
}
|
||||
}
|
|
@ -239,6 +239,16 @@ void R_AddDrawSurfCmd( drawSurf_t* drawSurfs, int numDrawSurfs, int numTranspSur
|
|||
memcpy(tr.prevProjMatrix, tr.currProjMatrix, sizeof(tr.prevProjMatrix));
|
||||
memcpy(tr.currViewMatrix, tr.viewParms.world.modelMatrix, sizeof(tr.currViewMatrix));
|
||||
memcpy(tr.currProjMatrix, tr.viewParms.projectionMatrix, sizeof(tr.currProjMatrix));
|
||||
|
||||
// camera positions
|
||||
VectorCopy(tr.currCameraPosition, tr.prevCameraPosition);
|
||||
VectorCopy(tr.viewParms.world.viewOrigin, tr.currCameraPosition);
|
||||
|
||||
// clip plane distances
|
||||
tr.prevZNear = tr.currZNear;
|
||||
tr.prevZFar = tr.currZFar;
|
||||
tr.currZNear = tr.viewParms.zNear;
|
||||
tr.currZFar = tr.viewParms.zFar;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ struct trRefEntity_t {
|
|||
|
||||
struct orientationr_t {
|
||||
vec3_t origin; // in world coordinates
|
||||
vec3_t axis[3]; // orientation in world
|
||||
vec3_t axis[3]; // orientation in world, order: forward, left, up
|
||||
vec3_t viewOrigin; // viewParms->or.origin in local coordinates
|
||||
float modelMatrix[16];
|
||||
};
|
||||
|
@ -1024,13 +1024,19 @@ typedef struct {
|
|||
trRefdef_t rtRefdef;
|
||||
|
||||
// from current and last frame's non-portal full-screen scene view
|
||||
// needed for motion vectors
|
||||
// needed for motion vectors and temporal reprojection in general
|
||||
float currViewProjMatrix[16];
|
||||
float prevViewProjMatrix[16];
|
||||
float currViewMatrix[16];
|
||||
float prevViewMatrix[16];
|
||||
float currProjMatrix[16];
|
||||
float prevProjMatrix[16];
|
||||
vec3_t currCameraPosition;
|
||||
vec3_t prevCameraPosition;
|
||||
float currZNear;
|
||||
float currZFar;
|
||||
float prevZNear;
|
||||
float prevZFar;
|
||||
|
||||
} trGlobals_t;
|
||||
|
||||
|
@ -1663,10 +1669,9 @@ void R_CameraAxisVectorsFromMatrix( const matrix4x4_t modelView, vec3_t axisX, v
|
|||
void R_MakeIdentityMatrix( matrix4x4_t m );
|
||||
void R_MakeOrthoProjectionMatrix( matrix4x4_t m, float w, float h );
|
||||
|
||||
// LinearDepth(depthZW, A, B) -> B / (depthZW - A)
|
||||
void R_LinearDepthConstantsFromProjectionMatrix( const float* projMatrix, float* A, float* B );
|
||||
void R_LinearDepthConstantsFromClipPlanes( float zNear, float zFar, float* A, float* B );
|
||||
void RB_LinearDepthConstants( float* A, float* B );
|
||||
// LinearDepth(depthZW, A, B, C) -> A / (B + depthZW * C)
|
||||
void R_LinearDepthConstantsFromClipPlanes( float zNear, float zFar, vec3_t constants );
|
||||
void RB_LinearDepthConstants( vec3_t constants );
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -483,23 +483,17 @@ void R_MakeOrthoProjectionMatrix( matrix4x4_t m, float w, float h )
|
|||
}
|
||||
|
||||
|
||||
void R_LinearDepthConstantsFromProjectionMatrix( const float* projMatrix, float* A, float* B )
|
||||
void R_LinearDepthConstantsFromClipPlanes( float n, float f, vec3_t constants )
|
||||
{
|
||||
*A = -projMatrix[2 * 4 + 2];
|
||||
*B = projMatrix[3 * 4 + 2];
|
||||
constants[0] = f * n;
|
||||
constants[1] = n;
|
||||
constants[2] = f - n;
|
||||
}
|
||||
|
||||
|
||||
void R_LinearDepthConstantsFromClipPlanes( float n, float f, float* A, float* B )
|
||||
void RB_LinearDepthConstants( vec3_t constants )
|
||||
{
|
||||
*A = -n / (f - n);
|
||||
*B = f * (n / (f - n));
|
||||
}
|
||||
|
||||
|
||||
void RB_LinearDepthConstants( float* A, float* B )
|
||||
{
|
||||
R_LinearDepthConstantsFromProjectionMatrix( backEnd.viewParms.projectionMatrix, A, B );
|
||||
R_LinearDepthConstantsFromClipPlanes( backEnd.viewParms.zNear, backEnd.viewParms.zFar, constants );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -241,20 +241,31 @@ void CompileVertexShader(const char* headerPath, const char* shaderPath, const c
|
|||
CompileShader(args, _countof(extras), extras);
|
||||
}
|
||||
|
||||
void CompilePixelShader(const char* headerPath, const char* shaderPath, const char* varName)
|
||||
void CompilePixelShader(const char* headerPath, const char* shaderPath, const char* varName, int psOptionCount = 0, ...)
|
||||
{
|
||||
const char* extras[] =
|
||||
int psExtraCount = 4;
|
||||
const char* psExtras[64] =
|
||||
{
|
||||
"-D", "PIXEL_SHADER=1",
|
||||
"-Vn", HeaderVariable(va("g_%s_ps", varName))
|
||||
};
|
||||
|
||||
assert(psExtraCount + psOptionCount <= _countof(psExtras));
|
||||
|
||||
va_list argPtr;
|
||||
va_start(argPtr, psOptionCount);
|
||||
for(int i = 0; i < psOptionCount; i++)
|
||||
{
|
||||
psExtras[psExtraCount++] = va_arg(argPtr, const char*);
|
||||
}
|
||||
va_end(argPtr);
|
||||
|
||||
ShaderArgs args;
|
||||
args.entryPoint = "ps";
|
||||
args.headerPath = headerPath;
|
||||
args.shaderPath = shaderPath;
|
||||
args.targetProfile = targetPS;
|
||||
CompileShader(args, _countof(extras), extras);
|
||||
CompileShader(args, psExtraCount, psExtras);
|
||||
}
|
||||
|
||||
void CompileCompute(const char* headerPath, const char* shaderPath, const char* varName)
|
||||
|
@ -412,6 +423,7 @@ void ProcessCRP()
|
|||
CompileGraphics("opaque.h", "opaque.hlsl", "opaque");
|
||||
CompileGraphics("transp_draw.h", "transp_draw.hlsl", "transp_draw");
|
||||
CompilePixelShader("transp_resolve.h", "transp_resolve.hlsl", "transp_resolve");
|
||||
CompilePixelShader("transp_resolve_vol.h", "transp_resolve.hlsl", "transp_resolve_vol", 1, "-D VOLUMETRIC_LIGHT=1");
|
||||
CompilePixelShader("tone_map.h", "tone_map.hlsl", "tone_map");
|
||||
CompilePixelShader("tone_map_inverse.h", "tone_map_inverse.hlsl", "tone_map_inverse");
|
||||
CompilePixelShader("accumdof_accum.h", "accumdof_accum.hlsl", "accum");
|
||||
|
@ -424,8 +436,6 @@ void ProcessCRP()
|
|||
CompileCompute("gatherdof_fill.h", "gatherdof_fill.hlsl", "fill");
|
||||
CompilePixelShader("gatherdof_combine.h", "gatherdof_combine.hlsl", "combine");
|
||||
CompilePixelShader("gatherdof_debug.h", "gatherdof_debug.hlsl", "debug");
|
||||
CompileGraphics("fog_inside.h", "fog_inside.hlsl", "inside");
|
||||
CompileGraphics("fog_outside.h", "fog_outside.hlsl", "outside");
|
||||
CompilePixelShader("magnifier.h", "magnifier.hlsl", "magnifier");
|
||||
CompilePixelShader("dl_draw.h", "dl_draw.hlsl", "dl_draw");
|
||||
CompilePixelShader("dl_denoising.h", "dl_denoising.hlsl", "dl_denoising");
|
||||
|
@ -440,6 +450,38 @@ void ProcessCRP()
|
|||
CompileCompute("mblur_tile_max.h", "mblur_tile_max.hlsl", "tile_max");
|
||||
CompilePixelShader("mblur_blur.h", "mblur_blur.hlsl", "blur");
|
||||
CompilePixelShader("mblur_pack.h", "mblur_pack.hlsl", "pack");
|
||||
CompilePixelShader("sun_overlay.h", "sun_overlay.hlsl", "sun_overlay");
|
||||
CompilePixelShader("sun_visibility.h", "sun_visibility.hlsl", "sun_visibility");
|
||||
CompilePixelShader("sun_blur.h", "sun_blur.hlsl", "sun_blur");
|
||||
const char* vlComputeShaders[] =
|
||||
{
|
||||
#if 0
|
||||
"vl_particles_dispatch",
|
||||
"vl_particles_preprocess_extinction",
|
||||
"vl_particles_preprocess_frustum",
|
||||
"vl_extinction_injection_particles",
|
||||
"vl_frustum_injection_particles",
|
||||
#endif
|
||||
"vl_extinction_injection_fog",
|
||||
"vl_frustum_anisotropy_average",
|
||||
"vl_frustum_injection_fog",
|
||||
"vl_frustum_inscatter_ambient",
|
||||
"vl_frustum_inscatter_point_light",
|
||||
"vl_frustum_inscatter_sunlight",
|
||||
"vl_frustum_raymarch",
|
||||
"vl_frustum_sunlight_visibility",
|
||||
"vl_frustum_temporal",
|
||||
"vl_shadow_point_light",
|
||||
"vl_shadow_sun"
|
||||
};
|
||||
for(int i = 0; i < _countof(vlComputeShaders); i++)
|
||||
{
|
||||
const char* const s = vlComputeShaders[i];
|
||||
CompileCompute(va("%s.h", s), va("%s.hlsl", s), s);
|
||||
}
|
||||
CompileGraphics("vl_debug_ambient.h", "vl_debug_ambient.hlsl", "vl_debug_ambient");
|
||||
CompileGraphics("vl_debug_extinction.h", "vl_debug_extinction.hlsl", "vl_debug_extinction");
|
||||
CompileGraphics("vl_debug_shadow_sun.h", "vl_debug_shadow_sun.hlsl", "vl_debug_shadow_sun");
|
||||
CompileCompute("depth_pyramid.h", "depth_pyramid.hlsl", "depth_pyramid");
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,6 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_dof_accum.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_gather.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dynamic_lights.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_fog.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_gbuffer_viz.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
|
@ -139,9 +138,12 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sun_editor.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sunlight.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_tone_map.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_draw.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_resolve.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_volumetric_light.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_post.cpp" />
|
||||
|
@ -202,12 +204,6 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\dl_draw.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_outside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fullscreen.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -283,6 +279,15 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_blur.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_overlay.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_visibility.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -298,6 +303,63 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\ui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_ambient.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_extinction.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_shadow_sun.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_fog.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_particles.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_anisotropy_average.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_fog.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_particles.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_ambient.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_point_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_sunlight.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_raymarch.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_sunlight_visibility.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_temporal.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_dispatch.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_extinction.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_frustum.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_point_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_sun.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\wireframe_normals.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -357,13 +419,14 @@
|
|||
<None Include="..\..\code\renderer\shaders\crp\alpha_test.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\common.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\dof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\fullscreen.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\gatherdof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\oit.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\raytracing.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\scene_view.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\simplex_noise.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\typedefs.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\vl_common.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\shared.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\smaa.hlsli" />
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_dof_accum.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_gather.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dynamic_lights.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_fog.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_gbuffer_viz.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
|
@ -43,9 +42,12 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sun_editor.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sunlight.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_tone_map.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_draw.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_resolve.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_volumetric_light.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_post.cpp" />
|
||||
|
@ -106,12 +108,6 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\dl_draw.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_inside.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_outside.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fullscreen.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -187,6 +183,15 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_blur.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_overlay.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_visibility.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -202,6 +207,63 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\ui.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_ambient.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_extinction.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_shadow_sun.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_fog.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_particles.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_anisotropy_average.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_fog.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_particles.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_ambient.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_point_light.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_sunlight.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_raymarch.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_sunlight_visibility.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_temporal.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_dispatch.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_extinction.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_frustum.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_point_light.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_sun.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\wireframe_normals.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -273,9 +335,6 @@
|
|||
<None Include="..\..\code\renderer\shaders\crp\dof.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\fog.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\fullscreen.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
|
@ -291,9 +350,15 @@
|
|||
<None Include="..\..\code\renderer\shaders\crp\scene_view.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\simplex_noise.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\typedefs.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\vl_common.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\grp\fog.hlsli">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</None>
|
||||
|
|
|
@ -132,7 +132,6 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_dof_accum.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_gather.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dynamic_lights.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_fog.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_gbuffer_viz.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
|
@ -141,9 +140,12 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sun_editor.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sunlight.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_tone_map.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_draw.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_resolve.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_volumetric_light.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_post.cpp" />
|
||||
|
@ -204,12 +206,6 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\dl_draw.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_outside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fullscreen.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -285,6 +281,15 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_blur.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_overlay.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_visibility.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -300,6 +305,63 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\ui.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_ambient.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_extinction.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_shadow_sun.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_fog.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_particles.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_anisotropy_average.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_fog.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_particles.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_ambient.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_point_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_sunlight.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_raymarch.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_sunlight_visibility.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_temporal.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_dispatch.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_extinction.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_frustum.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_point_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_sun.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\wireframe_normals.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -359,13 +421,14 @@
|
|||
<None Include="..\..\code\renderer\shaders\crp\alpha_test.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\common.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\dof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\fullscreen.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\gatherdof.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\oit.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\raytracing.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\scene_view.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\simplex_noise.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\typedefs.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\crp\vl_common.h.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\fog.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\shared.hlsli" />
|
||||
<None Include="..\..\code\renderer\shaders\grp\smaa.hlsli" />
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_dof_accum.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dof_gather.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_dynamic_lights.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_fog.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_gbuffer_viz.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
|
@ -43,9 +42,12 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sun_editor.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_sunlight.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_tone_map.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_draw.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_transp_resolve.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_volumetric_light.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\grp_post.cpp" />
|
||||
|
@ -106,12 +108,6 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\dl_draw.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_inside.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fog_outside.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\fullscreen.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -187,6 +183,15 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_blur.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_overlay.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\sun_visibility.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -202,6 +207,63 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\ui.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_ambient.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_extinction.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_debug_shadow_sun.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_fog.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_extinction_injection_particles.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_anisotropy_average.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_fog.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_injection_particles.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_ambient.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_point_light.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_inscatter_sunlight.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_raymarch.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_sunlight_visibility.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_frustum_temporal.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_dispatch.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_extinction.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_particles_preprocess_frustum.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_point_light.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\vl_shadow_sun.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\wireframe_normals.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -273,9 +335,6 @@
|
|||
<None Include="..\..\code\renderer\shaders\crp\dof.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\fog.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\fullscreen.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
|
@ -291,9 +350,15 @@
|
|||
<None Include="..\..\code\renderer\shaders\crp\scene_view.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\simplex_noise.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\typedefs.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\crp\vl_common.h.hlsli">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</None>
|
||||
<None Include="..\..\code\renderer\shaders\grp\fog.hlsli">
|
||||
<Filter>shaders\grp</Filter>
|
||||
</None>
|
||||
|
|
Loading…
Reference in a new issue