projectedgrid.java

来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 640 行 · 第 1/2 页

JAVA
640
字号
/*
 * 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.effects.water;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import com.jme.math.FastMath;
import com.jme.math.Matrix4f;
import com.jme.math.Quaternion;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.AbstractCamera;
import com.jme.renderer.Camera;
import com.jme.renderer.Renderer;
import com.jme.scene.TexCoords;
import com.jme.scene.TriMesh;
import com.jme.util.Timer;
import com.jme.util.geom.BufferUtils;
import com.jmex.effects.ProjectedTextureUtil;

/**
 * <code>ProjectedGrid</code>
 * Projected grid mesh
 *
 * @author Rikard Herlitz (MrCoder)
 */
public class ProjectedGrid extends TriMesh {
    private static final long serialVersionUID = 1L;
    
	private int sizeX;
	private int sizeY;

	//x/z step
	private static Vector3f calcVec1 = new Vector3f();
	private static Vector3f calcVec2 = new Vector3f();
	private static Vector3f calcVec3 = new Vector3f();

	private FloatBuffer vertBuf;
	private FloatBuffer normBuf;
	private FloatBuffer texs;
	private IntBuffer indexBuffer;

	private float viewPortWidth = 0;
	private float viewPortHeight = 0;
	private float viewPortLeft = 0;
	private float viewPortBottom = 0;

	private Quaternion origin = new Quaternion();
	private Quaternion direction = new Quaternion();
	private Vector2f source = new Vector2f();

	private Matrix4f modelViewMatrix = new Matrix4f();
	private Matrix4f projectionMatrix = new Matrix4f();
	private Matrix4f modelViewProjectionInverse = new Matrix4f();
	private Quaternion intersectBottomLeft = new Quaternion();
	private Quaternion intersectTopLeft = new Quaternion();
	private Quaternion intersectTopRight = new Quaternion();
	private Quaternion intersectBottomRight = new Quaternion();

	private Matrix4f modelViewMatrix1 = new Matrix4f();
	private Matrix4f projectionMatrix1 = new Matrix4f();
	private Matrix4f modelViewProjection1 = new Matrix4f();
	private Matrix4f modelViewProjectionInverse1 = new Matrix4f();
	private Quaternion intersectBottomLeft1 = new Quaternion();
	private Quaternion intersectTopLeft1 = new Quaternion();
	private Quaternion intersectTopRight1 = new Quaternion();
	private Quaternion intersectBottomRight1 = new Quaternion();

	private Vector3f camloc = new Vector3f();
	private Vector3f camdir = new Vector3f();
	private Quaternion pointFinal = new Quaternion();
	private Quaternion pointTop = new Quaternion();
	private Quaternion pointBottom = new Quaternion();
	private Vector3f realPoint = new Vector3f();

	public boolean freezeProjector = false;
	public boolean useReal = false;
	private Vector3f projectorLoc = new Vector3f();
	private Timer timer;
	private Camera cam;
	private float fovY = 45.0f;

	private HeightGenerator heightGenerator;
	private float textureScale;

	private float[] vertBufArray;
	private float[] normBufArray;
	private float[] texBufArray;
	
	public ProjectedGrid( String name, Camera cam, int sizeX, int sizeY, float texureScale, HeightGenerator heightGenerator ) {
		super( name );
		this.sizeX = sizeX;
		this.sizeY = sizeY;
		this.textureScale = texureScale;
		this.heightGenerator = heightGenerator;
		this.cam = cam;
		
		if (cam.getFrustumNear() > 0.0f) {
			fovY = FastMath.atan(cam.getFrustumTop() / cam.getFrustumNear())
					* 2.0f / FastMath.DEG_TO_RAD;
		}

		timer = Timer.getTimer();

		setVertexCount( sizeX * sizeY );

		vertBufArray = new float[getVertexCount()*3];
		normBufArray = new float[getVertexCount()*3];
		texBufArray = new float[getVertexCount()*2];

		buildVertices();
		buildTextureCoordinates();
		buildNormals();
	}

	public void switchFreeze() {
		freezeProjector = !freezeProjector;
	}

	public void draw( Renderer r ) {
		update();
		super.draw( r );
	}

