📄 abstractcamera.java
字号:
* @param bound the bound to check for culling
* @return true if the bound should be culled, false otherwise.
*/
public Camera.FrustumIntersect contains( BoundingVolume bound ) {
if ( bound == null ) {
return FrustumIntersect.Inside;
}
int mask;
FrustumIntersect rVal = FrustumIntersect.Inside;
for ( int planeCounter = FRUSTUM_PLANES; planeCounter >= 0; planeCounter-- ) {
if ( planeCounter == bound.getCheckPlane() ) {
continue; // we have already checked this plane at first iteration
}
int planeId = ( planeCounter == FRUSTUM_PLANES ) ? bound.getCheckPlane() : planeCounter;
mask = 1 << ( planeId );
if ( ( planeState & mask ) == 0 ) {
Side side = bound.whichSide( worldPlane[planeId] );
if (side == Side.NEGATIVE) {
//object is outside of frustum
bound.setCheckPlane( planeId );
return FrustumIntersect.Outside;
} else if (side == Side.POSITIVE) {
//object is visible on *this* plane, so mark this plane
//so that we don't check it for sub nodes.
planeState |= mask;
} else {
rVal = FrustumIntersect.Intersects;
}
}
}
return rVal;
}
/**
* <code>onFrustumChange</code> updates the frustum to reflect any changes
* made to the planes. The new frustum values are kept in a temporary
* location for use when calculating the new frame. It should be noted that
* the abstract implementation of this class only updates the data, and does
* not make any rendering calls. As such, any impelmenting subclass should
* insure to override this method call it with super and then call the
* rendering specific code.
*/
public void onFrustumChange() {
if ( !isParallelProjection() ) {
float nearSquared = frustumNear * frustumNear;
float leftSquared = frustumLeft * frustumLeft;
float rightSquared = frustumRight * frustumRight;
float bottomSquared = frustumBottom * frustumBottom;
float topSquared = frustumTop * frustumTop;
float inverseLength = FastMath.invSqrt( nearSquared + leftSquared );
coeffLeft[0] = frustumNear * inverseLength;
coeffLeft[1] = -frustumLeft * inverseLength;
inverseLength = FastMath.invSqrt( nearSquared + rightSquared );
coeffRight[0] = -frustumNear * inverseLength;
coeffRight[1] = frustumRight * inverseLength;
inverseLength = FastMath.invSqrt( nearSquared + bottomSquared );
coeffBottom[0] = frustumNear * inverseLength;
coeffBottom[1] = -frustumBottom * inverseLength;
inverseLength = FastMath.invSqrt( nearSquared + topSquared );
coeffTop[0] = -frustumNear * inverseLength;
coeffTop[1] = frustumTop * inverseLength;
}
else {
coeffLeft[0] = 1;
coeffLeft[1] = 0;
coeffRight[0] = -1;
coeffRight[1] = 0;
coeffBottom[0] = 1;
coeffBottom[1] = 0;
coeffTop[0] = -1;
coeffTop[1] = 0;
}
updateMatrices = true;
}
/**
* <code>onFrameChange</code> updates the view frame of the camera. It
* should be noted that the abstract implementation of this class only
* updates the data, and does not make any rendering calls. As such, any
* implementing subclass should insure to override this method call it with
* super and then call the rendering specific code.
*/
public void onFrameChange() {
float dirDotLocation = direction.dot( location );
// left plane
Vector3f leftPlaneNormal = worldPlane[LEFT_PLANE].normal;
leftPlaneNormal.x = left.x * coeffLeft[0];
leftPlaneNormal.y = left.y * coeffLeft[0];
leftPlaneNormal.z = left.z * coeffLeft[0];
leftPlaneNormal.addLocal( direction.x * coeffLeft[1], direction.y
* coeffLeft[1], direction.z * coeffLeft[1] );
worldPlane[LEFT_PLANE].setConstant( location.dot( leftPlaneNormal ) );
// right plane
Vector3f rightPlaneNormal = worldPlane[RIGHT_PLANE].normal;
rightPlaneNormal.x = left.x * coeffRight[0];
rightPlaneNormal.y = left.y * coeffRight[0];
rightPlaneNormal.z = left.z * coeffRight[0];
rightPlaneNormal.addLocal( direction.x * coeffRight[1], direction.y
* coeffRight[1], direction.z * coeffRight[1] );
worldPlane[RIGHT_PLANE].setConstant( location.dot( rightPlaneNormal ) );
// bottom plane
Vector3f bottomPlaneNormal = worldPlane[BOTTOM_PLANE].normal;
bottomPlaneNormal.x = up.x * coeffBottom[0];
bottomPlaneNormal.y = up.y * coeffBottom[0];
bottomPlaneNormal.z = up.z * coeffBottom[0];
bottomPlaneNormal.addLocal( direction.x * coeffBottom[1], direction.y
* coeffBottom[1], direction.z * coeffBottom[1] );
worldPlane[BOTTOM_PLANE].setConstant( location.dot( bottomPlaneNormal ) );
// top plane
Vector3f topPlaneNormal = worldPlane[TOP_PLANE].normal;
topPlaneNormal.x = up.x * coeffTop[0];
topPlaneNormal.y = up.y * coeffTop[0];
topPlaneNormal.z = up.z * coeffTop[0];
topPlaneNormal.addLocal( direction.x * coeffTop[1], direction.y
* coeffTop[1], direction.z * coeffTop[1] );
worldPlane[TOP_PLANE].setConstant( location.dot( topPlaneNormal ) );
if ( isParallelProjection() ) {
worldPlane[LEFT_PLANE].setConstant( worldPlane[LEFT_PLANE].getConstant() + frustumLeft );
worldPlane[RIGHT_PLANE].setConstant( worldPlane[RIGHT_PLANE].getConstant() - frustumRight );
worldPlane[TOP_PLANE].setConstant( worldPlane[TOP_PLANE].getConstant() + frustumTop );
worldPlane[BOTTOM_PLANE].setConstant( worldPlane[BOTTOM_PLANE].getConstant() - frustumBottom );
}
// far plane
worldPlane[FAR_PLANE].normal.set( -direction.x, -direction.y,
-direction.z );
worldPlane[FAR_PLANE].setConstant( -( dirDotLocation + frustumFar ) );
// near plane
worldPlane[NEAR_PLANE].normal
.set( direction.x, direction.y, direction.z );
worldPlane[NEAR_PLANE].setConstant( dirDotLocation + frustumNear );
updateMatrices = true;
updateSMatrices = true;
}
/**
* @return true if parallel projection is enable, false if in normal perspective mode
* @see #setParallelProjection(boolean)
*/
public boolean isParallelProjection() {
return this.parallelProjection;
}
/**
* store the value for field parallelProjection
*/
private boolean parallelProjection;
/**
* Enable/disable parallel projection.
*
* @param value true to set up this camera for parallel projection is enable, false to enter normal perspective mode
*/
public void setParallelProjection( final boolean value ) {
this.parallelProjection = value;
}
/* @see Camera#getWorldCoordinates */
public Vector3f getWorldCoordinates( Vector2f screenPos, float zPos ) {
return getWorldCoordinates( screenPos, zPos, null );
}
protected final Matrix4f _transMatrix = new Matrix4f();
protected final Matrix4f _modelView = new Matrix4f();
protected final Matrix4f _projection = new Matrix4f();
public Matrix4f getProjectionMatrix() {
if (isParallelProjection()) {
_projection.loadIdentity();
_projection.m00 = 2.0f / (frustumRight - frustumLeft);
_projection.m11 = 2.0f / (frustumBottom - frustumTop);
_projection.m22 = -2.0f / (frustumFar - frustumNear);
_projection.m33 = 1f;
_projection.m30 = -(frustumRight + frustumLeft) / (frustumRight - frustumLeft);
_projection.m31 = -(frustumBottom + frustumTop) / (frustumBottom - frustumTop);
_projection.m32 = -(frustumFar + frustumNear) / (frustumFar - frustumNear);
} else {
// XXX: Cache results or is this low cost enough to happen every time it is called?
_projection.loadIdentity();
_projection.m00 = (2.0f * frustumNear) / (frustumRight - frustumLeft);
_projection.m11 = (2.0f * frustumNear) / (frustumTop - frustumBottom);
_projection.m20 = (frustumRight + frustumLeft) / (frustumRight - frustumLeft);
_projection.m21 = (frustumTop + frustumBottom) / (frustumTop - frustumBottom);
_projection.m22 = -(frustumFar + frustumNear) / (frustumFar - frustumNear);
_projection.m32 = -(2.0f * frustumFar * frustumNear) / (frustumFar - frustumNear);
_projection.m23 = -1.0f;
_projection.m33 = -0.0f;
}
return _projection;
}
public Matrix4f getModelViewMatrix() {
// XXX: Cache results or is this low cost enough to happen every time it is called?
_modelView.loadIdentity();
_modelView.m00 = -left.x;
_modelView.m10 = -left.y;
_modelView.m20 = -left.z;
_modelView.m01 = up.x;
_modelView.m11 = up.y;
_modelView.m21 = up.z;
_modelView.m02 = -direction.x;
_modelView.m12 = -direction.y;
_modelView.m22 = -direction.z;
_transMatrix.loadIdentity();
_transMatrix.m30 = -location.x;
_transMatrix.m31 = -location.y;
_transMatrix.m32 = -location.z;
_transMatrix.multLocal(_modelView);
_modelView.set(_transMatrix);
return _modelView;
}
private static final Quaternion tmp_quat = new Quaternion();
private boolean updateMatrices = true;
private boolean updateSMatrices = true;
private final Matrix4f modelViewProjectionInverse = new Matrix4f();
private final Matrix4f modelViewProjection = new Matrix4f();
private boolean dataOnly;
/* @see Camera#getWorldCoordinates */
public Vector3f getWorldCoordinates( Vector2f screenPosition,
float zPos, Vector3f store ) {
if ( store == null ) {
store = new Vector3f();
}
checkViewProjection();
if ( updateMatrices ) {
modelViewProjection.invert( modelViewProjectionInverse );
updateMatrices = false;
}
tmp_quat.set(
( screenPosition.x / getWidth() - viewPortLeft ) / ( viewPortRight - viewPortLeft ) * 2 - 1,
( screenPosition.y / getHeight() - viewPortBottom ) / ( viewPortTop - viewPortBottom ) * 2 - 1,
zPos * 2 - 1, 1 );
modelViewProjectionInverse.mult( tmp_quat, tmp_quat );
tmp_quat.multLocal( 1.0f / tmp_quat.w );
store.x = tmp_quat.x;
store.y = tmp_quat.y;
store.z = tmp_quat.z;
return store;
}
/* @see Camera#getScreenCoordinates */
public Vector3f getScreenCoordinates( Vector3f worldPos ) {
return getScreenCoordinates( worldPos, null );
}
/**
* Implementation contributed by Zbyl.
*
* @see Camera#getScreenCoordinates(Vector3f, Vector3f)
*/
public Vector3f getScreenCoordinates( Vector3f worldPosition, Vector3f store ) {
if ( store == null ) {
store = new Vector3f();
}
checkViewProjection();
tmp_quat.set( worldPosition.x, worldPosition.y, worldPosition.z, 1 );
modelViewProjection.mult( tmp_quat, tmp_quat );
tmp_quat.multLocal( 1.0f / tmp_quat.w );
store.x = ( ( tmp_quat.x + 1 ) * ( viewPortRight - viewPortLeft ) / 2 ) * getWidth();
store.y = ( ( tmp_quat.y + 1 ) * ( viewPortTop - viewPortBottom ) / 2 ) * getHeight();
store.z = ( tmp_quat.z + 1 ) / 2;
return store;
}
/**
* update modelViewProjection if necessary.
*/
private void checkViewProjection() {
if ( updateSMatrices ) {
modelViewProjection.set( getModelViewMatrix() ).multLocal( getProjectionMatrix() );
updateSMatrices = false;
}
}
/**
* @return the width/resolution of the display.
*/
public abstract int getHeight();
/**
* @return the height/resolution of the display.
*/
public abstract int getWidth();
public void write(JMEExporter e) throws IOException {
OutputCapsule capsule = e.getCapsule(this);
capsule.write(location, "location", Vector3f.ZERO);
capsule.write(left, "left", Vector3f.UNIT_X);
capsule.write(up, "up", Vector3f.UNIT_Y);
capsule.write(direction, "direction", Vector3f.UNIT_Z);
capsule.write(frustumNear, "frustumNear", 1);
capsule.write(frustumFar, "frustumFar", 2);
capsule.write(frustumLeft, "frustumLeft", -0.5f);
capsule.write(frustumRight, "frustumRight", 0.5f);
capsule.write(frustumTop, "frustumTop", 0.5f);
capsule.write(frustumBottom, "frustumBottom", -0.5f);
capsule.write(coeffLeft, "coeffLeft", new float[2]);
capsule.write(coeffRight, "coeffRight", new float[2]);
capsule.write(coeffBottom, "coeffBottom", new float[2]);
capsule.write(coeffTop, "coeffTop", new float[2]);
capsule.write(planeQuantity, "planeQuantity", 6);
capsule.write(viewPortLeft, "viewPortLeft", 0);
capsule.write(viewPortRight, "viewPortRight", 1);
capsule.write(viewPortTop, "viewPortTop", 1);
capsule.write(viewPortBottom, "viewPortBottom", 0);
capsule.write(width, "width", 0);
capsule.write(height, "height", 0);
}
public void read(JMEImporter e) throws IOException {
InputCapsule capsule = e.getCapsule(this);
location = (Vector3f)capsule.readSavable("location", Vector3f.ZERO.clone());
left = (Vector3f)capsule.readSavable("left", Vector3f.UNIT_X.clone());
up = (Vector3f)capsule.readSavable("up", Vector3f.UNIT_Y.clone());
direction = (Vector3f)capsule.readSavable("direction", Vector3f.UNIT_Z.clone());
frustumNear = capsule.readFloat("frustumNear", 1);
frustumFar = capsule.readFloat("frustumFar", 2);
frustumLeft = capsule.readFloat("frustumLeft", -0.5f);
frustumRight = capsule.readFloat("frustumRight", 0.5f);
frustumTop = capsule.readFloat("frustumTop", 0.5f);
frustumBottom = capsule.readFloat("frustumBottom", -0.5f);
coeffLeft = capsule.readFloatArray("coeffLeft", new float[2]);
coeffRight = capsule.readFloatArray("coeffRight", new float[2]);
coeffBottom = capsule.readFloatArray("coeffBottom", new float[2]);
coeffTop = capsule.readFloatArray("coeffTop", new float[2]);
planeQuantity = capsule.readInt("planeQuantity", 6);
viewPortLeft = capsule.readFloat("viewPortLeft", 0);
viewPortRight = capsule.readFloat("viewPortRight", 1);
viewPortTop = capsule.readFloat("viewPortTop", 1);
viewPortBottom = capsule.readFloat("viewPortBottom", 0);
width = capsule.readInt("width", 0);
height = capsule.readInt("height", 0);
}
public Class<AbstractCamera> getClassTag() {
return AbstractCamera.class;
}
public void setDataOnly(boolean dataOnly) {
this.dataOnly = dataOnly;
}
public boolean isDataOnly() {
return dataOnly;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -