Add support for spotlights

This commit is contained in:
BeaR 2013-04-09 18:25:22 +02:00
parent cf5f049abd
commit fa3a1fbd52
6 changed files with 67 additions and 8 deletions

View file

@ -654,6 +654,29 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
}
break;
case GE_CMD_LKS0:
case GE_CMD_LKS1:
case GE_CMD_LKS2:
case GE_CMD_LKS3:
{
int l = cmd - GE_CMD_LKS0;
gstate_c.lightspotCoef[l] = getFloat24(data);
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
break;
case GE_CMD_LKO0:
case GE_CMD_LKO1:
case GE_CMD_LKO2:
case GE_CMD_LKO3:
{
int l = cmd - GE_CMD_LKO0;
gstate_c.lightangle[l] = getFloat24(data);
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
break;
case GE_CMD_LAC0:case GE_CMD_LAC1:case GE_CMD_LAC2:case GE_CMD_LAC3:
case GE_CMD_LDC0:case GE_CMD_LDC1:case GE_CMD_LDC2:case GE_CMD_LDC3:

View file

@ -119,6 +119,10 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs)
u_lightdir[i] = glGetUniformLocation(program, temp);
sprintf(temp, "u_lightatt%i", i);
u_lightatt[i] = glGetUniformLocation(program, temp);
sprintf(temp, "u_lightangle%i", i);
u_lightangle[i] = glGetUniformLocation(program, temp);
sprintf(temp, "u_lightspotCoef%i", i);
u_lightspotCoef[i] = glGetUniformLocation(program, temp);
sprintf(temp, "u_lightambient%i", i);
u_lightambient[i] = glGetUniformLocation(program, temp);
sprintf(temp, "u_lightdiffuse%i", i);
@ -324,6 +328,8 @@ void LinkedShader::updateUniforms() {
if (u_lightpos[i] != -1) glUniform3fv(u_lightpos[i], 1, gstate_c.lightpos[i]);
if (u_lightdir[i] != -1) glUniform3fv(u_lightdir[i], 1, gstate_c.lightdir[i]);
if (u_lightatt[i] != -1) glUniform3fv(u_lightatt[i], 1, gstate_c.lightatt[i]);
if (u_lightangle[i] != -1) glUniform1f(u_lightangle[i], gstate_c.lightangle[i]);
if (u_lightspotCoef[i] != -1) glUniform1f(u_lightspotCoef[i], gstate_c.lightspotCoef[i]);
if (u_lightambient[i] != -1) glUniform3fv(u_lightambient[i], 1, gstate_c.lightColor[0][i]);
if (u_lightdiffuse[i] != -1) glUniform3fv(u_lightdiffuse[i], 1, gstate_c.lightColor[1][i]);
if (u_lightspecular[i] != -1) glUniform3fv(u_lightspecular[i], 1, gstate_c.lightColor[2][i]);

View file

@ -74,6 +74,8 @@ public:
int u_lightpos[4];
int u_lightdir[4];
int u_lightatt[4]; // attenuation
int u_lightangle[4]; // spotlight cone angle (cosine)
int u_lightspotCoef[4]; // spotlight dropoff
int u_lightdiffuse[4]; // each light consist of vec4[3]
int u_lightspecular[4]; // attenuation
int u_lightambient[4]; // attenuation

View file

@ -288,8 +288,7 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
float distanceToLight = toLight.Length();
float dot = 0.0f;
if (distanceToLight > 0.0f)
{
if (distanceToLight > 0.0f) {
toLight /= distanceToLight;
dot = toLight * norm;
}
@ -300,12 +299,21 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
dot = powf(dot, specCoef_);
float lightScale = 1.0f;
if (type != GE_LIGHTTYPE_DIRECTIONAL)
{
if (type != GE_LIGHTTYPE_DIRECTIONAL) {
lightScale = 1.0f / (gstate_c.lightatt[l][0] + gstate_c.lightatt[l][1]*distanceToLight + gstate_c.lightatt[l][2]*distanceToLight*distanceToLight);
if (lightScale > 1.0f) lightScale = 1.0f;
}
if (type == GE_LIGHTTYPE_SPOT) {
Vec3 lightDir = gstate_c.lightdir[l];
lightDir.Normalize();
float angle = toLight * lightDir;
if (angle < gstate_c.lightangle[l])
lightScale = 0.0f;
else
lightScale *= powf(angle, gstate_c.lightspotCoef[l]);
}
Color4 lightDiff(gstate_c.lightColor[1][l], 0.0f);
Color4 diff = (lightDiff * *diffuse) * (dot * lightScale);

View file

@ -230,6 +230,8 @@ void GenerateVertexShader(int prim, char *buffer) {
// These are needed for the full thing
WRITE(p, "uniform vec3 u_lightdir%i;\n", i);
WRITE(p, "uniform vec3 u_lightatt%i;\n", i);
WRITE(p, "uniform float u_lightangle%i;\n", i);
WRITE(p, "uniform float u_lightspotCoef%i;\n", i);
WRITE(p, "uniform lowp vec3 u_lightambient%i;\n", i);
WRITE(p, "uniform lowp vec3 u_lightdiffuse%i;\n", i);
@ -336,12 +338,28 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, " dot%i = pow(dot%i, u_matspecular.a);\n", i, i);
}
WRITE(p, " float lightScale%i = 1.0;\n", i);
if (type != GE_LIGHTTYPE_DIRECTIONAL) {
// Attenuation
// Attenuation
switch (type) {
case GE_LIGHTTYPE_DIRECTIONAL:
WRITE(p, " float lightScale%i = 1.0;\n", i);
break;
case GE_LIGHTTYPE_POINT:
WRITE(p, " float distance%i = length(toLight%i);\n", i, i);
WRITE(p, " lightScale%i = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance%i, distance%i*distance%i)), 0.0, 1.0);\n", i, i, i, i, i);
WRITE(p, " float lightScale%i = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance%i, distance%i*distance%i)), 0.0, 1.0);\n", i, i, i, i, i);
break;
case GE_LIGHTTYPE_SPOT:
WRITE(p, " float lightScale%i = 0.0;\n", i);
WRITE(p, " float angle%i = dot(normalize(u_lightdir%i), normalize(toLight%i));\n", i, i, i);
WRITE(p, " if (angle%i >= u_lightangle%i) {\n", i, i);
WRITE(p, " float distance%i = length(toLight%i);\n", i, i);
WRITE(p, " lightScale%i = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance%i, distance%i*distance%i)), 0.0, 1.0) * pow(angle%i, u_lightspotCoef%i);\n", i, i, i, i, i, i, i);
WRITE(p, " }\n");
break;
default:
// ILLEGAL
break;
}
WRITE(p, " vec3 diffuse%i = (u_lightdiffuse%i * %s) * (max(dot%i, 0.0) * lightScale%i);\n", i, i, diffuse, i, i);
if (doSpecular) {
WRITE(p, " vec3 halfVec%i = normalize(normalize(toLight%i) + vec3(0.0, 0.0, 1.0));\n", i, i);

View file

@ -264,6 +264,8 @@ struct GPUStateCache
float lightdir[4][3];
float lightatt[4][3];
float lightColor[3][4][3]; // Ambient Diffuse Specular
float lightangle[4]; // spotlight cone angle (cosine)
float lightspotCoef[4]; // spotlight dropoff
float morphWeights[8];
u32 curTextureWidth;