Implemented automatic normal calculation in A3D (this closes issue 345)

This commit is contained in:
codeanticode
2010-11-16 11:48:31 +00:00
parent 6c9b1f4fbc
commit 41f5c96c37
4 changed files with 117 additions and 47 deletions
@@ -81,6 +81,9 @@ public interface PConstants {
// material properties
// TODO: check whether we still need them in PGraphicsAndroid3D and if yes
// how the work in combination with the global material properties (ambient, diffuse,
// emissive, specular colors).
// Ambient color (usually to be kept the same as diffuse)
// fill(_) sets both ambient and diffuse.
@@ -105,10 +108,10 @@ public interface PConstants {
static public final int ER = 32;
static public final int EG = 33;
static public final int EB = 34;
// has this vertex been lit yet
static public final int BEEN_LIT = 35;
// has this vertex been assigned a normal yet
static public final int HAS_NORMAL = 35;
static public final int VERTEX_FIELD_COUNT = 36;
@@ -371,6 +374,27 @@ public interface PConstants {
static final int SHAPE = 5;
// normal modes.
/**
* In the vertex mode, the user should specify a normal for
* each vertex.
*/
static final int VERTEX = 6;
/**
* Normal vectors are automatically calculated if not set.
*/
static final int AUTO = 7;
/**
* ... and, the constant SHAPE from text placement modes
* is used to set the SHAPE normal mode, where the same shape
* is used for all the vertices in a shape. This conflict in the
* name of constants should be solved (TODO).
*/
// text alignment modes
// are inherited from LEFT, CENTER, RIGHT
+35 -36
View File
@@ -403,6 +403,8 @@ public class PGraphics extends PImage implements PConstants {
protected float vertices[][] =
new float[DEFAULT_VERTICES][VERTEX_FIELD_COUNT];
protected int vertexCount; // total number of vertices
// This array allows to assign a different texture for each vertex.
protected PImage verticesTexture[] = new PImage[DEFAULT_VERTICES];
// ........................................................
@@ -490,19 +492,9 @@ public class PGraphics extends PImage implements PConstants {
// ........................................................
/// normal calculated per triangle
static protected final int NORMAL_MODE_AUTO = 0;
/// one normal manually specified per shape
static protected final int NORMAL_MODE_SHAPE = 1;
/// normals specified for each shape vertex
static protected final int NORMAL_MODE_VERTEX = 2;
/// Current mode for normals, one of AUTO, SHAPE, or VERTEX
protected int normalMode;
/// Keep track of how many calls to normal, to determine the mode.
//protected int normalCount;
/** Current normal vector. */
public float normalX, normalY, normalZ;
@@ -703,6 +695,8 @@ public class PGraphics extends PImage implements PConstants {
rectMode(CORNER);
ellipseMode(DIAMETER);
normalMode = AUTO;
// no current font
textFont = null;
@@ -875,6 +869,14 @@ public class PGraphics extends PImage implements PConstants {
}
/**
* Sets the normal mode, either AUTO, SHAPE or VERTEX.
*/
public void normalMode(int mode) {
this.normalMode = mode;
}
/**
* Sets the current normal vector. Only applies with 3D rendering
* and inside a beginShape/endShape block.
@@ -883,10 +885,6 @@ public class PGraphics extends PImage implements PConstants {
* allowing you to specify a vector perpendicular to the surface
* of the shape, which determines how lighting affects it.
* <P/>
* For the most part, PGraphics3D will attempt to automatically
* assign normals to shapes, but since that's imperfect,
* this is a better option when you want more control.
* <P/>
* For people familiar with OpenGL, this function is basically
* identical to glNormal3f().
*/
@@ -894,25 +892,6 @@ public class PGraphics extends PImage implements PConstants {
normalX = nx;
normalY = ny;
normalZ = nz;
// if drawing a shape and the normal hasn't been set yet,
// then we need to set the normals for each vertex so far
if (shape != 0) {
if (normalMode == NORMAL_MODE_AUTO) {
// either they set the normals, or they don't [0149]
// for (int i = vertex_start; i < vertexCount; i++) {
// vertices[i][NX] = normalX;
// vertices[i][NY] = normalY;
// vertices[i][NZ] = normalZ;
// }
// One normal per begin/end shape
normalMode = NORMAL_MODE_SHAPE;
} else if (normalMode == NORMAL_MODE_SHAPE) {
// a separate normal for each vertex
normalMode = NORMAL_MODE_VERTEX;
}
}
}
@@ -1078,11 +1057,31 @@ public class PGraphics extends PImage implements PConstants {
vertex[V] = textureV;
}
float norm2 = normalX * normalX + normalY * normalY + normalZ * normalZ;
if (norm2 < EPSILON) {
vertex[HAS_NORMAL] = 0;
} else {
if (Math.abs(norm2 - 1) < EPSILON) {
float norm = PApplet.sqrt(norm2);
normalX /= norm;
normalY /= norm;
normalZ /= norm;
}
vertex[HAS_NORMAL] = 1;
}
vertex[NX] = normalX;
vertex[NY] = normalY;
vertex[NZ] = normalZ;
vertex[BEEN_LIT] = 0;
if (normalMode == VERTEX || normalMode == AUTO) {
// The AUTO mode works as the VERTEX mode (it allows the user to specify
// per-vertex normals) but if there are triangles where some of the vertices
// have no normal, then it will calculate the normal for that triangle (in
// the renderTriangles() method of PGraphicsAndroid3D).
normalX = normalY = normalZ = 0;
}
verticesTexture[vertexCount] = textureImage;
@@ -163,7 +163,8 @@ public class PGraphicsAndroid3D extends PGraphics {
/** Used to store empty values to be passed when a light has no
ambient, diffuse or specular component **/
public float[] zeroLight = { 0.0f, 0.0f, 0.0f, 1.0f };
public float[] baseLight = { 0.0f, 0.0f, 0.0f, 1.0f };
/** Default ambient light for the entire scene **/
public float[] baseLight = { 0.05f, 0.05f, 0.05f, 1.0f };
boolean lightsAllocated = false;
@@ -866,6 +867,9 @@ public class PGraphicsAndroid3D extends PGraphics {
shapeFirst = 0;
// The current normal vector is set to zero.
normalX = normalY = normalZ = 0;
if (primarySurface) {
// This instance of PGraphicsAndroid3D is the primary (onscreen) drawing surface.
@@ -1164,7 +1168,7 @@ public class PGraphicsAndroid3D extends PGraphics {
textureImage = null;
textureImagePrev = null;
normalMode = NORMAL_MODE_AUTO;
normalMode = AUTO;
}
// public void edge(boolean e)
@@ -1232,6 +1236,10 @@ public class PGraphicsAndroid3D extends PGraphics {
}
shape = 0;
if (normalMode == SHAPE) {
normalX = normalY = normalZ = 0;
}
}
protected void endShapeStroke(int mode) {
@@ -1892,6 +1900,41 @@ public class PGraphicsAndroid3D extends PGraphics {
float b[] = vertices[triangles[i][VERTEX2]];
float c[] = vertices[triangles[i][VERTEX3]];
if (normalMode == AUTO && (a[HAS_NORMAL] == 0 ||
b[HAS_NORMAL] == 0 ||
c[HAS_NORMAL] == 0)) {
// Ok, some of the vertices defining the current triangle have not been
// assigned a normal, and the normal mode is AUTO, so we generate the normal
// for all the vertices of this triangle.
// Assuming CW vertex ordering, so the outside direction for this triangle
// should be given by the cross product (b - a) x (b - c):
float x1 = b[X] - a[X];
float y1 = b[Y] - a[Y];
float z1 = b[Z] - a[Z];
float x2 = b[X] - c[X];
float y2 = b[Y] - c[Y];
float z2 = b[Z] - c[Z];
float cx = y1 * z2 - y2 * z1;
float cy = z1 * x2 - z2 * x1;
float cz = x1 * y2 - x2 * y1;
float norm = PApplet.sqrt(cx * cx + cy * cy + cz * cz);
cx /= norm;
cy /= norm;
cz /= norm;
// Same normal vector assigned to the three vertices:
a[NX] = b[NX] = c[NX] = cx;
a[NY] = b[NY] = c[NY] = cy;
a[NZ] = b[NZ] = c[NZ] = cz;
a[HAS_NORMAL] = b[HAS_NORMAL] = c[HAS_NORMAL] = 1;
}
float uscale = 1.0f;
float vscale = 1.0f;
float cx = 0.0f;
@@ -5574,9 +5617,9 @@ public class PGraphicsAndroid3D extends PGraphics {
float t = 1.0f - c;
mult((t*rx*rx) + c, (t*rx*ry) - (s*rz), (t*rx*rz) + (s*ry), 0,
(t*rx*ry) + (s*rz), (t*ry*ry) + c, (t*ry*rz) - (s*rx), 0,
(t*rx*rz) - (s*ry), (t*ry*rz) + (s*rx), (t*rz*rz) + c, 0,
0, 0, 0, 1);
(t*rx*ry) + (s*rz), (t*ry*ry) + c, (t*ry*rz) - (s*rx), 0,
(t*rx*rz) - (s*ry), (t*ry*rz) + (s*rx), (t*rz*rz) + c, 0,
0, 0, 0, 1);
}
public void scale(float sx, float sy, float sz) {
@@ -2317,7 +2317,7 @@ public class PShape3D extends PShape implements PConstants {
// Loading texture map.
String texname = elements[1];
currentMtl.kdMap = parent.loadImage(texname);
// Texture orientation in Processing is inverted with respecto to OpenGL.
// Texture orientation in Processing is inverted with respect to OpenGL.
currentMtl.kdMap.getTexture().setFlippedY(true);
} else if (elements[0].equals("Ka") && elements.length > 3) {
// The ambient color of the material
@@ -2358,6 +2358,9 @@ public class PShape3D extends PShape implements PConstants {
int tMode0 = a3d.textureMode;
a3d.textureMode = NORMAL;
int nMode0 = a3d.normalMode;
a3d.normalMode = AUTO;
// Using RGB mode for coloring.
int cMode0 = a3d.colorMode;
a3d.colorMode = RGB;
@@ -2502,9 +2505,10 @@ public class PShape3D extends PShape implements PConstants {
a3d.endShapeRecorderImpl(this);
// Restore texture and color modes.
// Restore texture, color, and normal modes.
a3d.textureMode = tMode0;
a3d.colorMode = cMode0;
a3d.normalMode = nMode0;
// Restore colors
a3d.calcR = specularR0;