mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2025-02-21 11:21:32 +00:00
implemented dynamic lights
This commit is contained in:
parent
ccb9827b03
commit
ffde1f2b1b
16 changed files with 602 additions and 100 deletions
|
@ -304,6 +304,16 @@ struct FrameStats
|
||||||
int skippedFrames;
|
int skippedFrames;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BatchType
|
||||||
|
{
|
||||||
|
enum Id
|
||||||
|
{
|
||||||
|
Standard,
|
||||||
|
DynamicLight,
|
||||||
|
Count
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct World
|
struct World
|
||||||
{
|
{
|
||||||
void Init();
|
void Init();
|
||||||
|
@ -312,7 +322,7 @@ struct World
|
||||||
void Begin();
|
void Begin();
|
||||||
void End();
|
void End();
|
||||||
void DrawPrePass(const drawSceneViewCommand_t& cmd);
|
void DrawPrePass(const drawSceneViewCommand_t& cmd);
|
||||||
void BeginBatch(const shader_t* shader, bool hasStaticGeo);
|
void BeginBatch(const shader_t* shader, bool hasStaticGeo, BatchType::Id batchType);
|
||||||
void EndBatch();
|
void EndBatch();
|
||||||
void EndSkyBatch();
|
void EndSkyBatch();
|
||||||
void RestartBatch();
|
void RestartBatch();
|
||||||
|
@ -322,6 +332,8 @@ struct World
|
||||||
void BindVertexBuffers(bool staticGeo, uint32_t firstStage, uint32_t stageCount);
|
void BindVertexBuffers(bool staticGeo, uint32_t firstStage, uint32_t stageCount);
|
||||||
void BindIndexBuffer(bool staticGeo);
|
void BindIndexBuffer(bool staticGeo);
|
||||||
void DrawFog();
|
void DrawFog();
|
||||||
|
void DrawLitSurfaces(dlight_t* dl, bool opaque);
|
||||||
|
void DrawDynamicLights(bool opaque);
|
||||||
void DrawSkyBox();
|
void DrawSkyBox();
|
||||||
void DrawClouds();
|
void DrawClouds();
|
||||||
|
|
||||||
|
@ -356,6 +368,7 @@ struct World
|
||||||
uint32_t boundStaticVertexBuffersFirst;
|
uint32_t boundStaticVertexBuffersFirst;
|
||||||
uint32_t boundStaticVertexBuffersCount;
|
uint32_t boundStaticVertexBuffersCount;
|
||||||
HPipeline batchPSO;
|
HPipeline batchPSO;
|
||||||
|
BatchType::Id batchType;
|
||||||
bool batchHasStaticGeo;
|
bool batchHasStaticGeo;
|
||||||
int psoChangeCount;
|
int psoChangeCount;
|
||||||
bool batchDepthHack;
|
bool batchDepthHack;
|
||||||
|
@ -384,6 +397,17 @@ struct World
|
||||||
// shader trace
|
// shader trace
|
||||||
HBuffer traceRenderBuffer;
|
HBuffer traceRenderBuffer;
|
||||||
HBuffer traceReadbackBuffer;
|
HBuffer traceReadbackBuffer;
|
||||||
|
|
||||||
|
// dynamic lights
|
||||||
|
HRootSignature dlRootSignature;
|
||||||
|
HPipeline dlPipelines[CT_COUNT * 2 * 2]; // { cull type, polygon offset, depth test }
|
||||||
|
bool dlOpaque;
|
||||||
|
float dlIntensity; // 1 for most surfaces, but can be scaled down for liquids etc.
|
||||||
|
bool dlDepthTestEqual;
|
||||||
|
// quick explanation on why dlOpaque is useful in the first place:
|
||||||
|
// - opaque surfaces can have a diffuse texture whose alpha isn't 255 everywhere
|
||||||
|
// - when that happens and we multiply the color by the the alpha (DL uses additive blending),
|
||||||
|
// we get "light holes" in opaque surfaces, which is not what we want
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UI
|
struct UI
|
||||||
|
|
|
@ -43,6 +43,11 @@ namespace fog_outside
|
||||||
{
|
{
|
||||||
#include "hlsl/fog_outside_ps.h"
|
#include "hlsl/fog_outside_ps.h"
|
||||||
}
|
}
|
||||||
|
namespace dyn_light
|
||||||
|
{
|
||||||
|
#include "hlsl/dynamic_light_vs.h"
|
||||||
|
#include "hlsl/dynamic_light_ps.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
|
@ -66,6 +71,26 @@ struct FogPixelRC
|
||||||
float colorDepth[4];
|
float colorDepth[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DynLightVertexRC
|
||||||
|
{
|
||||||
|
float modelViewMatrix[16];
|
||||||
|
float projectionMatrix[16];
|
||||||
|
float osLightPos[4];
|
||||||
|
float osEyePos[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DynLightPixelRC
|
||||||
|
{
|
||||||
|
uint32_t stageIndices; // low 16 = texture, high 16 = sampler
|
||||||
|
uint32_t pad0[3];
|
||||||
|
float color[3];
|
||||||
|
float recSqrRadius; // 1 / (r * r)
|
||||||
|
float greyscale;
|
||||||
|
float intensity;
|
||||||
|
float opaque;
|
||||||
|
float pad1;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,15 +110,20 @@ static const uint32_t zppMaxIndexCount = 8 * zppMaxVertexCount;
|
||||||
static uint32_t zppIndices[zppMaxIndexCount];
|
static uint32_t zppIndices[zppMaxIndexCount];
|
||||||
|
|
||||||
|
|
||||||
static bool HasStaticGeo(const drawSurf_t* drawSurf, const shader_t* shader)
|
static bool HasStaticGeo(int staticGeoChunk, const shader_t* shader)
|
||||||
{
|
{
|
||||||
|
if(forceDynamic)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// @NOTE: the shader->isDynamic check is needed because of the shader editing feature
|
// @NOTE: the shader->isDynamic check is needed because of the shader editing feature
|
||||||
// without it, an edited shader that changes vertex attributes won't display correctly
|
// without it, an edited shader that changes vertex attributes won't display correctly
|
||||||
// because the original "baked" vertex attributes would be used instead
|
// because the original "baked" vertex attributes would be used instead
|
||||||
return
|
return
|
||||||
!shader->isDynamic &&
|
!shader->isDynamic &&
|
||||||
drawSurf->staticGeoChunk > 0 &&
|
staticGeoChunk > 0 &&
|
||||||
drawSurf->staticGeoChunk < ARRAY_LEN(grp.world.statChunks);
|
staticGeoChunk < ARRAY_LEN(grp.world.statChunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateEntityData(bool& depthHack, int entityNum, double originalTime)
|
static void UpdateEntityData(bool& depthHack, int entityNum, double originalTime)
|
||||||
|
@ -130,6 +160,11 @@ static void UpdateEntityData(bool& depthHack, int entityNum, double originalTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetDynamicLightPipelineIndex(cullType_t cullType, qbool polygonOffset, qbool depthTestEquals)
|
||||||
|
{
|
||||||
|
return (int)cullType + CT_COUNT * (int)polygonOffset + CT_COUNT * 2 * (int)depthTestEquals;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void World::Init()
|
void World::Init()
|
||||||
{
|
{
|
||||||
|
@ -294,6 +329,22 @@ void World::Init()
|
||||||
desc.memoryUsage = MemoryUsage::Readback;
|
desc.memoryUsage = MemoryUsage::Readback;
|
||||||
traceReadbackBuffer = CreateBuffer(desc);
|
traceReadbackBuffer = CreateBuffer(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// dynamic lights
|
||||||
|
//
|
||||||
|
{
|
||||||
|
RootSignatureDesc desc("dynamic lights");
|
||||||
|
desc.usingVertexBuffers = true;
|
||||||
|
desc.samplerCount = ARRAY_LEN(grp.samplers);
|
||||||
|
desc.samplerVisibility = ShaderStages::PixelBit;
|
||||||
|
desc.genericVisibility = ShaderStages::VertexBit | ShaderStages::PixelBit;
|
||||||
|
desc.AddRange(DescriptorType::Texture, 0, MAX_DRAWIMAGES * 2);
|
||||||
|
desc.AddRange(DescriptorType::RWBuffer, MAX_DRAWIMAGES * 2, 1);
|
||||||
|
desc.constants[ShaderStage::Vertex].byteCount = sizeof(DynLightVertexRC);
|
||||||
|
desc.constants[ShaderStage::Pixel].byteCount = sizeof(DynLightPixelRC);
|
||||||
|
dlRootSignature = CreateRootSignature(desc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -325,6 +376,37 @@ void World::Init()
|
||||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||||
fogInsidePipeline = CreateGraphicsPipeline(desc);
|
fogInsidePipeline = CreateGraphicsPipeline(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// dynamic lights
|
||||||
|
//
|
||||||
|
{
|
||||||
|
GraphicsPipelineDesc desc("dynamic light opaque", dlRootSignature);
|
||||||
|
desc.shortLifeTime = true;
|
||||||
|
desc.vertexShader = ShaderByteCode(dyn_light::g_vs);
|
||||||
|
desc.pixelShader = ShaderByteCode(dyn_light::g_ps);
|
||||||
|
desc.depthStencil.enableDepthWrites = false;
|
||||||
|
desc.rasterizer.clampDepth = r_depthClamp->integer != 0;
|
||||||
|
desc.AddRenderTarget(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE, grp.renderTargetFormat);
|
||||||
|
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||||
|
desc.vertexLayout.AddAttribute(1, ShaderSemantic::Normal, DataType::Float32, 3, 0);
|
||||||
|
desc.vertexLayout.AddAttribute(2, ShaderSemantic::TexCoord, DataType::Float32, 2, 0);
|
||||||
|
desc.vertexLayout.AddAttribute(3, ShaderSemantic::Color, DataType::UNorm8, 4, 0);
|
||||||
|
for(int cullType = 0; cullType < CT_COUNT; ++cullType)
|
||||||
|
{
|
||||||
|
desc.rasterizer.cullMode = (cullType_t)cullType;
|
||||||
|
for(int polygonOffset = 0; polygonOffset < 2; ++polygonOffset)
|
||||||
|
{
|
||||||
|
desc.rasterizer.polygonOffset = polygonOffset != 0;
|
||||||
|
for(int depthTestEquals = 0; depthTestEquals < 2; ++depthTestEquals)
|
||||||
|
{
|
||||||
|
desc.depthStencil.depthComparison = depthTestEquals ? ComparisonFunction::Equal : ComparisonFunction::GreaterEqual;
|
||||||
|
const int index = GetDynamicLightPipelineIndex((cullType_t)cullType, (qbool)polygonOffset, (qbool)depthTestEquals);
|
||||||
|
dlPipelines[index] = CreateGraphicsPipeline(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::BeginFrame()
|
void World::BeginFrame()
|
||||||
|
@ -413,8 +495,6 @@ void World::Begin()
|
||||||
|
|
||||||
void World::End()
|
void World::End()
|
||||||
{
|
{
|
||||||
EndBatch();
|
|
||||||
|
|
||||||
grp.renderMode = RenderMode::None;
|
grp.renderMode = RenderMode::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +562,7 @@ void World::DrawPrePass(const drawSceneViewCommand_t& cmd)
|
||||||
CmdDrawIndexed(fullIndexCount, firstIndex, 0);
|
CmdDrawIndexed(fullIndexCount, firstIndex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::BeginBatch(const shader_t* shader, bool hasStaticGeo)
|
void World::BeginBatch(const shader_t* shader, bool hasStaticGeo, BatchType::Id type)
|
||||||
{
|
{
|
||||||
tess.numVertexes = 0;
|
tess.numVertexes = 0;
|
||||||
tess.numIndexes = 0;
|
tess.numIndexes = 0;
|
||||||
|
@ -497,6 +577,7 @@ void World::BeginBatch(const shader_t* shader, bool hasStaticGeo)
|
||||||
tess.shaderTime = tess.shader->clampTime;
|
tess.shaderTime = tess.shader->clampTime;
|
||||||
}
|
}
|
||||||
batchHasStaticGeo = hasStaticGeo;
|
batchHasStaticGeo = hasStaticGeo;
|
||||||
|
batchType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::EndBatch()
|
void World::EndBatch()
|
||||||
|
@ -508,17 +589,23 @@ void World::EndBatch()
|
||||||
tess.shader->numStages == 0 ||
|
tess.shader->numStages == 0 ||
|
||||||
tess.shader->numPipelines <= 0)
|
tess.shader->numPipelines <= 0)
|
||||||
{
|
{
|
||||||
// @TODO: make sure we never get tess.shader->numStages 0 here in the first place
|
goto clean_up;
|
||||||
tess.numVertexes = 0;
|
}
|
||||||
tess.numIndexes = 0;
|
|
||||||
return;
|
if(batchType == BatchType::DynamicLight)
|
||||||
|
{
|
||||||
|
if(tess.shader->lightingStages[ST_DIFFUSE] < 0 ||
|
||||||
|
tess.shader->lightingStages[ST_DIFFUSE] >= MAX_SHADER_STAGES)
|
||||||
|
{
|
||||||
|
goto clean_up;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for debugging of sort order issues, stop rendering after a given sort value
|
// for debugging of sort order issues, stop rendering after a given sort value
|
||||||
if(r_debugSort->value > 0.0f &&
|
if(r_debugSort->value > 0.0f &&
|
||||||
r_debugSort->value < tess.shader->sort)
|
r_debugSort->value < tess.shader->sort)
|
||||||
{
|
{
|
||||||
return;
|
goto clean_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryBuffers& db = dynBuffers[GetFrameIndex()];
|
GeometryBuffers& db = dynBuffers[GetFrameIndex()];
|
||||||
|
@ -526,17 +613,29 @@ void World::EndBatch()
|
||||||
!db.indexBuffer.CanAdd(indexCount))
|
!db.indexBuffer.CanAdd(indexCount))
|
||||||
{
|
{
|
||||||
Q_assert(!"Dynamic buffer too small!");
|
Q_assert(!"Dynamic buffer too small!");
|
||||||
return;
|
goto clean_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shader_t* const shader = tess.shader;
|
const shader_t* const shader = tess.shader;
|
||||||
if(!tess.deformsPreApplied)
|
if(!tess.deformsPreApplied)
|
||||||
{
|
{
|
||||||
RB_DeformTessGeometry(0, vertexCount, 0, indexCount);
|
RB_DeformTessGeometry(0, vertexCount, 0, indexCount);
|
||||||
for(int s = 0; s < shader->numStages; ++s)
|
if(batchType == BatchType::DynamicLight)
|
||||||
{
|
{
|
||||||
R_ComputeColors(shader->stages[s], tess.svars[s], 0, vertexCount);
|
const int stageIndex = shader->lightingStages[ST_DIFFUSE];
|
||||||
R_ComputeTexCoords(shader->stages[s], tess.svars[s], 0, vertexCount, qfalse);
|
if(stageIndex >= 0 && stageIndex < MAX_SHADER_STAGES)
|
||||||
|
{
|
||||||
|
R_ComputeColors(shader->stages[stageIndex], tess.svars[0], 0, vertexCount);
|
||||||
|
R_ComputeTexCoords(shader->stages[stageIndex], tess.svars[0], 0, vertexCount, qfalse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(int s = 0; s < shader->numStages; ++s)
|
||||||
|
{
|
||||||
|
R_ComputeColors(shader->stages[s], tess.svars[s], 0, vertexCount);
|
||||||
|
R_ComputeTexCoords(shader->stages[s], tess.svars[s], 0, vertexCount, qfalse);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,53 +674,96 @@ void World::EndBatch()
|
||||||
batchOldShadingRate = batchShadingRate;
|
batchOldShadingRate = batchShadingRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int p = 0; p < shader->numPipelines; ++p)
|
if(batchType == BatchType::DynamicLight)
|
||||||
{
|
{
|
||||||
const pipeline_t& pipeline = shader->pipelines[p];
|
const dlight_t* const dl = tess.light;
|
||||||
const int psoIndex = backEnd.viewParms.isMirror ? pipeline.mirrorPipeline : pipeline.pipeline;
|
const int stageIndex = tess.shader->lightingStages[ST_DIFFUSE];
|
||||||
if(batchPSO != grp.psos[psoIndex].pipeline)
|
const image_t* image = GetBundleImage(shader->stages[stageIndex]->bundle);
|
||||||
|
const uint32_t texIdx = image->textureIndex;
|
||||||
|
const uint32_t sampIdx = GetSamplerIndex(image);
|
||||||
|
Q_assert(texIdx > 0);
|
||||||
|
|
||||||
|
const int pipelineIndex = GetDynamicLightPipelineIndex(shader->cullType, shader->polygonOffset, dlDepthTestEqual);
|
||||||
|
const HPipeline pipeline = dlPipelines[pipelineIndex];
|
||||||
|
if(batchPSO != pipeline)
|
||||||
{
|
{
|
||||||
batchPSO = grp.psos[psoIndex].pipeline;
|
batchPSO = pipeline;
|
||||||
CmdBindPipeline(batchPSO);
|
CmdBindPipeline(batchPSO);
|
||||||
psoChangeCount++;
|
psoChangeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldVertexRC vertexRC = {};
|
DynLightVertexRC vertexRC = {};
|
||||||
memcpy(vertexRC.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(vertexRC.modelViewMatrix));
|
memcpy(vertexRC.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(vertexRC.modelViewMatrix));
|
||||||
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
|
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
|
||||||
memcpy(vertexRC.clipPlane, clipPlane, sizeof(vertexRC.clipPlane));
|
VectorCopy(dl->transformed, vertexRC.osLightPos);
|
||||||
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Vertex, &vertexRC);
|
vertexRC.osLightPos[3] = 1.0f;
|
||||||
|
VectorCopy(backEnd.orient.viewOrigin, vertexRC.osEyePos);
|
||||||
|
vertexRC.osEyePos[3] = 1.0f;
|
||||||
|
CmdSetRootConstants(dlRootSignature, ShaderStage::Vertex, &vertexRC);
|
||||||
|
|
||||||
WorldPixelRC pixelRC = {};
|
DynLightPixelRC pixelRC = {};
|
||||||
pixelRC.greyscale = tess.greyscale;
|
pixelRC.greyscale = tess.greyscale;
|
||||||
pixelRC.frameSeed = grp.frameSeed;
|
pixelRC.stageIndices = (sampIdx << 16) | (texIdx);
|
||||||
pixelRC.noiseScale = r_ditherStrength->value;
|
VectorCopy(tess.light->color, pixelRC.color);
|
||||||
pixelRC.invBrightness = 1.0f / r_brightness->value;
|
pixelRC.recSqrRadius = 1.0f / Square(dl->radius);
|
||||||
pixelRC.invGamma = 1.0f / r_gamma->value;
|
pixelRC.intensity = dlIntensity;
|
||||||
pixelRC.shaderTrace = (uint32_t)!!tr.traceWorldShader;
|
pixelRC.opaque = dlOpaque ? 1.0f : 0.0f;
|
||||||
pixelRC.shaderIndex = (uint32_t)shader->index;
|
CmdSetRootConstants(dlRootSignature, ShaderStage::Pixel, &pixelRC);
|
||||||
pixelRC.frameIndex = RHI::GetFrameIndex();
|
|
||||||
pixelRC.centerPixel = (glConfig.vidWidth / 2) | ((glConfig.vidHeight / 2) << 16);
|
|
||||||
for(int s = 0; s < pipeline.numStages; ++s)
|
|
||||||
{
|
|
||||||
const image_t* image = GetBundleImage(shader->stages[pipeline.firstStage + s]->bundle);
|
|
||||||
const uint32_t texIdx = image->textureIndex;
|
|
||||||
const uint32_t sampIdx = GetSamplerIndex(image);
|
|
||||||
Q_assert(texIdx > 0);
|
|
||||||
pixelRC.stageIndices[s] = (sampIdx << 16) | (texIdx);
|
|
||||||
}
|
|
||||||
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Pixel, &pixelRC);
|
|
||||||
|
|
||||||
BindVertexBuffers(batchHasStaticGeo, pipeline.firstStage, pipeline.numStages);
|
BindVertexBuffers(batchHasStaticGeo, 0, 1);
|
||||||
|
|
||||||
CmdDrawIndexed(indexCount, db.indexBuffer.batchFirst, batchHasStaticGeo ? 0 : db.vertexBuffers.batchFirst);
|
CmdDrawIndexed(indexCount, db.indexBuffer.batchFirst, batchHasStaticGeo ? 0 : db.vertexBuffers.batchFirst);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(int p = 0; p < shader->numPipelines; ++p)
|
||||||
|
{
|
||||||
|
const pipeline_t& pipeline = shader->pipelines[p];
|
||||||
|
const int psoIndex = backEnd.viewParms.isMirror ? pipeline.mirrorPipeline : pipeline.pipeline;
|
||||||
|
if(batchPSO != grp.psos[psoIndex].pipeline)
|
||||||
|
{
|
||||||
|
batchPSO = grp.psos[psoIndex].pipeline;
|
||||||
|
CmdBindPipeline(batchPSO);
|
||||||
|
psoChangeCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldVertexRC vertexRC = {};
|
||||||
|
memcpy(vertexRC.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(vertexRC.modelViewMatrix));
|
||||||
|
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
|
||||||
|
memcpy(vertexRC.clipPlane, clipPlane, sizeof(vertexRC.clipPlane));
|
||||||
|
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Vertex, &vertexRC);
|
||||||
|
|
||||||
|
WorldPixelRC pixelRC = {};
|
||||||
|
pixelRC.greyscale = tess.greyscale;
|
||||||
|
pixelRC.frameSeed = grp.frameSeed;
|
||||||
|
pixelRC.noiseScale = r_ditherStrength->value;
|
||||||
|
pixelRC.invBrightness = 1.0f / r_brightness->value;
|
||||||
|
pixelRC.invGamma = 1.0f / r_gamma->value;
|
||||||
|
pixelRC.shaderTrace = (uint32_t)!!tr.traceWorldShader;
|
||||||
|
pixelRC.shaderIndex = (uint32_t)shader->index;
|
||||||
|
pixelRC.frameIndex = RHI::GetFrameIndex();
|
||||||
|
pixelRC.centerPixel = (glConfig.vidWidth / 2) | ((glConfig.vidHeight / 2) << 16);
|
||||||
|
for(int s = 0; s < pipeline.numStages; ++s)
|
||||||
|
{
|
||||||
|
const image_t* image = GetBundleImage(shader->stages[pipeline.firstStage + s]->bundle);
|
||||||
|
const uint32_t texIdx = image->textureIndex;
|
||||||
|
const uint32_t sampIdx = GetSamplerIndex(image);
|
||||||
|
Q_assert(texIdx > 0);
|
||||||
|
pixelRC.stageIndices[s] = (sampIdx << 16) | (texIdx);
|
||||||
|
}
|
||||||
|
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Pixel, &pixelRC);
|
||||||
|
|
||||||
|
BindVertexBuffers(batchHasStaticGeo, pipeline.firstStage, pipeline.numStages);
|
||||||
|
CmdDrawIndexed(indexCount, db.indexBuffer.batchFirst, batchHasStaticGeo ? 0 : db.vertexBuffers.batchFirst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!batchHasStaticGeo)
|
if(!batchHasStaticGeo)
|
||||||
{
|
{
|
||||||
db.vertexBuffers.EndBatch(tess.numVertexes);
|
db.vertexBuffers.EndBatch(tess.numVertexes);
|
||||||
}
|
}
|
||||||
db.indexBuffer.EndBatch(tess.numIndexes);
|
db.indexBuffer.EndBatch(tess.numIndexes);
|
||||||
|
|
||||||
|
clean_up:
|
||||||
tess.numVertexes = 0;
|
tess.numVertexes = 0;
|
||||||
tess.numIndexes = 0;
|
tess.numIndexes = 0;
|
||||||
}
|
}
|
||||||
|
@ -662,7 +804,7 @@ void World::EndSkyBatch()
|
||||||
void World::RestartBatch()
|
void World::RestartBatch()
|
||||||
{
|
{
|
||||||
EndBatch();
|
EndBatch();
|
||||||
BeginBatch(tess.shader, batchHasStaticGeo);
|
BeginBatch(tess.shader, batchHasStaticGeo, BatchType::Standard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::DrawGUI()
|
void World::DrawGUI()
|
||||||
|
@ -935,6 +1077,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||||
const shader_t* oldShader = NULL;
|
const shader_t* oldShader = NULL;
|
||||||
int oldEntityNum = -1;
|
int oldEntityNum = -1;
|
||||||
bool oldHasStaticGeo = false;
|
bool oldHasStaticGeo = false;
|
||||||
|
bool forceEntityChange = false;
|
||||||
backEnd.currentEntity = &tr.worldEntity;
|
backEnd.currentEntity = &tr.worldEntity;
|
||||||
|
|
||||||
ShadingRate::Id lowShadingRate = (ShadingRate::Id)r_shadingRate->integer;
|
ShadingRate::Id lowShadingRate = (ShadingRate::Id)r_shadingRate->integer;
|
||||||
|
@ -955,20 +1098,21 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||||
|
|
||||||
CmdSetShadingRate(lowShadingRate);
|
CmdSetShadingRate(lowShadingRate);
|
||||||
batchOldShadingRate = lowShadingRate;
|
batchOldShadingRate = lowShadingRate;
|
||||||
|
DrawDynamicLights(qtrue);
|
||||||
DrawFog();
|
DrawFog();
|
||||||
|
|
||||||
if(transpCount > 0)
|
// needed after DrawDynamicLights
|
||||||
{
|
forceEntityChange = true;
|
||||||
CmdBindRootSignature(grp.uberRootSignature);
|
|
||||||
CmdBindDescriptorTable(grp.uberRootSignature, grp.descriptorTable);
|
|
||||||
CmdBindRenderTargets(1, &grp.renderTarget, &depthTexture);
|
|
||||||
batchPSO = RHI_MAKE_NULL_HANDLE();
|
|
||||||
boundVertexBuffers = BufferFamily::Invalid;
|
|
||||||
boundIndexBuffer = BufferFamily::Invalid;
|
|
||||||
|
|
||||||
const TextureBarrier depthWriteBarrier(depthTexture, ResourceStates::DepthWriteBit);
|
CmdBindRootSignature(grp.uberRootSignature);
|
||||||
CmdBarrier(1, &depthWriteBarrier);
|
CmdBindDescriptorTable(grp.uberRootSignature, grp.descriptorTable);
|
||||||
}
|
CmdBindRenderTargets(1, &grp.renderTarget, &depthTexture);
|
||||||
|
batchPSO = RHI_MAKE_NULL_HANDLE();
|
||||||
|
boundVertexBuffers = BufferFamily::Invalid;
|
||||||
|
boundIndexBuffer = BufferFamily::Invalid;
|
||||||
|
|
||||||
|
const TextureBarrier depthWriteBarrier(depthTexture, ResourceStates::DepthWriteBit);
|
||||||
|
CmdBarrier(1, &depthWriteBarrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
int entityNum;
|
int entityNum;
|
||||||
|
@ -985,7 +1129,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool hasStaticGeo = forceDynamic ? false : HasStaticGeo(drawSurf, shader);
|
const bool hasStaticGeo = HasStaticGeo(drawSurf->staticGeoChunk, shader);
|
||||||
const bool staticChanged = hasStaticGeo != oldHasStaticGeo;
|
const bool staticChanged = hasStaticGeo != oldHasStaticGeo;
|
||||||
const bool shaderChanged = shader != oldShader;
|
const bool shaderChanged = shader != oldShader;
|
||||||
bool entityChanged = entityNum != oldEntityNum;
|
bool entityChanged = entityNum != oldEntityNum;
|
||||||
|
@ -1006,14 +1150,15 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||||
oldHasStaticGeo = hasStaticGeo;
|
oldHasStaticGeo = hasStaticGeo;
|
||||||
EndSkyBatch();
|
EndSkyBatch();
|
||||||
EndBatch();
|
EndBatch();
|
||||||
BeginBatch(shader, hasStaticGeo);
|
BeginBatch(shader, hasStaticGeo, BatchType::Standard);
|
||||||
tess.greyscale = drawSurf->greyscale;
|
tess.greyscale = drawSurf->greyscale;
|
||||||
batchShadingRate = lowShadingRate;
|
batchShadingRate = lowShadingRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(entityChanged)
|
if(entityChanged || forceEntityChange)
|
||||||
{
|
{
|
||||||
UpdateEntityData(batchDepthHack, entityNum, originalTime);
|
UpdateEntityData(batchDepthHack, entityNum, originalTime);
|
||||||
|
forceEntityChange = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hasStaticGeo)
|
if(hasStaticGeo)
|
||||||
|
@ -1022,7 +1167,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||||
if(tess.numIndexes + chunk.indexCount > SHADER_MAX_INDEXES)
|
if(tess.numIndexes + chunk.indexCount > SHADER_MAX_INDEXES)
|
||||||
{
|
{
|
||||||
EndBatch();
|
EndBatch();
|
||||||
BeginBatch(tess.shader, batchHasStaticGeo);
|
BeginBatch(tess.shader, batchHasStaticGeo, BatchType::Standard);
|
||||||
batchShadingRate = lowShadingRate;
|
batchShadingRate = lowShadingRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,12 +1198,17 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
||||||
EndSkyBatch();
|
EndSkyBatch();
|
||||||
EndBatch();
|
EndBatch();
|
||||||
|
|
||||||
CmdSetShadingRate(ShadingRate::SR_1x1);
|
|
||||||
|
|
||||||
if(transpCount <= 0)
|
if(transpCount <= 0)
|
||||||
{
|
{
|
||||||
|
DrawDynamicLights(qtrue);
|
||||||
|
CmdSetShadingRate(lowShadingRate);
|
||||||
|
batchOldShadingRate = lowShadingRate;
|
||||||
DrawFog();
|
DrawFog();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawDynamicLights(qfalse);
|
||||||
|
}
|
||||||
|
|
||||||
db.vertexBuffers.EndUpload();
|
db.vertexBuffers.EndUpload();
|
||||||
db.indexBuffer.EndUpload();
|
db.indexBuffer.EndUpload();
|
||||||
|
@ -1205,6 +1355,154 @@ void World::DrawFog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::DrawLitSurfaces(dlight_t* dl, bool opaque)
|
||||||
|
{
|
||||||
|
if(dl->head == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!opaque && !drawTransparents)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shader_t* shader = NULL;
|
||||||
|
const shader_t* oldShader = NULL;
|
||||||
|
int oldEntityNum = -666;
|
||||||
|
bool oldHasStaticGeo = false;
|
||||||
|
|
||||||
|
// save original time for entity shader offsets
|
||||||
|
const double originalTime = backEnd.refdef.floatTime;
|
||||||
|
|
||||||
|
// draw everything
|
||||||
|
const int liquidFlags = CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER;
|
||||||
|
oldEntityNum = -1;
|
||||||
|
dlOpaque = opaque;
|
||||||
|
backEnd.currentEntity = &tr.worldEntity;
|
||||||
|
tess.light = dl;
|
||||||
|
tess.numVertexes = 0;
|
||||||
|
tess.numIndexes = 0;
|
||||||
|
|
||||||
|
for(litSurf_t* litSurf = dl->head; litSurf != NULL; litSurf = litSurf->next)
|
||||||
|
{
|
||||||
|
backEnd.pc3D[RB_LIT_SURFACES]++;
|
||||||
|
|
||||||
|
int entityNum;
|
||||||
|
R_DecomposeLitSort(litSurf->sort, &entityNum, &shader);
|
||||||
|
|
||||||
|
if(opaque && shader->sort > SS_OPAQUE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!opaque && shader->sort <= SS_OPAQUE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int stageIndex = shader->lightingStages[ST_DIFFUSE];
|
||||||
|
if(stageIndex < 0 || stageIndex >= shader->numStages)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool hasStaticGeo = HasStaticGeo(litSurf->staticGeoChunk, shader);
|
||||||
|
const bool staticChanged = hasStaticGeo != oldHasStaticGeo;
|
||||||
|
const bool shaderChanged = shader != oldShader;
|
||||||
|
bool entityChanged = entityNum != oldEntityNum;
|
||||||
|
Q_assert(shader != NULL);
|
||||||
|
if(!hasStaticGeo && !drawDynamic)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(staticChanged || shaderChanged || entityChanged)
|
||||||
|
{
|
||||||
|
oldShader = shader;
|
||||||
|
oldEntityNum = entityNum;
|
||||||
|
oldHasStaticGeo = hasStaticGeo;
|
||||||
|
EndBatch();
|
||||||
|
BeginBatch(shader, hasStaticGeo, BatchType::DynamicLight);
|
||||||
|
tess.greyscale = litSurf->greyscale;
|
||||||
|
|
||||||
|
const shaderStage_t* const stage = shader->stages[stageIndex];
|
||||||
|
dlIntensity = (shader->contentFlags & liquidFlags) != 0 ? 0.5f : 1.0f;
|
||||||
|
dlDepthTestEqual = opaque || (stage->stateBits & GLS_ATEST_BITS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(entityChanged)
|
||||||
|
{
|
||||||
|
UpdateEntityData(batchDepthHack, entityNum, originalTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TransformDlights(1, dl, &backEnd.orient);
|
||||||
|
|
||||||
|
if(hasStaticGeo)
|
||||||
|
{
|
||||||
|
const StaticGeometryChunk& chunk = statChunks[litSurf->staticGeoChunk];
|
||||||
|
if(tess.numIndexes + chunk.indexCount > SHADER_MAX_INDEXES)
|
||||||
|
{
|
||||||
|
EndBatch();
|
||||||
|
BeginBatch(tess.shader, batchHasStaticGeo, BatchType::DynamicLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(tess.indexes + tess.numIndexes, statIndices + chunk.firstCPUIndex, chunk.indexCount * sizeof(uint32_t));
|
||||||
|
tess.numIndexes += chunk.indexCount;
|
||||||
|
backEnd.pc3D[RB_LIT_INDICES_LATECULL_IN] += chunk.indexCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int oldNumIndexes = tess.numIndexes;
|
||||||
|
R_TessellateSurface(litSurf->surface);
|
||||||
|
backEnd.pc3D[RB_LIT_INDICES_LATECULL_IN] += tess.numIndexes - oldNumIndexes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the contents of the last shader batch
|
||||||
|
if(shader != NULL)
|
||||||
|
{
|
||||||
|
EndBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
backEnd.refdef.floatTime = originalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::DrawDynamicLights(bool opaque)
|
||||||
|
{
|
||||||
|
SCOPED_RENDER_PASS("Dynamic Lights", 1.0f, 0.25f, 0.25f);
|
||||||
|
|
||||||
|
if(r_dynamiclight->integer == 0 ||
|
||||||
|
backEnd.refdef.num_dlights == 0 ||
|
||||||
|
backEnd.viewParms.isMirror)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdBindRootSignature(dlRootSignature);
|
||||||
|
CmdBindDescriptorTable(dlRootSignature, grp.descriptorTable);
|
||||||
|
CmdBindRenderTargets(1, &grp.renderTarget, &depthTexture);
|
||||||
|
batchPSO = RHI_MAKE_NULL_HANDLE();
|
||||||
|
boundVertexBuffers = BufferFamily::Invalid;
|
||||||
|
boundIndexBuffer = BufferFamily::Invalid;
|
||||||
|
|
||||||
|
ShadingRate::Id lowShadingRate = (ShadingRate::Id)r_shadingRate->integer;
|
||||||
|
batchShadingRate = lowShadingRate;
|
||||||
|
batchOldShadingRate = ShadingRate::SR_1x1;
|
||||||
|
CmdSetShadingRate(lowShadingRate);
|
||||||
|
|
||||||
|
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||||
|
batchOldDepthHack = false;
|
||||||
|
batchDepthHack = false;
|
||||||
|
|
||||||
|
tess.numVertexes = 0;
|
||||||
|
tess.numIndexes = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < backEnd.refdef.num_dlights; ++i)
|
||||||
|
{
|
||||||
|
DrawLitSurfaces(&backEnd.refdef.dlights[i], opaque);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void World::DrawSkyBox()
|
void World::DrawSkyBox()
|
||||||
{
|
{
|
||||||
if(!drawSky)
|
if(!drawSky)
|
||||||
|
|
128
code/renderer/hlsl/dynamic_light.hlsl
Normal file
128
code/renderer/hlsl/dynamic_light.hlsl
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
===========================================================================
|
||||||
|
Copyright (C) 2019-2023 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/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
// dynamic light shader
|
||||||
|
|
||||||
|
|
||||||
|
#if VERTEX_SHADER
|
||||||
|
|
||||||
|
struct VIn
|
||||||
|
{
|
||||||
|
float3 position : POSITION;
|
||||||
|
float3 normal : NORMAL;
|
||||||
|
float2 texCoords : TEXCOORD0;
|
||||||
|
float4 color : COLOR0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct VOut
|
||||||
|
{
|
||||||
|
float4 position : SV_Position;
|
||||||
|
float3 normal : NORMAL;
|
||||||
|
float2 texCoords : TEXCOORD0;
|
||||||
|
float4 color : COLOR0;
|
||||||
|
float3 osLightVec : TEXCOORD1;
|
||||||
|
float3 osEyeVec : TEXCOORD2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if VERTEX_SHADER
|
||||||
|
|
||||||
|
cbuffer RootConstants
|
||||||
|
{
|
||||||
|
matrix modelViewMatrix;
|
||||||
|
matrix projectionMatrix;
|
||||||
|
float4 osLightPos;
|
||||||
|
float4 osEyePos;
|
||||||
|
};
|
||||||
|
|
||||||
|
VOut vs(VIn input)
|
||||||
|
{
|
||||||
|
float4 positionVS = mul(modelViewMatrix, float4(input.position.xyz, 1));
|
||||||
|
|
||||||
|
VOut output;
|
||||||
|
output.position = mul(projectionMatrix, positionVS);
|
||||||
|
output.normal = input.normal;
|
||||||
|
output.texCoords = input.texCoords;
|
||||||
|
output.color = input.color;
|
||||||
|
output.osLightVec = osLightPos.xyz - input.position.xyz;
|
||||||
|
output.osEyeVec = osEyePos.xyz - input.position.xyz;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if PIXEL_SHADER
|
||||||
|
|
||||||
|
#include "shared.hlsli"
|
||||||
|
|
||||||
|
cbuffer RootConstants
|
||||||
|
{
|
||||||
|
uint4 stageIndices; // low 16 = texture, high 16 = sampler
|
||||||
|
float3 color;
|
||||||
|
float recSqrRadius; // 1 / (r * r)
|
||||||
|
float greyscale;
|
||||||
|
float intensity;
|
||||||
|
float opaque;
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture2D textures2D[4096] : register(t0);
|
||||||
|
SamplerState samplers[96] : register(s0);
|
||||||
|
|
||||||
|
float BezierEase(float t)
|
||||||
|
{
|
||||||
|
return t * t * (3.0 - 2.0 * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
[earlydepthstencil]
|
||||||
|
float4 ps(VOut input) : SV_Target
|
||||||
|
{
|
||||||
|
// fetch data
|
||||||
|
uint textureIndex = stageIndices.x & 0xFFFF;
|
||||||
|
uint samplerIndex = stageIndices.x >> 16;
|
||||||
|
float lightRecSqrRadius = recSqrRadius;
|
||||||
|
float3 lightColor = color;
|
||||||
|
float4 baseColored = input.color * textures2D[textureIndex].Sample(samplers[samplerIndex], input.texCoords);
|
||||||
|
float4 base = MakeGreyscale(baseColored, greyscale);
|
||||||
|
float3 nL = normalize(input.osLightVec); // normalized object-space light vector
|
||||||
|
float3 nV = normalize(input.osEyeVec); // normalized object-space view vector
|
||||||
|
float3 nN = input.normal; // normalized object-space normal vector
|
||||||
|
|
||||||
|
// light intensity
|
||||||
|
float intensFactor = min(dot(input.osLightVec, input.osLightVec) * lightRecSqrRadius, 1.0);
|
||||||
|
float3 intens = lightColor * BezierEase(1.0 - sqrt(intensFactor));
|
||||||
|
|
||||||
|
// specular reflection term (N.H)
|
||||||
|
float specFactor = min(abs(dot(nN, normalize(nL + nV))), 1.0);
|
||||||
|
float spec = pow(specFactor, 16.0) * 0.25;
|
||||||
|
|
||||||
|
// Lambertian diffuse reflection term (N.L)
|
||||||
|
float diffuse = min(abs(dot(nN, nL)), 1.0);
|
||||||
|
float3 color = (base.rgb * diffuse.rrr + spec.rrr) * intens * intensity;
|
||||||
|
float alpha = lerp(opaque, 1.0, base.a);
|
||||||
|
float4 final = float4(color.rgb * alpha, alpha);
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -29,22 +29,10 @@ to do:
|
||||||
- git cherry-pick c75b2b27fa936854d27dadf458e3ec3b03829561
|
- git cherry-pick c75b2b27fa936854d27dadf458e3ec3b03829561
|
||||||
- https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
|
- https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
|
||||||
- GPU resident vertex data for models: load on demand based on submitted { surface, shader } pairs
|
- GPU resident vertex data for models: load on demand based on submitted { surface, shader } pairs
|
||||||
- reloading a map can lead to a TDR timeout
|
|
||||||
could it be related to the copy queue?
|
|
||||||
use PIX to capture and replay the bad command list?
|
|
||||||
seems to not happen ever since I fixed the usage of the stale depth buffer?!
|
|
||||||
- transparents don't batch properly I think -> entityMergeable support? ("entityMergable" in the code)
|
|
||||||
- use Application Verifier to catch issues
|
- use Application Verifier to catch issues
|
||||||
- tone mapping: look at https://github.com/h3r2tic/tony-mc-mapface
|
- tone mapping: look at https://github.com/h3r2tic/tony-mc-mapface
|
||||||
- ubershader PS: run-time alpha test evaluation to reduce PSO count?
|
- ubershader PS: run-time alpha test evaluation to reduce PSO count?
|
||||||
- mip-map generation: figure out whether out of bounds texture UAV writes are OK or not
|
|
||||||
I think they are in this use case but an explicit confirmation would be nice...
|
|
||||||
- working depth pre-pass (account for cull mode, generate buffers on demand)
|
|
||||||
full depth pre-pass -> Z-buffer is complete and won't get updated by opaque drawing
|
|
||||||
1 full-screen pass per dynamic light, culled early with the depth bounds test -> write out to a light buffer
|
|
||||||
draw opaques, locate the light stage and add the light buffer data to the light stage result
|
|
||||||
- r_depthFade
|
- r_depthFade
|
||||||
- r_dynamiclight
|
|
||||||
- when creating the root signature, validate that neither of the tables have any gap
|
- when creating the root signature, validate that neither of the tables have any gap
|
||||||
- use root signature 1.1 to use the hints that help the drivers optimize out static resources
|
- use root signature 1.1 to use the hints that help the drivers optimize out static resources
|
||||||
- is it possible to force Resource Binding Tier 2 somehow? are we supposed to run on old HW to test? :(
|
- is it possible to force Resource Binding Tier 2 somehow? are we supposed to run on old HW to test? :(
|
||||||
|
@ -57,7 +45,6 @@ to do:
|
||||||
- move UI to the uber shader system, tessellate to generate proper data
|
- move UI to the uber shader system, tessellate to generate proper data
|
||||||
- share structs between HLSL and C++ with .hlsli files -> change cbuffer to ConstantBuffer<MyStruct>
|
- share structs between HLSL and C++ with .hlsli files -> change cbuffer to ConstantBuffer<MyStruct>
|
||||||
- share texture and sampler array sizes between HLSL and C++ with .hlsli files
|
- share texture and sampler array sizes between HLSL and C++ with .hlsli files
|
||||||
- what's the actual fog curve used by Q3?
|
|
||||||
- roq video textures support?
|
- roq video textures support?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -826,6 +813,7 @@ namespace RHI
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mapped = (uint8_t*)MapBuffer(userHBuffer);
|
mapped = (uint8_t*)MapBuffer(userHBuffer);
|
||||||
|
Q_assert(mapped != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
userBuffer.uploading = true;
|
userBuffer.uploading = true;
|
||||||
|
@ -3108,9 +3096,10 @@ namespace RHI
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* mappedPtr;
|
void* mappedPtr = NULL;
|
||||||
D3D(buffer.buffer->Map(0, NULL, &mappedPtr));
|
D3D(buffer.buffer->Map(0, NULL, &mappedPtr));
|
||||||
buffer.mapped = true;
|
buffer.mapped = true;
|
||||||
|
Q_assert(mappedPtr != NULL);
|
||||||
|
|
||||||
return (uint8_t*)mappedPtr;
|
return (uint8_t*)mappedPtr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
backEndData_t* backEndData;
|
backEndData_t* backEndData;
|
||||||
backEndState_t backEnd;
|
backEndState_t backEnd;
|
||||||
|
|
||||||
|
|
||||||
|
// @TODO: remove all this
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
|
||||||
static int64_t startTime;
|
static int64_t startTime;
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
static void RB_Set2D()
|
static void RB_Set2D()
|
||||||
{
|
{
|
||||||
backEnd.projection2D = qtrue;
|
backEnd.projection2D = qtrue;
|
||||||
|
|
|
@ -511,7 +511,7 @@ static const cvarTableItem_t r_cvars[] =
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&r_dynamiclight, "r_dynamiclight", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables dynamic lights",
|
&r_dynamiclight, "r_dynamiclight", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables dynamic lights",
|
||||||
"", 0, "", "" // @TODO: CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE once implemented
|
"Enable dynamic lights", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "For power-ups, muzzle flashes, rockets, explosions, ...", ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&r_lego, "r_lego", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "LEGO(R) texture filtering",
|
&r_lego, "r_lego", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "LEGO(R) texture filtering",
|
||||||
|
|
|
@ -552,6 +552,7 @@ struct litSurf_t {
|
||||||
const surfaceType_t* surface; // any of surface*_t
|
const surfaceType_t* surface; // any of surface*_t
|
||||||
litSurf_t* next;
|
litSurf_t* next;
|
||||||
float greyscale;
|
float greyscale;
|
||||||
|
int staticGeoChunk;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dlight_t {
|
struct dlight_t {
|
||||||
|
@ -837,6 +838,24 @@ enum drawSurfGeneralSort_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum litSurfGeneralSort_t {
|
||||||
|
// dimensions - the sum should stay within 32 bits
|
||||||
|
LITSORT_ENTITY_BITS = 10, // GENTITYNUM_BITS
|
||||||
|
LITSORT_SHADER_BITS = 14, // log2 MAX_SHADERS
|
||||||
|
LITSORT_STATICGEO_BITS = 1,
|
||||||
|
LITSORT_CULLTYPE_BITS = 2, // PSO part 1
|
||||||
|
LITSORT_POLYGONOFFSET_BITS = 1, // PSO part 2
|
||||||
|
LITSORT_DEPTHTEST_BITS = 1, // PSO part 3
|
||||||
|
// offsets
|
||||||
|
LITSORT_ENTITY_INDEX = 0,
|
||||||
|
LITSORT_SHADER_INDEX = LITSORT_ENTITY_INDEX + LITSORT_ENTITY_BITS,
|
||||||
|
LITSORT_STATICGEO_INDEX = LITSORT_SHADER_INDEX + LITSORT_SHADER_BITS,
|
||||||
|
LITSORT_CULLTYPE_INDEX = LITSORT_STATICGEO_INDEX + LITSORT_STATICGEO_BITS,
|
||||||
|
LITSORT_POLYGONOFFSET_INDEX = LITSORT_CULLTYPE_INDEX + LITSORT_CULLTYPE_BITS,
|
||||||
|
LITSORT_DEPTHTEST_INDEX = LITSORT_POLYGONOFFSET_INDEX + LITSORT_POLYGONOFFSET_BITS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#define MAX_TMUS 4
|
#define MAX_TMUS 4
|
||||||
|
|
||||||
|
|
||||||
|
@ -852,15 +871,6 @@ typedef struct {
|
||||||
byte color2D[4];
|
byte color2D[4];
|
||||||
trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
|
trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
|
||||||
|
|
||||||
// dynamic lights data set by the back-end for the GAL
|
|
||||||
qbool dlOpaque; // qtrue when drawing an opaque surface
|
|
||||||
float dlIntensity; // 1 for most surfaces, but can be scaled down for liquids etc.
|
|
||||||
unsigned int dlStateBits; // the state bits to apply for this draw call
|
|
||||||
// quick explanation on why dlOpaque is useful in the first place:
|
|
||||||
// - opaque surfaces can have a diffuse texture whose alpha isn't 255 everywhere
|
|
||||||
// - when that happens and we multiply the color by the the alpha (DL uses additive blending),
|
|
||||||
// we get "light holes" in opaque surfaces, which is not what we want
|
|
||||||
|
|
||||||
qbool renderFrame;
|
qbool renderFrame;
|
||||||
|
|
||||||
int* pc; // current stats set, depending on projection2D
|
int* pc; // current stats set, depending on projection2D
|
||||||
|
@ -1119,9 +1129,11 @@ void R_AddMD3Surfaces( trRefEntity_t *e );
|
||||||
void R_AddPolygonSurfaces();
|
void R_AddPolygonSurfaces();
|
||||||
|
|
||||||
void R_AddDrawSurf(const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk = 0, int zppFirstIndex = 0, int zppIndexCount = 0, float radiusOverZ = 666.0f );
|
void R_AddDrawSurf(const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk = 0, int zppFirstIndex = 0, int zppIndexCount = 0, float radiusOverZ = 666.0f );
|
||||||
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex );
|
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk );
|
||||||
uint64_t R_ComposeSort( int entityNum, const shader_t* shader, int staticGeoChunk );
|
uint64_t R_ComposeSort( int entityNum, const shader_t* shader, int staticGeoChunk );
|
||||||
void R_DecomposeSort( uint64_t sort, int* entityNum, const shader_t** shader );
|
void R_DecomposeSort( uint64_t sort, int* entityNum, const shader_t** shader );
|
||||||
|
uint32_t R_ComposeLitSort( int entityNum, const shader_t* shader, int staticGeoChunk );
|
||||||
|
void R_DecomposeLitSort( uint32_t sort, int* entityNum, const shader_t** shader );
|
||||||
|
|
||||||
|
|
||||||
#define CULL_IN 0 // completely unclipped
|
#define CULL_IN 0 // completely unclipped
|
||||||
|
@ -1311,7 +1323,6 @@ struct shaderCommands_t
|
||||||
vec2_t texCoords[SHADER_MAX_VERTEXES];
|
vec2_t texCoords[SHADER_MAX_VERTEXES];
|
||||||
vec2_t texCoords2[SHADER_MAX_VERTEXES];
|
vec2_t texCoords2[SHADER_MAX_VERTEXES];
|
||||||
color4ub_t vertexColors[SHADER_MAX_VERTEXES];
|
color4ub_t vertexColors[SHADER_MAX_VERTEXES];
|
||||||
unsigned int dlIndexes[SHADER_MAX_INDEXES];
|
|
||||||
stageVars_t svars[MAX_SHADER_STAGES];
|
stageVars_t svars[MAX_SHADER_STAGES];
|
||||||
stageVars_t svarsFog;
|
stageVars_t svarsFog;
|
||||||
|
|
||||||
|
@ -1323,7 +1334,6 @@ struct shaderCommands_t
|
||||||
|
|
||||||
int numIndexes;
|
int numIndexes;
|
||||||
int numVertexes;
|
int numVertexes;
|
||||||
int dlNumIndexes;
|
|
||||||
|
|
||||||
const dlight_t* light;
|
const dlight_t* light;
|
||||||
|
|
||||||
|
|
|
@ -1280,13 +1280,14 @@ static float SurfGreyscaleAmount( const shader_t* shader )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk, int zppFirstIndex, int zppIndexCount, float radiusOverZ )
|
// @TODO: remove the fogIndex argument
|
||||||
|
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int /*fogIndex*/, int staticGeoChunk, int zppFirstIndex, int zppIndexCount, float radiusOverZ )
|
||||||
{
|
{
|
||||||
if (tr.refdef.numDrawSurfs >= MAX_DRAWSURFS)
|
if (tr.refdef.numDrawSurfs >= MAX_DRAWSURFS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
drawSurf_t* const drawSurf = &tr.refdef.drawSurfs[tr.refdef.numDrawSurfs++];
|
drawSurf_t* const drawSurf = &tr.refdef.drawSurfs[tr.refdef.numDrawSurfs++];
|
||||||
drawSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, fogIndex );
|
drawSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, staticGeoChunk );
|
||||||
drawSurf->surface = surface;
|
drawSurf->surface = surface;
|
||||||
drawSurf->model = tr.currentModel != NULL ? tr.currentModel->index : 0;
|
drawSurf->model = tr.currentModel != NULL ? tr.currentModel->index : 0;
|
||||||
drawSurf->shaderNum = shader->index;
|
drawSurf->shaderNum = shader->index;
|
||||||
|
@ -1298,7 +1299,8 @@ void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex )
|
// @TODO: remove the fogIndex argument
|
||||||
|
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int /*fogIndex*/, int staticGeoChunk )
|
||||||
{
|
{
|
||||||
if (tr.refdef.numLitSurfs >= MAX_DRAWSURFS)
|
if (tr.refdef.numLitSurfs >= MAX_DRAWSURFS)
|
||||||
return;
|
return;
|
||||||
|
@ -1306,10 +1308,11 @@ void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fog
|
||||||
tr.pc[RF_LIT_SURFS]++;
|
tr.pc[RF_LIT_SURFS]++;
|
||||||
|
|
||||||
litSurf_t* const litSurf = &tr.refdef.litSurfs[tr.refdef.numLitSurfs++];
|
litSurf_t* const litSurf = &tr.refdef.litSurfs[tr.refdef.numLitSurfs++];
|
||||||
litSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, fogIndex );
|
litSurf->sort = R_ComposeLitSort( tr.currentEntityNum, shader, staticGeoChunk );
|
||||||
litSurf->surface = surface;
|
litSurf->surface = surface;
|
||||||
litSurf->shaderNum = shader->index;
|
litSurf->shaderNum = shader->index;
|
||||||
litSurf->greyscale = SurfGreyscaleAmount( shader );
|
litSurf->greyscale = SurfGreyscaleAmount( shader );
|
||||||
|
litSurf->staticGeoChunk = staticGeoChunk;
|
||||||
|
|
||||||
if (!tr.light->head)
|
if (!tr.light->head)
|
||||||
tr.light->head = litSurf;
|
tr.light->head = litSurf;
|
||||||
|
@ -1339,7 +1342,28 @@ void R_DecomposeSort( uint64_t sort, int* entityNum, const shader_t** shader )
|
||||||
{
|
{
|
||||||
*entityNum = ( sort >> DRAWSORT_ENTITY_INDEX ) & MAX_REFENTITIES;
|
*entityNum = ( sort >> DRAWSORT_ENTITY_INDEX ) & MAX_REFENTITIES;
|
||||||
*shader = tr.sortedShaders[ ( sort >> DRAWSORT_SHADER_INDEX ) & (MAX_SHADERS-1) ];
|
*shader = tr.sortedShaders[ ( sort >> DRAWSORT_SHADER_INDEX ) & (MAX_SHADERS-1) ];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t R_ComposeLitSort( int entityNum, const shader_t* shader, int staticGeoChunk )
|
||||||
|
{
|
||||||
|
const int stageIndex = max( shader->lightingStages[ST_DIFFUSE], 0 );
|
||||||
|
const int depthTestEquals = ( shader->stages[stageIndex]->stateBits & GLS_DEPTHFUNC_EQUAL ) != 0;
|
||||||
|
|
||||||
|
return
|
||||||
|
( (uint32_t)entityNum << LITSORT_ENTITY_INDEX ) |
|
||||||
|
( (uint32_t)shader->sortedIndex << LITSORT_SHADER_INDEX ) |
|
||||||
|
( (uint32_t)( staticGeoChunk > 0 ? 0 : 1 ) << LITSORT_STATICGEO_INDEX ) |
|
||||||
|
( (uint32_t)shader->cullType << LITSORT_CULLTYPE_INDEX ) |
|
||||||
|
( (uint32_t)shader->polygonOffset << LITSORT_POLYGONOFFSET_INDEX ) |
|
||||||
|
( (uint32_t)depthTestEquals << LITSORT_DEPTHTEST_INDEX );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void R_DecomposeLitSort( uint32_t sort, int* entityNum, const shader_t** shader )
|
||||||
|
{
|
||||||
|
*entityNum = ( sort >> LITSORT_ENTITY_INDEX ) & MAX_REFENTITIES;
|
||||||
|
*shader = tr.sortedShaders[ ( sort >> LITSORT_SHADER_INDEX ) & (MAX_SHADERS-1) ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ SURFACE SHADERS
|
||||||
shaderCommands_t tess;
|
shaderCommands_t tess;
|
||||||
|
|
||||||
|
|
||||||
|
// @TODO: remove all this...
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
|
||||||
// we must set some things up before beginning any tesselation
|
// we must set some things up before beginning any tesselation
|
||||||
// because a surface may be forced to perform a RB_End due to overflow
|
// because a surface may be forced to perform a RB_End due to overflow
|
||||||
|
|
||||||
|
@ -251,3 +255,6 @@ void RB_EndSurface()
|
||||||
// clear shader so we can tell we don't have any unclosed surfaces
|
// clear shader so we can tell we don't have any unclosed surfaces
|
||||||
tess.numIndexes = 0;
|
tess.numIndexes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1809,8 +1809,8 @@ static void SortNewShader()
|
||||||
const int numLitSurfs = tr.refdef.numLitSurfs;
|
const int numLitSurfs = tr.refdef.numLitSurfs;
|
||||||
litSurf_t* litSurfs = tr.refdef.litSurfs;
|
litSurf_t* litSurfs = tr.refdef.litSurfs;
|
||||||
for ( i = 0; i < numLitSurfs; ++i, ++litSurfs ) {
|
for ( i = 0; i < numLitSurfs; ++i, ++litSurfs ) {
|
||||||
R_DecomposeSort( litSurfs->sort, &entityNum, &wrongShader );
|
R_DecomposeLitSort( litSurfs->sort, &entityNum, &wrongShader );
|
||||||
litSurfs->sort = R_ComposeSort( entityNum, tr.shaders[litSurfs->shaderNum], drawSurfs->staticGeoChunk );
|
litSurfs->sort = R_ComposeLitSort( entityNum, tr.shaders[litSurfs->shaderNum], drawSurfs->staticGeoChunk );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -350,6 +350,10 @@ static void R_AddLitSurface( msurface_t* surf, const dlight_t* light )
|
||||||
if ( surf->shader->sort < SS_OPAQUE )
|
if ( surf->shader->sort < SS_OPAQUE )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// lighting a fog box' surface looks absolutely terrible
|
||||||
|
if ( (surf->shader->contentFlags & CONTENTS_FOG) != 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
if ( surf->lightCount == tr.lightCount )
|
if ( surf->lightCount == tr.lightCount )
|
||||||
return; // already in the lit list (or already culled) for this light
|
return; // already in the lit list (or already culled) for this light
|
||||||
|
|
||||||
|
@ -374,7 +378,7 @@ static void R_AddLitSurface( msurface_t* surf, const dlight_t* light )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_AddLitSurf( surf->data, surf->shader, surf->fogIndex );
|
R_AddLitSurf( surf->data, surf->shader, surf->fogIndex, surf->staticGeoChunk );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,9 @@ void CompileShader(const ShaderArgs& args, int extraCount = 0, const char** extr
|
||||||
{
|
{
|
||||||
static char temp[4096];
|
static char temp[4096];
|
||||||
|
|
||||||
strcpy(temp, va("dxc.exe -Fh %s -E %s -T %s -WX",
|
// -Ges: Enable strict mode
|
||||||
|
// -Gis: Force IEEE strictness
|
||||||
|
strcpy(temp, va("dxc.exe -Fh %s -E %s -T %s -WX -Ges -Gis",
|
||||||
args.headerPath, args.entryPoint, args.targetProfile));
|
args.headerPath, args.entryPoint, args.targetProfile));
|
||||||
|
|
||||||
for(int i = 0; i < extraCount; ++i)
|
for(int i = 0; i < extraCount; ++i)
|
||||||
|
@ -231,6 +233,7 @@ int main(int /*argc*/, const char** argv)
|
||||||
CompileVSAndPS("imgui", "imgui.hlsl");
|
CompileVSAndPS("imgui", "imgui.hlsl");
|
||||||
CompileVSAndPS("ui", "ui.hlsl");
|
CompileVSAndPS("ui", "ui.hlsl");
|
||||||
CompileVSAndPS("depth_pre_pass", "depth_pre_pass.hlsl");
|
CompileVSAndPS("depth_pre_pass", "depth_pre_pass.hlsl");
|
||||||
|
CompileVSAndPS("dynamic_light", "dynamic_light.hlsl");
|
||||||
CompileVS("fog_vs.h", "fog_inside.hlsl");
|
CompileVS("fog_vs.h", "fog_inside.hlsl");
|
||||||
CompilePS("fog_inside_ps.h", "fog_inside.hlsl");
|
CompilePS("fog_inside_ps.h", "fog_inside.hlsl");
|
||||||
CompilePS("fog_outside_ps.h", "fog_outside.hlsl");
|
CompilePS("fog_outside_ps.h", "fog_outside.hlsl");
|
||||||
|
|
|
@ -259,6 +259,9 @@
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</FxCompile>
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
|
|
@ -56,6 +56,9 @@
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||||
<Filter>hlsl</Filter>
|
<Filter>hlsl</Filter>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||||
|
<Filter>hlsl</Filter>
|
||||||
|
</FxCompile>
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||||
<Filter>hlsl</Filter>
|
<Filter>hlsl</Filter>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
|
|
@ -263,6 +263,9 @@
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||||
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
|
</FxCompile>
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
|
|
@ -56,6 +56,9 @@
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||||
<Filter>hlsl</Filter>
|
<Filter>hlsl</Filter>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||||
|
<Filter>hlsl</Filter>
|
||||||
|
</FxCompile>
|
||||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||||
<Filter>hlsl</Filter>
|
<Filter>hlsl</Filter>
|
||||||
</FxCompile>
|
</FxCompile>
|
||||||
|
|
Loading…
Reference in a new issue