mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-04 10:15:27 +02:00
Merge pull request #7920 from hrydgard/vshader-depth-round
Round depth values to 16-bit precision to match the PSP's 16-bit depth buffer
This commit is contained in:
commit
12884eceb9
13 files changed
+150
-21
No files matched your search
@@ -211,6 +211,7 @@ void SoftwareTransform(
|
||||
// The w of uv is also never used (hardcoded to 1.0.)
|
||||
}
|
||||
} else {
|
||||
// Okay, need to actually perform the full transform.
|
||||
for (int index = 0; index < maxIndex; index++) {
|
||||
reader.Goto(index);
|
||||
|
||||
@@ -401,6 +402,9 @@ void SoftwareTransform(
|
||||
}
|
||||
transformed[index].color0_32 = c0.ToRGBA();
|
||||
transformed[index].color1_32 = c1.ToRGBA();
|
||||
|
||||
// The multiplication by the projection matrix is still performed in the vertex shader.
|
||||
// So is vertex depth rounding, to simulate the 16-bit depth buffer.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -889,7 +889,7 @@ void DIRECTX9_GPU::Execute_ViewportType(u32 op, u32 diff) {
|
||||
switch (op >> 24) {
|
||||
case GE_CMD_VIEWPORTZ1:
|
||||
case GE_CMD_VIEWPORTZ2:
|
||||
shaderManager_->DirtyUniform(DIRTY_PROJMATRIX);
|
||||
shaderManager_->DirtyUniform(DIRTY_PROJMATRIX | DIRTY_DEPTHRANGE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,10 @@ void ShaderManagerDX9::VSSetColorUniform3(int creg, u32 color) {
|
||||
pD3Ddevice->SetVertexShaderConstantF(creg, col, 1);
|
||||
}
|
||||
|
||||
void ShaderManagerDX9::VSSetFloatUniform4(int creg, float data[4]) {
|
||||
pD3Ddevice->SetVertexShaderConstantF(creg, data, 1);
|
||||
}
|
||||
|
||||
void ShaderManagerDX9::VSSetFloat24Uniform3(int creg, const u32 data[3]) {
|
||||
const u32 col[4] = {
|
||||
data[0] >> 8, data[1] >> 8, data[2] >> 8, 0
|
||||
@@ -475,6 +479,26 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) {
|
||||
VSSetFloatArray(CONST_VS_UVSCALEOFFSET, uvscaleoff, 4);
|
||||
}
|
||||
|
||||
if (dirtyUniforms & DIRTY_DEPTHRANGE) {
|
||||
float viewZScale = gstate.getViewportZScale();
|
||||
float viewZCenter = gstate.getViewportZCenter();
|
||||
|
||||
// Adjust for D3D projection matrix. We got squashed up to only 0-1, so we multiply
|
||||
// the scale factor by 2, and add an offset.
|
||||
// Given the way we do the rounding, the integer part of the offset is probably mostly irrelevant as we cancel
|
||||
// it afterwards anyway.
|
||||
viewZScale *= 2.0f;
|
||||
viewZCenter -= 32767.5f;
|
||||
float viewZInvScale;
|
||||
if (viewZScale != 0.0) {
|
||||
viewZInvScale = 1.0f / viewZScale;
|
||||
} else {
|
||||
viewZInvScale = 0.0;
|
||||
}
|
||||
|
||||
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
|
||||
VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data);
|
||||
}
|
||||
// Lighting
|
||||
if (dirtyUniforms & DIRTY_AMBIENT) {
|
||||
VSSetColorUniform3Alpha(CONST_VS_AMBIENT, gstate.ambientcolor, gstate.getAmbientA());
|
||||
|
||||
@@ -57,6 +57,8 @@ enum {
|
||||
DIRTY_UVSCALEOFFSET = (1 << 18), // this will be dirtied ALL THE TIME... maybe we'll need to do "last value with this shader compares"
|
||||
DIRTY_TEXCLAMP = (1 << 19),
|
||||
|
||||
DIRTY_DEPTHRANGE = (1 << 20),
|
||||
|
||||
DIRTY_WORLDMATRIX = (1 << 21),
|
||||
DIRTY_VIEWMATRIX = (1 << 22), // Maybe we'll fold this into projmatrix eventually
|
||||
DIRTY_TEXMATRIX = (1 << 23),
|
||||
@@ -143,6 +145,7 @@ private:
|
||||
void VSSetFloat(int creg, float value);
|
||||
void VSSetFloatArray(int creg, const float *value, int count);
|
||||
void VSSetFloat24Uniform3(int creg, const u32 data[3]);
|
||||
void VSSetFloatUniform4(int creg, float data[4]);
|
||||
|
||||
void Clear();
|
||||
|
||||
|
||||
@@ -745,10 +745,12 @@ void TransformDrawEngineDX9::ApplyDrawState(int prim) {
|
||||
float zScale = gstate.getViewportZScale() / 65535.0f;
|
||||
float zCenter = gstate.getViewportZCenter() / 65535.0f;
|
||||
|
||||
// Note - we lose the sign of the zscale here. Although I suppose we still keep it in gstate_c.vpDepth...
|
||||
float depthRangeMin = zCenter - fabsf(zScale);
|
||||
float depthRangeMax = zCenter + fabsf(zScale);
|
||||
// Note - We lose the sign of the zscale here. But we keep it in gstate_c.vpDepth.
|
||||
// That variable is only check for sign later so the multiplication by 2 isn't really necessary.
|
||||
|
||||
// It's unclear why we need this Z offset of 1 to match OpenGL, but this checks out in multiple games.
|
||||
float depthRangeMin = zCenter - fabsf(zScale) - 0.5f/65535.0f;
|
||||
float depthRangeMax = zCenter + fabsf(zScale) - 0.5f/65535.0f;
|
||||
gstate_c.vpDepth = zScale * 2;
|
||||
|
||||
// D3D doesn't like viewports partially outside the target, so we
|
||||
|
||||
@@ -226,6 +226,11 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!gstate.isModeThrough()) {
|
||||
WRITE(p, "float4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE);
|
||||
}
|
||||
|
||||
// And the "varyings".
|
||||
if (useHWTransform) {
|
||||
WRITE(p, "struct VS_IN { \n");
|
||||
if (vertTypeIsSkinningEnabled(vertType)) {
|
||||
@@ -279,6 +284,20 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
|
||||
// Confirmed: Through mode gets through exactly the same in GL and D3D in Phantasy Star: Text is 38023.0 in the test scene.
|
||||
|
||||
if (!gstate.isModeThrough()) {
|
||||
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
||||
// Not completely sure this is 100% right under DX9 as the Z range is different...
|
||||
WRITE(p, "\nfloat4 depthRoundZVP(float4 v) {\n");
|
||||
WRITE(p, " float z = v.z / v.w;\n");
|
||||
WRITE(p, " z = z * u_depthRange.x + u_depthRange.y;\n");
|
||||
WRITE(p, " z = floor(z);\n");
|
||||
WRITE(p, " z = (z - u_depthRange.z) * u_depthRange.w;\n");
|
||||
WRITE(p, " return float4(v.x, v.y, z * v.w, v.w);\n");
|
||||
WRITE(p, "}\n\n");
|
||||
}
|
||||
|
||||
WRITE(p, "VS_OUT main(VS_IN In) {\n");
|
||||
WRITE(p, " VS_OUT Out = (VS_OUT)0; \n");
|
||||
if (!useHWTransform) {
|
||||
@@ -309,7 +328,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
if (gstate.isModeThrough()) {
|
||||
WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj_through);\n");
|
||||
} else {
|
||||
WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj);\n");
|
||||
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n");
|
||||
}
|
||||
} else {
|
||||
// Step 1: World Transform / Skinning
|
||||
@@ -398,7 +417,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
||||
WRITE(p, " float4 viewPos = float4(mul(float4(worldpos, 1.0), u_view), 1.0);\n");
|
||||
|
||||
// Final view and projection transforms.
|
||||
WRITE(p, " Out.gl_Position = mul(viewPos, u_proj);\n");
|
||||
WRITE(p, " Out.gl_Position = depthRoundZVP(mul(viewPos, u_proj));\n");
|
||||
|
||||
// TODO: Declare variables for dots for shade mapping if needed.
|
||||
|
||||
|
||||
@@ -87,5 +87,6 @@ int TranslateNumBonesDX9(int bones);
|
||||
#define CONST_VS_LIGHTDIFFUSE 71
|
||||
#define CONST_VS_LIGHTSPECULAR 75
|
||||
#define CONST_VS_LIGHTAMBIENT 79
|
||||
#define CONST_VS_DEPTHRANGE 83
|
||||
|
||||
};
|
||||
+10
-4
@@ -77,8 +77,8 @@ static const CommandTableEntry commandTable[] = {
|
||||
{GE_CMD_FOG2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, DIRTY_FOGCOEF, &GLES_GPU::Execute_FogCoef},
|
||||
|
||||
// Should these maybe flush?
|
||||
{GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE},
|
||||
{GE_CMD_MAXZ, FLAG_FLUSHBEFOREONCHANGE},
|
||||
{GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE},
|
||||
{GE_CMD_MAXZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE},
|
||||
|
||||
// Changes that dirty texture scaling.
|
||||
{GE_CMD_TEXMAPMODE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, DIRTY_UVSCALEOFFSET, &GLES_GPU::Execute_TexMapMode},
|
||||
@@ -206,8 +206,8 @@ static const CommandTableEntry commandTable[] = {
|
||||
{GE_CMD_VIEWPORTY1, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GLES_GPU::Execute_ViewportType},
|
||||
{GE_CMD_VIEWPORTX2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GLES_GPU::Execute_ViewportType},
|
||||
{GE_CMD_VIEWPORTY2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GLES_GPU::Execute_ViewportType},
|
||||
{GE_CMD_VIEWPORTZ1, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GLES_GPU::Execute_ViewportType},
|
||||
{GE_CMD_VIEWPORTZ2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GLES_GPU::Execute_ViewportType},
|
||||
{GE_CMD_VIEWPORTZ1, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, DIRTY_DEPTHRANGE, &GLES_GPU::Execute_ViewportZType},
|
||||
{GE_CMD_VIEWPORTZ2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, DIRTY_DEPTHRANGE, &GLES_GPU::Execute_ViewportZType},
|
||||
|
||||
// Region
|
||||
{GE_CMD_REGION1, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GLES_GPU::Execute_Region},
|
||||
@@ -1014,6 +1014,12 @@ void GLES_GPU::Execute_ViewportType(u32 op, u32 diff) {
|
||||
gstate_c.textureChanged |= TEXCHANGE_PARAMSONLY;
|
||||
}
|
||||
|
||||
void GLES_GPU::Execute_ViewportZType(u32 op, u32 diff) {
|
||||
gstate_c.framebufChanged = true;
|
||||
gstate_c.textureChanged |= TEXCHANGE_PARAMSONLY;
|
||||
shaderManager_->DirtyUniform(DIRTY_DEPTHRANGE);
|
||||
}
|
||||
|
||||
void GLES_GPU::Execute_TexScaleU(u32 op, u32 diff) {
|
||||
gstate_c.uv.uScale = getFloat24(op);
|
||||
shaderManager_->DirtyUniform(DIRTY_UVSCALEOFFSET);
|
||||
|
||||
@@ -101,6 +101,7 @@ public:
|
||||
void Execute_Scissor(u32 op, u32 diff);
|
||||
void Execute_FramebufType(u32 op, u32 diff);
|
||||
void Execute_ViewportType(u32 op, u32 diff);
|
||||
void Execute_ViewportZType(u32 op, u32 diff);
|
||||
void Execute_TexScaleU(u32 op, u32 diff);
|
||||
void Execute_TexScaleV(u32 op, u32 diff);
|
||||
void Execute_TexOffsetU(u32 op, u32 diff);
|
||||
|
||||
@@ -167,6 +167,7 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTrans
|
||||
numBones = TranslateNumBones(vertTypeGetNumBoneWeights(vertType));
|
||||
else
|
||||
numBones = 0;
|
||||
u_depthRange = glGetUniformLocation(program, "u_depthRange");
|
||||
|
||||
#ifdef USE_BONE_ARRAY
|
||||
u_bone = glGetUniformLocation(program, "u_bone");
|
||||
@@ -233,6 +234,8 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTrans
|
||||
if (u_texmtx != -1) availableUniforms |= DIRTY_TEXMATRIX;
|
||||
if (u_stencilReplaceValue != -1) availableUniforms |= DIRTY_STENCILREPLACEVALUE;
|
||||
if (u_blendFixA != -1 || u_blendFixB != -1 || u_fbotexSize != -1) availableUniforms |= DIRTY_SHADERBLEND;
|
||||
if (u_depthRange != -1)
|
||||
availableUniforms |= DIRTY_DEPTHRANGE;
|
||||
|
||||
// Looping up to numBones lets us avoid checking u_bone[i]
|
||||
#ifdef USE_BONE_ARRAY
|
||||
@@ -343,6 +346,10 @@ static void SetFloat24Uniform3(int uniform, const u32 data[3]) {
|
||||
glUniform3fv(uniform, 1, (const GLfloat *)&col[0]);
|
||||
}
|
||||
|
||||
static void SetFloatUniform4(int uniform, float data[4]) {
|
||||
glUniform4fv(uniform, 1, data);
|
||||
}
|
||||
|
||||
static void SetMatrix4x3(int uniform, const float *m4x3) {
|
||||
float m4x4[16];
|
||||
ConvertMatrix4x3To4x4(m4x4, m4x3);
|
||||
@@ -442,7 +449,7 @@ void LinkedShader::UpdateUniforms(u32 vertType) {
|
||||
if (dirty & DIRTY_PROJTHROUGHMATRIX)
|
||||
{
|
||||
Matrix4x4 proj_through;
|
||||
proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1);
|
||||
proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0.0f, 1.0f);
|
||||
glUniformMatrix4fv(u_proj_through, 1, GL_FALSE, proj_through.getReadPtr());
|
||||
}
|
||||
if (dirty & DIRTY_TEXENV) {
|
||||
@@ -547,7 +554,7 @@ void LinkedShader::UpdateUniforms(u32 vertType) {
|
||||
glUniform4fv(u_uvscaleoffset, 1, uvscaleoff);
|
||||
}
|
||||
|
||||
if (dirty & DIRTY_TEXCLAMP) {
|
||||
if ((dirty & DIRTY_TEXCLAMP) && u_texclamp != -1) {
|
||||
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
|
||||
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
|
||||
const int w = gstate.getTextureWidth(0);
|
||||
@@ -582,6 +589,18 @@ void LinkedShader::UpdateUniforms(u32 vertType) {
|
||||
if (dirty & DIRTY_TEXMATRIX) {
|
||||
SetMatrix4x3(u_texmtx, gstate.tgenMatrix);
|
||||
}
|
||||
if ((dirty & DIRTY_DEPTHRANGE) && u_depthRange != -1) {
|
||||
float viewZScale = gstate.getViewportZScale();
|
||||
float viewZCenter = gstate.getViewportZCenter();
|
||||
float viewZInvScale;
|
||||
if (viewZScale != 0.0) {
|
||||
viewZInvScale = 1.0f / viewZScale;
|
||||
} else {
|
||||
viewZInvScale = 0.0;
|
||||
}
|
||||
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
|
||||
SetFloatUniform4(u_depthRange, data);
|
||||
}
|
||||
|
||||
if (dirty & DIRTY_STENCILREPLACEVALUE) {
|
||||
glUniform1f(u_stencilReplaceValue, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));
|
||||
|
||||
@@ -88,6 +88,8 @@ public:
|
||||
int u_view;
|
||||
int u_texmtx;
|
||||
int u_world;
|
||||
int u_depthRange; // x,y = viewport xscale/xcenter. z,w=clipping minz/maxz (?)
|
||||
|
||||
#ifdef USE_BONE_ARRAY
|
||||
int u_bone; // array, size is numBones
|
||||
#else
|
||||
@@ -132,10 +134,10 @@ public:
|
||||
enum {
|
||||
DIRTY_PROJMATRIX = (1 << 0),
|
||||
DIRTY_PROJTHROUGHMATRIX = (1 << 1),
|
||||
DIRTY_FOGCOLOR = (1 << 2),
|
||||
DIRTY_FOGCOEF = (1 << 3),
|
||||
DIRTY_TEXENV = (1 << 4),
|
||||
DIRTY_ALPHACOLORREF = (1 << 5),
|
||||
DIRTY_FOGCOLOR = (1 << 2),
|
||||
DIRTY_FOGCOEF = (1 << 3),
|
||||
DIRTY_TEXENV = (1 << 4),
|
||||
DIRTY_ALPHACOLORREF = (1 << 5),
|
||||
|
||||
// 1 << 6 is free! Wait, not anymore...
|
||||
DIRTY_STENCILREPLACEVALUE = (1 << 6),
|
||||
@@ -155,7 +157,10 @@ enum {
|
||||
DIRTY_SHADERBLEND = (1 << 17), // Used only for in-shader blending.
|
||||
|
||||
DIRTY_UVSCALEOFFSET = (1 << 18), // this will be dirtied ALL THE TIME... maybe we'll need to do "last value with this shader compares"
|
||||
|
||||
// Texclamp is fairly rare so let's share it's bit with DIRTY_DEPTHRANGE.
|
||||
DIRTY_TEXCLAMP = (1 << 19),
|
||||
DIRTY_DEPTHRANGE = (1 << 19),
|
||||
|
||||
DIRTY_WORLDMATRIX = (1 << 21),
|
||||
DIRTY_VIEWMATRIX = (1 << 22), // Maybe we'll fold this into projmatrix eventually
|
||||
|
||||
@@ -871,11 +871,11 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
|
||||
|
||||
glstate.viewport.set(left, bottom, right - left, top - bottom);
|
||||
|
||||
float zScale = gstate.getViewportZScale() * (1.0f / 65535.0f);
|
||||
float zCenter = gstate.getViewportZCenter() * (1.0f / 65535.0f);
|
||||
float zScale = gstate.getViewportZScale();
|
||||
float zCenter = gstate.getViewportZCenter();
|
||||
float depthRangeMin = zCenter - zScale;
|
||||
float depthRangeMax = zCenter + zScale;
|
||||
glstate.depthRange.set(depthRangeMin, depthRangeMax);
|
||||
glstate.depthRange.set(depthRangeMin * (1.0f / 65535.0f), depthRangeMax * (1.0f / 65535.0f));
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
float minz = gstate.getDepthRangeMin() * (1.0f / 65535.0f);
|
||||
|
||||
@@ -152,6 +152,33 @@ enum DoLightComputation {
|
||||
LIGHT_FULL,
|
||||
};
|
||||
|
||||
|
||||
// Depth range and viewport
|
||||
//
|
||||
// After the multiplication with the projection matrix, we have a 4D vector in clip space.
|
||||
// In OpenGL, Z is from -1 to 1, while in D3D, Z is from 0 to 1.
|
||||
// PSP appears to use the OpenGL convention. As Z is from -1 to 1, and the viewport is represented
|
||||
// by a center and a scale, to find the final Z value, all we need to do is to multiply by ZScale and
|
||||
// add ZCenter - these are properly scaled to directly give a Z value in [0, 65535].
|
||||
//
|
||||
// z = vec.z * ViewportZScale + ViewportZCenter;
|
||||
//
|
||||
// That will give us the final value between 0 and 65535, which we can simply floor to simulate
|
||||
// the limited precision of the PSP's depth buffer. Then we convert it back:
|
||||
// z = floor(z);
|
||||
//
|
||||
// vec.z = (z - ViewportZCenter) / ViewportZScale;
|
||||
//
|
||||
// Now, the regular machinery will take over and do the calculation again.
|
||||
//
|
||||
// All this above is for full transform mode.
|
||||
// In through mode, the Z coordinate just goes straight through and there is no perspective division.
|
||||
// We simulate this of course with pretty much an identity matrix. Rounding Z becomes very easy.
|
||||
//
|
||||
// TODO: Skip all this if we can actually get a 16-bit depth buffer along with stencil, which
|
||||
// is a bit of a rare configuration, although quite common on mobile.
|
||||
|
||||
|
||||
void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransform) {
|
||||
char *p = buffer;
|
||||
|
||||
@@ -214,6 +241,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||
boneWeightDecl = boneWeightInDecl;
|
||||
}
|
||||
|
||||
|
||||
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !gstate.isModeThrough();
|
||||
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
|
||||
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
|
||||
@@ -336,6 +364,10 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
|
||||
}
|
||||
|
||||
if (!gstate.isModeThrough()) {
|
||||
WRITE(p, "uniform highp vec4 u_depthRange;\n");
|
||||
}
|
||||
|
||||
WRITE(p, "%s %s lowp vec4 v_color0;\n", shading, varying);
|
||||
if (lmode) {
|
||||
WRITE(p, "%s %s lowp vec3 v_color1;\n", shading, varying);
|
||||
@@ -357,6 +389,18 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||
}
|
||||
}
|
||||
|
||||
// See comment above this function (GenerateVertexShader).
|
||||
if (!gstate.isModeThrough()) {
|
||||
// Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection.
|
||||
WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n");
|
||||
WRITE(p, " float z = v.z / v.w;\n");
|
||||
WRITE(p, " z = z * u_depthRange.x + u_depthRange.y;\n");
|
||||
WRITE(p, " z = floor(z);\n");
|
||||
WRITE(p, " z = (z - u_depthRange.z) * u_depthRange.w;\n");
|
||||
WRITE(p, " return vec4(v.x, v.y, z * v.w, v.w);\n");
|
||||
WRITE(p, "}\n\n");
|
||||
}
|
||||
|
||||
WRITE(p, "void main() {\n");
|
||||
|
||||
if (!useHWTransform) {
|
||||
@@ -383,7 +427,8 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||
if (gstate.isModeThrough()) {
|
||||
WRITE(p, " gl_Position = u_proj_through * vec4(position.xyz, 1.0);\n");
|
||||
} else {
|
||||
WRITE(p, " gl_Position = u_proj * vec4(position.xyz, 1.0);\n");
|
||||
// The viewport is used in this case, so need to compensate for that.
|
||||
WRITE(p, " gl_Position = depthRoundZVP(u_proj * vec4(position.xyz, 1.0));\n");
|
||||
}
|
||||
} else {
|
||||
// Step 1: World Transform / Skinning
|
||||
@@ -476,7 +521,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
|
||||
WRITE(p, " vec4 viewPos = u_view * vec4(worldpos, 1.0);\n");
|
||||
|
||||
// Final view and projection transforms.
|
||||
WRITE(p, " gl_Position = u_proj * viewPos;\n");
|
||||
WRITE(p, " gl_Position = depthRoundZVP(u_proj * viewPos);\n");
|
||||
|
||||
// TODO: Declare variables for dots for shade mapping if needed.
|
||||
|
||||
|
||||
Reference in new issue
Block a user