| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Asciidoctor 1.5.4"><title>TerraMonkey - The jMonkeyEngine Terrain System</title><link rel="stylesheet" href="./asciidoctor.css">
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
- <link rel="stylesheet" href="./coderay-asciidoctor.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css"><link rel="stylesheet" href="/home/travis/build/jMonkeyEngine/wiki/build/asciidoc/html5/jme3/advanced/twemoji-awesome.css"></head><body class="article toc2 toc-left"><div id="header"><div id="toolbar"><a href="https://github.com/jMonkeyEngine/wiki/edit/master/src/docs/asciidoc/jme3/advanced/terrain.adoc"><i class="fa fa-pencil-square" aria-hidden="true"></i></a><a href="https://github.com/jMonkeyEngine/wiki/new/master/src/docs/asciidoc/jme3/advanced/"><i class="fa fa-plus-square" aria-hidden="true"></i></a><input dir="auto" style="position: relative; vertical-align: top;" spellcheck="false" autocomplete="off" class="searchbox__input aa-input" id="doc-search" name="search" placeholder="Search in the doc" required="required" type="search"></div><h1>TerraMonkey - The jMonkeyEngine Terrain System</h1><div class="details"><span class="author" id="author"></span><br><span id="revnumber">version ,</span> <span id="revdate">2016/03/17 20:48</span></div><div id="toc" class="toc2"><div id="toctitle">Table of Contents</div><ul class="sectlevel1"><li><a href="#overview">Overview</a><ul class="sectlevel2"><li><a href="#current-features">Current Features:</a></li><li><a href="#planned-features">Planned Features:</a></li></ul></li><li><a href="#sample-code">Sample Code</a></li><li><a href="#geo-mip-mapping">Geo Mip Mapping</a></li><li><a href="#terrain-quad-tree">Terrain Quad Tree</a></li><li><a href="#texture-splatting">Texture Splatting</a></li><li><a href="#code-sample-terrain-j3md">Code Sample: Terrain.j3md</a></li></ul></div></div><div id="content"><div class="sect2"><h3 id="overview">Overview</h3><div class="paragraph"><p>TerraMonkey is a GeoMipMapping quad tree of terrain tiles that supports real time editing and texture splatting. That’s a mouth full! Lets look at each part:</p></div>
- <div class="ulist"><ul><li><p><strong>GeoMipMapping:</strong> a method of changing the level of detail (LOD) of geometry tiles based on how far away they are from the camera. Between the edges of two tiles, it will seam those edges together so you don’t get gaps or holes. For an in-depth read on how it works, read <a href="http://www.flipcode.com/archives/article_geomipmaps.pdf">Fast Terrain Rendering Using Geometrical MipMapping
- </a>.</p></li><li><p><strong>Quad Tree:</strong> The entire terrain structure is made up of TerrainPatches (these hold the actual meshes) as leaves in a quad tree (TerrainQuad). TerrainQuads are subdivided by 4 until they reach minimum size, then a TerrainPatch is created, and that is where the actual geometry mesh lives. This allows for fast culling of the terrain that you can’t see.</p></li><li><p><strong>Splatting:</strong> The ability to paint multiple textures onto your terrain. What differs here from JME2 is that this is all done in a shader, no more render passes. So it performs much faster.</p></li><li><p><strong>Real-time editing:</strong> <a href="../../sdk/terrain_editor.html">TerraMonkey terrains are editable in jMonkeyEngine SDK</a>, and you are able to modify them in real time, for example by raising and lowering the terrain.</p></li></ul></div>
- <div class="sect2"><h3 id="current-features">Current Features:</h3><div class="ulist"><ul><li><p>Support for 16 splat textures. You use a custom combination of Diffuse, Normal, Specular, and Glow Maps.</p></li><li><p>GeoMipMapping: LodControl optimizes the level of detail</p></li><li><p>Terrain can be randomized or generated from a heightmap</p></li><li><p>jMonkeyEngine SDK terrain editor</p></li><li><p>Streaming <a href="../../jme3/advanced/endless_terraingrid.html">terrain grid</a> (i.e. infinite terrain)</p></li></ul></div></div>
- <div class="sect2"><h3 id="planned-features">Planned Features:</h3><div class="ulist"><ul><li><p>Hydraulic erosion and procedural texture generation</p></li><li><p>Holes: caves, cliffs</p></li></ul></div></div></div>
- <div class="sect1"><h2 id="sample-code">Sample Code</h2><div class="sectionbody"><div class="ulist"><ul><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/terrain/TerrainTest.java">TerrainTest.java</a></p></li><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAdvanced.java">TerrainTestAdvanced.java</a></p></li><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/terrain/TerrainTestCollision.java">TerrainTestCollision.java</a></p></li><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/terrain/TerrainTestModifyHeight.java">TerrainTestModifyHeight.java</a></p></li><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/terrain/TerrainTestReadWrite.java">TerrainTestReadWrite.java</a></p></li></ul></div></div></div>
- <div class="sect1"><h2 id="geo-mip-mapping">Geo Mip Mapping</h2><div class="sectionbody"><div style="text-align: left;" class="imageblock"><div class="content"><img src="../../jme3/advanced/terrain-lod-high-medium-low.png" alt="The wiremesh of a terrain with visible differences in levels of detail (LOD)" width="" height=""></div></div>
- <div class="paragraph"><p>You have seen GeoMipMapping implemented in games before. This is where the farther away terrain has fewer polygons, and as you move closer, more polygons fill in. The whole terrain is divided into a grid of patches, and each one has its own level of detail (LOD). The GeoMipMapping algorithm looks at each patch, and its neighbours, to determine how to render the geometry. It will seam the edges between two patches with different LOD.</p></div>
- <div class="paragraph"><p>GeoMipMapping often leads to “popping where you see the terrain switch from one LOD to another. TerraMonkey has been designed so you can swap out different LOD calculation algorithms based on what will look best for your game. You can do this with the LodCalculator interface.</p></div>
- <div class="paragraph"><p>GeoMipMapping in TerraMonkey has been split into several parts: the terrain quad tree, and the LODGeomap. The geomap deals with the actual LOD and seaming algorithm. So if you want a different data structure for your terrain system, you can re-use this piece of code. The quad tree (TerrainQuad and TerrainPatch) provide a means to organize the LODGeomaps, notify them of their neighbour’s LOD change, and to update the geometry when the LOD does change. To change the LOD it does this by changing the index buffer of the triangle strip, so the whole geometry doesn’t have to be re-loaded onto the video card. If you are eager for more detail on how GeoMipMapping works read: <a href="http://www.flipcode.com/archives/article_geomipmaps.pdf">Fast Terrain Rendering Using Geometrical MipMapping
- </a>.</p></div></div></div>
- <div class="sect1"><h2 id="terrain-quad-tree">Terrain Quad Tree</h2><div class="sectionbody"><div class="paragraph"><p>TerraMonkey is a quad tree. Each node is a TerrainQuad, and each leaf is a TerrainPatch. A TerrainQuad has either 4 child TerrainQuads, or 4 child TerrainPatches. The TerrainPatch holds the actual mesh geometry. This structure is almost exactly the same as JME2’s TerrainPage system. Except now each leaf has a reference to its neighbours, so it doesn’t ever have to traverse the tree to get them.</p></div></div></div>
- <div class="sect1"><h2 id="texture-splatting">Texture Splatting</h2><div class="sectionbody"><div class="paragraph"><p>When you ‘slap’ a texture on a mesh, the whole mesh looks the same. For big meshes (such as terrains) that is undesirable because it looks very boring (your whole landscape would be all rock, or all grass, or all sand). Texture Splatting is a technique that lets you “paint several textures into one combined texure. Each of the splat textures has an opacity value so you can define where it is visible in the final overall texture.</p></div>
- <div class="paragraph"><p>The default material for TerraMonkey is TerrainLighting.j3md. This material combines several texture maps to produce the final custom texture. Remember, Diffuse Maps are the main textures that define the look; optionally, each Diffuse Map can be enhanced with a Normal Map; Alpha Maps describe the opacity of each Diffuse Map used (one color –red, green, blue, or alpha– stands for one Diffuse Map’s opacity); Glow and Specular Maps define optional effects.</p></div>
- <div class="admonitionblock important"><table><tr><td class="icon"><i class="fa icon-important" title="Important"></i></td><td class="content"><div class="paragraph"><p>We recommend to <a href="../../sdk/terrain_editor.html">create and edit Splat Textures for terrains visually in the jMonkeyEngine SDK</a>, and not do it manually. If you are simply curious about how the SDK’s terrain texture plugin works, or if you indeed want to generate materials manually, then read on for the implementation details.</p></div></td></tr></table></div>
- <div class="paragraph"><p>Here are the names of TerrainLighting.j3md’s material properties:</p></div>
- <div class="imageblock right text-left"><div class="content"><img src="../../jme3/beginner/mountains512.png" alt="A heightmap encodes the topological highs and lows of the terrain" width="128" height="128"></div></div>
- <div class="ulist"><ul><li><p>1-3 Alpha Maps</p><div class="ulist"><ul><li><p><code>AlphaMap</code></p></li><li><p><code>AlphaMap_1</code></p></li><li><p><code>AlphaMap_2</code></p></li></ul></div></li><li><p>12 Diffuse and/or Normal Maps (either in 6 pairs, or 12 stand-alone Diffuse Maps)</p><div class="ulist"><ul><li><p><code>DiffuseMap</code>, <code>DiffuseMap_0_scale</code>, <code>NormalMap</code></p></li><li><p><code>DiffuseMap_1</code>, <code>DiffuseMap_1_scale</code>, <code>NormalMap_1</code></p></li><li><p><code>DiffuseMap_2</code>, <code>DiffuseMap_2_scale</code>, <code>NormalMap_2</code></p></li><li><p><code>DiffuseMap_3</code>, <code>DiffuseMap_3_scale</code>, <code>NormalMap_3</code></p></li></ul></div></li></ul></div>
- <div class="paragraph right text-left"><p><span class="image"><img src="../../jme3/beginner/alphamap.png" alt="An alpha map can describe where 4 textures are painted onto the terrain." width="128" height="128"></span></p></div>
- <div class="ulist"><ul><li><p><code>DiffuseMap_4</code>, <code>DiffuseMap_4_scale</code>, <code>NormalMap_4</code></p></li><li><p>…</p></li><li><p><code>DiffuseMap_11</code>, <code>DiffuseMap_11_scale</code>, <code>NormalMap_11</code></p><div class="ulist"><ul><li><p>Light maps</p></li></ul></div></li><li><p><code>GlowMap</code></p></li><li><p><code>SpecularMap</code></p></li></ul></div>
- <div class="admonitionblock note"><table><tr><td class="icon"><i class="fa icon-note" title="Note"></i></td><td class="content"><div class="paragraph"><p><code>DiffuseMap_0_scale</code> is a float value (e.g. 1.0f); you must specify one scale per Diffuse Map.</p></div></td></tr></table></div>
- <div class="paragraph"><p>OpenGL supports a maximum of 16 <em>samplers</em> in any given shader. This means you can only use a subset of material properties at the same time if you use the terrain’s default lighting shader (TerrainLighting.j3md)!</p></div>
- <div class="paragraph"><p>Adhere to the following constraints:</p></div>
- <div class="imageblock right text-left"><div class="content"><img src="../../jme3/beginner/road.jpg" alt="The Diffuse Map of one of the terrain textures depicts the colors of a paved surface" width="" height=""></div></div>
- <div class="ulist"><ul><li><p>1-12 Diffuse Maps. One Diffuse Map is the minimum!</p></li><li><p>1-3 Alpha Maps. For each 4 Diffuse Maps, you need 1 more Alpha Map!</p></li><li><p>0-6 Normal Maps. Diffuse Maps & Normal Maps always come in pairs!</p></li><li><p>0 or 1 Glow Map</p></li><li><p>0 or 1 Specular Map.</p></li><li><p><strong>The sum of all textures used must be 16, or less.</strong></p></li></ul></div>
- <div class="paragraph"><p>Here are some common examples what this means:</p></div>
- <div class="imageblock right text-left"><div class="content"><img src="../../jme3/beginner/road_normal.png" alt="The Normal Map of one of the terrain textures depicts the bumpiness of a paved surface" width="" height=""></div></div>
- <div class="ulist"><ul><li><p>3 Alpha + 11 Diffuse + 1 Normal.</p></li><li><p>3 Alpha + 11 Diffuse + 1 Glow.</p></li><li><p>3 Alpha + 11 Diffuse + 1 Specular.</p></li><li><p>3 Alpha + 10 Diffuse + 3 Normal.</p></li><li><p>3 Alpha + 10 Diffuse + 1 Normal + 1 Glow + 1 Specular.</p></li><li><p>2 Alpha + 8 Diffuse + 6 Normal.</p></li><li><p>2 Alpha + 6 Diffuse + 6 Normal + 1 Glow + 1 Specular.</p></li><li><p>1 Alpha + 3 Diffuse + 3 Normal + 1 Glow + 1 Specular (rest unused)</p></li></ul></div>
- <div class="paragraph"><p>You can hand-paint Alpha, Diffuse, Glow, and Specular maps in a drawing program, like Photoshop. Define each splat texture in the Alpha Map in either Red, Green, Blue, or Alpha (=RGBA). The JmeTests project bundled in the <a href="../../sdk.html">SDK</a> includes some image files that show you how this works. The example images show a terrain heightmap next to its Alpha Map (which has been prepare for 3 Diffuse Maps), and one examplary Diffuse/Normal Map pair.</p></div></div></div>
- <div class="sect1"><h2 id="code-sample-terrain-j3md">Code Sample: Terrain.j3md</h2><div class="sectionbody"><div class="paragraph"><p>This example shows the simpler material definition <code>Terrain.j3md</code>, which only supports 1 Alpha Map, 3 Diffuse Maps, 3 Normal Maps, and does not support Phong illumination. It makes the exmaple shorter – TerrainLighting.j3md works accordingly (The list of material properties see above. Links to extended sample code see above.)</p></div>
- <div class="paragraph"><p>First, we load our textures and the heightmap texture for the terrain</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create material from Terrain Material Definition</span>
- matRock = <span class="keyword">new</span> Material(assetManager, <span class="string"><span class="delimiter">"</span><span class="content">Common/MatDefs/Terrain/Terrain.j3md</span><span class="delimiter">"</span></span>);
- <span class="comment">// Load alpha map (for splat textures)</span>
- matRock.setTexture(<span class="string"><span class="delimiter">"</span><span class="content">Alpha</span><span class="delimiter">"</span></span>, assetManager.loadTexture(<span class="string"><span class="delimiter">"</span><span class="content">Textures/Terrain/splat/alphamap.png</span><span class="delimiter">"</span></span>));
- <span class="comment">// load heightmap image (for the terrain heightmap)</span>
- Texture heightMapImage = assetManager.loadTexture(<span class="string"><span class="delimiter">"</span><span class="content">Textures/Terrain/splat/mountains512.png</span><span class="delimiter">"</span></span>);
- <span class="comment">// load grass texture</span>
- Texture grass = assetManager.loadTexture(<span class="string"><span class="delimiter">"</span><span class="content">Textures/Terrain/splat/grass.jpg</span><span class="delimiter">"</span></span>);
- grass.setWrap(WrapMode.Repeat);
- matRock.setTexture(<span class="string"><span class="delimiter">"</span><span class="content">Tex1</span><span class="delimiter">"</span></span>, grass);
- matRock.setFloat(<span class="string"><span class="delimiter">"</span><span class="content">Tex1Scale</span><span class="delimiter">"</span></span>, <span class="float">64f</span>);
- <span class="comment">// load dirt texture</span>
- Texture dirt = assetManager.loadTexture(<span class="string"><span class="delimiter">"</span><span class="content">Textures/Terrain/splat/dirt.jpg</span><span class="delimiter">"</span></span>);
- dirt.setWrap(WrapMode.Repeat);
- matRock.setTexture(<span class="string"><span class="delimiter">"</span><span class="content">Tex2</span><span class="delimiter">"</span></span>, dirt);
- matRock.setFloat(<span class="string"><span class="delimiter">"</span><span class="content">Tex2Scale</span><span class="delimiter">"</span></span>, <span class="float">32f</span>);
- <span class="comment">// load rock texture</span>
- Texture rock = assetManager.loadTexture(<span class="string"><span class="delimiter">"</span><span class="content">Textures/Terrain/splat/road.jpg</span><span class="delimiter">"</span></span>);
- rock.setWrap(WrapMode.Repeat);
- matRock.setTexture(<span class="string"><span class="delimiter">"</span><span class="content">Tex3</span><span class="delimiter">"</span></span>, rock);
- matRock.setFloat(<span class="string"><span class="delimiter">"</span><span class="content">Tex3Scale</span><span class="delimiter">"</span></span>, <span class="float">128f</span>);</code></pre></div></div>
- <div class="paragraph"><p>We create the heightmap from the <code>heightMapImage</code>.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">AbstractHeightMap heightmap = <span class="predefined-constant">null</span>;
- heightmap = <span class="keyword">new</span> ImageBasedHeightMap(heightMapImage.getImage(), <span class="float">1f</span>);
- heightmap.load();</code></pre></div></div>
- <div class="paragraph"><p>Next we create the actual terrain.</p></div>
- <div class="ulist"><ul><li><p>The terrain tiles are 65x65.</p></li><li><p>The total size of the terrain is 513x513, but it can easily be up to 1025x1025.</p></li><li><p>It uses the heightmap to generate the height values.</p></li></ul></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">terrain = <span class="keyword">new</span> TerrainQuad(<span class="string"><span class="delimiter">"</span><span class="content">terrain</span><span class="delimiter">"</span></span>, <span class="integer">65</span>, <span class="integer">513</span>, heightmap.getHeightMap());
- terrain.setMaterial(matRock);
- terrain.setLocalScale(<span class="float">2f</span>, <span class="float">1f</span>, <span class="float">2f</span>); <span class="comment">// scale to make it less steep</span>
- <span class="predefined-type">List</span><Camera> cameras = <span class="keyword">new</span> <span class="predefined-type">ArrayList</span><>();
- cameras.add(getCamera());
- TerrainLodControl control = <span class="keyword">new</span> TerrainLodControl(terrain, cameras);
- terrain.addControl(control);
- rootNode.attachChild(terrain);</code></pre></div></div>
- <div class="admonitionblock tip"><table><tr><td class="icon"><i class="fa icon-tip" title="Tip"></i></td><td class="content"><div class="paragraph"><p>As an alternative to an image-based height map, you can also generate a Hill hightmap:</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">heightmap = <span class="keyword">new</span> HillHeightMap(<span class="integer">1025</span>, <span class="integer">1000</span>, <span class="integer">50</span>, <span class="integer">100</span>, (<span class="type">byte</span>) <span class="integer">3</span>);</code></pre></div></div></td></tr></table></div></div></div></div><div id="footer"><div id="footer-text">Version <br>Last updated 2019-12-20 23:30:51 +00:00</div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script><script>docsearch({
- apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
- indexName: 'jmonkeyengine',
- inputSelector: '#doc-search',
- debug: false // Set debug to true if you want to inspect the dropdown
- });</script></body></html>
|