Commits

Michael Ludwig committed f26d62a

Significantly improve performance of FFP emulator by moving normal matrix computation to the CPU, and spotlight cos computation to the CPU, and switching back to single-sided lighting.

Comments (0)

Files changed (6)

ferox-renderer-jogl/src/main/java/com/ferox/renderer/impl/jogl/JoglFixedFunctionRenderer.java

 
     // state tracking
     private boolean alphaTestEnabled;
-    private boolean twosidedLighting;
 
     private GL2 gl;
 
 
         transferBuffer = BufferUtil.newByteBuffer(DataType.FLOAT, 16).asFloatBuffer();
         alphaTestEnabled = false;
-        twosidedLighting = false;
     }
 
     @Override
     }
 
     @Override
-    public void setDrawStyle(DrawStyle front, DrawStyle back) {
-        super.setDrawStyle(front, back);
-
-        if (back != DrawStyle.NONE && !twosidedLighting) {
-            gl.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_TRUE);
-            twosidedLighting = true;
-        } else if (back == DrawStyle.NONE && twosidedLighting) {
-            gl.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_FALSE);
-            twosidedLighting = false;
-        }
-    }
-
-    @Override
     protected void glMatrixMode(MatrixMode mode) {
         switch (mode) {
         case MODELVIEW:

ferox-renderer-lwjgl/src/main/java/com/ferox/renderer/impl/lwjgl/LwjglFixedFunctionRenderer.java

 
     // state tracking
     private boolean alphaTestEnabled;
-    private boolean twosidedLighting;
 
     public LwjglFixedFunctionRenderer(LwjglContext context, LwjglRendererDelegate delegate) {
         super(context, delegate);
 
         transferBuffer = BufferUtil.newByteBuffer(DataType.FLOAT, 16).asFloatBuffer();
         alphaTestEnabled = false;
-        twosidedLighting = false;
     }
 
     @Override
     }
 
     @Override
-    public void setDrawStyle(DrawStyle front, DrawStyle back) {
-        super.setDrawStyle(front, back);
-
-        if (back != DrawStyle.NONE && !twosidedLighting) {
-            GL11.glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL11.GL_TRUE);
-            twosidedLighting = true;
-        } else if (back == DrawStyle.NONE && twosidedLighting) {
-            GL11.glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL11.GL_FALSE);
-            twosidedLighting = false;
-        }
-    }
-
-    @Override
     protected void glMatrixMode(MatrixMode mode) {
         switch (mode) {
         case MODELVIEW:

ferox-renderer/src/main/java/com/ferox/renderer/FixedFunctionRenderer.java

  * <p/>
  * For the purposes of lighting, the renderer supports 8 simultaneous lights. For the purposes of texturing,
  * the renderer supports 4 simultaneous textures. Lighting is computed using the Blinn-Phong model adopted by
- * OpenGL and will use two-sided lighting, separate specular colors, and smooth shading.
+ * OpenGL and will use single-sided lighting, separate specular colors, and smooth shading.
  *
  * @author Michael Ludwig
  */

ferox-renderer/src/main/java/com/ferox/renderer/impl/ShaderFixedFunctionEmulator.java

 package com.ferox.renderer.impl;
 
-import com.ferox.math.Const;
-import com.ferox.math.Matrix4;
-import com.ferox.math.Vector3;
-import com.ferox.math.Vector4;
+import com.ferox.math.*;
 import com.ferox.renderer.*;
 import com.ferox.renderer.builder.ShaderBuilder;
 
     private final Vector4 cachedLightPos = new Vector4();
 
     private final Matrix4 modelview = new Matrix4();
+    private final Matrix3 normal = new Matrix3();
 
     // lazily allocated during the first activate()
     private Shader shader;
      */
     private Shader.Uniform modelviewMatrix; // mat4
     private Shader.Uniform projectionMatrix; // mat4
+    private Shader.Uniform normalMatrix; // mat3
 
     private Shader.Uniform enableLighting; // bool
 
 
     @Override
     public void setLightPosition(int light, @Const Vector4 pos) {
-        // FIXME validate w
+        if (pos.w != 0 && pos.w != 1.0) {
+            throw new IllegalArgumentException(
+                    "Light position must have a w component of 0 or 1, not: " + pos.w);
+        }
         cachedLightPos.mul(modelview, pos);
         glsl.setUniformArray(lightPosition, light, cachedLightPos);
     }
 
     @Override
     public void setSpotlight(int light, @Const Vector3 dir, double angle, double exponent) {
-        // FIXME prenormalize the direction
-        cachedSpotlightDirection.transform(modelview, dir, 0.0);
+        cachedSpotlightDirection.transform(modelview, dir, 0.0).normalize();
         glsl.setUniformArray(spotlightDirections, light, cachedSpotlightDirection);
-        glsl.setUniformArray(spotlightCutoffs, light, angle);
+        glsl.setUniformArray(spotlightCutoffs, light, Math.cos(Math.toRadians(angle)));
         glsl.setUniformArray(spotlightExponents, light, exponent);
     }
 
     public void setModelViewMatrix(@Const Matrix4 modelView) {
         glsl.setUniform(modelviewMatrix, modelView);
         modelview.set(modelView);
+
+        // compute normal matrix
+        normal.setUpper(modelView).inverse().transpose();
+        glsl.setUniform(normalMatrix, normal);
     }
 
     // FIXME validate element size and or type? type should be handled, but element size is more flexible
 
         modelviewMatrix = shader.getUniform("uModelview");
         projectionMatrix = shader.getUniform("uProjection");
+        normalMatrix = shader.getUniform("uNormalMatrix");
         enableLighting = shader.getUniform("uEnableLighting");
         globalAmbient = shader.getUniform("uGlobalLight");
 
         glsl.setUniform(fogConfig, cachedFogConfig);
 
         // transform uniforms
+        modelview.set(defaults.modelView);
         glsl.setUniform(modelviewMatrix, defaults.modelView);
-        modelview.set(defaults.modelView);
+        normal.setUpper(modelview).inverse().transpose();
+        glsl.setUniform(normalMatrix, normal);
         glsl.setUniform(projectionMatrix, defaults.projection);
 
         // lighting

ferox-renderer/src/main/resources/com/ferox/renderer/impl/ffp.frag

 
 // FIXME add texture uniforms somehow
 
-in vec4 vFrontPrimaryColor;
-in vec4 vFrontSecondaryColor;
-in vec4 vBackPrimaryColor;
-in vec4 vBackSecondaryColor;
+in vec4 vPrimaryColor;
+in vec4 vSecondaryColor;
 
 // FIXME add interpolated texture coordinates
 
 out vec4 fColor;
 
 void main() {
-    vec4 primaryColor, secondaryColor;
-    if (gl_FrontFacing) {
-        primaryColor = vFrontPrimaryColor;
-        secondaryColor = vFrontSecondaryColor;
-    } else {
-        primaryColor = vBackPrimaryColor;
-        secondaryColor = vBackSecondaryColor;
-    }
-
     // FIXME apply texturing to vPrimaryColor before color sum
-    vec4 color = primaryColor + secondaryColor;
+    vec4 color = vPrimaryColor + vSecondaryColor;
 
     // fog
     if (uEnableFog) {

ferox-renderer/src/main/resources/com/ferox/renderer/impl/ffp.vert

 #version 150
 
 uniform mat4 uModelview;
+uniform mat3 uNormalMatrix; // compute on CPU to improve performance when vertex bound
 uniform mat4 uProjection;
 
 uniform bool uEnableLighting;
 uniform vec4 uLightDiffuse[8];
 uniform vec4 uLightAmbient[8];
 uniform vec4 uLightSpecular[8];
-uniform vec3 uSpotlightDirection[8];
-uniform float uSpotlightCutoff[8];
+uniform vec3 uSpotlightDirection[8]; // assumed to be normalized
+uniform float uSpotlightCutoff[8]; // cached to cos of actual angle, so 180 -> -1.0
 uniform float uSpotlightExponent[8];
 uniform vec3 uLightAttenuation[8];
 
 
 // FIXME add texture coordinates
 
-out vec4 vFrontPrimaryColor;
-out vec4 vBackPrimaryColor;
-out vec4 vFrontSecondaryColor;
-out vec4 vBackSecondaryColor;
+out vec4 vPrimaryColor;
+out vec4 vSecondaryColor;
 
 void computeLighting(const int light, const vec4 eyePos, const vec3 eyeNorm,
                      out vec4 primaryColor, out vec4 secondaryColor) {
 
         attenuation = 1.0 / (uLightAttenuation[light].x + uLightAttenuation[light].y * d + uLightAttenuation[light].z * d * d);
         float sdi = max(dot(-vp, uSpotlightDirection[light]), 0.0);
-        if (uSpotlightCutoff[light] == 180.0) {
+        if (uSpotlightCutoff[light] == -1.0) {
             spot = 1.0;
-        } else if (sdi >= cos(radians(uSpotlightCutoff[light]))) {
+        } else if (sdi >= uSpotlightCutoff[light]) {
             spot = pow(sdi, uSpotlightExponent[light]);
         }
     }
         float si = pow(max(dot(eyeNorm, h), 0.0), uMatShininess);
         secondaryColor = attenuation * spot * si * uMatSpecular * uLightSpecular[light];
     } else {
-        secondaryColor = vec4(0.0, 0.0, 0.0, 0.0);
+       secondaryColor = vec4(0.0, 0.0, 0.0, 0.0);
     }
 }
 
 void main() {
     vec4 eyePos = uModelview * aVertex;
-    vec4 frontPrimaryColor = aDiffuse;
-    vec4 frontSecondaryColor = vec4(0.0, 0.0, 0.0, 1.0);
-
-    vec4 backPrimaryColor = frontPrimaryColor;
-    vec4 backSecondaryColor = frontSecondaryColor;
+    vec4 primaryColor = aDiffuse;
+    vec4 secondaryColor = vec4(0.0, 0.0, 0.0, 1.0);
 
     if (uEnableLighting) {
-        vec3 eyeNorm = normalize((transpose(inverse(mat3(uModelview))) * aNormal.xyz));
+        vec3 eyeNorm = normalize(uNormalMatrix * aNormal.xyz);
         vec3 backEyeNorm = -eyeNorm;
 
-        frontPrimaryColor = uMatEmissive + uMatAmbient * uGlobalLight;
-        backPrimaryColor = frontPrimaryColor;
+        primaryColor = uMatEmissive + uMatAmbient * uGlobalLight;
 
         for (int i = 0; i < 8; i++) {
             if (uEnableLight[i]) {
-                vec4 fp, fs, bp, bs;
+                vec4 fp, fs;
                 computeLighting(i, eyePos, eyeNorm, fp, fs);
-                computeLighting(i, eyePos, backEyeNorm, bp, bs);
 
-                frontPrimaryColor += fp;
-                frontSecondaryColor += fs;
-                backPrimaryColor += bp;
-                backSecondaryColor += bs;
+                primaryColor += fp;
+                secondaryColor += fs;
             }
         }
     }
 
-    vFrontPrimaryColor = vec4(frontPrimaryColor.xyz, aDiffuse.w);
-    vFrontSecondaryColor = vec4(frontSecondaryColor.xyz, 0.0);
-    vBackPrimaryColor = vec4(backPrimaryColor.xyz, aDiffuse.w);
-    vBackSecondaryColor = vec4(backSecondaryColor.xyz, 0.0);
+    vPrimaryColor = vec4(primaryColor.xyz, aDiffuse.w);
+    vSecondaryColor = vec4(secondaryColor.xyz, 0.0);
     gl_Position = uProjection * eyePos;
 }