Skip to content

Commit

Permalink
Refactored global math constants into Phoria namespace (e.g. RADIANS …
Browse files Browse the repository at this point in the history
…is now Phoria.RADIANS)

Normal matrix calculation fixes related to transformed normals - fixes issues with non-uniform object scaling and translation of objects messing up lighting.
Optimized some related normal calculations.
Improved documentation related to Distant light direction (i.e. normalized direction vector)
Improved code comments related to object->world->camera space calculations.
Allow a texture index to be set on the 'style' for an Entity - to avoid having to set texture index per polygon when all polygons are using same texture. Tweaked test0uv to demonstrate.
Fixed scene JSON serialisation (prototype) related to objects with textures applied.
Fixed top and bottom generated cube face orientation (for uv coords).
  • Loading branch information
kevinroast committed Nov 4, 2013
1 parent 13aaa93 commit bbf34fb
Show file tree
Hide file tree
Showing 21 changed files with 299 additions and 108 deletions.
8 changes: 4 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,14 @@
var rotates = [0,0,0];
var fnAnimate = function() {2
// rotate local matrix of an object
testCube.rotateY(0.5*RADIANS);
testCube.rotateY(0.5*Phoria.RADIANS);
// translate local matrix of child object - will receive rotation from parent
childCube.identity().translateY(Math.sin(Date.now() / 1000) + 3);
// translate visible light objects around the origin - will rotate child Light emitters
var sine = Math.sin(Date.now() / 500);
blueLightObj.identity().rotateY(rotates[0]+=1*RADIANS).translateY(sine);
redLightObj.identity().rotateY(rotates[1]+=0.5*RADIANS).translateY(sine);
greenLightObj.identity().rotateY(rotates[2]+=1.5*RADIANS).translateY(sine);
blueLightObj.identity().rotateY(rotates[0]+=1*Phoria.RADIANS).translateY(sine);
redLightObj.identity().rotateY(rotates[1]+=0.5*Phoria.RADIANS).translateY(sine);
greenLightObj.identity().rotateY(rotates[2]+=1.5*Phoria.RADIANS).translateY(sine);

// execute the model view 3D pipeline
scene.modelView();
Expand Down
16 changes: 9 additions & 7 deletions scripts/phoria-entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
};
})();

var CLIP_ARRAY_TYPE = (typeof Uint32Array !== 'undefined') ? Uint32Array : Array;
Phoria.CLIP_ARRAY_TYPE = (typeof Uint32Array !== 'undefined') ? Uint32Array : Array;

(function() {
"use strict";
Expand Down Expand Up @@ -189,7 +189,7 @@ var CLIP_ARRAY_TYPE = (typeof Uint32Array !== 'undefined') ? Uint32Array : Array
fillmode: "inflate",
linewidth: 1.0,
linescale: 0.0,
hiddenangle: -PI/2,
hiddenangle: -Phoria.PIO2,
doublesided: false
};

Expand Down Expand Up @@ -218,7 +218,8 @@ var CLIP_ARRAY_TYPE = (typeof Uint32Array !== 'undefined') ? Uint32Array : Array
* linewidth: 1.0, // wireframe line thickness
* linescale: 0.0, // depth based scaling factor for wireframes - can be zero for no scaling
* hiddenangle: 0.0, // hidden surface test angle - generally between -PI and 0 - depends on perspective fov
* doublesided: false
* doublesided: false, // true to always render polygons - i.e. do not perform hidden surface test
* texture: undefined // default texture index to use for polygons if not specified - e.g. when UVs are used
* }
* onRender: function() {...}
* }
Expand Down Expand Up @@ -393,7 +394,7 @@ var CLIP_ARRAY_TYPE = (typeof Uint32Array !== 'undefined') ? Uint32Array : Array
}
if (this._clip === null || this._clip.length < len)
{
this._clip = new CLIP_ARRAY_TYPE(len);
this._clip = new Phoria.CLIP_ARRAY_TYPE(len);
}
},

Expand Down Expand Up @@ -777,12 +778,13 @@ Phoria.PhysicsEntity.GRAVITY = {x:0, y:-9.8, z:0};
"use strict";

