Skip to content

Commit

Permalink
GPU: Skip specular on negative diffuse factor.
Browse files Browse the repository at this point in the history
This is correct per hardware tests, see #8403.  Note that the PS3 emulator
running PSP HD remasters does not correctly handle this, and applies
specular for negative diffuse factor.
  • Loading branch information
unknownbrackets committed Nov 22, 2018
1 parent 6e46d6c commit 4816bfc
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 16 deletions.
12 changes: 7 additions & 5 deletions GPU/Directx9/VertexShaderGeneratorDX9.cpp
Expand Up @@ -582,7 +582,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
bool doSpecular = comp == GE_LIGHTCOMP_BOTH;
bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE;

WRITE(p, " ldot = max(dot(toLight, worldnormal), 0.0);\n");
WRITE(p, " ldot = dot(toLight, worldnormal);\n");
if (poweredDiffuse) {
// pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0.
// Seen in Tales of the World: Radiant Mythology (#2424.)
Expand Down Expand Up @@ -617,11 +617,13 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
break;
}

WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * ldot;\n", i, diffuseStr);
WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr);
if (doSpecular) {
WRITE(p, " ldot = dot(normalize(toLight + float3(0.0, 0.0, 1.0)), worldnormal);\n");
WRITE(p, " if (ldot > 0.0)\n");
WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale);
WRITE(p, " if (ldot >= 0.0) {\n");
WRITE(p, " ldot = dot(normalize(toLight + float3(0.0, 0.0, 1.0)), worldnormal);\n");
WRITE(p, " if (ldot > 0.0)\n");
WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale);
WRITE(p, " }\n");
}
WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale);
}
Expand Down
12 changes: 7 additions & 5 deletions GPU/GLES/VertexShaderGeneratorGLES.cpp
Expand Up @@ -676,7 +676,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
bool doSpecular = comp == GE_LIGHTCOMP_BOTH;
bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE;

WRITE(p, " ldot = max(dot(toLight, worldnormal), 0.0);\n");
WRITE(p, " ldot = dot(toLight, worldnormal);\n");
if (poweredDiffuse) {
// pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0.
// Seen in Tales of the World: Radiant Mythology (#2424.)
Expand Down Expand Up @@ -711,11 +711,13 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
break;
}

WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * ldot;\n", i, diffuseStr);
WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr);
if (doSpecular) {
WRITE(p, " ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n");
WRITE(p, " if (ldot > 0.0)\n");
WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale);
WRITE(p, " if (ldot >= 0.0) {\n");
WRITE(p, " ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n");
WRITE(p, " if (ldot > 0.0)\n");
WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(ldot, u_matspecular.a) %s);\n", i, specularStr, timesLightScale);
WRITE(p, " }\n");
}
WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale);
}
Expand Down
2 changes: 1 addition & 1 deletion GPU/Software/Lighting.cpp
Expand Up @@ -117,7 +117,7 @@ void Process(VertexData& vertex, bool hasColor) {
final_color += ldc * mdc * diffuse_factor * att * spot;
}

if (gstate.isUsingSpecularLight(light)) {
if (gstate.isUsingSpecularLight(light) && diffuse_factor >= 0.0f) {
Vec3<float> H = L + Vec3<float>(0.f, 0.f, 1.f);

Vec3<float> lsc = Vec3<float>::FromRGB(gstate.getSpecularColor(light));
Expand Down
12 changes: 7 additions & 5 deletions GPU/Vulkan/VertexShaderGeneratorVulkan.cpp
Expand Up @@ -465,7 +465,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
bool doSpecular = comp == GE_LIGHTCOMP_BOTH;
bool poweredDiffuse = comp == GE_LIGHTCOMP_ONLYPOWDIFFUSE;

WRITE(p, " mediump float dot%i = max(dot(toLight, worldnormal), 0.0);\n", i);
WRITE(p, " mediump float dot%i = dot(toLight, worldnormal);\n", i);
if (poweredDiffuse) {
// pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0.
// Seen in Tales of the World: Radiant Mythology (#2424.)
Expand Down Expand Up @@ -500,11 +500,13 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
break;
}

WRITE(p, " diffuse = (light.diffuse[%i] * %s) * dot%i;\n", i, diffuseStr, i);
WRITE(p, " diffuse = (light.diffuse[%i] * %s) * max(dot%i, 0.0);\n", i, diffuseStr, i);
if (doSpecular) {
WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i);
WRITE(p, " if (dot%i > 0.0)\n", i);
WRITE(p, " lightSum1 += light.specular[%i] * %s * (pow(dot%i, light.matspecular.a) %s);\n", i, specularStr, i, timesLightScale);
WRITE(p, " if (dot%i >= 0.0) {\n", i);
WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i);
WRITE(p, " if (dot%i > 0.0)\n", i);
WRITE(p, " lightSum1 += light.specular[%i] * %s * (pow(dot%i, light.matspecular.a) %s);\n", i, specularStr, i, timesLightScale);
WRITE(p, " }\n");
}
WRITE(p, " lightSum0.rgb += (light.ambient[%i] * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale);
}
Expand Down

0 comments on commit 4816bfc

Please sign in to comment.