kopia lustrzana https://github.com/OpenDroneMap/WebODM
762 wiersze
24 KiB
JavaScript
762 wiersze
24 KiB
JavaScript
'use strict';
|
|
var Notify = require( 'osg/notify' );
|
|
var MACROUTILS = require( 'osg/Utils' );
|
|
var osgMath = require( 'osg/math' );
|
|
var NodeVisitor = require( 'osg/NodeVisitor' );
|
|
var CullSettings = require( 'osg/CullSettings' );
|
|
var CullStack = require( 'osg/CullStack' );
|
|
var mat4 = require( 'osg/glMatrix' ).mat4;
|
|
var MatrixTransform = require( 'osg/MatrixTransform' );
|
|
var AutoTransform = require( 'osg/AutoTransform' );
|
|
var Projection = require( 'osg/Projection' );
|
|
var LightSource = require( 'osg/LightSource' );
|
|
var osgPool = require( 'osgUtil/osgPool' );
|
|
var Geometry = require( 'osg/Geometry' );
|
|
var RenderLeaf = require( 'osg/RenderLeaf' );
|
|
var RenderBin = require( 'osg/RenderBin' );
|
|
var RenderStage = require( 'osg/RenderStage' );
|
|
var Node = require( 'osg/Node' );
|
|
var Lod = require( 'osg/Lod' );
|
|
var PagedLOD = require( 'osg/PagedLOD' );
|
|
var Camera = require( 'osg/Camera' );
|
|
var TransformEnums = require( 'osg/transformEnums' );
|
|
var vec3 = require( 'osg/glMatrix' ).vec3;
|
|
var Skeleton = require( 'osgAnimation/Skeleton' );
|
|
var RigGeometry = require( 'osgAnimation/RigGeometry' );
|
|
var Bone = require( 'osgAnimation/Bone' );
|
|
var MorphGeometry = require( 'osgAnimation/MorphGeometry' );
|
|
|
|
/**
|
|
* CullVisitor traverse the tree and collect Matrix/State for the rendering traverse
|
|
* @class CullVisitor
|
|
*/
|
|
var CullVisitor = function () {
|
|
NodeVisitor.call( this, NodeVisitor.TRAVERSE_ACTIVE_CHILDREN );
|
|
CullSettings.call( this );
|
|
CullStack.call( this );
|
|
|
|
this._rootStateGraph = undefined;
|
|
this._currentStateGraph = undefined;
|
|
this._currentRenderBin = undefined;
|
|
this._currentRenderStage = undefined;
|
|
this._rootRenderStage = undefined;
|
|
this._computedNear = Number.POSITIVE_INFINITY;
|
|
this._computedFar = Number.NEGATIVE_INFINITY;
|
|
|
|
var lookVector = vec3.fromValues( 0.0, 0.0, -1.0 );
|
|
this._camera = undefined;
|
|
/*jshint bitwise: false */
|
|
this._bbCornerFar = ( lookVector[ 0 ] >= 0 ? 1 : 0 ) | ( lookVector[ 1 ] >= 0 ? 2 : 0 ) | ( lookVector[ 2 ] >= 0 ? 4 : 0 );
|
|
this._bbCornerNear = ( ~this._bbCornerFar ) & 7;
|
|
/*jshint bitwise: true */
|
|
|
|
this._reserveLeafStack = [ new RenderLeaf() ];
|
|
this._reserveLeafStackCurrent = 0;
|
|
|
|
this._reserveRenderStageStacks = {};
|
|
|
|
this._reserveCullSettingsStack = [ new CullSettings() ];
|
|
this._reserveCullSettingsStackCurrent = 0;
|
|
|
|
this._renderBinStack = [];
|
|
this.visitorType = NodeVisitor.CULL_VISITOR;
|
|
|
|
this._identityMatrix = mat4.create();
|
|
|
|
this._renderer = undefined;
|
|
this._renderStageType = RenderStage;
|
|
|
|
this._numCamera = 0;
|
|
this._numMatrixTransform = 0;
|
|
this._numProjection = 0;
|
|
this._numNode = 0;
|
|
this._numLightSource = 0;
|
|
this._numGeometry = 0;
|
|
|
|
};
|
|
|
|
/** @lends CullVisitor.prototype */
|
|
CullVisitor.prototype = MACROUTILS.objectInherit( CullStack.prototype, MACROUTILS.objectInherit( NodeVisitor.prototype, {
|
|
distance: function ( coord, matrix ) {
|
|
return -( coord[ 0 ] * matrix[ 2 ] + coord[ 1 ] * matrix[ 6 ] + coord[ 2 ] * matrix[ 10 ] + matrix[ 14 ] );
|
|
},
|
|
|
|
getComputedNear: function () {
|
|
return this._computedNear;
|
|
},
|
|
|
|
getComputedFar: function () {
|
|
return this._computedFar;
|
|
},
|
|
|
|
resetStats: function () {
|
|
this._numCamera = 0;
|
|
this._numMatrixTransform = 0;
|
|
this._numProjection = 0;
|
|
this._numNode = 0;
|
|
this._numLightSource = 0;
|
|
this._numGeometry = 0;
|
|
},
|
|
|
|
handleCullCallbacksAndTraverse: function ( node ) {
|
|
var ccb = node.getCullCallback();
|
|
if ( ccb && !ccb.cull( node, this ) )
|
|
return;
|
|
this.traverse( node );
|
|
},
|
|
|
|
getCurrentCamera: function () {
|
|
return this._currentRenderBin.getStage().getCamera();
|
|
},
|
|
|
|
updateCalculatedNearFar: ( function () {
|
|
var nearVec = vec3.create();
|
|
var farVec = vec3.create();
|
|
|
|
return function ( matrix, drawable ) {
|
|
|
|
var bb = drawable.getBoundingBox();
|
|
var dNear, dFar;
|
|
|
|
// efficient computation of near and far, only taking into account the nearest and furthest
|
|
// corners of the bounding box.
|
|
dNear = this.distance( bb.corner( this._bbCornerNear, nearVec ), matrix );
|
|
dFar = this.distance( bb.corner( this._bbCornerFar, farVec ), matrix );
|
|
|
|
if ( dNear > dFar ) {
|
|
var tmp = dNear;
|
|
dNear = dFar;
|
|
dFar = tmp;
|
|
}
|
|
|
|
if ( dFar < 0.0 ) {
|
|
// whole object behind the eye point so discard
|
|
return false;
|
|
}
|
|
|
|
if ( dNear < this._computedNear ) {
|
|
this._computedNear = dNear;
|
|
}
|
|
|
|
if ( dFar > this._computedFar ) {
|
|
this._computedFar = dFar;
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
} )(),
|
|
|
|
|
|
setStateGraph: function ( sg ) {
|
|
this._rootStateGraph = sg;
|
|
this._currentStateGraph = sg;
|
|
},
|
|
setRenderStage: function ( rg ) {
|
|
this._rootRenderStage = rg;
|
|
this._currentRenderBin = rg;
|
|
},
|
|
setRenderer: function ( renderer ) {
|
|
this._renderer = renderer;
|
|
},
|
|
getRenderer: function () {
|
|
return this._renderer;
|
|
},
|
|
|
|
reset: function () {
|
|
CullStack.prototype.reset.call( this );
|
|
// Reset the stack before reseting the current leaf index.
|
|
// Reseting elements and refilling them later is faster than create new elements
|
|
// That's the reason to have a leafStack, see http://jsperf.com/refill/2
|
|
this.resetRenderLeafStack();
|
|
this._reserveLeafStackCurrent = 0;
|
|
|
|
this.resetCullSettingsStack();
|
|
this._reserveCullSettingsStackCurrent = 0;
|
|
|
|
// renderstage / renderbin pools
|
|
var resetStages = window.Object.keys( this._reserveRenderStageStacks );
|
|
for ( var i = 0, l = resetStages.length; i < l; i++ ) {
|
|
var key = resetStages[ i ];
|
|
this._reserveRenderStageStacks[ key ].reset();
|
|
}
|
|
RenderBin.resetStack();
|
|
|
|
this._computedNear = Number.POSITIVE_INFINITY;
|
|
this._computedFar = Number.NEGATIVE_INFINITY;
|
|
},
|
|
|
|
getCurrentRenderBin: function () {
|
|
return this._currentRenderBin;
|
|
},
|
|
|
|
setCurrentRenderBin: function ( rb ) {
|
|
this._currentRenderBin = rb;
|
|
},
|
|
|
|
// mimic the osg implementation
|
|
// in osg you can push 0, in this case an identity matrix will be loaded
|
|
addPositionedAttribute: function ( matrix, attribute ) {
|
|
|
|
var m = matrix ? matrix : this._identityMatrix;
|
|
this._currentRenderBin.getStage().positionedAttribute.push( [ m, attribute ] );
|
|
|
|
},
|
|
|
|
pushStateSet: function ( stateset ) {
|
|
this._currentStateGraph = this._currentStateGraph.findOrInsert( stateset );
|
|
if ( stateset.getBinName() !== undefined ) {
|
|
var renderBinStack = this._renderBinStack;
|
|
var currentRenderBin = this._currentRenderBin;
|
|
renderBinStack.push( currentRenderBin );
|
|
this._currentRenderBin = currentRenderBin.getStage().findOrInsert( stateset.getBinNumber(), stateset.getBinName() );
|
|
}
|
|
},
|
|
|
|
/** Pop the top state set and hence associated state group.
|
|
* Move the current state group to the parent of the popped
|
|
* state group.
|
|
*/
|
|
popStateSet: function () {
|
|
var currentStateGraph = this._currentStateGraph;
|
|
var stateset = currentStateGraph.getStateSet();
|
|
this._currentStateGraph = currentStateGraph.parent;
|
|
if ( stateset.getBinName() !== undefined ) {
|
|
var renderBinStack = this._renderBinStack;
|
|
if ( renderBinStack.length === 0 ) {
|
|
this._currentRenderBin = this._currentRenderBin.getStage();
|
|
} else {
|
|
this._currentRenderBin = renderBinStack.pop();
|
|
}
|
|
}
|
|
},
|
|
|
|
popProjectionMatrix: function () {
|
|
if ( this._computeNearFar === true && this._computedFar >= this._computedNear ) {
|
|
var m = this.getCurrentProjectionMatrix();
|
|
if ( this._clampProjectionMatrixCallback !== undefined ) {
|
|
this._clampProjectionMatrixCallback( m, this._computedNear, this._computedFar, this._nearFarRatio );
|
|
} else {
|
|
this.clampProjectionMatrix( m, this._computedNear, this._computedFar, this._nearFarRatio );
|
|
}
|
|
}
|
|
CullStack.prototype.popProjectionMatrix.call( this );
|
|
},
|
|
|
|
|
|
clampProjectionMatrix: function ( projection, znear, zfar, nearFarRatio, resultNearFar ) {
|
|
var epsilon = 1e-6;
|
|
if ( zfar < znear - epsilon ) {
|
|
Notify.log( 'clampProjectionMatrix not applied, invalid depth range, znear = ' + znear + ' zfar = ' + zfar, false, true );
|
|
return false;
|
|
}
|
|
|
|
var desiredZnear, desiredZfar;
|
|
if ( zfar < znear + epsilon ) {
|
|
// znear and zfar are too close together and could cause divide by zero problems
|
|
// late on in the clamping code, so move the znear and zfar apart.
|
|
var average = ( znear + zfar ) * 0.5;
|
|
znear = average - epsilon;
|
|
zfar = average + epsilon;
|
|
// OSG_INFO << '_clampProjectionMatrix widening znear and zfar to '<<znear<<' '<<zfar<<std::endl;
|
|
}
|
|
|
|
if ( Math.abs( projection[ 3 ] ) < epsilon &&
|
|
Math.abs( projection[ 7 ] ) < epsilon &&
|
|
Math.abs( projection[ 11 ] ) < epsilon ) {
|
|
// OSG_INFO << 'Orthographic matrix before clamping'<<projection<<std::endl;
|
|
|
|
var deltaSpan = ( zfar - znear ) * 0.02;
|
|
if ( deltaSpan < 1.0 ) {
|
|
deltaSpan = 1.0;
|
|
}
|
|
desiredZnear = znear - deltaSpan;
|
|
desiredZfar = zfar + deltaSpan;
|
|
|
|
// assign the clamped values back to the computed values.
|
|
znear = desiredZnear;
|
|
zfar = desiredZfar;
|
|
|
|
projection[ 10 ] = -2.0 / ( desiredZfar - desiredZnear );
|
|
projection[ 14 ] = -( desiredZfar + desiredZnear ) / ( desiredZfar - desiredZnear );
|
|
// OSG_INFO << 'Orthographic matrix after clamping '<<projection<<std::endl;
|
|
} else {
|
|
|
|
// OSG_INFO << 'Persepective matrix before clamping'<<projection<<std::endl;
|
|
//std::cout << '_computed_znear'<<_computed_znear<<std::endl;
|
|
//std::cout << '_computed_zfar'<<_computed_zfar<<std::endl;
|
|
|
|
var zfarPushRatio = 1.02;
|
|
var znearPullRatio = 0.98;
|
|
|
|
//znearPullRatio = 0.99;
|
|
|
|
desiredZnear = znear * znearPullRatio;
|
|
desiredZfar = zfar * zfarPushRatio;
|
|
|
|
// near plane clamping.
|
|
var minNearPlane = zfar * nearFarRatio;
|
|
if ( desiredZnear < minNearPlane ) {
|
|
desiredZnear = minNearPlane;
|
|
}
|
|
|
|
// assign the clamped values back to the computed values.
|
|
znear = desiredZnear;
|
|
zfar = desiredZfar;
|
|
|
|
var m22 = projection[ 10 ];
|
|
var m32 = projection[ 14 ];
|
|
var m23 = projection[ 11 ];
|
|
var m33 = projection[ 15 ];
|
|
var transNearPlane = ( -desiredZnear * m22 + m32 ) / ( -desiredZnear * m23 + m33 );
|
|
var transFarPlane = ( -desiredZfar * m22 + m32 ) / ( -desiredZfar * m23 + m33 );
|
|
|
|
var ratio = Math.abs( 2.0 / ( transNearPlane - transFarPlane ) );
|
|
var center = -( transNearPlane + transFarPlane ) / 2.0;
|
|
|
|
var centerRatio = center * ratio;
|
|
projection[ 2 ] = projection[ 2 ] * ratio + projection[ 3 ] * centerRatio;
|
|
projection[ 6 ] = projection[ 6 ] * ratio + projection[ 7 ] * centerRatio;
|
|
projection[ 10 ] = m22 * ratio + m23 * centerRatio;
|
|
projection[ 14 ] = m32 * ratio + m33 * centerRatio;
|
|
// same as
|
|
// var matrix = [ 1.0, 0.0, 0.0, 0.0,
|
|
// 0.0, 1.0, 0.0, 0.0,
|
|
// 0.0, 0.0, ratio, 0.0,
|
|
// 0.0, 0.0, center * ratio, 1.0
|
|
// ];
|
|
// mat4.mul( projection , matrix, projection );
|
|
|
|
// OSG_INFO << 'Persepective matrix after clamping'<<projection<<std::endl;
|
|
}
|
|
if ( resultNearFar !== undefined ) {
|
|
resultNearFar[ 0 ] = znear;
|
|
resultNearFar[ 1 ] = zfar;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
popCameraModelViewProjectionMatrix: function () {
|
|
this.popModelViewMatrix();
|
|
this.popProjectionMatrix();
|
|
},
|
|
|
|
pushCameraModelViewProjectionMatrix: function ( camera, modelview, projection ) {
|
|
this.pushModelViewMatrix( modelview );
|
|
this.pushProjectionMatrix( projection );
|
|
},
|
|
|
|
apply: function ( node ) {
|
|
this[ node.typeID ]( node );
|
|
},
|
|
|
|
createOrReuseRenderStage: function ( classInstance ) {
|
|
|
|
var type = !classInstance ? 'RenderStage' : classInstance.className();
|
|
var classCtor = !classInstance ? RenderStage : classInstance.constructor;
|
|
|
|
var stack;
|
|
if ( this._reserveRenderStageStacks[ type ] ) {
|
|
stack = this._reserveRenderStageStacks[ type ];
|
|
} else {
|
|
stack = new osgPool.OsgObjectMemoryStack( classCtor );
|
|
this._reserveRenderStageStacks[ type ] = stack;
|
|
}
|
|
return stack.get().init();
|
|
|
|
},
|
|
|
|
createOrReuseRenderLeaf: function () {
|
|
var l = this._reserveLeafStack[ this._reserveLeafStackCurrent++ ];
|
|
if ( this._reserveLeafStackCurrent === this._reserveLeafStack.length ) {
|
|
this._reserveLeafStack.push( new RenderLeaf() );
|
|
}
|
|
return l;
|
|
},
|
|
|
|
resetRenderLeafStack: function () {
|
|
for ( var i = 0, j = this._reserveLeafStackCurrent; i <= j; i++ ) {
|
|
this._reserveLeafStack[ i ].reset();
|
|
}
|
|
},
|
|
|
|
createOrReuseCullSettings: function () {
|
|
var l = this._reserveCullSettingsStack[ this._reserveCullSettingsStackCurrent++ ];
|
|
|
|
if ( this._reserveCullSettingsStackCurrent === this._reserveCullSettingsStack.length ) {
|
|
|
|
this._reserveCullSettingsStack.push( new CullSettings() );
|
|
|
|
}
|
|
return l;
|
|
},
|
|
|
|
resetCullSettingsStack: function () {
|
|
for ( var i = 0, j = this._reserveCullSettingsStackCurrent; i <= j; i++ ) {
|
|
this._reserveCullSettingsStack[ i ].reset();
|
|
}
|
|
},
|
|
|
|
// function call after the push state in the geometry apply function
|
|
// the idea is to avoid heavy copy-paste for the rigGeometry apply
|
|
// since the only difference is that we want to push an additional state
|
|
// Maybe it will be useful when we'll add morph target geometry or something...
|
|
postPushGeometry: function ( cull, node ) {
|
|
|
|
var sourceGeometry;
|
|
var geometryStateSetAnimation;
|
|
|
|
if ( node instanceof RigGeometry ) {
|
|
|
|
geometryStateSetAnimation = node.getStateSetAnimation();
|
|
if ( geometryStateSetAnimation ) cull.pushStateSet( geometryStateSetAnimation );
|
|
|
|
sourceGeometry = node.getSourceGeometry();
|
|
|
|
if ( sourceGeometry instanceof MorphGeometry ) {
|
|
|
|
geometryStateSetAnimation = sourceGeometry.getStateSetAnimation();
|
|
if ( geometryStateSetAnimation ) cull.pushStateSet( geometryStateSetAnimation );
|
|
|
|
}
|
|
|
|
} else if ( node instanceof MorphGeometry ) {
|
|
|
|
geometryStateSetAnimation = node.getStateSetAnimation();
|
|
if ( geometryStateSetAnimation ) cull.pushStateSet( geometryStateSetAnimation );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// same comment as above (postPushGeometry)
|
|
prePopGeometry: function ( cull, node ) {
|
|
|
|
if ( node instanceof RigGeometry ) {
|
|
|
|
var sourceGeometry = node.getSourceGeometry();
|
|
|
|
if ( sourceGeometry instanceof MorphGeometry ) {
|
|
|
|
if ( sourceGeometry.getStateSetAnimation() ) cull.popStateSet();
|
|
|
|
}
|
|
|
|
if ( node.getStateSetAnimation() ) cull.popStateSet();
|
|
|
|
} else if ( node instanceof MorphGeometry && node.getStateSetAnimation() ) {
|
|
|
|
cull.popStateSet();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
pushLeaf: function ( node, depth ) {
|
|
var leafs = this._currentStateGraph.leafs;
|
|
if ( leafs.length === 0 ) {
|
|
this._currentRenderBin.addStateGraph( this._currentStateGraph );
|
|
}
|
|
|
|
var leaf = this.createOrReuseRenderLeaf();
|
|
|
|
leaf.init( this._currentStateGraph,
|
|
node,
|
|
this.getCurrentProjectionMatrix(),
|
|
this.getCurrentViewMatrix(),
|
|
this.getCurrentModelViewMatrix(),
|
|
this.getCurrentModelMatrix(),
|
|
depth );
|
|
|
|
leafs.push( leaf );
|
|
|
|
}
|
|
|
|
} ) );
|
|
|
|
|
|
// Camera cull visitor call
|
|
// ANY CHANGE, any change : double check in rendere Camera code
|
|
// for the first camera
|
|
CullVisitor.prototype[ Camera.typeID ] = function ( camera ) {
|
|
this._numCamera++;
|
|
|
|
var stateset = camera.getStateSet();
|
|
if ( stateset ) this.pushStateSet( stateset );
|
|
|
|
var modelview = this._reservedMatrixStack.get();
|
|
var projection = this._reservedMatrixStack.get();
|
|
|
|
if ( camera.getReferenceFrame() === TransformEnums.RELATIVE_RF ) {
|
|
|
|
var lastProjectionMatrix = this.getCurrentProjectionMatrix();
|
|
mat4.mul( projection, lastProjectionMatrix, camera.getProjectionMatrix() );
|
|
|
|
var lastViewMatrix = this.getCurrentModelViewMatrix();
|
|
mat4.mul( modelview, lastViewMatrix, camera.getViewMatrix() );
|
|
|
|
} else {
|
|
|
|
// absolute
|
|
mat4.copy( modelview, camera.getViewMatrix() );
|
|
mat4.copy( projection, camera.getProjectionMatrix() );
|
|
|
|
}
|
|
|
|
|
|
// save current state of the camera
|
|
var previousZnear = this._computedNear;
|
|
var previousZfar = this._computedFar;
|
|
|
|
// save cullSettings
|
|
// TODO Perf: why it's not a stack
|
|
// and is pollutin GC ?
|
|
var previousCullsettings = this.createOrReuseCullSettings();
|
|
previousCullsettings.setCullSettings( this );
|
|
|
|
this._computedNear = Number.POSITIVE_INFINITY;
|
|
this._computedFar = Number.NEGATIVE_INFINITY;
|
|
//
|
|
|
|
this.setCullSettings( camera );
|
|
// global override
|
|
// upon who setted the parameter
|
|
// if it's cullvisitor
|
|
// it's an OVERRIDER for enableFrustumCulling
|
|
// allowing for global EnableFrustimCulling
|
|
if ( previousCullsettings.getSettingSourceOverrider() === this && previousCullsettings.getEnableFrustumCulling() ) {
|
|
this.setEnableFrustumCulling( true );
|
|
}
|
|
|
|
|
|
this.pushCameraModelViewProjectionMatrix( camera, modelview, projection );
|
|
|
|
if ( camera.getViewport() ) {
|
|
this.pushViewport( camera.getViewport() );
|
|
}
|
|
|
|
|
|
// nested camera
|
|
if ( camera.getRenderOrder() === Camera.NESTED_RENDER ) {
|
|
|
|
this.handleCullCallbacksAndTraverse( camera );
|
|
|
|
} else {
|
|
// not tested
|
|
|
|
var renderBin = this.getCurrentRenderBin();
|
|
var previousStage = renderBin.getStage();
|
|
|
|
// use render to texture stage
|
|
var rtts = this.createOrReuseRenderStage( this._rootRenderStage );
|
|
|
|
rtts.setCamera( camera );
|
|
rtts.setClearDepth( camera.getClearDepth() );
|
|
rtts.setClearColor( camera.getClearColor() );
|
|
rtts.setClearMask( camera.getClearMask() );
|
|
|
|
var vp;
|
|
if ( camera.getViewport() === undefined ) {
|
|
vp = previousStage.getViewport();
|
|
} else {
|
|
vp = camera.getViewport();
|
|
}
|
|
rtts.setViewport( vp );
|
|
|
|
// skip positional state for now
|
|
// ...
|
|
|
|
this.setCurrentRenderBin( rtts );
|
|
|
|
this.handleCullCallbacksAndTraverse( camera );
|
|
|
|
this.setCurrentRenderBin( renderBin );
|
|
|
|
if ( camera.getRenderOrder() === Camera.PRE_RENDER ) {
|
|
this.getCurrentRenderBin().getStage().addPreRenderStage( rtts, camera.renderOrderNum );
|
|
} else {
|
|
this.getCurrentRenderBin().getStage().addPostRenderStage( rtts, camera.renderOrderNum );
|
|
}
|
|
}
|
|
|
|
this.popCameraModelViewProjectionMatrix( camera );
|
|
|
|
if ( camera.getViewport() ) {
|
|
this.popViewport();
|
|
}
|
|
|
|
// restore previous state of the camera
|
|
this.setCullSettings( previousCullsettings );
|
|
this._computedNear = previousZnear;
|
|
this._computedFar = previousZfar;
|
|
|
|
if ( stateset ) this.popStateSet();
|
|
|
|
};
|
|
|
|
|
|
CullVisitor.prototype[ MatrixTransform.typeID ] = function ( node ) {
|
|
this._numMatrixTransform++;
|
|
|
|
// Camera and lights must enlarge node parent bounding boxes for this not to cull
|
|
if ( this.isCulled( node, this.nodePath ) ) {
|
|
return;
|
|
}
|
|
// push the culling mode.
|
|
this.pushCurrentMask();
|
|
|
|
var matrix = this._reservedMatrixStack.get();
|
|
var lastMatrixStack = this.getCurrentModelViewMatrix();
|
|
mat4.copy( matrix, lastMatrixStack );
|
|
node.computeLocalToWorldMatrix( matrix );
|
|
this.pushModelViewMatrix( matrix );
|
|
|
|
|
|
var stateset = node.getStateSet();
|
|
|
|
if ( stateset ) this.pushStateSet( stateset );
|
|
|
|
this.handleCullCallbacksAndTraverse( node );
|
|
|
|
if ( stateset ) this.popStateSet();
|
|
|
|
|
|
this.popModelViewMatrix();
|
|
|
|
// pop the culling mode.
|
|
this.popCurrentMask();
|
|
};
|
|
|
|
CullVisitor.prototype[ Projection.typeID ] = function ( node ) {
|
|
this._numProjection++;
|
|
|
|
var lastMatrixStack = this.getCurrentProjectionMatrix();
|
|
var matrix = this._reservedMatrixStack.get();
|
|
mat4.mul( matrix, lastMatrixStack, node.getProjectionMatrix() );
|
|
this.pushProjectionMatrix( matrix );
|
|
|
|
var stateset = node.getStateSet();
|
|
if ( stateset ) this.pushStateSet( stateset );
|
|
|
|
this.handleCullCallbacksAndTraverse( node );
|
|
|
|
if ( stateset ) this.popStateSet();
|
|
|
|
this.popProjectionMatrix();
|
|
};
|
|
|
|
// here it's treated as a group node for culling
|
|
// as there's isn't any in osgjs
|
|
// so frustumCulling is done here
|
|
CullVisitor.prototype[ Node.typeID ] = function ( node ) {
|
|
this._numNode++;
|
|
|
|
// Camera and lights must enlarge node parent bounding boxes for this not to cull
|
|
if ( this.isCulled( node, this.nodePath ) ) {
|
|
return;
|
|
}
|
|
|
|
// push the culling mode.
|
|
this.pushCurrentMask();
|
|
|
|
var stateset = node.getStateSet();
|
|
if ( stateset ) this.pushStateSet( stateset );
|
|
|
|
this.handleCullCallbacksAndTraverse( node );
|
|
|
|
if ( stateset ) this.popStateSet();
|
|
|
|
// pop the culling mode.
|
|
this.popCurrentMask();
|
|
};
|
|
|
|
// same code like MatrixTransform
|
|
CullVisitor.prototype[ AutoTransform.typeID ] = CullVisitor.prototype[ MatrixTransform.typeID ];
|
|
|
|
// same code like Node
|
|
CullVisitor.prototype[ Lod.typeID ] = CullVisitor.prototype[ Node.typeID ];
|
|
|
|
// same code like Node
|
|
CullVisitor.prototype[ PagedLOD.typeID ] = CullVisitor.prototype[ Node.typeID ];
|
|
|
|
|
|
CullVisitor.prototype[ LightSource.typeID ] = function ( node ) {
|
|
this._numLightSource++;
|
|
|
|
var stateset = node.getStateSet();
|
|
if ( stateset ) this.pushStateSet( stateset );
|
|
|
|
var light = node.getLight();
|
|
if ( light ) {
|
|
if ( node.getReferenceFrame() === TransformEnums.RELATIVE_RF )
|
|
this.addPositionedAttribute( this.getCurrentModelViewMatrix(), light );
|
|
else
|
|
this.addPositionedAttribute( null, light );
|
|
}
|
|
|
|
|
|
this.handleCullCallbacksAndTraverse( node );
|
|
|
|
if ( stateset ) this.popStateSet();
|
|
};
|
|
|
|
CullVisitor.prototype[ Geometry.typeID ] = ( function () {
|
|
|
|
var tempVec = vec3.create();
|
|
var loggedOnce = false;
|
|
return function geometryApply( node ) {
|
|
|
|
this._numGeometry++;
|
|
|
|
var modelview = this.getCurrentModelViewMatrix();
|
|
var bb = node.getBoundingBox();
|
|
if ( this._computeNearFar && bb.valid() ) {
|
|
if ( !this.updateCalculatedNearFar( modelview, node ) ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// using modelview is not a pb because geometry
|
|
// is a leaf node, else traversing the graph would be an
|
|
// issue because we use modelview after
|
|
var ccb = node.getCullCallback();
|
|
if ( ccb && !ccb.cull( node, this ) )
|
|
return;
|
|
|
|
var stateset = node.getStateSet();
|
|
if ( stateset ) this.pushStateSet( stateset );
|
|
|
|
this.postPushGeometry( this, node );
|
|
|
|
var depth = 0;
|
|
if ( bb.valid() ) {
|
|
depth = this.distance( bb.center( tempVec ), modelview );
|
|
}
|
|
if ( osgMath.isNaN( depth ) ) {
|
|
|
|
if ( !loggedOnce ) {
|
|
Notify.warn( 'warning geometry has a NaN depth, ' + modelview + ' center ' + tempVec );
|
|
loggedOnce = true;
|
|
}
|
|
|
|
} else {
|
|
|
|
this.pushLeaf( node, depth );
|
|
|
|
}
|
|
|
|
this.prePopGeometry( this, node );
|
|
if ( stateset ) this.popStateSet();
|
|
};
|
|
} )();
|
|
|
|
CullVisitor.prototype[ Skeleton.typeID ] = CullVisitor.prototype[ MatrixTransform.typeID ];
|
|
|
|
CullVisitor.prototype[ RigGeometry.typeID ] = CullVisitor.prototype[ Geometry.typeID ];
|
|
|
|
CullVisitor.prototype[ MorphGeometry.typeID ] = CullVisitor.prototype[ Geometry.typeID ];
|
|
|
|
CullVisitor.prototype[ Bone.typeID ] = CullVisitor.prototype[ MatrixTransform.typeID ];
|
|
|
|
module.exports = CullVisitor;
|