return function ( dx, dy ) { var proj = this._camera.getProjectionMatrix(); // modulate panning speed with verticalFov value // if it's an orthographic we don't change the panning speed // TODO : manipulators in osgjs don't support well true orthographic camera anyway because they // manage the view matrix (and you need to edit the projection matrix to 'zoom' for true ortho camera) var vFov = proj[ 15 ] === 1 ? 1.0 : 2.00 / proj[ 5 ]; var speed = this.getSpeedFactor() * vFov; dy *= speed; dx *= speed; Matrix.inverse( this._rotation, inv ); x[ 0 ] = Matrix.get( inv, 0, 0 ); x[ 1 ] = Matrix.get( inv, 0, 1 ); x[ 2 ] = Matrix.get( inv, 0, 2 ); Vec3.normalize( x, x ); y[ 0 ] = Matrix.get( inv, 2, 0 ); y[ 1 ] = Matrix.get( inv, 2, 1 ); y[ 2 ] = Matrix.get( inv, 2, 2 ); Vec3.normalize( y, y ); Vec3.mult( x, -dx, x ); Vec3.mult( y, dy, y ); Vec3.add( this._target, x, this._target ); Vec3.add( this._target, y, this._target ); };
return function ( nv ) { var dt = nv.getFrameStamp().getDeltaTime(); var delta; var mouseFactor = 0.1; delta = this._rotate.update( dt ); this.computeRotation( -delta[ 0 ] * mouseFactor * this._scaleMouseMotion, -delta[ 1 ] * mouseFactor * this._scaleMouseMotion ); var panFactor = 0.002; delta = this._pan.update( dt ); this.computePan( -delta[ 0 ] * panFactor, -delta[ 1 ] * panFactor ); delta = this._zoom.update( dt ); this.computeZoom( 1.0 + delta[ 0 ] / 10.0 ); var target = this._target; var distance = this._distance; /* 1. Works but bypass other manipulators */ // Matrix.copy( this._rotBase, this._inverseMatrix ); /* 2. Works but gets broken by other manipulators */ Matrix.inverse( this._rotation, this._inverseMatrix ); Matrix.postMult( this._rotBase, this._inverseMatrix ); /* 3. Doesnt' work */ // Matrix.preMult( this._rotBase, this._rotation ); // Matrix.inverse( this._rotBase, this._inverseMatrix ); Vec3.set( 0.0, distance, 0.0, eye ); Matrix.transformVec3( this._inverseMatrix, eye, eye ); Matrix.makeLookAt( Vec3.add( target, eye, eye ), target, this._upz, this._inverseMatrix ); };
return function ( yawDelta, pitchDelta ) { Quat.transformVec3( this._orientation, this._right, right ); Vec3.normalize( right, rightNormalized ); Vec3.sub( this._eye, this._pivotPoint, dir ); var scalar = Vec3.dot( rightNormalized, dir ); Vec3.sub( dir, Vec3.mult( rightNormalized, scalar, rightScalar ), offset ); var xy = Vec3.createAndSet( -offset[ 0 ], -offset[ 1 ], 0 ); var positionPitch = Math.atan2( -offset[ 2 ], Vec3.length( xy ) ); pitchDelta = Math.max( -Math.PI / 2 + 0.01, Math.min( Math.PI / 2 - 0.01, ( positionPitch + pitchDelta ) ) ) - positionPitch; Quat.makeRotate( pitchDelta * this._rotateFactor, right[ 0 ], right[ 1 ], right[ 2 ], pitchQuat ); Quat.makeRotate( yawDelta * this._rotateFactor, this._upz[ 0 ], this._upz[ 1 ], this._upz[ 2 ], yawQuat ); Quat.mult( yawQuat, pitchQuat, pitchyawQuat ); Quat.transformVec3( pitchyawQuat, dir, tmp ); Vec3.add( tmp, this._pivotPoint, this._eye ); // Find rotation offset and target Quat.mult( yawQuat, this._orientation, this._orientation ); Quat.transformVec3( this._orientation, this._right, right ); Quat.makeRotate( pitchDelta * this._rotateFactor, right[ 0 ], right[ 1 ], right[ 2 ], pitchQuat ); Quat.mult( pitchQuat, this._orientation, this._orientation ); };
startTranslateEdit: function ( e ) { var origin = this._editLineOrigin; var dir = this._editLineDirection; // 3d origin (center of gizmo) var gizmoMat = this._translateNode.getWorldMatrices()[ 0 ]; Matrix.getTrans( gizmoMat, origin ); // 3d direction Vec3.init( dir ); dir[ this._hoverNode._nbAxis ] = 1.0; if ( this._translateInLocal ) { Matrix.transformVec3( this._editWorldScaleRot, dir, dir ); Vec3.normalize( dir, dir ); } Vec3.add( origin, dir, dir ); // project on canvas this.getCanvasPositionFromWorldPoint( origin, origin ); this.getCanvasPositionFromWorldPoint( dir, dir ); Vec2.sub( dir, origin, dir ); Vec2.normalize( dir, dir ); var offset = this._editOffset; getCanvasCoord( offset, e ); Vec2.sub( offset, origin, offset ); },
return function ( dx, dy, rotMat ) { var speed = Vec3.length( Vec3.sub( this._eye, this._pivotPoint, speedTmp ) ) / this._panFactor; if ( speed < 10 ) speed = 10; trans[ 0 ] = dx * speed / 2; trans[ 1 ] = dy * speed / 2; trans[ 2 ] = 0; Matrix.transformVec3( rotMat, trans, rotPos ); Vec3.add( this._eye, rotPos, this._eye ); };
return function ( ratio ) { var newValue = this._distance + this.getSpeedFactor() * ( ratio - 1.0 ); if ( newValue < this._minDistance ) { if ( this._autoPushTarget ) { // push the target instead of zooming on it Vec3.sub( this._target, this.getEyePosition( dir ), dir ); Vec3.normalize( dir, dir ); Vec3.mult( dir, this._minDistance - newValue, dir ); Vec3.add( this._target, dir, this._target ); } newValue = this._minDistance; } if ( newValue > this._maxDistance ) newValue = this._maxDistance; this._distance = newValue; };
var PolytopeIntersection = function ( index, candidates, candidatesMasks, referencePlane, nodePath ) { this._index = index - 1; ///< primitive index this._distance = 0; ///< distance from reference plane this._maxDistance = -1; ///< maximum distance of intersection points from reference plane this._numPoints = 0; this._points = []; this._maxNumIntersections = 6; this._center = Vec3.create(); for ( var i = 0, j = candidates.length; i < j; i++ ) { if ( candidatesMasks[ i ] === 0 ) continue; this._points[ this._numPoints++ ] = Vec3.copy( candidates[ i ], Vec3.create() ); Vec3.add( this._center, candidates[ i ], this._center ); var distance = referencePlane[ 0 ] * candidates[ i ][ 0 ] + referencePlane[ 1 ] * candidates[ i ][ 1 ] + referencePlane[ 2 ] * candidates[ i ][ 2 ] + referencePlane[ 3 ]; if ( distance > this._maxDistance ) this._maxDistance = distance; if ( this._numPoints === this._maxNumIntesections ) break; } Vec3.mult( this._center, 1 / this._numPoints, this._center ); this._distance = referencePlane[ 0 ] * this._center[ 0 ] + referencePlane[ 1 ] * this._center[ 1 ] + referencePlane[ 2 ] * this._center[ 2 ] + referencePlane[ 3 ]; this.nodePath = nodePath; };
return function () { if ( this._lines.length > 0 ) return this._lines; // Polytope lines already calculated var selectorMask = 0x1; for ( var i = 0, j = this._planes.length; i < j; i++, selectorMask <<= 1 ) { Vec3.copy( this.getNormal( this._planes[ i ] ), normal1 ); Vec3.mult( normal1, -this._planes[ i ][ 3 ], point1 ); // canonical point on plane[ i ] var subSelectorMask = ( selectorMask << 1 ); for ( var jt = i + 1, k = this._planes.length; jt < k; ++jt, subSelectorMask <<= 1 ) { Vec3.copy( this.getNormal( this._planes[ jt ] ), normal2 ); if ( Math.abs( Vec3.dot( normal1, normal2 ) ) > ( 1.0 - epsilon ) ) continue; Vec3.cross( normal1, normal2, lineDirection ); Vec3.cross( lineDirection, normal1, searchDirection ); //-plane2.distance(point1)/(searchDirection*normal2); var searchDist = -this.distance( this._planes[ jt ], point1 ) / Vec3.dot( searchDirection, normal2 ); if ( osgMath.isNaN( searchDist ) ) continue; Vec3.mult( searchDirection, searchDist, linePoint ); Vec3.add( point1, lineDirection, lineDirection ); this._lines.push( new PlanesLine( selectorMask | subSelectorMask, Vec3.copy( linePoint, Vec3.create() ), Vec3.copy( lineDirection, Vec3.create() ) ) ); } } return this._lines; };
return function ( bb ) { if ( !bb.valid() ) return; if ( this.valid() ) { Vec3.copy( bb._min, newbb._min ); Vec3.copy( bb._max, newbb._max ); for ( var i = 0; i < 8; i++ ) { Vec3.sub( bb.corner( i, v ), this._center, v ); // get the direction vector from corner Vec3.normalize( v, v ); // normalise it. Vec3.mult( v, -this._radius, v ); // move the vector in the opposite direction distance radius. Vec3.add( v, this._center, v ); // move to absolute position. newbb.expandByVec3( v ); // add it into the new bounding box. } newbb.center( this._center ); this._radius = newbb.radius(); } else { bb.center( this._center ); this._radius = bb.radius(); } };
return function ( s, e, bb ) { var min = bb._min; var xmin = min[ 0 ]; var ymin = min[ 1 ]; var zmin = min[ 2 ]; var max = bb._max; var xmax = max[ 0 ]; var ymax = max[ 1 ]; var zmax = max[ 2 ]; var invX = this._dInvX; var invY = this._dInvY; var invZ = this._dInvZ; if ( s[ 0 ] <= e[ 0 ] ) { // trivial reject of segment wholely outside. if ( e[ 0 ] < xmin ) return false; if ( s[ 0 ] > xmax ) return false; if ( s[ 0 ] < xmin ) { // clip s to xMin. Vec3.mult( invX, xmin - s[ 0 ], tmp ); Vec3.add( s, tmp, s ); } if ( e[ 0 ] > xmax ) { // clip e to xMax. Vec3.mult( invX, xmax - s[ 0 ], tmp ); Vec3.add( s, tmp, e ); } } else { if ( s[ 0 ] < xmin ) return false; if ( e[ 0 ] > xmax ) return false; if ( e[ 0 ] < xmin ) { // clip s to xMin. Vec3.mult( invX, xmin - s[ 0 ], tmp ); Vec3.add( s, tmp, e ); } if ( s[ 0 ] > xmax ) { // clip e to xMax. Vec3.mult( invX, xmax - s[ 0 ], tmp ); Vec3.add( s, tmp, s ); } } // compate s and e against the yMin to yMax range of bb. if ( s[ 1 ] <= e[ 1 ] ) { // trivial reject of segment wholely outside. if ( e[ 1 ] < ymin ) return false; if ( s[ 1 ] > ymax ) return false; if ( s[ 1 ] < ymin ) { // clip s to yMin. Vec3.mult( invY, ymin - s[ 1 ], tmp ); Vec3.add( s, tmp, s ); } if ( e[ 1 ] > ymax ) { // clip e to yMax. Vec3.mult( invY, ymax - s[ 1 ], tmp ); Vec3.add( s, tmp, e ); } } else { if ( s[ 1 ] < ymin ) return false; if ( e[ 1 ] > ymax ) return false; if ( e[ 1 ] < ymin ) { // clip s to yMin. Vec3.mult( invY, ymin - s[ 1 ], tmp ); Vec3.add( s, tmp, e ); } if ( s[ 1 ] > ymax ) { // clip e to yMax. Vec3.mult( invY, ymax - s[ 1 ], tmp ); Vec3.add( s, tmp, s ); } } // compate s and e against the zMin to zMax range of bb. if ( s[ 2 ] <= e[ 2 ] ) { // trivial reject of segment wholely outside. if ( e[ 2 ] < zmin ) return false; if ( s[ 2 ] > zmax ) return false; if ( s[ 2 ] < zmin ) { // clip s to zMin. Vec3.mult( invZ, zmin - s[ 2 ], tmp ); Vec3.add( s, tmp, s ); } if ( e[ 2 ] > zmax ) { // clip e to zMax. Vec3.mult( invZ, zmax - s[ 2 ], tmp ); Vec3.add( s, tmp, e ); } } else { if ( s[ 2 ] < zmin ) return false; if ( e[ 2 ] > zmax ) return false; if ( e[ 2 ] < zmin ) { // clip s to zMin. Vec3.mult( invZ, zmin - s[ 2 ], tmp ); Vec3.add( s, tmp, e ); } if ( s[ 2 ] > zmax ) { // clip e to zMax. Vec3.mult( invZ, zmax - s[ 2 ], tmp ); Vec3.add( s, tmp, s ); } } return true; };
return function ( v1, v2, v3 ) { this._index++; if ( ( this._dimensionMask & ( 1 << 2 ) ) === 0 ) return; if ( this._limitOneIntersection && this._intersections.length > 0 ) return; var selectorMask = 0x1; var insideMask = 0x0; this._candidates = []; this._candidatesMasks = []; var d1, d2, d3, d1IsNegative, d2IsNegative, d3IsNegative; for ( var i = 0, j = this._planes.length; i < j; ++i, selectorMask <<= 1 ) { d1 = this.distance( this._planes[ i ], v1 ); d2 = this.distance( this._planes[ i ], v2 ); d3 = this.distance( this._planes[ i ], v3 ); d1IsNegative = ( d1 < 0.0 ); d2IsNegative = ( d2 < 0.0 ); d3IsNegative = ( d3 < 0.0 ); if ( d1IsNegative && d2IsNegative && d3IsNegative ) return; // Triangle outside if ( !d1IsNegative && !d2IsNegative && !d3IsNegative ) { // completly inside this plane insideMask |= selectorMask; continue; } // edge v1-v2 intersects if ( d1 === 0.0 ) { Vec3.copy( v1, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } else if ( d2 === 0.0 ) { Vec3.copy( v2, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } else if ( d1IsNegative && !d2IsNegative ) { //v1-(v2-v1)*(d1/(-d1+d2))) ) Vec3.sub( v2, v1, tmpHit ); Vec3.mult( tmpHit, d1 / ( -d1 + d2 ), tmpHit ); Vec3.sub( v1, tmpHit, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } else if ( !d1IsNegative && d2IsNegative ) { //(v1+(v2-v1)*(d1/(d1-d2))) Vec3.sub( v2, v1, tmpHit ); Vec3.mult( tmpHit, d1 / ( d1 - d2 ), tmpHit ); Vec3.add( v1, tmpHit, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } // edge v1-v3 intersects if ( d3 === 0.0 ) { Vec3.copy( v3, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } else if ( d1IsNegative && !d3IsNegative ) { // v1-(v3-v1)*(d1/(-d1+d3)) Vec3.sub( v3, v1, tmpHit ); Vec3.mult( tmpHit, d1 / ( -d1 + d3 ), tmpHit ); Vec3.sub( v1, tmpHit, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } else if ( !d1IsNegative && d3IsNegative ) { // v1+(v3-v1)*(d1/(d1-d3)) Vec3.sub( v3, v1, tmpHit ); Vec3.mult( tmpHit, d1 / ( d1 - d3 ), tmpHit ); Vec3.add( v1, tmpHit, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } // edge v2-v3 intersects if ( d2IsNegative && !d3IsNegative ) { // v2-(v3-v2)*(d2/(-d2+d3)) Vec3.sub( v3, v2, tmpHit ); Vec3.mult( tmpHit, d2 / ( -d2 + d3 ), tmpHit ); Vec3.sub( v2, tmpHit, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } else if ( !d2IsNegative && d3IsNegative ) { //v2+(v3-v2)*(d2/(d2-d3)) Vec3.sub( v3, v2, tmpHit ); Vec3.mult( tmpHit, d2 / ( d2 - d3 ), tmpHit ); Vec3.add( v2, tmpHit, tmpHit ); this._candidates.push( Vec3.copy( tmpHit, Vec3.create() ) ); this._candidatesMasks.push( selectorMask ); } } if ( insideMask === this._planesMask ) { // triangle lies inside of all planes this._candidates.push( Vec3.copy( v1, Vec3.create() ) ); this._candidatesMasks.push( this._planesMask ); this._candidates.push( Vec3.copy( v2, Vec3.create() ) ); this._candidatesMasks.push( this._planesMask ); this._candidates.push( Vec3.copy( v3, Vec3.create() ) ); this._candidatesMasks.push( this._planesMask ); this._intersections.push( new PolytopeIntersection( this._index, this._candidates, this._candidatesMasks, this._referencePlane, this._nodePath.slice( 0 ) ) ); return; } var numCands = this.checkCandidatePoints( insideMask ); if ( numCands > 0 ) { this._intersections.push( new PolytopeIntersection( this._index, this._candidates, this._candidatesMasks, this._referencePlane, this._nodePath.slice( 0 ) ) ); return; } // handle case where the polytope goes through the triangle // without containing any point of it // Probably it can be moved to other function and do the relevant closures. var lines = this.getPolytopeLines(); this._candidates = []; // check all polytope lines against the triangle // use algorithm from "Real-time rendering" (second edition) pp.580 //var e1= Vec3.create(); //var e2= Vec3.create(); Vec3.sub( v2, v1, e1 ); Vec3.sub( v3, v1, e2 ); for ( i = 0; i < lines.length; ++i ) { //var point = Vec3.create(); //var p = Vec3.create(); Vec3.cross( lines[ i ]._dir, e2, p ); var a = Vec3.dot( e1, p ); if ( Math.abs( a ) < 1E-6 ) continue; var f = 1.0 / a; //var s = Vec3.create(); Vec3.sub( lines[ i ]._pos, v1, s ); var u = f * ( Vec3.dot( s, p ) ); if ( u < 0.0 || u > 1.0 ) continue; //var q = Vec3.create(); Vec3.cross( s, e1, q ); var v = f * ( Vec3.dot( lines[ i ]._dir, q ) ); if ( v < 0.0 || u + v > 1.0 ) continue; var t = f * ( Vec3.dot( e2, q ) ); Vec3.mult( lines[ i ]._dir, t, point ); Vec3.add( lines[ i ]._pos, point, point ); this._candidates.push( Vec3.copy( point, Vec3.create() ) ); this._candidatesMasks.push( lines[ i ]._planeMask ); } numCands = this.checkCandidatePoints( insideMask ); if ( numCands > 0 ) { this._intersections.push( new PolytopeIntersection( this._index, this._candidates, this._candidatesMasks, this._referencePlane, this._nodePath.slice( 0 ) ) ); return; } };
return function ( v1, v2 ) { this._index++; if ( ( this._dimensionMask & ( 1 << 1 ) ) === 0 ) return; if ( this._limitOneIntersection && this._intersections.length > 0 ) return; var v1Inside = true; var v2Inside = true; var selectorMask = 0x1; var insideMask = 0x0; this._candidates = []; this._candidatesMasks = []; var d1, d2, d1IsNegative, d2IsNegative; for ( var i = 0, j = this._planes.length; i < j; ++i, selectorMask <<= 1 ) { d1 = this.distance( this._planes[ i ], v1 ); d2 = this.distance( this._planes[ i ], v2 ); d1IsNegative = ( d1 < 0.0 ); d2IsNegative = ( d2 < 0.0 ); if ( d1IsNegative && d2IsNegative ) return; // line outside if ( !d1IsNegative && !d2IsNegative ) { // completly inside this plane insideMask |= selectorMask; continue; } if ( d1IsNegative ) v1Inside = false; if ( d2IsNegative ) v2Inside = false; if ( d1 === 0.0 ) { Vec3.copy( v1, hit ); this._candidates.push( hit ); this._candidatesMasks.push( selectorMask ); } else if ( d2 === 0.0 ) { Vec3.copy( v2, hit ); this._candidates.push( hit ); this._candidatesMasks.push( selectorMask ); } else if ( d1IsNegative && !d2IsNegative ) { //v1-(v2-v1)*(d1/(-d1+d2))) ) Vec3.sub( v2, v1, hit ); Vec3.mult( hit, d1 / ( -d1 + d2 ), hit ); Vec3.sub( v1, hit, hit ); this._candidates.push( hit ); this._candidatesMasks.push( selectorMask ); } else if ( !d1IsNegative && d2IsNegative ) { //(v1+(v2-v1)*(d1/(d1-d2))) Vec3.sub( v2, v1, hit ); Vec3.mult( hit, d1 / ( d1 - d2 ), hit ); Vec3.add( v1, hit, hit ); this._candidates.push( hit ); this._candidatesMasks.push( selectorMask ); } } if ( insideMask === this._planesMask ) { this._candidates.push( Vec3.copy( v1, Vec3.create() ) ); this._candidatesMasks.push( this._planesMask ); this._candidates.push( Vec3.copy( v2, Vec3.create() ) ); this._candidatesMasks.push( this._planesMask ); this._intersections.push( new PolytopeIntersection( this._index, this._candidates, this._candidatesMasks, this._referencePlane, this._nodePath.slice( 0 ) ) ); return; } var numCands = this.checkCandidatePoints( insideMask ); if ( numCands > 0 ) { if ( v1Inside ) { this._candidatesMasks.push( this._planesMask ); this._candidates.push( Vec3.copy( v1, Vec3.create() ) ); } if ( v2Inside ) { this._candidatesMasks.push( this._planesMask ); this._candidates.push( Vec3.copy( v2, Vec3.create() ) ); } this._intersections.push( new PolytopeIntersection( this._index, this._candidates, this._candidatesMasks, this._referencePlane, this._nodePath.slice( 0 ) ) ); } };
return function ( target, distance, eye ) { Matrix.inverse( this._rotation, tmpInverse ); tmpDist[ 1 ] = distance; Matrix.transformVec3( tmpInverse, tmpDist, eye ); Vec3.add( target, eye, eye ); };
return function ( dz ) { var zoomSpeed = dz * this._zoomFactor; Vec3.sub( this._pivotPoint, this._eye, vectorDistance ); Vec3.add( this._eye, Vec3.mult( vectorDistance, zoomSpeed, speedDist ), this._eye ); };
compute: function ( primitiveSet, vx, nx, tx, ia, ib, ic ) { var i0 = primitiveSet.index( ia ); var i1 = primitiveSet.index( ib ); var i2 = primitiveSet.index( ic ); // TODO perf : cache xx.getElements() but more importantly // subarray call have very high overhead, it's super useful // when you call it a few times for big array chunk, but for // small array extraction (each vertex) it's better to use a temporary // pre allocated array and simply fill it // then, you'll have to write in the big arrays at the end var P1 = vx.getElements().subarray( i0 * 3, i0 * 3 + 3 ); var P2 = vx.getElements().subarray( i1 * 3, i1 * 3 + 3 ); var P3 = vx.getElements().subarray( i2 * 3, i2 * 3 + 3 ); var N1 = nx.getElements().subarray( i0 * 3, i0 * 3 + 3 ); var N2 = nx.getElements().subarray( i1 * 3, i1 * 3 + 3 ); var N3 = nx.getElements().subarray( i2 * 3, i2 * 3 + 3 ); var uv1 = tx.getElements().subarray( i0 * 2, i0 * 2 + 2 ); var uv2 = tx.getElements().subarray( i1 * 2, i1 * 2 + 2 ); var uv3 = tx.getElements().subarray( i2 * 2, i2 * 2 + 2 ); var vz, vy; // TODO perf : use temporary vec var V = Vec3.create(); var B1 = Vec3.create(); var B2 = Vec3.create(); var B3 = Vec3.create(); var T1 = Vec3.create(); var T2 = Vec3.create(); var T3 = Vec3.create(); var v1 = Vec3.create(); var v2 = Vec3.create(); Vec3.set( P2[ 0 ] - P1[ 0 ], uv2[ 0 ] - uv1[ 0 ], uv2[ 1 ] - uv1[ 1 ], v1 ); Vec3.set( P3[ 0 ] - P1[ 0 ], uv3[ 0 ] - uv1[ 0 ], uv3[ 1 ] - uv1[ 1 ], v2 ); Vec3.cross( v1, v2, V ); if ( V[ 0 ] !== 0.0 ) { Vec3.normalize( V, V ); vy = -V[ 1 ] / V[ 0 ]; vz = -V[ 2 ] / V[ 0 ]; T1[ 0 ] += vy; B1[ 0 ] += vz; T2[ 0 ] += vy; B2[ 0 ] += vz; T3[ 0 ] += vy; B3[ 0 ] += vz; } Vec3.set( P2[ 1 ] - P1[ 1 ], uv2[ 0 ] - uv1[ 0 ], uv2[ 1 ] - uv1[ 1 ], v1 ); Vec3.set( P3[ 1 ] - P1[ 1 ], uv3[ 0 ] - uv1[ 0 ], uv3[ 1 ] - uv1[ 1 ], v2 ); Vec3.cross( v1, v2, V ); if ( V[ 0 ] !== 0.0 ) { Vec3.normalize( V, V ); vy = -V[ 1 ] / V[ 0 ]; vz = -V[ 2 ] / V[ 0 ]; T1[ 1 ] += vy; B1[ 1 ] += vz; T2[ 1 ] += vy; B2[ 1 ] += vz; T3[ 1 ] += vy; B3[ 1 ] += vz; } Vec3.set( P2[ 2 ] - P1[ 2 ], uv2[ 0 ] - uv1[ 0 ], uv2[ 1 ] - uv1[ 1 ], v1 ); Vec3.set( P3[ 2 ] - P1[ 2 ], uv3[ 0 ] - uv1[ 0 ], uv3[ 1 ] - uv1[ 1 ], v2 ); Vec3.cross( v1, v2, V ); if ( V[ 0 ] !== 0.0 ) { Vec3.normalize( V, V ); vy = -V[ 1 ] / V[ 0 ]; vz = -V[ 2 ] / V[ 0 ]; T1[ 2 ] += vy; B1[ 2 ] += vz; T2[ 2 ] += vy; B2[ 2 ] += vz; T3[ 2 ] += vy; B3[ 2 ] += vz; } var tempVec = Vec3.create(); var tempVec2 = Vec3.create(); var Tdst, Bdst, Ndst; Vec3.cross( N1, T1, tempVec ); Vec3.cross( tempVec, N1, tempVec2 ); Tdst = this._T.subarray( i0 * 3, i0 * 3 + 3 ); Vec3.add( tempVec2, Tdst, Tdst ); Vec3.cross( B1, N1, tempVec ); Vec3.cross( N1, tempVec, tempVec2 ); Bdst = this._B.subarray( i0 * 3, i0 * 3 + 3 ); Vec3.add( tempVec2, Bdst, Bdst ); Vec3.cross( N2, T2, tempVec ); Vec3.cross( tempVec, N2, tempVec2 ); Tdst = this._T.subarray( i1 * 3, i1 * 3 + 3 ); Vec3.add( tempVec2, Tdst, Tdst ); Vec3.cross( B2, N2, tempVec ); Vec3.cross( N2, tempVec, tempVec2 ); Bdst = this._B.subarray( i1 * 3, i1 * 3 + 3 ); Vec3.add( tempVec2, Bdst, Bdst ); Vec3.cross( N3, T3, tempVec ); Vec3.cross( tempVec, N3, tempVec2 ); Tdst = this._T.subarray( i2 * 3, i2 * 3 + 3 ); Vec3.add( tempVec2, Tdst, Tdst ); Vec3.cross( B3, N3, tempVec ); Vec3.cross( N3, tempVec, tempVec2 ); Bdst = this._B.subarray( i2 * 3, i2 * 3 + 3 ); Vec3.add( tempVec2, Bdst, Bdst ); Ndst = this._N.subarray( i0 * 3, i0 * 3 + 3 ); Vec3.add( N1, Ndst, Ndst ); Ndst = this._N.subarray( i1 * 3, i1 * 3 + 3 ); Vec3.add( N2, Ndst, Ndst ); Ndst = this._N.subarray( i2 * 3, i2 * 3 + 3 ); Vec3.add( N3, Ndst, Ndst ); }