Create "final" two non-VR 3D modes: Column-interleaved and checkerboard.

This commit is contained in:
Christopher Bruns 2016-10-09 13:05:50 -04:00
parent fc246be03e
commit 779e6acb7b
15 changed files with 300 additions and 67 deletions

View file

@ -2,7 +2,6 @@
#define __GL_RENDERBUFFERS_H
#include "gl/shaders/gl_shader.h"
#include "gl/renderer/gl_renderer.h"
class FGLBloomTextureLevel
{

View file

@ -105,6 +105,8 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
mTonemapPalette = nullptr;
mBuffers = nullptr;
mPresentShader = nullptr;
mPresent3dCheckerShader = nullptr;
mPresent3dColumnShader = nullptr;
mPresent3dRowShader = nullptr;
mBloomExtractShader = nullptr;
mBloomCombineShader = nullptr;
@ -139,6 +141,8 @@ void FGLRenderer::Initialize(int width, int height)
mFXAAShader = new FFXAAShader;
mFXAALumaShader = new FFXAALumaShader;
mPresentShader = new FPresentShader();
mPresent3dCheckerShader = new FPresent3DCheckerShader();
mPresent3dColumnShader = new FPresent3DColumnShader();
mPresent3dRowShader = new FPresent3DRowShader();
m2DDrawer = new F2DDrawer;
@ -192,6 +196,8 @@ FGLRenderer::~FGLRenderer()
}
if (mBuffers) delete mBuffers;
if (mPresentShader) delete mPresentShader;
if (mPresent3dCheckerShader) delete mPresent3dCheckerShader;
if (mPresent3dColumnShader) delete mPresent3dColumnShader;
if (mPresent3dRowShader) delete mPresent3dRowShader;
if (mBloomExtractShader) delete mBloomExtractShader;
if (mBloomCombineShader) delete mBloomCombineShader;

View file

@ -31,6 +31,8 @@ class FLensShader;
class FFXAALumaShader;
class FFXAAShader;
class FPresentShader;
class FPresent3DCheckerShader;
class FPresent3DColumnShader;
class FPresent3DRowShader;
class F2DDrawer;
class FHardwareTexture;
@ -109,6 +111,8 @@ public:
FFXAALumaShader *mFXAALumaShader;
FFXAAShader *mFXAAShader;
FPresentShader *mPresentShader;
FPresent3DCheckerShader *mPresent3dCheckerShader;
FPresent3DColumnShader *mPresent3dColumnShader;
FPresent3DRowShader *mPresent3dRowShader;
FTexture *gllight;

View file

@ -38,23 +38,37 @@
#include "gl/system/gl_cvars.h"
#include "gl/shaders/gl_present3dRowshader.h"
void FPresentStereoShaderBase::Init(const char * vtx_shader_name, const char * program_name)
{
FPresentShaderBase::Init(vtx_shader_name, program_name);
LeftEyeTexture.Init(mShader, "LeftEyeTexture");
RightEyeTexture.Init(mShader, "RightEyeTexture");
WindowPositionParity.Init(mShader, "WindowPositionParity");
}
void FPresent3DCheckerShader::Bind()
{
if (!mShader)
{
Init("shaders/glsl/present_checker3d.fp", "shaders/glsl/presentChecker3d");
}
mShader.Bind();
}
void FPresent3DColumnShader::Bind()
{
if (!mShader)
{
Init("shaders/glsl/present_column3d.fp", "shaders/glsl/presentColumn3d");
}
mShader.Bind();
}
void FPresent3DRowShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present_row3d.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/presentRow3d");
mShader.SetAttribLocation(0, "PositionInProjection");
mShader.SetAttribLocation(1, "UV");
LeftEyeTexture.Init(mShader, "LeftEyeTexture");
RightEyeTexture.Init(mShader, "RightEyeTexture");
InvGamma.Init(mShader, "InvGamma");
Contrast.Init(mShader, "Contrast");
Brightness.Init(mShader, "Brightness");
Scale.Init(mShader, "UVScale");
VerticalPixelOffset.Init(mShader, "VerticalPixelOffset");
Init("shaders/glsl/present_row3d.fp", "shaders/glsl/presentRow3d");
}
mShader.Bind();
}

View file

