mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-03-06 14:27:44 +00:00
finish front/back face culling code based on matrix determinant. Optimised opengl to avoid redundant state changes.
This commit is contained in:
parent
44ea902181
commit
f031e5d095
|
@ -69,8 +69,7 @@ struct Model
|
|||
|
||||
//matrices
|
||||
float modelMat[16];
|
||||
|
||||
|
||||
float determinant; // we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order
|
||||
|
||||
// misc
|
||||
int lutIdx = 0;
|
||||
|
|
|
@ -83,25 +83,26 @@ void CNew3D::RenderScene(int priority, bool alpha)
|
|||
|
||||
for (auto &n : m_nodes) {
|
||||
|
||||
if (n.viewport.priority != priority) {
|
||||
if (n.viewport.priority != priority || n.models.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf(n.viewport.projectionMatrix);
|
||||
glViewport (n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadMatrixf (n.viewport.projectionMatrix);
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
|
||||
m_r3dShader.SetViewportUniforms(&n.viewport);
|
||||
|
||||
for (auto &m : n.models) {
|
||||
|
||||
bool matrixLoaded = false;
|
||||
|
||||
if (m.meshes.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf(m.modelMat);
|
||||
m_r3dShader.SetModelStates(&m);
|
||||
|
||||
for (auto &mesh : m.meshes) {
|
||||
|
||||
|
@ -115,6 +116,11 @@ void CNew3D::RenderScene(int priority, bool alpha)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matrixLoaded) {
|
||||
glLoadMatrixf(m.modelMat);
|
||||
matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
|
||||
}
|
||||
|
||||
if (mesh.texture) {
|
||||
mesh.texture->BindTexture();
|
||||
|
@ -244,6 +250,9 @@ bool CNew3D::DrawModel(UINT32 modelAddr)
|
|||
m->modelMat[i] = m_modelMat.currentMatrix[i];
|
||||
}
|
||||
|
||||
//calculate determinant
|
||||
m->determinant = Determinant3x3(m_modelMat);
|
||||
|
||||
CacheModel(m, modelAddress);
|
||||
|
||||
return true;
|
||||
|
@ -706,15 +715,13 @@ void CNew3D::CopyVertexData(R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
|
|||
Poly p;
|
||||
V3::Vec3 normal;
|
||||
float dotProd;
|
||||
float zFlip;
|
||||
bool clockWise;
|
||||
//====================
|
||||
|
||||
V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal);
|
||||
|
||||
dotProd = V3::dotProduct(normal, r3dPoly.faceNormal);
|
||||
zFlip = -1.0f*m_matrixBasePtr[0x5]; // coordinate system m13 component
|
||||
clockWise = (zFlip*dotProd >= 0.0);
|
||||
clockWise = dotProd >= 0.0;
|
||||
|
||||
if (clockWise) {
|
||||
p.p1 = r3dPoly.v[0];
|
||||
|
@ -931,8 +938,6 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
|||
}
|
||||
}
|
||||
|
||||
bool cw = ClockWiseWinding();
|
||||
|
||||
//sorted the data, now copy to main data structures
|
||||
|
||||
// we know how many meshes we have so reserve appropriate space
|
||||
|
@ -954,69 +959,6 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
|||
}
|
||||
}
|
||||
|
||||
// Macro to generate column-major (OpenGL) index from y,x subscripts
|
||||
#define CMINDEX(y,x) (x*4+y)
|
||||
|
||||
// 3x3 matrix used (upper-left of m[])
|
||||
static void MultMat3Vec3(GLfloat out[3], GLfloat m[4 * 4], GLfloat v[3])
|
||||
{
|
||||
out[0] = m[CMINDEX(0, 0)] * v[0] + m[CMINDEX(0, 1)] * v[1] + m[CMINDEX(0, 2)] * v[2];
|
||||
out[1] = m[CMINDEX(1, 0)] * v[0] + m[CMINDEX(1, 1)] * v[1] + m[CMINDEX(1, 2)] * v[2];
|
||||
out[2] = m[CMINDEX(2, 0)] * v[0] + m[CMINDEX(2, 1)] * v[1] + m[CMINDEX(2, 2)] * v[2];
|
||||
}
|
||||
|
||||
static GLfloat Sign(GLfloat x)
|
||||
{
|
||||
if (x > 0.0f)
|
||||
return 1.0f;
|
||||
else if (x < 0.0f)
|
||||
return -1.0f;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// Inverts and transposes a 3x3 matrix (upper-left of the 4x4), returning a
|
||||
// 4x4 matrix with the extra components undefined (do not use them!)
|
||||
static void InvertTransposeMat3(GLfloat out[4 * 4], GLfloat m[4 * 4])
|
||||
{
|
||||
GLfloat invDet;
|
||||
GLfloat a00 = m[CMINDEX(0, 0)], a01 = m[CMINDEX(0, 1)], a02 = m[CMINDEX(0, 2)];
|
||||
GLfloat a10 = m[CMINDEX(1, 0)], a11 = m[CMINDEX(1, 1)], a12 = m[CMINDEX(1, 2)];
|
||||
GLfloat a20 = m[CMINDEX(2, 0)], a21 = m[CMINDEX(2, 1)], a22 = m[CMINDEX(2, 2)];
|
||||
|
||||
invDet = 1.0f / (a00*(a22*a11 - a21*a12) - a10*(a22*a01 - a21*a02) + a20*(a12*a01 - a11*a02));
|
||||
out[CMINDEX(0, 0)] = invDet*(a22*a11 - a21*a12); out[CMINDEX(1, 0)] = invDet*(-(a22*a01 - a21*a02)); out[CMINDEX(2, 0)] = invDet*(a12*a01 - a11*a02);
|
||||
out[CMINDEX(0, 1)] = invDet*(-(a22*a10 - a20*a12)); out[CMINDEX(1, 1)] = invDet*(a22*a00 - a20*a02); out[CMINDEX(2, 1)] = invDet*(-(a12*a00 - a10*a02));
|
||||
out[CMINDEX(0, 2)] = invDet*(a21*a10 - a20*a11); out[CMINDEX(1, 2)] = invDet*(-(a21*a00 - a20*a01)); out[CMINDEX(2, 2)] = invDet*(a11*a00 - a10*a01);
|
||||
}
|
||||
|
||||
bool CNew3D::ClockWiseWinding()
|
||||
{
|
||||
GLfloat x[3] = { 1.0f, 0.0f, 0.0f };
|
||||
GLfloat y[3] = { 0.0f, 1.0f, 0.0f };
|
||||
GLfloat z[3] = { 0.0f, 0.0f, -1.0f*m_matrixBasePtr[0x5] };
|
||||
GLfloat m[4 * 4];
|
||||
GLfloat xT[3], yT[3], zT[3], pT[3];
|
||||
|
||||
InvertTransposeMat3(m, m_modelMat.currentMatrix);
|
||||
MultMat3Vec3(xT, m_modelMat.currentMatrix, x);
|
||||
MultMat3Vec3(yT, m_modelMat.currentMatrix, y);
|
||||
MultMat3Vec3(zT, m, z);
|
||||
V3::crossProduct(pT, xT, yT);
|
||||
|
||||
float s = Sign(zT[2] * pT[2]);
|
||||
|
||||
if (s < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
else if (s > 0.0f) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
int debugbreak = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float CNew3D::Determinant3x3(const float m[16]) {
|
||||
|
||||
/*
|
||||
|
|
|
@ -169,9 +169,7 @@ private:
|
|||
void CacheModel(Model *m, const UINT32 *data);
|
||||
void CopyVertexData(R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
|
||||
|
||||
enum class AlphaType{ none, poly, texture };
|
||||
void RenderScene(int priority, bool alpha);
|
||||
bool ClockWiseWinding(); // calculate winding with current matrix
|
||||
float Determinant3x3(const float m[16]);
|
||||
|
||||
/*
|
||||
|
|
|
@ -143,8 +143,12 @@ void R3DShader::Start()
|
|||
m_textureAlpha = false; // use alpha in texture
|
||||
m_alphaTest = false; // discard fragment based on alpha (ogl does this with fixed function)
|
||||
m_doubleSided = false;
|
||||
m_lightEnabled = false;
|
||||
|
||||
m_dirty = true; // dirty means all the above are dirty, ie first run
|
||||
m_matDet = MatDet::notset;
|
||||
|
||||
m_dirtyMesh = true; // dirty means all the above are dirty, ie first run
|
||||
m_dirtyModel = true;
|
||||
}
|
||||
|
||||
bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
|
||||
|
@ -206,52 +210,61 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
|
|||
return; // sanity check
|
||||
}
|
||||
|
||||
if (m_dirty) {
|
||||
if (m_dirtyMesh) {
|
||||
glUniform1i(m_locTexture, 0);
|
||||
}
|
||||
|
||||
if (m_dirty || m->textured != m_textured) {
|
||||
if (m_dirtyMesh || m->textured != m_textured) {
|
||||
glUniform1i(m_locTextureEnabled, m->textured);
|
||||
m_textured = m->textured;
|
||||
}
|
||||
|
||||
if (m_dirty || m->alphaTest != m_alphaTest) {
|
||||
if (m_dirtyMesh || m->alphaTest != m_alphaTest) {
|
||||
glUniform1i(m_locAlphaTest, m->alphaTest);
|
||||
m_alphaTest = m->alphaTest;
|
||||
}
|
||||
|
||||
if (m_dirty || m->textureAlpha != m_textureAlpha) {
|
||||
if (m_dirtyMesh || m->textureAlpha != m_textureAlpha) {
|
||||
glUniform1i(m_locTextureAlpha, m->textureAlpha);
|
||||
m_textureAlpha = m->textureAlpha;
|
||||
}
|
||||
|
||||
if (m_dirty || m->fogIntensity != m_fogIntensity) {
|
||||
if (m_dirtyMesh || m->fogIntensity != m_fogIntensity) {
|
||||
glUniform1f(m_locFogIntensity, m->fogIntensity);
|
||||
m_fogIntensity = m->fogIntensity;
|
||||
}
|
||||
|
||||
glUniform1i(m_locLightEnable, m->lighting);
|
||||
glUniform1f(m_locShininess, 1);
|
||||
if (m_dirtyMesh || m->lighting != m_lightEnabled) {
|
||||
glUniform1i(m_locLightEnable, m->lighting);
|
||||
m_lightEnabled = m->lighting;
|
||||
}
|
||||
|
||||
// technically not uniforms
|
||||
if (m_dirty || m->doubleSided != m_doubleSided) {
|
||||
m_doubleSided = m->doubleSided;
|
||||
if (m_doubleSided) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
else {
|
||||
glEnable(GL_CULL_FACE);
|
||||
//glUniform1f(m_locShininess, 1);
|
||||
|
||||
if (m_matDet!=MatDet::zero) {
|
||||
|
||||
if (m_dirtyMesh || m->doubleSided != m_doubleSided) {
|
||||
|
||||
m_doubleSided = m->doubleSided;
|
||||
|
||||
if (m_doubleSided) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
else {
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_dirty = false;
|
||||
|
||||
m_dirtyMesh = false;
|
||||
}
|
||||
|
||||
void R3DShader::SetViewportUniforms(const Viewport *vp)
|
||||
{
|
||||
//didn't bother caching these, they don't get frequently called anyway
|
||||
glUniform1f(m_locFogDensity, vp->fogParams[3]);
|
||||
glUniform1f(m_locFogStart, vp->fogParams[4]);
|
||||
glUniform1f (m_locFogDensity, vp->fogParams[3]);
|
||||
glUniform1f (m_locFogStart, vp->fogParams[4]);
|
||||
glUniform3fv(m_locFogColour, 1, vp->fogParams);
|
||||
|
||||
glUniform3fv(m_locLighting, 2, vp->lightingParams);
|
||||
|
@ -260,4 +273,37 @@ void R3DShader::SetViewportUniforms(const Viewport *vp)
|
|||
glUniform3fv(m_locSpotColor, 1, vp->spotColor);
|
||||
}
|
||||
|
||||
void R3DShader::SetModelStates(const Model* model)
|
||||
{
|
||||
//==========
|
||||
MatDet test;
|
||||
//==========
|
||||
|
||||
if (model->determinant < 0) { test = MatDet::negative; }
|
||||
else if (model->determinant > 0) { test = MatDet::positive; }
|
||||
else if (model->determinant == 0) { test = MatDet::zero; }
|
||||
|
||||
if (m_dirtyModel || m_matDet!=test) {
|
||||
|
||||
switch (test) {
|
||||
case MatDet::negative:
|
||||
glCullFace(GL_FRONT);
|
||||
glEnable(GL_CULL_FACE);
|
||||
m_doubleSided = false;
|
||||
break;
|
||||
case MatDet::positive:
|
||||
glCullFace(GL_BACK);
|
||||
glEnable(GL_CULL_FACE);
|
||||
m_doubleSided = false;
|
||||
break;
|
||||
default:
|
||||
glDisable(GL_CULL_FACE);
|
||||
m_doubleSided = true; // basically drawing on both sides now
|
||||
}
|
||||
}
|
||||
|
||||
m_matDet = test;
|
||||
m_dirtyModel = false;
|
||||
}
|
||||
|
||||
} // New3D
|
||||
|
|
|
@ -11,33 +11,43 @@ class R3DShader
|
|||
public:
|
||||
R3DShader();
|
||||
|
||||
bool LoadShader(const char* vertexShader = nullptr, const char* fragmentShader = nullptr);
|
||||
void SetMeshUniforms(const Mesh* m);
|
||||
void SetViewportUniforms(const Viewport *vp);
|
||||
void Start();
|
||||
void SetShader(bool enable = true);
|
||||
bool LoadShader (const char* vertexShader = nullptr, const char* fragmentShader = nullptr);
|
||||
void SetMeshUniforms (const Mesh* m);
|
||||
void SetModelStates (const Model* model);
|
||||
void SetViewportUniforms (const Viewport *vp);
|
||||
void Start ();
|
||||
void SetShader (bool enable = true);
|
||||
|
||||
private:
|
||||
|
||||
// shader IDs
|
||||
GLuint m_shaderProgram;
|
||||
GLuint m_vertexShader;
|
||||
GLuint m_fragmentShader;
|
||||
|
||||
// mesh uniform data
|
||||
// mesh uniform locations
|
||||
GLint m_locTexture;
|
||||
GLint m_locTextureEnabled;
|
||||
GLint m_locTextureAlpha;
|
||||
GLint m_locAlphaTest;
|
||||
|
||||
bool m_textured;
|
||||
bool m_textureAlpha; // use alpha in texture
|
||||
bool m_alphaTest; // discard fragment based on alpha (ogl does this with fixed function)
|
||||
float m_fogIntensity;
|
||||
bool m_doubleSided;
|
||||
// cached mesh values
|
||||
bool m_textured;
|
||||
bool m_textureAlpha; // use alpha in texture
|
||||
bool m_alphaTest; // discard fragment based on alpha (ogl does this with fixed function)
|
||||
float m_fogIntensity;
|
||||
bool m_doubleSided;
|
||||
bool m_lightEnabled;
|
||||
|
||||
bool m_dirty;
|
||||
// cached model values
|
||||
enum class MatDet { notset, negative, positive, zero };
|
||||
MatDet m_matDet;
|
||||
|
||||
// viewport uniform data
|
||||
// are our cache values dirty
|
||||
bool m_dirtyMesh;
|
||||
bool m_dirtyModel;
|
||||
|
||||
// viewport uniform locations
|
||||
GLint m_locFogIntensity;
|
||||
GLint m_locFogDensity;
|
||||
GLint m_locFogStart;
|
||||
|
|
Loading…
Reference in a new issue