From cd5978773a0a7445ef9ac9226873874d815b4ecf Mon Sep 17 00:00:00 2001 From: Ian Curtis Date: Sat, 19 Aug 2017 20:06:31 +0000 Subject: [PATCH] Harry made some important discoveries with regards to fixed shading on the model 3 (per vertex poly brightness values). Firstly values are allowed to be negative, and they are used as a drop in replacement in the standard lighting equation for the normal dot light vector. This quite radically changes the brightness in LA Machine guns, but now correctly matches the arcade. --- Src/Graphics/New3D/Model.h | 7 ++-- Src/Graphics/New3D/New3D.cpp | 55 +++++++++++---------------- Src/Graphics/New3D/R3DShader.cpp | 65 +++++++++++++++----------------- 3 files changed, 55 insertions(+), 72 deletions(-) diff --git a/Src/Graphics/New3D/Model.h b/Src/Graphics/New3D/Model.h index 440b40e..d50c0fe 100644 --- a/Src/Graphics/New3D/Model.h +++ b/Src/Graphics/New3D/Model.h @@ -12,7 +12,7 @@ namespace New3D { struct ClipVertex { - float pos[3]; + float pos[4]; }; struct ClipPoly @@ -23,12 +23,11 @@ struct ClipPoly struct Vertex { - float pos[3]; + float pos[4]; float normal[3]; float texcoords[2]; UINT8 color[4]; - UINT8 fixedShade; - UINT8 padding[3]; + float fixedShade; }; struct Poly // our polys are always 3 triangles, unlike the real h/w diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index 9b9b640..a2b5b3b 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -10,6 +10,8 @@ #define MAX_RAM_POLYS 100000 #define MAX_ROM_POLYS 500000 +#define BYTE_TO_FLOAT(B) ((2.0f * (B) + 1.0f) * (1.0F/255.0f)) + namespace New3D { CNew3D::CNew3D(const Util::Config::Node &config, std::string gameName) @@ -286,11 +288,11 @@ void CNew3D::RenderFrame(void) glEnableVertexAttribArray(4); // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inVertex"), 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); + glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inVertex"), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inNormal"), 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inTexCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inColour"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color)); - glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFixedShade"), 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, fixedShade)); + glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inFixedShade"), 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, fixedShade)); m_r3dShader.SetShader(true); @@ -784,8 +786,11 @@ void CNew3D::RenderViewport(UINT32 addr) vp->lightingParams[5] = 0.0; // reserved // this is a hack because we haven't yet found in memory where these are set - // these two games use a slightly different light model to the test of the games - if (m_gameName == "lamachin" || m_gameName == "dayto2pe") { + if (m_gameName == "dayto2pe"|| + m_gameName == "lamachin"|| + m_gameName == "von2" || + m_gameName == "von254g" || + m_gameName == "von2a") { vp->sunClamp = false; } else { @@ -1178,33 +1183,29 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data) p.v[j].pos[0] = (((INT32)ix) >> 8) * m_vertexFactor; p.v[j].pos[1] = (((INT32)iy) >> 8) * m_vertexFactor; p.v[j].pos[2] = (((INT32)iz) >> 8) * m_vertexFactor; + p.v[j].pos[3] = 1.0f; // Per vertex normals if (ph.SmoothShading()) { - p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f; - p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f; - p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f; + p.v[j].normal[0] = BYTE_TO_FLOAT((INT8)(ix & 0xFF)); + p.v[j].normal[1] = BYTE_TO_FLOAT((INT8)(iy & 0xFF)); + p.v[j].normal[2] = BYTE_TO_FLOAT((INT8)(iz & 0xFF)); } if (ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading()) { // fixed shading seems to be disabled if actual normals are set //========== - UINT8 shade; + float shade; //========== - if (m_step <= 0x15) { - shade = ((ix & 0x7F) * 255) / 127; // this matches the sdk (values are from 0-127 only) and the intensity is clamped to to 0-1 + if (ph.SpecularEnabled()) { + shade = (ix & 0xFF) / 255.f; // Star wars is the only game to use unsigned fixed shaded values. It's also the only game to set the specular flag on these polys } else { - if (ph.SpecularEnabled()) { - shade = ix & 0xFF; // Star wars is the only game to use unsigned fixed shaded values. It's also the only game to set the specular flag on these polys - } - else { - shade = (ix + 128) & 0xFF; // Step 2+ uses signed or unsigned values for lighting 0-255. Todo finish this logic - } + shade = BYTE_TO_FLOAT((INT8)(ix & 0xFF)); } - - p.v[j].fixedShade = shade; // hardware doesn't really have per vertex colours, only per poly + + p.v[j].fixedShade = shade; } float texU, texV = 0; @@ -1606,23 +1607,11 @@ void CNew3D::ClipModel(const Model *m) //================================== Poly& poly = (*polys)[start + i]; - float in[4], out[4]; //================================== - memcpy(in, poly.p1.pos, sizeof(float) * 3); - in[3] = 1; - MultVec(m->modelMat, in, out); - memcpy(clipPoly.list[0].pos, out, sizeof(float) * 3); - - memcpy(in, poly.p2.pos, sizeof(float) * 3); - in[3] = 1; - MultVec(m->modelMat, in, out); - memcpy(clipPoly.list[1].pos, out, sizeof(float) * 3); - - memcpy(in, poly.p3.pos, sizeof(float) * 3); - in[3] = 1; - MultVec(m->modelMat, in, out); - memcpy(clipPoly.list[2].pos, out, sizeof(float) * 3); + MultVec(m->modelMat, poly.p1.pos, clipPoly.list[0].pos); + MultVec(m->modelMat, poly.p2.pos, clipPoly.list[1].pos); + MultVec(m->modelMat, poly.p3.pos, clipPoly.list[2].pos); clipPoly.count = 3; diff --git a/Src/Graphics/New3D/R3DShader.cpp b/Src/Graphics/New3D/R3DShader.cpp index d469e40..3da73bd 100644 --- a/Src/Graphics/New3D/R3DShader.cpp +++ b/Src/Graphics/New3D/R3DShader.cpp @@ -12,14 +12,9 @@ uniform float fogIntensity; uniform float fogDensity; uniform float fogStart; uniform float modelScale; -uniform int hardwareStep; -uniform vec3 lighting[2]; // also used in fragment shader -uniform bool lightEnabled; // also used in fragment shader -uniform bool fixedShading; // also used in fragment shader -uniform bool sunClamp; // also used in fragment shader // attributes -attribute vec3 inVertex; +attribute vec4 inVertex; attribute vec3 inNormal; attribute vec2 inTexCoord; attribute vec4 inColour; @@ -31,39 +26,19 @@ varying vec3 fsViewVertex; varying vec3 fsViewNormal; // per vertex normal vector varying vec2 fsTexCoord; varying vec4 fsColor; - -vec4 GetVertexColour() -{ - vec4 polyColour = inColour; - - if(fixedShading) { - - float lightAmbient = lighting[1].y; - if(!sunClamp) { - lightAmbient = 0; // guess work here. La machine guns is the only game to use this light model. Black is black in this game, it's not effected by ambient - } - - if(lightEnabled) { - polyColour.rgb *= (inFixedShade + lightAmbient); // per vertex brightness + ambient - } - else { - polyColour.rgb += lightAmbient; // this is similar to above but basically a flat shaded version. So poly colour + ambient - } - } - - return polyColour; -} +varying float fsFixedShade; void main(void) { - fsViewVertex = vec3(gl_ModelViewMatrix * vec4(inVertex,1.0)); + fsViewVertex = vec3(gl_ModelViewMatrix * inVertex); fsViewNormal = (mat3(gl_ModelViewMatrix) * inNormal) / modelScale; float z = length(fsViewVertex); fsFogFactor = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0); - fsColor = GetVertexColour(); + fsColor = inColour; fsTexCoord = inTexCoord; - gl_Position = gl_ModelViewProjectionMatrix * vec4(inVertex,1.0); + fsFixedShade = inFixedShade; + gl_Position = gl_ModelViewProjectionMatrix * inVertex; } )glsl"; @@ -99,6 +74,7 @@ uniform float shininess; // specular shininess uniform float fogAttenuation; uniform float fogAmbient; uniform bool fixedShading; +uniform int hardwareStep; //interpolated inputs from vertex shader varying float fsFogFactor; @@ -106,6 +82,7 @@ varying vec3 fsViewVertex; varying vec3 fsViewNormal; // per vertex normal vector varying vec4 fsColor; varying vec2 fsTexCoord; +varying float fsFixedShade; vec4 GetTextureValue() { @@ -134,6 +111,17 @@ vec4 GetTextureValue() return tex1Data; } +void Step15Lighting(inout vec4 colour) +{ + // on step 1.5 these polys seem to be effected by vpAmbient + // logic is not completely understood + if(hardwareStep==0x15) { + if(!lightEnabled && fixedShading) { + colour.rgb += lighting[1].y; // + vpAmbient + } + } +} + void main() { vec4 tex1Data; @@ -149,9 +137,10 @@ void main() } colData = fsColor; + Step15Lighting(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/16.0)) { // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports discard; } @@ -161,7 +150,7 @@ void main() ellipse = 1.0 - ellipse; // invert ellipse = max(0.0, ellipse); // clamp - if (lightEnabled && !fixedShading) { + if (lightEnabled) { vec3 lightIntensity; vec3 sunVector; // sun lighting vector (as reflecting away from vertex) float sunFactor; // sun light projection along vertex normal (0.0 to 1.0) @@ -170,7 +159,12 @@ void main() sunVector = lighting[0]; // Compute diffuse factor for sunlight - sunFactor = dot(sunVector, fsViewNormal); + if(fixedShading) { + sunFactor = fsFixedShade; + } + else { + sunFactor = dot(sunVector, fsViewNormal); + } // Clamp ceil, fix for upscaled models without "modelScale" defined sunFactor = clamp(sunFactor,-1.0,1.0); @@ -208,7 +202,8 @@ void main() finalData.rgb *= lightIntensity; - if (specularEnabled) { + // for now assume fixed shading doesn't work with specular + if (specularEnabled && !fixedShading) { float exponent, NdotL, specularFactor; vec4 biasIndex, expIndex, multIndex;