/**
* DistantLight models an infinitely distant light that has no position only a direction from which light eminates.
* DistantLight models an infinitely distant light that has no position only a normalised direction from which light eminates.
*/
Phoria.DistantLight = function()
{
Phoria.DistantLight.superclass.constructor.call(this);

// direction should be a normalised vector
this.direction = {x:0, y:0, z:1};

// add scene handler to transform the light direction into world direction
Expand All @@ -801,7 +803,7 @@ Phoria.PhysicsEntity.GRAVITY = {x:0, y:-9.8, z:0};
Phoria.BaseEntity.create(desc, e);
if (desc.color) e.color = desc.color;
if (desc.intensity) e.intensity = desc.intensity;
if (desc.direction) e.direction = desc.direction;
if (desc.direction) e.direction = vec3.toXYZ(vec3.normalize(e.direction, vec3.fromXYZ(desc.direction)));

return e;
};
Expand All @@ -811,7 +813,7 @@ Phoria.PhysicsEntity.GRAVITY = {x:0, y:-9.8, z:0};
direction: null,
worlddirection: null,

transformToScene: function transformToScene(scene, matLocal, time)
transformToScene: function transformToScene()
{
this.worlddirection = vec3.fromValues(
-this.direction.x,
Expand Down
2 changes: 1 addition & 1 deletion scripts/phoria-min.js

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions scripts/phoria-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@

if (light instanceof Phoria.DistantLight)
{
// Distant lights have no "position" - they simply light the world with parallel rays from an
// infinitely distant location - closest example is light from the sun when overhead
// Distant lights have no "position", just a direction - they light the world with parallel rays
// from an infinitely distant location - closest example is light from the sun when overhead
// note that light worlddirection is precalculated as negative.
var dotVP = vec3.dot(normal, light.worlddirection);

Expand Down Expand Up @@ -214,7 +214,7 @@
var x = x2 - x1, y = y2 - y1,
det = x * x + y * y, idet;

if (det === 0) det === EPSILON;
if (det === 0) det === Phoria.EPSILON;

idet = pixels / Math.sqrt(det);

Expand Down Expand Up @@ -452,7 +452,7 @@
case "plain":
{
ctx.beginPath();
ctx.arc(coord[0], coord[1], w, 0, TWOPI, true);
ctx.arc(coord[0], coord[1], w, 0, Phoria.TWOPI, true);
ctx.closePath();
ctx.fill();
break;
Expand Down Expand Up @@ -485,7 +485,7 @@
Math.min(Math.ceil(rgb[1] * obj.style.color[1]),255) + "," +
Math.min(Math.ceil(rgb[2] * obj.style.color[2]),255) + ")";
ctx.beginPath();
ctx.arc(coord[0], coord[1], w, 0, TWOPI, true);
ctx.arc(coord[0], coord[1], w, 0, Phoria.TWOPI, true);
ctx.closePath();
ctx.fill();
break;
Expand Down Expand Up @@ -554,7 +554,7 @@
{
case "plain":
{
if (poly.texture === undefined)
if (obj.style.texture === undefined && poly.texture === undefined)
{
fillStyle = color[0] + "," + color[1] + "," + color[2];
}
Expand All @@ -578,9 +578,9 @@

// render the polygon - textured or one of the solid fill modes
ctx.save();
if (poly.texture !== undefined)
if (obj.style.texture !== undefined || poly.texture !== undefined)
{
var bitmap = obj.textures[ poly.texture ],
var bitmap = obj.textures[ poly.texture !== undefined ? poly.texture : obj.style.texture ],
tx0, ty0, tx1, ty1, tx2, ty2;
var fRenderTriangle = function(vs, sx0, sy0, sx1, sy1, sx2, sy2)
{
Expand Down
62 changes: 38 additions & 24 deletions scripts/phoria-scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
};

this.perspective = {
// vertical field-of-view in degrees NOTE: converted to radians for mat4.perspective()
// vertical field-of-view in degrees NOTE: converted to Phoria.RADIANS for mat4.perspective()
fov: 35.0,
// aspect ratio of the view plane
aspect: 1.0,
Expand Down Expand Up @@ -174,6 +174,14 @@
{
scene.onCamera = scene.onCamera.toString();
}*/
for (var p in scene)
{
if (scene.hasOwnProperty(p) && p.indexOf("_") === 0)
{
// remove private property/function before serialisation
delete scene[p];
}
}
if (scene.graph)
{
var fnProcessEntities = function(entities) {
Expand All @@ -186,14 +194,10 @@
if (e.hasOwnProperty(p))
{
// if property name matches "on*Handlers" it is an event handler function list by convention

// TODO: whoops! the *add* event handler methods are called "on..."! e.g. onCamera on a live scene - rename??? or not serialise???
// if not serialise, probably still enough for good debug dump... - also could have "debug" flag that *Does* output private props?

/*if (p.indexOf("on") === 0 && typeof e[p] === "function")
if (p.indexOf("on") === 0 && e[p] instanceof Array)
{
e[p] = e[p].toString();
}*/
}

// TODO: modify all Phoria entity classes to correctly mark private vars with "_"

Expand All @@ -202,14 +206,23 @@
// remove private property/function before serialisation
delete e[p];
}
if (p === "children" && e[p] instanceof Array)
switch (p)
{
fnProcessEntities(e[p]);
case "textures":
delete e[p];
break;

case "children":
if (e[p] instanceof Array)
{
fnProcessEntities(e[p]);
}
break;
}
}
}

// TODO: need to serialise the Entity type into the object structure
// TODO: need to serialise the Entity type into the object structure!
}
};
fnProcessEntities(scene.graph);
Expand Down Expand Up @@ -349,7 +362,7 @@
var perspective = mat4.create();
mat4.perspective(
perspective,
-this.perspective.fov * RADIANS,
-this.perspective.fov * Phoria.RADIANS,
this.perspective.aspect,
this.perspective.near,
this.perspective.far);
Expand All @@ -373,7 +386,7 @@
// used to quickly lookup entities in event handlers without walking child lists etc.
if (obj.id) entityById[obj.id] = obj;

// multiply local with parent matrix to combine affine transformation
// multiply local with parent matrix to combine affine transformations
var matLocal = obj.matrix;
if (matParent)
{
Expand Down Expand Up @@ -408,13 +421,13 @@
verts = obj.points[v];
vec = vec4.set(obj._worldcoords[v], verts.x, verts.y, verts.z, 1.0);

// local object transformation -> world
// local object transformation -> world space
// skip local transform if matrix not present
// else store locally transformed vec4 world points
if (matLocal) vec4.transformMat4(vec, vec, matLocal);
}

// multiply by camera matrix to generate world coords
// multiply by camera matrix to generate camera space coords
for (var v=0; v<len; v++)
{
vec4.transformMat4(obj._coords[v], obj._worldcoords[v], camera);
Expand Down Expand Up @@ -469,7 +482,7 @@
w = vec[3];

// stop divide by zero
if (w === 0) w = EPSILON;
if (w === 0) w = Phoria.EPSILON;

// is this vertex outside the clipping boundries for the perspective frustum?
objClip += (obj._clip[v] = (vec[0] > w+clipOffset || vec[0] < -w-clipOffset ||
Expand All @@ -490,14 +503,12 @@
if (objClip !== len)
{
// normal lighting transformation
if (obj.polygons.length !== 0)
if (obj.style.drawmode === "solid" && obj.polygons.length !== 0)
{
// NOTE: have a flag on scene for "transposedNormalMatrix..."? - i.e. make it optional...

// TODO: have a flag on scene for "transposedNormalMatrix..." - i.e. make it optional?
// invert and transpose the view matrix - for correct normal scaling
var matNormals = mat4.invert(mat4.clone(matLocal), matLocal);
mat4.transpose(matNormals, matNormals);
//var matNormals = matLocal;

switch (obj.style.shademode)
{
Expand All @@ -509,15 +520,17 @@
{
if (!obj.polygons[i]._worldnormal) obj.polygons[i]._worldnormal = vec4.create();

// normal transformation -> world
// normal transformation -> world space
normal = obj.polygons[i].normal;
wnormal = obj.polygons[i]._worldnormal;
vec4.transformMat4(wnormal, normal, matNormals);
vec4.normalize(wnormal, wnormal);
// use vec3 to ensure normal directional component is not modified
vec3.transformMat4(wnormal, normal, matNormals);
vec3.normalize(wnormal, wnormal);
}
break;
}
/*case "gouraud":
/*
case "gouraud":
{
// transform each vertex normal
for (var i=0, normal, wnormal; i<len; i++)
Expand All @@ -528,7 +541,8 @@
vec4.normalize(wnormal, wnormal);
}
break;
}*/
}
*/
}
}

Expand Down
37 changes: 25 additions & 12 deletions scripts/phoria-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@
* @date 10th April 2013
*/

// Global constants
var RADIANS = Math.PI/180.0;
var PI = Math.PI;
var TWOPI = Math.PI*2;
var ONEOPI = 1.0 / Math.PI;
var PIO2 = Math.PI/2;
var EPSILON = 0.000001;

// glMatrix library - many small Arrays are faster without the use of Float32Array wrap/conversion
// init glMatrix library - many small Arrays are faster without the use of Float32Array wrap/conversion
glMatrix.setMatrixArrayType(Array);

/**
Expand All @@ -29,6 +21,16 @@ vec3.fromXYZ = function(xyz) {
return out;
};

/**
* Creates a new xyz object initialized with the given vec3 values
*
* @param {vec3} 3D vector
* @returns {x:0,y:0,z:0} a new xyz object property tuple
*/
vec3.toXYZ = function(vec) {
return {x:vec[0], y:vec[1], z:vec[2]};
};

/**
* Creates a new vec4 initialized with the given xyz tuple and w coordinate
*
Expand Down Expand Up @@ -57,6 +59,15 @@ if (typeof Phoria === "undefined" || !Phoria)
}


// Global Phoria constants
Phoria.RADIANS = Math.PI/180.0;
Phoria.TWOPI = Math.PI*2;
Phoria.ONEOPI = 1.0/Math.PI;
Phoria.PIO2 = Math.PI/2;
Phoria.PIO4 = Math.PI/4;
Phoria.EPSILON = 0.000001;


(function() {
"use strict";

Expand Down Expand Up @@ -269,8 +280,10 @@ if (typeof Phoria === "undefined" || !Phoria)
var v = vec4.fromValues(
(y1 * z2) - (z1 * y2),
-((z2 * x1) - (x2 * z1)),
(x1 * y2) - (y1 * x2), 0 );
return vec4.normalize(v, v);
(x1 * y2) - (y1 * x2),
0);
// use vec3 here to save a pointless multiply * 0 and add op
return vec3.normalize(v, v);
}

/**
Expand Down Expand Up @@ -472,7 +485,7 @@ if (typeof Phoria === "undefined" || !Phoria)
points: [{x:-1*s,y:1*s,z:-1*s}, {x:1*s,y:1*s,z:-1*s}, {x:1*s,y:-1*s,z:-1*s}, {x:-1*s,y:-1*s,z:-1*s},
{x:-1*s,y:1*s,z:1*s}, {x:1*s,y:1*s,z:1*s}, {x:1*s,y:-1*s,z:1*s}, {x:-1*s,y:-1*s,z:1*s}],
edges: [{a:0,b:1}, {a:1,b:2}, {a:2,b:3}, {a:3,b:0}, {a:4,b:5}, {a:5,b:6}, {a:6,b:7}, {a:7,b:4}, {a:0,b:4}, {a:1,b:5}, {a:2,b:6}, {a:3,b:7}],
polygons: [{vertices:[0,1,2,3]},{vertices:[1,5,6,2]},{vertices:[5,4,7,6]},{vertices:[4,0,3,7]},{vertices:[0,4,5,1]},{vertices:[2,6,7,3]}]
polygons: [{vertices:[0,1,2,3]},{vertices:[1,5,6,2]},{vertices:[5,4,7,6]},{vertices:[4,0,3,7]},{vertices:[4,5,1,0]},{vertices:[3,2,6,7]}]
};
}

Expand Down
2 changes: 1 addition & 1 deletion test0.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
if (!pause)
{
// rotate local matrix of the cube
cube.rotateY(0.5*RADIANS);
cube.rotateY(0.5*Phoria.RADIANS);

// execute the model view 3D pipeline and render the scene
scene.modelView();
Expand Down
Loading

0 comments on commit bbf34fb

Please sign in to comment.