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.

This commit is contained in:
Ian Curtis 2017-08-19 20:06:31 +00:00
parent 94e6f9a156
commit cd5978773a
3 changed files with 55 additions and 72 deletions

View file

@ -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

View file

@ -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;

View file

@ -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;