mesh_generation_with_heightmap_and_shaders.rst 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. .. _doc_mesh_generation_with_heightmap_and_shaders:
  2. Mesh generation with heightmap and shaders
  3. ==========================================
  4. Introduction
  5. ------------
  6. This tutorial will help you to use Godot shaders to deform a plane
  7. mesh so it appears like a basic terrain. Remember that this solution
  8. has pros and cons.
  9. Pros:
  10. - Pretty easy to do.
  11. - This approach allows computation of LOD terrains.
  12. - The heightmap can be used in Godot to create a normal map.
  13. Cons:
  14. - The Vertex Shader can't re-compute normals of the faces. Thus, if
  15. your mesh is not static, this method will **not** work with shaded
  16. materials.
  17. - This tutorial uses a plane mesh imported from Blender to Godot
  18. Engine. Godot is able to create meshes as well.
  19. See this tutorial as an introduction, not a method that you should
  20. employ in your games, except if you intend to do LOD. Otherwise, this is
  21. probably not the best way.
  22. However, let's first create a heightmap. To do so, let's first create a
  23. heightmap. To do this, I'll use GIMP editor, but you can use any image
  24. editor you like.
  25. The heightmap
  26. -------------
  27. We will use a few functions of GIMP image editor to produce a simple
  28. heightmap. Start GIMP and create a square image of 512x512 pixels.
  29. .. image:: /img/1_GIMP_createImage512.png
  30. You are now in front of a new, blank, square image.
  31. .. image:: /img/2_GIMP.png
  32. Then, use a filter to render some clouds on this new image.
  33. .. image:: /img/3_GIMP_FilterRenderClouds.png
  34. Parameter this filter to whatever you want. A white pixel corresponds
  35. to the highest point of the heightmap, a black pixel corresponds to
  36. the lowest one. So, darker regions are valleys and brighter are
  37. mountains. If you want, you can check "tileable" to render a heightmap
  38. that can be cloned and tiled close together with another one. X and Y
  39. size don't matter a lot as long as they are big enough to provide a
  40. decent ground. A value of 4.0 or 5.0 for both is nice. Click on the
  41. "New Seed" button to roll a dice and GIMP will create a new random
  42. heightmap. Once you are happy with the result, click "OK".
  43. .. image:: /img/4_GIMP_Clouds.png
  44. You can continue to edit your image if you wish. For our example,
  45. let's keep the heightmap as is, and let's export it to a PNG file, say
  46. "heightmap.png". Save it in your Godot project folder.
  47. The plane mesh
  48. --------------
  49. Now, we will need a plane mesh to import in Godot. Let's run Blender.
  50. .. image:: /img/5_Blender.png
  51. Remove the start cube mesh, then add a new plane to the scene.
  52. .. image:: /img/6_Blender_CreatePlane.png
  53. Zoom a bit, then switch to Edit mode (Tab key) and in the Tools
  54. buttongroup at the left, hit "Subdivide" 5 or 6 times.
  55. .. image:: /img/7_Blender_subdivided.png
  56. Your mesh is now subdivided, which means we added vertices to the
  57. plane mesh that we will later be able to move. Job's not finished yet:
  58. in order to texture this mesh a proper UV map is necessary. Currently,
  59. the default UV map contains only the 4 corner vertices we had at the
  60. beginning. However, we now have more, and we want to be able to
  61. texture over the whole mesh correctly.
  62. If all the vertices of your mesh are not selected, select them all
  63. (hit "A"). They must appear orange, not black. Then, in the
  64. Shading/UVs button group a the left, click the "Unwrap" button (or
  65. simply hit "U") and select "Smart UV Project". Keep the default
  66. options and hit "Ok".
  67. .. image:: /img/8_Blender_UVSmart.png
  68. Now, we need to switch our view to "UV/Image editor".
  69. .. image:: /img/9_Blender_UV_editor.png
  70. Select all the vertices again ("A") then in the UV button, select
  71. "Export UV Layout".
  72. .. image:: /img/10_Blender_exportUV.png
  73. Export the layout as a PNG file. Name it "plane.png" and save it in
  74. your Godot project folder. Now, let's export our mesh as an OBJ file.
  75. Top of the screen, click "File/Export/Wavefront (obj)". Save your
  76. object as "plane.obj" in your Godot project folder.
  77. Shader magic
  78. ------------
  79. Let's now open Godot Editor.
  80. Create a new project in the folder you previously created and name it
  81. what you want.
  82. .. image:: /img/11_Godot.png
  83. In our default scene (3D), create a root node "Spatial". Next, import
  84. the mesh OBJ file. Click "Import", choose "3D Mesh" and select your
  85. plane.obj file, set the target path as "/" (or wherever you want in
  86. your project folder).
  87. .. image:: /img/12_Godot_ImportMesh.png
  88. I like to check "Normals" in the import popup so the import will also
  89. consider faces normals, which can be useful (even if we don't use them
  90. in this tutorial). Your mesh is now displayed in the FileSystem in
  91. "res://".
  92. .. image:: /img/13_Godot_ImportPopup.png
  93. Create a MeshInstance node. In the Inspector, load the mesh we just
  94. imported. Select "plane.msh" and hit ok.
  95. .. image:: /img/14_Godot_LoadMesh.png
  96. Great! Our plane is now rendered in the 3D view.
  97. .. image:: /img/15_Godot_MeshPlaneRendered.png
  98. It is time to add some shader stuff. In the Inspector, in the
  99. "Material Override" line, add a "New ShaderMaterial". Edit it by
  100. clicking the ">" button just right to it.
  101. .. image:: /img/16_Godot_ShaderMaterial.png
  102. You have two ways to create a shader: by code (MaterialShader), or
  103. using a shader graph (MaterialShaderGraph). The second one is a bit
  104. more visual, but we will not cover it for now. Create a "New
  105. MaterialShader".
  106. .. image:: /img/17_Godot_newMaterialShader.png
  107. Edit it by clicking the ">" button just right to it. The Shaders
  108. editor opens.
  109. .. image:: /img/18_Godot_ShaderEditorOpened.png
  110. The Vertex tab is for the Vertex shader, and the Fragment tab is for
  111. the Fragment shader. No need to explain what both of them do, right?
  112. If so, head to the :ref:`doc_shading_language` page. Else, let's start with the
  113. Fragment shader. This one is used to texture the plane using an image.
  114. For this example, we will texture it with the heightmap image itself,
  115. so we'll actually see mountains as brighter regions and canyons as
  116. darker regions. Use this code:
  117. ::
  118. uniform texture source;
  119. uniform color col;
  120. DIFFUSE = col.rgb * tex(source,UV).rgb;
  121. This shader is very simple (it actually comes from the :ref:`doc_shading_language` page).
  122. What it basically does is take 2 parameters that we have to provide from
  123. outside the shader ("uniform"):
  124. - the texture file
  125. - a color
  126. Then, we multiply every pixel of the image given by
  127. ``tex(source, UV).rgb`` by the color defined ``col`` and we set it to
  128. DIFFUSE variable, which is the rendered color. Remember that the
  129. ``UV`` variable is a shader variable that returns the 2D position of
  130. the pixel in the texture image, according to the vertex we are
  131. currently dealing with. That is the use of the UV Layout we made
  132. before. The color ``col`` is actually not necessary to display the
  133. texture, but it is interesting to play and see how it does, right?
  134. However, the plane is displayed black! This is because we didn't set
  135. the texture file and the color to use.
  136. .. image:: /img/19_Godot_BlackPlane.png
  137. In the Inspector, click the "Previous" button to get back to the
  138. ShaderMaterial. This is where you want to set the texture and the
  139. color. In "Source", click "Load" and select the texture file
  140. "heightmap.png". But the mesh is still black! This is because our
  141. Fragment shader multiplies each pixel value of the texture by the
  142. ``col`` parameter. However, this color is currently set to black
  143. (0,0,0), and as you know, 0\*x = 0 ;) . Just change the ``col``
  144. parameter to another color to see your texture appear:
  145. .. image:: /img/20_Godot_TexturedPlane.png
  146. Good. Now, the Vertex Shader.
  147. The Vertex Shader is the first shader to be executed by the pipeline. It
  148. deals with vertices.
  149. Click the "Vertex" tab to switch, and paste this code:
  150. ::
  151. uniform texture source;
  152. uniform float height_range;
  153. vec2 xz = SRC_VERTEX.xz;
  154. float h = tex(source, UV).g * height_range;
  155. VERTEX = vec3(xz.x, h, xz.y);
  156. VERTEX = MODELVIEW_MATRIX * VERTEX;
  157. This shader uses two "uniform" parameters. The ``source`` parameter is
  158. already set for the fragment shader. Thus, the same image will be used
  159. in this shader as the heightmap. The ``height_range`` parameter is a
  160. parameter that we will use to increase the height effect.
  161. At line 3, we save the x and z position of the SRC_VERTEX, because we
  162. do not want them to change : the plane must remain square. Remember
  163. that Y axis corresponds to the "altitude", which is the only one we
  164. want to change with the heightmap.
  165. At line 4, we compute an ``h`` variable by multiplying the pixel value
  166. at the UV position and the ``height_range``. As the heightmap is a
  167. greyscale image, all r, g and b channels contain the same value. I
  168. used ``g``, but any of r, g and b have the same effect.
  169. At line 5, we set the current vertex' position at (xz.x, h, xz.y)
  170. position. Concerning xz.y remember that its type is "vec2". Thus, its
  171. components are x and y. The y component simply contains the z position
  172. we set at line 3.
  173. Finally, at line 6, we multiply the vertex by the model/view matrix in
  174. order to set its position according to camera position. If you try to
  175. comment this line, you'll see that the mesh behaves weird as you move
  176. and rotate the camera.
  177. That's all good, but our plane remains flat. This is because the
  178. ``height_range`` value is 0. Increase this value to observe the mesh
  179. distort and take to form of the terrain we set before:
  180. .. image:: /img/21_Godot_Fini.png