⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 terrainpage.java

📁 java 3d game jme 工程开发源代码
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.jmex.terrain;

import java.io.IOException;

import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingVolume;
import com.jme.math.FastMath;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;

/**
 * <code>TerrainPage</code> is used to build a quad tree of terrain blocks. The
 * <code>TerrainPage</code> will have four children, either four pages or four
 * blocks. The size of the page must be (2^N + 1), to allow for even splitting
 * of the blocks. Organization of the page into a quad tree allows for very fast
 * culling of the terrain. The total size of the heightmap is provided, as well
 * as the desired end size for a block. Appropriate values for the end block
 * size is completely dependent on the application. In some cases, a large size
 * will give performance gains, in others, a small size is the best option. It
 * is recommended that different combinations are tried.
 * 
 * @author Mark Powell
 * @author Joshua Slack
 */
public class TerrainPage extends Node {

    private static final long serialVersionUID = 1L;

    private Vector2f offset;

    private int totalSize;

    private int size;

    private Vector3f stepScale;

    private float offsetAmount;

    private short quadrant = 1;

    private static Vector3f calcVec1 = new Vector3f();

    /**
     * Empty Constructor to be used internally only.
     */
    public TerrainPage() {
    }

    /**
     * Creates a TerrainPage to be filled later. Usually, users don't want to
     * call this function unless they have a terrain page already built.
     * 
     * @param name
     *            The name of the page node.
     */
    public TerrainPage(String name) {
        super(name);
    }

    /**
     * Constructor instantiates a new <code>TerrainPage</code> object. The
     * data is then split into either 4 new <code>TerrainPages</code> or 4 new
     * <code>TerrainBlock</code>.
     * 
     * @param name
     *            the name of the page.
     * @param blockSize
     *            the size of the leaf nodes. This is used to determine if four
     *            new <code>TerrainPage</code> objects should be the child or
     *            four new <code>TerrainBlock</code> objects.
     * @param size
     *            the size of the heightmap for this page.
     * @param stepScale
     *            the scale of the axes.
     * @param heightMap
     *            the height data.
     */
    public TerrainPage(String name, int blockSize, int size,
            Vector3f stepScale, float[] heightMap) {
        this(name, blockSize, size, stepScale, heightMap, size,
                new Vector2f(), 0);
        fixNormals();
    }

    /**
     * Constructor instantiates a new <code>TerrainPage</code> object. The
     * data is then split into either 4 new <code>TerrainPages</code> or 4 new
     * <code>TerrainBlock</code>.
     * 
     * @param name
     *            the name of the page.
     * @param blockSize
     *            the size of the leaf nodes. This is used to determine if four
     *            new <code>TerrainPage</code> objects should be the child or
     *            four new <code>TerrainBlock</code> objects.
     * @param size
     *            the size of the heightmap for this page.
     * @param stepScale
     *            the scale of the axes.
     * @param heightMap
     *            the height data.
     * @param totalSize
     *            the total terrain size, used if the page is an internal node
     *            of a terrain system.
     * @param offset
     *            the texture offset for the page.
     * @param offsetAmount
     *            the amount of the offset.
     */
    protected TerrainPage(String name, int blockSize, int size,
            Vector3f stepScale, float[] heightMap, int totalSize,
            Vector2f offset, float offsetAmount) {
        super(name);
        if (!FastMath.isPowerOfTwo(size - 1)) {
            throw new JmeException("size given: " + size
                    + "  Terrain page sizes may only be (2^N + 1)");
        }

        this.offset = offset;
        this.offsetAmount = offsetAmount;
        this.totalSize = totalSize;
        this.size = size;
        this.stepScale = stepScale;
        split(blockSize, heightMap);
    }

    /**
     * <code>setDetailTexture</code> sets the detail texture coordinates to be
     * applied on top of the normal terrain texture.
     * 
     * @param unit
     *            the texture unit to set the coordinates.
     * @param repeat
     *            the number of tiling for the texture.
     */
    public void setDetailTexture(int unit, int repeat) {
        for (int i = 0; i < this.getQuantity(); i++) {
            if (this.getChild(i) instanceof TerrainPage) {
                ((TerrainPage) getChild(i)).setDetailTexture(unit, repeat);
            } else if (this.getChild(i) instanceof TerrainBlock) {
                ((TerrainBlock) getChild(i)).setDetailTexture(unit, repeat);

            }
        }
    }

    /**
     * <code>setModelBound</code> sets the model bounds for the terrain
     * blocks.
     * 
     * @param v
     *            the bounding volume to set for the terrain blocks.
     */
    public void setModelBound(BoundingVolume v) {
        for (int i = 0; i < this.getQuantity(); i++) {
            if (this.getChild(i) instanceof TerrainPage) {
                ((TerrainPage) getChild(i)).setModelBound(v.clone(null));
            } else if (this.getChild(i) instanceof TerrainBlock) {
                ((TerrainBlock) getChild(i)).setModelBound(v.clone(null));

            }
        }
    }

    /**
     * <code>updateModelBound</code> updates the model bounds (generates the
     * bounds from the current vertices).
     */
    public void updateModelBound() {
        for (int i = 0; i < this.getQuantity(); i++) {
            if (this.getChild(i) instanceof TerrainPage) {
                ((TerrainPage) getChild(i)).updateModelBound();
            } else if (this.getChild(i) instanceof TerrainBlock) {
                ((TerrainBlock) getChild(i)).updateModelBound();

            }
        }
    }

