Added lighting to scirenderer G2D 98/12398/2
Pedro Arthur [Tue, 27 Aug 2013 20:45:25 +0000 (17:45 -0300)]
Change-Id: If5ac0f1dc6db5ee4cfb254113a0c587073f09ebf

scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DDrawingTools.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLight.java [new file with mode: 0644]
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java [new file with mode: 0644]
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/DrawTools.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java [new file with mode: 0644]
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Motor3D.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3f.java

index 5dd6747..4842e6a 100644 (file)
@@ -31,6 +31,7 @@ import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvas;
 import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvasFactory;
 import org.scilab.forge.scirenderer.implementation.g2d.clipping.G2DClippingManager;
 import org.scilab.forge.scirenderer.implementation.g2d.motor.Motor3D;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLightManager;
 
 /**
  *
@@ -41,7 +42,7 @@ import org.scilab.forge.scirenderer.implementation.g2d.motor.Motor3D;
 public class G2DDrawingTools implements DrawingTools {
 
     private final TransformationManager transformationManager;
-    //private final G2DLightManager lightManager;
+    private final G2DLightManager lightManager;
     private final G2DClippingManager clippingManager;
     private final G2DCanvas g2dCanvas;
 
@@ -51,7 +52,7 @@ public class G2DDrawingTools implements DrawingTools {
      */
     G2DDrawingTools(G2DCanvas canvas) {
         this.transformationManager = new TransformationManagerImpl(canvas);
-        //this.lightManager = new G2DLightManager(this);
+        this.lightManager = new G2DLightManager(this);
         this.clippingManager = new G2DClippingManager(this);
         this.g2dCanvas = canvas;
 
@@ -83,8 +84,7 @@ public class G2DDrawingTools implements DrawingTools {
 
     @Override
     public LightManager getLightManager() {
-        return null;
-        //return lightManager;
+        return lightManager;
     }
 
     @Override
diff --git a/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLight.java b/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLight.java
new file mode 100644 (file)
index 0000000..5407f61
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.lighting;
+
+
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Pedro SOUZA
+ */
+public class G2DLight implements Light {
+
+    private int index;
+    private boolean isEnable;
+    private Color ambientColor = new Color(0, 0, 0);
+    private Color diffuseColor = new Color(0, 0, 0);
+    private Color specularColor = new Color(0, 0, 0);
+    private Vector3d position = new Vector3d(0, 0, 0);
+    private Vector3d spotDirection = new Vector3d(0, 0, -1);
+    private Vector3d direction = new Vector3d(0, 0, 0);
+    private float spotAngle = 180;
+    private boolean isDirectional = false;
+
+
+    public G2DLight(int index) {
+           this.index = index;
+    }
+
+    @Override
+    public boolean isEnable() {
+        return isEnable;
+    }
+
+    @Override
+    public void setEnable(boolean enable) {
+        if (enable != isEnable) {
+            isEnable = enable;
+        }
+    }
+
+    @Override
+    public Color getAmbientColor() {
+        return ambientColor;
+    }
+
+    @Override
+    public void setAmbientColor(Color color) {
+        if (color != null) {
+            ambientColor = color;
+        }
+    }
+
+    @Override
+    public Color getDiffuseColor() {
+        return diffuseColor;
+    }
+
+    @Override
+    public void setDiffuseColor(Color color) {
+        if (color != null) {
+            diffuseColor = color;
+        }
+    }
+
+    @Override
+    public Color getSpecularColor() {
+        return specularColor;
+    }
+
+    @Override
+    public void setSpecularColor(Color color) {
+        if (color != null) {
+            specularColor = color;
+        }
+    }
+
+    @Override
+    public Vector3d getPosition() {
+        return position;
+    }
+
+    @Override
+    public void setPosition(Vector3d position) {
+        if (position != null) {
+            isDirectional = false;
+            this.position = position;
+        }
+    }
+
+    public Vector3d getDirection() {
+        return direction;
+    }
+
+    public void setDirection(Vector3d direction) {
+        if (direction != null) {
+            isDirectional = true;
+            this.direction = direction.getNormalized();
+        }
+    }
+
+    @Override
+    public Vector3d getSpotDirection() {
+        return spotDirection;
+    }
+
+    @Override
+    public void setSpotDirection(Vector3d spotDirection) {
+        if (spotDirection != null) {
+            this.spotDirection = spotDirection;
+        }
+    }
+
+    @Override
+    public float getSpotAngle() {
+        return spotAngle;
+    }
+
+    @Override
+    public void setSpotAngle(float angle) {
+        if (angle != spotAngle) {
+            spotAngle = angle;
+        }
+    }
+
+    @Override
+    public int getIndex() {
+        return index;
+    }
+    
+    public boolean isPoint() {
+        return !isDirectional;
+    }
+}
diff --git a/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java b/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java
new file mode 100644 (file)
index 0000000..e8bfcde
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.lighting;
+
+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;
+
+
+
+/**
+ * @author Pedro SOUZA
+ */
+public class G2DLightManager implements LightManager {
+
+    /**
+     * The drawing tools.
+     */
+    private final G2DDrawingTools drawingTools;
+
+    /**
+     * The lights.
+     */
+    private final G2DLight[] lights;
+
+    /**
+     * The current lightning status.
+     */
+    private boolean isLightningEnable = DEFAULT_LIGHTNING_STATUS;
+
+    private Material material;
+
+    /**
+     * Default constructor.
+     * @param drawingTools the drawing tools.
+     */
+    public G2DLightManager(G2DDrawingTools drawingTools) {
+        this.drawingTools = drawingTools;
+        lights = new G2DLight[getLightNumber()];
+    }
+
+    @Override
+    public int getLightNumber() {
+        return 16;
+    }
+
+    @Override
+    public Light getLight(int i) {
+        if (i < 0 || i >= getLightNumber()) {
+            return null;
+        } else {
+            if (lights[i] == null) {
+                lights[i] = new G2DLight(i);
+            }
+            return lights[i];
+        }
+    }
+
+    @Override
+    public void setLightningEnable(boolean isLightningEnable) {
+        this.isLightningEnable = isLightningEnable;
+    }
+
+    @Override
+    public boolean isLightningEnable() {
+        return isLightningEnable;
+    }
+
+    @Override
+    public void setMaterial(Material material) {
+        this.material = material;
+    }
+       
+       public Material getMaterial() {
+        return material;
+    }
+}
index 4de3fdd..92f476c 100644 (file)
@@ -60,15 +60,17 @@ public final class DrawTools {
         Area area = new Area(contour);
         area.add(new Area(stroke.createStrokedShape(contour)));
 
-        GradientPaint gp = new GradientPaint((float) v0[0], (float) v0[1], t.colors[0], (float) pv0[0], (float) pv0[1], TRANSLUCENT_BLACK);
-        g2d.setPaint(gp);
+
+        g2d.setColor(t.colors[0]);
         g2d.fill(contour);
 
-        gp = new GradientPaint((float) v1[0], (float) v1[1], t.colors[1], (float) pv1[0], (float) pv1[1], TRANSLUCENT_BLACK);
+        float[] col = t.colors[1].getComponents(null);
+        GradientPaint gp = new GradientPaint((float) v1[0], (float) v1[1], t.colors[1], (float) pv1[0], (float) pv1[1], new Color(col[0], col[1], col[2], 0.0f));
         g2d.setPaint(gp);
         g2d.fill(contour);
 
-        gp = new GradientPaint((float) v2[0], (float) v2[1], t.colors[2], (float) pv2[0], (float) pv2[1], TRANSLUCENT_BLACK);
+        col = t.colors[1].getComponents(null);
+        gp = new GradientPaint((float) v2[0], (float) v2[1], t.colors[2], (float) pv2[0], (float) pv2[1], new Color(col[0], col[1], col[2], 0.0f));
         g2d.setPaint(gp);
         g2d.fill(contour);
 
diff --git a/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java b/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java
new file mode 100644 (file)
index 0000000..c045e96
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+ */
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3f;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLight;
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+
+/**
+ * @author Pedro SOUZA
+ */
+public class LightHelper {
+
+    /**
+     * @param buffer the float buffer.
+     * @param stride the stride between elements.
+     * @return an array of Vector3f from the given float buffer.
+     */
+    public static Vector3f[] getVector3f(FloatBuffer buffer, int stride) {
+        if (buffer == null) return null;
+        if (stride < 3) return null;
+
+        float[] floats;
+        buffer.rewind();
+        if (buffer.hasArray()) {
+            floats = buffer.array();
+        } else {
+            floats = new float[buffer.limit()];
+            buffer.get(floats);
+        }
+
+        Vector3f[] ret = new Vector3f[floats.length / stride];
+        for (int i = 0; i < floats.length; i+= stride) {
+            ret[i] = new Vector3f(floats[i], floats[i+1], floats[i+2]);
+        }
+        return ret;
+    }
+
+    /**
+     * @param buffer the float buffer.
+     * @param index the indices  buffer.
+     * @param stride the stride between elements.
+     * @return an array of Vector3f from the given float buffer.
+     */
+    public static Vector3f[] getIndexedVector3f(FloatBuffer buffer, IntBuffer index, int stride) {
+        if (buffer == null || index == null) return null;
+        if (stride < 3) return null;
+
+        float[] floats;
+        buffer.rewind();
+        if (buffer.hasArray()) {
+            floats = buffer.array();
+        } else {
+            floats = new float[buffer.limit()];
+            buffer.get(floats);
+        }
+
+        int[] idx;
+        index.rewind();
+        if (index.hasArray()) {
+            idx = index.array();
+        } else {
+            idx = new int[index.limit()];
+            index.get(idx);
+        }
+
+        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]);
+        }
+        return ret;
+    }
+
+    /**
+     * Apply the given ambient color to the output.
+     * @param ambient the ambient color.
+     * @param output the color vector to apply the ambient color.
+     * @param additive if true the ambient color is added to output.
+     * @return the resulting color vector.
+     */
+    public static Color[] applyAmbient(Color ambient, Color[] output, boolean additive) {
+        for (int i = 0; i < output.length; ++i) {
+            if (additive) {
+                output[i] = getColorSum(ambient, output[i]);
+            } else {
+                output[i] = ambient;
+            }
+        }
+        return output;
+    }
+
+    /**
+     * Apply diffuse light to the output colors
+     * @param light the light position or direction.
+     * @param directional if true the vector light is considered a direction otherwise a position.
+     * @param vertices the surface vertices.
+     * @param normals the surface normals.
+     * @param colors the surface per-vertex colors.
+     * @param dffuse the light diffuse color.
+     * @param output the output color vector.
+     * @param additive if true the calculated diffuse color is added to the output.
+     * @return the resulting color vector.
+     */
+    public static Color[] applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color diffuse, Color[] output, boolean additive) {
+        float ndotl;
+        for (int i = 0; i < colors.length; ++i) {
+
+            if (directional) {
+                ndotl = normals[i].getNormalized().scalar(light);
+            }else {
+                Vector3f ray = light.minus(vertices[i]).getNormalized();
+                ndotl = normals[i].getNormalized().scalar(ray);
+            }
+            ndotl = clamp(ndotl);
+            Color c = getColorProduct(colors[i], diffuse);
+            if (additive) {
+                output[i] = getColorSum(getColorProduct(c, ndotl), output[i]);
+            } else {
+                output[i] = getColorProduct(c, ndotl);
+            }
+        }
+        return output;
+    }
+    
+    /**
+     * Apply diffuse light to the output colors
+     * @param light the light position or direction.
+     * @param directional if true the vector light is considered a direction otherwise a position.
+     * @param vertices the surface vertices.
+     * @param normals the surface normals.
+     * @param color the surface color.
+     * @param output the output color vector.
+     * @param additive if true the calculated diffuse color is added to the output.
+     * @return the resulting color vector.
+     */
+    public static Color[] applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color color, Color[] output, boolean additive) {
+        float ndotl;
+        for (int i = 0; i < output.length; ++i) {
+
+            if (directional) {
+                ndotl = normals[i].getNormalized().scalar(light);
+            }else {
+                Vector3f ray = light.minus(vertices[i]).getNormalized();
+                ndotl = normals[i].getNormalized().scalar(ray);
+            }
+            ndotl = clamp(ndotl);
+            if (additive) {
+                output[i] = getColorSum(getColorProduct(color, ndotl), output[i]);
+            } else {
+                output[i] = getColorProduct(color, ndotl);
+            }
+        }
+        return output;
+    }
+
+    public static Color[] applySpecular(Vector3f camera, Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color specular, Color[] output, boolean additive) {
+        for (int i = 0; i < output.length; ++i) {
+            if (additive) {
+            } else {
+            }
+        }
+        return output;
+    }
+
+    /**
+     * Apply a per-vertex lighting to the given colors
+     * @param light the light.
+     * @param mat the material properties.
+     * @param vertices the surface vertices.
+     * @param normals the surface normals.
+     * @param colors the surface per-vertex colors.
+     * @param output the output color vector.
+     * @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) {
+        Color ambient = getColorProduct(mat.getAmbientColor(), light.getAmbientColor());
+        Color diffuse = getColorProduct(mat.getDiffuseColor(), light.getDiffuseColor());
+        Color specular = getColorProduct(mat.getSpecularColor(), light.getSpecularColor());
+
+        Color[] finalColor = applyAmbient(ambient, output, additive);
+
+        float[] v;
+        if (light.isPoint()) {
+            v = light.getPosition().getDataAsFloatArray();
+        } else {
+            v = light.getDirection().getDataAsFloatArray();  
+        }
+
+        Vector3f vec = new Vector3f(v[0], v[1], v[2]);
+
+        if (mat.isColorMaterialEnable()) {
+            finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, colors, light.getDiffuseColor(), finalColor, true);
+        } else {
+            finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, diffuse, finalColor, true);
+        }
+
+        //TODO: how to retrieve Camera position?
+        //finalColor = performSpecular(null, null, false, vertices, normals, specular, finalColor, true);
+
+        return finalColor;
+    }
+
+    /**
+     * return the product of the given colors
+     */
+    private static Color getColorProduct(Color a, Color b) {
+        float[] ca = a.getComponents(null);
+        float[] cb = b.getComponents(null);
+        return new Color(ca[0] * cb[0], ca[1] * cb[1], ca[2] * cb[2]);
+    }
+
+    /**
+     * return the clamped product of the color
+     */
+    private static Color getColorProduct(Color a, float f) {
+        float[] ca = a.getComponents(null);
+        return new Color(clamp(ca[0] * f), clamp(ca[1] * f), clamp(ca[2] * f));
+    }
+
+    /**
+     * return the clamped sum of the given colors
+     */
+    private static Color getColorSum(Color a, Color b) {
+        float[] ca = a.getComponents(null);
+        float[] cb = b.getComponents(null);
+        return new Color(clamp(ca[0] + cb[0]), clamp(ca[1] + cb[1]), clamp(ca[2] + cb[2]));
+    }
+
+    /**
+     * Clamp the given value to [0, 1]
+     */
+    private static float clamp(float f) {
+        f = f < 0.0f ? 0.0f : f;
+        f = f > 1.0f ? 1.0f : f;
+        return f;
+    }
+}
index fb51159..012e26b 100644 (file)
@@ -36,6 +36,13 @@ import org.scilab.forge.scirenderer.texture.AnchorPosition;
 import org.scilab.forge.scirenderer.texture.Texture;
 import org.scilab.forge.scirenderer.tranformations.Transformation;
 import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector3f;
