本程序介绍JME的的地形实用工具类。您将学习如何使用ProceduralTextureGenerator,ImageBasedHeightMap,MidPointHeightMap和TerrainBlock对象。
这一切都将允许看毫不费力地创建地形。
import com.jme.app.SimpleGame; import com.jme.terrain.TerrainBlock; import com.jme.terrain.util.MidPointHeightMap; import com.jme.terrain.util.ImageBasedHeightMap; import com.jme.terrain.util.ProceduralTextureGenerator; import com.jme.math.Vector3f; import com.jme.bounding.BoundingBox; import com.jme.scene.state.TextureState; import com.jme.util.TextureManager; import com.jme.image.Texture; import java.net.URL; import javax.swing.*; /** * Started Date: Aug 19, 2004<br><br> * * This program introduces jME's terrain utility classes and how * they are used. It * goes over ProceduralTextureGenerator, * ImageBasedHeightMap, MidPointHeightMap, and * TerrainBlock. * * @author Jack Lindamood */ public class HelloTerrain extends SimpleGame { public static void main(String[] args) { HelloTerrain app = new HelloTerrain(); app.setDialogBehaviour(SimpleGame.ALWAYS_SHOW_PROPS_DIALOG); app.start(); } protected void simpleInitGame() { // First a hand made terrain homeGrownHeightMap(); // Next an automatically generated terrain with a texture generatedHeightMap(); // Finally a terrain loaded from a greyscale image with // fancy textures on it. complexTerrain(); } private void homeGrownHeightMap() { // The map for our terrain. Each value is a height on the terrain int[] map=new int[]{ 1,2,3,4, 89 2,1,2,3, 3,2,1,2, 4,3,2,1 }; // Create a terrain block. Our integer height values will // scale on the map 2x larger x, // and 2x larger z. Our map's origin will be the regular // origin, and it won't create an // AreaClodMesh from it. TerrainBlock tb=new TerrainBlock("block",4, new Vector3f(2,1,2), map, new Vector3f(0,0,0), false); // Give the terrain a bounding box. tb.setModelBound(new BoundingBox()); tb.updateModelBound(); // Attach the terrain TriMesh to our rootNode rootNode.attachChild(tb); } private void generatedHeightMap() { // This will be the texture for the terrain. URL grass=HelloTerrain.class.getClassLoader().getResource( "jmetest/data/texture/grassb.png"); // Use the helper class to create a terrain for us. The // terrain will be 64x64 MidPointHeightMap mph=new MidPointHeightMap(64,1.5f); // Create a terrain block from the created terrain map. TerrainBlock tb=new TerrainBlock("midpoint block",mph.getSize(), new Vector3f(1,.11f,1), mph.getHeightMap(), new Vector3f(0,-25,0),false); // Add the texture TextureState ts=display.getRenderer().createTextureState(); ts.setTexture( TextureManager.loadTexture(grass, Texture.MM_LINEAR,Texture.FM_LINEAR,true) ); tb.setRenderState(ts); // Give the terrain a bounding box. tb.setModelBound(new BoundingBox()); tb.updateModelBound(); // Attach the terrain TriMesh to rootNode rootNode.attachChild(tb); } private void complexTerrain() { // This grayscale image will be our terrain URL grayscale = HelloTerrain. class.getClassLoader(). getResource("jmetest/data/texture/bubble.jpg"); // These will be the textures of our terrain. URL waterImage=HelloTerrain. class.getClassLoader(). getResource("jmetest/data/texture/water.png"); URL dirtImage=HelloTerrain. class.getClassLoader(). getResource("jmetest/data/texture/dirt.jpg"); URL highest=HelloTerrain. class.getClassLoader(). getResource("jmetest/data/texture/highest.jpg"); // Create an image height map based on the gray scale of our image. ImageBasedHeightMap ib=new ImageBasedHeightMap( new ImageIcon(grayScale).getImage() ); // Create a terrain block from the image's grey scale TerrainBlock tb=new TerrainBlock("image icon",ib.getSize(), new Vector3f(.5f,.05f,.5f),ib.getHeightMap(), new Vector3f(0,0,0),false); // Create an object to generate textured terrain from the // image based height map. ProceduralTextureGenerator pg=new ProceduralTextureGenerator(ib); // Look like water from height 0-60 with the strongest // "water look" at 30 pg.addTexture(new ImageIcon(waterImage),0,30,60); // Look like dirt from height 40-120 with the strongest // "dirt look" at 80 pg.addTexture(new ImageIcon(dirtImage),40,80,120); // Look like highest (pure white) from height 110-256 // with the strongest "white look" at 130 pg.addTexture(new ImageIcon(highest),110,130,256); // Tell pg to create a texture from the ImageIcon's it has recieved. pg.createTexture(256); TextureState ts=display.getRenderer().createTextureState(); // Load the texture and assign it. ts.setTexture( TextureManager.loadTexture( pg.getImageIcon().getImage(), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, true, true ) ); tb.setRenderState(ts); // Give the terrain a bounding box tb.setModelBound(new BoundingBox()); tb.updateModelBound(); // Move the terrain in front of the camera tb.setLocalTranslation(new Vector3f(0,0,-50)); // Attach the terrain to our rootNode. rootNode.attachChild(tb); } } 这个程序演示了jme的地形如何工作,所有的地形来自基类 TerrainBlock。这个类也是一个TriMesh,此类用一个整数 数组创建地形,这个程序创建了3个不同类型的地形, 第一个始手工的,第2个使用工具创建,第3个是从某地形文件创建,我们开始第一个先 // The map for our terrain. Each value is a height on the terrain int[] map=new int[]{ 1,2,3,4, 2,1,2,3, 3,2,1,2, 4,3,2,1 }; // Create a terrain block. Our integer height values will // scale on the map 2x larger x, // and 2x larger z. Our map's origin will be the regular // origin, and it won't create an // AreaClodMesh from it. TerrainBlock tb=new TerrainBlock("block",4, new Vector3f(2,1,2), map, new Vector3f(0,0,0), false); 这个地图数组就是整数值,每个整数代表一个高度 这地形是一个正方形,如果你用map数组创建每个高度 他看起来就是这样的,这就是在terrainblock如何生成的 TerrainBlock第一个参数是地形块的名字(每个spatial对象必须有名字),接着块的尺寸是4*4.3rd是地形的scale值,我们定义了地形的整数值但如果我们要浮点的高度, scale值把地形沿x和z轴拉长了两倍。通过这个值可以控制 地形的大小,最后两个参数是地形的原点(0,0,00 如果我们要用areaclodmesh创建地形,地形将占用更大的内存可是会有更快的刷新率 下面,看这个地形的生成 // Use the helper class to create a terrain for us. The // terrain will be 64x64 MidPointHeightMap mph=new MidPointHeightMap(64,1.5f); // Create a terrain block from the created terrain map. TerrainBlock tb=new TerrainBlock("midpoint block",mph.getSize(), new Vector3f(1,.11f,1), mph.getHeightMap(), new Vector3f(0,-25,0),false); 这里我们使用midpointheightmap去生成一个地形, 地形是64*64的,我们给他的粗糙度是1.5,这个值让 地形变得平滑,你可以把它设成你期望的效果, terrainblock对象从midpointheightmap中读取地形大小。 最后我们创建一个灰色图片的地形。 你要注意地形图片的明暗度,imagebasedheightmap创建的地形从高到低由亮到暗, // Create an image height map based on the gray scale of our image. ImageBasedHeightMap ib=new ImageBasedHeightMap( new ImageIcon(grayScale).getImage() ); 我必须传递imagebasedheightmap一个图片对象,为此 我创建imageicon获取url资源的图片,在height map和 terrainblock创建之后,下一步是创建strange地形, 首先,看这三个地形 第一个是water,第2个是dirt最后一个是highest.jpg 注意highest.jpg是相似白,现在另一个要关注的是复杂 地形的尺寸 // Create an object to generate textured terrain from the // image based height map. ProceduralTextureGenerator pg=new ProceduralTextureGenerator(ib); // Look like water from height 0-60 with the strongest // "water look" at 30 pg.addTexture(new ImageIcon(waterImage),0,30,60); // Look like dirt from height 40-120 with the strongest // "dirt look" at 80 pg.addTexture(new ImageIcon(dirtImage),40,80,120); // Look like highest (pure white) from height 110-256 // with the strongest "white look" at 130 pg.addTexture(new ImageIcon(highest),110,130,256); 当我创建pd时传递它一个height map(实际height map 对象不是int[]数组),它使用height map创建纹理 下面我传递3个图片给地形的3个部分,让我们看其中一个 另外两个是同样的道理 // Look like water from height 0-60 with the strongest // "water look" at 30 pg.addTexture(new ImageIcon(waterImage),0,30,60); 这个方法调用pg从高0-60存放water图片,water图片融合 0-30之间,这个融合的最大强度是30,同样处理其他两个纹理,通知pg需要创建纹理 // Tell pg to create a texture from the ImageIcon's it has recieved. pg.createTexture(256); 你将注意当我创建纹理对象需要使用texturestate, 我从pg获得texture TextureState ts=display.getRenderer().createTextureState(); // Load the texture and assign it. ts.setTexture( TextureManager.loadTexture( pg.getImageIcon().getImage(), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, true, true ) ); 全部的工作完成了,一个terrain类创建地形并把它拆分到 不同的约束盒所以你看不到地形被包裹