Fix scirenderer g2d specular lighting calculation. 89/12689/2
Pedro Arthur [Thu, 26 Sep 2013 21:30:16 +0000 (18:30 -0300)]
Now the vertices, normals and the light position/directions are
transformed using the same transformation that is passed to opengl
reproducing exactly the same effect in JoGl and g2d.

Change-Id: I8df42f98c3eb4ff24b4e935430705e52b8dd2a1d

scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Motor3D.java

index e8bfcde..3fae29f 100644 (file)
@@ -15,6 +15,8 @@ import org.scilab.forge.scirenderer.lightning.Light;
 import org.scilab.forge.scirenderer.lightning.LightManager;
 import org.scilab.forge.scirenderer.shapes.appearance.Material;
 import org.scilab.forge.scirenderer.implementation.g2d.G2DDrawingTools;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3f;
 
 
 
@@ -84,4 +86,43 @@ public class G2DLightManager implements LightManager {
        public Material getMaterial() {
         return material;
     }
+
+    /**
+     * Returns the camera position used to perform the lighting.
+     */
+    public Vector3f getCameraPosition() {
+        double[] m = drawingTools.getTransformationManager().getTransformation().getMatrix();
+        //extract the translation of the matrix
+        return new Vector3f((float)m[12], (float)m[13], (float)m[14]);
+    }
+
+    /**
+     * Returns the vertex transformation as a float array.
+     */
+    public float[] getVertexTransform() {
+        float[] ret = new float[16];
+        double[] m = drawingTools.getTransformationManager().getTransformation().getMatrix();
+        for (int i = 0; i < 16; ++i) {
+            ret[i] = (float)m[i];
+        }
+        return ret;
+    }
+
+    /**
+     * Returns the normal transformation as a float array.
+     * The normal transformation is defined as the inverse transpose
+     * of the vertex transformation.
+     */
+    public float[] getNormalTransform() {
+        float[] ret = new float[16];
+        double[] m = drawingTools.getTransformationManager().getTransformation().getInverseTransformation().getMatrix();
+
+        //only the top 3x3 matrix is used.
+        ret[0] = (float)m[0];  ret[4] = (float)m[1];  ret[8] =  (float)m[2];  ret[12] = 0.f;
+        ret[1] = (float)m[4];  ret[5] = (float)m[5];  ret[9] =  (float)m[6];  ret[13] = 0.f;
+        ret[2] = (float)m[8];  ret[6] = (float)m[9];  ret[10] = (float)m[10]; ret[14] = 0.f;
+        ret[3] = 0.f;          ret[7] = 0.f;          ret[11] = 0.f;          ret[15] = 1.f;
+
+        return ret;
+    }
 }
