Package com.ardor3d.util

Source Code of com.ardor3d.util.ExtendedCamera

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.util;

import com.ardor3d.bounding.BoundingBox;
import com.ardor3d.bounding.BoundingSphere;
import com.ardor3d.bounding.BoundingVolume;
import com.ardor3d.math.Vector3;
import com.ardor3d.math.Vector4;
import com.ardor3d.math.type.ReadOnlyMatrix4;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.renderer.Camera;

/**
* Camera with additional pssm related functionality.
*/
public class ExtendedCamera extends Camera {
    /** The corners of the camera frustum. */
    protected final Vector3[] _corners = new Vector3[8];

    /** Temporary vector used for storing extents during corner calculations. */
    protected final Vector3 _extents = new Vector3();

    /**
     * Instantiates a new PSSM camera.
     */
    public ExtendedCamera() {
        this(0, 0); // copy later
    }

    /**
     * Instantiates a new PSSM camera.
     *
     * @param width
     *            the width
     * @param height
     *            the height
     */
    public ExtendedCamera(final int width, final int height) {
        super(width, height);
        init();
    }

    /**
     * Instantiates a new PSSM camera.
     *
     * @param source
     *            the source
     */
    public ExtendedCamera(final Camera source) {
        super(source);
        init();
    }

    /**
     * Initialize structures.
     */
    private void init() {
        for (int i = 0; i < _corners.length; i++) {
            _corners[i] = new Vector3();
        }
    }

    /**
     * Compress this camera's near and far frustum planes to be smaller if possible, using the given bounds as a
     * measure.
     *
     * @param sceneBounds
     *            the scene bounds
     */
    public void pack(final BoundingVolume sceneBounds) {
        final ReadOnlyVector3 center = sceneBounds.getCenter();
        for (int i = 0; i < _corners.length; i++) {
            _corners[i].set(center);
        }

        if (sceneBounds instanceof BoundingBox) {
            final BoundingBox bbox = (BoundingBox) sceneBounds;
            bbox.getExtent(_extents);
        } else if (sceneBounds instanceof BoundingSphere) {
            final BoundingSphere bsphere = (BoundingSphere) sceneBounds;
            _extents.set(bsphere.getRadius(), bsphere.getRadius(), bsphere.getRadius());
        }

        _corners[0].addLocal(_extents.getX(), _extents.getY(), _extents.getZ());
        _corners[1].addLocal(_extents.getX(), -_extents.getY(), _extents.getZ());
        _corners[2].addLocal(_extents.getX(), _extents.getY(), -_extents.getZ());
        _corners[3].addLocal(_extents.getX(), -_extents.getY(), -_extents.getZ());
        _corners[4].addLocal(-_extents.getX(), _extents.getY(), _extents.getZ());
        _corners[5].addLocal(-_extents.getX(), -_extents.getY(), _extents.getZ());
        _corners[6].addLocal(-_extents.getX(), _extents.getY(), -_extents.getZ());
        _corners[7].addLocal(-_extents.getX(), -_extents.getY(), -_extents.getZ());

        final ReadOnlyMatrix4 mvMatrix = getModelViewMatrix();
        double optimalCameraNear = Double.MAX_VALUE;
        double optimalCameraFar = -Double.MAX_VALUE;
        final Vector4 position = Vector4.fetchTempInstance();
        for (int i = 0; i < _corners.length; i++) {
            position.set(_corners[i].getX(), _corners[i].getY(), _corners[i].getZ(), 1);
            mvMatrix.applyPre(position, position);

            optimalCameraNear = Math.min(-position.getZ(), optimalCameraNear);
            optimalCameraFar = Math.max(-position.getZ(), optimalCameraFar);
        }
        Vector4.releaseTempInstance(position);

        // XXX: use of getFrustumNear and getFrustumFar seems suspicious...
        // XXX: It depends on the frustum being reset each update
        optimalCameraNear = Math.min(Math.max(getFrustumNear(), optimalCameraNear), getFrustumFar());
        optimalCameraFar = Math.max(optimalCameraNear, Math.min(getFrustumFar(), optimalCameraFar));

        final double change = optimalCameraNear / _frustumNear;
        setFrustumLeft(getFrustumLeft() * change);
        setFrustumRight(getFrustumRight() * change);
        setFrustumTop(getFrustumTop() * change);
        setFrustumBottom(getFrustumBottom() * change);

        setFrustumNear(optimalCameraNear);
        setFrustumFar(optimalCameraFar);
    }