@ -29,22 +29,35 @@
#define GL_PRESENT3DROWSHADER_H_
#include "gl_shaderprogram.h"
#include "gl_presentshader.h"
class FPresent3DRowShader
class FPresentStereoShaderBase : public FPresentShaderBase
{
public:
void Bind();
FBufferedUniformSampler LeftEyeTexture;
FBufferedUniformSampler RightEyeTexture;
FBufferedUniform1f InvGamma;
FBufferedUniform1f Contrast;
FBufferedUniform1f Brightness;
FBufferedUniform2f Scale;
FBufferedUniform1i VerticalPixelOffset;
FBufferedUniform1i WindowPositionParity;
private:
FShaderProgram mShader;
protected:
void Init(const char * vtx_shader_name, const char * program_name) override;
};
class FPresent3DCheckerShader : public FPresentStereoShaderBase
{
public:
void Bind() override;
};
class FPresent3DColumnShader : public FPresentStereoShaderBase
{
public:
void Bind() override;
};
class FPresent3DRowShader : public FPresentStereoShaderBase
{
public:
void Bind() override;
};
// GL_PRESENT3DROWSHADER_H_

View file

@ -36,21 +36,26 @@
#include "gl/system/gl_cvars.h"
#include "gl/shaders/gl_presentshader.h"
void FPresentShaderBase::Init(const char * vtx_shader_name, const char * program_name)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, vtx_shader_name, "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link(program_name);
mShader.SetAttribLocation(0, "PositionInProjection");
mShader.SetAttribLocation(1, "UV");
InvGamma.Init(mShader, "InvGamma");
Contrast.Init(mShader, "Contrast");
Brightness.Init(mShader, "Brightness");
Scale.Init(mShader, "UVScale");
}
void FPresentShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/present");
mShader.SetAttribLocation(0, "PositionInProjection");
mShader.SetAttribLocation(1, "UV");
Init("shaders/glsl/present.fp", "shaders/glsl/present");
InputTexture.Init(mShader, "InputTexture");
InvGamma.Init(mShader, "InvGamma");
Contrast.Init(mShader, "Contrast");
Brightness.Init(mShader, "Brightness");
Scale.Init(mShader, "UVScale");
}
mShader.Bind();
}

View file

@ -3,19 +3,27 @@
#include "gl_shaderprogram.h"
class FPresentShader
class FPresentShaderBase
{
public:
void Bind();
virtual void Bind() = 0;
FBufferedUniformSampler InputTexture;
FBufferedUniform1f InvGamma;
FBufferedUniform1f Contrast;
FBufferedUniform1f Brightness;
FBufferedUniform2f Scale;
private:
protected:
virtual void Init(const char * vtx_shader_name, const char * program_name);
FShaderProgram mShader;
};
class FPresentShader : public FPresentShaderBase
{
public:
void Bind() override;
FBufferedUniformSampler InputTexture;
};
#endif

View file