index b1ea6e5..4c0d143 100644 (file)
@@ -54,9 +54,10 @@ public class LightHelper {
      * @param buffer the float buffer.
      * @param index the indices  buffer.
      * @param stride the stride between elements.
+     * @param transf matrix to transform the vector, if null no transformation is applied.
      * @return an array of Vector3f from the given float buffer.
      */
-    public static Vector3f[] getIndexedVector3f(FloatBuffer buffer, IntBuffer index, int stride) {
+    public static Vector3f[] getIndexedVector3f(FloatBuffer buffer, IntBuffer index, int stride, float[] transf) {
         if (buffer == null || index == null) return null;
         if (stride < 3) return null;
 
@@ -79,11 +80,32 @@ public class LightHelper {
         }
 
         Vector3f[] ret = new Vector3f[idx.length];
-        for (int i = 0; i < idx.length; ++i) {
-            ret[i] = new Vector3f(floats[stride * idx[i]], floats[stride * idx[i] + 1], floats[stride * idx[i] + 2]);
+        float x, y, z;
+        if (transf != null && transf.length == 16) {
+            for (int i = 0; i < idx.length; ++i) {
+                ret[i] = transform(floats[stride * idx[i]], floats[stride * idx[i] + 1], floats[stride * idx[i] + 2], transf);
+            }
+        } else {
+            for (int i = 0; i < idx.length; ++i) {
+                ret[i] = new Vector3f(floats[stride * idx[i]], floats[stride * idx[i] + 1], floats[stride * idx[i] + 2]);
+            }
         }
         return ret;
     }
+    
+    static Vector3f transform(float x, float y, float z, float[] transf) {
+        float xx = transf[0] * x + transf[4] * y + transf[8] * z + transf[12];
+        float yy = transf[1] * x + transf[5] * y + transf[9] * z + transf[13];
+        float zz = transf[2] * x + transf[6] * y + transf[10] * z + transf[14];
+        return new Vector3f(xx, yy, zz);
+    }
+
+    static Vector3f transformDirection(float x, float y, float z, float[] transf) {
+        float xx = transf[0] * x + transf[4] * y + transf[8] * z;
+        float yy = transf[1] * x + transf[5] * y + transf[9] * z;
+        float zz = transf[2] * x + transf[6] * y + transf[10] * z;
+        return new Vector3f(xx, yy, zz);
+    }
 
     /**
      * Apply the given ambient color to the output.
@@ -189,19 +211,27 @@ public class LightHelper {
     public static Color[] applySpecular(Vector3f camera, Vector3f light, float shininess, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color specular, Color[] output, boolean additive) {
 
         for (int i = 0; i < output.length; ++i) {
-            Vector3f R;
 
             Vector3f view = camera.minus(vertices[i]).getNormalized();
+            Vector3f half;
+            float ndotl;
             if (directional) {
-                R = reflect(light.negate(), normals[i]);
+                half = view.plus(light);
+                ndotl = normals[i].scalar(light);
             } else {
                 Vector3f ray = light.minus(vertices[i]).getNormalized();
-                R = reflect(ray.negate(), normals[i]);
+                half = view.plus(ray);
+                ndotl = normals[i].scalar(ray);
             }
-            R = R.getNormalized();
-            float s = R.scalar(view);
-            s = clamp(s);
-            s = (float)Math.pow((double)s, (double)shininess);
+            half = half.getNormalized();
+
+            float s = 0.0f;
+            if (ndotl > 0.0f) {
+                s = normals[i].scalar(half);
+                s = clamp(s);
+                s = (float)Math.pow((double)s, (double)shininess);
+            }
+
             if (additive) {
                 output[i] = getColorSum(getColorProduct(specular, s), output[i]);
             } else {
@@ -215,22 +245,20 @@ public class LightHelper {
      * Apply a per-vertex lighting to the given colors
      * @param light the light.
      * @param mat the material properties.
+     * @param camera the camera position.
      * @param vertices the surface vertices.
      * @param normals the surface normals.
      * @param colors the surface per-vertex colors.
      * @param output the output color vector.
+     * @param transf the light transformation matrix. If null no transformation is applyed.
      * @param additive if true the calculated color is added to the output.
      * @return the resulting color vector.
      */
-    public static Color[] applyLight(G2DLight light, Material mat, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color[] output, boolean additive) {
+    public static Color[] applyLight(G2DLight light, Material mat, Vector3f camera, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color[] output, float[] transf, boolean additive) {
         Color ambient = getColorProduct(mat.getAmbientColor(), light.getAmbientColor());
         Color diffuse = getColorProduct(mat.getDiffuseColor(), light.getDiffuseColor());
         Color specular = getColorProduct(mat.getSpecularColor(), light.getSpecularColor());
 
-        for (int i = 0; i < normals.length; ++i) {
-            normals[i] = normals[i].getNormalized();
-        }
-
         Color[] finalColor;
         if (mat.isColorMaterialEnable()) {
             finalColor = applyAmbient(light.getAmbientColor(), colors, output, additive);
@@ -245,7 +273,16 @@ public class LightHelper {
             v = light.getDirection().getDataAsFloatArray();
         }
 
-        Vector3f vec = new Vector3f(v[0], v[1], v[2]);
+        Vector3f vec;
+        if (transf != null && transf.length == 16) {
+            if (light.isPoint()) {
+                vec = transform(v[0], v[1], v[2], transf);
+            } else {
+                vec = transformDirection(v[0], v[1], v[2], transf).getNormalized();
+            }
+        } else {
+            vec = new Vector3f(v[0], v[1], v[2]);
+        }
 
         if (mat.isColorMaterialEnable()) {
             finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, colors, light.getDiffuseColor(), finalColor, true);
@@ -253,7 +290,7 @@ public class LightHelper {
             finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, diffuse, finalColor, true);
         }
 
-        //finalColor = applySpecular(???, vec, mat.getShininess(), !light.isPoint(), vertices, normals, specular, finalColor, true);
+        finalColor = applySpecular(camera, vec, mat.getShininess(), !light.isPoint(), vertices, normals, specular, finalColor, true);
 
         return finalColor;
     }
index a98c47d..a90b5bc 100644 (file)
@@ -577,8 +577,16 @@ public class Motor3D {
             return colors;
         }
 
-        Vector3f[] vertexArray = LightHelper.getIndexedVector3f(vertices, index, G2DElementsBuffer.ELEMENT_SIZE);
-        Vector3f[] normalArray = LightHelper.getIndexedVector3f(normals, index, G2DElementsBuffer.ELEMENT_SIZE);
+        float[] vertexTransf = lightManager.getVertexTransform();
+        float[] normalTransf = lightManager.getNormalTransform();
+        //for transformed vertices camera is at origin.
+        Vector3f camera = new Vector3f(0.f, 0.f ,0.f);
+        Vector3f[] vertexArray = LightHelper.getIndexedVector3f(vertices, index, G2DElementsBuffer.ELEMENT_SIZE, vertexTransf);
+        Vector3f[] normalArray = LightHelper.getIndexedVector3f(normals, index, G2DElementsBuffer.ELEMENT_SIZE, normalTransf);
+
+        for (int i = 0; i < normalArray.length; ++i) {
+            normalArray[i] = normalArray[i].getNormalized();
+        }
 
 
         Color[] outColors = new Color[colors.length];
@@ -588,7 +596,7 @@ public class Motor3D {
 
             if (l == null || !l.isEnable()) continue;
 
-            outColors = LightHelper.applyLight(l, mat, vertexArray, normalArray, colors, outColors, !first);
+            outColors = LightHelper.applyLight(l, mat, camera, vertexArray, normalArray, colors, outColors, vertexTransf, !first);
             first = false;
         }
         return outColors;