From 9f66fcaac74e673ea637bbb51e0bbd3b565c8564 Mon Sep 17 00:00:00 2001 From: gm-matthew <108370479+gm-matthew@users.noreply.github.com> Date: Fri, 22 Dec 2023 02:00:47 +0000 Subject: [PATCH 1/2] Floating point reversed z-buffer and new clipping code Also always draw nodes with culling disabled even if they test as being outside the visible frustum --- Src/Graphics/New3D/Mat4.cpp | 22 +- Src/Graphics/New3D/Mat4.h | 4 +- Src/Graphics/New3D/New3D.cpp | 404 ++++-------------------- Src/Graphics/New3D/New3D.h | 37 +-- Src/Graphics/New3D/R3DFrameBuffers.cpp | 4 +- Src/Graphics/New3D/R3DShaderQuads.h | 7 +- Src/Graphics/New3D/R3DShaderTriangles.h | 12 +- 7 files changed, 94 insertions(+), 396 deletions(-) diff --git a/Src/Graphics/New3D/Mat4.cpp b/Src/Graphics/New3D/Mat4.cpp index 5021552..2181cd7 100644 --- a/Src/Graphics/New3D/Mat4.cpp +++ b/Src/Graphics/New3D/Mat4.cpp @@ -149,14 +149,12 @@ void Mat4::Rotate(float angle, float x, float y, float z) Mat4::MultiMatrices(currentMatrix, m, currentMatrix); } -void Mat4::Frustum(float left, float right, float bottom, float top, float nearVal, float farVal) +void Mat4::Frustum(float left, float right, float bottom, float top, float nearVal) { - float x = (2.0F*nearVal) / (right - left); - float y = (2.0F*nearVal) / (top - bottom); + float x = 2.0F / (right - left); + float y = 2.0F / (top - bottom); float a = (right + left) / (right - left); float b = (top + bottom) / (top - bottom); - float c = -(farVal + nearVal) / (farVal - nearVal); - float d = -(2.0F*farVal*nearVal) / (farVal - nearVal); float m[16]; m[0] = x; @@ -171,30 +169,30 @@ void Mat4::Frustum(float left, float right, float bottom, float top, float nearV m[8] = a; m[9] = b; - m[10] = c; + m[10] = 0.f; m[11] = -1.f; m[12] = 0.f; m[13] = 0.f; - m[14] = d; + m[14] = nearVal; m[15] = 0.f; Mat4::MultiMatrices(currentMatrix, m, currentMatrix); } -void Mat4::Perspective(float fovy, float aspect, float zNear, float zFar) +void Mat4::Perspective(float fovy, float aspect, float zNear) { - float ymax = zNear * tanf(fovy * (float)(M_PI / 360.0)); + float ymax = tanf(fovy * (float)(M_PI / 360.0)); float xmax = ymax * aspect; - Frustum(-xmax, xmax, -ymax, ymax, zNear, zFar); + Frustum(-xmax, xmax, -ymax, ymax, zNear); } void Mat4::Ortho(float left, float right, float bottom, float top, float nearVal, float farVal) { float tx = -(right + left) / (right - left); float ty = -(top + bottom) / (top - bottom); - float tz = -(farVal + nearVal) / (farVal - nearVal); + float tz = (farVal + nearVal - 1.f) / (farVal - nearVal); float m[16]; m[0] = 2.f/(right-left); @@ -209,7 +207,7 @@ void Mat4::Ortho(float left, float right, float bottom, float top, float nearVal m[8] = 0.f; m[9] = 0.f; - m[10] = -2.f/(farVal-nearVal); + m[10] = 1.f/(farVal-nearVal); m[11] = 0.f; m[12] = tx; diff --git a/Src/Graphics/New3D/Mat4.h b/Src/Graphics/New3D/Mat4.h index 288d8fe..f8f6702 100644 --- a/Src/Graphics/New3D/Mat4.h +++ b/Src/Graphics/New3D/Mat4.h @@ -15,8 +15,8 @@ public: void Translate (float x, float y, float z); void Rotate (float angle, float x, float y, float z); void Scale (float x, float y, float z); - void Frustum (float left, float right, float bottom, float top, float nearVal, float farVal); - void Perspective (float fovy, float aspect, float zNear, float zFar); + void Frustum (float left, float right, float bottom, float top, float nearVal); + void Perspective (float fovy, float aspect, float zNear); void Ortho (float left, float right, float bottom, float top, float nearVal, float farVal); void MultMatrix (const float *m); void LoadMatrix (const float *m); diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index 020ae47..40c2b72 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -13,6 +13,8 @@ #define BYTE_TO_FLOAT(B) ((2.0f * (B) + 1.0f) * (float)(1.0/255.0)) +#define NEAR_PLANE 1e-3f + namespace New3D { CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName) : @@ -267,7 +269,7 @@ bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer) continue; } - CalcViewport(&n.viewport, std::abs(m_nfPairs[priority].zNear*0.96f), std::abs(m_nfPairs[priority].zFar*1.05f)); // make planes 5% bigger + CalcViewport(&n.viewport); glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); m_r3dShader.SetViewportUniforms(&n.viewport); @@ -323,7 +325,7 @@ void CNew3D::SetRenderStates() m_r3dShader.SetShader(true); - glDepthFunc (GL_LEQUAL); + glDepthFunc (GL_GEQUAL); glEnable (GL_DEPTH_TEST); glDepthMask (GL_TRUE); glActiveTexture (GL_TEXTURE0); @@ -348,11 +350,6 @@ void CNew3D::DisableRenderStates() void CNew3D::RenderFrame(void) { - for (int i = 0; i < 4; i++) { - m_nfPairs[i].zNear = -std::numeric_limits::max(); - m_nfPairs[i].zFar = std::numeric_limits::max(); - } - { std::lock_guard guard(m_losMutex); std::swap(m_losBack, m_losFront); @@ -411,6 +408,7 @@ void CNew3D::RenderFrame(void) m_r3dFrameBuffers.SetFBO(Layer::colour); + glClearDepth(0.0); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); m_r3dShader.DiscardAlpha(true); @@ -421,7 +419,7 @@ void CNew3D::RenderFrame(void) ProcessLos(pri); } - glDepthFunc(GL_LESS); + glDepthFunc(GL_GREATER); m_r3dShader.DiscardAlpha(false); @@ -537,10 +535,6 @@ bool CNew3D::DrawModel(UINT32 modelAddr) CacheModel(m, modelAddress); } - if (m_nodeAttribs.currentClipStatus != Clip::INSIDE) { - ClipModel(m); // not storing clipped values, only working out the Z range - } - return true; } @@ -605,7 +599,6 @@ void CNew3D::DescendCullingNode(UINT32 addr) const UINT32 *node, *lodPtr; UINT32 matrixOffset, child1Ptr, sibling2Ptr; - BBox bbox; UINT16 uCullRadius; float fCullRadius; UINT16 uBlendRadius; @@ -679,10 +672,10 @@ void CNew3D::DescendCullingNode(UINT32 addr) // apply translation vector if (node[0x00] & 0x10) { - float x = Util::Uint32AsFloat(node[0x04 - m_offset]); - float y = Util::Uint32AsFloat(node[0x05 - m_offset]); - float z = Util::Uint32AsFloat(node[0x06 - m_offset]); - m_modelMat.Translate(x, y, z); + float centroid_x = Util::Uint32AsFloat(node[0x04 - m_offset]); + float centroid_y = Util::Uint32AsFloat(node[0x05 - m_offset]); + float centroid_z = Util::Uint32AsFloat(node[0x06 - m_offset]); + m_modelMat.Translate(centroid_x, centroid_y, centroid_z); } // multiply matrix, if specified else if (matrixOffset) { @@ -693,42 +686,29 @@ void CNew3D::DescendCullingNode(UINT32 addr) ResetMatrix(m_modelMat); } + float& x = m_modelMat.currentMatrix[12]; + float& y = m_modelMat.currentMatrix[13]; + float& z = m_modelMat.currentMatrix[14]; + uCullRadius = node[9 - m_offset] & 0xFFFF; - fCullRadius = R3DFloat::GetFloat16(uCullRadius); + fCullRadius = R3DFloat::GetFloat16(uCullRadius) * m_nodeAttribs.currentModelScale;; uBlendRadius = node[9 - m_offset] >> 16; - fBlendRadius = R3DFloat::GetFloat16(uBlendRadius); + fBlendRadius = R3DFloat::GetFloat16(uBlendRadius) * m_nodeAttribs.currentModelScale;; - if (m_nodeAttribs.currentClipStatus != Clip::INSIDE) { - - if (uCullRadius != R3DFloat::Pro16BitMax) { - - CalcBox(fCullRadius, bbox); - TransformBox(m_modelMat, bbox); - - m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes); - - if (m_nodeAttribs.currentClipStatus == Clip::INSIDE) { - CalcBoxExtents(bbox); - } - } - else { - m_nodeAttribs.currentClipStatus = Clip::NOT_SET; - } + bool outsideFrustum = false; + if ((z * m_planes.bnlu - x * m_planes.bnlv * m_planes.correction) > fCullRadius || + (z * m_planes.bntu + y * m_planes.bntw) > fCullRadius || + (z * m_planes.bnru - x * m_planes.bnrv * m_planes.correction) > fCullRadius || + (z * m_planes.bnbu + y * m_planes.bnbw) > fCullRadius) + { + outsideFrustum = true; } - float LODscale; - if (m_nodeAttribs.currentDisableCulling) { - LODscale = std::numeric_limits::max(); - } - else { - float distance = std::hypot(m_modelMat.currentMatrix[12], m_modelMat.currentMatrix[13], m_modelMat.currentMatrix[14]); - LODscale = fBlendRadius * m_nodeAttribs.currentModelScale / distance; - } + float LODscale = m_nodeAttribs.currentDisableCulling ? std::numeric_limits::max() : (fBlendRadius / std::hypot(x, y, z)); + const LOD *lod = m_LODBlendTable->table[lodTablePointer].lod; - const LODFeatureType& lodTableEntry = m_LODBlendTable->table[lodTablePointer]; - - if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && LODscale >= lodTableEntry.lod[3].deleteSize) { + if (m_nodeAttribs.currentDisableCulling || (!outsideFrustum && LODscale >= lod[3].deleteSize)) { // Descend down first link if ((node[0x00] & 0x08)) // 4-element LOD table @@ -740,17 +720,17 @@ void CNew3D::DescendCullingNode(UINT32 addr) int modelLOD; for (modelLOD = 0; modelLOD < 3; modelLOD++) { - if (LODscale >= lodTableEntry.lod[modelLOD].deleteSize && lodPtr[modelLOD] & 0x1000000) + if (LODscale >= lod[modelLOD].deleteSize && lodPtr[modelLOD] & 0x1000000) break; } float tempAlpha = m_nodeAttribs.currentModelAlpha; - float nodeAlpha = lodTableEntry.lod[modelLOD].blendFactor * (LODscale - lodTableEntry.lod[modelLOD].deleteSize); + float nodeAlpha = lod[modelLOD].blendFactor * (LODscale - lod[modelLOD].deleteSize); nodeAlpha = std::clamp(nodeAlpha, 0.0f, 1.0f); - if (nodeAlpha > 15.0f / 16.0f) // shader discards pixels below 1/16 alpha + if (nodeAlpha > 31.0f / 32.0f) // shader discards pixels below 1/32 alpha nodeAlpha = 1.0f; - else if (nodeAlpha < 1.0f / 16.0f) + else if (nodeAlpha < 1.0f / 32.0f) nodeAlpha = 0.0f; m_nodeAttribs.currentModelAlpha *= nodeAlpha; // alpha of each node multiples by the alpha of its parent @@ -776,7 +756,7 @@ void CNew3D::DescendCullingNode(UINT32 addr) } else { - float nodeAlpha = lodTableEntry.lod[3].blendFactor * (LODscale - lodTableEntry.lod[3].deleteSize); + float nodeAlpha = lod[3].blendFactor * (LODscale - lod[3].deleteSize); nodeAlpha = std::clamp(nodeAlpha, 0.0f, 1.0f); m_nodeAttribs.currentModelAlpha *= nodeAlpha; // alpha of each node multiples by the alpha of its parent @@ -1015,28 +995,27 @@ void CNew3D::RenderViewport(UINT32 addr) m_LODBlendTable = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17] & 0xFFFFFF); - /* - vp->angle_left = -atan2f(Util::Uint32AsFloat(vpnode[12]), Util::Uint32AsFloat(vpnode[13])); // These values work out as the normals for the clipping planes. - vp->angle_right = atan2f(Util::Uint32AsFloat(vpnode[16]), -Util::Uint32AsFloat(vpnode[17])); // Sometimes these values (dirt devils,lost world) are totally wrong - vp->angle_top = atan2f(Util::Uint32AsFloat(vpnode[14]), Util::Uint32AsFloat(vpnode[15])); // and don't work for the frustum values exactly. - vp->angle_bottom = -atan2f(Util::Uint32AsFloat(vpnode[18]), -Util::Uint32AsFloat(vpnode[19])); // Perhaps they are just used for culling and not rendering. - */ - float cv = Util::Uint32AsFloat(vpnode[0x8]); // 1/(left-right) float cw = Util::Uint32AsFloat(vpnode[0x9]); // 1/(top-bottom) float io = Util::Uint32AsFloat(vpnode[0xa]); // top / bottom (ratio) - ish float jo = Util::Uint32AsFloat(vpnode[0xb]); // left / right (ratio) + // clipping plane normals + m_planes.bnlu = Util::Uint32AsFloat(vpnode[0xc]); + m_planes.bnlv = Util::Uint32AsFloat(vpnode[0xd]); + m_planes.bntu = Util::Uint32AsFloat(vpnode[0xe]); + m_planes.bntw = Util::Uint32AsFloat(vpnode[0xf]); + m_planes.bnru = Util::Uint32AsFloat(vpnode[0x10]); + m_planes.bnrv = Util::Uint32AsFloat(vpnode[0x11]); + m_planes.bnbu = Util::Uint32AsFloat(vpnode[0x12]); + m_planes.bnbw = Util::Uint32AsFloat(vpnode[0x13]); + vp->angle_left = (0.0f - jo) / cv; vp->angle_right = (1.0f - jo) / cv; vp->angle_bottom = -(1.0f - io)/ cw; vp->angle_top = -(0.0f - io)/ cw; - // calculate the frustum shape, near/far pair are dummy values - CalcViewport(vp, 1.f, 1000.f); - - // calculate frustum planes - CalcFrustumPlanes(m_planes, vp->projectionMatrix); // we need to calc a 'projection matrix' to get the correct frustum planes for clipping + CalcViewport(vp); // Lighting (note that sun vector points toward sun -- away from vertex) vp->lightingParams[0] = Util::Uint32AsFloat(vpnode[0x05]); // sun X @@ -1520,283 +1499,12 @@ bool CNew3D::IsVROMModel(UINT32 modelAddr) return modelAddr >= 0x100000; } -void CNew3D::CalcFrustumPlanes(Plane p[5], const float* matrix) +void CNew3D::CalcViewport(Viewport* vp) { - // Left Plane - p[0].a = matrix[3] + matrix[0]; - p[0].b = matrix[7] + matrix[4]; - p[0].c = matrix[11] + matrix[8]; - p[0].d = matrix[15] + matrix[12]; - p[0].Normalise(); - - // Right Plane - p[1].a = matrix[3] - matrix[0]; - p[1].b = matrix[7] - matrix[4]; - p[1].c = matrix[11] - matrix[8]; - p[1].d = matrix[15] - matrix[12]; - p[1].Normalise(); - - // Bottom Plane - p[2].a = matrix[3] + matrix[1]; - p[2].b = matrix[7] + matrix[5]; - p[2].c = matrix[11] + matrix[9]; - p[2].d = matrix[15] + matrix[13]; - p[2].Normalise(); - - // Top Plane - p[3].a = matrix[3] - matrix[1]; - p[3].b = matrix[7] - matrix[5]; - p[3].c = matrix[11] - matrix[9]; - p[3].d = matrix[15] - matrix[13]; - p[3].Normalise(); - - // Front Plane - p[4].a = 0.f; - p[4].b = 0.f; - p[4].c = -1.f; - p[4].d = 0.f; -} - -void CNew3D::CalcBox(float distance, BBox& box) -{ - //bottom left front - box.points[0][0] = -distance; - box.points[0][1] = -distance; - box.points[0][2] = distance; - box.points[0][3] = 1.f; - - //bottom left back - box.points[1][0] = -distance; - box.points[1][1] = -distance; - box.points[1][2] = -distance; - box.points[1][3] = 1.f; - - //bottom right back - box.points[2][0] = distance; - box.points[2][1] = -distance; - box.points[2][2] = -distance; - box.points[2][3] = 1.f; - - //bottom right front - box.points[3][0] = distance; - box.points[3][1] = -distance; - box.points[3][2] = distance; - box.points[3][3] = 1.f; - - //top left front - box.points[4][0] = -distance; - box.points[4][1] = distance; - box.points[4][2] = distance; - box.points[4][3] = 1.f; - - //top left back - box.points[5][0] = -distance; - box.points[5][1] = distance; - box.points[5][2] = -distance; - box.points[5][3] = 1.f; - - //top right back - box.points[6][0] = distance; - box.points[6][1] = distance; - box.points[6][2] = -distance; - box.points[6][3] = 1.f; - - //top right front - box.points[7][0] = distance; - box.points[7][1] = distance; - box.points[7][2] = distance; - box.points[7][3] = 1.f; -} - -void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) -{ - for (int i = 0; i < 4; i++) { - out[i] = - in[0] * matrix[0 * 4 + i] + - in[1] * matrix[1 * 4 + i] + - in[2] * matrix[2 * 4 + i] + - in[3] * matrix[3 * 4 + i]; - } -} - -void CNew3D::TransformBox(const float *m, BBox& box) -{ - for (int i = 0; i < 8; i++) { - float v[4]; - MultVec(m, box.points[i], v); - box.points[i][0] = v[0]; - box.points[i][1] = v[1]; - box.points[i][2] = v[2]; - } -} - -Clip CNew3D::ClipBox(const BBox& box, Plane planes[5]) -{ - int count = 0; - - for (int i = 0; i < 8; i++) { - - int temp = 0; - - for (int j = 0; j < 5; j++) { - if (planes[j].DistanceToPoint(box.points[i]) >= 0.f) { - temp++; - } - } - - if (temp == 5) count++; // point is inside all 4 frustum planes - } - - if (count == 8) return Clip::INSIDE; - if (count > 0) return Clip::INTERCEPT; - - //if we got here all points are outside of the view frustum - //check for all points being side same of any plane, means box outside of view - - for (int i = 0; i < 5; i++) { - - int temp = 0; - - for (int j = 0; j < 8; j++) { - if (planes[i].DistanceToPoint(box.points[j]) >= 0.f) { - temp++; - } - } - - if (temp == 0) { - return Clip::OUTSIDE; - } - } - - //if we got here, box is traversing view frustum - - return Clip::INTERCEPT; -} - -void CNew3D::CalcBoxExtents(const BBox& box) -{ - for (int i = 0; i < 8; i++) { - if (box.points[i][2] < 0.f) { - m_nfPairs[m_currentPriority].zNear = std::max(box.points[i][2], m_nfPairs[m_currentPriority].zNear); - m_nfPairs[m_currentPriority].zFar = std::min(box.points[i][2], m_nfPairs[m_currentPriority].zFar); - } - } -} - -void CNew3D::ClipPolygon(ClipPoly& clipPoly, Plane planes[5]) -{ - //============ - ClipPoly temp; - ClipPoly *in; - ClipPoly *out; - //============ - - in = &clipPoly; - out = &temp; - - for (int i = 0; i < 4; i++) { - - //================= - bool currentIn; - float currentDot; - //================= - - currentDot = planes[i].DotProduct(in->list[0].pos); - currentIn = (currentDot + planes[i].d) >= 0.f; - out->count = 0; - - for (int j = 0; j < in->count; j++) { - - if (currentIn) { - out->list[out->count] = in->list[j]; - out->count++; - } - - int nextIndex = j + 1; - if (nextIndex >= in->count) { - nextIndex = 0; - } - - float nextDot = planes[i].DotProduct(in->list[nextIndex].pos); - bool nextIn = (nextDot + planes[i].d) >= 0.f; - - // we have an intersection - if (currentIn != nextIn) { - - float u = (currentDot + planes[i].d) / (currentDot - nextDot); - - const float* p1 = in->list[j].pos; - const float* p2 = in->list[nextIndex].pos; - - out->list[out->count].pos[0] = p1[0] + ((p2[0] - p1[0]) * u); - out->list[out->count].pos[1] = p1[1] + ((p2[1] - p1[1]) * u); - out->list[out->count].pos[2] = p1[2] + ((p2[2] - p1[2]) * u); - out->count++; - } - - currentDot = nextDot; - currentIn = nextIn; - } - - std::swap(in, out); - } -} - -void CNew3D::ClipModel(const Model *m) -{ - //=============================== - ClipPoly clipPoly; - std::vector* vertices; - int offset; - //=============================== - - if (m->dynamic) { - vertices = &m_polyBufferRam; - offset = MAX_ROM_VERTS; - } - else { - vertices = &m_polyBufferRom; - offset = 0; - } - - for (const auto &mesh : *m->meshes) { - - int start = mesh.vboOffset - offset; - - for (int i = 0; i < mesh.vertexCount; i += m_numPolyVerts) { // inc to next poly - - for (int j = 0; j < m_numPolyVerts; j++) { - MultVec(m->modelMat, (*vertices)[start + i + j].pos, clipPoly.list[j].pos); // copy all 3 of 4 our transformed vertices into our clip poly struct - } - - clipPoly.count = m_numPolyVerts; - - ClipPolygon(clipPoly, m_planes); - - for (int j = 0; j < clipPoly.count; j++) { - if (clipPoly.list[j].pos[2] < 0.f) { - m_nfPairs[m_currentPriority].zNear = std::max(clipPoly.list[j].pos[2], m_nfPairs[m_currentPriority].zNear); - m_nfPairs[m_currentPriority].zFar = std::min(clipPoly.list[j].pos[2], m_nfPairs[m_currentPriority].zFar); - } - } - } - } -} - -void CNew3D::CalcViewport(Viewport* vp, float near, float far) -{ - if (far > 1e30f) { - far = near * 1000000.f; // fix for ocean hunter which passes some FLT_MAX for a few matrices. HW must have some safe guard for these - } - - if (near < far / 1000000.f) { - near = far / 1000000.f; // if we get really close to zero somehow, we will have almost no depth precision - } - - float l = near * vp->angle_left; // we need to calc the shape of the projection frustum for culling - float r = near * vp->angle_right; - float t = near * vp->angle_top; - float b = near * vp->angle_bottom; + float l = vp->angle_left; // we need to calc the shape of the projection frustum for culling + float r = vp->angle_right; + float t = vp->angle_top; + float b = vp->angle_bottom; vp->projectionMatrix.LoadIdentity(); // reset matrix @@ -1828,13 +1536,14 @@ void CNew3D::CalcViewport(Viewport* vp, float near, float far) // screen and non-wide-screen modes have identical resolution parameters // and only their scissor box differs) float correction = windowAR / viewableAreaAR; + m_planes.correction = 1.0f / correction; vp->x = 0; vp->y = m_yOffs + (int)((float)(384 - (vp->vpY + vp->vpHeight))*m_yRatio); vp->width = m_totalXRes; vp->height = (int)((float)vp->vpHeight*m_yRatio); - vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far); + vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, NEAR_PLANE); } else { @@ -1843,7 +1552,7 @@ void CNew3D::CalcViewport(Viewport* vp, float near, float far) vp->width = (int)((float)vp->vpWidth*m_xRatio); vp->height = (int)((float)vp->vpHeight*m_yRatio); - vp->projectionMatrix.Frustum(l, r, b, t, near, far); + vp->projectionMatrix.Frustum(l, r, b, t, NEAR_PLANE); } } @@ -1883,17 +1592,10 @@ bool CNew3D::ProcessLos(int priority) int losX, losY; TranslateLosPosition(n.viewport.losPosX, n.viewport.losPosY, losX, losY); - float depth; - glReadPixels(losX, losY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + float range; + glReadPixels(losX, losY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &range); - depth = 2.0f * depth - 1.0f; - - float zNear = m_nfPairs[priority].zNear; - float zFar = m_nfPairs[priority].zFar; - float zVal = 2.0f * zNear * zFar / (zFar + zNear - depth * (zFar - zNear)); - - // real3d test program indicates that return values are 1/zVal - zVal = 1.0f / zVal; + float zVal = range / NEAR_PLANE; GLubyte stencilVal; glReadPixels(losX, losY, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &stencilVal); diff --git a/Src/Graphics/New3D/New3D.h b/Src/Graphics/New3D/New3D.h index 7808537..e2f8fa6 100644 --- a/Src/Graphics/New3D/New3D.h +++ b/Src/Graphics/New3D/New3D.h @@ -287,31 +287,22 @@ private: R3DScrollFog m_r3dScrollFog; R3DFrameBuffers m_r3dFrameBuffers; - Plane m_planes[5]; - - struct BBox - { - V4::Vec4 points[8]; - }; - - struct NFPair - { - float zNear; - float zFar; - }; - - NFPair m_nfPairs[4]; int m_currentPriority; - void CalcFrustumPlanes (Plane p[5], const float* matrix); - void CalcBox (float distance, BBox& box); - void TransformBox (const float *m, BBox& box); - void MultVec (const float matrix[16], const float in[4], float out[4]); - Clip ClipBox (const BBox& box, Plane planes[5]); - void ClipModel (const Model *m); - void ClipPolygon (ClipPoly& clipPoly, Plane planes[5]); - void CalcBoxExtents (const BBox& box); - void CalcViewport (Viewport* vp, float near, float far); + struct + { + float bnlu; + float bnlv; + float bntu; + float bntw; + float bnru; + float bnrv; + float bnbu; + float bnbw; + float correction; + } m_planes; + + void CalcViewport (Viewport* vp); }; } // New3D diff --git a/Src/Graphics/New3D/R3DFrameBuffers.cpp b/Src/Graphics/New3D/R3DFrameBuffers.cpp index 9b0aff0..6948a9f 100644 --- a/Src/Graphics/New3D/R3DFrameBuffers.cpp +++ b/Src/Graphics/New3D/R3DFrameBuffers.cpp @@ -59,7 +59,7 @@ bool R3DFrameBuffers::CreateFBO(int width, int height) // depth/stencil attachment glGenRenderbuffers(1, &m_renderBufferID); glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferID); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferID); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferID); @@ -80,7 +80,7 @@ bool R3DFrameBuffers::CreateFBODepthCopy(int width, int height) glGenRenderbuffers(1, &m_renderBufferIDCopy); glBindRenderbuffer(GL_RENDERBUFFER, m_renderBufferIDCopy); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferIDCopy); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_renderBufferIDCopy); diff --git a/Src/Graphics/New3D/R3DShaderQuads.h b/Src/Graphics/New3D/R3DShaderQuads.h index cf7ae90..be8c7cc 100644 --- a/Src/Graphics/New3D/R3DShaderQuads.h +++ b/Src/Graphics/New3D/R3DShaderQuads.h @@ -353,7 +353,7 @@ void QuadraticInterpolation() depth = vertex.z * interp_oneOverW; } - gl_FragDepth = depth * 0.5 + 0.5; + gl_FragDepth = depth; } void main() @@ -376,7 +376,7 @@ void main() Step15Luminous(colData); // no-op for step 2.0+ finalData = tex1Data * colData; - if (finalData.a < (1.0/16.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports + if (finalData.a < (1.0/32.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports discard; } @@ -433,7 +433,8 @@ void main() sunFactor = clamp(sunFactor,-1.0,1.0); // Optional clamping, value is allowed to be negative - if(sunClamp) { + // We suspect that translucent polygons are always clamped (e.g. lasers in Daytona 2) + if(sunClamp || fsColor.a < 0.99) { sunFactor = max(sunFactor,0.0); } diff --git a/Src/Graphics/New3D/R3DShaderTriangles.h b/Src/Graphics/New3D/R3DShaderTriangles.h index 85f3037..0d868b9 100644 --- a/Src/Graphics/New3D/R3DShaderTriangles.h +++ b/Src/Graphics/New3D/R3DShaderTriangles.h @@ -103,6 +103,9 @@ uniform bool fixedShading; uniform int hardwareStep; uniform int colourLayer; +// matrices (shared with vertex shader) +uniform mat4 projMat; + //interpolated inputs from vertex shader in vec3 fsViewVertex; in vec3 fsViewNormal; // per vertex normal vector @@ -135,7 +138,9 @@ void main() if(fsDiscard > 0) { discard; //emulate back face culling here } - + + gl_FragDepth = projMat[3][2] * gl_FragCoord.w; + fogData = vec4(fogColour.rgb * fogAmbient, CalcFog()); tex1Data = vec4(1.0, 1.0, 1.0, 1.0); @@ -147,7 +152,7 @@ void main() Step15Luminous(colData); // no-op for step 2.0+ finalData = tex1Data * colData; - if (finalData.a < (1.0/16.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports + if (finalData.a < (1.0/32.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports discard; } @@ -204,7 +209,8 @@ void main() sunFactor = clamp(sunFactor,-1.0,1.0); // Optional clamping, value is allowed to be negative - if(sunClamp) { + // We suspect that translucent polygons are always clamped (e.g. lasers in Daytona 2) + if(sunClamp || fsColor.a < 0.99) { sunFactor = max(sunFactor,0.0); } From 6acb1165d422cf8614f9ceee2036da17f0407c9d Mon Sep 17 00:00:00 2001 From: gm-matthew <108370479+gm-matthew@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:31:05 +0000 Subject: [PATCH 2/2] Added new uniform bool polyAlpha to shaders Added original matrix functions back into Mat4 class though they are currently unused --- Src/Graphics/New3D/Mat4.cpp | 43 ++++++++++++++++++++++--- Src/Graphics/New3D/Mat4.h | 5 +-- Src/Graphics/New3D/New3D.cpp | 4 +-- Src/Graphics/New3D/R3DShader.cpp | 6 ++++ Src/Graphics/New3D/R3DShader.h | 2 ++ Src/Graphics/New3D/R3DShaderQuads.h | 3 +- Src/Graphics/New3D/R3DShaderTriangles.h | 3 +- 7 files changed, 55 insertions(+), 11 deletions(-) diff --git a/Src/Graphics/New3D/Mat4.cpp b/Src/Graphics/New3D/Mat4.cpp index 2181cd7..ba0a925 100644 --- a/Src/Graphics/New3D/Mat4.cpp +++ b/Src/Graphics/New3D/Mat4.cpp @@ -149,7 +149,40 @@ void Mat4::Rotate(float angle, float x, float y, float z) Mat4::MultiMatrices(currentMatrix, m, currentMatrix); } -void Mat4::Frustum(float left, float right, float bottom, float top, float nearVal) +void Mat4::Frustum(float left, float right, float bottom, float top, float nearVal, float farVal) +{ + float x = 2.0F / (right - left); + float y = 2.0F / (top - bottom); + float a = (right + left) / (right - left); + float b = (top + bottom) / (top - bottom); + float c = -(farVal + nearVal) / (farVal - nearVal); + float d = -(2.0F * farVal * nearVal) / (farVal - nearVal); + + float m[16]; + m[0] = x; + m[1] = 0.f; + m[2] = 0.f; + m[3] = 0.f; + + m[4] = 0.f; + m[5] = y; + m[6] = 0.f; + m[7] = 0.f; + + m[8] = a; + m[9] = b; + m[10] = c; + m[11] = -1.f; + + m[12] = 0.f; + m[13] = 0.f; + m[14] = d; + m[15] = 0.f; + + Mat4::MultiMatrices(currentMatrix, m, currentMatrix); +} + +void Mat4::FrustumRZ(float left, float right, float bottom, float top, float nearVal) { float x = 2.0F / (right - left); float y = 2.0F / (top - bottom); @@ -180,19 +213,19 @@ void Mat4::Frustum(float left, float right, float bottom, float top, float nearV Mat4::MultiMatrices(currentMatrix, m, currentMatrix); } -void Mat4::Perspective(float fovy, float aspect, float zNear) +void Mat4::Perspective(float fovy, float aspect, float zNear, float zFar) { float ymax = tanf(fovy * (float)(M_PI / 360.0)); float xmax = ymax * aspect; - Frustum(-xmax, xmax, -ymax, ymax, zNear); + Frustum(-xmax, xmax, -ymax, ymax, zNear, zFar); } void Mat4::Ortho(float left, float right, float bottom, float top, float nearVal, float farVal) { float tx = -(right + left) / (right - left); float ty = -(top + bottom) / (top - bottom); - float tz = (farVal + nearVal - 1.f) / (farVal - nearVal); + float tz = -(farVal + nearVal) / (farVal - nearVal); float m[16]; m[0] = 2.f/(right-left); @@ -207,7 +240,7 @@ void Mat4::Ortho(float left, float right, float bottom, float top, float nearVal m[8] = 0.f; m[9] = 0.f; - m[10] = 1.f/(farVal-nearVal); + m[10] = -2.f/(farVal-nearVal); m[11] = 0.f; m[12] = tx; diff --git a/Src/Graphics/New3D/Mat4.h b/Src/Graphics/New3D/Mat4.h index f8f6702..1c3f81a 100644 --- a/Src/Graphics/New3D/Mat4.h +++ b/Src/Graphics/New3D/Mat4.h @@ -15,8 +15,9 @@ public: void Translate (float x, float y, float z); void Rotate (float angle, float x, float y, float z); void Scale (float x, float y, float z); - void Frustum (float left, float right, float bottom, float top, float nearVal); - void Perspective (float fovy, float aspect, float zNear); + void Frustum (float left, float right, float bottom, float top, float nearVal, float farVal); + void FrustumRZ (float left, float right, float bottom, float top, float nearVal); + void Perspective (float fovy, float aspect, float zNear, float zFar); void Ortho (float left, float right, float bottom, float top, float nearVal, float farVal); void MultMatrix (const float *m); void LoadMatrix (const float *m); diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index 40c2b72..88e5be6 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -1543,7 +1543,7 @@ void CNew3D::CalcViewport(Viewport* vp) vp->width = m_totalXRes; vp->height = (int)((float)vp->vpHeight*m_yRatio); - vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, NEAR_PLANE); + vp->projectionMatrix.FrustumRZ(l*correction, r*correction, b, t, NEAR_PLANE); } else { @@ -1552,7 +1552,7 @@ void CNew3D::CalcViewport(Viewport* vp) vp->width = (int)((float)vp->vpWidth*m_xRatio); vp->height = (int)((float)vp->vpHeight*m_yRatio); - vp->projectionMatrix.Frustum(l, r, b, t, NEAR_PLANE); + vp->projectionMatrix.FrustumRZ(l, r, b, t, NEAR_PLANE); } } diff --git a/Src/Graphics/New3D/R3DShader.cpp b/Src/Graphics/New3D/R3DShader.cpp index fb7a6bd..2c4c9e0 100644 --- a/Src/Graphics/New3D/R3DShader.cpp +++ b/Src/Graphics/New3D/R3DShader.cpp @@ -112,6 +112,7 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader) m_locTextureInverted = glGetUniformLocation(m_shaderProgram, "textureInverted"); m_locTexWrapMode = glGetUniformLocation(m_shaderProgram, "textureWrapMode"); m_locColourLayer = glGetUniformLocation(m_shaderProgram, "colourLayer"); + m_locPolyAlpha = glGetUniformLocation(m_shaderProgram, "polyAlpha"); m_locFogIntensity = glGetUniformLocation(m_shaderProgram, "fogIntensity"); m_locFogDensity = glGetUniformLocation(m_shaderProgram, "fogDensity"); @@ -292,6 +293,11 @@ void R3DShader::SetMeshUniforms(const Mesh* m) m_translatorMap = m->translatorMap; } + if (m_dirtyMesh || m->polyAlpha != m_polyAlpha) { + glUniform1i(m_locPolyAlpha, m->polyAlpha); + m_polyAlpha = m->polyAlpha; + } + if (m_dirtyMesh || m->wrapModeU != m_texWrapMode[0] || m->wrapModeV != m_texWrapMode[1]) { m_texWrapMode[0] = m->wrapModeU; m_texWrapMode[1] = m->wrapModeV; diff --git a/Src/Graphics/New3D/R3DShader.h b/Src/Graphics/New3D/R3DShader.h index 778a910..84ca182 100644 --- a/Src/Graphics/New3D/R3DShader.h +++ b/Src/Graphics/New3D/R3DShader.h @@ -55,6 +55,7 @@ private: GLint m_locTexWrapMode; GLint m_locTranslatorMap; GLint m_locColourLayer; + GLint m_locPolyAlpha; // cached mesh values bool m_textured1; @@ -68,6 +69,7 @@ private: bool m_specularEnabled; bool m_fixedShading; bool m_translatorMap; + bool m_polyAlpha; bool m_layered; bool m_noLosReturn; diff --git a/Src/Graphics/New3D/R3DShaderQuads.h b/Src/Graphics/New3D/R3DShaderQuads.h index be8c7cc..5a81d49 100644 --- a/Src/Graphics/New3D/R3DShaderQuads.h +++ b/Src/Graphics/New3D/R3DShaderQuads.h @@ -211,6 +211,7 @@ uniform float fogAmbient; uniform bool fixedShading; uniform int hardwareStep; uniform int colourLayer; +uniform bool polyAlpha; // matrices (shared with vertex shader) uniform mat4 projMat; @@ -434,7 +435,7 @@ void main() // Optional clamping, value is allowed to be negative // We suspect that translucent polygons are always clamped (e.g. lasers in Daytona 2) - if(sunClamp || fsColor.a < 0.99) { + if(sunClamp || polyAlpha) { sunFactor = max(sunFactor,0.0); } diff --git a/Src/Graphics/New3D/R3DShaderTriangles.h b/Src/Graphics/New3D/R3DShaderTriangles.h index 0d868b9..b28ac24 100644 --- a/Src/Graphics/New3D/R3DShaderTriangles.h +++ b/Src/Graphics/New3D/R3DShaderTriangles.h @@ -102,6 +102,7 @@ uniform float fogAmbient; uniform bool fixedShading; uniform int hardwareStep; uniform int colourLayer; +uniform bool polyAlpha; // matrices (shared with vertex shader) uniform mat4 projMat; @@ -210,7 +211,7 @@ void main() // Optional clamping, value is allowed to be negative // We suspect that translucent polygons are always clamped (e.g. lasers in Daytona 2) - if(sunClamp || fsColor.a < 0.99) { + if(sunClamp || polyAlpha) { sunFactor = max(sunFactor,0.0); }