@ -43,10 +43,25 @@
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
EXTERN_CVAR(Bool, fullscreen)
EXTERN_CVAR(Int, win_y) // pixel position of top of display window
EXTERN_CVAR(Int, win_x) // screen pixel position of left of display window
EXTERN_CVAR(Int, win_y) // screen pixel position of top of display window
namespace s3d {
/* static */
const CheckerInterleaved3D& CheckerInterleaved3D::getInstance(float ipd)
{
static CheckerInterleaved3D instance(ipd);
return instance;
}
/* static */
const ColumnInterleaved3D& ColumnInterleaved3D::getInstance(float ipd)
{
static ColumnInterleaved3D instance(ipd);
return instance;
}
/* static */
const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd)
{
@ -54,11 +69,7 @@ const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd)
return instance;
}
RowInterleaved3D::RowInterleaved3D(double ipdMeters)
: TopBottom3D(ipdMeters)
{}
void RowInterleaved3D::Present() const
static void prepareInterleavedPresent(FPresentStereoShaderBase& shader)
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
@ -79,27 +90,102 @@ void RowInterleaved3D::Present() const
const GL_IRECT& box = GLRenderer->mOutputLetterbox;
glViewport(box.left, box.top, box.width, box.height);
bool applyGamma = true;
shader.Bind();
shader.LeftEyeTexture.Set(0);
shader.RightEyeTexture.Set(1);
GLRenderer->mPresent3dRowShader->Bind();
GLRenderer->mPresent3dRowShader->LeftEyeTexture.Set(0);
GLRenderer->mPresent3dRowShader->RightEyeTexture.Set(1);
if (!applyGamma || GLRenderer->framebuffer->IsHWGammaActive())
if ( GLRenderer->framebuffer->IsHWGammaActive() )
{
GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f);
GLRenderer->mPresent3dRowShader->Contrast.Set(1.0f);
GLRenderer->mPresent3dRowShader->Brightness.Set(0.0f);
shader.InvGamma.Set(1.0f);
shader.Contrast.Set(1.0f);
shader.Brightness.Set(0.0f);
}
else
{
GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f / clamp<float>(Gamma, 0.1f, 4.f));
GLRenderer->mPresent3dRowShader->Contrast.Set(clamp<float>(vid_contrast, 0.1f, 3.f));
GLRenderer->mPresent3dRowShader->Brightness.Set(clamp<float>(vid_brightness, -0.8f, 0.8f));
shader.InvGamma.Set(1.0f / clamp<float>(Gamma, 0.1f, 4.f));
shader.Contrast.Set(clamp<float>(vid_contrast, 0.1f, 3.f));
shader.Brightness.Set(clamp<float>(vid_brightness, -0.8f, 0.8f));
}
GLRenderer->mPresent3dRowShader->Scale.Set(
shader.Scale.Set(
GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(),
GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight());
}
// fixme: I don't know how to get absolute window position on Mac and Linux
// fixme: I don't know how to get window border decoration size anywhere
// So for now I'll hard code the border effect on my test machine.
// Workaround for others is to fuss with vr_swap_eyes CVAR until it looks right.
// Presumably the top/left window border on my test machine has an odd number of pixels
// in the horizontal direction, and an even number in the vertical direction.
#define WINDOW_BORDER_HORIZONTAL_PARITY 1
#define WINDOW_BORDER_VERTICAL_PARITY 0
void CheckerInterleaved3D::Present() const
{
prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
int windowVOffset = 0;
int windowHOffset = 0;
#ifdef _WIN32
if (!fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
}
#endif // _WIN32
GLRenderer->mPresent3dCheckerShader->WindowPositionParity.Set(
(windowVOffset
+ windowHOffset
+ GLRenderer->mOutputLetterbox.height + 1 // +1 because of origin at bottom
) % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset
);
GLRenderer->RenderScreenQuad();
}
void s3d::CheckerInterleaved3D::AdjustViewports() const
{
// decrease the total pixel count by 2, but keep the same aspect ratio
const float sqrt2 = 1.41421356237f;
// Change size of renderbuffer, and align to screen
GLRenderer->mSceneViewport.height /= sqrt2;
GLRenderer->mSceneViewport.top /= sqrt2;
GLRenderer->mSceneViewport.width /= sqrt2;
GLRenderer->mSceneViewport.left /= sqrt2;
GLRenderer->mScreenViewport.height /= sqrt2;
GLRenderer->mScreenViewport.top /= sqrt2;
GLRenderer->mScreenViewport.width /= sqrt2;
GLRenderer->mScreenViewport.left /= sqrt2;
}
void ColumnInterleaved3D::Present() const
{
prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
int windowHOffset = 0;
#ifdef _WIN32
if (!fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
}
#endif // _WIN32
GLRenderer->mPresent3dColumnShader->WindowPositionParity.Set(windowHOffset);
GLRenderer->RenderScreenQuad();
}
void RowInterleaved3D::Present() const
{
prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
@ -108,13 +194,14 @@ void RowInterleaved3D::Present() const
#ifdef _WIN32
if (! fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR
windowVOffset = win_y;
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
}
#endif // _WIN32
GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(
windowVOffset // fixme: vary with window location
+ box.height % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset
GLRenderer->mPresent3dRowShader->WindowPositionParity.Set(
(windowVOffset
+ GLRenderer->mOutputLetterbox.height + 1 // +1 because of origin at bottom
) % 2
);
GLRenderer->RenderScreenQuad();

View file

@ -42,15 +42,30 @@
#include "gl/system/gl_system.h"
#include "gl/renderer/gl_renderstate.h"
class FPresent3DRowShader;
namespace s3d {
class CheckerInterleaved3D : public SideBySideSquished
{
public:
static const CheckerInterleaved3D& getInstance(float ipd);
CheckerInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
void Present() const override;
void AdjustViewports() const override;
};
class ColumnInterleaved3D : public SideBySideSquished
{
public:
static const ColumnInterleaved3D& getInstance(float ipd);
ColumnInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
void Present() const override;
};
class RowInterleaved3D : public TopBottom3D
{
public:
static const RowInterleaved3D& getInstance(float ipd);
RowInterleaved3D(double ipdMeters);
RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {}
void Present() const override;
};

View file

@ -107,6 +107,12 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode()
case 12:
setCurrentMode(RowInterleaved3D::getInstance(vr_ipd));
break;
case 13:
setCurrentMode(ColumnInterleaved3D::getInstance(vr_ipd));
break;
case 14:
setCurrentMode(CheckerInterleaved3D::getInstance(vr_ipd));
break;
case 0:
default:
setCurrentMode(MonoView::getInstance());

View file

@ -2707,6 +2707,8 @@ OPTVAL_SBSFULL = "Side-by-side Full";
OPTVAL_SBSNARROW = "Side-by-side Narrow";
OPTVAL_TOPBOTTOM = "Top/Bottom";
OPTVAL_ROWINTERLEAVED = "Row Interleaved";
OPTVAL_COLUMNINTERLEAVED = "Column Interleaved";
OPTVAL_CHECKERBOARD = "Checkerboard";
OPTVAL_QUADBUFFERED = "Quad-buffered";
OPTVAL_UNCHARTED2 = "Uncharted 2";
OPTVAL_HEJLDAWSON = "Hejl Dawson";

View file

@ -180,6 +180,8 @@ OptionValue VRMode
4, "$OPTVAL_SBSNARROW"
11, "$OPTVAL_TOPBOTTOM"
12, "$OPTVAL_ROWINTERLEAVED"
13, "$OPTVAL_COLUMNINTERLEAVED"
14, "$OPTVAL_CHECKERBOARD"
5, "$OPTVAL_LEFTEYE"
6, "$OPTVAL_RIGHTEYE"
7, "$OPTVAL_QUADBUFFERED"

View file

@ -0,0 +1,37 @@
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D LeftEyeTexture;
uniform sampler2D RightEyeTexture;
uniform float InvGamma;
uniform float Contrast;
uniform float Brightness;
uniform int WindowPositionParity; // top-of-window might not be top-of-screen
vec4 ApplyGamma(vec4 c)
{
vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5;
val += Brightness * 0.5;
val = pow(max(val, vec3(0.0)), vec3(InvGamma));
return vec4(val, c.a);
}
void main()
{
int thisVerticalPixel = int(gl_FragCoord.y); // Bottom row is typically the right eye, when WindowHeight is even
int thisHorizontalPixel = int(gl_FragCoord.x); // column
bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row
+ thisHorizontalPixel // and each column
+ WindowPositionParity // because the window might not be aligned to the screen
) % 2 == 0;
vec4 inputColor;
if (isLeftEye) {
inputColor = texture(LeftEyeTexture, TexCoord);
}
else {
// inputColor = vec4(0, 1, 0, 1);
inputColor = texture(RightEyeTexture, TexCoord);
}
FragColor = ApplyGamma(inputColor);
}

View file

@ -0,0 +1,35 @@
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D LeftEyeTexture;
uniform sampler2D RightEyeTexture;
uniform float InvGamma;
uniform float Contrast;
uniform float Brightness;
uniform int WindowPositionParity; // top-of-window might not be top-of-screen
vec4 ApplyGamma(vec4 c)
{
vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5;
val += Brightness * 0.5;
val = pow(max(val, vec3(0.0)), vec3(InvGamma));
return vec4(val, c.a);
}
void main()
{
int thisHorizontalPixel = int(gl_FragCoord.x); // zero-based column index from left
bool isLeftEye = (thisHorizontalPixel // because we want to alternate eye view on each column
+ WindowPositionParity // because the window might not be aligned to the screen
) % 2 == 0;
vec4 inputColor;
if (isLeftEye) {
inputColor = texture(LeftEyeTexture, TexCoord);
}
else {
// inputColor = vec4(0, 1, 0, 1);
inputColor = texture(RightEyeTexture, TexCoord);
}
FragColor = ApplyGamma(inputColor);
}

View file

@ -7,7 +7,7 @@ uniform sampler2D RightEyeTexture;
uniform float InvGamma;
uniform float Contrast;
uniform float Brightness;
uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen
uniform int WindowPositionParity; // top-of-window might not be top-of-screen
vec4 ApplyGamma(vec4 c)
{
@ -19,9 +19,9 @@ vec4 ApplyGamma(vec4 c)
void main()
{
int thisVerticalPixel = int(gl_FragCoord.y + 1.0); // Bottom row is typically the right eye, when WindowHeight is even
int thisVerticalPixel = int(gl_FragCoord.y); // Bottom row is typically the right eye, when WindowHeight is even
bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row
+ VerticalPixelOffset // because the window might not be aligned to the screen
+ WindowPositionParity // because the window might not be aligned to the screen
) % 2 == 0;
vec4 inputColor;
if (isLeftEye) {