+
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLight;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLightManager;
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
 
 /**
  * @author Calixte DENIZET
@@ -182,8 +189,11 @@ public class Motor3D {
             image = ((G2DTextureManager.G2DTexture) texture).getImage();
         }
 
+        G2DLightManager lm = (G2DLightManager)drawingTools.getLightManager();
+        lm.setMaterial(appearance.getMaterial());
+
         if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
-            addTriangles(vertexBuffer, normalBuffer, colorBuffer, appearance.getFillColor(), indicesBuffer, textureCoordinatesBuffer, image, texture, geometry.getFillDrawingMode());
+            addTriangles(vertexBuffer, normalBuffer, colorBuffer, appearance.getFillColor(), indicesBuffer, textureCoordinatesBuffer, image, texture, geometry.getFillDrawingMode(), lm);
         }
 
         if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
@@ -313,6 +323,7 @@ public class Motor3D {
             if (textureCoords != null) {
                 ta = new Vector3d[ind.length];
             }
+
             for (int i = 0; i < ind.length; i++) {
                 va[i] = verticesArray[ind[i]];
                 ca[i] = colorsArray[ind[i]];
@@ -402,7 +413,7 @@ public class Motor3D {
      * @param indices a buffer containg the index of the vertices to retrieve
      * @param drawingMode the drawing mode
      */
