mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Lighting: Take the specular viewer direction from the view matrix
The viewer is at infinity along view space +z, so in world space, where lighting happens, it's the view matrix's third column rather than (0,0,1): turning the camera moves the highlights (gpu/lighting/specular). The shaders read it from u_view. In a Need for Speed Carbon frame replayed on a PSP, this and the pow bring the error of the cars from MSE 957 to 120 (Vulkan). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
48f3d5c907
commit
6f6d3e2a81
6 files changed
+22
-11
No files matched your search
@@ -41,7 +41,7 @@ Lighter::Lighter(int vertType) {
|
||||
materialSpecular.GetFromRGB(gstate.materialspecular);
|
||||
materialSpecular.a = 1.0f;
|
||||
specCoef_ = PSPSpecularCoef(getFloat24(gstate.materialspecularcoef));
|
||||
// viewer_ = Vec3f(-gstate.viewMatrix[9], -gstate.viewMatrix[10], -gstate.viewMatrix[11]);
|
||||
viewDir_ = PSPViewDirection(gstate.viewMatrix);
|
||||
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
|
||||
materialUpdate_ = hasColor ? (gstate.materialupdate & 7) : 0;
|
||||
|
||||
@@ -148,13 +148,8 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
|
||||
Color4 lightDiff(lcolor[1][l], 0.0f);
|
||||
Color4 diff = (lightDiff * *diffuse) * dot;
|
||||
|
||||
// Real PSP specular
|
||||
static const Vec3f toViewer(0, 0, 1);
|
||||
// Better specular
|
||||
// Vec3f toViewer = (viewer - pos).NormalizedOr001(cpu_info.bSSE4_1);
|
||||
|
||||
if (doSpecular && facingLight) {
|
||||
Vec3f halfVec = (toLight + toViewer).NormalizedOr001(cpu_info.bSSE4_1);
|
||||
Vec3f halfVec = (toLight + viewDir_).NormalizedOr001(cpu_info.bSSE4_1);
|
||||
|
||||
dot = Dot(halfVec, norm);
|
||||
if (dot > 0.0f) {
|
||||
|
||||
@@ -85,6 +85,11 @@ inline float PSPSpecularCoef(float e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
// The viewer is at infinity along view space +z, so in world space it's the view matrix's third column.
|
||||
inline Vec3f PSPViewDirection(const float viewMatrix[12]) {
|
||||
return Vec3f(viewMatrix[2], viewMatrix[5], viewMatrix[8]).NormalizedOr001(false);
|
||||
}
|
||||
|
||||
// Convenient way to do precomputation to save the parts of the lighting calculation
|
||||
// that's common between the many vertices of a draw call.
|
||||
class Lighter {
|
||||
@@ -106,7 +111,7 @@ private:
|
||||
Color4 materialDiffuse;
|
||||
Color4 materialSpecular;
|
||||
float specCoef_;
|
||||
// Vec3f viewer_;
|
||||
Vec3f viewDir_;
|
||||
bool doShadeMapping_;
|
||||
int materialUpdate_;
|
||||
|
||||
|
||||
@@ -500,6 +500,14 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
} else {
|
||||
WRITE(p, " mediump vec3 worldnormal = normalizeOr001(mul(vec4(0.0, 0.0, %s1.0, 0.0), u_world).xyz);\n", flipNormal ? "-" : "");
|
||||
}
|
||||
if (enableLighting) {
|
||||
// The viewer is at infinity along view space +z: in world space, the view matrix's third column.
|
||||
if (compat.shaderLanguage == HLSL_D3D11) {
|
||||
WRITE(p, " mediump vec3 viewDir = normalizeOr001(vec3(u_view[0].z, u_view[1].z, u_view[2].z));\n");
|
||||
} else {
|
||||
WRITE(p, " mediump vec3 viewDir = normalizeOr001(u_view[2].xyz);\n");
|
||||
}
|
||||
}
|
||||
|
||||
WRITE(p, " vec4 viewPos = vec4(mul(vec4(worldpos, 1.0), u_view).xyz, 1.0);\n");
|
||||
if (useSimpleStereo) {
|
||||
@@ -668,7 +676,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
p.F(" diffuse = (u_lightdiffuse%s * diffuseColor) * max(ldot, 0.0);\n", iStr);
|
||||
p.C(" if (comp == 0x1u && ldot >= 0.0) {\n"); // do specular. note - must allow for the >= case, since the u_matspecular.a <= 0.0 case relies on it.
|
||||
p.C(" if (u_matspecular.a > 0.0) {\n");
|
||||
p.C(" vec3 halfVec = toLight + vec3(0.0, 0.0, 1.0);\n");
|
||||
p.C(" vec3 halfVec = toLight + viewDir;\n");
|
||||
p.C(" float halfInvLen = inversesqrt(dot(halfVec, halfVec));\n");
|
||||
p.C(" ldot = pspPow(dot(halfVec, worldnormal) * halfInvLen, u_matspecular.a);\n");
|
||||
p.C(" } else {\n");
|
||||
@@ -748,7 +756,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
if (doSpecular) {
|
||||
p.C(" if (ldot >= 0.0) {\n");
|
||||
p.C(" if (u_matspecular.a > 0.0) {\n");
|
||||
p.C(" vec3 halfVec = toLight + vec3(0.0, 0.0, 1.0);\n");
|
||||
p.C(" vec3 halfVec = toLight + viewDir;\n");
|
||||
p.C(" float halfInvLen = inversesqrt(dot(halfVec, halfVec));\n");
|
||||
p.C(" ldot = pspPow(dot(halfVec, worldnormal) * halfInvLen, u_matspecular.a);\n");
|
||||
p.C(" } else {\n");
|
||||
|
||||
@@ -369,7 +369,7 @@ static void ProcessSIMD(VertexData &vertex, const WorldCoords &worldpos, const W
|
||||
}
|
||||
|
||||
if (lstate.specular && diffuse_factor >= 0.0f) {
|
||||
Vec3<float> H = L + Vec3<float>(0.f, 0.f, 1.f);
|
||||
Vec3<float> H = L + state.viewDir;
|
||||
|
||||
float specular_factor = Dot33(H.NormalizedOr001(useSSE4), worldnormal);
|
||||
specular_factor = pspLightPow(specular_factor, state.specularExp);
|
||||
|
||||
@@ -53,6 +53,7 @@ struct State {
|
||||
|
||||
Vec4<int> baseAmbientColorFactor;
|
||||
float specularExp;
|
||||
Vec3f viewDir;
|
||||
|
||||
struct {
|
||||
bool colorForAmbient : 1;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
#include "GPU/Common/VertexDecoderCommon.h"
|
||||
#include "GPU/Common/SoftwareTransformCommon.h"
|
||||
#include "GPU/Common/TransformCommon.h"
|
||||
#include "GPU/Common/VertexReader.h"
|
||||
#include "GPU/GPUStateSIMDUtil.h"
|
||||
#include "Common/Math/SIMDHeaders.h"
|
||||
@@ -259,6 +260,7 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) {
|
||||
} else {
|
||||
state->lightingState.usesWorldNormal = state->uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP;
|
||||
}
|
||||
state->lightingState.viewDir = PSPViewDirection(gstate.viewMatrix);
|
||||
|
||||
float world[16];
|
||||
float view[16];
|
||||
|
||||
Reference in new issue
Block a user