/* =========================================================================== Copyright (C) 2024 Gian 'myT' Schellenbaum This file is part of Challenge Quake 3 (CNQ3). Challenge Quake 3 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Challenge Quake 3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Challenge Quake 3. If not, see . =========================================================================== */ // generic shader for the prepass of opaque surfaces #include "common.hlsli" #include "alpha_test.h.hlsli" #include "scene_view.h.hlsli" cbuffer RootConstants { matrix modelViewMatrix; matrix modelMatrix; matrix prevModelMatrix; float normalMatrix0; float normalMatrix1; float normalMatrix2; float normalMatrix3; float normalMatrix4; float normalMatrix5; float normalMatrix6; float normalMatrix7; float normalMatrix8; float motionBlurScale; uint textureIndex; uint samplerIndex; uint alphaTest; uint motionBlurMode; }; struct VIn { float3 position : POSITION; float3 normal : NORMAL; float2 texCoords : TEXCOORD0; float4 color : COLOR0; }; struct VOut { float4 position : SV_Position; float4 currPosition : CURRPOSITION; float4 prevPosition : PREVPOSITION; float4 prevPositionMB : PREVPOSITIONMB; #if BARYCENTRICS nointerpolation float3 normalWS : NORMALWS; nointerpolation float3 positionWS : POSITIONWS; #else float3 normalWS : NORMALWS; float3 positionWS : POSITIONWS; #endif float2 texCoords : TEXCOORD0; float4 color : COLOR0; float clipDist : SV_ClipDistance0; }; VOut vs(VIn input) { SceneView scene = GetSceneView(); float4 positionOS = float4(input.position, 1); float4 positionWS = mul(modelMatrix, positionOS); float4 positionVS = mul(modelViewMatrix, float4(input.position, 1)); float4 prevPositionWS = mul(prevModelMatrix, positionOS); float3x3 normalMatrix = float3x3( normalMatrix0, normalMatrix3, normalMatrix6, normalMatrix1, normalMatrix4, normalMatrix7, normalMatrix2, normalMatrix5, normalMatrix8); float4 currPosition = mul(scene.projectionMatrix, positionVS); float4 prevPosition = mul(scene.prevViewProjMatrix, prevPositionWS); float4 prevPositionMB; if(motionBlurMode == 1) { // camera only, ignore previous model matrix prevPositionMB = mul(scene.prevViewProjMatrix, positionWS); } else if(motionBlurMode == 2) { // object only, ignore previous view & projection matrices prevPositionMB = mul(scene.projectionMatrix, mul(scene.viewMatrix, prevPositionWS)); } else { // both combined prevPositionMB = prevPosition; } VOut output; output.position = currPosition; output.currPosition = currPosition; output.prevPosition = prevPosition; output.prevPositionMB = prevPositionMB; output.normalWS = mul(normalMatrix, input.normal); output.positionWS = positionWS.xyz; output.texCoords = input.texCoords; output.color = input.color; output.clipDist = dot(positionVS, scene.clipPlane); return output; } struct POut { float2 normal : SV_Target0; float2 motionVector : SV_Target1; float2 motionVectorMB : SV_Target2; float4 shadingPosition : SV_Target3; }; #if BARYCENTRICS POut ps(VOut input, float3 barycentrics : SV_Barycentrics) #else POut ps(VOut input) #endif { if(alphaTest != ATEST_NONE) { Texture2D texture0 = ResourceDescriptorHeap[textureIndex]; SamplerState sampler0 = ResourceDescriptorHeap[samplerIndex]; float4 dst = texture0.Sample(sampler0, input.texCoords) * input.color; if(FailsAlphaTest(dst.a, alphaTest)) { discard; } } #if BARYCENTRICS float3 p0 = GetAttributeAtVertex(input.positionWS, 0); float3 p1 = GetAttributeAtVertex(input.positionWS, 1); float3 p2 = GetAttributeAtVertex(input.positionWS, 2); float3 position = barycentrics.x * p0 + barycentrics.y * p1 + barycentrics.z * p2; float3 n0 = GetAttributeAtVertex(input.normalWS, 0); float3 n1 = GetAttributeAtVertex(input.normalWS, 1); float3 n2 = GetAttributeAtVertex(input.normalWS, 2); float3 normal = barycentrics.x * n0 + barycentrics.y * n1 + barycentrics.z * n2; float3 pos[3] = { p0, p1, p2 }; float3 nor[3] = { n0, n1, n2 }; float3 shadingPosition = GetShadingPosition(position, normal, pos, nor, barycentrics); shadingPosition += 0.01 * normal; float3 dist3 = saturate(abs(shadingPosition - position)); float dist = saturate(distance(shadingPosition, position)); float positionDelta = asfloat(PackColor(float4(dist3, dist))); #else float3 normal = input.normalWS; float3 shadingPosition = input.positionWS + 0.01 * normal; float positionDelta = asfloat(0); #endif float2 currPosTC = NDCToTC(input.currPosition.xy / input.currPosition.w); float2 prevPosTC = NDCToTC(input.prevPosition.xy / input.prevPosition.w); float2 prevPosMBTC = NDCToTC(input.prevPositionMB.xy / input.prevPositionMB.w); POut output; output.normal = OctEncode(normalize(normal)); output.motionVector = currPosTC - prevPosTC; output.motionVectorMB = (currPosTC - prevPosMBTC) * motionBlurScale; output.shadingPosition = float4(shadingPosition, positionDelta); return output; }