	public void update() {
		if( freezeProjector ) return;

		float time = timer.getTimeInSeconds();

		camloc.set( cam.getLocation() );
		camdir.set( cam.getDirection() );

		AbstractCamera camera = (AbstractCamera) cam;

		viewPortWidth = camera.getWidth();
		viewPortHeight = camera.getHeight();
		viewPortLeft = camera.getViewPortLeft();
		viewPortBottom = camera.getViewPortBottom();
		modelViewMatrix.set( camera.getModelViewMatrix() );
		projectionMatrix.set( camera.getProjectionMatrix() );
		modelViewProjectionInverse.set( modelViewMatrix ).multLocal( projectionMatrix );
		modelViewProjectionInverse.invertLocal();

		source.set( 0.5f, 0.5f );
		getWorldIntersection( source, modelViewProjectionInverse, pointFinal );
		pointFinal.multLocal( 1.0f / pointFinal.w );
		realPoint.set( pointFinal.x, pointFinal.y, pointFinal.z );
		projectorLoc.set( cam.getLocation() );
		realPoint.set( projectorLoc ).addLocal( cam.getDirection() );

		Matrix4f rangeMatrix = null;
		if( useReal ) {
			Vector3f fakeLoc = new Vector3f( projectorLoc );
			Vector3f fakePoint = new Vector3f( realPoint );
			fakeLoc.addLocal( 0, 1000, 0 );

			rangeMatrix = getMinMax( fakeLoc, fakePoint, cam );
		}

		ProjectedTextureUtil.matrixLookAt( projectorLoc, realPoint, Vector3f.UNIT_Y, modelViewMatrix );
		ProjectedTextureUtil.matrixProjection( fovY + 10.0f, viewPortWidth / viewPortHeight, cam.getFrustumNear(), cam.getFrustumFar(), projectionMatrix );
		modelViewProjectionInverse.set( modelViewMatrix ).multLocal( projectionMatrix );
		modelViewProjectionInverse.invertLocal();

		if( useReal && rangeMatrix != null ) {
			rangeMatrix.multLocal( modelViewProjectionInverse );
			modelViewProjectionInverse.set( rangeMatrix );
		}

		source.set( 0, 0 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectBottomLeft );
		source.set( 0, 1 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectTopLeft );
		source.set( 1, 1 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectTopRight );
		source.set( 1, 0 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectBottomRight );

		vertBuf.rewind();
		float du = 1.0f / (float) (sizeX - 1);
		float dv = 1.0f / (float) (sizeY - 1);
		float u = 0, v = 0;
		int index = 0;
		for( int y = 0; y < sizeY; y++ ) {
			for( int x = 0; x < sizeX; x++ ) {
				interpolate( intersectTopLeft, intersectTopRight, u, pointTop );
				interpolate( intersectBottomLeft, intersectBottomRight, u, pointBottom );
				interpolate( pointTop, pointBottom, v, pointFinal );
				pointFinal.x /= pointFinal.w;
				pointFinal.z /= pointFinal.w;
				realPoint.set( pointFinal.x,
							   heightGenerator.getHeight( pointFinal.x, pointFinal.z, time ),
							   pointFinal.z );

				vertBufArray[index++] = realPoint.x;
				vertBufArray[index++] = realPoint.y;
				vertBufArray[index++] = realPoint.z;

				u += du;
			}
			v += dv;
			u = 0;
		}
		vertBuf.put( vertBufArray );

		texs.rewind();
		for( int i = 0; i < getVertexCount(); i++ ) {
			texBufArray[i*2] = vertBufArray[i*3] * textureScale;
			texBufArray[i*2+1] = vertBufArray[i*3+2] * textureScale;
		}
		texs.put( texBufArray );

		normBuf.rewind();
		oppositePoint.set( 0, 0, 0 );
		adjacentPoint.set( 0, 0, 0 );
		rootPoint.set( 0, 0, 0 );
		tempNorm.set( 0, 0, 0 );
		int adj = 0, opp = 0, normalIndex = 0;
		for( int row = 0; row < sizeY; row++ ) {
			for( int col = 0; col < sizeX; col++ ) {
				if( row == sizeY - 1 ) {
					if( col == sizeX - 1 ) { // last row, last col
						// up cross left
						adj = normalIndex - sizeX;
						opp = normalIndex - 1;
					}
					else { // last row, except for last col
						// right cross up
						adj = normalIndex + 1;
						opp = normalIndex - sizeX;
					}
				}
				else {
					if( col == sizeX - 1 ) { // last column except for last row
						// left cross down
						adj = normalIndex - 1;
						opp = normalIndex + sizeX;
					}
					else { // most cases
						// down cross right
						adj = normalIndex + sizeX;
						opp = normalIndex + 1;
					}
				}
				rootPoint.set(vertBufArray[normalIndex*3],vertBufArray[normalIndex*3+1],vertBufArray[normalIndex*3+2]);
				adjacentPoint.set(vertBufArray[adj*3],vertBufArray[adj*3+1],vertBufArray[adj*3+2]);
				oppositePoint.set(vertBufArray[opp*3],vertBufArray[opp*3+1],vertBufArray[opp*3+2]);
				tempNorm.set( adjacentPoint ).subtractLocal( rootPoint )
						.crossLocal( oppositePoint.subtractLocal( rootPoint ) )
						.normalizeLocal();

				normBufArray[normalIndex*3] = tempNorm.x;
				normBufArray[normalIndex*3+1] = tempNorm.y;
				normBufArray[normalIndex*3+2] = tempNorm.z;

				normalIndex++;
			}
		}
		normBuf.put( normBufArray );
	}

	private Matrix4f getMinMax( Vector3f fakeLoc, Vector3f fakePoint, Camera cam ) {
		Matrix4f rangeMatrix;
		ProjectedTextureUtil.matrixLookAt( fakeLoc, fakePoint, Vector3f.UNIT_Y, modelViewMatrix1 );
		ProjectedTextureUtil.matrixProjection( fovY, viewPortWidth / viewPortHeight, cam.getFrustumNear(), cam.getFrustumFar(), projectionMatrix1 );
		modelViewProjection1.set( modelViewMatrix1 ).multLocal( projectionMatrix1 );
		modelViewProjectionInverse1.set( modelViewProjection1 ).invertLocal();

		source.set( 0, 0 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectBottomLeft1 );
		source.set( 0, 1 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectTopLeft1 );
		source.set( 1, 1 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectTopRight1 );
		source.set( 1, 0 );
		getWorldIntersection( source, modelViewProjectionInverse, intersectBottomRight1 );

		Vector3f tmp = new Vector3f();
		tmp.set( intersectBottomLeft.x, intersectBottomLeft.y, intersectBottomLeft.z );
		modelViewProjection1.mult( tmp, tmp );
		intersectBottomLeft.x = tmp.x;
		intersectBottomLeft.y = tmp.y;
		intersectBottomLeft.z = tmp.z;

		tmp.set( intersectTopLeft1.x, intersectTopLeft1.y, intersectTopLeft1.z );
		modelViewProjection1.mult( tmp, tmp );
		intersectTopLeft1.x = tmp.x;
		intersectTopLeft1.y = tmp.y;
		intersectTopLeft1.z = tmp.z;

⌨️ 快捷键说明

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