    /**
     * <code>updateFromHeightMap</code> updates the verts of all sub blocks
     * from the contents of their heightmaps.
     */
    public void updateFromHeightMap() {
        for (int i = 0; i < this.getQuantity(); i++) {
            if (this.getChild(i) instanceof TerrainPage) {
                ((TerrainPage) getChild(i)).updateFromHeightMap();
            } else if (this.getChild(i) instanceof TerrainBlock) {
                ((TerrainBlock) getChild(i)).updateFromHeightMap();

            }
        }
    }

    /**
     * <code>getHeight</code> returns the height of an arbitrary point on the
     * terrain. If the point is between height point values, the height is
     * linearly interpolated. This provides smooth height calculations. If the
     * point provided is not within the bounds of the height map, the NaN float
     * value is returned (Float.NaN).
     * 
     * @param position
     *            the vector representing the height location to check.
     * @return the height at the provided location.
     */
    public float getHeight(Vector2f position) {
        return getHeight(position.x, position.y);
    }

    /**
     * <code>getHeight</code> returns the height of an arbitrary point on the
     * terrain. If the point is between height point values, the height is
     * linearly interpolated. This provides smooth height calculations. If the
     * point provided is not within the bounds of the height map, the NaN float
     * value is returned (Float.NaN).
     * 
     * @param position
     *            the vector representing the height location to check. Only the
     *            x and z values are used.
     * @return the height at the provided location.
     */
    public float getHeight(Vector3f position) {
        return getHeight(position.x, position.z);
    }

    /**
     * <code>getHeight</code> returns the height of an arbitrary point on the
     * terrain. If the point is between height point values, the height is
     * linearly interpolated. This provides smooth height calculations. If the
     * point provided is not within the bounds of the height map, the NaN float
     * value is returned (Float.NaN).
     * 
     * @param x
     *            the x coordinate to check.
     * @param z
     *            the z coordinate to check.
     * @return the height at the provided location.
     */
    public float getHeight(float x, float z) {
        // determine which quadrant this is in.
        Spatial child = null;
        int split = (size - 1) >> 1;
        float halfmapx = split * stepScale.x, halfmapz = split * stepScale.z;
        float newX = 0, newZ = 0;
        if (x == 0)
            x += .001f;
        if (z == 0)
            z += .001f;
        if (x > 0) {
            if (z > 0) {
                // upper right
                child = getChild(3);
                newX = x;
                newZ = z;
            } else {
                // lower right
                child = getChild(2);
                newX = x;
                newZ = z + halfmapz;
            }
        } else {
            if (z > 0) {
                // upper left
                child = getChild(1);
                newX = x + halfmapx;
                newZ = z;
            } else {
                // lower left...
                child = getChild(0);
                if (x == 0)
                    x -= .1f;
                if (z == 0)
                    z -= .1f;
                newX = x + halfmapx;
                newZ = z + halfmapz;
            }
        }
        if (child instanceof TerrainBlock)
            return ((TerrainBlock) child).getHeight(newX, newZ);
        else if (child instanceof TerrainPage)
            return ((TerrainPage) child).getHeight(x
                    - ((TerrainPage) child).getLocalTranslation().x, z
                    - ((TerrainPage) child).getLocalTranslation().z);
        return Float.NaN;
    }

    /**
     * <code>getHeightFromWorld</code> returns the height of an arbitrary
     * point on the terrain when given world coordinates. If the point is
     * between height point values, the height is linearly interpolated. This
     * provides smooth height calculations. If the point provided is not within
     * the bounds of the height map, the NaN float value is returned
     * (Float.NaN).
     * 
     * @param position
     *            the vector representing the height location to check.
     * @return the height at the provided location.
     */
    public float getHeightFromWorld(Vector3f position) {
        Vector3f locationPos = calcVec1.set(position).subtractLocal(
                localTranslation).divideLocal(stepScale);
        locationPos.multLocal(getStepScale());

        return getHeight(locationPos.x, locationPos.z);
    }

    /**
     * <code>getSurfaceNormal</code> returns the normal of an arbitrary point
     * on the terrain. The normal is linearly interpreted from the normals of
     * the 4 nearest defined points. If the point provided is not within the
     * bounds of the height map, null is returned.
     * 
     * @param position
     *            the vector representing the location to find a normal at.
     * @param store
     *            the Vector3f object to store the result in. If null, a new one
     *            is created.
     * @return the normal vector at the provided location.
     */
    public Vector3f getSurfaceNormal(Vector2f position, Vector3f store) {
        return getSurfaceNormal(position.x, position.y, store);
    }

    /**
     * <code>getSurfaceNormal</code> returns the normal of an arbitrary point
     * on the terrain. The normal is linearly interpreted from the normals of
     * the 4 nearest defined points. If the point provided is not within the
     * bounds of the height map, null is returned.
     * 
     * @param position
     *            the vector representing the location to find a normal at. Only
     *            the x and z values are used.
     * @param store
     *            the Vector3f object to store the result in. If null, a new one
     *            is created.
     * @return the normal vector at the provided location.
     */
    public Vector3f getSurfaceNormal(Vector3f position, Vector3f store) {
        return getSurfaceNormal(position.x, position.z, store);
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -