package org.papervision3d.core.controller
{
import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.log.PaperLogger;
/**
* The MorphController class controls a mesh's vertices by applying a morph.
*
* Each possible mesh that can be blended (a morph target) must be specified.
* Each morph target is assigned a blend weight. The result is obtained via two methods :
*
*
* - NORMALIZED (Target1, Target2, ...)*(w1, w2, ...) = (1-w1-w2-...)*BaseMesh + w1*Target1 + w2*Target2 + ...
* - RELATIVE (Target1, Target2, ...) + (w1, w2, ...) = BaseMesh + w1*Target1 + w2*Target2 + ...
*
*
* @author Tim Knip / floorplanner.com
*/
public class MorphController implements IObjectController
{
/** */
public var active :Boolean;
/** */
public var target :TriangleMesh3D;
/** */
public var targets :Array;
/** */
public var weights :Array;
/** */
public var normalized :Boolean;
/** */
private var cached :Array;
/**
* Constructor.
*/
public function MorphController(target:TriangleMesh3D, normalized:Boolean=true)
{
this.target = target;
this.active = true;
this.targets = new Array();
this.normalized = normalized;
this.weights = new Array();
this.cached = new Array(target.geometry.vertices.length);
var v :Vertex3D;
for(var i:int = 0; i < cached.length; i++)
{
v = target.geometry.vertices[i];
cached[i] = v.clone();
}
}
/**
*
*/
public function addMorphTarget(mesh:TriangleMesh3D, weight:Number):void
{
if(mesh.geometry.vertices.length != this.target.geometry.vertices.length)
{
PaperLogger.warning("Invalid morph target! " +
"Number of specified vertices (" + mesh.geometry.vertices.length + ")" +
" not equal to number of base vertices (" +
+this.target.geometry.vertices.length + ").");
return;
}
this.targets.push(mesh);
this.weights.push(weight);
}
/**
*
*/
public function update():void
{
var orig :Array = this.target.geometry.vertices;
var cached :Array = this.cached;
var mesh :TriangleMesh3D;
var c :Vertex3D, v :Vertex3D, t :Vertex3D;
var num :int = orig.length;
var totalWeight :Number = 0;
var restWeight :Number, weight :Number;
var i :int, j :int;
if(!this.active)
{
return;
}
if(normalized)
{
for(i = 0; i < weights.length; i++)
{
totalWeight += weights[i];
}
restWeight = 1 - totalWeight;
}
for(i = 0; i < num; i++)
{
v = orig[i];
c = cached[i];
v.x = normalized ? restWeight * c.x : c.x;
v.y = normalized ? restWeight * c.y : c.y;
v.z = normalized ? restWeight * c.z : c.z;
for(j = 0; j < targets.length; j++)
{
mesh = targets[j];
t = mesh.geometry.vertices[i];
weight = weights[j];
v.x += weight * t.x;
v.y += weight * t.y;
v.z += weight * t.z;
}
}
}
}
}