mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-22 03:51:22 +00:00
added motion blur and freeze frame commands
- fixed crash due to missing blue noise texture - added motion vector viz - renamed TextureFormat entries
This commit is contained in:
parent
c592ef22d6
commit
838c9a6485
39 changed files with 1707 additions and 134 deletions
|
@ -103,10 +103,21 @@ add: Cinematic Rendering Pipeline CVars
|
|||
0 - disabled
|
||||
1 - 1/4 pixel count, 9 samples total
|
||||
2 - 1/16 pixel count, 25 samples total
|
||||
motion blur:
|
||||
crp_mblur <0 to 3> (default: 0) sets the motion blur mode
|
||||
0 - disabled
|
||||
1 - camera blur only
|
||||
2 - object blur only
|
||||
3 - camera and object blur
|
||||
crp_mblur_exposure <0.0 to 1.0> (default: 0.5) is the exposure time in percentage of frame time
|
||||
miscellaneous:
|
||||
crp_drawNormals <0|1> (default: 0) draws vertex normals as colorized wireframe lines
|
||||
crp_updateRTAS <0|1> (default: 1) enables raytracing acceleration structure builds every frame
|
||||
|
||||
add: Cinematic Rendering Pipeline commands
|
||||
cin_freezeFrame freezes the rendered frame (minus ImGUI and tone map) and G-Buffer for inspection
|
||||
cin_freezeFrameMB freezes the rendered frame (minus ImGUI, tone map and motion blur)
|
||||
|
||||
fix: allocating enough memory for 4K screenshots and video captures
|
||||
|
||||
fix: the new demo player now drops zombie snapshots and snapshots from before a server time rewind
|
||||
|
|
|
@ -361,6 +361,7 @@ static qbool CL_CG_GetValue( char* value, int valueSize, const char* key )
|
|||
{ "trap_CNQ3_NK_Upload", CG_EXT_NK_UPLOAD },
|
||||
{ "trap_CNQ3_NK_Draw", CG_EXT_NK_DRAW },
|
||||
{ "trap_CNQ3_SetCharEvents", CG_EXT_SETCHAREVENTS },
|
||||
{ "trap_CNQ3_R_AddRefEntityToScene", CG_EXT_CNQ3_R_ADDREFENTITYTOSCENE },
|
||||
// commands
|
||||
{ "screenshotnc", 1 },
|
||||
{ "screenshotncJPEG", 1 },
|
||||
|
@ -525,7 +526,7 @@ static intptr_t CL_CgameSystemCalls( intptr_t *args )
|
|||
re.ClearScene();
|
||||
return 0;
|
||||
case CG_R_ADDREFENTITYTOSCENE:
|
||||
re.AddRefEntityToScene( VMA(1), qfalse );
|
||||
re.AddRefEntityToScene( VMA(1), REV_ORIGINAL );
|
||||
return 0;
|
||||
case CG_R_ADDPOLYTOSCENE:
|
||||
re.AddPolyToScene( args[1], args[2], VMA(3), 1 );
|
||||
|
@ -648,7 +649,7 @@ static intptr_t CL_CgameSystemCalls( intptr_t *args )
|
|||
return 0;
|
||||
|
||||
case CG_EXT_R_ADDREFENTITYTOSCENE2:
|
||||
re.AddRefEntityToScene( VMA(1), qtrue );
|
||||
re.AddRefEntityToScene( VMA(1), REV_INTSHADERTIME );
|
||||
return 0;
|
||||
|
||||
case CG_EXT_R_FORCEFIXEDDLIGHTS:
|
||||
|
@ -728,6 +729,10 @@ static intptr_t CL_CgameSystemCalls( intptr_t *args )
|
|||
cls.cgameCharEvents = (qbool)args[1];
|
||||
return 0;
|
||||
|
||||
case CG_EXT_CNQ3_R_ADDREFENTITYTOSCENE:
|
||||
re.AddRefEntityToScene( VMA(1), REV_MOTIONBLUR );
|
||||
return 0;
|
||||
|
||||
default:
|
||||
Com_Error( ERR_DROP, "Bad cgame system trap: %i", args[0] );
|
||||
}
|
||||
|
|
|
@ -885,7 +885,7 @@ static intptr_t CL_UISystemCalls( intptr_t* args )
|
|||
return 0;
|
||||
|
||||
case UI_R_ADDREFENTITYTOSCENE:
|
||||
re.AddRefEntityToScene( VMA(1), qfalse );
|
||||
re.AddRefEntityToScene( VMA(1), REV_ORIGINAL );
|
||||
return 0;
|
||||
|
||||
case UI_R_ADDPOLYTOSCENE:
|
||||
|
@ -1127,7 +1127,7 @@ static intptr_t CL_UISystemCalls( intptr_t* args )
|
|||
return 0;
|
||||
|
||||
case UI_EXT_R_ADDREFENTITYTOSCENE2:
|
||||
re.AddRefEntityToScene( VMA(1), qtrue );
|
||||
re.AddRefEntityToScene( VMA(1), REV_INTSHADERTIME );
|
||||
return 0;
|
||||
|
||||
case UI_EXT_CVAR_SETRANGE:
|
||||
|
|
|
@ -206,7 +206,8 @@ typedef enum {
|
|||
CG_EXT_NK_CREATEFONTATLAS,
|
||||
CG_EXT_NK_UPLOAD,
|
||||
CG_EXT_NK_DRAW,
|
||||
CG_EXT_SETCHAREVENTS
|
||||
CG_EXT_SETCHAREVENTS,
|
||||
CG_EXT_CNQ3_R_ADDREFENTITYTOSCENE
|
||||
} cgameImport_t;
|
||||
|
||||
|
||||
|
|
|
@ -40,8 +40,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
// animation without needing to know the frame count
|
||||
|
||||
// refdef flags
|
||||
#define RDF_NOWORLDMODEL 1 // used for player configuration screen
|
||||
#define RDF_HYPERSPACE 4 // teleportation effect
|
||||
#define RDF_NOWORLDMODEL 1 // used for player configuration screen
|
||||
#define RDF_HYPERSPACE 4 // teleportation effect
|
||||
#define RDF_CNQ3_TELEPORTED 8 // the camera teleported since the last submitted scene
|
||||
|
||||
typedef struct {
|
||||
vec3_t xyz;
|
||||
|
@ -79,7 +80,7 @@ typedef struct {
|
|||
float shadowPlane; // projection shadows go here, stencils go slightly lower
|
||||
|
||||
vec3_t axis[3]; // rotation vectors
|
||||
qbool nonNormalizedAxes; // axis are not normalized, i.e. they have scale
|
||||
qbool nonNormalizedAxes; // axis are not normalized, i.e. they have scale
|
||||
float origin[3]; // also used as MODEL_BEAM's "from"
|
||||
int frame; // also used as MODEL_BEAM's diameter
|
||||
|
||||
|
@ -97,15 +98,64 @@ typedef struct {
|
|||
byte shaderRGBA[4]; // colors used by rgbgen entity shaders
|
||||
float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers
|
||||
union {
|
||||
float fShaderTime; // subtracted from refdef time to control effect start times
|
||||
int iShaderTime; // qvm float have 23bit mantissa. After 8388607ms (02:20) we lost data.
|
||||
float fShaderTime; // subtracted from refdef time to control effect start times
|
||||
int iShaderTime; // qvm float have 23bit mantissa. After 8388607ms (02:20) we lost data.
|
||||
} shaderTime;
|
||||
|
||||
// extra sprite information
|
||||
float radius;
|
||||
float rotation;
|
||||
} refEntityBase_t;
|
||||
|
||||
typedef struct {
|
||||
refEntityType_t reType;
|
||||
int renderfx;
|
||||
|
||||
qhandle_t hModel; // opaque type outside refresh
|
||||
|
||||
// most recent data
|
||||
vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN)
|
||||
float shadowPlane; // projection shadows go here, stencils go slightly lower
|
||||
|
||||
vec3_t axis[3]; // rotation vectors
|
||||
qbool nonNormalizedAxes; // axis are not normalized, i.e. they have scale
|
||||
float origin[3]; // also used as MODEL_BEAM's "from"
|
||||
int frame; // also used as MODEL_BEAM's diameter
|
||||
|
||||
// previous data for frame interpolation
|
||||
float oldorigin[3]; // also used as MODEL_BEAM's "to"
|
||||
int oldframe;
|
||||
float backlerp; // 0.0 = current, 1.0 = old
|
||||
|
||||
// texturing
|
||||
int skinNum; // inline skin index
|
||||
qhandle_t customSkin; // NULL for default skin
|
||||
qhandle_t customShader; // use one image for the entire thing
|
||||
|
||||
// misc
|
||||
byte shaderRGBA[4]; // colors used by rgbgen entity shaders
|
||||
float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers
|
||||
union {
|
||||
float fShaderTime; // subtracted from refdef time to control effect start times
|
||||
int iShaderTime; // qvm float have 23bit mantissa. After 8388607ms (02:20) we lost data.
|
||||
} shaderTime;
|
||||
|
||||
// extra sprite information
|
||||
float radius;
|
||||
float rotation;
|
||||
|
||||
// CNQ3 extensions
|
||||
int uniqueId; // for tracking refresh entities across frames, 0 is untracked
|
||||
float motionBlurScale; // 1.0f by default but can tweak for e.g. first-person weapon
|
||||
} refEntity_t;
|
||||
|
||||
typedef enum {
|
||||
REV_ORIGINAL,
|
||||
REV_INTSHADERTIME,
|
||||
REV_MOTIONBLUR,
|
||||
REV_LATEST = REV_MOTIONBLUR
|
||||
} refEntityVersion_t;
|
||||
|
||||
|
||||
#define MAX_RENDER_STRINGS 8
|
||||
#define MAX_RENDER_STRING_LENGTH 32
|
||||
|
|
|
@ -138,10 +138,10 @@ struct DOFCombineRC
|
|||
|
||||
void GatherDepthOfField::Init()
|
||||
{
|
||||
const TextureFormat::Id renderTargetFormat = TextureFormat::RGBA64_Float;
|
||||
const TextureFormat::Id renderTargetFormat = TextureFormat::R16G16B16A16_Float;
|
||||
|
||||
tileWidth = (uint32_t)(glConfig.vidWidth + 15) / 16;
|
||||
tileHeight = (uint32_t)(glConfig.vidHeight + 15) / 16;
|
||||
tileTextureWidth = (uint32_t)(glConfig.vidWidth + 15) / 16;
|
||||
tileTextureHeight = (uint32_t)(glConfig.vidHeight + 15) / 16;
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("DOF split");
|
||||
|
@ -223,8 +223,8 @@ void GatherDepthOfField::Init()
|
|||
desc.name = "DOF far field CoC";
|
||||
farCocTexture = CreateTexture(desc);
|
||||
|
||||
desc.width = tileWidth;
|
||||
desc.height = tileHeight;
|
||||
desc.width = tileTextureWidth;
|
||||
desc.height = tileTextureHeight;
|
||||
desc.name = "DOF near field CoC tile #1";
|
||||
nearCocTileTexture = CreateTexture(desc);
|
||||
desc.name = "DOF near field CoC tile #2";
|
||||
|
@ -334,7 +334,7 @@ void GatherDepthOfField::DrawNearCocTileGen()
|
|||
|
||||
CmdBindPipeline(nearCocTileGenPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((tileWidth + 7) / 8, (tileHeight + 7) / 8, 1);
|
||||
CmdDispatch((tileTextureWidth + 7) / 8, (tileTextureHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawNearCocTileMax()
|
||||
|
@ -353,7 +353,7 @@ void GatherDepthOfField::DrawNearCocTileMax()
|
|||
|
||||
CmdBindPipeline(nearCocTileMaxPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((tileWidth + 7) / 8, (tileHeight + 7) / 8, 1);
|
||||
CmdDispatch((tileTextureWidth + 7) / 8, (tileTextureHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void GatherDepthOfField::DrawBlur()
|
||||
|
|
|
@ -27,6 +27,7 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include "compshaders/crp/gbufferviz_depth.h"
|
||||
#include "compshaders/crp/gbufferviz_normal.h"
|
||||
#include "compshaders/crp/gbufferviz_position.h"
|
||||
#include "compshaders/crp/gbufferviz_motion.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
@ -50,6 +51,11 @@ struct DecodePositionRC
|
|||
uint32_t coloredDelta;
|
||||
};
|
||||
|
||||
struct MotionVectorRC
|
||||
{
|
||||
uint32_t textureIndex;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
|
@ -87,6 +93,17 @@ void GBufferViz::Init()
|
|||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
decodeShadingPositionPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("G-Buffer Motion");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_fullscreen_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_gbufferviz_motion_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
motionVectorPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void GBufferViz::DrawGUI()
|
||||
|
@ -166,14 +183,47 @@ void GBufferViz::DrawGUI()
|
|||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
else if(textureIndex == GBufferTexture::MotionVectorRaw ||
|
||||
textureIndex == GBufferTexture::MotionVectorMB)
|
||||
{
|
||||
srp.renderMode = RenderMode::None;
|
||||
|
||||
const HTexture texture =
|
||||
textureIndex == GBufferTexture::MotionVectorRaw ?
|
||||
crp.motionVectorTexture :
|
||||
crp.motionVectorMBTexture;
|
||||
|
||||
SCOPED_RENDER_PASS("Debug Motion", 1.0f, 1.0f, 1.0f);
|
||||
|
||||
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(texture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
MotionVectorRC rc = {};
|
||||
rc.textureIndex = GetTextureIndexSRV(texture);
|
||||
|
||||
CmdBindRenderTargets(1, &renderTarget, NULL);
|
||||
CmdBindPipeline(motionVectorPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
if(ImGui::Begin("G-Buffer", &windowActive, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::Checkbox("Full-res", &fullResolution);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Depth", &textureIndex, GBufferTexture::Depth);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Normal", &textureIndex, GBufferTexture::Normal);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Light", &textureIndex, GBufferTexture::Light);
|
||||
|
||||
ImGui::RadioButton("Motion Raw", &textureIndex, GBufferTexture::MotionVectorRaw);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Motion MB", &textureIndex, GBufferTexture::MotionVectorMB);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Shading Position Delta", &textureIndex, GBufferTexture::ShadingPositionDelta);
|
||||
if(textureIndex == GBufferTexture::ShadingPositionDelta)
|
||||
|
@ -182,7 +232,13 @@ void GBufferViz::DrawGUI()
|
|||
ImGui::Checkbox("Per-axis delta", &coloredPositionDelta);
|
||||
}
|
||||
|
||||
const ImVec2 resolution = ImVec2(glConfig.vidWidth / 2, glConfig.vidHeight / 2);
|
||||
ImVec2 resolution = ImVec2(glConfig.vidWidth, glConfig.vidHeight);
|
||||
if(!fullResolution)
|
||||
{
|
||||
resolution.x /= 2;
|
||||
resolution.y /= 2;
|
||||
}
|
||||
|
||||
HTexture texture;
|
||||
switch(textureIndex)
|
||||
{
|
||||
|
@ -190,6 +246,8 @@ void GBufferViz::DrawGUI()
|
|||
case GBufferTexture::Normal: texture = renderTarget; break;
|
||||
case GBufferTexture::Light: texture = crp.lightTexture; break;
|
||||
case GBufferTexture::ShadingPositionDelta: texture = renderTarget; break;
|
||||
case GBufferTexture::MotionVectorRaw: texture = renderTarget; break;
|
||||
case GBufferTexture::MotionVectorMB: texture = renderTarget; break;
|
||||
default: Q_assert(!"Invalid G-Buffer texture index"); texture = crp.lightTexture; break;
|
||||
}
|
||||
ImGui::Image((ImTextureID)GetTextureIndexSRV(texture), resolution);
|
||||
|
|
|
@ -40,6 +40,8 @@ extern cvar_t* crp_accumDof_focusDist;
|
|||
extern cvar_t* crp_accumDof_radius;
|
||||
extern cvar_t* crp_accumDof_samples;
|
||||
extern cvar_t* crp_accumDof_preview;
|
||||
extern cvar_t* crp_mblur;
|
||||
extern cvar_t* crp_mblur_exposure;
|
||||
extern cvar_t* crp_drawNormals;
|
||||
extern cvar_t* crp_updateRTAS;
|
||||
extern cvar_t* crp_debug0;
|
||||
|
@ -58,6 +60,15 @@ struct DOFMethod
|
|||
};
|
||||
};
|
||||
|
||||
struct MotionBlurModes
|
||||
{
|
||||
enum Flags
|
||||
{
|
||||
CameraBit = 1 << 0,
|
||||
ObjectBit = 1 << 1
|
||||
};
|
||||
};
|
||||
|
||||
struct Tessellator
|
||||
{
|
||||
enum Id
|
||||
|
@ -111,6 +122,10 @@ private:
|
|||
|
||||
bool batchOldDepthHack;
|
||||
bool batchDepthHack;
|
||||
int batchEntityId;
|
||||
float batchMotionScale;
|
||||
|
||||
HPipeline skyboxMotionPipeline;
|
||||
};
|
||||
|
||||
struct WorldOpaque
|
||||
|
@ -237,8 +252,30 @@ private:
|
|||
HTexture nearCocTileTexture;
|
||||
HTexture nearCocTileTexture2;
|
||||
HTexture farCocTexture;
|
||||
uint32_t tileWidth;
|
||||
uint32_t tileHeight;
|
||||
uint32_t tileTextureWidth;
|
||||
uint32_t tileTextureHeight;
|
||||
};
|
||||
|
||||
struct MotionBlur
|
||||
{
|
||||
void Init();
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
void DrawPack();
|
||||
void DrawTileGen();
|
||||
void DrawTileMax();
|
||||
void DrawBlur();
|
||||
|
||||
HPipeline packPipeline;
|
||||
HPipeline tileGenPipeline;
|
||||
HPipeline tileMaxPipeline;
|
||||
HPipeline blurPipeline;
|
||||
HTexture tileTexture;
|
||||
HTexture tileTexture2;
|
||||
HTexture packedTexture;
|
||||
uint32_t tileTextureWidth;
|
||||
uint32_t tileTextureHeight;
|
||||
};
|
||||
|
||||
struct Magnifier
|
||||
|
@ -266,6 +303,8 @@ private:
|
|||
Normal,
|
||||
Light,
|
||||
ShadingPositionDelta,
|
||||
MotionVectorRaw,
|
||||
MotionVectorMB,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
@ -273,9 +312,11 @@ private:
|
|||
HPipeline linearizeDepthPipeline;
|
||||
HPipeline decodeNormalsPipeline;
|
||||
HPipeline decodeShadingPositionPipeline;
|
||||
HPipeline motionVectorPipeline;
|
||||
bool windowActive = false;
|
||||
int textureIndex = 0;
|
||||
bool coloredPositionDelta = false;
|
||||
bool fullResolution = false;
|
||||
};
|
||||
|
||||
struct DynamicLights
|
||||
|
@ -405,6 +446,18 @@ struct GeoBuffers
|
|||
uint32_t vertexBufferStrides[BaseBufferId::Count + StageBufferId::Count];
|
||||
};
|
||||
|
||||
struct FreezeFrame
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
Inactive,
|
||||
Pending,
|
||||
Active,
|
||||
PendingBeforeMB,
|
||||
ActiveBeforeMB
|
||||
};
|
||||
};
|
||||
|
||||
struct CRP : IRenderPipeline
|
||||
{
|
||||
void Init() override;
|
||||
|
@ -445,7 +498,8 @@ struct CRP : IRenderPipeline
|
|||
HTexture readbackRenderTarget;
|
||||
HTexture depthTexture;
|
||||
HTexture normalTexture;
|
||||
HTexture motionVectorTexture;
|
||||
HTexture motionVectorTexture; // raw, for TAA/denoisers/etc
|
||||
HTexture motionVectorMBTexture; // mangled, for motion blur only
|
||||
HTexture noisyLightTexture;
|
||||
HTexture lightTexture;
|
||||
HTexture shadingPositionTexture;
|
||||
|
@ -456,6 +510,8 @@ struct CRP : IRenderPipeline
|
|||
HSampler samplers[BASE_SAMPLER_COUNT]; // all base samplers
|
||||
uint32_t samplerIndices[BASE_SAMPLER_COUNT]; // descriptor heap indices
|
||||
HTexture blueNoise2D;
|
||||
FreezeFrame::Id freezeFrame;
|
||||
HTexture frozenTexture;
|
||||
|
||||
// blit
|
||||
HPipeline blitPipelineLDR;
|
||||
|
@ -486,6 +542,7 @@ struct CRP : IRenderPipeline
|
|||
ToneMap toneMap;
|
||||
GatherDepthOfField gatherDof;
|
||||
AccumDepthOfField accumDof;
|
||||
MotionBlur motionBlur;
|
||||
Fog fog;
|
||||
Magnifier magnifier;
|
||||
DynamicLights dynamicLights;
|
||||
|
|
|
@ -64,6 +64,8 @@ cvar_t* crp_accumDof_focusDist;
|
|||
cvar_t* crp_accumDof_radius;
|
||||
cvar_t* crp_accumDof_samples;
|
||||
cvar_t* crp_accumDof_preview;
|
||||
cvar_t* crp_mblur;
|
||||
cvar_t* crp_mblur_exposure;
|
||||
cvar_t* crp_drawNormals;
|
||||
cvar_t* crp_updateRTAS;
|
||||
cvar_t* crp_debug0;
|
||||
|
@ -150,6 +152,25 @@ static const cvarTableItem_t crp_cvars[] =
|
|||
&crp_gatherDof_brightness, "crp_gatherDof_brightness", "2", CVAR_ARCHIVE, CVART_FLOAT, "0", "8", "blur brightness weight",
|
||||
"Gather DoF bokeh brightness", CVARCAT_GRAPHICS, "Blur brightness weight", ""
|
||||
},
|
||||
{
|
||||
&crp_mblur, "crp_mblur", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "3",
|
||||
"motion blur mode\n"
|
||||
S_COLOR_VAL " 0 " S_COLOR_HELP "= Disabled\n"
|
||||
S_COLOR_VAL " 1 " S_COLOR_HELP "= Camera only\n"
|
||||
S_COLOR_VAL " 2 " S_COLOR_HELP "= Object only\n"
|
||||
S_COLOR_VAL " 3 " S_COLOR_HELP "= Camera + Object",
|
||||
"Motion blur mode", CVARCAT_GRAPHICS, "", "",
|
||||
CVAR_GUI_VALUE("0", "Disabled", "")
|
||||
CVAR_GUI_VALUE("1", "Camera only", "")
|
||||
CVAR_GUI_VALUE("2", "Object only", "")
|
||||
CVAR_GUI_VALUE("3", "Camera + Object", "")
|
||||
},
|
||||
{
|
||||
&crp_mblur_exposure, "crp_mblur_exposure", "0.5", CVAR_ARCHIVE, CVART_FLOAT, "0", "1",
|
||||
"motion blur scale\n"
|
||||
"This is the exposure time in percentage of frame time.",
|
||||
"Motion blur exposure", CVARCAT_GRAPHICS, "Exposure time in percentage of frame time", ""
|
||||
},
|
||||
{
|
||||
&crp_drawNormals, "crp_drawNormals", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "draws vertex normals",
|
||||
"Draw vertex normals", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", ""
|
||||
|
@ -179,6 +200,52 @@ static const cvarTableItem_t crp_cvars[] =
|
|||
#endif
|
||||
};
|
||||
|
||||
static void FreezeFrame_f();
|
||||
static void FreezeFrameMB_f();
|
||||
|
||||
static const cmdTableItem_t crp_cmds[] =
|
||||
{
|
||||
{ "cin_freezeFrame", FreezeFrame_f, NULL, "toggles freeze frame mode" },
|
||||
{ "cin_freezeFrameMB", FreezeFrameMB_f, NULL, "toggles freeze frame mode for MB" }
|
||||
};
|
||||
|
||||
static void FreezeFrame_f()
|
||||
{
|
||||
if(crp.freezeFrame == FreezeFrame::Active ||
|
||||
crp.freezeFrame == FreezeFrame::ActiveBeforeMB)
|
||||
{
|
||||
crp.freezeFrame = FreezeFrame::Inactive;
|
||||
}
|
||||
else
|
||||
{
|
||||
crp.freezeFrame = FreezeFrame::Pending;
|
||||
}
|
||||
}
|
||||
|
||||
static void FreezeFrameMB_f()
|
||||
{
|
||||
if(crp.freezeFrame == FreezeFrame::Active ||
|
||||
crp.freezeFrame == FreezeFrame::ActiveBeforeMB)
|
||||
{
|
||||
crp.freezeFrame = FreezeFrame::Inactive;
|
||||
}
|
||||
else
|
||||
{
|
||||
crp.freezeFrame = FreezeFrame::PendingBeforeMB;
|
||||
}
|
||||
}
|
||||
|
||||
static HTexture LoadTexture(const char* name, int flags, textureWrap_t glWrapClampMode, const image_t* onFail = tr.defaultImage)
|
||||
{
|
||||
image_t* const image = R_FindImageFile(name, flags, glWrapClampMode);
|
||||
if(image == NULL)
|
||||
{
|
||||
return onFail->texture;
|
||||
}
|
||||
|
||||
return image->texture;
|
||||
}
|
||||
|
||||
|
||||
void PSOCache::Init(Entry* entries_, uint32_t maxEntryCount_)
|
||||
{
|
||||
|
@ -215,12 +282,8 @@ int PSOCache::AddPipeline(const GraphicsPipelineDesc& desc, const char* name)
|
|||
|
||||
void CRP::Init()
|
||||
{
|
||||
static bool veryFirstInit = true;
|
||||
if(veryFirstInit)
|
||||
{
|
||||
ri.Cvar_RegisterTable(crp_cvars, ARRAY_LEN(crp_cvars));
|
||||
veryFirstInit = false;
|
||||
}
|
||||
ri.Cvar_RegisterTable(crp_cvars, ARRAY_LEN(crp_cvars));
|
||||
ri.Cmd_RegisterTable(crp_cmds, ARRAY_LEN(crp_cmds));
|
||||
|
||||
InitDesc initDesc;
|
||||
initDesc.directDescriptorHeapIndexing = true;
|
||||
|
@ -262,13 +325,12 @@ void CRP::Init()
|
|||
}
|
||||
|
||||
{
|
||||
renderTargetFormat = TextureFormat::RGBA64_Float;
|
||||
renderTargetFormat = TextureFormat::R16G16B16A16_Float;
|
||||
|
||||
TextureDesc desc("render target #1", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit;
|
||||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.SetClearColor(vec4_zero);
|
||||
desc.committedResource = true;
|
||||
desc.format = renderTargetFormat;
|
||||
desc.shortLifeTime = true;
|
||||
|
@ -279,6 +341,17 @@ void CRP::Init()
|
|||
renderTarget = renderTargets[0];
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("frozen frame", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.format = renderTargetFormat;
|
||||
desc.shortLifeTime = true;
|
||||
frozenTexture = RHI::CreateTexture(desc);
|
||||
|
||||
freezeFrame = FreezeFrame::Inactive;
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("readback render target", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
|
@ -286,7 +359,7 @@ void CRP::Init()
|
|||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RGBA32_UNorm;
|
||||
desc.format = TextureFormat::R8G8B8A8_UNorm;
|
||||
desc.shortLifeTime = true;
|
||||
readbackRenderTarget = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
@ -360,29 +433,40 @@ void CRP::Init()
|
|||
desc.shortLifeTime = true;
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.format = TextureFormat::RG32_SNorm;
|
||||
desc.format = TextureFormat::R16G16_SNorm;
|
||||
desc.SetClearColor(vec4_zero);
|
||||
normalTexture = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("GBuffer motion vectors", glConfig.vidWidth, glConfig.vidHeight);
|
||||
TextureDesc desc("GBuffer raw motion vectors", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.committedResource = true;
|
||||
desc.shortLifeTime = true;
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.format = TextureFormat::RG32_Float;
|
||||
desc.format = TextureFormat::R16G16_Float;
|
||||
desc.SetClearColor(vec4_zero);
|
||||
motionVectorTexture = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("GBuffer MB motion vectors", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.committedResource = true;
|
||||
desc.shortLifeTime = true;
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.format = TextureFormat::R16G16_Float;
|
||||
desc.SetClearColor(vec4_zero);
|
||||
motionVectorMBTexture = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("GBuffer direct light", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.committedResource = true;
|
||||
desc.shortLifeTime = true;
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.format = TextureFormat::RGBA64_Float;
|
||||
desc.format = TextureFormat::R16G16B16A16_Float;
|
||||
desc.SetClearColor(colorBlack);
|
||||
lightTexture = RHI::CreateTexture(desc);
|
||||
desc.name = "GBuffer raw direct light";
|
||||
|
@ -395,7 +479,7 @@ void CRP::Init()
|
|||
desc.shortLifeTime = true;
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
desc.format = TextureFormat::RGBA128_Float;
|
||||
desc.format = TextureFormat::R32G32B32A32_Float;
|
||||
desc.SetClearColor(vec4_zero);
|
||||
shadingPositionTexture = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
@ -407,10 +491,10 @@ void CRP::Init()
|
|||
desc.pixelShader = ShaderByteCode(g_blit_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::RGBA32_UNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::R8G8B8A8_UNorm);
|
||||
blitPipelineLDR = CreateGraphicsPipeline(desc);
|
||||
desc.name = "blit HDR";
|
||||
desc.renderTargets[0].format = TextureFormat::RGBA64_Float;
|
||||
desc.renderTargets[0].format = TextureFormat::R16G16B16A16_Float;
|
||||
blitPipelineHDR = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
|
@ -443,6 +527,7 @@ void CRP::Init()
|
|||
toneMap.Init();
|
||||
gatherDof.Init();
|
||||
accumDof.Init();
|
||||
motionBlur.Init();
|
||||
fog.Init();
|
||||
magnifier.Init();
|
||||
dynamicLights.Init();
|
||||
|
@ -455,7 +540,7 @@ void CRP::Init()
|
|||
void CRP::LoadResources()
|
||||
{
|
||||
const int flags = IMG_NOPICMIP | IMG_NOMIPMAP | IMG_NOIMANIP | IMG_NOAF;
|
||||
blueNoise2D = R_FindImageFile("textures/stbn_2d.tga", flags, TW_REPEAT)->texture;
|
||||
blueNoise2D = LoadTexture("textures/stbn_2d.tga", flags, TW_REPEAT);
|
||||
}
|
||||
|
||||
void CRP::ShutDown(bool fullShutDown)
|
||||
|
@ -495,6 +580,22 @@ void CRP::BeginFrame()
|
|||
|
||||
void CRP::EndFrame()
|
||||
{
|
||||
if(freezeFrame == FreezeFrame::Pending)
|
||||
{
|
||||
crp.SwapRenderTargets();
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(frozenTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
Blit(frozenTexture, GetReadRenderTarget(), "Blit Frozen Frame", true, vec2_one, vec2_zero);
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(frozenTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdEndBarrier();
|
||||
srp.EndFrame();
|
||||
freezeFrame = FreezeFrame::Active;
|
||||
return;
|
||||
}
|
||||
|
||||
srp.DrawGUI();
|
||||
gbufferViz.DrawGUI();
|
||||
magnifier.DrawGUI();
|
||||
|
@ -605,7 +706,21 @@ void CRP::ProcessShader(shader_t& shader)
|
|||
|
||||
void CRP::ExecuteRenderCommands(const byte* data, bool /*readbackRequested*/)
|
||||
{
|
||||
// @NOTE: the CRP always blits the final result to the readback texture
|
||||
// @NOTE: readbackRequested is unused because
|
||||
// the CRP always blits the final result to the readback texture
|
||||
|
||||
if(freezeFrame == FreezeFrame::Active ||
|
||||
freezeFrame == FreezeFrame::ActiveBeforeMB)
|
||||
{
|
||||
BeginFrame();
|
||||
Blit(GetWriteRenderTarget(), frozenTexture, "Blit Frozen Frame", true, vec2_one, vec2_zero);
|
||||
if(freezeFrame == FreezeFrame::ActiveBeforeMB)
|
||||
{
|
||||
motionBlur.Draw();
|
||||
}
|
||||
EndFrame();
|
||||
return;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
@ -768,6 +883,21 @@ void CRP::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
transpResolve.Draw(cmd);
|
||||
CmdSetViewportAndScissor(vp.viewportX, vp.viewportY, vp.viewportWidth, vp.viewportHeight);
|
||||
gatherDof.Draw();
|
||||
if(freezeFrame == FreezeFrame::PendingBeforeMB &&
|
||||
IsViewportFullscreen(backEnd.viewParms))
|
||||
{
|
||||
crp.SwapRenderTargets();
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(frozenTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
Blit(frozenTexture, GetReadRenderTarget(), "Blit Frozen Frame", true, vec2_one, vec2_zero);
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(frozenTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdEndBarrier();
|
||||
freezeFrame = FreezeFrame::ActiveBeforeMB;
|
||||
}
|
||||
motionBlur.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -796,6 +926,11 @@ void CRP::UploadSceneViewData()
|
|||
R_InvMatrix(dest.projectionMatrix, dest.invProjectionMatrix);
|
||||
memcpy(dest.viewMatrix, vp.world.modelMatrix, sizeof(dest.viewMatrix));
|
||||
R_InvMatrix(dest.viewMatrix, dest.invViewMatrix);
|
||||
|
||||
memcpy(dest.prevViewProjMatrix, tr.prevViewProjMatrix, sizeof(dest.prevViewProjMatrix));
|
||||
memcpy(dest.prevViewMatrix, tr.prevViewMatrix, sizeof(dest.prevViewMatrix));
|
||||
memcpy(dest.prevProjectionMatrix, tr.prevProjMatrix, sizeof(dest.prevProjectionMatrix));
|
||||
|
||||
RB_CreateClipPlane(dest.clipPlane);
|
||||
#if defined(_DEBUG)
|
||||
dest.debug[0] = crp_debug0->value;
|
||||
|
@ -814,10 +949,15 @@ void CRP::UploadSceneViewData()
|
|||
dest.depthTextureIndex = GetTextureIndexSRV(depthTexture);
|
||||
dest.normalTextureIndex = GetTextureIndexSRV(normalTexture);
|
||||
dest.shadingPositionTextureIndex = GetTextureIndexSRV(shadingPositionTexture);
|
||||
dest.motionVectorTextureIndex = GetTextureIndexSRV(motionVectorTexture);
|
||||
dest.motionVectorMBTextureIndex = GetTextureIndexSRV(motionVectorMBTexture);
|
||||
dest.lightTextureIndex = GetTextureIndexSRV(lightTexture);
|
||||
dest.tlasBufferIndex = IsNullHandle(tlasBuffer) ? 0 : GetBufferIndexSRV(tlasBuffer);
|
||||
dest.tlasInstanceBufferIndex = IsNullHandle(tlasInstanceBuffer) ? 0 : GetBufferIndexSRV(tlasInstanceBuffer);
|
||||
dest.lightCount = refdef.num_dlights;
|
||||
RB_LinearDepthConstants(&dest.linearDepthA, &dest.linearDepthB);
|
||||
dest.zNear = vp.zNear;
|
||||
dest.zFar = vp.zFar;
|
||||
|
||||
for(int i = 0; i < refdef.num_dlights; i++)
|
||||
{
|
||||
|
|
227
code/renderer/crp_motion_blur.cpp
Normal file
227
code/renderer/crp_motion_blur.cpp
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// Cinematic Rendering Pipeline - scatter-as-gather motion blur
|
||||
|
||||
|
||||
#include "crp_local.h"
|
||||
#include "compshaders/crp/fullscreen.h"
|
||||
#include "compshaders/crp/mblur_pack.h"
|
||||
#include "compshaders/crp/mblur_tile_gen.h"
|
||||
#include "compshaders/crp/mblur_tile_max.h"
|
||||
#include "compshaders/crp/mblur_blur.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct MBPackRC
|
||||
{
|
||||
float motionScale;
|
||||
float maxRadiusPx;
|
||||
};
|
||||
|
||||
struct MBTileGenRC
|
||||
{
|
||||
uint32_t inputTextureIndex;
|
||||
uint32_t outputTextureIndex;
|
||||
};
|
||||
|
||||
struct MBTileMaxRC
|
||||
{
|
||||
uint32_t inputTextureIndex;
|
||||
uint32_t outputTextureIndex;
|
||||
uint32_t samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
struct MBBlurRC
|
||||
{
|
||||
uint32_t colorTextureIndex;
|
||||
uint32_t tileTextureIndex;
|
||||
uint32_t packedTextureIndex;
|
||||
uint32_t blueNoiseTextureIndex;
|
||||
uint32_t pointSamplerIndex; // clamp
|
||||
uint32_t linearSamplerIndex; // clamp
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
void MotionBlur::Init()
|
||||
{
|
||||
tileTextureWidth = (uint32_t)(glConfig.vidWidth + 15) / 16;
|
||||
tileTextureHeight = (uint32_t)(glConfig.vidHeight + 15) / 16;
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("MBlur velocity/depth packing");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_fullscreen_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_pack_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::R32G32_UInt);
|
||||
packPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("MBlur tile generation");
|
||||
desc.shortLifeTime = true;
|
||||
desc.shader = ShaderByteCode(g_tile_gen_cs);
|
||||
tileGenPipeline = CreateComputePipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
ComputePipelineDesc desc("MBlur tile dilation");
|
||||
desc.shortLifeTime = true;
|
||||
desc.shader = ShaderByteCode(g_tile_max_cs);
|
||||
tileMaxPipeline = CreateComputePipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("MBlur reconstruction filter");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(g_fullscreen_vs);
|
||||
desc.pixelShader = ShaderByteCode(g_blur_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, crp.renderTargetFormat);
|
||||
blurPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("MBlur velocity tile #1", tileTextureWidth, tileTextureHeight);
|
||||
desc.shortLifeTime = true;
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::UnorderedAccessBit;
|
||||
desc.allowedState = ResourceStates::UnorderedAccessBit | ResourceStates::ComputeShaderAccessBit | ResourceStates::PixelShaderAccessBit;
|
||||
desc.format = TextureFormat::R16G16_Float;
|
||||
tileTexture = CreateTexture(desc);
|
||||
desc.name = "MBlur velocity tile #2";
|
||||
tileTexture2 = CreateTexture(desc);
|
||||
}
|
||||
|
||||
{
|
||||
TextureDesc desc("MBlur packed velocity/depth", glConfig.vidWidth, glConfig.vidHeight);
|
||||
desc.shortLifeTime = true;
|
||||
desc.committedResource = true;
|
||||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::ComputeShaderAccessBit | ResourceStates::PixelShaderAccessBit;
|
||||
desc.format = TextureFormat::R32G32_UInt;
|
||||
packedTexture = CreateTexture(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void MotionBlur::Draw()
|
||||
{
|
||||
if(crp_mblur->integer == 0 ||
|
||||
(backEnd.refdef.rdflags & RDF_CNQ3_TELEPORTED) != 0 ||
|
||||
!IsViewportFullscreen(backEnd.viewParms))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrawPack();
|
||||
DrawTileGen();
|
||||
DrawTileMax();
|
||||
DrawBlur();
|
||||
}
|
||||
|
||||
void MotionBlur::DrawPack()
|
||||
{
|
||||
SCOPED_RENDER_PASS("MBlur Pack", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.motionVectorMBTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.depthTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(packedTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
MBPackRC rc = {};
|
||||
rc.motionScale = crp_mblur_exposure->value;
|
||||
rc.maxRadiusPx = min(glConfig.vidHeight / 25.0f, 30.0f);
|
||||
|
||||
CmdBindRenderTargets(1, &packedTexture, NULL);
|
||||
CmdBindPipeline(packPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
|
||||
void MotionBlur::DrawTileGen()
|
||||
{
|
||||
SCOPED_RENDER_PASS("MBlur Tile Gen", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(packedTexture, ResourceStates::ComputeShaderAccessBit);
|
||||
CmdTextureBarrier(tileTexture, ResourceStates::UnorderedAccessBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
MBTileGenRC rc = {};
|
||||
rc.inputTextureIndex = GetTextureIndexSRV(packedTexture);
|
||||
rc.outputTextureIndex = GetTextureIndexUAV(tileTexture, 0);
|
||||
|
||||
CmdBindPipeline(tileGenPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((tileTextureWidth + 7) / 8, (tileTextureHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void MotionBlur::DrawTileMax()
|
||||
{
|
||||
SCOPED_RENDER_PASS("MBlur Tile Max", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(tileTexture, ResourceStates::ComputeShaderAccessBit);
|
||||
CmdTextureBarrier(tileTexture2, ResourceStates::UnorderedAccessBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
MBTileMaxRC rc = {};
|
||||
rc.inputTextureIndex = GetTextureIndexSRV(tileTexture);
|
||||
rc.outputTextureIndex = GetTextureIndexUAV(tileTexture2, 0);
|
||||
rc.samplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Point);
|
||||
|
||||
CmdBindPipeline(tileMaxPipeline);
|
||||
CmdSetComputeRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDispatch((tileTextureWidth + 7) / 8, (tileTextureHeight + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void MotionBlur::DrawBlur()
|
||||
{
|
||||
SCOPED_RENDER_PASS("MBlur Blur", 0.125f, 0.125f, 0.25f);
|
||||
|
||||
crp.SwapRenderTargets();
|
||||
|
||||
CmdBeginBarrier();
|
||||
CmdTextureBarrier(crp.GetReadRenderTarget(), ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(tileTexture2, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(packedTexture, ResourceStates::PixelShaderAccessBit);
|
||||
CmdTextureBarrier(crp.renderTarget, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
MBBlurRC rc = {};
|
||||
rc.colorTextureIndex = GetTextureIndexSRV(crp.GetReadRenderTarget());
|
||||
rc.tileTextureIndex = GetTextureIndexSRV(tileTexture2);
|
||||
rc.packedTextureIndex = GetTextureIndexSRV(packedTexture);
|
||||
rc.blueNoiseTextureIndex = GetTextureIndexSRV(crp.blueNoise2D);
|
||||
rc.pointSamplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Point);
|
||||
rc.linearSamplerIndex = GetSamplerIndex(TW_CLAMP_TO_EDGE, TextureFilter::Linear);
|
||||
|
||||
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
||||
CmdBindPipeline(blurPipeline);
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
CmdDraw(3, 0);
|
||||
}
|
|
@ -23,6 +23,8 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
#include "crp_local.h"
|
||||
#include "compshaders/crp/prepass.h"
|
||||
#include "compshaders/crp/fullscreen.h"
|
||||
#include "compshaders/crp/skybox_motion.h"
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
@ -30,17 +32,128 @@ struct PrepassRC
|
|||
{
|
||||
float modelViewMatrix[16];
|
||||
float modelMatrix[16];
|
||||
float normalMatrix[16];
|
||||
float prevModelMatrix[16];
|
||||
float normalMatrix[9];
|
||||
float motionBlurScale;
|
||||
uint32_t textureIndex;
|
||||
uint32_t samplerIndex;
|
||||
uint32_t alphaTest;
|
||||
uint32_t motionBlurMode;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
struct EntityData
|
||||
{
|
||||
float modelMatrix[16];
|
||||
int uniqueId;
|
||||
};
|
||||
|
||||
struct EntityTracker
|
||||
{
|
||||
void BeginFrame()
|
||||
{
|
||||
Q_assert(!begun);
|
||||
Q_assert(!enabled);
|
||||
|
||||
const viewParms_t& vp = backEnd.viewParms;
|
||||
enabled = IsViewportFullscreen(vp) && !vp.isPortal;
|
||||
begun = true;
|
||||
}
|
||||
|
||||
void EndFrame()
|
||||
{
|
||||
Q_assert(begun);
|
||||
|
||||
begun = false;
|
||||
if(enabled)
|
||||
{
|
||||
enabled = false;
|
||||
EntityArray* prevEntsCopy = prevEnts;
|
||||
prevEnts = currEnts;
|
||||
currEnts = prevEntsCopy;
|
||||
currEnts->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CompareEntity(float* prevModelMatrix, int uniqueId, const float* modelMatrix)
|
||||
{
|
||||
Q_assert(begun);
|
||||
|
||||
if(!enabled || uniqueId == 0)
|
||||
{
|
||||
memcpy(prevModelMatrix, modelMatrix, 16 * sizeof(float));
|
||||
return;
|
||||
}
|
||||
|
||||
EntityData* prevEnt = NULL;
|
||||
for(uint32_t i = 0, end = prevEnts->count; i < end; i++)
|
||||
{
|
||||
EntityData& ent = (*prevEnts)[i];
|
||||
if(ent.uniqueId == uniqueId)
|
||||
{
|
||||
prevEnt = &ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(prevEnt != NULL)
|
||||
{
|
||||
memcpy(prevModelMatrix, prevEnt->modelMatrix, 16 * sizeof(float));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(prevModelMatrix, modelMatrix, 16 * sizeof(float));
|
||||
}
|
||||
|
||||
EntityData* currEnt = NULL;
|
||||
for(uint32_t i = 0, end = currEnts->count; i < end; i++)
|
||||
{
|
||||
EntityData& ent = (*currEnts)[i];
|
||||
if(ent.uniqueId == uniqueId)
|
||||
{
|
||||
currEnt = &ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(currEnt != NULL)
|
||||
{
|
||||
memcpy(currEnt->modelMatrix, modelMatrix, 16 * sizeof(float));
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityData ent;
|
||||
memcpy(ent.modelMatrix, modelMatrix, 16 * sizeof(float));
|
||||
ent.uniqueId = uniqueId;
|
||||
currEnts->Add(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef RHI::StaticUnorderedArray<EntityData, 16384> EntityArray;
|
||||
EntityArray entities[2];
|
||||
EntityArray* currEnts = &entities[0];
|
||||
EntityArray* prevEnts = &entities[1];
|
||||
bool enabled;
|
||||
bool begun;
|
||||
};
|
||||
|
||||
static EntityTracker et;
|
||||
|
||||
|
||||
void Prepass::Init()
|
||||
{
|
||||
psoCache.Init(psoCacheEntries, ARRAY_LEN(psoCacheEntries));
|
||||
|
||||
{
|
||||
GraphicsPipelineDesc desc("Skybox Motion Vectors");
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader.Set(g_fullscreen_vs);
|
||||
desc.pixelShader.Set(g_skybox_motion_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::R16G16_Float);
|
||||
skyboxMotionPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void Prepass::Draw(const drawSceneViewCommand_t& cmd)
|
||||
|
@ -57,6 +170,8 @@ void Prepass::Draw(const drawSceneViewCommand_t& cmd)
|
|||
backEnd.refdef = cmd.refdef;
|
||||
backEnd.viewParms = cmd.viewParms;
|
||||
|
||||
et.BeginFrame();
|
||||
|
||||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
batchOldDepthHack = false;
|
||||
batchDepthHack = false;
|
||||
|
@ -65,18 +180,44 @@ void Prepass::Draw(const drawSceneViewCommand_t& cmd)
|
|||
CmdTextureBarrier(crp.depthTexture, ResourceStates::DepthWriteBit);
|
||||
CmdTextureBarrier(crp.normalTexture, ResourceStates::RenderTargetBit);
|
||||
CmdTextureBarrier(crp.motionVectorTexture, ResourceStates::RenderTargetBit);
|
||||
CmdTextureBarrier(crp.motionVectorMBTexture, ResourceStates::RenderTargetBit);
|
||||
CmdTextureBarrier(crp.shadingPositionTexture, ResourceStates::RenderTargetBit);
|
||||
CmdEndBarrier();
|
||||
|
||||
CmdClearDepthStencilTarget(crp.depthTexture, true, 0.0f);
|
||||
CmdClearColorTarget(crp.normalTexture, vec4_zero, NULL);
|
||||
CmdClearColorTarget(crp.motionVectorTexture, vec4_zero, NULL);
|
||||
CmdClearColorTarget(crp.shadingPositionTexture, vec4_zero, NULL);
|
||||
|
||||
// clear the motion vectors with skybox values
|
||||
CmdBeginDebugLabel("Skybox Motion Vectors");
|
||||
{
|
||||
CmdBindRenderTargets(1, &crp.motionVectorTexture, NULL);
|
||||
CmdBindPipeline(skyboxMotionPipeline);
|
||||
CmdDraw(3, 0);
|
||||
|
||||
if(crp_mblur->integer & MotionBlurModes::CameraBit)
|
||||
{
|
||||
CmdBindRenderTargets(1, &crp.motionVectorMBTexture, NULL);
|
||||
CmdBindPipeline(skyboxMotionPipeline);
|
||||
CmdDraw(3, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdClearColorTarget(crp.motionVectorMBTexture, vec4_zero, NULL);
|
||||
}
|
||||
}
|
||||
CmdEndDebugLabel();
|
||||
|
||||
GeoBuffers& db = crp.dynBuffers[GetFrameIndex()];
|
||||
db.BeginUpload();
|
||||
|
||||
const HTexture renderTargets[] = { crp.normalTexture, crp.motionVectorTexture, crp.shadingPositionTexture };
|
||||
const HTexture renderTargets[] =
|
||||
{
|
||||
crp.normalTexture,
|
||||
crp.motionVectorTexture,
|
||||
crp.motionVectorMBTexture,
|
||||
crp.shadingPositionTexture
|
||||
};
|
||||
CmdBindRenderTargets(ARRAY_LEN(renderTargets), renderTargets, &crp.depthTexture);
|
||||
CmdBindVertexBuffers(ARRAY_LEN(db.vertexBuffers), db.vertexBuffers, db.vertexBufferStrides, NULL);
|
||||
CmdBindIndexBuffer(db.indexBuffer.buffer, IndexType::UInt32, 0);
|
||||
|
@ -88,6 +229,7 @@ void Prepass::Draw(const drawSceneViewCommand_t& cmd)
|
|||
const shader_t* shader = NULL;
|
||||
const shader_t* oldShader = NULL;
|
||||
int oldEntityNum = -1;
|
||||
batchEntityId = -1;
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
|
||||
tess.numVertexes = 0;
|
||||
|
@ -109,13 +251,16 @@ void Prepass::Draw(const drawSceneViewCommand_t& cmd)
|
|||
|
||||
const bool shaderChanged = shader != oldShader;
|
||||
const bool entityChanged = entityNum != oldEntityNum;
|
||||
if(shaderChanged || entityChanged)
|
||||
const bool idChanged = drawSurf->uniqueEntityId != batchEntityId;
|
||||
if(shaderChanged || entityChanged || idChanged)
|
||||
{
|
||||
oldShader = shader;
|
||||
oldEntityNum = entityNum;
|
||||
EndBatch();
|
||||
BeginBatch(shader);
|
||||
tess.greyscale = drawSurf->greyscale;
|
||||
batchEntityId = drawSurf->uniqueEntityId;
|
||||
batchMotionScale = drawSurf->motionBlurScale;
|
||||
}
|
||||
|
||||
if(entityChanged)
|
||||
|
@ -136,6 +281,8 @@ void Prepass::Draw(const drawSceneViewCommand_t& cmd)
|
|||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
batchOldDepthHack = false;
|
||||
batchDepthHack = false;
|
||||
|
||||
et.EndFrame();
|
||||
}
|
||||
|
||||
void Prepass::ProcessShader(shader_t& shader)
|
||||
|
@ -181,9 +328,10 @@ void Prepass::ProcessShader(shader_t& shader)
|
|||
desc.rasterizer.cullMode = shader.cullType;
|
||||
desc.rasterizer.polygonOffset = shader.polygonOffset != 0;
|
||||
desc.rasterizer.clampDepth = clampDepth;
|
||||
desc.AddRenderTarget(0, TextureFormat::RG32_SNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::RG32_Float);
|
||||
desc.AddRenderTarget(0, TextureFormat::RGBA128_Float);
|
||||
desc.AddRenderTarget(0, TextureFormat::R16G16_SNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::R16G16_Float);
|
||||
desc.AddRenderTarget(0, TextureFormat::R16G16_Float);
|
||||
desc.AddRenderTarget(0, TextureFormat::R32G32B32A32_Float);
|
||||
|
||||
pipeline_t& p = shader.prepassPipeline;
|
||||
p.firstStage = 0;
|
||||
|
@ -219,6 +367,7 @@ void Prepass::EndBatch()
|
|||
{
|
||||
PrepassRC rc = {};
|
||||
float tempMatrix[16];
|
||||
float normalMatrix[16];
|
||||
|
||||
const int vertexCount = tess.numVertexes;
|
||||
const int indexCount = tess.numIndexes;
|
||||
|
@ -265,13 +414,26 @@ void Prepass::EndBatch()
|
|||
const uint32_t alphaTest = AlphaTestShaderConstFromStateBits(stage->stateBits);
|
||||
Q_assert(sampIdx < ARRAY_LEN(crp.samplers));
|
||||
|
||||
R_InvMatrix(backEnd.modelMatrix, tempMatrix);
|
||||
R_TransposeMatrix(tempMatrix, normalMatrix);
|
||||
|
||||
memcpy(rc.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(rc.modelViewMatrix));
|
||||
memcpy(rc.modelMatrix, backEnd.modelMatrix, sizeof(rc.modelMatrix));
|
||||
R_InvMatrix(backEnd.modelMatrix, tempMatrix);
|
||||
R_TransposeMatrix(tempMatrix, rc.normalMatrix);
|
||||
et.CompareEntity(rc.prevModelMatrix, batchEntityId, backEnd.modelMatrix);
|
||||
rc.normalMatrix[0] = normalMatrix[ 0];
|
||||
rc.normalMatrix[1] = normalMatrix[ 1];
|
||||
rc.normalMatrix[2] = normalMatrix[ 2];
|
||||
rc.normalMatrix[3] = normalMatrix[ 4];
|
||||
rc.normalMatrix[4] = normalMatrix[ 5];
|
||||
rc.normalMatrix[5] = normalMatrix[ 6];
|
||||
rc.normalMatrix[6] = normalMatrix[ 8];
|
||||
rc.normalMatrix[7] = normalMatrix[ 9];
|
||||
rc.normalMatrix[8] = normalMatrix[10];
|
||||
rc.motionBlurScale = batchMotionScale;
|
||||
rc.textureIndex = texIdx;
|
||||
rc.samplerIndex = sampIdx;
|
||||
rc.alphaTest = alphaTest;
|
||||
rc.motionBlurMode = crp_mblur->integer;
|
||||
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
||||
|
||||
db.DrawStage(vertexCount, indexCount);
|
||||
|
|
|
@ -172,11 +172,11 @@ void GRP::Init()
|
|||
renderTargetFormat = TextureFormat::R10G10B10A2_UNorm;
|
||||
break;
|
||||
case RTCF_R16G16B16A16:
|
||||
renderTargetFormat = TextureFormat::RGBA64_UNorm;
|
||||
renderTargetFormat = TextureFormat::R16G16B16A16_UNorm;
|
||||
break;
|
||||
case RTCF_R8G8B8A8:
|
||||
default:
|
||||
renderTargetFormat = TextureFormat::RGBA32_UNorm;
|
||||
renderTargetFormat = TextureFormat::R8G8B8A8_UNorm;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ void GRP::Init()
|
|||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RGBA32_UNorm;
|
||||
desc.format = TextureFormat::R8G8B8A8_UNorm;
|
||||
desc.shortLifeTime = true;
|
||||
readbackRenderTarget = RHI::CreateTexture(desc);
|
||||
}
|
||||
|
|
|
@ -58,9 +58,9 @@ void PostProcess::Init()
|
|||
}
|
||||
|
||||
TextureFormat::Id rtFormats[RTCF_COUNT] = {};
|
||||
rtFormats[RTCF_R8G8B8A8] = TextureFormat::RGBA32_UNorm;
|
||||
rtFormats[RTCF_R8G8B8A8] = TextureFormat::R8G8B8A8_UNorm;
|
||||
rtFormats[RTCF_R10G10B10A2] = TextureFormat::R10G10B10A2_UNorm;
|
||||
rtFormats[RTCF_R16G16B16A16] = TextureFormat::RGBA64_UNorm;
|
||||
rtFormats[RTCF_R16G16B16A16] = TextureFormat::R16G16B16A16_UNorm;
|
||||
for(int i = 0; i < RTCF_COUNT; ++i)
|
||||
{
|
||||
Q_assert((int)rtFormats[i] > 0 && (int)rtFormats[i] < TextureFormat::Count);
|
||||
|
@ -91,7 +91,7 @@ void PostProcess::Init()
|
|||
desc.pixelShader = ShaderByteCode(g_post_ps);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::RGBA32_UNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::R8G8B8A8_UNorm);
|
||||
toneMapPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ void SMAA::Update()
|
|||
desc.initialState = ResourceStates::PixelShaderAccessBit;
|
||||
desc.allowedState = ResourceStates::PixelShaderAccessBit;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RG16_UNorm;
|
||||
desc.format = TextureFormat::R8G8_UNorm;
|
||||
areaTexture = CreateTexture(desc);
|
||||
|
||||
MappedTexture texture;
|
||||
|
@ -208,7 +208,7 @@ void SMAA::Update()
|
|||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RG16_UNorm;
|
||||
desc.format = TextureFormat::R8G8_UNorm;
|
||||
edgeTexture = CreateTexture(desc);
|
||||
}
|
||||
{
|
||||
|
@ -218,7 +218,7 @@ void SMAA::Update()
|
|||
Vector4Clear(desc.clearColor);
|
||||
desc.usePreferredClearValue = true;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RGBA32_UNorm;
|
||||
desc.format = TextureFormat::R8G8B8A8_UNorm;
|
||||
blendTexture = CreateTexture(desc);
|
||||
}
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ void SMAA::Update()
|
|||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RGBA32_UNorm;
|
||||
desc.format = TextureFormat::R8G8B8A8_UNorm;
|
||||
inputTexture = CreateTexture(desc);
|
||||
}
|
||||
{
|
||||
|
@ -234,7 +234,7 @@ void SMAA::Update()
|
|||
desc.initialState = ResourceStates::RenderTargetBit;
|
||||
desc.allowedState = ResourceStates::RenderTargetBit | ResourceStates::PixelShaderAccessBit;
|
||||
desc.committedResource = true;
|
||||
desc.format = TextureFormat::RGBA32_UNorm;
|
||||
desc.format = TextureFormat::R8G8B8A8_UNorm;
|
||||
outputTexture = CreateTexture(desc);
|
||||
|
||||
grp.post.SetInverseToneMapInput(outputTexture);
|
||||
|
@ -281,7 +281,7 @@ void SMAA::Update()
|
|||
desc.depthStencil.frontFace.passOp = StencilOp::Replace;
|
||||
desc.depthStencil.backFace.passOp = StencilOp::Replace;
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::RG16_UNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::R8G8_UNorm);
|
||||
firstPassPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
{
|
||||
|
@ -295,7 +295,7 @@ void SMAA::Update()
|
|||
desc.depthStencil.frontFace.comparison = ComparisonFunction::Equal;
|
||||
desc.depthStencil.backFace.comparison = ComparisonFunction::Equal;
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::RGBA32_UNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::R8G8B8A8_UNorm);
|
||||
secondPassPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
{
|
||||
|
@ -304,7 +304,7 @@ void SMAA::Update()
|
|||
desc.pixelShader = GetShaderByteCode(2, true);
|
||||
desc.depthStencil.DisableDepth();
|
||||
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
||||
desc.AddRenderTarget(0, TextureFormat::RGBA32_UNorm);
|
||||
desc.AddRenderTarget(0, TextureFormat::R8G8B8A8_UNorm);
|
||||
thirdPassPipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -877,16 +877,22 @@ namespace RHI
|
|||
{
|
||||
switch(format)
|
||||
{
|
||||
case TextureFormat::RGBA128_Float:
|
||||
case TextureFormat::R32G32B32A32_Float:
|
||||
return 16;
|
||||
case TextureFormat::RGBA64_Float:
|
||||
case TextureFormat::R16G16B16A16_UNorm:
|
||||
case TextureFormat::R16G16B16A16_Float:
|
||||
case TextureFormat::R32G32_Float:
|
||||
case TextureFormat::R32G32_UInt:
|
||||
return 8;
|
||||
case TextureFormat::RGBA32_UNorm:
|
||||
case TextureFormat::R8G8B8A8_UNorm:
|
||||
case TextureFormat::Depth32_Float:
|
||||
case TextureFormat::Depth24_Stencil8:
|
||||
case TextureFormat::R10G10B10A2_UNorm:
|
||||
case TextureFormat::R32_UInt:
|
||||
case TextureFormat::R16G16_SNorm:
|
||||
case TextureFormat::R16G16_Float:
|
||||
return 4;
|
||||
case TextureFormat::RG16_UNorm:
|
||||
case TextureFormat::R8G8_UNorm:
|
||||
return 2;
|
||||
case TextureFormat::R8_UNorm:
|
||||
return 1;
|
||||
|
@ -1260,7 +1266,7 @@ namespace RHI
|
|||
D3D(readbackCommandList->Reset(readbackCommandAllocator, NULL));
|
||||
|
||||
Texture& texture = rhi.textures.Get(htexture);
|
||||
Q_assert(texture.desc.format == TextureFormat::RGBA32_UNorm);
|
||||
Q_assert(texture.desc.format == TextureFormat::R8G8B8A8_UNorm);
|
||||
const D3D12_RESOURCE_DESC textureDesc = texture.texture->GetDesc();
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
|
||||
rhi.device->GetCopyableFootprints(&textureDesc, 0, 1, 0, &layout, NULL, NULL, NULL);
|
||||
|
@ -1804,18 +1810,20 @@ namespace RHI
|
|||
{
|
||||
switch(format)
|
||||
{
|
||||
case TextureFormat::RGBA32_UNorm: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case TextureFormat::RGBA64_UNorm: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case TextureFormat::RGBA64_Float: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case TextureFormat::RGBA128_Float: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case TextureFormat::R8G8B8A8_UNorm: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case TextureFormat::R16G16B16A16_UNorm: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case TextureFormat::R32G32_Float: return DXGI_FORMAT_R32G32_FLOAT;
|
||||
case TextureFormat::R16G16B16A16_Float: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case TextureFormat::R32G32B32A32_Float: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case TextureFormat::Depth32_Float: return DXGI_FORMAT_D32_FLOAT;
|
||||
case TextureFormat::Depth24_Stencil8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case TextureFormat::RG16_UNorm: return DXGI_FORMAT_R8G8_UNORM;
|
||||
case TextureFormat::R8G8_UNorm: return DXGI_FORMAT_R8G8_UNORM;
|
||||
case TextureFormat::R8_UNorm: return DXGI_FORMAT_R8_UNORM;
|
||||
case TextureFormat::R10G10B10A2_UNorm: return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case TextureFormat::R32_UInt: return DXGI_FORMAT_R32_UINT;
|
||||
case TextureFormat::RG32_SNorm: return DXGI_FORMAT_R16G16_SNORM;
|
||||
case TextureFormat::RG32_Float: return DXGI_FORMAT_R16G16_FLOAT;
|
||||
case TextureFormat::R32G32_UInt: return DXGI_FORMAT_R32G32_UINT;
|
||||
case TextureFormat::R16G16_SNorm: return DXGI_FORMAT_R16G16_SNORM;
|
||||
case TextureFormat::R16G16_Float: return DXGI_FORMAT_R16G16_FLOAT;
|
||||
default: Q_assert(!"Unsupported texture format"); return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
}
|
||||
|
@ -2258,7 +2266,7 @@ namespace RHI
|
|||
}
|
||||
{
|
||||
TextureDesc desc("null RW", 1, 1);
|
||||
desc.format = TextureFormat::RGBA32_UNorm;
|
||||
desc.format = TextureFormat::R8G8B8A8_UNorm;
|
||||
desc.initialState = ResourceStates::UnorderedAccessBit;
|
||||
desc.allowedState = ResourceStates::UnorderedAccessBit | ResourceStates::PixelShaderAccessBit;
|
||||
rhi.nullRWTexture = CreateTexture(desc);
|
||||
|
|
|
@ -162,18 +162,20 @@ namespace RHI
|
|||
enum Id
|
||||
{
|
||||
Invalid,
|
||||
RGBA32_UNorm,
|
||||
RGBA64_UNorm,
|
||||
RGBA64_Float,
|
||||
RGBA128_Float,
|
||||
R8G8B8A8_UNorm,
|
||||
R16G16B16A16_UNorm,
|
||||
R32G32_Float,
|
||||
R16G16B16A16_Float,
|
||||
R32G32B32A32_Float,
|
||||
Depth32_Float,
|
||||
RG16_UNorm,
|
||||
R8G8_UNorm,
|
||||
R8_UNorm,
|
||||
Depth24_Stencil8,
|
||||
R10G10B10A2_UNorm,
|
||||
R32_UInt,
|
||||
RG32_SNorm,
|
||||
RG32_Float,
|
||||
R32G32_UInt,
|
||||
R16G16_SNorm,
|
||||
R16G16_Float,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
@ -430,7 +432,7 @@ namespace RHI
|
|||
struct RenderTarget
|
||||
{
|
||||
uint32_t q3BlendMode = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
|
||||
TextureFormat::Id format = TextureFormat::RGBA32_UNorm;
|
||||
TextureFormat::Id format = TextureFormat::R8G8B8A8_UNorm;
|
||||
}
|
||||
renderTargets[MaxRenderTargets];
|
||||
uint32_t renderTargetCount = 0;
|
||||
|
@ -501,7 +503,7 @@ namespace RHI
|
|||
sampleCount = 1;
|
||||
initialState = ResourceStates::PixelShaderAccessBit;
|
||||
allowedState = ResourceStates::PixelShaderAccessBit;
|
||||
format = TextureFormat::RGBA32_UNorm;
|
||||
format = TextureFormat::R8G8B8A8_UNorm;
|
||||
committedResource = false;
|
||||
usePreferredClearValue = false;
|
||||
}
|
||||
|
@ -514,7 +516,7 @@ namespace RHI
|
|||
uint32_t sampleCount = 1;
|
||||
ResourceStates::Flags initialState = ResourceStates::PixelShaderAccessBit;
|
||||
ResourceStates::Flags allowedState = ResourceStates::PixelShaderAccessBit;
|
||||
TextureFormat::Id format = TextureFormat::RGBA32_UNorm;
|
||||
TextureFormat::Id format = TextureFormat::R8G8B8A8_UNorm;
|
||||
bool committedResource = false;
|
||||
bool usePreferredClearValue = false; // for render targets and depth/stencil buffers
|
||||
float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
|
|
@ -290,6 +290,21 @@ bool IsValueInRange(T p, T min, T max)
|
|||
return all(p >= min) && all(p <= max);
|
||||
}
|
||||
|
||||
bool IsValue01(float2 p)
|
||||
{
|
||||
return IsValueInRange(p, float2(0, 0), float2(1, 1));
|
||||
}
|
||||
|
||||
bool IsValue01(float3 p)
|
||||
{
|
||||
return IsValueInRange(p, float3(0, 0, 0), float3(1, 1, 1));
|
||||
}
|
||||
|
||||
bool IsValue01(float4 p)
|
||||
{
|
||||
return IsValueInRange(p, float4(0, 0, 0, 0), float4(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint2 GetTextureSize(Texture2D<T> texture0)
|
||||
{
|
||||
|
@ -299,6 +314,15 @@ uint2 GetTextureSize(Texture2D<T> texture0)
|
|||
return size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint2 GetTextureSize(RWTexture2D<T> texture0)
|
||||
{
|
||||
uint2 size;
|
||||
texture0.GetDimensions(size.x, size.y);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// by Sakib Saikia, https://sakibsaikia.github.io/graphics/2022/01/04/Nan-Checks-In-HLSL.html
|
||||
bool IsNan(float x)
|
||||
{
|
||||
|
@ -316,3 +340,59 @@ float AnimateBlueNoise(float blueNoise, uint frameIndex)
|
|||
{
|
||||
return frac(blueNoise + float(frameIndex % 32) * 0.61803399);
|
||||
}
|
||||
|
||||
float2 NDCToTC(float2 ndc)
|
||||
{
|
||||
float2 tc = ndc * float2(0.5, -0.5) + 0.5;
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
float2 TCToNDC(float2 tc)
|
||||
{
|
||||
float2 ndc = (2.0 * tc - 1.0) * float2(1, -1);
|
||||
|
||||
return ndc;
|
||||
}
|
||||
|
||||
// returns the longest vector
|
||||
float2 vmax(float2 a, float2 b)
|
||||
{
|
||||
float2 result = dot(a, a) > dot(b, b) ? a : b;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint PackHalf2(float2 input)
|
||||
{
|
||||
uint2 d = f32tof16(input);
|
||||
uint result = d.x | (d.y << 16u);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float2 UnpackHalf2(uint input)
|
||||
{
|
||||
uint2 d = uint2(input & 0xFFFFu, input >> 16u);
|
||||
float2 result = f16tof32(d);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float2 CartesianToPolar(float2 cartesian)
|
||||
{
|
||||
float radius = length(cartesian);
|
||||
float angle = atan2(cartesian.y, cartesian.x);
|
||||
float2 polar = float2(radius, angle);
|
||||
|
||||
return polar;
|
||||
}
|
||||
|
||||
float2 PolarToCartesian(float2 polar)
|
||||
{
|
||||
float sinAngle, cosAngle;
|
||||
sincos(polar.y, sinAngle, cosAngle);
|
||||
float2 cartesian = polar.x * float2(cosAngle, sinAngle);
|
||||
|
||||
return cartesian;
|
||||
}
|
||||
|
|
44
code/renderer/shaders/crp/gbufferviz_motion.hlsl
Normal file
44
code/renderer/shaders/crp/gbufferviz_motion.hlsl
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// colorizes motion vectors for debugging
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint textureIndex;
|
||||
};
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
Texture2D<float2> motionTexture = ResourceDescriptorHeap[textureIndex];
|
||||
float2 size = float2(GetTextureSize(motionTexture));
|
||||
float scale = size.y / size.x; // correct for aspect ratio
|
||||
uint3 tc = uint3(input.position.xy, 0);
|
||||
float2 raw = motionTexture.Load(tc);
|
||||
float2 display = abs(raw) * 50.0 * scale;
|
||||
float4 result = float4(display, 0, 1);
|
||||
|
||||
return result;
|
||||
}
|
336
code/renderer/shaders/crp/mblur_blur.hlsl
Normal file
336
code/renderer/shaders/crp/mblur_blur.hlsl
Normal file
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// motion blur reconstruction filter
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint colorTextureIndex;
|
||||
uint tileTextureIndex;
|
||||
uint packedTextureIndex;
|
||||
uint blueNoiseTextureIndex;
|
||||
uint pointSamplerIndex; // clamp
|
||||
uint linearSamplerIndex; // clamp
|
||||
};
|
||||
|
||||
#if 1
|
||||
|
||||
/*
|
||||
Summary:
|
||||
- sampling N times in a line along fragment's direction
|
||||
- sampling N times in a line along neighborhood's strongest direction
|
||||
- bilinearly interpolating neighborhood tiles in polar coordinates with clamped velocity
|
||||
- jittering the lines' center points with blue noise
|
||||
- binary classification of samples based on depth and distance/velocity
|
||||
- weighting samples based on direction similarity
|
||||
- background reconstruction using mirrored samples
|
||||
|
||||
References:
|
||||
- "A Reconstruction Filter for Plausible Motion Blur" by McGuire et al.
|
||||
- "Next-Generation Post-Processing in Call of Duty Advanced Warfare" by Jorge Jimenez
|
||||
*/
|
||||
|
||||
void ProcessSample(
|
||||
inout float4 fgAccum, inout float4 bgAccum, inout float alpha, inout float center,
|
||||
float Zs, float Zc, float Vsl, float Vcl, float distTC, float3 C0s, float3 C1s, float W0d)
|
||||
{
|
||||
const float DepthThreshold = 0.28; // 10mm assuming 56u == 2m
|
||||
|
||||
if(Zs - DepthThreshold < Zc && Vsl >= distTC)
|
||||
{
|
||||
fgAccum += float4(C0s, 1) * W0d;
|
||||
bgAccum += float4(C1s, 1);
|
||||
alpha += 1.0;
|
||||
}
|
||||
else if(Zs >= Zc && Vcl >= distTC)
|
||||
{
|
||||
bgAccum += float4(C0s, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
center += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
SamplerState pointSampler = SamplerDescriptorHeap[pointSamplerIndex];
|
||||
SamplerState linearSampler = SamplerDescriptorHeap[linearSamplerIndex];
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
Texture2D<float2> tileTexture = ResourceDescriptorHeap[tileTextureIndex];
|
||||
Texture2D<uint2> packedTexture = ResourceDescriptorHeap[packedTextureIndex];
|
||||
Texture2D blueNoiseTexture = ResourceDescriptorHeap[blueNoiseTextureIndex];
|
||||
float2 fullResSize = float2(GetTextureSize(colorTexture));
|
||||
float2 tileSize = float2(GetTextureSize(tileTexture));
|
||||
uint2 blueNoiseSize = GetTextureSize(blueNoiseTexture);
|
||||
|
||||
float2 tileTC = input.texCoords;
|
||||
float2 Vnraw = tileTexture.SampleLevel(pointSampler, tileTC, 0);
|
||||
float2 tileWeights = frac(tileTC * tileSize + 0.5);
|
||||
float4 Vnx = tileTexture.GatherRed(pointSampler, tileTC);
|
||||
float4 Vny = tileTexture.GatherGreen(pointSampler, tileTC);
|
||||
float2 Vnpa[4];
|
||||
float Vnw[4];
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
float2 Vni = float2(Vnx[i], Vny[i]);
|
||||
if(length(Vni * fullResSize) < 2.0)
|
||||
{
|
||||
Vni = Vnraw; // ignore tiles with small vectors
|
||||
}
|
||||
Vnpa[i] = CartesianToPolar(Vni);
|
||||
}
|
||||
Vnw[0] = (1.0 - tileWeights.x) * tileWeights.y; // (-,+)
|
||||
Vnw[1] = tileWeights.x * tileWeights.y; // (+,+)
|
||||
Vnw[2] = tileWeights.x * (1.0 - tileWeights.y); // (+,-)
|
||||
Vnw[3] = (1.0 - tileWeights.x) * (1.0 - tileWeights.y); // (-,-)
|
||||
float2 Vnp = Vnw[0] * Vnpa[0] + Vnw[1] * Vnpa[1] + Vnw[2] * Vnpa[2] + Vnw[3] * Vnpa[3];
|
||||
Vnp.x = max(Vnp.x, length(Vnraw)); // make sure the lerp won't yield a smaller vector
|
||||
float2 Vn = PolarToCartesian(Vnp);
|
||||
float2 Vnn = normalize(Vn);
|
||||
float3 color = colorTexture.SampleLevel(pointSampler, input.texCoords, 0).rgb;
|
||||
uint2 packedFrag = packedTexture.Load(uint3(input.texCoords * fullResSize, 0));
|
||||
float2 Vc = UnpackHalf2(packedFrag.x);
|
||||
float Vcl = length(Vc);
|
||||
float2 Vcn = Vc / Vcl;
|
||||
float Zc = asfloat(packedFrag.y) * scene.zFar;
|
||||
float lengthPx = length(Vn * fullResSize);
|
||||
if(lengthPx < 0.5)
|
||||
{
|
||||
return float4(color, 1);
|
||||
}
|
||||
|
||||
if(length(Vc * fullResSize) <= 4.0)
|
||||
{
|
||||
Vc = Vn;
|
||||
Vcn = Vnn;
|
||||
}
|
||||
|
||||
uint2 blueNoisePx = (input.texCoords * fullResSize) % blueNoiseSize;
|
||||
float2 blueNoise = blueNoiseTexture.Load(uint3(blueNoisePx, 0)).xy;
|
||||
float tcJitter = blueNoise.x;
|
||||
uint sampleCount = min(2 * uint(ceil(lengthPx)), 64);
|
||||
float2 tcStepN = 0.5 * Vn / float2(sampleCount - 1, sampleCount - 1);
|
||||
float2 tcStepC = 0.5 * Vc / float2(sampleCount - 1, sampleCount - 1);
|
||||
float4 fgAccum = float4(0, 0, 0, 0);
|
||||
float4 bgAccum = float4(0, 0, 0, 0);
|
||||
float alpha = 0.0; // foreground (1) / background (0) lerp
|
||||
float center = 0.0; // center (1) / background (0) lerp
|
||||
uint realSampleCount = 0;
|
||||
|
||||
if(length(Vc * fullResSize) >= 1.0)
|
||||
{
|
||||
fgAccum += float4(color, 1);
|
||||
alpha += 1.0;
|
||||
}
|
||||
bgAccum += float4(color, 1);
|
||||
|
||||
uint totalSampleCount = sampleCount * 2;
|
||||
for(uint i = 1; i < totalSampleCount; i++)
|
||||
{
|
||||
float lineStep = float(i / 2);
|
||||
float i0 = tcJitter + lineStep;
|
||||
float i1 = tcJitter - lineStep;
|
||||
float2 tcStep, dirn;
|
||||
[flatten]
|
||||
if(i % 2 == 0)
|
||||
{
|
||||
tcStep = tcStepN;
|
||||
dirn = Vnn;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcStep = tcStepC;
|
||||
dirn = Vcn;
|
||||
}
|
||||
float2 TC0 = input.texCoords + i0 * tcStep;
|
||||
float2 TC1 = input.texCoords + i1 * tcStep;
|
||||
|
||||
[branch]
|
||||
if(!IsValue01(TC0) || !IsValue01(TC1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint2 packedSample0 = packedTexture.Load(uint3(TC0 * fullResSize, 0));
|
||||
float2 V0s = UnpackHalf2(packedSample0.x);
|
||||
float V0sl = length(V0s);
|
||||
float2 V0sn = V0s / V0sl;
|
||||
float Z0s = asfloat(packedSample0.y) * scene.zFar;
|
||||
float3 C0s = colorTexture.SampleLevel(pointSampler, TC0, 0).rgb;
|
||||
float distTC0 = distance(TC0, input.texCoords);
|
||||
float W0d = max(dot(V0sn, dirn), 0.0);
|
||||
|
||||
uint2 packedSample1 = packedTexture.Load(uint3(TC1 * fullResSize, 0));
|
||||
float2 V1s = UnpackHalf2(packedSample1.x);
|
||||
float V1sl = length(V1s);
|
||||
float2 V1sn = V1s / V1sl;
|
||||
float Z1s = asfloat(packedSample1.y) * scene.zFar;
|
||||
float3 C1s = colorTexture.SampleLevel(pointSampler, TC1, 0).rgb;
|
||||
float distTC1 = distance(TC1, input.texCoords);
|
||||
float W1d = max(dot(V1sn, dirn), 0.0);
|
||||
|
||||
ProcessSample(fgAccum, bgAccum, alpha, center, Z0s, Zc, V0sl, Vcl, distTC0, C0s, C1s, W0d);
|
||||
ProcessSample(fgAccum, bgAccum, alpha, center, Z1s, Zc, V1sl, Vcl, distTC1, C1s, C0s, W1d);
|
||||
|
||||
realSampleCount += 2;
|
||||
}
|
||||
|
||||
if(fgAccum.w <= 0.0 || bgAccum.w <= 0.0)
|
||||
{
|
||||
return float4(color, 1.0);
|
||||
}
|
||||
|
||||
fgAccum.rgb /= fgAccum.w;
|
||||
bgAccum.rgb /= bgAccum.w;
|
||||
alpha /= float(realSampleCount);
|
||||
center /= float(realSampleCount);
|
||||
float3 bg = center * color + (1.0 - center) * bgAccum.rgb;
|
||||
float3 blended = alpha * fgAccum.rgb + (1.0 - alpha) * bg;
|
||||
|
||||
return float4(blended, 1.0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
Summary:
|
||||
- sampling N times in a line along fragment's direction
|
||||
- sampling N times in a line along neighborhood's strongest direction
|
||||
- jittering neighborhood tiles to trade banding for blue noise
|
||||
- jittering the lines' center points with blue noise
|
||||
- weighting samples based on depth, distance and direction similarity
|
||||
|
||||
References:
|
||||
- "A Reconstruction Filter for Plausible Motion Blur" by McGuire et al.
|
||||
- "A Fast and Stable Feature-Aware Motion Blur Filter" by Guertin et al.
|
||||
*/
|
||||
|
||||
float Cone(float distSamples, float velocityLength)
|
||||
{
|
||||
float result = saturate(1.0 - distSamples / velocityLength);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float Cylinder(float distSamples, float velocityLength)
|
||||
{
|
||||
float l = velocityLength;
|
||||
float result = 1.0 - smoothstep(0.95 * l, 1.05 * l, distSamples);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float SoftDepthFalloff(float zA, float zB)
|
||||
{
|
||||
float result = saturate(1.0 - (zB - zA) / max(zB, zA));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
SamplerState pointSampler = SamplerDescriptorHeap[pointSamplerIndex];
|
||||
SamplerState linearSampler = SamplerDescriptorHeap[linearSamplerIndex];
|
||||
Texture2D colorTexture = ResourceDescriptorHeap[colorTextureIndex];
|
||||
Texture2D<float2> tileTexture = ResourceDescriptorHeap[tileTextureIndex];
|
||||
Texture2D<uint2> packedTexture = ResourceDescriptorHeap[packedTextureIndex];
|
||||
Texture2D blueNoiseTexture = ResourceDescriptorHeap[blueNoiseTextureIndex];
|
||||
float2 fullResSize = float2(GetTextureSize(colorTexture));
|
||||
float2 tileSize = float2(GetTextureSize(tileTexture));
|
||||
uint2 blueNoiseSize = GetTextureSize(blueNoiseTexture);
|
||||
|
||||
uint2 blueNoisePx = (input.texCoords * fullResSize) % blueNoiseSize;
|
||||
float2 blueNoise = blueNoiseTexture.Load(uint3(blueNoisePx, 0)).xy;
|
||||
float2 tileJitterTC = 0.25 * (blueNoise * 2.0 - 1.0) / tileSize;
|
||||
float2 tileTC = input.texCoords + tileJitterTC;
|
||||
float2 Vn = tileTexture.SampleLevel(pointSampler, tileTC, 0);
|
||||
float2 Vnn = normalize(Vn);
|
||||
float3 color = colorTexture.SampleLevel(pointSampler, input.texCoords, 0).rgb;
|
||||
uint2 packedFrag = packedTexture.Load(uint3(input.texCoords * fullResSize, 0));
|
||||
float2 Vc = UnpackHalf2(packedFrag.x);
|
||||
float Vcl = length(Vc);
|
||||
float2 Vcn = Vc / Vcl;
|
||||
float Zc = asfloat(packedFrag.y) * scene.zFar;
|
||||
float lengthPx = length(Vn * fullResSize);
|
||||
if(lengthPx < 0.5)
|
||||
{
|
||||
return float4(color, 1);
|
||||
}
|
||||
|
||||
uint sampleCount = min(4 * uint(ceil(lengthPx)), 64); // per line
|
||||
float2 tcStepN = 2.0 * Vn / float2(sampleCount - 1, sampleCount - 1);
|
||||
float2 tcStepC = 2.0 * Vc / float2(sampleCount - 1, sampleCount - 1);
|
||||
float3 colorAccum = color;
|
||||
float weightAccum = 1.0;
|
||||
uint sampleCountTotal = sampleCount * 2; // across all lines
|
||||
for(uint i = 0; i < sampleCount; i++)
|
||||
{
|
||||
float step = float(i / 2);
|
||||
|
||||
float2 tc;
|
||||
float2 dirn;
|
||||
[flatten]
|
||||
if(sampleCount % 2 == 0)
|
||||
{
|
||||
tc = input.texCoords - 0.5 * Vn + (blueNoise.x + step) * tcStepN;
|
||||
dirn = Vnn;
|
||||
}
|
||||
else
|
||||
{
|
||||
tc = input.texCoords - 0.5 * Vc + (blueNoise.y + step) * tcStepC;
|
||||
dirn = Vcn;
|
||||
}
|
||||
|
||||
if(!IsValue01(tc))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint2 packedSample = packedTexture.Load(uint3(tc * fullResSize, 0));
|
||||
float2 Vs = UnpackHalf2(packedSample.x);
|
||||
float Vsl = length(Vs);
|
||||
float2 Vsn = Vs / Vsl;
|
||||
float Zs = asfloat(packedSample.y) * scene.zFar;
|
||||
float3 colorSample = colorTexture.SampleLevel(pointSampler, tc, 0).rgb;
|
||||
float fg = SoftDepthFalloff(Zc, Zs);
|
||||
float bg = SoftDepthFalloff(Zs, Zc);
|
||||
float distTC = distance(tc, input.texCoords);
|
||||
float fgWeight = fg * Cone(distTC, Vsl) * max(0, dot(dirn, Vsn));
|
||||
float bgWeight = bg * Cone(distTC, Vcl) * max(0, dot(dirn, Vcn));
|
||||
float overlapWeight = 2.0 * Cylinder(distTC, Vsl) * Cylinder(distTC, Vcl);
|
||||
float weight = fgWeight + bgWeight + overlapWeight;
|
||||
colorAccum += colorSample * weight;
|
||||
weightAccum += weight;
|
||||
}
|
||||
float4 result = float4(colorAccum /= weightAccum, 1.0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
57
code/renderer/shaders/crp/mblur_pack.hlsl
Normal file
57
code/renderer/shaders/crp/mblur_pack.hlsl
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// motion blur packing of scaled velocities and linear depth into a full-screen texture
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
float motionScale;
|
||||
float maxRadiusPx;
|
||||
};
|
||||
|
||||
uint2 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
Texture2D<float> depthTexture = ResourceDescriptorHeap[scene.depthTextureIndex];
|
||||
float2 textureSize = float2(GetTextureSize(depthTexture));
|
||||
uint3 tc = uint3(input.texCoords * textureSize, 0);
|
||||
float depthZW = depthTexture.Load(tc);
|
||||
float linearDepth01 = scene.LinearDepth(depthZW) / scene.zFar;
|
||||
|
||||
Texture2D<float2> motionTexture = ResourceDescriptorHeap[scene.motionVectorMBTextureIndex];
|
||||
float2 motionTC = motionTexture.Load(tc) * motionScale;
|
||||
float2 motionPx = motionTC * textureSize;
|
||||
float motionLengthPx = length(motionPx);
|
||||
if(motionLengthPx > maxRadiusPx)
|
||||
{
|
||||
motionTC *= maxRadiusPx / motionLengthPx;
|
||||
}
|
||||
uint motionPacked = PackHalf2(motionTC);
|
||||
uint2 result = uint2(motionPacked, asuint(linearDepth01));
|
||||
|
||||
return result;
|
||||
}
|
62
code/renderer/shaders/crp/mblur_tile_gen.hlsl
Normal file
62
code/renderer/shaders/crp/mblur_tile_gen.hlsl
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// motion blur velocity tile generation
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint inputTextureIndex;
|
||||
uint outputTextureIndex;
|
||||
};
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID, uint3 gid : SV_GroupID, uint3 gtid : SV_GroupThreadID)
|
||||
{
|
||||
uint2 tcOut = dtid.xy;
|
||||
RWTexture2D<float2> outputTexture = ResourceDescriptorHeap[outputTextureIndex];
|
||||
if(any(tcOut >= GetTextureSize(outputTexture)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Texture2D<uint2> inputTexture = ResourceDescriptorHeap[inputTextureIndex];
|
||||
|
||||
// This loop can read out of bounds in the inputTexture.
|
||||
// Each full-res pixel has a corresponding tile pixel, but the reverse isn't always true.
|
||||
// Texture.Load is specced to return 0 on OOB accesses.
|
||||
// Since we max() the values, zeroes have no effect on the final result.
|
||||
uint2 tcInCorner = tcOut * uint2(16, 16);
|
||||
float2 maxVelocity = float2(0, 0);
|
||||
for(uint y = 0; y < 16; y++)
|
||||
{
|
||||
for(uint x = 0; x < 16; x++)
|
||||
{
|
||||
uint2 tcIn = tcInCorner + uint2(x, y);
|
||||
float2 velocity = UnpackHalf2(inputTexture.Load(uint3(tcIn, 0)).x);
|
||||
maxVelocity = vmax(maxVelocity, velocity);
|
||||
}
|
||||
}
|
||||
|
||||
outputTexture[tcOut] = maxVelocity;
|
||||
}
|
62
code/renderer/shaders/crp/mblur_tile_max.hlsl
Normal file
62
code/renderer/shaders/crp/mblur_tile_max.hlsl
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// motion blur velocity tile dilation
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
|
||||
|
||||
cbuffer RootConstants : register(b0)
|
||||
{
|
||||
uint inputTextureIndex;
|
||||
uint outputTextureIndex;
|
||||
uint samplerIndex; // point/clamp
|
||||
};
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void cs(uint3 dtid : SV_DispatchThreadID)
|
||||
{
|
||||
uint2 tc = dtid.xy;
|
||||
RWTexture2D<float2> outputTexture = ResourceDescriptorHeap[outputTextureIndex];
|
||||
uint2 textureSize = GetTextureSize(outputTexture);
|
||||
if(any(tc >= textureSize))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Texture2D<float2> inputTexture = ResourceDescriptorHeap[inputTextureIndex];
|
||||
SamplerState samplerState = SamplerDescriptorHeap[samplerIndex];
|
||||
|
||||
float2 tcShifted = float2(tc) + float2(0.5, 0.5);
|
||||
float2 pixelSize = float2(1, 1) / float2(textureSize);
|
||||
float2 maxVelocity = float2(0, 0);
|
||||
for(int y = -1; y <= 1; y++)
|
||||
{
|
||||
for(int x = -1; x <= 1; x++)
|
||||
{
|
||||
float2 tc01 = (tcShifted + float2(x, y)) * pixelSize;
|
||||
float2 velocity = inputTexture.SampleLevel(samplerState, tc01, 0);
|
||||
maxVelocity = vmax(maxVelocity, velocity);
|
||||
}
|
||||
}
|
||||
|
||||
outputTexture[tc] = maxVelocity;
|
||||
}
|
|
@ -30,10 +30,21 @@ cbuffer RootConstants
|
|||
{
|
||||
matrix modelViewMatrix;
|
||||
matrix modelMatrix;
|
||||
matrix normalMatrix;
|
||||
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
|
||||
|
@ -47,8 +58,11 @@ struct VIn
|
|||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
nointerpolation float3 normalWS : NORMAL;
|
||||
nointerpolation float3 positionWS : POSITION;
|
||||
float4 currPosition : CURRPOSITION;
|
||||
float4 prevPosition : PREVPOSITION;
|
||||
float4 prevPositionMB : PREVPOSITIONMB;
|
||||
nointerpolation float3 normalWS : NORMALWS;
|
||||
nointerpolation float3 positionWS : POSITIONWS;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float clipDist : SV_ClipDistance0;
|
||||
|
@ -57,13 +71,40 @@ struct VOut
|
|||
VOut vs(VIn input)
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
matrix projectionMatrix = scene.projectionMatrix;
|
||||
float4 positionVS = mul(modelViewMatrix, float4(input.position.xyz, 1));
|
||||
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 = mul(projectionMatrix, positionVS);
|
||||
output.normalWS = mul(normalMatrix, float4(input.normal, 0)).xyz;
|
||||
output.positionWS = mul(modelMatrix, float4(input.position, 1)).xyz;
|
||||
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);
|
||||
|
@ -75,24 +116,10 @@ struct POut
|
|||
{
|
||||
float2 normal : SV_Target0;
|
||||
float2 motionVector : SV_Target1;
|
||||
float4 shadingPosition : SV_Target2;
|
||||
float2 motionVectorMB : SV_Target2;
|
||||
float4 shadingPosition : SV_Target3;
|
||||
};
|
||||
|
||||
float3 FixNormal(float3 vertexNormal, float3 faceNormal)
|
||||
{
|
||||
if(length(vertexNormal) < 0.5)
|
||||
{
|
||||
return faceNormal;
|
||||
}
|
||||
|
||||
if(dot(vertexNormal, faceNormal) < 0.0)
|
||||
{
|
||||
return -vertexNormal;
|
||||
}
|
||||
|
||||
return vertexNormal;
|
||||
}
|
||||
|
||||
POut ps(VOut input, float3 barycentrics : SV_Barycentrics)
|
||||
{
|
||||
if(alphaTest != ATEST_NONE)
|
||||
|
@ -125,9 +152,14 @@ POut ps(VOut input, float3 barycentrics : SV_Barycentrics)
|
|||
float dist = saturate(distance(shadingPosition, position));
|
||||
float positionDelta = asfloat(PackColor(float4(dist3, dist)));
|
||||
|
||||
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 = float2(0, 0); // @TODO:
|
||||
output.motionVector = currPosTC - prevPosTC;
|
||||
output.motionVectorMB = (currPosTC - prevPosMBTC) * motionBlurScale;
|
||||
output.shadingPosition = float4(shadingPosition, positionDelta);
|
||||
|
||||
return output;
|
||||
|
|
|
@ -45,6 +45,9 @@ struct SceneView
|
|||
matrix invProjectionMatrix;
|
||||
matrix viewMatrix;
|
||||
matrix invViewMatrix;
|
||||
matrix prevViewProjMatrix;
|
||||
matrix prevViewMatrix;
|
||||
matrix prevProjectionMatrix;
|
||||
float4 clipPlane;
|
||||
float4 debug;
|
||||
uint sceneViewIndex;
|
||||
|
@ -52,11 +55,24 @@ struct SceneView
|
|||
uint depthTextureIndex;
|
||||
uint normalTextureIndex;
|
||||
uint shadingPositionTextureIndex;
|
||||
uint motionVectorTextureIndex;
|
||||
uint motionVectorMBTextureIndex;
|
||||
uint lightTextureIndex;
|
||||
uint tlasBufferIndex;
|
||||
uint tlasInstanceBufferIndex;
|
||||
uint lightCount;
|
||||
float linearDepthA;
|
||||
float linearDepthB;
|
||||
float zNear;
|
||||
float zFar;
|
||||
DynamicLight lights[SCENE_VIEW_MAX_LIGHTS];
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
float LinearDepth(float zwDepth)
|
||||
{
|
||||
return linearDepthB / (zwDepth - linearDepthA);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
|
48
code/renderer/shaders/crp/skybox_motion.hlsl
Normal file
48
code/renderer/shaders/crp/skybox_motion.hlsl
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// outputs motion vectors for objects infinitely far away
|
||||
|
||||
|
||||
#include "common.hlsli"
|
||||
#include "fullscreen.hlsli"
|
||||
#include "scene_view.h.hlsli"
|
||||
|
||||
|
||||
float2 ps(VOut input) : SV_Target
|
||||
{
|
||||
SceneView scene = GetSceneView();
|
||||
|
||||
// we need the position to match for perfect translation invariance
|
||||
matrix prevViewMatrix = scene.prevViewMatrix;
|
||||
prevViewMatrix[0][3] = scene.viewMatrix[0][3];
|
||||
prevViewMatrix[1][3] = scene.viewMatrix[1][3];
|
||||
prevViewMatrix[2][3] = scene.viewMatrix[2][3];
|
||||
|
||||
float2 currNDC = TCToNDC(input.texCoords.xy);
|
||||
float4 currPointNDC = float4(currNDC, 0, 1);
|
||||
float4 pointWSw = mul(scene.invViewMatrix, mul(scene.invProjectionMatrix, currPointNDC));
|
||||
float4 pointWS = pointWSw / pointWSw.w;
|
||||
float4 prevPointNDC = mul(scene.prevProjectionMatrix, mul(prevViewMatrix, pointWS));
|
||||
float2 prevNDC = prevPointNDC.xy / prevPointNDC.w;
|
||||
float2 motionTC = NDCToTC(currNDC) - NDCToTC(prevNDC);
|
||||
|
||||
return motionTC;
|
||||
}
|
|
@ -76,11 +76,6 @@ float GetBitAsFloat(uint bits, uint bitIndex)
|
|||
return (bits & (1u << bitIndex)) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
float2 UnpackHalf2(uint data)
|
||||
{
|
||||
return float2(f16tof32(data), f16tof32(data >> 16));
|
||||
}
|
||||
|
||||
float4 DepthFadeFragmentColor(float4 color, OIT_Fragment fragment, float storedDepthZW)
|
||||
{
|
||||
if(((fragment.depthFadeScaleBias >> 8) & 1) == 0)
|
||||
|
|
|
@ -72,7 +72,7 @@ void MipMapGenerator::Init(bool ddhi_, const ShaderByteCode& g2l, const ShaderBy
|
|||
for(int t = 0; t < 2; ++t)
|
||||
{
|
||||
TextureDesc desc(va("mip-map generation #%d", t + 1), MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE);
|
||||
desc.format = TextureFormat::RGBA64_Float;
|
||||
desc.format = TextureFormat::R16G16B16A16_Float;
|
||||
desc.initialState = ResourceStates::UnorderedAccessBit;
|
||||
desc.allowedState = ResourceStates::UnorderedAccessBit | ResourceStates::ComputeShaderAccessBit;
|
||||
textures[MipSlice::Float16_0 + t] = CreateTexture(desc);
|
||||
|
|
|
@ -222,6 +222,24 @@ void R_AddDrawSurfCmd( drawSurf_t* drawSurfs, int numDrawSurfs, int numTranspSur
|
|||
cmd->shouldClearColor = shouldClearColor;
|
||||
cmd->shouldDrawScene = shouldDrawScene;
|
||||
Vector4Copy( clearColor, cmd->clearColor );
|
||||
|
||||
// full-screen non-portal view?
|
||||
if(!tr.viewParms.isPortal &&
|
||||
tr.viewParms.viewportX == 0 &&
|
||||
tr.viewParms.viewportY == 0 &&
|
||||
tr.viewParms.viewportWidth == glConfig.vidWidth &&
|
||||
tr.viewParms.viewportHeight == glConfig.vidHeight)
|
||||
{
|
||||
// combined view-projection matrices
|
||||
memcpy(tr.prevViewProjMatrix, tr.currViewProjMatrix, sizeof(tr.prevViewProjMatrix));
|
||||
R_MultMatrix(tr.viewParms.world.modelMatrix, tr.viewParms.projectionMatrix, tr.currViewProjMatrix);
|
||||
|
||||
// separate view and projection matrices
|
||||
memcpy(tr.prevViewMatrix, tr.currViewMatrix, sizeof(tr.prevViewMatrix));
|
||||
memcpy(tr.prevProjMatrix, tr.currProjMatrix, sizeof(tr.prevProjMatrix));
|
||||
memcpy(tr.currViewMatrix, tr.viewParms.world.modelMatrix, sizeof(tr.currViewMatrix));
|
||||
memcpy(tr.currProjMatrix, tr.viewParms.projectionMatrix, sizeof(tr.currProjMatrix));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -534,6 +534,8 @@ struct drawSurf_t {
|
|||
int zppFirstIndex;
|
||||
int zppIndexCount;
|
||||
float radiusOverZ;
|
||||
int uniqueEntityId;
|
||||
float motionBlurScale;
|
||||
};
|
||||
|
||||
void R_TessellateSurface( const surfaceType_t* surfType );
|
||||
|
@ -1007,11 +1009,21 @@ typedef struct {
|
|||
qbool shaderParseFailed;
|
||||
int shaderParseNumWarnings;
|
||||
|
||||
// raytracing support
|
||||
rtSurf_t rtSurfs[MAX_DRAWSURFS];
|
||||
int numRTSurfs;
|
||||
int sceneCounterRT;
|
||||
trRefdef_t rtRefdef;
|
||||
|
||||
// from current and last frame's non-portal full-screen scene view
|
||||
// needed for motion vectors
|
||||
float currViewProjMatrix[16];
|
||||
float prevViewProjMatrix[16];
|
||||
float currViewMatrix[16];
|
||||
float prevViewMatrix[16];
|
||||
float currProjMatrix[16];
|
||||
float prevProjMatrix[16];
|
||||
|
||||
} trGlobals_t;
|
||||
|
||||
extern backEndState_t backEnd;
|
||||
|
@ -1141,7 +1153,7 @@ void R_AddMD3Surfaces( trRefEntity_t *e );
|
|||
|
||||
void R_AddPolygonSurfaces();
|
||||
|
||||
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, 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 uniqueEntityId, float mblurScale, 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 staticGeoChunk );
|
||||
void R_AddRTSurf( const surfaceType_t* surface, const shader_t* shader );
|
||||
uint64_t R_ComposeSort( int entityNum, const shader_t* shader, int staticGeoChunk );
|
||||
|
@ -1411,7 +1423,7 @@ SCENE GENERATION
|
|||
void R_ClearFrame();
|
||||
|
||||
void RE_ClearScene();
|
||||
void RE_AddRefEntityToScene( const refEntity_t *ent, qbool intShaderTime );
|
||||
void RE_AddRefEntityToScene( const refEntity_t *ent, refEntityVersion_t version );
|
||||
void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
|
||||
void RE_AddLightToScene( const vec3_t org, float radius, float r, float g, float b );
|
||||
void RE_RenderScene( const refdef_t *fd, int us );
|
||||
|
|
|
@ -1280,7 +1280,7 @@ static float SurfGreyscaleAmount( const shader_t* shader )
|
|||
}
|
||||
|
||||
|
||||
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int staticGeoChunk, int zppFirstIndex, int zppIndexCount, float radiusOverZ )
|
||||
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int uniqueEntityId, float mblurScale, int staticGeoChunk, int zppFirstIndex, int zppIndexCount, float radiusOverZ )
|
||||
{
|
||||
if (tr.refdef.numDrawSurfs >= MAX_DRAWSURFS)
|
||||
return;
|
||||
|
@ -1295,6 +1295,8 @@ void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int st
|
|||
drawSurf->zppFirstIndex = zppFirstIndex;
|
||||
drawSurf->zppIndexCount = zppIndexCount;
|
||||
drawSurf->radiusOverZ = radiusOverZ;
|
||||
drawSurf->uniqueEntityId = uniqueEntityId;
|
||||
drawSurf->motionBlurScale = mblurScale;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1644,7 +1646,7 @@ static void R_AddEntitySurfaces()
|
|||
continue;
|
||||
}
|
||||
shader = R_GetShaderByHandle( ent->e.customShader );
|
||||
R_AddDrawSurf( &entitySurface, shader );
|
||||
R_AddDrawSurf( &entitySurface, shader, ent->e.uniqueId, ent->e.motionBlurScale );
|
||||
R_AddRTSurf( &entitySurface, shader ); // @TODO: billboards need to be procedural geometry
|
||||
break;
|
||||
|
||||
|
@ -1654,7 +1656,7 @@ static void R_AddEntitySurfaces()
|
|||
|
||||
tr.currentModel = R_GetModelByHandle( ent->e.hModel );
|
||||
if (!tr.currentModel) {
|
||||
R_AddDrawSurf( &entitySurface, tr.defaultShader );
|
||||
R_AddDrawSurf( &entitySurface, tr.defaultShader, ent->e.uniqueId, ent->e.motionBlurScale );
|
||||
} else {
|
||||
switch ( tr.currentModel->type ) {
|
||||
case MOD_MD3:
|
||||
|
@ -1669,7 +1671,7 @@ static void R_AddEntitySurfaces()
|
|||
case MOD_BAD: // null model axis
|
||||
if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal)
|
||||
break;
|
||||
R_AddDrawSurf( &entitySurface, tr.defaultShader );
|
||||
R_AddDrawSurf( &entitySurface, tr.defaultShader, ent->e.uniqueId, ent->e.motionBlurScale );
|
||||
break;
|
||||
default:
|
||||
ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
|
||||
|
|
|
@ -287,7 +287,7 @@ void R_AddMD3Surfaces( trRefEntity_t* ent )
|
|||
// don't add third_person objects if not viewing through a portal
|
||||
if ( !personalModel ) {
|
||||
if( !culled )
|
||||
R_AddDrawSurf( (const surfaceType_t*)surface, shader );
|
||||
R_AddDrawSurf( (const surfaceType_t*)surface, shader, ent->e.uniqueId, ent->e.motionBlurScale );
|
||||
R_AddRTSurf( (const surfaceType_t*)surface, shader );
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ typedef struct {
|
|||
// a scene is built up by calls to R_ClearScene and the various R_Add functions.
|
||||
// Nothing is drawn until R_RenderScene is called.
|
||||
void (*ClearScene)();
|
||||
void (*AddRefEntityToScene)( const refEntity_t *re, qbool intShaderTime );
|
||||
void (*AddRefEntityToScene)( const refEntity_t *re, refEntityVersion_t version );
|
||||
void (*AddPolyToScene)( qhandle_t hShader, int numVerts, const polyVert_t *verts, int num );
|
||||
qbool (*LightForPoint)( const vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
|
||||
void (*AddLightToScene)( const vec3_t org, float radius, float r, float g, float b );
|
||||
|
|
|
@ -83,7 +83,7 @@ void R_AddPolygonSurfaces()
|
|||
|
||||
const srfPoly_t* poly = tr.refdef.polys;
|
||||
for (int i = 0; i < tr.refdef.numPolys; ++i, ++poly) {
|
||||
R_AddDrawSurf( (const surfaceType_t*)poly, R_GetShaderByHandle( poly->hShader ) );
|
||||
R_AddDrawSurf( (const surfaceType_t*)poly, R_GetShaderByHandle( poly->hShader ), 0, 1.0f );
|
||||
// @TODO: polygons are sometimes used to replace sprites (e.g. CPMA rocket smoke),
|
||||
// they should be procedural geometry
|
||||
R_AddRTSurf( (const surfaceType_t*)poly, R_GetShaderByHandle( poly->hShader ) );
|
||||
|
@ -154,7 +154,7 @@ void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t* verts
|
|||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void RE_AddRefEntityToScene( const refEntity_t* ent, qbool intShaderTime )
|
||||
void RE_AddRefEntityToScene( const refEntity_t* ent, refEntityVersion_t version )
|
||||
{
|
||||
if ( !tr.registered ) {
|
||||
return;
|
||||
|
@ -169,9 +169,15 @@ void RE_AddRefEntityToScene( const refEntity_t* ent, qbool intShaderTime )
|
|||
}
|
||||
|
||||
trRefEntity_t* const trEnt = &backEndData->entities[r_numentities];
|
||||
trEnt->e = *ent;
|
||||
if ( version == REV_LATEST ) {
|
||||
trEnt->e = *ent;
|
||||
} else {
|
||||
memcpy( &trEnt->e, ent, sizeof( refEntityBase_t ) );
|
||||
trEnt->e.uniqueId = 0;
|
||||
trEnt->e.motionBlurScale = 1.0f;
|
||||
}
|
||||
trEnt->lightingCalculated = qfalse;
|
||||
trEnt->intShaderTime = intShaderTime;
|
||||
trEnt->intShaderTime = version >= REV_INTSHADERTIME;
|
||||
r_numentities++;
|
||||
}
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ static qbool R_LightCullSurface( const surfaceType_t* surface, const dlight_t* d
|
|||
}
|
||||
|
||||
|
||||
static void R_AddWorldSurface( msurface_t* surf )
|
||||
static void R_AddWorldSurface( msurface_t* surf, int uniqueId, float mblurScale )
|
||||
{
|
||||
if ( surf->vcBSP == tr.viewCount )
|
||||
return; // already checked during this BSP walk
|
||||
|
@ -210,7 +210,7 @@ static void R_AddWorldSurface( msurface_t* surf )
|
|||
radiusOverZ = triangles->radius / max( dist, 0.001f );
|
||||
}
|
||||
|
||||
R_AddDrawSurf( surf->data, surf->shader, surf->staticGeoChunk, surf->zppFirstIndex, surf->zppIndexCount, radiusOverZ );
|
||||
R_AddDrawSurf( surf->data, surf->shader, uniqueId, mblurScale, surf->staticGeoChunk, surf->zppFirstIndex, surf->zppIndexCount, radiusOverZ );
|
||||
}
|
||||
|
||||
|
||||
|
@ -319,7 +319,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits )
|
|||
while (c--) {
|
||||
// the surface may have already been added if it spans multiple leafs
|
||||
msurface_t* surf = *mark;
|
||||
R_AddWorldSurface( surf );
|
||||
R_AddWorldSurface( surf, 0, 1.0f );
|
||||
mark++;
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ void R_AddBrushModelSurfaces( const trRefEntity_t* re )
|
|||
return;
|
||||
|
||||
for ( int s = 0; s < bmodel->numSurfaces; ++s ) {
|
||||
R_AddWorldSurface( bmodel->firstSurface + s );
|
||||
R_AddWorldSurface( bmodel->firstSurface + s, re->e.uniqueId, re->e.motionBlurScale );
|
||||
}
|
||||
|
||||
R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.orient );
|
||||
|
|
|
@ -413,7 +413,13 @@ void ProcessCRP()
|
|||
CompilePixelShader("gbufferviz_depth.h", "gbufferviz_depth.hlsl", "gbufferviz_depth");
|
||||
CompilePixelShader("gbufferviz_normal.h", "gbufferviz_normal.hlsl", "gbufferviz_normal");
|
||||
CompilePixelShader("gbufferviz_position.h", "gbufferviz_position.hlsl", "gbufferviz_position");
|
||||
CompilePixelShader("gbufferviz_motion.h", "gbufferviz_motion.hlsl", "gbufferviz_motion");
|
||||
CompileGraphics("wireframe_normals.h", "wireframe_normals.hlsl", "wireframe_normals");
|
||||
CompilePixelShader("skybox_motion.h", "skybox_motion.hlsl", "skybox_motion");
|
||||
CompileCompute("mblur_tile_gen.h", "mblur_tile_gen.hlsl", "tile_gen");
|
||||
CompileCompute("mblur_tile_max.h", "mblur_tile_max.hlsl", "tile_max");
|
||||
CompilePixelShader("mblur_blur.h", "mblur_blur.hlsl", "blur");
|
||||
CompilePixelShader("mblur_pack.h", "mblur_pack.hlsl", "pack");
|
||||
}
|
||||
|
||||
int main(int /*argc*/, const char** argv)
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_motion_blur.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
|
@ -231,6 +232,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_depth.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_motion.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_normal.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -243,6 +247,18 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\magnifier.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_blur.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_pack.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_gen.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_max.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -261,6 +277,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\prepass.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_motion_blur.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
|
@ -135,6 +136,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_depth.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_motion.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_normal.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -147,6 +151,18 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\magnifier.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_blur.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_pack.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_gen.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_max.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_1.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -165,6 +181,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\prepass.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_motion_blur.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
|
@ -233,6 +234,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_depth.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_motion.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_normal.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -245,6 +249,18 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\magnifier.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_blur.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_pack.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_gen.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_max.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_1.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
@ -263,6 +279,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\prepass.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
<ClCompile Include="..\..\code\renderer\crp_geometry.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_magnifier.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_main.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_motion_blur.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_opaque.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_prepass.cpp" />
|
||||
<ClCompile Include="..\..\code\renderer\crp_raytracing.cpp" />
|
||||
|
@ -135,6 +136,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_depth.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_motion.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\gbufferviz_normal.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -147,6 +151,18 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\magnifier.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_blur.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_pack.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_gen.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mblur_tile_max.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\mip_1.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
@ -165,6 +181,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\shaders\crp\prepass.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\skybox_motion.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\shaders\crp\tone_map.hlsl">
|
||||
<Filter>shaders\crp</Filter>
|
||||
</FxCompile>
|
||||
|
|
Loading…
Reference in a new issue