GPU: Skip specular on negative diffuse factor.

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.
This commit is contained in:
Unknown W. Brackets 2018-11-22 08:15:40 -08:00
parent 6e46d6c0f9
commit 4816bfc1a6
4 changed files with 22 additions and 16 deletions

View File

@ -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.)
@ -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);
}

View File

@ -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.)
@ -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);
}

View File

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

View File

@ -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.)
@ -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);
}