Use minz/maxz as the depth range.
This allows values that fall outside the viewport, but still within the depth range, to be drawn.
This commit is contained in:
parent
b28402337c
commit
0920f6c6eb
3 changed files with 26 additions and 65 deletions
|
@ -597,8 +597,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
|||
float xOffset = 0.0f;
|
||||
float hScale = 1.0f;
|
||||
float yOffset = 0.0f;
|
||||
float zScale = 1.0f;
|
||||
float zOffset = 0.0f;
|
||||
|
||||
// If we're within the bounds, we want clipping the viewport way. So leave it be.
|
||||
if (left < 0.0f || right > renderWidth) {
|
||||
|
@ -632,29 +630,22 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
|||
out.viewportW = right - left;
|
||||
out.viewportH = bottom - top;
|
||||
|
||||
// The depth viewport parameters are the same, but we handle it a bit differently.
|
||||
// When clipping is enabled, depth is clamped to [0, 65535]. And minz/maxz discard.
|
||||
// So, we apply the depth range as minz/maxz, and transform for the viewport.
|
||||
float vpZScale = gstate.getViewportZScale();
|
||||
float vpZCenter = gstate.getViewportZCenter();
|
||||
// Near/far can be inverted. We deal with that in the projection/scale.
|
||||
float near = vpZCenter - fabsf(vpZScale);
|
||||
float far = vpZCenter + fabsf(vpZScale);
|
||||
float minz = gstate.getDepthRangeMin();
|
||||
float maxz = gstate.getDepthRangeMax();
|
||||
|
||||
if (near < 0.0f || far > 65535.0f) {
|
||||
float overageNear = std::max(-near, 0.0f);
|
||||
float overageFar = std::max(far - 65535.0f, 0.0f);
|
||||
float drift = overageFar - overageNear;
|
||||
// Okay. So, in our shader, -1 will map to minz, and +1 will map to maxz.
|
||||
float halfActualZRange = (maxz - minz) * (1.0f / 2.0f);
|
||||
float zScale = vpZScale / halfActualZRange;
|
||||
// This adjusts the center from halfActualZRange to vpZCenter.
|
||||
float zOffset = (vpZCenter - (minz + halfActualZRange)) / halfActualZRange;
|
||||
|
||||
near += overageNear;
|
||||
far -= overageFar;
|
||||
|
||||
zScale = (vpZScale * 2.0f) / (far - near);
|
||||
zOffset = drift / (far - near);
|
||||
} else if (vpZScale < 0.0f) {
|
||||
// This flips to match our near/far.
|
||||
zScale = -zScale;
|
||||
}
|
||||
|
||||
out.depthRangeMin = near * (1.0f / 65535.0f);
|
||||
out.depthRangeMax = far * (1.0f / 65535.0f);
|
||||
out.depthRangeMin = ToScaledDepth(minz);
|
||||
out.depthRangeMax = ToScaledDepth(maxz);
|
||||
|
||||
bool scaleChanged = gstate_c.vpWidthScale != wScale || gstate_c.vpHeightScale != hScale;
|
||||
bool offsetChanged = gstate_c.vpXOffset != xOffset || gstate_c.vpYOffset != yOffset;
|
||||
|
@ -669,18 +660,6 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
|||
out.dirtyProj = true;
|
||||
out.dirtyDepth = depthChanged;
|
||||
}
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
float minz = gstate.getDepthRangeMin();
|
||||
float maxz = gstate.getDepthRangeMax();
|
||||
if (minz > near || maxz < far) {
|
||||
if ((gstate.clipEnable & 1) == 0) {
|
||||
WARN_LOG_REPORT_ONCE(minmaxznoclip, G3D, "Unsupported depth range test without clipping - clip: %f-%f, test: %f-%f", near, far, minz, maxz);
|
||||
} else {
|
||||
WARN_LOG_REPORT_ONCE(minmaxz, G3D, "Unsupported depth range test - clip: %f-%f, test: %f-%f", near, far, minz, maxz);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -480,23 +480,14 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) {
|
|||
}
|
||||
|
||||
if (dirtyUniforms & DIRTY_DEPTHRANGE) {
|
||||
float viewZScale = gstate.getViewportZScale();
|
||||
float viewZCenter = gstate.getViewportZCenter();
|
||||
float viewZInvScale;
|
||||
// Depth is [0, 1] mapping to [minz, maxz], not too hard.
|
||||
float minz = gstate.getDepthRangeMin();
|
||||
float maxz = gstate.getDepthRangeMax();
|
||||
|
||||
// We had to scale and translate Z to account for our clamped Z range.
|
||||
// Therefore, we also need to reverse this to round properly.
|
||||
//
|
||||
// Example: scale = 65535.0, center = 0.0
|
||||
// Resulting range = -65535 to 65535, clamped to [0, 65535]
|
||||
// gstate_c.vpDepthScale = 2.0f
|
||||
// gstate_c.vpZOffset = -1.0f
|
||||
//
|
||||
// The projection already accounts for those, so we need to reverse them.
|
||||
//
|
||||
// Additionally, D3D9 uses a range from [0, 1]. We double and move the center.
|
||||
viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f;
|
||||
viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f;
|
||||
float actualZRange = maxz - minz;
|
||||
float viewZScale = actualZRange;
|
||||
float viewZCenter = minz;
|
||||
float viewZInvScale;
|
||||
|
||||
if (viewZScale != 0.0) {
|
||||
viewZInvScale = 1.0f / viewZScale;
|
||||
|
|
|
@ -589,23 +589,14 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) {
|
|||
SetMatrix4x3(u_texmtx, gstate.tgenMatrix);
|
||||
}
|
||||
if ((dirty & DIRTY_DEPTHRANGE) && u_depthRange != -1) {
|
||||
float viewZScale = gstate.getViewportZScale();
|
||||
float viewZCenter = gstate.getViewportZCenter();
|
||||
float viewZInvScale;
|
||||
// Since depth is [-1, 1] mapping to [minz, maxz], this is easy.
|
||||
float minz = gstate.getDepthRangeMin();
|
||||
float maxz = gstate.getDepthRangeMax();
|
||||
|
||||
// We had to scale and translate Z to account for our clamped Z range.
|
||||
// Therefore, we also need to reverse this to round properly.
|
||||
//
|
||||
// Example: scale = 65535.0, center = 0.0
|
||||
// Resulting range = -65535 to 65535, clamped to [0, 65535]
|
||||
// gstate_c.vpDepthScale = 2.0f
|
||||
// gstate_c.vpZOffset = -1.0f
|
||||
//
|
||||
// The projection already accounts for those, so we need to reverse them.
|
||||
//
|
||||
// Additionally, OpenGL uses a range from [-1, 1]. So we multiply by scale and add the center.
|
||||
viewZScale *= 1.0f / gstate_c.vpDepthScale;
|
||||
viewZCenter -= 65535.0f * gstate_c.vpZOffset;
|
||||
float halfActualZRange = (maxz - minz) * (1.0f / 2.0f);
|
||||
float viewZScale = halfActualZRange;
|
||||
float viewZCenter = minz + halfActualZRange;
|
||||
float viewZInvScale;
|
||||
|
||||
if (viewZScale != 0.0) {
|
||||
viewZInvScale = 1.0f / viewZScale;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue