BackBuffer and RenderTarget at one pass?
- Fu-Bama
- Topic Author
I'm trying to make interlaced effect, but current solution has two full-screen resolution render targets.
One to bypass effect and get raw BackBuffer image stored,
second to write that stored raw BackBuffer at the end of the shader to get previous frame without any effects applied.
Code:
/*
Interlaced effect PS v0.1.0 (c) 2018 Jacob Maximilian Fober,
This work is licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-sa/4.0/.
*/
#ifndef ShaderAnalyzer
uniform int Order <
ui_label = "Row order";
ui_type = "combo";
ui_items = "Odd first\0Even first\0";
> = 0;
#endif
// Previous frame render target and buffer
texture InterlacedTarget { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; };
sampler InterlacedSampler { Texture = InterlacedTarget; };
texture InterlacedTargetBuffer { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; };
sampler InterlacedSamplerBuffer { Texture = InterlacedTargetBuffer; };
#include "ReShade.fxh"
void CurrentFramePS(float4 vpos : SV_Position, float2 UvCoord : TEXCOORD, out float3 CurFrame : SV_Target)
{
CurFrame = tex2D(ReShade::BackBuffer, UvCoord).rgb;
// Output raw BackBuffer to InterlacedTargetBuffer
}
void InterlacedPS(float4 vpos : SV_Position, float2 UvCoord : TEXCOORD, out float3 Image : SV_Target)
{
// Interlaced rows boolean
bool OddPixel = frac(int(ReShade::ScreenSize.y * UvCoord.y) * 0.5) != 0;
// Read BackBuffer texture saved at previous frame
float3 PrevFrame = tex2D(InterlacedSampler, UvCoord).rgb;
// Read texture not yet displayed on screen
float3 CurFrame = tex2D(ReShade::BackBuffer, UvCoord).rgb;
// Set rows to previous and current frame
Image = (bool(Order) ? OddPixel : !OddPixel) ? PrevFrame : CurFrame;
}
void PreviousFramePS(float4 vpos : SV_Position, float2 UvCoord : TEXCOORD, out float3 PrevFrame : SV_Target)
{
PrevFrame = tex2D(InterlacedSamplerBuffer, UvCoord).rgb;
// Output raw BackBuffer (wouthout effects aplied at pass above)..
// ..to InterlacedTarget from InterlacedTargetBuffer for use at next frame
}
technique Interlaced
{
pass
{
VertexShader = PostProcessVS;
PixelShader = CurrentFramePS;
RenderTarget = InterlacedTargetBuffer;
}
pass
{
VertexShader = PostProcessVS;
PixelShader = InterlacedPS;
}
pass
{
VertexShader = PostProcessVS;
PixelShader = PreviousFramePS;
RenderTarget = InterlacedTarget;
}
}
Please Log in or Create an account to join the conversation.
- Marty McFly
Also:
int(ReShade::ScreenSize.y * UvCoord.y)
is vpos.y.
Please Log in or Create an account to join the conversation.
- crosire
Additional documentation beside the code Marty mentioned is here (see the "RenderTarget" pass state):
github.com/crosire/reshade-shaders/blob/...ERENCE.md#techniques
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Since it's interlaced shader we don't need full-res render targets, only half vertical resolution.
Even better, we can squeeze both render target outputs into one texture of a screen size.
But hey, if we flip flop write Back Buffer odd rows between top and bottom half of the Render Target, the previous frame will survive till second pass. And we can get rid of the third pass.
I managed to reduce it to 2 passes and one render target.
Here's how the render target looks like:
It flip flops current and previous frame from top to bottom at every frame.
The code:
/*
Interlaced effect PS v1.0.2 (c) 2018 Jacob Maximilian Fober,
This work is licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-sa/4.0/.
*/
#ifndef ShaderAnalyzer
uniform int FrameCount < source = "framecount"; >;
#endif
// Previous frame render target buffer
texture InterlacedTargetBuffer { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; MagFilter = POINT; MinFilter = POINT; MipFilter = POINT;};
sampler InterlacedBufferSampler { Texture = InterlacedTargetBuffer; };
#include "ReShade.fxh"
void InterlacedTargetPass(float4 vpos : SV_Position, float2 UvCoord : TEXCOORD, out float3 Target : SV_Target)
{
// Interlaced rows boolean
bool OddPixel = frac(int(ReShade::ScreenSize.y * UvCoord.y) * 0.5) != 0;
bool OddFrame = frac(FrameCount * 0.5) != 0;
bool BottomHalf = UvCoord.y > 0.5;
// Flip flop saving texture between top and bottom half of the RenderTarget
float2 Coordinates;
Coordinates.x = UvCoord.x;
Coordinates.y = UvCoord.y * 2;
// Adjust flip flop coordinates
Coordinates.y -= BottomHalf ?
1 + ReShade::PixelSize.y * 0.5
: ReShade::PixelSize.y * 0.5;
// Flip flop save to Render Target texture
Target = (OddFrame ? BottomHalf : UvCoord.y < 0.5) ?
tex2D(ReShade::BackBuffer, Coordinates).rgb
: tex2D(InterlacedBufferSampler, UvCoord).rgb;
// Outputs raw BackBuffer to InterlacedTargetBuffer for the next frame
}
void InterlacedPS(float4 vpos : SV_Position, float2 UvCoord : TEXCOORD, out float3 Image : SV_Target)
{
// Interlaced rows boolean
bool OddPixel = frac(int(ReShade::ScreenSize.y * UvCoord.y) * 0.5) != 0;
bool OddFrame = frac(FrameCount * 0.5) != 0;
// Calculate coordinates of BackBuffer texture saved at previous frame
float2 Coordinates = float2(UvCoord.x, UvCoord.y * 0.5);
Coordinates.y += OddFrame ?
ReShade::PixelSize.y * 0.25
: ReShade::PixelSize.y * 0.25 + 0.5;
// Sample odd and even rows
Image = OddPixel ? tex2D(ReShade::BackBuffer, UvCoord).rgb
: tex2D(InterlacedBufferSampler, Coordinates).rgb;
// Preview RenderTarget
// Image = tex2D(InterlacedBufferSampler, UvCoord).rgb;
}
technique Interlaced
{
pass
{
VertexShader = PostProcessVS;
PixelShader = InterlacedTargetPass;
RenderTarget = InterlacedTargetBuffer;
ClearRenderTargets = false;
}
pass
{
VertexShader = PostProcessVS;
PixelShader = InterlacedPS;
}
}
Please Log in or Create an account to join the conversation.
But it works in Mirrors Edge (2007), RAGE and Blender.
EDIT*
It looks like
ClearRenderTargets = false;
is not working for those
Please Log in or Create an account to join the conversation.
- crosire
This is expected. OpenGL has its origin at the bottom left corner of the screen, while DirectX has its origin at the top left corner. ReShade fixes texture coordinates to match DirectX terminology, but doesn't do so for positions.Fu-Bama wrote: I just noticed that vpos : SV_Position is vertically reversed on OpenGL. Is it a bug? It's counting from the bottom to top at Y channel.
Please Log in or Create an account to join the conversation.
When you un-comment at line 57 where there is // Preview RenderTarget you can see flip flop flashing of black texture when in DX10. That means the game does not preserve data from previous shader run, but clears it. Can it be fixed?
Please Log in or Create an account to join the conversation.
- Marty McFly
Please Log in or Create an account to join the conversation.
Reading from InterlacedTargetBuffer is not necessary in that pass. If I could just leave one half of the target untouched in the memory. BlendEnable = true in pass settings suppose to do that, right? Blend the render target with whatever was present in memory?Marty McFly wrote: Hm. InterlacedTargetPass reads from InterlacedTargetBuffer and writes to it at the same time (...)
But I have no idea how to use it. I don't quite get it from the documentation. github.com/crosire/reshade-shaders/blob/...ERENCE.md#techniques
Please Log in or Create an account to join the conversation.
- Marty McFly
BlendEnable = true; //to enable blending
BlendOp = ADD; //mimic lerp, A*(1-k) + B*k, where B is current data, A is previous
SrcBlend = SRCALPHA; //B*k so if alpha == 1 we get output of your pass, Src being output of current frame
DestBlend = INVSRCALPHA; //A*(1-k) so if alpha == 0 we get what was originally in the buffer (Dest being previous data)
Please Log in or Create an account to join the conversation.
- crosire
Please Log in or Create an account to join the conversation.
Thanks
Code:
/*
Interlaced effect PS v1.0.4 (c) 2018 Jacob Maximilian Fober,
(blending fix thanks to Marty McFly)
This work is licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-sa/4.0/.
*/
#ifndef ShaderAnalyzer
uniform int FrameCount < source = "framecount"; >;
#endif
// Previous frame render target buffer
texture InterlacedTargetBuffer { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; };
sampler InterlacedBufferSampler { Texture = InterlacedTargetBuffer;
MagFilter = POINT;
MinFilter = POINT;
MipFilter = POINT;
};
#include "ReShade.fxh"
void InterlacedTargetPass(float4 vpos : SV_Position, float2 UvCoord : TEXCOORD,
out float4 Target : SV_Target)
{
// Interlaced rows boolean
bool OddPixel = frac(int(ReShade::ScreenSize.y * UvCoord.y) * 0.5) != 0;
bool OddFrame = frac(FrameCount * 0.5) != 0;
bool BottomHalf = UvCoord.y > 0.5;
// Flip flop saving texture between top and bottom half of the RenderTarget
float2 Coordinates;
Coordinates.x = UvCoord.x;
Coordinates.y = UvCoord.y * 2;
// Adjust flip flop coordinates
float hPixelSizeY = ReShade::PixelSize.y * 0.5;
Coordinates.y -= BottomHalf ? 1 + hPixelSizeY : hPixelSizeY;
// Flip flop save to Render Target texture
Target = (OddFrame ? BottomHalf : UvCoord.y < 0.5) ?
float4(tex2D(ReShade::BackBuffer, Coordinates).rgb, 1) : 0;
// Outputs raw BackBuffer to InterlacedTargetBuffer for the next frame
}
void InterlacedPS(float4 vpos : SV_Position, float2 UvCoord : TEXCOORD,
out float3 Image : SV_Target)
{
// Interlaced rows boolean
bool OddPixel = frac(int(ReShade::ScreenSize.y * UvCoord.y) * 0.5) != 0;
bool OddFrame = frac(FrameCount * 0.5) != 0;
// Calculate coordinates of BackBuffer texture saved at previous frame
float2 Coordinates = float2(UvCoord.x, UvCoord.y * 0.5);
float qPixelSizeY = ReShade::PixelSize.y * 0.25;
Coordinates.y += OddFrame ? qPixelSizeY : qPixelSizeY + 0.5;
// Sample odd and even rows
Image = OddPixel ? tex2D(ReShade::BackBuffer, UvCoord).rgb
: tex2D(InterlacedBufferSampler, Coordinates).rgb;
// Preview RenderTarget
// Image = tex2D(InterlacedBufferSampler, UvCoord).rgb;
}
technique Interlaced
{
pass
{
VertexShader = PostProcessVS;
PixelShader = InterlacedTargetPass;
RenderTarget = InterlacedTargetBuffer;
ClearRenderTargets = false;
BlendEnable = true;
BlendOp = ADD; //mimic lerp
SrcBlend = SRCALPHA;
DestBlend = INVSRCALPHA;
}
pass
{
VertexShader = PostProcessVS;
PixelShader = InterlacedPS;
}
}
Please Log in or Create an account to join the conversation.
- knowom
Please Log in or Create an account to join the conversation.