Fixed shading (per vertex poly colours) on step 1.5 hardware have the viewport ambient value added to them. This fixes various shading on scud. To do this had to switch the maths to the vertex shader.

This commit is contained in:
Ian Curtis 2017-08-14 09:14:06 +00:00
parent 8f622714a7
commit c12e4c3215
6 changed files with 99 additions and 60 deletions

View file

@ -26,7 +26,8 @@ struct Vertex
float pos[3]; float pos[3];
float normal[3]; float normal[3];
float texcoords[2]; float texcoords[2];
float color[4]; //rgba UINT8 color[4];
UINT8 fixedShade[4];
}; };
struct Poly // our polys are always 3 triangles, unlike the real h/w struct Poly // our polys are always 3 triangles, unlike the real h/w
@ -40,7 +41,7 @@ struct R3DPoly
{ {
Vertex v[4]; // just easier to have them as an array Vertex v[4]; // just easier to have them as an array
float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself
float faceColour[4]; // per face colour UINT8 faceColour[4]; // per face colour
int number = 4; int number = 4;
}; };
@ -85,6 +86,7 @@ struct Mesh
bool highPriority = false; // rendered over the top bool highPriority = false; // rendered over the top
// lighting // lighting
bool fixedShading = false;
bool lighting = false; bool lighting = false;
bool specular = false; bool specular = false;
float shininess = 0; float shininess = 0;
@ -151,6 +153,8 @@ struct Viewport
int number; // viewport number int number; // viewport number
float spotFogColor[3]; // spotlight color on fog float spotFogColor[3]; // spotlight color on fog
float scrollAtt; float scrollAtt;
int hardwareStep; // not really a viewport param but will do here
}; };
enum class Clip { INSIDE, OUTSIDE, INTERCEPT, NOT_SET }; enum class Clip { INSIDE, OUTSIDE, INTERCEPT, NOT_SET };

View file

