Adjust D3D depth calculations to get them to match OpenGL as close as I can get it.

This commit is contained in:
Henrik Rydgard 2015-08-29 17:43:09 +02:00
parent 76eacf32f4
commit 7b0a31ade5
4 changed files with 19 additions and 9 deletions

View File

@ -482,14 +482,21 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) {
if (dirtyUniforms & DIRTY_DEPTHRANGE) {
float viewZScale = gstate.getViewportZScale();
float viewZCenter = gstate.getViewportZCenter();
float viewZCenterClean = 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 offset is probably mostly irrelevant as we cancel
// it afterwards anyway.
viewZScale *= 2.0f;
viewZCenter -= 32768.0f;
float viewZInvScale;
if (viewZScale != 0.0) {
viewZInvScale = 1.0f / gstate.getViewportZScale();
viewZInvScale = 1.0f / viewZScale;
} else {
viewZInvScale = 0.0;
}
float data[4] = { viewZScale, viewZCenter, viewZCenterClean, viewZInvScale };
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data);
}
// Lighting

View File

@ -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) - 1.0f/65535.0f;
float depthRangeMax = zCenter + fabsf(zScale) - 1.0f/65535.0f;
gstate_c.vpDepth = zScale * 2;
// D3D doesn't like viewports partially outside the target, so we

View File

@ -284,6 +284,8 @@ 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...

View File

@ -592,14 +592,13 @@ void LinkedShader::UpdateUniforms(u32 vertType) {
if ((dirty & DIRTY_DEPTHRANGE) && u_depthRange != -1) {
float viewZScale = gstate.getViewportZScale();
float viewZCenter = gstate.getViewportZCenter();
float viewZCenterClean = gstate.getViewportZCenter();
float viewZInvScale;
if (viewZScale != 0.0) {
viewZInvScale = 1.0f / gstate.getViewportZScale();
viewZInvScale = 1.0f / viewZScale;
} else {
viewZInvScale = 0.0;
}
float data[4] = { viewZScale, viewZCenter, viewZCenterClean, viewZInvScale };
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
SetFloatUniform4(u_depthRange, data);
}