CubeGeometry class
@author mr.doob / http://mrdoob.com/ based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as
Ported to Dart from JS by: @author rob silverton / http://www.unwrong.com/
class CubeGeometry extends Geometry { //List materials; CubeGeomSides _sides; int segmentsWidth; int segmentsHeight; int segmentsDepth; /** * [materialOrList] is a [Material] or a [List] of [Material]. */ CubeGeometry( double width, double height, double depth, [this.segmentsWidth = 1, this.segmentsHeight = 1, this.segmentsDepth = 1, materialOrList, List sides] ) : super() { double width_half = width / 2, height_half = height / 2, depth_half = depth / 2; int mpx, mpy, mpz, mnx, mny, mnz; if ( materialOrList != null ) { if ( materialOrList is List ) { materials = materialOrList; } else { materials = []; for ( int i = 0; i < 6; i ++ ) { materials.add( materialOrList ); } } mpx = 0; mnx = 1; mpy = 2; mny = 3; mpz = 4; mnz = 5; } else { materials = []; } //_sides = { "px": true, "nx": true, "py": true, "ny": true, "pz": true, "nz": true }; _sides = new CubeGeomSides(); //TODO: not sure if this is the correct use of "dynamic" if ( sides != null ) { for ( var s in sides ) { if ( (_sides as dynamic)[ s ] != null ) { (_sides as dynamic)[ s ] = sides[ s ]; } } } if (_sides.px) buildPlane( 'z', 'y', -1.0, -1.0, depth, height, width_half, mpx ); // px if (_sides.nx) buildPlane( 'z', 'y', 1.0, -1.0, depth, height, - width_half, mnx ); // nx if (_sides.py) buildPlane( 'x', 'z', 1.0, 1.0, width, depth, height_half, mpy ); // py if (_sides.ny) buildPlane( 'x', 'z', 1.0, -1.0, width, depth, - height_half, mny ); // ny if (_sides.pz) buildPlane( 'x', 'y', 1.0, -1.0, width, height, depth_half, mpz ); // pz if (_sides.nz) buildPlane( 'x', 'y', -1.0, -1.0, width, height, - depth_half, mnz ); // nz computeCentroids(); mergeVertices(); } void buildPlane( String u, String v, double udir, double vdir, double width, double height, double depth, int material ) { String w; int gridX = ( segmentsWidth != null ) ? segmentsWidth : 1; int gridY = ( segmentsHeight != null ) ? segmentsHeight : 1; double width_half = width / 2.0; double height_half = height / 2.0; int offset = vertices.length; if ( ( u == 'x' && v == 'y' ) || ( u == 'y' && v == 'x' ) ) { w = 'z'; } else if ( ( u == 'x' && v == 'z' ) || ( u == 'z' && v == 'x' ) ) { w = 'y'; gridY = ( segmentsDepth != null ) ? segmentsDepth : 1; } else if ( ( u == 'z' && v == 'y' ) || ( u == 'y' && v == 'z' ) ) { w = 'x'; gridX = ( segmentsDepth != null ) ? segmentsDepth : 1; } num gridX1 = gridX + 1, gridY1 = gridY + 1, segment_width = width / gridX, segment_height = height / gridY; Vector3 normal = new Vector3.zero(); //TODO: find out how to do this sort of casting in Dart... // normal.dynamic[ w ] = depth > 0 ? 1 : - 1; if ( w == 'x' ) { normal.x = depth > 0 ? 1.0 : - 1.0; } else if ( w == 'y' ) { normal.y = depth > 0 ? 1.0 : - 1.0; } else if ( w == 'z' ) normal.z = depth > 0 ? 1.0 : - 1.0; for ( int iy = 0; iy < gridY1; iy ++ ) { for ( int ix = 0; ix < gridX1; ix ++ ) { Vector3 vector = new Vector3.zero(); //TODO: find out how to do this sort of casting in Dart... // vector[ u ] = ( ix * segment_width - width_half ) * udir; // vector[ v ] = ( iy * segment_height - height_half ) * vdir; // vector[ w ] = depth; if ( u == 'x' ) { vector.x = ( ix * segment_width - width_half ) * udir; } else if ( u == 'y' ) { vector.y = ( ix * segment_width - width_half ) * udir; } else if ( u == 'z' ) vector.z = ( ix * segment_width - width_half ) * udir; if ( v == 'x' ) { vector.x = ( iy * segment_height - height_half ) * vdir; } else if ( v == 'y' ) { vector.y = ( iy * segment_height - height_half ) * vdir; } else if ( v == 'z' ) vector.z = ( iy * segment_height - height_half ) * vdir; if ( w == 'x' ) { vector.x = depth; } else if ( w == 'y' ) { vector.y = depth; } else if ( w == 'z' ) vector.z = depth; vertices.add( vector ); } } for ( int iy = 0; iy < gridY; iy++ ) { for ( int ix = 0; ix < gridX; ix++ ) { num a = ix + gridX1 * iy; num b = ix + gridX1 * ( iy + 1 ); num c = ( ix + 1 ) + gridX1 * ( iy + 1 ); num d = ( ix + 1 ) + gridX1 * iy; Face4 face = new Face4( a + offset, b + offset, c + offset, d + offset ); face.normal.setFrom(normal); face.vertexNormals.addAll( [normal.clone(), normal.clone(), normal.clone(), normal.clone()] ); face.materialIndex = material; faces.add( face ); List faceVertexUV = faceVertexUvs[ 0 ]; List newUVs = new List(); newUVs.addAll([ new UV( ix / gridX, iy / gridY ), new UV( ix / gridX, ( iy + 1 ) / gridY ), new UV( ( ix + 1 ) / gridX, ( iy + 1 ) / gridY ), new UV( ( ix + 1 ) / gridX, iy / gridY ) ]); faceVertexUV.add( newUVs ); } } } }
Extends
Geometry > CubeGeometry
Constructors
new CubeGeometry(double width, double height, double depth, [int segmentsWidth = 1, int segmentsHeight = 1, int segmentsDepth = 1, materialOrList, List sides]) #
materialOrList is a Material or a List of Material.
CubeGeometry( double width, double height, double depth, [this.segmentsWidth = 1, this.segmentsHeight = 1, this.segmentsDepth = 1, materialOrList, List sides] ) : super() { double width_half = width / 2, height_half = height / 2, depth_half = depth / 2; int mpx, mpy, mpz, mnx, mny, mnz; if ( materialOrList != null ) { if ( materialOrList is List ) { materials = materialOrList; } else { materials = []; for ( int i = 0; i < 6; i ++ ) { materials.add( materialOrList ); } } mpx = 0; mnx = 1; mpy = 2; mny = 3; mpz = 4; mnz = 5; } else { materials = []; } //_sides = { "px": true, "nx": true, "py": true, "ny": true, "pz": true, "nz": true }; _sides = new CubeGeomSides(); //TODO: not sure if this is the correct use of "dynamic" if ( sides != null ) { for ( var s in sides ) { if ( (_sides as dynamic)[ s ] != null ) { (_sides as dynamic)[ s ] = sides[ s ]; } } } if (_sides.px) buildPlane( 'z', 'y', -1.0, -1.0, depth, height, width_half, mpx ); // px if (_sides.nx) buildPlane( 'z', 'y', 1.0, -1.0, depth, height, - width_half, mnx ); // nx if (_sides.py) buildPlane( 'x', 'z', 1.0, 1.0, width, depth, height_half, mpy ); // py if (_sides.ny) buildPlane( 'x', 'z', 1.0, -1.0, width, depth, - height_half, mny ); // ny if (_sides.pz) buildPlane( 'x', 'y', 1.0, -1.0, width, height, depth_half, mpz ); // pz if (_sides.nz) buildPlane( 'x', 'y', -1.0, -1.0, width, height, - depth_half, mnz ); // nz computeCentroids(); mergeVertices(); }
Properties
Operators
Methods
void applyMatrix(Matrix4 matrix) #
inherited from Geometry
void applyMatrix( Matrix4 matrix ) { Matrix4 matrixRotation = new Matrix4.identity(); extractRotation( matrixRotation, matrix); vertices.forEach((vertex) => vertex.applyProjection(matrix)); faces.forEach((face) { face.normal.applyProjection(matrixRotation); face.vertexNormals.forEach((normal) => normal.applyProjection(matrixRotation)); face.centroid.applyProjection(matrix); }); }
void buildPlane(String u, String v, double udir, double vdir, double width, double height, double depth, int material) #
void buildPlane( String u, String v, double udir, double vdir, double width, double height, double depth, int material ) { String w; int gridX = ( segmentsWidth != null ) ? segmentsWidth : 1; int gridY = ( segmentsHeight != null ) ? segmentsHeight : 1; double width_half = width / 2.0; double height_half = height / 2.0; int offset = vertices.length; if ( ( u == 'x' && v == 'y' ) || ( u == 'y' && v == 'x' ) ) { w = 'z'; } else if ( ( u == 'x' && v == 'z' ) || ( u == 'z' && v == 'x' ) ) { w = 'y'; gridY = ( segmentsDepth != null ) ? segmentsDepth : 1; } else if ( ( u == 'z' && v == 'y' ) || ( u == 'y' && v == 'z' ) ) { w = 'x'; gridX = ( segmentsDepth != null ) ? segmentsDepth : 1; } num gridX1 = gridX + 1, gridY1 = gridY + 1, segment_width = width / gridX, segment_height = height / gridY; Vector3 normal = new Vector3.zero(); //TODO: find out how to do this sort of casting in Dart... // normal.dynamic[ w ] = depth > 0 ? 1 : - 1; if ( w == 'x' ) { normal.x = depth > 0 ? 1.0 : - 1.0; } else if ( w == 'y' ) { normal.y = depth > 0 ? 1.0 : - 1.0; } else if ( w == 'z' ) normal.z = depth > 0 ? 1.0 : - 1.0; for ( int iy = 0; iy < gridY1; iy ++ ) { for ( int ix = 0; ix < gridX1; ix ++ ) { Vector3 vector = new Vector3.zero(); //TODO: find out how to do this sort of casting in Dart... // vector[ u ] = ( ix * segment_width - width_half ) * udir; // vector[ v ] = ( iy * segment_height - height_half ) * vdir; // vector[ w ] = depth; if ( u == 'x' ) { vector.x = ( ix * segment_width - width_half ) * udir; } else if ( u == 'y' ) { vector.y = ( ix * segment_width - width_half ) * udir; } else if ( u == 'z' ) vector.z = ( ix * segment_width - width_half ) * udir; if ( v == 'x' ) { vector.x = ( iy * segment_height - height_half ) * vdir; } else if ( v == 'y' ) { vector.y = ( iy * segment_height - height_half ) * vdir; } else if ( v == 'z' ) vector.z = ( iy * segment_height - height_half ) * vdir; if ( w == 'x' ) { vector.x = depth; } else if ( w == 'y' ) { vector.y = depth; } else if ( w == 'z' ) vector.z = depth; vertices.add( vector ); } } for ( int iy = 0; iy < gridY; iy++ ) { for ( int ix = 0; ix < gridX; ix++ ) { num a = ix + gridX1 * iy; num b = ix + gridX1 * ( iy + 1 ); num c = ( ix + 1 ) + gridX1 * ( iy + 1 ); num d = ( ix + 1 ) + gridX1 * iy; Face4 face = new Face4( a + offset, b + offset, c + offset, d + offset ); face.normal.setFrom(normal); face.vertexNormals.addAll( [normal.clone(), normal.clone(), normal.clone(), normal.clone()] ); face.materialIndex = material; faces.add( face ); List faceVertexUV = faceVertexUvs[ 0 ]; List newUVs = new List(); newUVs.addAll([ new UV( ix / gridX, iy / gridY ), new UV( ix / gridX, ( iy + 1 ) / gridY ), new UV( ( ix + 1 ) / gridX, ( iy + 1 ) / gridY ), new UV( ( ix + 1 ) / gridX, iy / gridY ) ]); faceVertexUV.add( newUVs ); } } }
void computeBoundingBox() #
inherited from Geometry
void computeBoundingBox() { if ( boundingBox == null ) { boundingBox = new BoundingBox( min: new Vector3.zero(), max: new Vector3.zero() ); } if ( vertices.length > 0 ) { Vector3 position, firstPosition = vertices[ 0 ]; boundingBox.min.setFrom( firstPosition ); boundingBox.max.setFrom( firstPosition ); Vector3 min = boundingBox.min, max = boundingBox.max; num vl = vertices.length; for ( int v = 1; v < vl; v ++ ) { position = vertices[ v ]; if ( position.x < min.x ) { min.x = position.x; } else if ( position.x > max.x ) { max.x = position.x; } if ( position.y < min.y ) { min.y = position.y; } else if ( position.y > max.y ) { max.y = position.y; } if ( position.z < min.z ) { min.z = position.z; } else if ( position.z > max.z ) { max.z = position.z; } } } }
void computeBoundingSphere() #
inherited from Geometry
void computeBoundingSphere() { num radiusSq; var maxRadiusSq = vertices.fold(0, (num curMaxRadiusSq, Vector3 vertex) { radiusSq = vertex.length2; return ( radiusSq > curMaxRadiusSq ) ? radiusSq : curMaxRadiusSq; }); boundingSphere = new BoundingSphere(radius: Math.sqrt(maxRadiusSq) ); }
void computeCentroids() #
inherited from Geometry
void computeCentroids() { faces.forEach((Face face) { face.centroid.setValues( 0.0, 0.0, 0.0 ); face.indices.forEach((idx) { face.centroid.add( vertices[ idx ] ); }); face.centroid /= face.size.toDouble(); }); }
void computeFaceNormals() #
inherited from Geometry
void computeFaceNormals() { faces.forEach((face) { var vA = vertices[ face.a ], vB = vertices[ face.b ], vC = vertices[ face.c ]; Vector3 cb = vC - vB; Vector3 ab = vA - vB; cb = cb.cross( ab ); cb.normalize(); face.normal = cb; }); }
void computeTangents() #
inherited from Geometry
void computeTangents() { // based on http://www.terathon.com/code/tangent.html // tangents go to vertices var f, fl, face; num i, il, vertexIndex, test, w; Vector3 vA, vB, vC; UV uvA, uvB, uvC; List uv; num x1, x2, y1, y2, z1, z2, s1, s2, t1, t2, r; Vector3 sdir = new Vector3.zero(), tdir = new Vector3.zero(), tmp = new Vector3.zero(), tmp2 = new Vector3.zero(), n = new Vector3.zero(), t; List<Vector3> tan1 = vertices.map((_) => new Vector3.zero()).toList(), tan2 = vertices.map((_) => new Vector3.zero()).toList(); var handleTriangle = ( context, a, b, c, ua, ub, uc ) { vA = context.vertices[ a ]; vB = context.vertices[ b ]; vC = context.vertices[ c ]; uvA = uv[ ua ]; uvB = uv[ ub ]; uvC = uv[ uc ]; x1 = vB.x - vA.x; x2 = vC.x - vA.x; y1 = vB.y - vA.y; y2 = vC.y - vA.y; z1 = vB.z - vA.z; z2 = vC.z - vA.z; s1 = uvB.u - uvA.u; s2 = uvC.u - uvA.u; t1 = uvB.v - uvA.v; t2 = uvC.v - uvA.v; r = 1.0 / ( s1 * t2 - s2 * t1 ); sdir.setValues( ( t2 * x1 - t1 * x2 ) * r, ( t2 * y1 - t1 * y2 ) * r, ( t2 * z1 - t1 * z2 ) * r ); tdir.setValues( ( s1 * x2 - s2 * x1 ) * r, ( s1 * y2 - s2 * y1 ) * r, ( s1 * z2 - s2 * z1 ) * r ); tan1[ a ].add( sdir ); tan1[ b ].add( sdir ); tan1[ c ].add( sdir ); tan2[ a ].add( tdir ); tan2[ b ].add( tdir ); tan2[ c ].add( tdir ); }; fl = this.faces.length; for ( f = 0; f < fl; f ++ ) { face = this.faces[ f ]; UV uv = faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents // TODO - Come up with a way to handle an arbitrary number of vertexes var triangles = []; if ( face.size == 3 ) { triangles.add([0, 1, 2]); } else if ( face.size == 4 ) { triangles.add([0, 1, 3]); triangles.add([1, 2, 3]); } triangles.forEach((t) { handleTriangle( this, face.indices[t[0]], face.indices[t[1]], face.indices[t[2]], t[0], t[1], t[2] ); }); } faces.forEach((face) { il = face.vertexNormals.length; for ( i = 0; i < il; i++ ) { n.setFrom( face.vertexNormals[ i ] ); vertexIndex = face.indices[i]; t = tan1[ vertexIndex ]; // Gram-Schmidt orthogonalize tmp.setFrom( t ); tmp.sub( n.scale( n.dot( t ) ) ).normalize(); // Calculate handedness tmp2 = face.vertexNormals[i].cross(t); test = tmp2.dot( tan2[ vertexIndex ] ); w = (test < 0.0) ? -1.0 : 1.0; face.vertexTangents[ i ] = new Vector4( tmp.x, tmp.y, tmp.z, w ); } }); hasTangents = true; }
void computeVertexNormals() #
inherited from Geometry
void computeVertexNormals() { List<Vector3> vertices; // create internal buffers for reuse when calling this method repeatedly // (otherwise memory allocation / deallocation every frame is big resource hog) if ( __tmpVertices == null ) { __tmpVertices = []; this.vertices.forEach((_) => __tmpVertices.add(new Vector3.zero())); vertices = __tmpVertices; faces.forEach((face) { face.vertexNormals = new List.generate(face.size, (_) => new Vector3.zero(), growable: false); }); } else { vertices = __tmpVertices; var vl = this.vertices.length; for ( var v = 0; v < vl; v ++ ) { vertices[ v ].setValues( 0.0, 0.0, 0.0 ); } } faces.forEach((Face face) { face.indices.forEach((idx) { vertices[ idx ].add( face.normal ); }); }); vertices.forEach((v) => v.normalize()); faces.forEach((Face face) { var i = 0; face.indices.forEach((idx) { face.vertexNormals[ i++ ].setFrom( vertices[ idx ] ); }); }); }
int mergeVertices() #
inherited from Geometry
int mergeVertices() { Map verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) List<Vector3> unique = []; List<int> changes = []; String key; int precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 num precision = Math.pow( 10, precisionPoints ); int i, il; var abcd = 'abcd', o, k, j, jl, u; Vector3 v; il = this.vertices.length; for( i = 0; i < il; i++) { v = this.vertices[i]; key = [ ( v.x * precision ).round().toStringAsFixed(0), ( v.y * precision ).round().toStringAsFixed(0), ( v.z * precision ).round().toStringAsFixed(0) ].join('_' ); if ( verticesMap[ key ] == null ) { verticesMap[ key ] = i; unique.add( v ); //TODO: pretty sure this is an acceptable change in syntax here: //changes[ i ] = unique.length - 1; changes.add( unique.length - 1); } else { //print('Duplicate vertex found. $i could be using ${verticesMap[key]}'); //print('changes len ${changes.length} add at i = $i'); //changes[ i ] = changes[ verticesMap[ key ] ]; changes.add( changes[ verticesMap[ key ] ] ); } } // Start to patch face indices faces.forEach((Face face) { for (var i = 0; i < face.size; i++) { face.indices[i] = changes[ face.indices[i] ]; /* TODO // check dups in (a, b, c, d) and convert to -> face3 var o = [ face.a, face.b, face.c, face.d ]; for ( var k = 3; k > 0; k -- ) { if ( o.indexOf( face[ abcd[ k ] ] ) != k ) { // console.log('faces', face.a, face.b, face.c, face.d, 'dup at', k); o.removeAt( k ); this.faces[ i ] = new THREE.Face3( o[0], o[1], o[2], face.normal, face.color, face.materialIndex ); for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { u = this.faceVertexUvs[ j ][ i ]; if ( u ) u.removeAt( k ); } this.faces[ i ].vertexColors = face.vertexColors; break; } }*/ } }); // Use unique set of vertices var diff = vertices.length - unique.length; vertices = unique; return diff; }