From f0e00c5dc7c8d09bfd8ab3bb1045f45967d70be4 Mon Sep 17 00:00:00 2001 From: Ian Curtis Date: Sun, 2 Apr 2017 21:03:59 +0000 Subject: [PATCH] Rewrite the spot light code, and implement the missing fog logic. (HarryTuttle) --- Src/Graphics/New3D/Model.h | 4 +- Src/Graphics/New3D/New3D.cpp | 76 ++++----- Src/Graphics/New3D/R3DScrollFog.cpp | 102 ++++++++---- Src/Graphics/New3D/R3DScrollFog.h | 30 ++-- Src/Graphics/New3D/R3DShader.cpp | 243 +++++++++++++++------------- Src/Graphics/New3D/R3DShader.h | 27 ++-- 6 files changed, 277 insertions(+), 205 deletions(-) diff --git a/Src/Graphics/New3D/Model.h b/Src/Graphics/New3D/Model.h index 540b009..bbb692c 100644 --- a/Src/Graphics/New3D/Model.h +++ b/Src/Graphics/New3D/Model.h @@ -137,11 +137,13 @@ struct Viewport float spotEllipse[4]; // spotlight ellipse (see RenderViewport()) float spotRange[2]; // Z range float spotColor[3]; // color - float fogParams[5]; // fog parameters (...) + float fogParams[7]; // fog parameters (...) float scrollFog; // a transparency value that determines if fog is blended over the bottom 2D layer int x, y; // viewport coordinates (scaled and in OpenGL format) int width, height; // viewport dimensions (scaled for display surface size) int priority; + float spotFogColor[3]; // spotlight color on fog + float scrollAtt; }; enum class Clip { INSIDE, OUTSIDE, INTERCEPT, NOT_SET }; diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index 4ca5129..af1b86c 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -97,15 +97,24 @@ void CNew3D::UploadTextures(unsigned level, unsigned x, unsigned y, unsigned wid void CNew3D::DrawScrollFog() { + + // the logic for this is still not quite right + // the sroll fog value seems to be set with multiple viewports.. currently unknown which one to use + for (int i = 0; i < 4; i++) { for (auto &n : m_nodes) { if (n.viewport.scrollFog > 0 && n.viewport.priority == i) { - float *rgb = n.viewport.fogParams; + float rgba[4] = {n.viewport.fogParams[0], n.viewport.fogParams[1], n.viewport.fogParams[2], n.viewport.scrollFog}; + float attenuation = n.viewport.scrollAtt; // Seems to pass the wrong values! + float ambient = n.viewport.fogParams[6]; + float *spotRGB = n.viewport.spotFogColor; + float *spotEllipse = n.viewport.spotEllipse; + glViewport(0, 0, m_totalXRes, m_totalYRes); // fill the whole viewport - m_r3dScrollFog.DrawScrollFog(rgb[0], rgb[1], rgb[2], n.viewport.scrollFog); + m_r3dScrollFog.DrawScrollFog(rgba, attenuation, ambient, spotRGB, spotEllipse); return; } @@ -752,27 +761,36 @@ void CNew3D::RenderViewport(UINT32 addr) // Spotlight int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index - vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF); // spotlight X position (fractional component?) - vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF); // spotlight Y - vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit? May have fractional component below bit 16) + int spotFogColorIdx = (vpnode[0x20] >> 8) & 7; // spotlight on fog color index + vp->spotEllipse[0] = (float)(INT16)(vpnode[0x1E] & 0xFFFF) / 8.0f; // spotlight X position (13.3 fixed point) + vp->spotEllipse[1] = (float)(INT16)(vpnode[0x1D] & 0xFFFF) / 8.0f; // spotlight Y + vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit) vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF); // spotlight Y size vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]); // spotlight start vp->spotRange[1] = *(float *)&vpnode[0x1F]; // spotlight extent - if (vp->spotRange[1] == 0) { // if light extent = 0 light is effectively disabled - spotColorIdx = 0; - } + // Star Wars Trilogy needs this + vp->spotRange[0] = std::min(vp->spotRange[0], std::numeric_limits::max()); + vp->spotRange[0] = std::max(vp->spotRange[0], std::numeric_limits::lowest()); vp->spotColor[0] = color[spotColorIdx][0]; // spotlight color vp->spotColor[1] = color[spotColorIdx][1]; vp->spotColor[2] = color[spotColorIdx][2]; - // Spotlight is applied on a per pixel basis, must scale its position and size to screen - vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; - vp->spotRange[1] += vp->spotRange[0]; // limit - vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]); // spotlight appears to be specified in terms of physical resolution (unconfirmed) - vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]); + vp->spotFogColor[0] = color[spotFogColorIdx][0]; // spotlight color on fog + vp->spotFogColor[1] = color[spotFogColorIdx][1]; + vp->spotFogColor[2] = color[spotFogColorIdx][2]; + + // spotlight is specified in terms of physical resolution + vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; // flip Y position + + // Avoid division by zero + vp->spotEllipse[2] = std::max(1.0f, vp->spotEllipse[2]); + vp->spotEllipse[3] = std::max(1.0f, vp->spotEllipse[3]); + + vp->spotEllipse[2] = std::roundf(2047.0f / vp->spotEllipse[2]); + vp->spotEllipse[3] = std::roundf(2047.0f / vp->spotEllipse[3]); // Scale the spotlight to the OpenGL viewport vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs; @@ -787,30 +805,16 @@ void CNew3D::RenderViewport(UINT32 addr) vp->fogParams[3] = std::abs(*(float *)&vpnode[0x23]); // fog density - ocean hunter uses negative values, but looks the same vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f); // fog start + // Avoid Infinite and NaN values for Star Wars Trilogy + if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3])) { + for (int i = 0; i < 7; i++) vp->fogParams[i] = 0.0f; + } + + vp->fogParams[5] = (float)((vpnode[0x24] >> 16) & 0xFF) * (1.0f / 255.0f); // fog attenuation + vp->fogParams[6] = (float)((vpnode[0x25] >> 16) & 0xFF) * (1.0f / 255.0f); // fog ambient + vp->scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f); // scroll fog - - // Unknown light/fog parameters - float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation - - { - //test fog paramaters - float lightFogColour[3]; - int fogColourIdx; - - fogColourIdx = (vpnode[0x20] >> 8) & 7; - - lightFogColour[0] = color[fogColourIdx][0]; - lightFogColour[1] = color[fogColourIdx][1]; - lightFogColour[2] = color[fogColourIdx][2]; - - float fogAttenuation = ((vpnode[0x24] >> 16) & 0xFF) / 255.f; - float fogAmbient = ((vpnode[0x25] >> 16) & 0xFF) / 255.f; - int debug = 0; - } - - if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) { // Star Wars Trilogy - vp->fogParams[3] = vp->fogParams[4] = 0.0f; - } + vp->scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation // Clear texture offsets before proceeding m_nodeAttribs.Reset(); diff --git a/Src/Graphics/New3D/R3DScrollFog.cpp b/Src/Graphics/New3D/R3DScrollFog.cpp index 9519a13..77400a1 100644 --- a/Src/Graphics/New3D/R3DScrollFog.cpp +++ b/Src/Graphics/New3D/R3DScrollFog.cpp @@ -12,17 +12,49 @@ static const char *vertexShaderFog = "{\n" "gl_Position = mvp * gl_Vertex;\n" "}\n"; - -static const char *fragmentShaderFog = - - "uniform vec4 fogColour;\n" - - "void main()\n" - "{\n" - "gl_FragColor = fogColour;\n" - "}\n"; - - + +static const char *fragmentShaderFog = + + "uniform float fogAttenuation;\n" + "uniform float fogAmbient;\n" + "uniform vec4 fogColour;\n" + "uniform vec3 spotFogColor;\n" + "uniform vec4 spotEllipse;\n" + + // Spotlight on fog + "float ellipse;\n" + "vec2 position, size;\n" + "vec3 lSpotFogColor;\n" + + // Scroll fog + "float lfogAttenuation;\n" + "vec3 lFogColor;\n" + "vec4 scrollFog;\n" + + "void main()\n" + "{\n" + // Scroll fog base color + "lFogColor = fogColour.rgb * fogAmbient;\n" + + // Spotlight on fog (area) + "position = spotEllipse.xy;\n" + "size = spotEllipse.zw;\n" + "ellipse = length((gl_FragCoord.xy - position) / size);\n" + "ellipse = pow(ellipse, 2.0);\n" // decay rate = square of distance from center + "ellipse = 1.0 - ellipse;\n" // invert + "ellipse = max(0.0, ellipse);\n" // clamp + + // Spotlight on fog (color) + "lSpotFogColor = mix(spotFogColor * ellipse * fogColour.rgb, vec3(0.0), fogAttenuation);\n" + + // Scroll fog density + "scrollFog = vec4(lFogColor + lSpotFogColor, fogColour.a);\n" + + // Final Color + "gl_FragColor = scrollFog;\n" + "}\n"; + + R3DScrollFog::R3DScrollFog() { //default coordinates are NDC -1,1 etc @@ -44,13 +76,13 @@ R3DScrollFog::R3DScrollFog() R3DScrollFog::~R3DScrollFog() { - DeallocResources(); -} - -void R3DScrollFog::DrawScrollFog(float r, float g, float b, float a) -{ - //======= - Mat4 mvp; + DeallocResources(); +} + +void R3DScrollFog::DrawScrollFog(float rgba[4], float attenuation, float ambient, float *spotRGB, float *spotEllipse) +{ + //======= + Mat4 mvp; //======= // yeah this would have been much easier with immediate mode and fixed function .. >_< @@ -60,13 +92,17 @@ void R3DScrollFog::DrawScrollFog(float r, float g, float b, float a) glDisable (GL_DEPTH_TEST); // disable depth testing glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - m_vbo.Bind (true); - glUseProgram (m_shaderProgram); - glUniform4f (m_locFogColour, r, g, b, a); - glUniformMatrix4fv (m_locMVP, 1, GL_FALSE, mvp); - - glEnableClientState (GL_VERTEX_ARRAY); + + m_vbo.Bind (true); + glUseProgram (m_shaderProgram); + glUniform4f (m_locFogColour, rgba[0], rgba[1], rgba[2], rgba[3]); + glUniform1f (m_locFogAttenuation, attenuation); + glUniform1f (m_locFogAmbient, ambient); + glUniform3f (m_locSpotFogColor, spotRGB[0], spotRGB[1], spotRGB[2]); + glUniform4f (m_locSpotEllipse, spotEllipse[0], spotEllipse[1], spotEllipse[2], spotEllipse[3]); + glUniformMatrix4fv (m_locMVP, 1, GL_FALSE, mvp); + + glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (3, GL_FLOAT, sizeof(SFVertex), 0); glDrawArrays (GL_TRIANGLES, 0, 6); glDisableClientState(GL_VERTEX_ARRAY); @@ -81,12 +117,16 @@ void R3DScrollFog::DrawScrollFog(float r, float g, float b, float a) void R3DScrollFog::AllocResources() { bool success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, std::string(), std::string(), vertexShaderFog, fragmentShaderFog); - - m_locMVP = glGetUniformLocation(m_shaderProgram, "mvp"); - m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour"); - - m_vbo.Create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(SFTriangle) * (2), m_triangles); -} + + m_locMVP = glGetUniformLocation(m_shaderProgram, "mvp"); + m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour"); + m_locFogAttenuation = glGetUniformLocation(m_shaderProgram, "fogAttenuation"); + m_locFogAmbient = glGetUniformLocation(m_shaderProgram, "fogAmbient"); + m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor"); + m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse"); + + m_vbo.Create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(SFTriangle) * (2), m_triangles); +} void R3DScrollFog::DeallocResources() { diff --git a/Src/Graphics/New3D/R3DScrollFog.h b/Src/Graphics/New3D/R3DScrollFog.h index 893607f..c44214d 100644 --- a/Src/Graphics/New3D/R3DScrollFog.h +++ b/Src/Graphics/New3D/R3DScrollFog.h @@ -9,13 +9,13 @@ class R3DScrollFog { public: - R3DScrollFog(); - ~R3DScrollFog(); - - void DrawScrollFog(float r, float g, float b, float a); - -private: - + R3DScrollFog(); + ~R3DScrollFog(); + + void DrawScrollFog(float rbga[4], float attenuation, float ambient, float *spotRGB, float *spotEllipse); + +private: + void AllocResources(); void DeallocResources(); @@ -42,12 +42,16 @@ private: GLuint m_shaderProgram; GLuint m_vertexShader; GLuint m_fragmentShader; - - GLuint m_locFogColour; - GLuint m_locMVP; - - VBO m_vbo; -}; + + GLuint m_locFogColour; + GLuint m_locMVP; + GLuint m_locFogAttenuation; + GLuint m_locFogAmbient; + GLuint m_locSpotFogColor; + GLuint m_locSpotEllipse; + + VBO m_vbo; +}; } diff --git a/Src/Graphics/New3D/R3DShader.cpp b/Src/Graphics/New3D/R3DShader.cpp index 1600c34..ae8afbb 100644 --- a/Src/Graphics/New3D/R3DShader.cpp +++ b/Src/Graphics/New3D/R3DShader.cpp @@ -2,30 +2,29 @@ #include "Graphics/Shader.h" namespace New3D { - -static const char *vertexShaderBasic = - + +static const char *vertexShaderBasic = + // uniforms "uniform float fogIntensity;\n" "uniform float fogDensity;\n" -"uniform float fogStart;\n" - -//outputs to fragment shader -"varying float fsFogFactor;\n" -"varying float fsSpecularTerm;\n" // specular light term (additive) -"varying vec3 fsViewVertex;\n" -"varying vec3 fsViewNormal;\n" // per vertex normal vector +"uniform float fogStart;\n" + +//outputs to fragment shader +"varying float fsFogFactor;\n" +"varying vec3 fsViewVertex;\n" +"varying vec3 fsViewNormal;\n" // per vertex normal vector "varying vec4 fsColor;\n" "void main(void)\n" -"{\n" - "fsViewVertex = vec3(gl_ModelViewMatrix * gl_Vertex);\n" - "fsViewNormal = normalize(gl_NormalMatrix *gl_Normal);\n" +"{\n" + "fsViewVertex = vec3(gl_ModelViewMatrix * gl_Vertex);\n" + "fsViewNormal = normalize(gl_NormalMatrix *gl_Normal);\n" "float z = length(fsViewVertex);\n" - "fsFogFactor = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);\n" - - "fsColor = gl_Color;\n" - "gl_TexCoord[0] = gl_MultiTexCoord0;\n" + "fsFogFactor = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);\n" + + "fsColor = gl_Color;\n" + "gl_TexCoord[0] = gl_MultiTexCoord0;\n" "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" "}\n"; @@ -41,40 +40,45 @@ static const char *fragmentShaderBasic = "uniform int alphaTest;\n" "uniform int textureAlpha;\n" "uniform vec3 fogColour;\n" -"uniform vec4 spotEllipse;\n" // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height) -"uniform vec2 spotRange;\n" // spotlight Z range: .x=start (viewspace coordinates), .y=limit -"uniform vec3 spotColor;\n" // spotlight RGB color -"uniform vec3 lighting[2];\n" // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0) -"uniform int lightEnable;\n" // lighting enabled (1.0) or luminous (0.0), drawn at full intensity -"uniform float specularCoefficient;\n" // specular coefficient -"uniform float shininess;\n" // specular shininess - -//interpolated inputs from vertex shader -"varying float fsFogFactor;\n" -"varying float fsSpecularTerm;\n" // specular light term (additive) -"varying vec3 fsViewVertex;\n" -"varying vec3 fsViewNormal;\n" // per vertex normal vector +"uniform vec4 spotEllipse;\n" // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height) +"uniform vec2 spotRange;\n" // spotlight Z range: .x=start (viewspace coordinates), .y=limit +"uniform vec3 spotColor;\n" // spotlight RGB color +"uniform vec3 spotFogColor;\n" // spotlight RGB color on fog +"uniform vec3 lighting[2];\n" // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0) +"uniform int lightEnable;\n" // lighting enabled (1.0) or luminous (0.0), drawn at full intensity +"uniform float specularCoefficient;\n" // specular coefficient +"uniform float shininess;\n" // specular shininess +"uniform float fogAttenuation;\n" +"uniform float fogAmbient;\n" + +//interpolated inputs from vertex shader +"varying float fsFogFactor;\n" +"varying vec3 fsViewVertex;\n" +"varying vec3 fsViewNormal;\n" // per vertex normal vector "varying vec4 fsColor;\n" "void main()\n" "{\n" - "vec4 tex1Data;\n" - "vec4 colData;\n" - "vec4 finalData;\n" - - "bool discardFragment = false;\n" - - "tex1Data = vec4(1.0, 1.0, 1.0, 1.0);\n" - - "if(textureEnabled==1) {\n" - - "tex1Data = texture2D( tex1, gl_TexCoord[0].st);\n" - - "if (microTexture==1) {\n" - "vec2 scale = baseTexSize/256.0;\n" - "vec4 tex2Data = texture2D( tex2, gl_TexCoord[0].st * scale * microTextureScale);\n" - - "tex1Data = (tex1Data+tex2Data)/2.0;\n" + "vec4 tex1Data;\n" + "vec4 colData;\n" + "vec4 finalData;\n" + "vec4 fogData;\n" + + "bool discardFragment = false;\n" + + "fogData = vec4(fogColour.rgb * fogAmbient, fsFogFactor);\n" + + "tex1Data = vec4(1.0, 1.0, 1.0, 1.0);\n" + + "if(textureEnabled==1) {\n" + + "tex1Data = texture2D( tex1, gl_TexCoord[0].st);\n" + + "if (microTexture==1) {\n" + "vec2 scale = baseTexSize/256.0;\n" + "vec4 tex2Data = texture2D( tex2, gl_TexCoord[0].st * scale * microTextureScale);\n" + + "tex1Data = (tex1Data+tex2Data)/2.0;\n" "}\n" "if (alphaTest==1) {\n" // does it make any sense to do this later? @@ -95,14 +99,20 @@ static const char *fragmentShaderBasic = "discardFragment = true;\n" "}\n" - "if (discardFragment) {\n" - "discard;\n" - "}\n" - - "if (lightEnable==1) {\n" - "vec3 lightIntensity;\n" - "vec3 sunVector;\n" // sun lighting vector (as reflecting away from vertex) - "float sunFactor;\n" // sun light projection along vertex normal (0.0 to 1.0) + "if (discardFragment) {\n" + "discard;\n" + "}\n" + + "float ellipse;\n" + "ellipse = length((gl_FragCoord.xy - spotEllipse.xy) / spotEllipse.zw);\n" + "ellipse = pow(ellipse, 2.0);\n" // decay rate = square of distance from center + "ellipse = 1.0 - ellipse;\n" // invert + "ellipse = max(0.0, ellipse);\n" // clamp + + "if (lightEnable==1) {\n" + "vec3 lightIntensity;\n" + "vec3 sunVector;\n" // sun lighting vector (as reflecting away from vertex) + "float sunFactor;\n" // sun light projection along vertex normal (0.0 to 1.0) // Real3D -> OpenGL view space convention (TO-DO: do this outside of shader) "sunVector = lighting[0] * vec3(1.0, -1.0, -1.0);\n" @@ -112,40 +122,43 @@ static const char *fragmentShaderBasic = // Total light intensity: sum of all components "lightIntensity = vec3(sunFactor*lighting[1].x + lighting[1].y);\n" // ambient + diffuse - - "lightIntensity = clamp(lightIntensity,0.0,1.0);\n" - - "vec2 ellipse;\n" - "float insideSpot;\n" - - // Compute spotlight and apply lighting - "ellipse = (gl_FragCoord.xy - spotEllipse.xy) / spotEllipse.zw;\n" - "insideSpot = dot(ellipse, ellipse);\n" - - "if ((insideSpot <= 1.0) && (-fsViewVertex.z >= spotRange.x)) {\n" - "lightIntensity.rgb += (1.0 - insideSpot)*spotColor;\n" - "}\n" - - "finalData.rgb *= lightIntensity;\n" - - "if (sunFactor > 0.0 && specularCoefficient > 0.0) {\n" - - "float nDotL = max(dot(fsViewNormal,sunVector),0.0);\n" - - "finalData.rgb += vec3(specularCoefficient * pow(nDotL,shininess));\n" - - //"vec3 v = normalize(-fsViewVertex);\n" - //"vec3 h = normalize(sunVector + v);\n" // halfway vector - //"float NdotHV = max(dot(fsViewNormal,h),0.0);\n" - //"finalData.rgb += vec3(specularCoefficient * pow(NdotHV,shininess));\n" - "}\n" - "}\n" - - - "finalData.rgb = mix(finalData.rgb, fogColour, fsFogFactor);\n" - - "gl_FragColor = finalData;\n" -"}\n"; + + "lightIntensity = clamp(lightIntensity,0.0,1.0);\n" + + // Compute spotlight and apply lighting + "float enable, range, d;\n" + "float inv_r = 1.0 / spotEllipse.z;\n" // slope of decay function + + "d = spotRange.x + spotRange.y + fsViewVertex.z;\n" + "enable = step(spotRange.x + min(spotRange.y, 0.0), -fsViewVertex.z);\n" + + // inverse-linear falloff + // Reference: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/ + // y = 1 / (d/r + 1)^2 + "range = 1.0 / pow(min(0.0, d * inv_r) - 1.0, 2.0);\n" + "range = clamp(range, 0.0, 1.0);\n" + "range *= enable;\n" + + "float lobeEffect = range * ellipse;\n" + + "lightIntensity.rgb += spotColor*lobeEffect;\n" + + "finalData.rgb *= lightIntensity;\n" + + "if (sunFactor > 0.0 && specularCoefficient > 0.0) {\n" + "float nDotL = max(dot(fsViewNormal,sunVector),0.0);\n" + "finalData.rgb += vec3(specularCoefficient * pow(nDotL,shininess));\n" + "}\n" + "}\n" + + // Spotlight on fog + "vec3 lSpotFogColor = spotFogColor * ellipse * fogColour.rgb;\n" + + // Fog & spotlight applied + "finalData.rgb = mix(finalData.rgb, lSpotFogColor * fogAttenuation + fogData.rgb, fogData.a);\n" + + "gl_FragColor = finalData;\n" +"}\n"; R3DShader::R3DShader() { @@ -211,20 +224,23 @@ bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader) m_locBaseTexSize = glGetUniformLocation(m_shaderProgram, "baseTexSize"); m_locFogIntensity = glGetUniformLocation(m_shaderProgram, "fogIntensity"); - m_locFogDensity = glGetUniformLocation(m_shaderProgram, "fogDensity"); - m_locFogStart = glGetUniformLocation(m_shaderProgram, "fogStart"); - m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour"); - - m_locLighting = glGetUniformLocation(m_shaderProgram, "lighting"); - m_locLightEnable = glGetUniformLocation(m_shaderProgram, "lightEnable"); + m_locFogDensity = glGetUniformLocation(m_shaderProgram, "fogDensity"); + m_locFogStart = glGetUniformLocation(m_shaderProgram, "fogStart"); + m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour"); + m_locFogAttenuation = glGetUniformLocation(m_shaderProgram, "fogAttenuation"); + m_locFogAmbient = glGetUniformLocation(m_shaderProgram, "fogAmbient"); + + m_locLighting = glGetUniformLocation(m_shaderProgram, "lighting"); + m_locLightEnable = glGetUniformLocation(m_shaderProgram, "lightEnable"); m_locShininess = glGetUniformLocation(m_shaderProgram, "shininess"); m_locSpecCoefficient= glGetUniformLocation(m_shaderProgram, "specularCoefficient"); - m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse"); - m_locSpotRange = glGetUniformLocation(m_shaderProgram, "spotRange"); - m_locSpotColor = glGetUniformLocation(m_shaderProgram, "spotColor"); - - return success; -} + m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse"); + m_locSpotRange = glGetUniformLocation(m_shaderProgram, "spotRange"); + m_locSpotColor = glGetUniformLocation(m_shaderProgram, "spotColor"); + m_locSpotFogColor = glGetUniformLocation(m_shaderProgram, "spotFogColor"); + + return success; +} void R3DShader::SetShader(bool enable) { @@ -331,17 +347,20 @@ void R3DShader::SetMeshUniforms(const Mesh* m) 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]); - glUniform3fv(m_locFogColour, 1, vp->fogParams); - - glUniform3fv(m_locLighting, 2, vp->lightingParams); - glUniform4fv(m_locSpotEllipse, 1, vp->spotEllipse); - glUniform2fv(m_locSpotRange, 1, vp->spotRange); - glUniform3fv(m_locSpotColor, 1, vp->spotColor); -} - -void R3DShader::SetModelStates(const Model* model) + glUniform1f (m_locFogDensity, vp->fogParams[3]); + glUniform1f (m_locFogStart, vp->fogParams[4]); + glUniform3fv(m_locFogColour, 1, vp->fogParams); + glUniform1f (m_locFogAttenuation, vp->fogParams[5]); + glUniform1f (m_locFogAmbient, vp->fogParams[6]); + + glUniform3fv(m_locLighting, 2, vp->lightingParams); + glUniform4fv(m_locSpotEllipse, 1, vp->spotEllipse); + glUniform2fv(m_locSpotRange, 1, vp->spotRange); + glUniform3fv(m_locSpotColor, 1, vp->spotColor); + glUniform3fv(m_locSpotFogColor, 1, vp->spotFogColor); +} + +void R3DShader::SetModelStates(const Model* model) { //========== MatDet test; diff --git a/Src/Graphics/New3D/R3DShader.h b/Src/Graphics/New3D/R3DShader.h index 867a29c..bad4636 100644 --- a/Src/Graphics/New3D/R3DShader.h +++ b/Src/Graphics/New3D/R3DShader.h @@ -59,20 +59,23 @@ private: // viewport uniform locations GLint m_locFogIntensity; - GLint m_locFogDensity; - GLint m_locFogStart; - GLint m_locFogColour; - - // lighting - GLint m_locLighting; + GLint m_locFogDensity; + GLint m_locFogStart; + GLint m_locFogColour; + GLint m_locFogAttenuation; + GLint m_locFogAmbient; + + // lighting + GLint m_locLighting; GLint m_locLightEnable; GLint m_locShininess; GLint m_locSpecCoefficient; - GLint m_locSpotEllipse; - GLint m_locSpotRange; - GLint m_locSpotColor; -}; - -} // New3D + GLint m_locSpotEllipse; + GLint m_locSpotRange; + GLint m_locSpotColor; + GLint m_locSpotFogColor; +}; + +} // New3D #endif \ No newline at end of file