/* =========================================================================== Copyright (C) 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 . =========================================================================== */ // add fragments of transparent surfaces to per-pixel linked lists #include "common.hlsli" #include "world.h.hlsli" #include "world.hlsli" #include "oit.h.hlsli" cbuffer RootConstants { matrix modelViewMatrix; matrix projectionMatrix; float4 clipPlane; uint textureIndex; uint samplerIndex; uint alphaTest; uint counterBuffer; uint indexTexture; uint fragmentBuffer; float greyscale; uint stateBits; uint shaderTrace; uint depthFadeDistOffset; // offset: fp16 - distance: fp16 uint depthFadeScaleBias; // enable: 1 - color bias: 4 - color scale: 4 }; #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; float clipDist : SV_ClipDistance0; float2 proj2232 : PROJ; float depthVS : DEPTHVS; }; #if VERTEX_SHADER 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.clipDist = dot(positionVS, clipPlane); output.proj2232 = float2(-projectionMatrix[2][2], projectionMatrix[2][3]); output.depthVS = -positionVS.z; return output; } #endif #if PIXEL_SHADER [earlydepthstencil] void ps(VOut input) { Texture2D texture0 = ResourceDescriptorHeap[textureIndex]; SamplerState sampler0 = SamplerDescriptorHeap[samplerIndex]; float4 dst = texture0.Sample(sampler0, input.texCoords) * input.color; if(FailsAlphaTest(dst.a, alphaTest)) { return; } dst = MakeGreyscale(dst, greyscale); RWStructuredBuffer counter = ResourceDescriptorHeap[counterBuffer]; uint fragmentIndex; InterlockedAdd(counter[0].fragmentCount, 1, fragmentIndex); if(fragmentIndex < counter[0].maxFragmentCount) { RWTexture2D indexTex = ResourceDescriptorHeap[indexTexture]; RWStructuredBuffer fragments = ResourceDescriptorHeap[fragmentBuffer]; uint prevFragmentIndex; InterlockedExchange(indexTex[int2(input.position.xy)], fragmentIndex, prevFragmentIndex); OIT_Fragment fragment; fragment.color = PackColor(dst); fragment.depth = input.depthVS; fragment.stateBits = stateBits; fragment.next = prevFragmentIndex; fragment.shaderTrace = shaderTrace; fragment.depthFadeDistOffset = depthFadeDistOffset; fragment.depthFadeScaleBias = depthFadeScaleBias; fragments[fragmentIndex] = fragment; } else { uint garbage; InterlockedAdd(counter[0].overflowCount, 1, garbage); InterlockedAdd(counter[0].fragmentCount, -1, garbage); } } #endif