    public void calculateFrustum() {
        calculateFrustum(_frustumNear, _frustumFar);
    }

    /**
     * Calculate frustum corners and center.
     *
     * @param fNear
     *            the near distance
     * @param fFar
     *            the far distance
     */
    public void calculateFrustum(final double fNear, final double fFar) {
        double fNearPlaneHeight = (_frustumTop - _frustumBottom) * fNear * 0.5 / _frustumNear;
        double fNearPlaneWidth = (_frustumRight - _frustumLeft) * fNear * 0.5 / _frustumNear;

        double fFarPlaneHeight = (_frustumTop - _frustumBottom) * fFar * 0.5 / _frustumNear;
        double fFarPlaneWidth = (_frustumRight - _frustumLeft) * fFar * 0.5 / _frustumNear;

        if (getProjectionMode() == ProjectionMode.Parallel) {
            fNearPlaneHeight = (_frustumTop - _frustumBottom) * 0.5;
            fNearPlaneWidth = (_frustumRight - _frustumLeft) * 0.5;

            fFarPlaneHeight = (_frustumTop - _frustumBottom) * 0.5;
            fFarPlaneWidth = (_frustumRight - _frustumLeft) * 0.5;
        }

        final Vector3 vNearPlaneCenter = Vector3.fetchTempInstance();
        final Vector3 vFarPlaneCenter = Vector3.fetchTempInstance();
        final Vector3 direction = Vector3.fetchTempInstance();
        final Vector3 left = Vector3.fetchTempInstance();
        final Vector3 up = Vector3.fetchTempInstance();

        direction.set(getDirection()).multiplyLocal(fNear);
        vNearPlaneCenter.set(getLocation()).addLocal(direction);
        direction.set(getDirection()).multiplyLocal(fFar);
        vFarPlaneCenter.set(getLocation()).addLocal(direction);

        left.set(getLeft()).multiplyLocal(fNearPlaneWidth);
        up.set(getUp()).multiplyLocal(fNearPlaneHeight);
        _corners[0].set(vNearPlaneCenter).subtractLocal(left).subtractLocal(up);
        _corners[1].set(vNearPlaneCenter).subtractLocal(left).addLocal(up);
        _corners[2].set(vNearPlaneCenter).addLocal(left).addLocal(up);
        _corners[3].set(vNearPlaneCenter).addLocal(left).subtractLocal(up);

        left.set(getLeft()).multiplyLocal(fFarPlaneWidth);
        up.set(getUp()).multiplyLocal(fFarPlaneHeight);
        _corners[4].set(vFarPlaneCenter).subtractLocal(left).subtractLocal(up);
        _corners[5].set(vFarPlaneCenter).subtractLocal(left).addLocal(up);
        _corners[6].set(vFarPlaneCenter).addLocal(left).addLocal(up);
        _corners[7].set(vFarPlaneCenter).addLocal(left).subtractLocal(up);

        Vector3.releaseTempInstance(vNearPlaneCenter);
        Vector3.releaseTempInstance(vFarPlaneCenter);
        Vector3.releaseTempInstance(direction);
        Vector3.releaseTempInstance(left);
        Vector3.releaseTempInstance(up);
    }

    public Vector3[] getCorners() {
        return _corners;
    }
}
TOP

Related Classes of com.ardor3d.util.ExtendedCamera

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.