@ -282,12 +282,14 @@ void CNew3D::RenderFrame(void)
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3); glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. // 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"), 3, 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("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("inTexCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
glVertexAttribPointer(m_r3dShader.GetVertexAttribPos("inColour"), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, color)); 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));
m_r3dShader.SetShader(true); m_r3dShader.SetShader(true);
@ -321,6 +323,7 @@ void CNew3D::RenderFrame(void)
glDisableVertexAttribArray(1); glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2); glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3); glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
} }
void CNew3D::BeginFrame(void) void CNew3D::BeginFrame(void)
@ -781,8 +784,7 @@ void CNew3D::RenderViewport(UINT32 addr)
vp->sunClamp = 1; // TODO work out how this is passed, doesn't appear to be in the viewport .. or in the model data vp->sunClamp = 1; // TODO work out how this is passed, doesn't appear to be in the viewport .. or in the model data
vp->intensityClamp = (m_step == 0x10); // just step 1.0 ? vp->intensityClamp = (m_step == 0x10); // just step 1.0 ?
vp->hardwareStep = m_step;
m_vpAmbient = vp->lightingParams[4]; // cache this
// Spotlight // Spotlight
int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index
@ -904,11 +906,11 @@ void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray
p.p3 = r3dPoly.v[0]; p.p3 = r3dPoly.v[0];
} }
//multiply face attributes with vertex attributes if required // Copy face colour to vertices
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i]; p.p1.color[i] = r3dPoly.faceColour[i];
p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i]; p.p2.color[i] = r3dPoly.faceColour[i];
p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i]; p.p3.color[i] = r3dPoly.faceColour[i];
} }
polyArray.emplace_back(p); polyArray.emplace_back(p);
@ -931,11 +933,11 @@ void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray
p.p3 = r3dPoly.v[2]; p.p3 = r3dPoly.v[2];
} }
//multiply face attributes with vertex attributes if required // Copy face colour to vertices
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i]; p.p1.color[i] = r3dPoly.faceColour[i];
p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i]; p.p2.color[i] = r3dPoly.faceColour[i];
p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i]; p.p3.color[i] = r3dPoly.faceColour[i];
} }
polyArray.emplace_back(p); polyArray.emplace_back(p);
@ -997,7 +999,8 @@ void CNew3D::SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph)
currentMesh->alphaTest = ph.AlphaTest(); currentMesh->alphaTest = ph.AlphaTest();
currentMesh->textureAlpha = ph.TextureAlpha(); currentMesh->textureAlpha = ph.TextureAlpha();
currentMesh->polyAlpha = ph.PolyAlpha(); currentMesh->polyAlpha = ph.PolyAlpha();
currentMesh->lighting = ph.LightEnabled() && !ph.FixedShading(); currentMesh->lighting = ph.LightEnabled();
currentMesh->fixedShading = ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading();
currentMesh->highPriority = ph.HighPriority(); currentMesh->highPriority = ph.HighPriority();
if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) { if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) {
@ -1119,29 +1122,29 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
// copy face attributes // copy face attributes
if ((ph.header[1] & 2) == 0) { if (!ph.PolyColor()) {
int colorIdx = ph.ColorIndex(); int colorIdx = ph.ColorIndex();
p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f; p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF);
p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f; p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF);
p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f; p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF);
} }
else { else {
p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f; p.faceColour[0] = ((ph.header[4] >> 24));
p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f; p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF);
p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f; p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF);
if (ph.TranslatorMap()) { if (ph.TranslatorMap()) {
p.faceColour[0] *= 15.9375f; // not using 16, as 16x16=256 not 255 and that would overflow (potentially) p.faceColour[0] = (p.faceColour[0] * 255) / 16; // When the translator map is enabled, max colour seems
p.faceColour[1] *= 15.9375f; p.faceColour[1] = (p.faceColour[1] * 255) / 16; // to be 16. Scaling these up gives the correct colours.
p.faceColour[2] *= 15.9375f; p.faceColour[2] = (p.faceColour[2] * 255) / 16; // Not sure why didn't allow 32 colours with 4 bits?
} }
} }
p.faceColour[3] = ph.Transparency() / 255.f; p.faceColour[3] = ph.Transparency();
if (ph.Discard1() && !ph.Discard2()) { if (ph.Discard1() && !ph.Discard2()) {
p.faceColour[3] *= 0.5f; p.faceColour[3] /= 2;
} }
// if we have flat shading, we can't re-use normals from shared vertices // if we have flat shading, we can't re-use normals from shared vertices
@ -1176,42 +1179,32 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
if (ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading()) { // fixed shading seems to be disabled if actual normals are set if (ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading()) { // fixed shading seems to be disabled if actual normals are set
//=========== //==========
float shade; UINT8 shade;
float offset; // if lighting is disabled colour seems to be an offset //==========
//===========
offset = !ph.LightEnabled() ? 1.f : 0.f;
if (m_step <= 0x15) { 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
shade = ((ix & 0x7F) / 127.f); // this matches the sdk (values are from 0-127 only) and the intensity is clamped to to 0-1
if (m_vpAmbient > 0) {
shade = (shade + 1) / 2; // Viewport ambient seems to effect fixed shading. Technically vp ambient can change dynamically, but not an issue in practise. If it was we would need this logic in shader
}
} }
else { else {
if (ph.SpecularEnabled()) { 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 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 { else {
shade = (((ix + 128) & 0xFF) / 255.f); // Step 2+ uses signed or unsigned values for lighting 0-255. Todo finish this logic shade = (ix + 128) & 0xFF; // Step 2+ uses signed or unsigned values for lighting 0-255. Todo finish this logic
} }
} }
shade += offset; p.v[j].fixedShade[0] = shade; // hardware doesn't really have per vertex colours, only per poly
p.v[j].fixedShade[1] = shade;
p.v[j].color[0] = shade; // hardware doesn't really have per vertex colours, only per poly p.v[j].fixedShade[2] = shade;
p.v[j].color[1] = shade; p.v[j].fixedShade[3] = 255;
p.v[j].color[2] = shade;
p.v[j].color[3] = 1;
} }
else { else {
p.v[j].color[0] = 1; p.v[j].fixedShade[0] = 255;
p.v[j].color[1] = 1; p.v[j].fixedShade[1] = 255;
p.v[j].color[2] = 1; p.v[j].fixedShade[2] = 255;
p.v[j].color[3] = 1; p.v[j].fixedShade[3] = 255;
} }
float texU, texV = 0; float texU, texV = 0;

