Shader simplification - well, more of it. Hopefully this helps the mali problems a bit more.

This commit is contained in:
Henrik Rydgard 2013-05-22 15:44:15 +02:00
parent 0ed09532f9
commit 199907b9ed
2 changed files with 61 additions and 63 deletions

View file

@ -196,8 +196,12 @@ void GenerateFragmentShader(char *buffer) {
WRITE(p, "varying vec2 v_texcoord;\n");
}
WRITE(p, "float roundAndScaleTo255f(in float x) { return floor(x * 255.0 + 0.5); }\n");
WRITE(p, "vec3 roundAndScaleTo255v(in vec3 x) { return floor(x * 255.0 + 0.5); }\n");
if (enableAlphaTest) {
WRITE(p, "float roundAndScaleTo255f(in float x) { return floor(x * 255.0 + 0.5); }\n");
}
if (enableColorTest) {
WRITE(p, "vec3 roundAndScaleTo255v(in vec3 x) { return floor(x * 255.0 + 0.5); }\n");
}
WRITE(p, "void main() {\n");

View file

@ -116,17 +116,6 @@ static const char * const boneWeightAttrDecl[8] = {
"attribute mediump vec4 a_w1;\nattribute mediump vec4 a_w2;\n",
};
static const char * const boneWeightAttr[8] = {
"a_w1.x",
"a_w1.y",
"a_w1.z",
"a_w1.w",
"a_w2.x",
"a_w2.y",
"a_w2.z",
"a_w2.w",
};
enum DoLightComputation {
LIGHT_OFF,
LIGHT_SHADE,
@ -300,24 +289,44 @@ void GenerateVertexShader(int prim, char *buffer) {
// No skinning, just standard T&L.
WRITE(p, " vec3 worldpos = (u_world * vec4(a_position.xyz, 1.0)).xyz;\n");
if (hasNormal)
WRITE(p, " vec3 worldnormal = (u_world * vec4(a_normal, 0.0)).xyz;\n");
WRITE(p, " vec3 worldnormal = normalize((u_world * vec4(a_normal, 0.0)).xyz);\n");
else
WRITE(p, " vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n");
} else {
int numWeights = 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT);
static const float rescale[4] = {0, 2*127.5f/128.f, 2*32767.5f/32768.f, 2.0f};
float factor = rescale[(vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT];
static const char * const boneWeightAttr[8] = {
"bw1.x", "bw1.y", "bw1.z", "bw1.w",
"bw2.x", "bw2.y", "bw2.z", "bw2.w",
};
switch (numWeights) {
case 1: WRITE(p, " float bw1 = a_w1 * %f;\n", factor); break;
case 2: WRITE(p, " vec2 bw1 = a_w1 * %f;\n", factor); break;
case 3: WRITE(p, " vec3 bw1 = a_w1 * %f;\n", factor); break;
case 4: WRITE(p, " vec4 bw1 = a_w1 * %f;\n", factor); break;
case 5: WRITE(p, " vec4 bw1 = a_w1 * %f; float bw2 = a_w2 * %f;\n", factor, factor); break;
case 6: WRITE(p, " vec4 bw1 = a_w1 * %f; vec2 bw2 = a_w2 * %f;\n", factor, factor); break;
case 7: WRITE(p, " vec4 bw1 = a_w1 * %f; vec3 bw2 = a_w2 * %f;\n", factor, factor); break;
case 8: WRITE(p, " vec4 bw1 = a_w1 * %f; vec4 bw2 = a_w2 * %f;\n", factor, factor); break;
}
#ifdef USE_FOR_LOOP
// To loop through the weights, we unfortunately need to put them in a float array.
// GLSL ES sucks - no way to directly initialize an array!
switch (numWeights) {
case 1: WRITE(p, " float w[1]; w[0] = a_w1;\n"); break;
case 2: WRITE(p, " float w[2]; w[0] = a_w1.x; w[1] = a_w1.y;\n"); break;
case 3: WRITE(p, " float w[3]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z;\n"); break;
case 4: WRITE(p, " float w[4]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w;\n"); break;
case 5: WRITE(p, " float w[5]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2;\n"); break;
case 6: WRITE(p, " float w[6]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y;\n"); break;
case 7: WRITE(p, " float w[7]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y; w[6] = a_w2.z;\n"); break;
case 8: WRITE(p, " float w[8]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y; w[6] = a_w2.z; w[7] = a_w2.w;\n"); break;
case 1: WRITE(p, " float w[1]; w[0] = bw1;\n"); break;
case 2: WRITE(p, " float w[2]; w[0] = bw1.x; w[1] = bw1.y;\n"); break;
case 3: WRITE(p, " float w[3]; w[0] = bw1.x; w[1] = bw1.y; w[2] = bw1.z;\n"); break;
case 4: WRITE(p, " float w[4]; w[0] = bw1.x; w[1] = bw1.y; w[2] = bw1.z; w[3] = bw1.w;\n"); break;
case 5: WRITE(p, " float w[5]; w[0] = bw1.x; w[1] = bw1.y; w[2] = bw1.z; w[3] = bw1.w; w[4] = bw2;\n"); break;
case 6: WRITE(p, " float w[6]; w[0] = bw1.x; w[1] = bw1.y; w[2] = bw1.z; w[3] = bw1.w; w[4] = bw2.x; w[5] = bw2.y;\n"); break;
case 7: WRITE(p, " float w[7]; w[0] = bw1.x; w[1] = bw1.y; w[2] = bw1.z; w[3] = bw1.w; w[4] = bw2.x; w[5] = bw2.y; w[6] = bw2.z;\n"); break;
case 8: WRITE(p, " float w[8]; w[0] = bw1.x; w[1] = bw1.y; w[2] = bw1.z; w[3] = bw1.w; w[4] = bw2.x; w[5] = bw2.y; w[6] = bw2.z; w[7] = bw2.w;\n"); break;
}
WRITE(p, " mat4 skinMatrix = w[0] * u_bone[0];\n");
@ -329,49 +338,37 @@ void GenerateVertexShader(int prim, char *buffer) {
#else
if (numWeights == 1)
WRITE(p, " mat4 skinMatrix = a_w1 * u_bone[0];\n");
WRITE(p, " mat4 skinMatrix = bw1 * u_bone[0]");
else
WRITE(p, " mat4 skinMatrix = a_w1.x * u_bone[0];\n");
WRITE(p, " mat4 skinMatrix = bw1.x * u_bone[0]");
for (int i = 1; i < numWeights; i++) {
const char *weightAttr = boneWeightAttr[i];
// workaround for "cant do .x of scalar" issue
if (numWeights == 1 && i == 0) weightAttr = "a_w1";
if (numWeights == 5 && i == 4) weightAttr = "a_w2";
WRITE(p, " skinMatrix += %s * u_bone[%i];\n", weightAttr, i);
if (numWeights == 1 && i == 0) weightAttr = "bw1";
if (numWeights == 5 && i == 4) weightAttr = "bw2";
WRITE(p, " + %s * u_bone[%i]", weightAttr, i);
}
#endif
WRITE(p, ";\n");
WRITE(p, " vec3 worldpos = (skinMatrix * vec4(a_position, 1.0)).xyz;\n");
WRITE(p, " vec3 worldpos = (u_world * (skinMatrix * vec4(a_position, 1.0))).xyz;\n");
if (hasNormal)
WRITE(p, " vec3 worldnormal = (skinMatrix * vec4(a_normal, 0.0)).xyz;\n");
WRITE(p, " vec3 worldnormal = normalize((u_world * (skinMatrix * vec4(a_normal, 0.0))).xyz);\n");
else
WRITE(p, " vec3 worldnormal = (skinMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz;\n");
static const float rescale[4] = {0, 2*127.5f/128.f, 2*32767.5f/32768.f, 2.0f};
float factor = rescale[(vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT];
// Finally, multiply by world matrix and compensate for quantization at the same time.
WRITE(p, " worldpos = (u_world * vec4(worldpos * %f, 1.0)).xyz;\n", factor);
if (hasNormal)
WRITE(p, " worldnormal = (u_world * vec4(worldnormal, 0.0)).xyz;\n");
WRITE(p, " vec3 worldnormal = (u_world * (skinMatrix * vec4(0.0, 0.0, 1.0, 0.0))).xyz;\n");
}
if (hasNormal)
WRITE(p, " worldnormal = normalize(worldnormal);\n");
WRITE(p, " vec4 viewPos = u_view * vec4(worldpos, 1.0);\n");
// Step 2: Color/Lighting
if (hasColor) {
WRITE(p, " lowp vec3 unlitColor = a_color0.rgb;\n");
} else {
WRITE(p, " lowp vec3 unlitColor = u_matambientalpha.rgb;\n");
}
// Final view and projection transforms.
WRITE(p, " gl_Position = u_proj * viewPos;\n");
// TODO: Declare variables for dots for shade mapping if needed.
const char *ambientStr = (gstate.materialupdate & 1) ? (hasColor ? "a_color0" : "u_matambientalpha") : "u_matambientalpha";
const char *diffuseStr = (gstate.materialupdate & 2) ? "unlitColor" : "u_matdiffuse";
const char *specularStr = (gstate.materialupdate & 4) ? "unlitColor" : "u_matspecular.rgb";
const char *diffuseStr = (gstate.materialupdate & 2) ? (hasColor ? "a_color0.rgb" : "u_matambientalpha.rgb") : "u_matdiffuse";
const char *specularStr = (gstate.materialupdate & 4) ? (hasColor ? "a_color0.rgb" : "u_matambientalpha.rgb") : "u_matspecular.rgb";
bool diffuseIsZero = true;
bool specularIsZero = true;
@ -416,34 +413,34 @@ void GenerateVertexShader(int prim, char *buffer) {
GELightType type = (GELightType)((gstate.ltype[i] >> 8) & 3);
if (type == GE_LIGHTTYPE_DIRECTIONAL)
WRITE(p, " toLight = u_lightpos%i;\n", i);
else
WRITE(p, " toLight = normalize(u_lightpos%i);\n", i);
else {
WRITE(p, " toLight = u_lightpos%i - worldpos;\n", i);
WRITE(p, " distance = length(toLight);\n");
WRITE(p, " toLight /= distance;\n");
}
bool doSpecular = (comp != GE_LIGHTCOMP_ONLYDIFFUSE);
bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE;
if (poweredDiffuse) {
WRITE(p, " mediump float dot%i = pow(dot(normalize(toLight), worldnormal), u_matspecular.a);\n", i, i);
WRITE(p, " mediump float dot%i = pow(dot(toLight, worldnormal), u_matspecular.a);\n", i, i);
} else {
WRITE(p, " mediump float dot%i = dot(normalize(toLight), worldnormal);\n", i);
WRITE(p, " mediump float dot%i = dot(toLight, worldnormal);\n", i);
}
char timesLightScale[128];
sprintf(timesLightScale, " * lightScale");
const char *timesLightScale = " * lightScale";
// Attenuation
switch (type) {
case GE_LIGHTTYPE_DIRECTIONAL:
timesLightScale[0] = 0;
timesLightScale = "";
break;
case GE_LIGHTTYPE_POINT:
WRITE(p, " distance = length(toLight);\n", i, i);
WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i);
break;
case GE_LIGHTTYPE_SPOT:
WRITE(p, " distance = length(toLight);\n", i, i);
WRITE(p, " lowp float angle%i = dot(normalize(u_lightdir%i), normalize(toLight));\n", i, i, i);
WRITE(p, " lowp float angle%i = dot(normalize(u_lightdir%i), toLight);\n", i, i, i);
WRITE(p, " if (angle%i >= u_lightangle%i) {\n", i, i);
WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle%i, u_lightspotCoef%i);\n", i, i, i);
WRITE(p, " } else {\n");
@ -457,12 +454,12 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, " diffuse = (u_lightdiffuse%i * %s) * max(dot%i, 0.0);\n", i, diffuseStr, i);
if (doSpecular) {
WRITE(p, " halfVec = normalize(normalize(toLight) + vec3(0.0, 0.0, 1.0));\n", i, i);
WRITE(p, " halfVec = normalize(toLight + vec3(0.0, 0.0, 1.0));\n", i, i);
WRITE(p, " dot%i = dot(halfVec, worldnormal);\n", i, i);
WRITE(p, " if (dot%i > 0.0)\n", i);
WRITE(p, " lightSum1 += u_lightspecular%i * %s * (pow(dot%i, u_matspecular.a) %s);\n", i, specularStr, i, timesLightScale);
}
WRITE(p, " lightSum0.rgb += (u_lightambient%i + diffuse) %s;\n", i, timesLightScale);
WRITE(p, " lightSum0.rgb += (u_lightambient%i + diffuse)%s;\n", i, timesLightScale);
}
if (gstate.isLightingEnabled()) {
@ -548,9 +545,6 @@ void GenerateVertexShader(int prim, char *buffer) {
// Compute fogdepth
if (enableFog)
WRITE(p, " v_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n");
// Step 4: Final view and projection transforms.
WRITE(p, " gl_Position = u_proj * viewPos;\n");
}
WRITE(p, "}\n");
}