More D3D hackery: Take inverted Z in proj matrix into account.

Also, *2 breaks it for no good reason so don't do that.
This commit is contained in:
Henrik Rydgard 2015-08-30 22:43:44 +02:00
parent 9bf5d40084
commit 08b340f423
3 changed files with 15 additions and 11 deletions

View File

@ -483,11 +483,15 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) {
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;
// It seems that we should adjust for D3D projection matrix. We got squashed up to only 0-1, so we divide
// the scale factor by 2, and add an offset. But, this doesn't work! I get near-perfect results not doing it.
// viewZScale *= 2.0f;
// Need to take the possibly inverted proj matrix into account.
if (gstate_c.vpDepth < 0.0)
viewZScale *= -1.0f;
viewZCenter -= 32767.5f;
float viewZInvScale;
if (viewZScale != 0.0) {

View File

@ -742,16 +742,16 @@ void TransformDrawEngineDX9::ApplyDrawState(int prim) {
vpWidth *= renderWidthFactor;
vpHeight *= renderHeightFactor;
float zScale = gstate.getViewportZScale() / 65535.0f;
float zCenter = gstate.getViewportZCenter() / 65535.0f;
float zScale = gstate.getViewportZScale();
float zCenter = gstate.getViewportZCenter();
// 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;
// It's unclear why we need this Z offset to match OpenGL, but this checks out in multiple games.
float depthRangeMin = (zCenter - fabsf(zScale)) * (1.0f / 65535.0f);
float depthRangeMax = (zCenter + fabsf(zScale)) * (1.0f / 65535.0f);
gstate_c.vpDepth = zScale * (2.0f / 65335.0f);
// D3D doesn't like viewports partially outside the target, so we
// apply the viewport partially in the shader.

View File

@ -288,10 +288,10 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
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...
// The Z range in D3D is different but we compensate for that using parameters.
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 = (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");