mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Added emissive texture support
This commit is contained in:
+118
-15
@@ -2287,6 +2287,8 @@ struct glRaytracingLightingState_t
|
||||
DXGI_FORMAT denoiseFormat;
|
||||
uint32_t frameCounter;
|
||||
bool externalDenoiser;
|
||||
ID3D12Resource* emissiveTexture;
|
||||
DXGI_FORMAT emissiveFormat;
|
||||
bool uploadToCurrentFrameResource;
|
||||
bool initialized;
|
||||
|
||||
@@ -2311,6 +2313,8 @@ struct glRaytracingLightingState_t
|
||||
currentHistoryIndex = 0;
|
||||
frameCounter = 0;
|
||||
externalDenoiser = false;
|
||||
emissiveTexture = nullptr;
|
||||
emissiveFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
uploadToCurrentFrameResource = false;
|
||||
initialized = false;
|
||||
}
|
||||
@@ -2333,14 +2337,15 @@ enum glRaytracingLightingDescriptorIndex_t
|
||||
GLR_DESC_DENOISE_B_SRV = 8,
|
||||
GLR_DESC_HISTORY_SRV = 9,
|
||||
GLR_DESC_TEMPORAL_SRV = 10,
|
||||
GLR_DESC_PATHTRACE_UAV = 11,
|
||||
GLR_DESC_DENOISE_A_UAV = 12,
|
||||
GLR_DESC_DENOISE_B_UAV = 13,
|
||||
GLR_DESC_OUTPUT_UAV = 14,
|
||||
GLR_DESC_TEMPORAL_UAV = 15,
|
||||
GLR_DESC_HISTORY_UAV = 16,
|
||||
GLR_DESC_COUNT = 17,
|
||||
GLR_DESC_SRV_COUNT = 11,
|
||||
GLR_DESC_EMISSIVE_SRV = 11,
|
||||
GLR_DESC_PATHTRACE_UAV = 12,
|
||||
GLR_DESC_DENOISE_A_UAV = 13,
|
||||
GLR_DESC_DENOISE_B_UAV = 14,
|
||||
GLR_DESC_OUTPUT_UAV = 15,
|
||||
GLR_DESC_TEMPORAL_UAV = 16,
|
||||
GLR_DESC_HISTORY_UAV = 17,
|
||||
GLR_DESC_COUNT = 18,
|
||||
GLR_DESC_SRV_COUNT = 12,
|
||||
GLR_DESC_UAV_COUNT = 6
|
||||
};
|
||||
|
||||
@@ -2434,6 +2439,7 @@ Texture2D<float> gDepthTex : register(t2);
|
||||
Texture2D<float4> gNormalTex : register(t3);
|
||||
Texture2D<float4> gPositionTex : register(t4);
|
||||
RaytracingAccelerationStructure gSceneBVH : register(t5);
|
||||
Texture2D<float4> gEmissiveTex : register(t11);
|
||||
RWTexture2D<float4> gOutputTex : register(u0);
|
||||
|
||||
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0;
|
||||
@@ -3373,6 +3379,61 @@ float TraceVisibilityBiased(float3 worldPos, float3 N, float3 dir, float maxT)
|
||||
return TraceShadow(origin, dir, max(maxT - gShadowBias * 0.5, 0.001));
|
||||
}
|
||||
|
||||
|
||||
float3 CompressEmissiveRadiance(float3 e, float peakLimit)
|
||||
{
|
||||
e = max(e, 0.0);
|
||||
float peak = max(max(e.r, e.g), e.b);
|
||||
if (peak > peakLimit && peak > 1e-5)
|
||||
e *= peakLimit / peak;
|
||||
return e;
|
||||
}
|
||||
|
||||
float3 LoadEmissiveRadianceClamped(int2 p)
|
||||
{
|
||||
int2 maxPixel = int2((int)gScreenSize.x - 1, (int)gScreenSize.y - 1);
|
||||
p = clamp(p, int2(0, 0), maxPixel);
|
||||
return CompressEmissiveRadiance(gEmissiveTex.Load(int3(p, 0)).rgb, 7.50);
|
||||
}
|
||||
|
||||
float3 EstimateEmissiveBloomAtPixel(uint2 pixel)
|
||||
{
|
||||
int2 p = int2(pixel);
|
||||
|
||||
// Strong threshold-free bloom. This stays direct/bloom-only: no extra
|
||||
// TraceRay calls, and no emissive lighting contribution. The goal is to make
|
||||
// visible glow maps read as hot emissive surfaces in the DXR output.
|
||||
float3 bloom = 0.0;
|
||||
bloom += LoadEmissiveRadianceClamped(p) * 0.180;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 1, 0)) * 0.220;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-1, 0)) * 0.220;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 1)) * 0.220;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -1)) * 0.220;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 2, 2)) * 0.135;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-2, 2)) * 0.135;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 2, -2)) * 0.135;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-2, -2)) * 0.135;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 4, 0)) * 0.090;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-4, 0)) * 0.090;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 4)) * 0.090;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -4)) * 0.090;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 8, 0)) * 0.060;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-8, 0)) * 0.060;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 8)) * 0.060;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -8)) * 0.060;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 14, 0)) * 0.035;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-14, 0)) * 0.035;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 14)) * 0.035;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -14)) * 0.035;
|
||||
|
||||
return bloom * 0.78;
|
||||
}
|
||||
|
||||
float3 SafeNormalizeOr(float3 v, float3 fallback)
|
||||
{
|
||||
float lenSq = dot(v, v);
|
||||
@@ -3717,7 +3778,8 @@ float EstimateVolumeDensityFromLight(Light Lgt)
|
||||
|
||||
return clamp(2.25 / max(range, 32.0), 0.0015, 0.035);
|
||||
}
|
||||
|
||||
)"
|
||||
R"(
|
||||
float3 EstimateSingleLightVolumetricScattering(uint2 pixel, float3 cameraPos, float3 worldPos, Light Lgt, inout uint rng)
|
||||
{
|
||||
if (Lgt.volumetricScattering <= 0.0)
|
||||
@@ -3927,8 +3989,8 @@ float3 EstimateDirectLightingForBounceHit(uint2 hitPixel, float3 hitPos, float3
|
||||
hitV = SafeNormalizeOr(hitV, -hitN);
|
||||
hitAlbedo = saturate(hitAlbedo);
|
||||
|
||||
// Treat unlit G-buffer surfaces as simple emissive bounce cards. Clamp so a
|
||||
// white UI/light-card cannot become an uncontrolled firefly in the GI path.
|
||||
// Treat unlit G-buffer surfaces as simple bounce cards. Glow-map emissive is
|
||||
// intentionally excluded here so visible emissive no longer casts GI/light.
|
||||
if (hitIsUnlit)
|
||||
return clamp(hitAlbedo * 2.0 + GetSkyRadiance(hitN) * 0.04, 0.0, 6.0);
|
||||
|
||||
@@ -3939,6 +4001,10 @@ float3 EstimateDirectLightingForBounceHit(uint2 hitPixel, float3 hitPos, float3
|
||||
// used a fixed sky term, so corners/cavities received too much indirect light.
|
||||
lighting += EstimateBounceSkyLighting(hitPos, hitN, rng) * (0.14 + 0.10 * upness);
|
||||
|
||||
// Glow-map emissive no longer participates in secondary GI. It remains a
|
||||
// direct visible/bloom-only effect until real material-space emissive lighting
|
||||
// is implemented.
|
||||
|
||||
// Baseline: every light contributes to bounced radiance, so small dynamic
|
||||
// lights do not vanish just because they were not chosen by the stochastic
|
||||
// next-event-estimation budget.
|
||||
@@ -4299,6 +4365,9 @@ float3 PathTraceDeterministicLighting(
|
||||
lightingAccum += skyColor * (0.70 * skyVis);
|
||||
lightingAccum += ambientSkyVis * (skyColorRGB * 0.15);
|
||||
|
||||
// Glow-map emissive is direct/bloom-only for now. It is added after lighting
|
||||
// in RayGen and is intentionally not injected into lightingAccum.
|
||||
|
||||
//if (isSkeletal)
|
||||
// lightingAccum += 0.1;
|
||||
|
||||
@@ -4344,11 +4413,15 @@ void RayGen()
|
||||
return;
|
||||
|
||||
float4 albedoSample = gAlbedoTex.Load(int3(pixel, 0));
|
||||
float4 emissiveSample = gEmissiveTex.Load(int3(pixel, 0));
|
||||
float3 emissiveSurface = CompressEmissiveRadiance(emissiveSample.rgb, 6.50);
|
||||
float depthSample = gDepthTex.Load(int3(pixel, 0));
|
||||
|
||||
float3 emissiveBloom = EstimateEmissiveBloomAtPixel(pixel);
|
||||
|
||||
if (depthSample <= 0.0 || depthSample >= 1.0)
|
||||
{
|
||||
gOutputTex[pixel] = albedoSample;
|
||||
gOutputTex[pixel] = float4(albedoSample.rgb + emissiveSurface + emissiveBloom, albedoSample.a);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4365,7 +4438,7 @@ void RayGen()
|
||||
|
||||
if (isUnlit)
|
||||
{
|
||||
gOutputTex[pixel] = float4(baseAlbedo, albedoSample.a);
|
||||
gOutputTex[pixel] = float4(baseAlbedo + emissiveSurface + emissiveBloom, albedoSample.a);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4454,6 +4527,12 @@ void RayGen()
|
||||
uint volumeRng = InitRng(pixel, 0u, 0x51u);
|
||||
finalColor += EstimatePathTracedVolumetricScattering(pixel, worldPos, volumeRng);
|
||||
|
||||
// Glow-map emission is direct radiance from the primary surface. It is added
|
||||
// after lighting so it remains visible in darkness and under ray-traced shadows.
|
||||
// emissiveBloom is the threshold-free halo, so emissive always blooms even if
|
||||
// the eventual swap-chain/backbuffer is LDR.
|
||||
finalColor += emissiveSurface + emissiveBloom;
|
||||
|
||||
gOutputTex[pixel] = float4(max(finalColor, 0.0), albedoSample.a);
|
||||
}
|
||||
)";
|
||||
@@ -4623,7 +4702,10 @@ void DenoiseCS(uint3 dispatchThreadId : SV_DispatchThreadID)
|
||||
|
||||
if (depthSample <= 0.0 || depthSample >= 1.0)
|
||||
{
|
||||
StoreDenoiseOutput(pixel, albedoSample);
|
||||
// Preserve raygen's emissive bloom on background/no-depth pixels.
|
||||
// Returning albedo here would erase the halo whenever the internal
|
||||
// temporal/a-trous denoiser is active.
|
||||
StoreDenoiseOutput(pixel, centerSource);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4867,7 +4949,9 @@ static ComPtr<IDxcBlob> glRaytracingLightingCompileLibrary(const char* src)
|
||||
L"-Zi",
|
||||
L"-Qembed_debug",
|
||||
#endif
|
||||
L"-O3",
|
||||
// Keep the DXR library smaller to avoid long driver-side linking during
|
||||
// CreateStateObject(). Compute/post shaders below still compile with O3.
|
||||
L"-O1",
|
||||
L"-all_resources_bound"
|
||||
};
|
||||
|
||||
@@ -5662,6 +5746,14 @@ static void glRaytracingLightingCreatePerPassDescriptors(
|
||||
g_glRaytracingCmd.device->CreateShaderResourceView(temporalTexture, &denoiseSrv,
|
||||
glRaytracingOffsetCpu(base, g_glRaytracingLighting.descriptorStride, GLR_DESC_TEMPORAL_SRV));
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC emissiveSrv = {};
|
||||
emissiveSrv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
emissiveSrv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
emissiveSrv.Format = g_glRaytracingLighting.emissiveFormat;
|
||||
emissiveSrv.Texture2D.MipLevels = 1;
|
||||
g_glRaytracingCmd.device->CreateShaderResourceView(g_glRaytracingLighting.emissiveTexture, &emissiveSrv,
|
||||
glRaytracingOffsetCpu(base, g_glRaytracingLighting.descriptorStride, GLR_DESC_EMISSIVE_SRV));
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC rayOutputUav = {};
|
||||
rayOutputUav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
rayOutputUav.Format = GL_RAYTRACING_DENOISE_FORMAT;
|
||||
@@ -6299,6 +6391,17 @@ void glRaytracingLightingUseExternalDenoiser(int enabled)
|
||||
glRaytracingLightingSetExternalDenoiser(enabled);
|
||||
}
|
||||
|
||||
|
||||
void glRaytracingLightingSetEmissiveInput(ID3D12Resource* texture, DXGI_FORMAT format)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
|
||||
|
||||
g_glRaytracingLighting.emissiveTexture = texture;
|
||||
g_glRaytracingLighting.emissiveFormat = (format == DXGI_FORMAT_UNKNOWN)
|
||||
? DXGI_FORMAT_R16G16B16A16_FLOAT
|
||||
: format;
|
||||
}
|
||||
|
||||
bool glRaytracingLightingExecuteForScene(const glRaytracingLightingPassDesc_t* pass, glRaytracingSceneHandle_t worldHandle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
|
||||
|
||||
+435
-38
@@ -129,6 +129,9 @@ using Microsoft::WRL::ComPtr;
|
||||
#ifndef GL_NORMAL_MAP_BINDING_QD3D12
|
||||
#define GL_NORMAL_MAP_BINDING_QD3D12 0x6002
|
||||
#endif
|
||||
#ifndef GL_GLOW_MAP_BINDING_QD3D12
|
||||
#define GL_GLOW_MAP_BINDING_QD3D12 0x6005
|
||||
#endif
|
||||
|
||||
// Optional material/ray-visibility tags for the DXR path. These are private
|
||||
// shim enums; they deliberately live next to the normal-map compatibility enums.
|
||||
@@ -186,6 +189,11 @@ void APIENTRY glBinormal3f(GLfloat x, GLfloat y, GLfloat z);
|
||||
void APIENTRY glBinormal3fv(const GLfloat* v);
|
||||
void APIENTRY glGlassMaterialQD3D12(GLboolean enable);
|
||||
void APIENTRY glMaterialGlassQD3D12(GLboolean enable);
|
||||
void APIENTRY glTagTextureGlowMap(GLuint texture, GLboolean isGlowMap);
|
||||
void APIENTRY glTextureGlowMap(GLuint texture, GLboolean isGlowMap);
|
||||
void APIENTRY glBindGlowMapTexture(GLuint texture);
|
||||
void APIENTRY glGlowMapTexture(GLuint texture);
|
||||
void APIENTRY glGlowMapStrengthf(GLfloat strength);
|
||||
void APIENTRY glRaytracingMaterialFlagsQD3D12(GLuint flags);
|
||||
void APIENTRY glRaytracingMaterialFlagQD3D12(GLuint flag, GLboolean enable);
|
||||
|
||||
@@ -195,6 +203,7 @@ void APIENTRY glRaytracingMaterialFlagQD3D12(GLuint flag, GLboolean enable);
|
||||
void glRaytracingLightingSetExternalDenoiser(int enable);
|
||||
void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_t maxBounces, int enableDenoiser, float denoiseStrength);
|
||||
void glRaytracingLightingSetVolumetricScattering(glRaytracingLight_t* light, float strength);
|
||||
void glRaytracingLightingSetEmissiveInput(ID3D12Resource* texture, DXGI_FORMAT format);
|
||||
void glRaytracingSetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle, uint32_t materialFlags);
|
||||
void glRaytracingSetMeshGlass(glRaytracingMeshHandle_t meshHandle, int isGlass);
|
||||
uint32_t glRaytracingGetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle);
|
||||
@@ -312,15 +321,18 @@ enum QD3D12RTVSlotGroup
|
||||
QD3D12_RTV_NORMAL_RENDER = 1,
|
||||
QD3D12_RTV_POSITION_RENDER = 2,
|
||||
QD3D12_RTV_VELOCITY_RENDER = 3,
|
||||
QD3D12_RTV_SCENE_RESOLVED = 4,
|
||||
QD3D12_RTV_NORMAL_RESOLVED = 5,
|
||||
QD3D12_RTV_POSITION_RESOLVED = 6,
|
||||
QD3D12_RTV_VELOCITY_RESOLVED = 7,
|
||||
QD3D12_RTV_BACKBUFFER = 8,
|
||||
QD3D12_RTV_GROUP_COUNT = 9
|
||||
QD3D12_RTV_EMISSIVE_RENDER = 4,
|
||||
QD3D12_RTV_SCENE_RESOLVED = 5,
|
||||
QD3D12_RTV_NORMAL_RESOLVED = 6,
|
||||
QD3D12_RTV_POSITION_RESOLVED = 7,
|
||||
QD3D12_RTV_VELOCITY_RESOLVED = 8,
|
||||
QD3D12_RTV_EMISSIVE_RESOLVED = 9,
|
||||
QD3D12_RTV_BACKBUFFER = 10,
|
||||
QD3D12_RTV_GROUP_COUNT = 11
|
||||
};
|
||||
|
||||
static const DXGI_FORMAT QD3D12_SceneColorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
static const DXGI_FORMAT QD3D12_EmissiveFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
static const DXGI_FORMAT QD3D12_StreamlineOutputFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
static const DXGI_FORMAT QD3D12_VelocityFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
static const DXGI_FORMAT QD3D12_DepthFormat = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
|
||||
@@ -444,11 +456,12 @@ struct TextureResource
|
||||
bool gpuValid = false;
|
||||
D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
|
||||
// Optional material role tag. Tagged textures are not treated as diffuse
|
||||
// inputs by default; they are selected as tangent-space normal maps for the
|
||||
// fixed-function G-buffer path when bound through glNormalMapTexture() or any
|
||||
// active texture unit.
|
||||
// Optional material role tags. Tagged textures are not treated as diffuse
|
||||
// inputs by default; they are selected as tangent-space normal/glow maps for
|
||||
// the fixed-function G-buffer path when explicitly bound or auto-discovered
|
||||
// from any active texture unit.
|
||||
bool isNormalMap = false;
|
||||
bool isGlowMap = false;
|
||||
};
|
||||
|
||||
static void QD3D12_ShutdownMipWorkers();
|
||||
@@ -523,7 +536,7 @@ struct GLBufferObject
|
||||
const char* vendor = "Justin Marshall";
|
||||
const char* renderer = "Quake D3D12 Wrapper";
|
||||
const char* version = "1.1-quake-d3d12";
|
||||
const char* extensions = "GL_SGIS_multitexture GL_ARB_multitexture GL_EXT_texture_env_add GL_ARB_texture_env_combine GL_ARB_texture_compression GL_EXT_texture_compression_s3tc GL_ARB_vertex_program GL_ARB_fragment_program GL_EXT_texture_cube_map GL_EXT_depth_bounds_test GL_EXT_stencil_two_side GL_ATI_separate_stencil GL_QD3D12_normal_map GL_QD3D12_glass_material GL_QD3D12_volumetric_light";
|
||||
const char* extensions = "GL_SGIS_multitexture GL_ARB_multitexture GL_EXT_texture_env_add GL_ARB_texture_env_combine GL_ARB_texture_compression GL_EXT_texture_compression_s3tc GL_ARB_vertex_program GL_ARB_fragment_program GL_EXT_texture_cube_map GL_EXT_depth_bounds_test GL_EXT_stencil_two_side GL_ATI_separate_stencil GL_QD3D12_normal_map GL_QD3D12_glow_map GL_QD3D12_glass_material GL_QD3D12_volumetric_light";
|
||||
|
||||
enum TexEnvModeShader
|
||||
{
|
||||
@@ -568,6 +581,9 @@ struct BatchKey
|
||||
float useNormalMap = 0.0f;
|
||||
float normalMapStrength = 1.0f;
|
||||
float normalMapYSign = 1.0f;
|
||||
UINT glowMapSrvIndex = 0;
|
||||
float useGlowMap = 0.0f;
|
||||
float glowMapStrength = 1.0f;
|
||||
|
||||
bool useARBPrograms = false;
|
||||
GLuint arbVertexProgram = 0;
|
||||
@@ -676,6 +692,9 @@ static bool BatchKeyEquals(const BatchKey& a, const BatchKey& b)
|
||||
a.useNormalMap == b.useNormalMap &&
|
||||
a.normalMapStrength == b.normalMapStrength &&
|
||||
a.normalMapYSign == b.normalMapYSign &&
|
||||
a.glowMapSrvIndex == b.glowMapSrvIndex &&
|
||||
a.useGlowMap == b.useGlowMap &&
|
||||
a.glowMapStrength == b.glowMapStrength &&
|
||||
a.alphaRef == b.alphaRef &&
|
||||
a.alphaFunc == b.alphaFunc &&
|
||||
a.useTex0 == b.useTex0 &&
|
||||
@@ -779,6 +798,9 @@ struct QD3D12Window
|
||||
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> velocityBuffers;
|
||||
D3D12_RESOURCE_STATES velocityBufferState[QD3D12_FrameCount] = {};
|
||||
|
||||
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> emissiveBuffers;
|
||||
D3D12_RESOURCE_STATES emissiveBufferState[QD3D12_FrameCount] = {};
|
||||
|
||||
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> sceneColorMsaaBuffers;
|
||||
D3D12_RESOURCE_STATES sceneColorMsaaState[QD3D12_FrameCount] = {};
|
||||
|
||||
@@ -791,6 +813,9 @@ struct QD3D12Window
|
||||
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> velocityMsaaBuffers;
|
||||
D3D12_RESOURCE_STATES velocityMsaaState[QD3D12_FrameCount] = {};
|
||||
|
||||
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> emissiveMsaaBuffers;
|
||||
D3D12_RESOURCE_STATES emissiveMsaaState[QD3D12_FrameCount] = {};
|
||||
|
||||
std::array<ComPtr<ID3D12Resource>, QD3D12_FrameCount> backBuffers;
|
||||
D3D12_RESOURCE_STATES backBufferState[QD3D12_FrameCount] = {};
|
||||
|
||||
@@ -824,6 +849,10 @@ struct QD3D12Window
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE velocitySrvCpu[QD3D12_FrameCount]{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE velocitySrvGpu[QD3D12_FrameCount]{};
|
||||
|
||||
UINT emissiveSrvIndex[QD3D12_FrameCount] = { UINT_MAX, UINT_MAX };
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE emissiveSrvCpu[QD3D12_FrameCount]{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE emissiveSrvGpu[QD3D12_FrameCount]{};
|
||||
|
||||
UINT slOutputSrvIndex[QD3D12_FrameCount] = { UINT_MAX, UINT_MAX };
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE slOutputSrvCpu[QD3D12_FrameCount]{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE slOutputSrvGpu[QD3D12_FrameCount]{};
|
||||
@@ -848,6 +877,10 @@ struct QD3D12Window
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE velocityMsaaSrvCpu[QD3D12_FrameCount]{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE velocityMsaaSrvGpu[QD3D12_FrameCount]{};
|
||||
|
||||
UINT emissiveMsaaSrvIndex[QD3D12_FrameCount] = { UINT_MAX, UINT_MAX };
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE emissiveMsaaSrvCpu[QD3D12_FrameCount]{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE emissiveMsaaSrvGpu[QD3D12_FrameCount]{};
|
||||
|
||||
D3D12_VIEWPORT viewport{};
|
||||
D3D12_RECT scissor{};
|
||||
|
||||
@@ -1119,6 +1152,8 @@ struct GLState
|
||||
GLuint currentNormalMapTexture = 0;
|
||||
float currentNormalMapStrength = 1.0f;
|
||||
float currentNormalMapYSign = 1.0f;
|
||||
GLuint currentGlowMapTexture = 0;
|
||||
float currentGlowMapStrength = 1.0f;
|
||||
ImmediateVertexBuffer immediateVerts;
|
||||
|
||||
GLenum matrixMode = GL_MODELVIEW;
|
||||
@@ -1703,6 +1738,12 @@ static D3D12_CPU_DESCRIPTOR_HANDLE CurrentVelocityRTV()
|
||||
return QD3D12_RtvAt(w, QD3D12_RTV_VELOCITY_RENDER, w.frameIndex);
|
||||
}
|
||||
|
||||
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentEmissiveRTV()
|
||||
{
|
||||
QD3D12Window& w = *g_currentWindow;
|
||||
return QD3D12_RtvAt(w, QD3D12_RTV_EMISSIVE_RENDER, w.frameIndex);
|
||||
}
|
||||
|
||||
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentResolvedSceneColorRTV()
|
||||
{
|
||||
QD3D12Window& w = *g_currentWindow;
|
||||
@@ -1727,6 +1768,12 @@ static D3D12_CPU_DESCRIPTOR_HANDLE CurrentResolvedVelocityRTV()
|
||||
return QD3D12_RtvAt(w, QD3D12_RTV_VELOCITY_RESOLVED, w.frameIndex);
|
||||
}
|
||||
|
||||
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentResolvedEmissiveRTV()
|
||||
{
|
||||
QD3D12Window& w = *g_currentWindow;
|
||||
return QD3D12_RtvAt(w, QD3D12_RTV_EMISSIVE_RESOLVED, w.frameIndex);
|
||||
}
|
||||
|
||||
static D3D12_CPU_DESCRIPTOR_HANDLE CurrentBackBufferRTV()
|
||||
{
|
||||
QD3D12Window& w = *g_currentWindow;
|
||||
@@ -1815,6 +1862,12 @@ static bool QD3D12_IsTextureTaggedNormalMap(GLuint id)
|
||||
return tex && tex->isNormalMap;
|
||||
}
|
||||
|
||||
static bool QD3D12_IsTextureTaggedGlowMap(GLuint id)
|
||||
{
|
||||
TextureResource* tex = QD3D12_FindTextureResource(id);
|
||||
return tex && tex->isGlowMap;
|
||||
}
|
||||
|
||||
static TextureResource* QD3D12_SelectNormalMapTexture(TextureResource* const* allTextures)
|
||||
{
|
||||
// Explicit material binding wins. This lets callers bind a normal map even
|
||||
@@ -1847,6 +1900,45 @@ static TextureResource* QD3D12_SelectNormalMapTexture(TextureResource* const* al
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static TextureResource* QD3D12_SelectGlowMapTexture(TextureResource* const* allTextures)
|
||||
{
|
||||
// Explicit material binding wins. Tagging enables automatic discovery from
|
||||
// arbitrary texture units without consuming the diffuse/lightmap slots.
|
||||
if (g_gl.currentGlowMapTexture != 0)
|
||||
{
|
||||
TextureResource* explicitGlow = QD3D12_FindTextureResource(g_gl.currentGlowMapTexture);
|
||||
if (explicitGlow)
|
||||
{
|
||||
// Common integration mistake: passing shader->GetBumpImage()->texnum
|
||||
// to glBindGlowMapTexture(). Never treat a texture explicitly tagged
|
||||
// as a normal map as emissive unless it was also explicitly tagged glow.
|
||||
if (explicitGlow->isNormalMap && !explicitGlow->isGlowMap)
|
||||
return nullptr;
|
||||
|
||||
return explicitGlow;
|
||||
}
|
||||
}
|
||||
|
||||
if (allTextures)
|
||||
{
|
||||
for (UINT i = 0; i < QD3D12_MaxTextureUnits; ++i)
|
||||
{
|
||||
TextureResource* tex = allTextures[i];
|
||||
if (tex && tex != &g_gl.whiteTexture && tex->isGlowMap)
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < QD3D12_MaxTextureUnits; ++i)
|
||||
{
|
||||
TextureResource* tex = QD3D12_FindTextureResource(g_gl.boundTexture[i]);
|
||||
if (tex && tex->isGlowMap)
|
||||
return tex;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const uint8_t* QD3D12_ResolveArrayPointer(const void* ptr)
|
||||
{
|
||||
if (g_gl.boundArrayBuffer != 0)
|
||||
@@ -2005,14 +2097,18 @@ cbuffer DrawCB : register(b0)
|
||||
#define gUseNormalMap gMotionPad.x
|
||||
#define gNormalMapStrength gMotionPad.y
|
||||
#define gNormalMapYSign gMotionPad.z
|
||||
#define gParallaxScale gMotionPad.w
|
||||
#define gParallaxScale 0.0
|
||||
#define gUseGlowMap gMotionPad.w
|
||||
#define gGlowMapStrength gMotionPad.w
|
||||
|
||||
Texture2D gTex0 : register(t0);
|
||||
Texture2D gTex1 : register(t1);
|
||||
Texture2D gNormalMap : register(t2);
|
||||
Texture2D gGlowMap : register(t3);
|
||||
SamplerState gSamp0 : register(s0);
|
||||
SamplerState gSamp1 : register(s1);
|
||||
SamplerState gSamp2 : register(s2);
|
||||
SamplerState gSamp3 : register(s3);
|
||||
|
||||
struct VSIn
|
||||
{
|
||||
@@ -2048,6 +2144,7 @@ struct PSOut
|
||||
float4 normal : SV_Target1;
|
||||
float4 position : SV_Target2;
|
||||
float4 velocity : SV_Target3;
|
||||
float4 emissive : SV_Target4;
|
||||
};
|
||||
|
||||
float4 QD3D12_GetTexEnvSource(float source, float4 texel, float4 primary, float4 previous, float4 constantColor)
|
||||
@@ -2306,21 +2403,61 @@ float3 BuildGBufferNormal(VSOut i)
|
||||
n);
|
||||
}
|
||||
|
||||
float2 QD3D12_BuildMaterialUV0(VSOut i)
|
||||
{
|
||||
float2 uv0 = i.uv0;
|
||||
float n = TinyNoise(int2(i.pos.xy)) * 0.0005;
|
||||
uv0 += float2(n, -n);
|
||||
|
||||
if (gUseNormalMap > 0.5)
|
||||
uv0 = QD3D12_ComputeParallaxUV(i, uv0);
|
||||
|
||||
return uv0;
|
||||
}
|
||||
|
||||
float4 QD3D12_SampleGlow(VSOut i)
|
||||
{
|
||||
if (gUseGlowMap <= 0.0)
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float4 glow = gGlowMap.Sample(gSamp3, QD3D12_BuildMaterialUV0(i));
|
||||
|
||||
// RGB-only glow maps are uploaded with an opaque alpha channel. Treat an
|
||||
// all-white/forced alpha as "no alpha mask" and derive coverage from RGB;
|
||||
// otherwise black areas of an RGB glow texture make the base material vanish.
|
||||
float rgbMask = saturate(max(max(glow.r, glow.g), glow.b));
|
||||
bool alphaLooksForcedOpaque = (glow.a >= 0.999);
|
||||
float glowMask = alphaLooksForcedOpaque ? rgbMask : saturate(max(glow.a, rgbMask));
|
||||
float emissionMask = alphaLooksForcedOpaque ? 1.0 : glowMask;
|
||||
|
||||
// Store bright HDR radiance in the FP16 emissive G-buffer. This is still
|
||||
// direct/bloom-only; emissive lighting has intentionally stayed disabled.
|
||||
// The higher baseline lets normal idTech glow maps read as obvious emission
|
||||
// without every material having to call glGlowMapStrengthf(3+).
|
||||
const float kDefaultGlowBloomRadiance = 3.25;
|
||||
float strength = max(gGlowMapStrength, 0.0);
|
||||
|
||||
// Low-value glow maps looked too weak after the no-light hotfix. Give the
|
||||
// emissive RGB a mild artist-friendly lift while preserving black texels.
|
||||
float3 glowRgb = max(glow.rgb, 0.0);
|
||||
float3 glowLift = sqrt(saturate(glowRgb));
|
||||
float3 emissionColor = max(glowRgb, glowLift * 0.55);
|
||||
float3 emission = emissionColor * emissionMask * strength * kDefaultGlowBloomRadiance;
|
||||
|
||||
return float4(emission, glowMask);
|
||||
}
|
||||
|
||||
float4 BuildTexturedColor(VSOut i)
|
||||
{
|
||||
float4 primary = i.col;
|
||||
float4 outColor = primary;
|
||||
|
||||
float2 uv0 = i.uv0;
|
||||
float2 uv0 = QD3D12_BuildMaterialUV0(i);
|
||||
float2 uv1 = i.uv1;
|
||||
|
||||
float n = TinyNoise(int2(i.pos.xy)) * 0.0005;
|
||||
uv0 += float2(n, -n);
|
||||
uv1 += float2(-n, n);
|
||||
|
||||
if (gUseNormalMap > 0.5)
|
||||
uv0 = QD3D12_ComputeParallaxUV(i, uv0);
|
||||
|
||||
if (gUseTex0 > 0.5)
|
||||
{
|
||||
float4 tex0 = gTex0.Sample(gSamp0, uv0);
|
||||
@@ -2335,12 +2472,23 @@ float4 BuildTexturedColor(VSOut i)
|
||||
gTexComb1RGB, gTexComb1Alpha, gTexComb1Operand, gTexEnvColor1);
|
||||
}
|
||||
|
||||
if (gUseGlowMap > 0.0)
|
||||
{
|
||||
float glowMask = saturate(QD3D12_SampleGlow(i).a);
|
||||
outColor.rgb *= (1.0 - glowMask);
|
||||
}
|
||||
|
||||
// outColor.xyz = ApplySoftwareRendererLook(outColor.xyz);
|
||||
outColor = ApplyFog(outColor, i.fogCoord);
|
||||
|
||||
return outColor;
|
||||
}
|
||||
|
||||
float4 BuildGlowEmission(VSOut i)
|
||||
{
|
||||
return QD3D12_SampleGlow(i);
|
||||
}
|
||||
|
||||
float2 ClipToUv(float4 clipPos)
|
||||
{
|
||||
float2 ndc = clipPos.xy / max(abs(clipPos.w), 1e-6);
|
||||
@@ -2397,6 +2545,7 @@ PSOut PSMain(VSOut i)
|
||||
o.normal = float4(BuildGBufferNormal(i), i.attr.y);
|
||||
o.position = float4(i.worldPos, i.attr.x);
|
||||
o.velocity = BuildVelocity(i);
|
||||
o.emissive = BuildGlowEmission(i);
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -2408,6 +2557,7 @@ PSOut PSMainAlphaTest(VSOut i)
|
||||
o.normal = float4(BuildGBufferNormal(i), i.attr.y);
|
||||
o.position = float4(i.worldPos, i.attr.x);
|
||||
o.velocity = BuildVelocity(i);
|
||||
o.emissive = BuildGlowEmission(i);
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -2418,18 +2568,22 @@ PSOut PSMainUntextured(VSOut i)
|
||||
o.normal = float4(BuildGBufferNormal(i), i.attr.y);
|
||||
o.position = float4(i.worldPos, i.attr.x);
|
||||
o.velocity = BuildVelocity(i);
|
||||
o.emissive = float4(0.0, 0.0, 0.0, 0.0);
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 PSMainColorOnly(VSOut i) : SV_Target0
|
||||
{
|
||||
return BuildTexturedColor(i);
|
||||
float4 c = BuildTexturedColor(i);
|
||||
c.rgb += BuildGlowEmission(i).rgb;
|
||||
return c;
|
||||
}
|
||||
|
||||
float4 PSMainAlphaTestColorOnly(VSOut i) : SV_Target0
|
||||
{
|
||||
float4 c = BuildTexturedColor(i);
|
||||
QD3D12_AlphaTest(c.a);
|
||||
c.rgb += BuildGlowEmission(i).rgb;
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -2445,6 +2599,7 @@ Texture2DMS<float> gDepthMS : register(t1);
|
||||
Texture2DMS<float4> gNormalMS : register(t2);
|
||||
Texture2DMS<float4> gPositionMS : register(t3);
|
||||
Texture2DMS<float4> gVelocityMS : register(t4);
|
||||
Texture2DMS<float4> gEmissiveMS : register(t5);
|
||||
SamplerState gSamp0 : register(s0);
|
||||
|
||||
struct VSOut
|
||||
@@ -2471,9 +2626,61 @@ float4 PSCopy(VSOut i) : SV_Target0
|
||||
return gTex0.Sample(gSamp0, i.uv);
|
||||
}
|
||||
|
||||
float3 QD3D12_LoadPostRadiance(float2 uv)
|
||||
{
|
||||
// Clamp bloom taps so a single bad HDR edge sample cannot flood the LDR
|
||||
// scene-color composite. The direct center emissive value is still added by
|
||||
// PSAdd below, so this only limits the halo.
|
||||
return min(max(gTex0.Sample(gSamp0, saturate(uv)).rgb, 0.0), 12.0);
|
||||
}
|
||||
|
||||
float3 QD3D12_EmissiveBloom(float2 uv)
|
||||
{
|
||||
uint srcW, srcH;
|
||||
gTex0.GetDimensions(srcW, srcH);
|
||||
float2 texel = 1.0 / max(float2((float)srcW, (float)srcH), float2(1.0, 1.0));
|
||||
|
||||
// Strong threshold-free bloom kernel. Direct emissive is still added by
|
||||
// PSAdd; this wider halo makes glow maps read even when the final color
|
||||
// buffer is LDR and clamps the swap-chain output.
|
||||
float3 bloom = 0.0;
|
||||
bloom += QD3D12_LoadPostRadiance(uv) * 0.180;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 1.0, 0.0)) * 0.220;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-1.0, 0.0)) * 0.220;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 1.0)) * 0.220;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -1.0)) * 0.220;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 2.0, 2.0)) * 0.135;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-2.0, 2.0)) * 0.135;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 2.0, -2.0)) * 0.135;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-2.0, -2.0)) * 0.135;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 4.0, 0.0)) * 0.090;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-4.0, 0.0)) * 0.090;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 4.0)) * 0.090;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -4.0)) * 0.090;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 8.0, 0.0)) * 0.060;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-8.0, 0.0)) * 0.060;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 8.0)) * 0.060;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -8.0)) * 0.060;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 14.0, 0.0)) * 0.035;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-14.0, 0.0)) * 0.035;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 14.0)) * 0.035;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -14.0)) * 0.035;
|
||||
|
||||
return min(bloom * 0.62, 5.0);
|
||||
}
|
||||
|
||||
float4 PSAdd(VSOut i) : SV_Target0
|
||||
{
|
||||
return gTex0.Sample(gSamp0, i.uv);
|
||||
float4 center = gTex0.Sample(gSamp0, i.uv);
|
||||
float3 direct = max(center.rgb, 0.0);
|
||||
float3 bloom = QD3D12_EmissiveBloom(i.uv);
|
||||
|
||||
return float4(direct + bloom, saturate(center.a));
|
||||
}
|
||||
|
||||
float PSDepthCopy(VSOut i) : SV_Depth
|
||||
@@ -2531,6 +2738,7 @@ struct PSGBufferPointResolveOut
|
||||
float4 normal : SV_Target0;
|
||||
float4 position : SV_Target1;
|
||||
float4 velocity : SV_Target2;
|
||||
float4 emissive : SV_Target3;
|
||||
};
|
||||
|
||||
PSGBufferPointResolveOut PSGBufferPointResolveMS(VSOut i)
|
||||
@@ -2553,6 +2761,7 @@ PSGBufferPointResolveOut PSGBufferPointResolveMS(VSOut i)
|
||||
o.normal = gNormalMS.Load(int2(srcPixel), sampleIndex);
|
||||
o.position = gPositionMS.Load(int2(srcPixel), sampleIndex);
|
||||
o.velocity = gVelocityMS.Load(int2(srcPixel), sampleIndex);
|
||||
o.emissive = gEmissiveMS.Load(int2(srcPixel), sampleIndex);
|
||||
|
||||
return o;
|
||||
}
|
||||
@@ -2971,6 +3180,19 @@ static BatchKey BuildCurrentBatchKey(GLenum originalMode, const TextureResource*
|
||||
key.normalMapStrength = g_gl.currentNormalMapStrength;
|
||||
key.normalMapYSign = g_gl.currentNormalMapYSign;
|
||||
|
||||
TextureResource* glowMap = QD3D12_SelectGlowMapTexture(allTextures);
|
||||
if (glowMap && glowMap->texture && glowMap->srvIndex != UINT_MAX)
|
||||
{
|
||||
key.glowMapSrvIndex = glowMap->srvIndex;
|
||||
key.useGlowMap = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
key.glowMapSrvIndex = g_gl.whiteTexture.srvIndex;
|
||||
key.useGlowMap = 0.0f;
|
||||
}
|
||||
key.glowMapStrength = g_gl.currentGlowMapStrength;
|
||||
|
||||
key.useARBPrograms = QD3D12ARB_IsActive();
|
||||
if (key.useARBPrograms)
|
||||
{
|
||||
@@ -4105,6 +4327,39 @@ static void QD3D12_PostFullscreenPass(ID3D12GraphicsCommandList* cl,
|
||||
cl->DrawInstanced(3, 1, 0, 0);
|
||||
}
|
||||
|
||||
static void QD3D12_CompositeEmissiveIntoSceneColor(QD3D12Window& w)
|
||||
{
|
||||
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
|
||||
const UINT frame = w.frameIndex;
|
||||
if (!cl || !g_gl.postAdditivePSO || !w.sceneColorBuffers[frame] || !w.emissiveBuffers[frame])
|
||||
return;
|
||||
|
||||
QD3D12_TransitionResource(cl, w.sceneColorBuffers[frame].Get(), w.sceneColorState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.emissiveBuffers[frame].Get(), w.emissiveBufferState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
D3D12_VIEWPORT viewport{};
|
||||
viewport.TopLeftX = 0.0f;
|
||||
viewport.TopLeftY = 0.0f;
|
||||
viewport.Width = (float)w.renderWidth;
|
||||
viewport.Height = (float)w.renderHeight;
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
|
||||
D3D12_RECT scissor{};
|
||||
scissor.left = 0;
|
||||
scissor.top = 0;
|
||||
scissor.right = (LONG)w.renderWidth;
|
||||
scissor.bottom = (LONG)w.renderHeight;
|
||||
|
||||
QD3D12_PostFullscreenPass(
|
||||
cl,
|
||||
g_gl.postAdditivePSO.Get(),
|
||||
w.emissiveSrvGpu[frame],
|
||||
CurrentResolvedSceneColorRTV(),
|
||||
viewport,
|
||||
scissor);
|
||||
}
|
||||
|
||||
static ID3D12Resource* QD3D12_PrepareStreamlineOutputForWrite(QD3D12Window& w)
|
||||
{
|
||||
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
|
||||
@@ -4773,6 +5028,25 @@ static void QD3D12_CreateRTVsForWindow(QD3D12Window& w)
|
||||
}
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
|
||||
{
|
||||
if (useMsaa)
|
||||
{
|
||||
CreateTexture2D(w.emissiveMsaaBuffers[i], w.emissiveMsaaState[i], QD3D12_EmissiveFormat, velocityClear, true,
|
||||
w.renderWidth, w.renderHeight, msaaSamples, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
QD3D12_RtvAt(w, QD3D12_RTV_EMISSIVE_RENDER, i), true);
|
||||
CreateTexture2D(w.emissiveBuffers[i], w.emissiveBufferState[i], QD3D12_EmissiveFormat, velocityClear, false,
|
||||
w.renderWidth, w.renderHeight, 1, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
QD3D12_RtvAt(w, QD3D12_RTV_EMISSIVE_RESOLVED, i), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateTexture2D(w.emissiveBuffers[i], w.emissiveBufferState[i], QD3D12_EmissiveFormat, velocityClear, true,
|
||||
w.renderWidth, w.renderHeight, 1, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
QD3D12_RtvAt(w, QD3D12_RTV_EMISSIVE_RENDER, i), true);
|
||||
}
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
|
||||
{
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE backBufferRtv = QD3D12_RtvAt(w, QD3D12_RTV_BACKBUFFER, i);
|
||||
@@ -4862,6 +5136,9 @@ static void QD3D12_CreateRTVsForWindow(QD3D12Window& w)
|
||||
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
|
||||
CreateTextureSrv(w.velocityBuffers[i].Get(), QD3D12_VelocityFormat, w.velocitySrvIndex[i], w.velocitySrvCpu[i], w.velocitySrvGpu[i]);
|
||||
|
||||
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
|
||||
CreateTextureSrv(w.emissiveBuffers[i].Get(), QD3D12_EmissiveFormat, w.emissiveSrvIndex[i], w.emissiveSrvCpu[i], w.emissiveSrvGpu[i]);
|
||||
|
||||
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
|
||||
CreateTextureSrv(w.slOutputBuffers[i].Get(), QD3D12_StreamlineOutputFormat, w.slOutputSrvIndex[i], w.slOutputSrvCpu[i], w.slOutputSrvGpu[i]);
|
||||
|
||||
@@ -4875,6 +5152,9 @@ static void QD3D12_CreateRTVsForWindow(QD3D12Window& w)
|
||||
|
||||
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
|
||||
CreateTextureMsaaSrv(w.velocityMsaaBuffers[i].Get(), QD3D12_VelocityFormat, w.velocityMsaaSrvIndex[i], w.velocityMsaaSrvCpu[i], w.velocityMsaaSrvGpu[i]);
|
||||
|
||||
for (UINT i = 0; i < QD3D12_FrameCount; ++i)
|
||||
CreateTextureMsaaSrv(w.emissiveMsaaBuffers[i].Get(), QD3D12_EmissiveFormat, w.emissiveMsaaSrvIndex[i], w.emissiveMsaaSrvCpu[i], w.emissiveMsaaSrvGpu[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5196,7 +5476,7 @@ static ComPtr<ID3DBlob> CompileShaderVariant(const char* entry, const char* targ
|
||||
|
||||
static void QD3D12_CreatePostRootSignature()
|
||||
{
|
||||
D3D12_DESCRIPTOR_RANGE ranges[5]{};
|
||||
D3D12_DESCRIPTOR_RANGE ranges[6]{};
|
||||
for (UINT i = 0; i < _countof(ranges); ++i)
|
||||
{
|
||||
ranges[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
@@ -5206,7 +5486,7 @@ static void QD3D12_CreatePostRootSignature()
|
||||
ranges[i].OffsetInDescriptorsFromTableStart = 0;
|
||||
}
|
||||
|
||||
D3D12_ROOT_PARAMETER params[5]{};
|
||||
D3D12_ROOT_PARAMETER params[6]{};
|
||||
for (UINT i = 0; i < _countof(params); ++i)
|
||||
{
|
||||
params[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
@@ -5363,13 +5643,14 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildPSODesc(
|
||||
|
||||
d.PrimitiveTopologyType = topoType;
|
||||
|
||||
d.NumRenderTargets = nativeColorOnly ? 1u : 4u;
|
||||
d.NumRenderTargets = nativeColorOnly ? 1u : 5u;
|
||||
d.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
if (!nativeColorOnly)
|
||||
{
|
||||
d.RTVFormats[1] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
d.RTVFormats[2] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
d.RTVFormats[3] = QD3D12_VelocityFormat;
|
||||
d.RTVFormats[4] = QD3D12_EmissiveFormat;
|
||||
}
|
||||
|
||||
d.DSVFormat = QD3D12_DepthDsvFormat;
|
||||
@@ -5387,12 +5668,13 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildPSODesc(
|
||||
d.BlendState.RenderTarget[1].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
|
||||
d.BlendState.RenderTarget[2].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
|
||||
d.BlendState.RenderTarget[3].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
|
||||
d.BlendState.RenderTarget[4].RenderTargetWriteMask = key.colorWriteMask ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
|
||||
}
|
||||
|
||||
d.BlendState.AlphaToCoverageEnable = FALSE;
|
||||
d.BlendState.IndependentBlendEnable = nativeColorOnly ? FALSE : TRUE;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < (nativeColorOnly ? 1 : 5); ++i)
|
||||
{
|
||||
auto& rt = d.BlendState.RenderTarget[i];
|
||||
rt.BlendEnable = FALSE;
|
||||
@@ -5500,16 +5782,17 @@ static void QD3D12_CreatePSOs()
|
||||
gbufferResolveDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
gbufferResolveDesc.SampleDesc.Count = 1;
|
||||
gbufferResolveDesc.SampleMask = UINT_MAX;
|
||||
gbufferResolveDesc.NumRenderTargets = 3;
|
||||
gbufferResolveDesc.NumRenderTargets = 4;
|
||||
gbufferResolveDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
gbufferResolveDesc.RTVFormats[1] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
gbufferResolveDesc.RTVFormats[2] = QD3D12_VelocityFormat;
|
||||
gbufferResolveDesc.RTVFormats[3] = QD3D12_EmissiveFormat;
|
||||
gbufferResolveDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
gbufferResolveDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
||||
gbufferResolveDesc.RasterizerState.DepthClipEnable = TRUE;
|
||||
gbufferResolveDesc.BlendState.AlphaToCoverageEnable = FALSE;
|
||||
gbufferResolveDesc.BlendState.IndependentBlendEnable = FALSE;
|
||||
for (UINT rt = 0; rt < 3; ++rt)
|
||||
for (UINT rt = 0; rt < 4; ++rt)
|
||||
{
|
||||
gbufferResolveDesc.BlendState.RenderTarget[rt].BlendEnable = FALSE;
|
||||
gbufferResolveDesc.BlendState.RenderTarget[rt].LogicOpEnable = FALSE;
|
||||
@@ -5628,13 +5911,14 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildARBPSODesc(
|
||||
d.InputLayout.NumElements = _countof(kGLVertexInputLayoutARB);
|
||||
d.PrimitiveTopologyType = topoType;
|
||||
|
||||
d.NumRenderTargets = nativeColorOnly ? 1u : 4u;
|
||||
d.NumRenderTargets = nativeColorOnly ? 1u : 5u;
|
||||
d.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
if (!nativeColorOnly)
|
||||
{
|
||||
d.RTVFormats[1] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
d.RTVFormats[2] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
d.RTVFormats[3] = QD3D12_VelocityFormat;
|
||||
d.RTVFormats[4] = QD3D12_EmissiveFormat;
|
||||
}
|
||||
|
||||
d.DSVFormat = QD3D12_DepthDsvFormat;
|
||||
@@ -5649,7 +5933,7 @@ static D3D12_GRAPHICS_PIPELINE_STATE_DESC BuildARBPSODesc(
|
||||
d.BlendState.AlphaToCoverageEnable = FALSE;
|
||||
d.BlendState.IndependentBlendEnable = nativeColorOnly ? FALSE : TRUE;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < (nativeColorOnly ? 1 : 5); ++i)
|
||||
{
|
||||
auto& rt = d.BlendState.RenderTarget[i];
|
||||
rt.BlendEnable = FALSE;
|
||||
@@ -6023,9 +6307,11 @@ void QD3D12_BeginFrame()
|
||||
const float normalClear[4] = { 0.0f, 0.0f, 1.0f, 0.5f };
|
||||
const float positionClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
const float velocityClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
const float emissiveClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentNormalRTV(), normalClear, 0, nullptr);
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentPositionRTV(), positionClear, 0, nullptr);
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentVelocityRTV(), velocityClear, 0, nullptr);
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentEmissiveRTV(), emissiveClear, 0, nullptr);
|
||||
|
||||
g_gl.frameOpen = true;
|
||||
g_gl.frameOwner = &w;
|
||||
@@ -6053,6 +6339,8 @@ void QD3D12_EndFrame()
|
||||
if (!g_gl.sceneResolvedThisFrame)
|
||||
{
|
||||
QD3D12_ResolveGBufferForCurrentFrame(w);
|
||||
if (!g_gl.raytracedLightingReadyThisFrame)
|
||||
QD3D12_CompositeEmissiveIntoSceneColor(w);
|
||||
|
||||
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.sceneColorBuffers[w.frameIndex].Get(), w.sceneColorState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
QD3D12_TransitionResource(g_gl.cmdList.Get(), w.normalBuffers[w.frameIndex].Get(), w.normalBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
@@ -7544,8 +7832,12 @@ static void FlushImmediate(GLenum mode, const GLVertex* src, size_t n)
|
||||
const bool explicitNormalUnit = (!arbProgramsActive) &&
|
||||
(g_gl.currentNormalMapTexture != 0) &&
|
||||
(g_gl.boundTexture[unit] == g_gl.currentNormalMapTexture);
|
||||
const bool taggedGlowUnit = (!arbProgramsActive) && QD3D12_IsTextureTaggedGlowMap(g_gl.boundTexture[unit]);
|
||||
const bool explicitGlowUnit = (!arbProgramsActive) &&
|
||||
(g_gl.currentGlowMapTexture != 0) &&
|
||||
(g_gl.boundTexture[unit] == g_gl.currentGlowMapTexture);
|
||||
|
||||
const bool wantsUnit = arbUnit || fixedColorUnit || taggedNormalUnit || explicitNormalUnit;
|
||||
const bool wantsUnit = arbUnit || fixedColorUnit || taggedNormalUnit || explicitNormalUnit || taggedGlowUnit || explicitGlowUnit;
|
||||
if (!wantsUnit)
|
||||
continue;
|
||||
|
||||
@@ -7571,6 +7863,13 @@ static void FlushImmediate(GLenum mode, const GLVertex* src, size_t n)
|
||||
UploadTexture(*normalMapTex);
|
||||
}
|
||||
|
||||
TextureResource* glowMapTex = QD3D12_SelectGlowMapTexture(boundTextures);
|
||||
if (glowMapTex && glowMapTex != &g_gl.whiteTexture && !glowMapTex->gpuValid)
|
||||
{
|
||||
EnsureTextureResource(*glowMapTex);
|
||||
UploadTexture(*glowMapTex);
|
||||
}
|
||||
|
||||
TextureResource* tex0 = boundTextures[0];
|
||||
TextureResource* tex1 = boundTextures[1];
|
||||
|
||||
@@ -7876,9 +8175,11 @@ static void QD3D12_FlushQueuedBatches()
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE lastTex0{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE lastTex1{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE lastNormalMap{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE lastGlowMap{};
|
||||
bool haveLastTex0 = false;
|
||||
bool haveLastTex1 = false;
|
||||
bool haveLastNormalMap = false;
|
||||
bool haveLastGlowMap = false;
|
||||
D3D12_PRIMITIVE_TOPOLOGY lastTopo = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||
|
||||
for (size_t i = 0; i < g_gl.queuedBatches.size(); ++i)
|
||||
@@ -7904,6 +8205,7 @@ static void QD3D12_FlushQueuedBatches()
|
||||
haveLastTex0 = false;
|
||||
haveLastTex1 = false;
|
||||
haveLastNormalMap = false;
|
||||
haveLastGlowMap = false;
|
||||
lastTopo = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||
}
|
||||
|
||||
@@ -7971,6 +8273,7 @@ static void QD3D12_FlushQueuedBatches()
|
||||
dc->_motionPad[0] = batch.key.useNormalMap;
|
||||
dc->_motionPad[1] = batch.key.normalMapStrength;
|
||||
dc->_motionPad[2] = batch.key.normalMapYSign;
|
||||
dc->_motionPad[3] = (batch.key.useGlowMap > 0.5f) ? batch.key.glowMapStrength : 0.0f;
|
||||
|
||||
if (batch.key.useARBPrograms)
|
||||
{
|
||||
@@ -8026,6 +8329,7 @@ static void QD3D12_FlushQueuedBatches()
|
||||
haveLastTex0 = false;
|
||||
haveLastTex1 = false;
|
||||
haveLastNormalMap = false;
|
||||
haveLastGlowMap = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -8062,6 +8366,18 @@ static void QD3D12_FlushQueuedBatches()
|
||||
lastNormalMap = normalMapGpu;
|
||||
haveLastNormalMap = true;
|
||||
}
|
||||
|
||||
UINT glowSrvIndex = batch.key.glowMapSrvIndex;
|
||||
if (glowSrvIndex == UINT_MAX)
|
||||
glowSrvIndex = g_gl.whiteTexture.srvIndex;
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE glowMapGpu = QD3D12_SrvGpu(glowSrvIndex);
|
||||
if (!haveLastGlowMap || glowMapGpu.ptr != lastGlowMap.ptr)
|
||||
{
|
||||
g_gl.cmdList->SetGraphicsRootDescriptorTable(4, glowMapGpu);
|
||||
lastGlowMap = glowMapGpu;
|
||||
haveLastGlowMap = true;
|
||||
}
|
||||
}
|
||||
|
||||
g_gl.cmdList->SetGraphicsRootConstantBufferView(0, cbAlloc.gpu);
|
||||
@@ -8192,11 +8508,13 @@ void APIENTRY glClear(GLbitfield mask)
|
||||
const float normalClear[4] = { 0.0f, 0.0f, 1.0f, 0.5f };
|
||||
const float positionClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
const float velocityClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
const float emissiveClear[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentRTV(), cc, 1, &clearRect);
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentNormalRTV(), normalClear, 1, &clearRect);
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentPositionRTV(), positionClear, 1, &clearRect);
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentVelocityRTV(), velocityClear, 1, &clearRect);
|
||||
g_gl.cmdList->ClearRenderTargetView(CurrentEmissiveRTV(), emissiveClear, 1, &clearRect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8543,6 +8861,9 @@ void APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures)
|
||||
if (g_gl.currentNormalMapTexture == deadId)
|
||||
g_gl.currentNormalMapTexture = 0;
|
||||
|
||||
if (g_gl.currentGlowMapTexture == deadId)
|
||||
g_gl.currentGlowMapTexture = 0;
|
||||
|
||||
auto it = g_gl.textures.find(deadId);
|
||||
if (it != g_gl.textures.end())
|
||||
{
|
||||
@@ -8606,6 +8927,49 @@ void APIENTRY glNormalMapYSignf(GLfloat sign)
|
||||
g_gl.currentNormalMapYSign = (sign < 0.0f) ? -1.0f : 1.0f;
|
||||
}
|
||||
|
||||
void APIENTRY glTagTextureGlowMap(GLuint texture, GLboolean isGlowMap)
|
||||
{
|
||||
if (texture == 0)
|
||||
{
|
||||
g_gl.lastError = GL_INVALID_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
TextureResource& tex = QD3D12_EnsureTextureName(texture);
|
||||
tex.isGlowMap = (isGlowMap != GL_FALSE);
|
||||
}
|
||||
|
||||
void APIENTRY glTextureGlowMap(GLuint texture, GLboolean isGlowMap)
|
||||
{
|
||||
glTagTextureGlowMap(texture, isGlowMap);
|
||||
}
|
||||
|
||||
void APIENTRY glBindGlowMapTexture(GLuint texture)
|
||||
{
|
||||
if (texture != 0)
|
||||
{
|
||||
TextureResource& tex = QD3D12_EnsureTextureName(texture);
|
||||
if (tex.isNormalMap && !tex.isGlowMap)
|
||||
{
|
||||
QD3D12_Log("glBindGlowMapTexture(%u) ignored: texture is tagged as a normal map. Did you pass the bump image texnum instead of the glow image texnum?", texture);
|
||||
g_gl.currentGlowMapTexture = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_gl.currentGlowMapTexture = texture;
|
||||
}
|
||||
|
||||
void APIENTRY glGlowMapTexture(GLuint texture)
|
||||
{
|
||||
glBindGlowMapTexture(texture);
|
||||
}
|
||||
|
||||
void APIENTRY glGlowMapStrengthf(GLfloat strength)
|
||||
{
|
||||
g_gl.currentGlowMapStrength = (strength < 0.0f) ? 0.0f : strength;
|
||||
}
|
||||
|
||||
void APIENTRY glRaytracingMaterialFlagsQD3D12(GLuint flags)
|
||||
{
|
||||
g_gl.currentRayMaterialFlags = QD3D12_ClampRayMaterialFlags((uint32_t)flags);
|
||||
@@ -8742,6 +9106,10 @@ void APIENTRY glGetIntegerv(GLenum pname, GLint* params)
|
||||
*params = (GLint)g_gl.currentNormalMapTexture;
|
||||
break;
|
||||
|
||||
case GL_GLOW_MAP_BINDING_QD3D12:
|
||||
*params = (GLint)g_gl.currentGlowMapTexture;
|
||||
break;
|
||||
|
||||
case GL_QD3D12_MATERIAL_FLAGS:
|
||||
*params = (GLint)QD3D12_CurrentRayMaterialFlags();
|
||||
break;
|
||||
@@ -11301,6 +11669,11 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
|
||||
{ "glNormalMapTexture", (PROC)glNormalMapTexture },
|
||||
{ "glNormalMapStrengthf", (PROC)glNormalMapStrengthf },
|
||||
{ "glNormalMapYSignf", (PROC)glNormalMapYSignf },
|
||||
{ "glTagTextureGlowMap", (PROC)glTagTextureGlowMap },
|
||||
{ "glTextureGlowMap", (PROC)glTextureGlowMap },
|
||||
{ "glBindGlowMapTexture", (PROC)glBindGlowMapTexture },
|
||||
{ "glGlowMapTexture", (PROC)glGlowMapTexture },
|
||||
{ "glGlowMapStrengthf", (PROC)glGlowMapStrengthf },
|
||||
{ "glGlassMaterialQD3D12", (PROC)glGlassMaterialQD3D12 },
|
||||
{ "glMaterialGlassQD3D12", (PROC)glMaterialGlassQD3D12 },
|
||||
{ "glRaytracingMaterialFlagsQD3D12", (PROC)glRaytracingMaterialFlagsQD3D12 },
|
||||
@@ -11560,8 +11933,8 @@ static void QD3D12_PointResolveMsaaGBufferToSingleSample(QD3D12Window& w)
|
||||
const UINT frame = w.frameIndex;
|
||||
|
||||
if (!w.depthMsaaBuffer ||
|
||||
!w.normalMsaaBuffers[frame] || !w.positionMsaaBuffers[frame] || !w.velocityMsaaBuffers[frame] ||
|
||||
!w.normalBuffers[frame] || !w.positionBuffers[frame] || !w.velocityBuffers[frame])
|
||||
!w.normalMsaaBuffers[frame] || !w.positionMsaaBuffers[frame] || !w.velocityMsaaBuffers[frame] || !w.emissiveMsaaBuffers[frame] ||
|
||||
!w.normalBuffers[frame] || !w.positionBuffers[frame] || !w.velocityBuffers[frame] || !w.emissiveBuffers[frame])
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -11570,16 +11943,19 @@ static void QD3D12_PointResolveMsaaGBufferToSingleSample(QD3D12Window& w)
|
||||
QD3D12_TransitionResource(cl, w.normalMsaaBuffers[frame].Get(), w.normalMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
QD3D12_TransitionResource(cl, w.positionMsaaBuffers[frame].Get(), w.positionMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
QD3D12_TransitionResource(cl, w.velocityMsaaBuffers[frame].Get(), w.velocityMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
QD3D12_TransitionResource(cl, w.emissiveMsaaBuffers[frame].Get(), w.emissiveMsaaState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
QD3D12_TransitionResource(cl, w.normalBuffers[frame].Get(), w.normalBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.positionBuffers[frame].Get(), w.positionBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.velocityBuffers[frame].Get(), w.velocityBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.emissiveBuffers[frame].Get(), w.emissiveBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[3] =
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[4] =
|
||||
{
|
||||
CurrentResolvedNormalRTV(),
|
||||
CurrentResolvedPositionRTV(),
|
||||
CurrentResolvedVelocityRTV()
|
||||
CurrentResolvedVelocityRTV(),
|
||||
CurrentResolvedEmissiveRTV()
|
||||
};
|
||||
|
||||
D3D12_VIEWPORT viewport{};
|
||||
@@ -11600,17 +11976,18 @@ static void QD3D12_PointResolveMsaaGBufferToSingleSample(QD3D12Window& w)
|
||||
cl->SetDescriptorHeaps(_countof(heaps), heaps);
|
||||
cl->SetGraphicsRootSignature(g_gl.postRootSig.Get());
|
||||
cl->SetPipelineState(g_gl.postGBufferPointResolveMsaaPSO.Get());
|
||||
cl->OMSetRenderTargets(3, rtvs, FALSE, nullptr);
|
||||
cl->OMSetRenderTargets(4, rtvs, FALSE, nullptr);
|
||||
cl->RSSetViewports(1, &viewport);
|
||||
cl->RSSetScissorRects(1, &scissor);
|
||||
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// t1..t4: depth + discontinuous G-buffer attributes. The shader uses
|
||||
// t1..t5: depth + discontinuous G-buffer attributes. The shader uses
|
||||
// Texture2DMS.Load(), selects a single depth-nearest sample, and never averages.
|
||||
cl->SetGraphicsRootDescriptorTable(1, w.depthMsaaSrvGpu);
|
||||
cl->SetGraphicsRootDescriptorTable(2, w.normalMsaaSrvGpu[frame]);
|
||||
cl->SetGraphicsRootDescriptorTable(3, w.positionMsaaSrvGpu[frame]);
|
||||
cl->SetGraphicsRootDescriptorTable(4, w.velocityMsaaSrvGpu[frame]);
|
||||
cl->SetGraphicsRootDescriptorTable(5, w.emissiveMsaaSrvGpu[frame]);
|
||||
cl->DrawInstanced(3, 1, 0, 0);
|
||||
}
|
||||
|
||||
@@ -11686,6 +12063,7 @@ static void QD3D12_BindLowResSceneTargets(QD3D12Window& w)
|
||||
QD3D12_TransitionResource(cl, w.normalMsaaBuffers[w.frameIndex].Get(), w.normalMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.positionMsaaBuffers[w.frameIndex].Get(), w.positionMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.velocityMsaaBuffers[w.frameIndex].Get(), w.velocityMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.emissiveMsaaBuffers[w.frameIndex].Get(), w.emissiveMsaaState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.depthMsaaBuffer.Get(), w.depthMsaaState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
}
|
||||
else
|
||||
@@ -11694,18 +12072,20 @@ static void QD3D12_BindLowResSceneTargets(QD3D12Window& w)
|
||||
QD3D12_TransitionResource(cl, w.normalBuffers[w.frameIndex].Get(), w.normalBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.positionBuffers[w.frameIndex].Get(), w.positionBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.velocityBuffers[w.frameIndex].Get(), w.velocityBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.emissiveBuffers[w.frameIndex].Get(), w.emissiveBufferState[w.frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, w.depthBuffer.Get(), w.depthState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[4] =
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[5] =
|
||||
{
|
||||
CurrentRTV(),
|
||||
CurrentNormalRTV(),
|
||||
CurrentPositionRTV(),
|
||||
CurrentVelocityRTV()
|
||||
CurrentVelocityRTV(),
|
||||
CurrentEmissiveRTV()
|
||||
};
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE dsv = CurrentActiveSceneDepthDSV();
|
||||
cl->OMSetRenderTargets(4, rtvs, FALSE, &dsv);
|
||||
cl->OMSetRenderTargets(5, rtvs, FALSE, &dsv);
|
||||
cl->RSSetViewports(1, &w.viewport);
|
||||
cl->RSSetScissorRects(1, &w.scissor);
|
||||
}
|
||||
@@ -11795,6 +12175,8 @@ static void QD3D12_ResolveSceneToOutputAndEnterNativePhase(QD3D12Window& w)
|
||||
QD3D12_ResolveGBufferForCurrentFrame(w);
|
||||
|
||||
const bool useLightingUpscaleInput = QD3D12_UseLightingTextureAsUpscaleInput(w);
|
||||
if (!g_gl.raytracedLightingReadyThisFrame)
|
||||
QD3D12_CompositeEmissiveIntoSceneColor(w);
|
||||
|
||||
QD3D12_TransitionResource(cl, w.sceneColorBuffers[w.frameIndex].Get(), w.sceneColorState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
QD3D12_TransitionResource(cl, w.velocityBuffers[w.frameIndex].Get(), w.velocityBufferState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
@@ -11862,9 +12244,10 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
ID3D12Resource* sceneColor = window->sceneColorBuffers[frameIndex].Get();
|
||||
ID3D12Resource* sceneNormal = window->normalBuffers[frameIndex].Get();
|
||||
ID3D12Resource* scenePosition = window->positionBuffers[frameIndex].Get();
|
||||
ID3D12Resource* sceneEmissive = window->emissiveBuffers[frameIndex].Get();
|
||||
ID3D12Resource* sceneDepth = window->depthBuffer.Get();
|
||||
|
||||
if (!sceneColor || !sceneNormal || !scenePosition || !sceneDepth)
|
||||
if (!sceneColor || !sceneNormal || !scenePosition || !sceneEmissive || !sceneDepth)
|
||||
return;
|
||||
|
||||
QD3D12_TransitionResource(
|
||||
@@ -11885,6 +12268,12 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
window->positionBufferState[frameIndex],
|
||||
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
QD3D12_TransitionResource(
|
||||
cl,
|
||||
sceneEmissive,
|
||||
window->emissiveBufferState[frameIndex],
|
||||
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
QD3D12_TransitionResource(
|
||||
cl,
|
||||
sceneDepth,
|
||||
@@ -11926,6 +12315,7 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
activeMaxBounces,
|
||||
useDLSSRayReconstruction ? 0 : 1,
|
||||
useDLSSRayReconstruction ? 0.0f : 1.0f);
|
||||
glRaytracingLightingSetEmissiveInput(sceneEmissive, QD3D12_EmissiveFormat);
|
||||
|
||||
glRaytracingLightingPassDesc_t pass = {};
|
||||
pass.albedoTexture = sceneColor;
|
||||
@@ -11954,6 +12344,7 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
QD3D12_TransitionResource(cl, window->normalMsaaBuffers[frameIndex].Get(), window->normalMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, window->positionMsaaBuffers[frameIndex].Get(), window->positionMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, window->velocityMsaaBuffers[frameIndex].Get(), window->velocityMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, window->emissiveMsaaBuffers[frameIndex].Get(), window->emissiveMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
QD3D12_TransitionResource(cl, window->depthMsaaBuffer.Get(), window->depthMsaaState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
}
|
||||
else
|
||||
@@ -11976,6 +12367,12 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
window->positionBufferState[frameIndex],
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
|
||||
QD3D12_TransitionResource(
|
||||
cl,
|
||||
sceneEmissive,
|
||||
window->emissiveBufferState[frameIndex],
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
|
||||
QD3D12_TransitionResource(
|
||||
cl,
|
||||
sceneDepth,
|
||||
|
||||
+14
-1
@@ -2254,4 +2254,17 @@ extern "C" {
|
||||
}
|
||||
#endif
|
||||
|
||||
void glRaytracingLightingSetVolumetricScattering(glRaytracingLight_t* light, float strength);
|
||||
void glRaytracingLightingSetVolumetricScattering(glRaytracingLight_t* light, float strength);
|
||||
|
||||
// QD3D12 glow-map extension additions for opengl.h
|
||||
#ifndef GL_GLOW_MAP_BINDING_QD3D12
|
||||
#define GL_GLOW_MAP_BINDING_QD3D12 0x6005
|
||||
#endif
|
||||
|
||||
// Glow-map material tagging / binding. Tagging is optional but lets the shim
|
||||
// auto-discover a glow map from bound texture units. Explicit binding wins.
|
||||
void APIENTRY glTagTextureGlowMap(GLuint texture, GLboolean isGlowMap);
|
||||
void APIENTRY glTextureGlowMap(GLuint texture, GLboolean isGlowMap); // alias
|
||||
void APIENTRY glBindGlowMapTexture(GLuint texture); // 0 disables explicit glow map
|
||||
void APIENTRY glGlowMapTexture(GLuint texture); // alias
|
||||
void APIENTRY glGlowMapStrengthf(GLfloat strength); // default 1.0; >1 allows overbright emission
|
||||
|
||||
@@ -931,6 +931,11 @@ void idMaterial::ParseBlend( idLexer &src, shaderStage_t *stage ) {
|
||||
stage->lighting = SL_DIFFUSE;
|
||||
return;
|
||||
}
|
||||
if (!token.Icmp("glowmap")) {
|
||||
stage->lighting = SL_GLOWMAP;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !token.Icmp( "specularmap" ) ) {
|
||||
stage->lighting = SL_SPECULAR;
|
||||
return;
|
||||
@@ -1895,6 +1900,20 @@ idImage* idMaterial::GetBumpImage(void) const {
|
||||
return GetEditorImage();
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
idMaterial::GetGlowImage
|
||||
===================
|
||||
*/
|
||||
idImage* idMaterial::GetGlowImage(void) const {
|
||||
for (int i = 0; i < numStages; i++) {
|
||||
if ((stages[i].lighting == SL_GLOWMAP || stages[i].isGlow) && stages[i].texture.image) {
|
||||
return stages[i].texture.image;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
idMaterial::AddImplicitStages
|
||||
@@ -2254,12 +2273,18 @@ void idMaterial::ParseMaterial(idLexer& src) {
|
||||
src.ParseRestOfLine(renderBump);
|
||||
continue;
|
||||
}
|
||||
#ifdef PREY
|
||||
|
||||
else if (!token.Icmp("glowmap")) {
|
||||
src.ReadTokenOnLine(&token);
|
||||
str = R_ParsePastImageProgram(src);
|
||||
idStr::snPrintf(buffer, sizeof(buffer), "blend glowmap\nmap %s\n}\n", str);
|
||||
newSrc.LoadMemory(buffer, strlen(buffer), "glowmap");
|
||||
newSrc.SetFlags(LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES);
|
||||
ParseStage(newSrc, trpDefault);
|
||||
newSrc.FreeSource();
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef PREY
|
||||
else if (!token.Icmp("highres")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,8 @@ typedef enum {
|
||||
SL_AMBIENT, // execute after lighting
|
||||
SL_BUMP,
|
||||
SL_DIFFUSE,
|
||||
SL_SPECULAR
|
||||
SL_SPECULAR,
|
||||
SL_GLOWMAP
|
||||
#ifdef PREY
|
||||
, SL_SHADER
|
||||
#endif
|
||||
@@ -506,6 +507,7 @@ public:
|
||||
// jmarshall
|
||||
idImage* GetDiffuseImage(void) const;
|
||||
idImage* GetBumpImage(void) const;
|
||||
idImage* GetGlowImage(void) const;
|
||||
bool IsSky(void) const;
|
||||
// jmarshall end
|
||||
// returns true if the material will generate interactions with normal lights
|
||||
|
||||
+17
-276
@@ -512,6 +512,16 @@ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) {
|
||||
shader->GetBumpImage()->Bind();
|
||||
glBindNormalMapTexture(shader->GetBumpImage()->texnum);
|
||||
|
||||
idImage* glowMapImage = shader->GetGlowImage();
|
||||
if (glowMapImage)
|
||||
{
|
||||
GL_SelectTexture(2);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glowMapImage->Bind();
|
||||
glBindGlowMapTexture(glowMapImage->texnum);
|
||||
glGlowMapStrengthf(0.5f);
|
||||
}
|
||||
|
||||
if (!surf->geo->isSkeletal)
|
||||
{
|
||||
glGeometryFlagf(GEOMETRY_FLAG_NONE);
|
||||
@@ -527,9 +537,15 @@ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) {
|
||||
// draw it
|
||||
RB_DrawElementsWithCounters(tri);
|
||||
|
||||
if (glowMapImage)
|
||||
{
|
||||
GL_SelectTexture(2);
|
||||
glBindGlowMapTexture(0);
|
||||
globalImages->BindNull();
|
||||
}
|
||||
|
||||
glBindNormalMapTexture(0);
|
||||
GL_SelectTexture(1);
|
||||
glBindNormalMapTexture(0);
|
||||
globalImages->BindNull();
|
||||
GL_SelectTexture(0);
|
||||
}
|
||||
@@ -1073,205 +1089,6 @@ int RB_STD_DrawShaderPasses( drawSurf_t **drawSurfs, int numDrawSurfs ) {
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
BACK END RENDERING OF STENCIL SHADOWS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=====================
|
||||
RB_T_Shadow
|
||||
|
||||
the shadow volumes face INSIDE
|
||||
=====================
|
||||
*/
|
||||
static void RB_T_Shadow( const drawSurf_t *surf ) {
|
||||
const srfTriangles_t *tri;
|
||||
|
||||
// set the light position if we are using a vertex program to project the rear surfaces
|
||||
if ( tr.backEndRendererHasVertexPrograms && r_useShadowVertexProgram.GetBool()
|
||||
&& surf->space != backEnd.currentSpace ) {
|
||||
idVec4 localLight;
|
||||
|
||||
R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.vLight->globalLightOrigin, localLight.ToVec3() );
|
||||
localLight.w = 0.0f;
|
||||
glProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, localLight.ToFloatPtr() );
|
||||
}
|
||||
|
||||
tri = surf->geo;
|
||||
|
||||
if ( !tri->shadowCache ) {
|
||||
return;
|
||||
}
|
||||
|
||||
glVertexPointer( 4, GL_FLOAT, sizeof( shadowCache_t ), vertexCache.Position(tri->shadowCache) );
|
||||
|
||||
// we always draw the sil planes, but we may not need to draw the front or rear caps
|
||||
int numIndexes;
|
||||
bool external = false;
|
||||
|
||||
if ( !r_useExternalShadows.GetInteger() ) {
|
||||
numIndexes = tri->numIndexes;
|
||||
} else if ( r_useExternalShadows.GetInteger() == 2 ) { // force to no caps for testing
|
||||
numIndexes = tri->numShadowIndexesNoCaps;
|
||||
} else if ( !(surf->dsFlags & DSF_VIEW_INSIDE_SHADOW) ) {
|
||||
// if we aren't inside the shadow projection, no caps are ever needed needed
|
||||
numIndexes = tri->numShadowIndexesNoCaps;
|
||||
external = true;
|
||||
} else if ( !backEnd.vLight->viewInsideLight && !(surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE) ) {
|
||||
// if we are inside the shadow projection, but outside the light, and drawing
|
||||
// a non-infinite shadow, we can skip some caps
|
||||
if ( backEnd.vLight->viewSeesShadowPlaneBits & surf->geo->shadowCapPlaneBits ) {
|
||||
// we can see through a rear cap, so we need to draw it, but we can skip the
|
||||
// caps on the actual surface
|
||||
numIndexes = tri->numShadowIndexesNoFrontCaps;
|
||||
} else {
|
||||
// we don't need to draw any caps
|
||||
numIndexes = tri->numShadowIndexesNoCaps;
|
||||
}
|
||||
external = true;
|
||||
} else {
|
||||
// must draw everything
|
||||
numIndexes = tri->numIndexes;
|
||||
}
|
||||
|
||||
// set depth bounds
|
||||
if( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
|
||||
glDepthBoundsEXT( surf->scissorRect.zmin, surf->scissorRect.zmax );
|
||||
}
|
||||
|
||||
// debug visualization
|
||||
if ( r_showShadows.GetInteger() ) {
|
||||
if ( r_showShadows.GetInteger() == 3 ) {
|
||||
if ( external ) {
|
||||
glColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
|
||||
} else {
|
||||
// these are the surfaces that require the reverse
|
||||
glColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright );
|
||||
}
|
||||
} else {
|
||||
// draw different color for turboshadows
|
||||
if ( surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE ) {
|
||||
if ( numIndexes == tri->numIndexes ) {
|
||||
glColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright );
|
||||
} else {
|
||||
glColor3f( 1/backEnd.overBright, 0.4/backEnd.overBright, 0.1/backEnd.overBright );
|
||||
}
|
||||
} else {
|
||||
if ( numIndexes == tri->numIndexes ) {
|
||||
glColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
|
||||
} else if ( numIndexes == tri->numShadowIndexesNoFrontCaps ) {
|
||||
glColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.6/backEnd.overBright );
|
||||
} else {
|
||||
glColor3f( 0.6/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
GL_Cull( CT_TWO_SIDED );
|
||||
RB_DrawShadowElementsWithCounters( tri, numIndexes );
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
glEnable( GL_STENCIL_TEST );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// patent-free work around
|
||||
if ( !external ) {
|
||||
// "preload" the stencil buffer with the number of volumes
|
||||
// that get clipped by the near or far clip plane
|
||||
glStencilOp( GL_KEEP, tr.stencilDecr, tr.stencilDecr );
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
RB_DrawShadowElementsWithCounters( tri, numIndexes );
|
||||
glStencilOp( GL_KEEP, tr.stencilIncr, tr.stencilIncr );
|
||||
GL_Cull( CT_BACK_SIDED );
|
||||
RB_DrawShadowElementsWithCounters( tri, numIndexes );
|
||||
}
|
||||
|
||||
// traditional depth-pass stencil shadows
|
||||
glStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr );
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
RB_DrawShadowElementsWithCounters( tri, numIndexes );
|
||||
|
||||
glStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr );
|
||||
GL_Cull( CT_BACK_SIDED );
|
||||
RB_DrawShadowElementsWithCounters( tri, numIndexes );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
RB_StencilShadowPass
|
||||
|
||||
Stencil test should already be enabled, and the stencil buffer should have
|
||||
been set to 128 on any surfaces that might receive shadows
|
||||
=====================
|
||||
*/
|
||||
void RB_StencilShadowPass( const drawSurf_t *drawSurfs ) {
|
||||
if ( !r_shadows.GetBool() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !drawSurfs ) {
|
||||
return;
|
||||
}
|
||||
|
||||
RB_LogComment( "---------- RB_StencilShadowPass ----------\n" );
|
||||
|
||||
globalImages->BindNull();
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
|
||||
// for visualizing the shadows
|
||||
if ( r_showShadows.GetInteger() ) {
|
||||
if ( r_showShadows.GetInteger() == 2 ) {
|
||||
// draw filled in
|
||||
GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS );
|
||||
} else {
|
||||
// draw as lines, filling the depth buffer
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS );
|
||||
}
|
||||
} else {
|
||||
// don't write to the color buffer, just the stencil buffer
|
||||
GL_State( GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS );
|
||||
}
|
||||
|
||||
if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) {
|
||||
glPolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() );
|
||||
glEnable( GL_POLYGON_OFFSET_FILL );
|
||||
}
|
||||
|
||||
glStencilFunc( GL_ALWAYS, 1, 255 );
|
||||
|
||||
if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
|
||||
glEnable( GL_DEPTH_BOUNDS_TEST_EXT );
|
||||
}
|
||||
|
||||
RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_Shadow );
|
||||
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
|
||||
if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) {
|
||||
glDisable( GL_POLYGON_OFFSET_FILL );
|
||||
}
|
||||
|
||||
if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) {
|
||||
glDisable( GL_DEPTH_BOUNDS_TEST_EXT );
|
||||
}
|
||||
|
||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
|
||||
glStencilFunc( GL_GEQUAL, 128, 255 );
|
||||
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================================
|
||||
|
||||
@@ -1627,76 +1444,6 @@ void RB_STD_FogAllLights( void ) {
|
||||
|
||||
//=========================================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
RB_STD_LightScale
|
||||
|
||||
Perform extra blending passes to multiply the entire buffer by
|
||||
a floating point value
|
||||
==================
|
||||
*/
|
||||
void RB_STD_LightScale( void ) {
|
||||
float v, f;
|
||||
|
||||
if ( backEnd.overBright == 1.0f ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( r_skipLightScale.GetBool() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
RB_LogComment( "---------- RB_STD_LightScale ----------\n" );
|
||||
|
||||
// the scissor may be smaller than the viewport for subviews
|
||||
if ( r_useScissor.GetBool() ) {
|
||||
glScissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1,
|
||||
backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1,
|
||||
backEnd.viewDef->scissor.x2 - backEnd.viewDef->scissor.x1 + 1,
|
||||
backEnd.viewDef->scissor.y2 - backEnd.viewDef->scissor.y1 + 1 );
|
||||
backEnd.currentScissor = backEnd.viewDef->scissor;
|
||||
}
|
||||
|
||||
// full screen blends
|
||||
glLoadIdentity();
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho( 0, 1, 0, 1, -1, 1 );
|
||||
|
||||
GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR );
|
||||
GL_Cull( CT_TWO_SIDED ); // so mirror views also get it
|
||||
globalImages->BindNull();
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glDisable( GL_STENCIL_TEST );
|
||||
|
||||
v = 1;
|
||||
while ( idMath::Fabs( v - backEnd.overBright ) > 0.01 ) { // a little extra slop
|
||||
f = backEnd.overBright / v;
|
||||
f /= 2;
|
||||
if ( f > 1 ) {
|
||||
f = 1;
|
||||
}
|
||||
glColor3f( f, f, f );
|
||||
v = v * f * 2;
|
||||
|
||||
glBegin( GL_QUADS );
|
||||
glVertex2f( 0,0 );
|
||||
glVertex2f( 0,1 );
|
||||
glVertex2f( 1,1 );
|
||||
glVertex2f( 1,0 );
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
glPopMatrix();
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
GL_Cull( CT_FRONT_SIDED );
|
||||
}
|
||||
|
||||
//=========================================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
RB_STD_DrawView
|
||||
@@ -1717,9 +1464,6 @@ void RB_STD_DrawView( void ) {
|
||||
// clear the z buffer, set the projection matrix, etc
|
||||
RB_BeginDrawingView();
|
||||
|
||||
// decide how much overbrighting we are going to do
|
||||
RB_DetermineLightScale();
|
||||
|
||||
// fill the depth buffer and clear color buffer to black except on
|
||||
// subviews
|
||||
RB_STD_FillDepthBuffer( drawSurfs, numDrawSurfs );
|
||||
@@ -1730,9 +1474,6 @@ void RB_STD_DrawView( void ) {
|
||||
// disable stencil shadow test
|
||||
glStencilFunc( GL_ALWAYS, 128, 255 );
|
||||
|
||||
// uplight the entire screen to crutch up not having better blending range
|
||||
RB_STD_LightScale();
|
||||
|
||||
// now draw any non-light dependent shading passes
|
||||
int processed = RB_STD_DrawShaderPasses( drawSurfs, numDrawSurfs );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user