-    private void addTriangles(FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors, Color defaultColor, IntBuffer indices, FloatBuffer textureCoords, final BufferedImage image, Texture texture, Geometry.FillDrawingMode drawingMode) {
+    private void addTriangles(FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors, Color defaultColor, IntBuffer indices, FloatBuffer textureCoords, final BufferedImage image, Texture texture, Geometry.FillDrawingMode drawingMode, G2DLightManager lightManager) {
         Object[] arrays = getArrays(vertices, colors, defaultColor, textureCoords, indices);
         Vector3d[] verticesArray = (Vector3d[]) arrays[0];
         Color[] colorsArray = (Color[]) arrays[1];
@@ -414,6 +425,8 @@ public class Motor3D {
         if (texture != null) {
             filter = texture.getMagnificationFilter();
         }
+        
+       colorsArray = applyLighting(vertices, normals, indices, colorsArray, lightManager);
 
         switch (drawingMode) {
             case TRIANGLE_FAN :
@@ -531,4 +544,37 @@ public class Motor3D {
 
         return c;
     }
+
+    /**
+     * Perform per-vertex lighting
+     */
+    private Color[] applyLighting(FloatBuffer vertices, FloatBuffer normals, IntBuffer index, Color[] colors, G2DLightManager lightManager) {
+
+        if (!lightManager.isLightningEnable() || vertices == null || normals == null
+            || index == null || colors == null) {
+            return colors;
+        }
+
+        Material mat = lightManager.getMaterial();
+        if (mat == null) {
+            return colors;
+        }
+
+
+        Vector3f[] vertexArray = LightHelper.getIndexedVector3f(vertices, index, G2DElementsBuffer.ELEMENT_SIZE);
+        Vector3f[] normalArray = LightHelper.getIndexedVector3f(normals, index, G2DElementsBuffer.ELEMENT_SIZE);
+
+
+        Color[] outColors = new Color[colors.length];
+        boolean first = true;
+        for (int i = 0; i < lightManager.getLightNumber(); ++i) {
+            G2DLight l = (G2DLight)lightManager.getLight(i);
+
+            if (l == null || !l.isEnable()) continue;
+
+            outColors = LightHelper.applyLight(l, mat, vertexArray, normalArray, colors, outColors, !first);
+            first = false;
+        }
+        return outColors;
+    }
 }
index 9730153..624f521 100644 (file)
@@ -45,4 +45,58 @@ public class Vector3f {
     public Vector3d asDouble() {
         return new Vector3d(x, y, z);
     }
+
+    public Vector3f plus(Vector3f v) {
+        return new Vector3f(x + v.x, y + v.y, z + v.z);
+    }
+
+    public Vector3f minus(Vector3f v) {
+        return new Vector3f(x - v.x, y - v.y, z - v.z);
+    }
+
+    public Vector3f times(float d) {
+        return new Vector3f(x * d, y * d, z * d);
+    }
+
+    public Vector3f getNormalized() {
+        float norm = getNorm();
+        if (norm == 0) {
+            return new Vector3f(0.0f, 0.0f, 0.0f);
+        }
+        return this.times(1.0f / getNorm());
+    }
+
+    public float getNorm() {
+        return (float)Math.sqrt(getNorm2());
+    }
+
+    public float getNorm2() {
+        return scalar(this);
+    }
+
+    public float scalar(Vector3f v) {
+        return x * v.x + y * v.y + z * v.z;
+    }
+
+    /**
+     * Create a new vector cross-product of the given vectors.
+     * @param v1 the first given vector.
+     * @param v2 the second given vector.
+     * @return a new vector cross-product of the given vectors.
+     */
+    public static Vector3f product(Vector3f v1, Vector3f v2) {
+        return new Vector3f(
+                   v1.y * v2.z - v1.z * v2.y,
+                   v1.z * v2.x - v1.x * v2.z,
+                   v1.x * v2.y - v1.y * v2.x
+               );
+    }
+
+    public final static float det(final Vector3f v0, final Vector3f v1, final Vector3f v2) {
+        return v0.x * (v1.y * v2.z - v1.z * v2.y) + v0.y * (v1.z * v2.x - v1.x * v2.z) + v0.z * (v1.x * v2.y - v1.y * v2.x);
+    }
+
+    public final static Vector3f getBarycenter(Vector3f v0, Vector3f v1, float w0, float w1) {
+        return new Vector3f(v0.x * w0 + v1.x * w1, v0.y * w0 + v1.y * w1, v0.z * w0 + v1.z * w1);
+    }
 }