View file

@ -216,7 +216,6 @@ private:
TextureSheet m_texSheet; TextureSheet m_texSheet;
NodeAttributes m_nodeAttribs; NodeAttributes m_nodeAttribs;
Mat4 m_modelMat; // current modelview matrix Mat4 m_modelMat; // current modelview matrix
float m_vpAmbient; // cached value
std::vector<Node> m_nodes; // this represents the entire render frame std::vector<Node> m_nodes; // this represents the entire render frame
std::vector<Poly> m_polyBufferRam; // dynamic polys std::vector<Poly> m_polyBufferRam; // dynamic polys

View file

@ -344,7 +344,7 @@ UINT8 PolyHeader::Transparency()
return 255; // without this check we get overflow. In the SDK, values are explicitly clamped to 0-32. return 255; // without this check we get overflow. In the SDK, values are explicitly clamped to 0-32.
} }
return (UINT8)((((header[6] >> 18) & 0x3F) * 255) / 32.f); return (((header[6] >> 18) & 0x3F) * 255) / 32;
} }
bool PolyHeader::PolyAlpha() bool PolyHeader::PolyAlpha()

View file

@ -12,12 +12,17 @@ uniform float fogIntensity;
uniform float fogDensity; uniform float fogDensity;
uniform float fogStart; uniform float fogStart;
uniform float modelScale; 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
// attributes // attributes
attribute vec3 inVertex; attribute vec3 inVertex;
attribute vec3 inNormal; attribute vec3 inNormal;
attribute vec2 inTexCoord; attribute vec2 inTexCoord;
attribute vec4 inColour; attribute vec4 inColour;
attribute vec4 inFixedShade;
// outputs to fragment shader // outputs to fragment shader
varying float fsFogFactor; varying float fsFogFactor;
@ -26,6 +31,27 @@ varying vec3 fsViewNormal; // per vertex normal vector
varying vec2 fsTexCoord; varying vec2 fsTexCoord;
varying vec4 fsColor; varying vec4 fsColor;
vec4 GetVertexColour()
{
vec4 polyColour = inColour;
if(fixedShading) {
if(hardwareStep==0x15) {
if(!lightEnabled) {
polyColour += inFixedShade; // + vp ambient??
}
else {
polyColour *= (inFixedShade + lighting[1].y); // fixed shade value + viewport ambient
}
}
else {
polyColour *= inFixedShade; //todo work out what ambient does. Probably a min clamp or 1-min clamp for signed values
}
}
return polyColour;
}
void main(void) void main(void)
{ {
fsViewVertex = vec3(gl_ModelViewMatrix * vec4(inVertex,1.0)); fsViewVertex = vec3(gl_ModelViewMatrix * vec4(inVertex,1.0));
@ -33,7 +59,7 @@ void main(void)
float z = length(fsViewVertex); float z = length(fsViewVertex);
fsFogFactor = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0); fsFogFactor = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);
fsColor = inColour; fsColor = GetVertexColour();
fsTexCoord = inTexCoord; fsTexCoord = inTexCoord;
gl_Position = gl_ModelViewProjectionMatrix * vec4(inVertex,1.0); gl_Position = gl_ModelViewProjectionMatrix * vec4(inVertex,1.0);
} }
@ -70,6 +96,7 @@ uniform float specularValue; // specular coefficient
uniform float shininess; // specular shininess uniform float shininess; // specular shininess
uniform float fogAttenuation; uniform float fogAttenuation;
uniform float fogAmbient; uniform float fogAmbient;
uniform bool fixedShading;
//interpolated inputs from vertex shader //interpolated inputs from vertex shader
varying float fsFogFactor; varying float fsFogFactor;
@ -132,7 +159,7 @@ void main()
ellipse = 1.0 - ellipse; // invert ellipse = 1.0 - ellipse; // invert
ellipse = max(0.0, ellipse); // clamp ellipse = max(0.0, ellipse); // clamp
if (lightEnabled) { if (lightEnabled && !fixedShading) {
vec3 lightIntensity; vec3 lightIntensity;
vec3 sunVector; // sun lighting vector (as reflecting away from vertex) vec3 sunVector; // sun lighting vector (as reflecting away from vertex)
float sunFactor; // sun light projection along vertex normal (0.0 to 1.0) float sunFactor; // sun light projection along vertex normal (0.0 to 1.0)
@ -242,6 +269,7 @@ void R3DShader::Start()
m_specularEnabled = false; m_specularEnabled = false;
m_layered = false; m_layered = false;
m_textureInverted = false; m_textureInverted = false;
m_fixedShading = false;
m_modelScale = 1.0f; m_modelScale = 1.0f;
m_shininess = 0; m_shininess = 0;
m_specularValue = 0; m_specularValue = 0;
@ -302,6 +330,7 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
m_locShininess = glGetUniformLocation(m_shaderProgram, "shininess"); m_locShininess = glGetUniformLocation(m_shaderProgram, "shininess");
m_locSpecularValue = glGetUniformLocation(m_shaderProgram, "specularValue"); m_locSpecularValue = glGetUniformLocation(m_shaderProgram, "specularValue");
m_locSpecularEnabled= glGetUniformLocation(m_shaderProgram, "specularEnabled"); m_locSpecularEnabled= glGetUniformLocation(m_shaderProgram, "specularEnabled");
m_locFixedShading = glGetUniformLocation(m_shaderProgram, "fixedShading");
m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse"); m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse");
m_locSpotRange = glGetUniformLocation(m_shaderProgram, "spotRange"); m_locSpotRange = glGetUniformLocation(m_shaderProgram, "spotRange");
@ -309,6 +338,8 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor"); m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor");
m_locModelScale = glGetUniformLocation(m_shaderProgram, "modelScale"); m_locModelScale = glGetUniformLocation(m_shaderProgram, "modelScale");
m_locHardwareStep = glGetUniformLocation(m_shaderProgram, "hardwareStep");
return success; return success;
} }
@ -400,6 +431,11 @@ void R3DShader::SetMeshUniforms(const Mesh* m)
m_specularValue = m->specularValue; m_specularValue = m->specularValue;
} }
if (m_dirtyMesh || m->fixedShading != m_fixedShading) {
glUniform1i(m_locFixedShading, m->fixedShading);
m_fixedShading = m->fixedShading;
}
if (m_dirtyMesh || m->layered != m_layered) { if (m_dirtyMesh || m->layered != m_layered) {
m_layered = m->layered; m_layered = m->layered;
if (m_layered) { if (m_layered) {
@ -445,6 +481,8 @@ void R3DShader::SetViewportUniforms(const Viewport *vp)
glUniform2fv(m_locSpotRange, 1, vp->spotRange); glUniform2fv(m_locSpotRange, 1, vp->spotRange);
glUniform3fv(m_locSpotColor, 1, vp->spotColor); glUniform3fv(m_locSpotColor, 1, vp->spotColor);
glUniform3fv(m_locSpotFogColor, 1, vp->spotFogColor); glUniform3fv(m_locSpotFogColor, 1, vp->spotFogColor);
glUniform1i (m_locHardwareStep, vp->hardwareStep);
} }
void R3DShader::SetModelStates(const Model* model) void R3DShader::SetModelStates(const Model* model)

View file

@ -52,6 +52,7 @@ private:
float m_shininess; float m_shininess;
float m_specularValue; float m_specularValue;
bool m_specularEnabled; bool m_specularEnabled;
bool m_fixedShading;
bool m_layered; bool m_layered;
float m_microTexScale; float m_microTexScale;
@ -83,6 +84,7 @@ private:
GLint m_locShininess; GLint m_locShininess;
GLint m_locSpecularValue; GLint m_locSpecularValue;
GLint m_locSpecularEnabled; GLint m_locSpecularEnabled;
GLint m_locFixedShading;
GLint m_locSpotEllipse; GLint m_locSpotEllipse;
GLint m_locSpotRange; GLint m_locSpotRange;
@ -91,6 +93,9 @@ private:
// model uniforms // model uniforms
GLint m_locModelScale; GLint m_locModelScale;
// global uniforms
GLint m_locHardwareStep;
}; };
} // New3D } // New3D