YouTube2Text

Traveling Trees - Explaining My Multimesh Instancer / Godot 4 Tutorial — Transcript

by devmar · 2,691 words · 373 segments · language en · Watch on YouTube

Full transcript

  1. 0:00hello YouTube Welcome Back to the
  2. 0:01channel it's nice to see some new faces
  3. 0:03here I appreciate each and every one of
  4. 0:05you today's video we'll be delving into
  5. 0:07the mechanics of my traveling multi mesh
  6. 0:09instancer which is a tool for creating
  7. 0:11vast immersive forests mostly where the
  8. 0:14trees follow the player around the map
  9. 0:17uh similar to my grass system except
  10. 0:19this one comes with Collision support
  11. 0:20and of course LOD optimization uh if
  12. 0:24you've recently subscribed thank you I
  13. 0:25appreciate it if you haven't yet please
  14. 0:27consider doing so all right let's Dive
  15. 0:29Right In um the main premise of the
  16. 0:31insten there is that the trees are
  17. 0:33spawned at randomized x and z positions
  18. 0:36with the Y position being driven by your
  19. 0:38hyp mob data so it's much more optimal
  20. 0:41than using Ray casts also it doesn't
  21. 0:44require your terrain to even have a
  22. 0:45glider at all we first instance the
  23. 0:47trees into the world and then as you
  24. 0:49move around the meshes get repositioned
  25. 0:51such that they're always around you but
  26. 0:53snapped into position and stationary now
  27. 0:55before I deep dive into the code uh let
  28. 0:57me demonstrate how this thing works
  29. 0:59observe first uh we're going to drop in
  30. 1:02the height mop texture which I have
  31. 1:04already done and set the height to nine
  32. 1:06because that is the height that I have
  33. 1:07in my terrain Shader uh next let's drop
  34. 1:10in the player node this is the node that
  35. 1:13the instancer will follow we'll set the
  36. 1:15instance count to something notable
  37. 1:17let's say 100 trees ground chunk mesh is
  38. 1:20only needed for scale data uh if your
  39. 1:22ground mesh is scaled uh the script will
  40. 1:25grab the scale off of here and apply it
  41. 1:27to the high map texture and that way we
  42. 1:28can make sure that this size of your hyp
  43. 1:30map texture matches the size of your
  44. 1:32terrain uh let's leave everything else
  45. 1:34at default and uh drop in a tree mesh uh
  46. 1:37control s reload the scene and here they
  47. 1:40are now let's increase the spacing to
  48. 1:42say 30 uh crank out position Randomness
  49. 1:46set the minimum scale to something
  50. 1:47really low and increase scale Randomness
  51. 1:50we can also scale the height and width
  52. 1:52overall like so and uh we can rotate the
  53. 1:55instances on all three axis but what we
  54. 1:57really want to do is randomize the
  55. 2:00rotation especially on the Y AIS
  56. 2:02although you can also randomize on x and
  57. 2:04z which is kind of cool next let's
  58. 2:05switch on generate colliders uh increase
  59. 2:08the coverage radius to say 100 uh this
  60. 2:10is the radius of the area surrounding
  61. 2:12the player where trees will have
  62. 2:14collisions and um create a collision
  63. 2:17shape down here I'm going to go with a
  64. 2:19box shape uh and I'm also going to make
  65. 2:21it bigger so that you can actually see
  66. 2:23it and now let's run the scene and
  67. 2:25hopefully you guys can see the colliders
  68. 2:27moving with the trees this is the same
  69. 2:29set of colliders throughout they just
  70. 2:31get repositioned on every update now why
  71. 2:34would I use multi over GPU particles I
  72. 2:36hear you ask well as of G 4.2 particle
  73. 2:39shaders don't expose the transform data
  74. 2:42of each particle you can't tell GD
  75. 2:45script where the individual particles
  76. 2:47are in the world which means that you
  77. 2:49can't uh give them colliders either now
  78. 2:51multi meeses also use Hardware
  79. 2:53acceleration for rendering but the
  80. 2:55transforms of the instances are actually
  81. 2:57handled by the CPU and that allows you
  82. 3:00full set get access to them so that's
  83. 3:02why now let's look at the code first we
  84. 3:04sample the scale of the ground mesh
  85. 3:07we'll use this to ensure that our height
  86. 3:09map image matches the scale of our
  87. 3:11terrain mesh then we create the multi
  88. 3:13mesh instance 3D resource uh we set it
  89. 3:16as top level because we only want it to
  90. 3:18update its position when we tell it to
  91. 3:20uh then we create a new multi mesh uh
  92. 3:22Define its format as 3D we set the
  93. 3:25instance amount and mesh these are both
  94. 3:27export variables so we can set them in
  95. 3:29the inspector instance rows is a square
  96. 3:31root of our instance amount I will it
  97. 3:34will get rounded down to the nearest
  98. 3:36integer because the variable is declared
  99. 3:38as an integer offset is instance amount
  100. 3:40divided by the number of rows and it's
  101. 3:42rounded up or down uh to the nearest
  102. 3:45integer generally the reason for
  103. 3:47rounding values in this script is to
  104. 3:48avoid floating Point Precision errors
  105. 3:50which would cause your trees to ditter
  106. 3:53hyp map also an export variable is a 2d
  107. 3:55texture it has to be the same one that
  108. 3:57you're using for your terrain
  109. 3:59displacement in fact in my
  110. 4:00implementation of this technique I grab
  111. 4:02the height map directly from the vertex
  112. 4:04Shader that does the ground displacement
  113. 4:06this weight here is crucial uh you must
  114. 4:09wait for the texture to load up
  115. 4:11otherwise the code would continue to run
  116. 4:13and you would have no pixel data and
  117. 4:14you'd get errors once the texture is
  118. 4:16loaded we're going to grab the noise
  119. 4:18image from it and also get its height
  120. 4:20and width and save them into the height
  121. 4:22and width variables because we'll need
  122. 4:24that data later this script is attached
  123. 4:26to a 3D node in my case it's a marker 3D
  124. 4:29but you can use anything that inherits
  125. 4:31from node 3D so attach the multim mesh
  126. 4:33to my 3D node then we create a timer for
  127. 4:36our updates we connect its timeout
  128. 4:38signal to the update function and we can
  129. 4:41set the interval between updates mine is
  130. 4:43set to update every half a second uh
  131. 4:45this really depends on how fast your
  132. 4:47player is moving for me I don't need to
  133. 4:49update more frequently than that and
  134. 4:50then we call the first update where we
  135. 4:52basically say snap my instance or
  136. 4:54position to that of the player again
  137. 4:56it's a snapped Vector to avoid any
  138. 4:58Precision issues and distribute the
  139. 5:00meshes and restart the timer inside
  140. 5:03distribute meshes we're going to iterate
  141. 5:05through our instance count to set the
  142. 5:07desired transform of each instance first
  143. 5:10we set the Z position to be the index of
  144. 5:12the instance then this line assigns a
  145. 5:14new value to the X component of the
  146. 5:16position Vector uh it takes the value of
  147. 5:18position Z and finds the remainder when
  148. 5:21divided by the number of rows the
  149. 5:23percentage operator also known as modulo
  150. 5:25calculates the remainder of the division
  151. 5:28and this line calculates a new value for
  152. 5:30the Z component of the position Vector
  153. 5:32taking the difference between the
  154. 5:34original position Z and the newly
  155. 5:36calculated position X and dividing this
  156. 5:38Difference by the number of rows well in
  157. 5:40simple terms this snippet of code takes
  158. 5:43the overall instance count which you set
  159. 5:45and divides it by the number of rows and
  160. 5:47builds a square patch out of them like a
  161. 5:50square shaped cluster of trees in our
  162. 5:52case why because the number of rows is
  163. 5:54always a square root of the instance
  164. 5:56count next we're going to uh Center our
  165. 5:59patch meaning that the patch moves by a
  166. 6:01measurement that is equal to a half of
  167. 6:03its side on both axis and now the
  168. 6:05instancer is in the middle of the patch
  169. 6:07more or less in the middle in most cases
  170. 6:09it won't be exactly in the middle
  171. 6:10because again we're using snapped
  172. 6:12vectors then we position our instance we
  173. 6:14multiply it start position by the
  174. 6:16spacing parameter and to it we add the
  175. 6:19difference between the instancer nodes
  176. 6:21Global position on the x-axis and the
  177. 6:23remainder of the division of global
  178. 6:25position X by instance spacing which is
  179. 6:27our spacing parameter and we also do the
  180. 6:29same for the Z component of the global
  181. 6:31position and these two lines are really
  182. 6:33the core of this technique because they
  183. 6:35allow the redistribution of uh x and z
  184. 6:38positions of each instance relative to
  185. 6:40the global position of the instance or
  186. 6:42node next we're going to add some
  187. 6:43Randomness to the position pause
  188. 6:45randomize is the export variable which
  189. 6:48sets the amount of x and z Randomness
  190. 6:50that we want to add to each transform
  191. 6:52this random function simply generates a
  192. 6:54pseudo random around a certain given
  193. 6:56pair of coordinates this is a direct
  194. 6:58translation from a noise generating
  195. 7:00Shader there's no point getting into the
  196. 7:02math of this we first added on one axis
  197. 7:04then subtract on the other axis
  198. 7:06otherwise the Z Randomness would get
  199. 7:08added on top of the X Randomness causing
  200. 7:11the instances to be pushed diagonally in
  201. 7:14the same direction so this determines
  202. 7:15the x and z positions of our instance we
  203. 7:18can now safely pass this data to our x
  204. 7:21and z variables and now we're ready to
  205. 7:23sample the height map to determine the Y
  206. 7:25position so the elevation of our
  207. 7:27instance for that we're going to call
  208. 7:29this function Get Hype up y for each
  209. 7:31pair of x and z and it will return the Y
  210. 7:34component inside this function we're
  211. 7:35going to get the coordinates of the
  212. 7:37pixel that we want to sample these first
  213. 7:40two lines will offset the pixel
  214. 7:41coordinates to allow us to sample the
  215. 7:43correct pixel why because the global
  216. 7:45position of a player is relative to the
  217. 7:47uh world origin whereas the image that
  218. 7:50we're sampling is positioned in the same
  219. 7:52way any other 2D texture wood in gdo and
  220. 7:54that is starting from the top left
  221. 7:56corner and stretching down towards
  222. 7:58bottom right so if a tree is here its x
  223. 8:01and z would be say 20 and 20 but the
  224. 8:04relevant pixel to sample is not here
  225. 8:06it's actually down here somewhere so
  226. 8:08this code snippet moves the reference
  227. 8:10point to the center of the image and
  228. 8:12ensures that we get that right then
  229. 8:14these four conditionals allow the
  230. 8:15instancer to continue indefinitely on
  231. 8:18both x and z axis even when you're
  232. 8:20outside of the image bounds because it
  233. 8:22just pushes you back to where the pixels
  234. 8:24can be found finally we get the pixel
  235. 8:26color uh the hot mup is a grayscale
  236. 8:28noise image as you know so it doesn't
  237. 8:30matter which color Channel you sample
  238. 8:32we're sampling red here but green or
  239. 8:35blue would return the same value then we
  240. 8:37just multiply that by the height of our
  241. 8:39terrain and also by vertical scale
  242. 8:41although this is only relevant when your
  243. 8:43ground mesh is also vertically scaled H
  244. 8:46scale and V scale are taken from the
  245. 8:48scale of your ground mesh so if it's not
  246. 8:50scaled then it'll just be one and does
  247. 8:52have no effect on this equation okay so
  248. 8:54now we have the full origin of our
  249. 8:56transform so we can save it into a
  250. 8:58variable next let's let tackle scaling
  251. 9:00uh we have a few parameters here if you
  252. 9:02recall we have minimum scale instance
  253. 9:04width instance height and scale
  254. 9:07Randomness all of these parameters are
  255. 9:09export variables so we can just read
  256. 9:11them from the inspector and save into
  257. 9:13the uh SC uh variable here which is also
  258. 9:16a vector 3 next we have instance
  259. 9:18rotation the base rotation is no
  260. 9:20rotation and then we read the rotation
  261. 9:22parameter from the inspector on all
  262. 9:24three axis and save those combined
  263. 9:26rotations into a vector 3 variable
  264. 9:28called rot so now we can finally create
  265. 9:30our final transform 3D we call it t uh
  266. 9:33we set its origin to the origin we set
  267. 9:36its rotation basis all three of them uh
  268. 9:38to our Vector components which
  269. 9:41effectively rotates the transform and
  270. 9:43finally we set the transform of this
  271. 9:45instance to T scaled by our scale factor
  272. 9:48instance scaling and rotations must be
  273. 9:51applied locally otherwise they'd be
  274. 9:53applied relative to the world origin as
  275. 9:55opposed to the instance okay so this
  276. 9:57takes care of the mult mishes but we
  277. 9:59also want our trees to have collisions
  278. 10:01which is kind of important especially
  279. 10:03for trees we will initiate the creation
  280. 10:05of colliders also in dysfunction that's
  281. 10:07why I have this Boolean here for first
  282. 10:10update we only want to spawn colliders
  283. 10:12once and afterwards we just reposition
  284. 10:14them as we move around so if this is the
  285. 10:17first time we run this update we'll
  286. 10:19generate a subset of trees which we want
  287. 10:21to have colliders I'm doing this because
  288. 10:23I don't need all trees to have gliders I
  289. 10:26only want those trees which I'm likely
  290. 10:27to interact with to have colliders so
  291. 10:30we'll run through the instance
  292. 10:31transforms uh and check the distance
  293. 10:33from the player to the instance and if
  294. 10:35it's within a certain distance which is
  295. 10:37also a parameter as you remember will
  296. 10:39append it to this array here called
  297. 10:41colliders to spawn and uh once we run
  298. 10:44through all instances we call spawn
  299. 10:46colliders where we will first uh create
  300. 10:49a static body to serve as a parent for
  301. 10:51the Collision shapes we will set it as
  302. 10:53top level because we don't want it to
  303. 10:54move we want it and its children to be
  304. 10:56stationary and we will position them on
  305. 10:59on each update we pass in the Collision
  306. 11:01shape instance Collision is another
  307. 11:03export variable of the type shape 3D
  308. 11:05which you can use to create the shape in
  309. 11:07the inspector here we have another array
  310. 11:09called colliders um which will store our
  311. 11:12colliders we run through the instance
  312. 11:14amount and for all index numbers that
  313. 11:17have a matching number inside the
  314. 11:19colliders to spawn array we will create
  315. 11:21a collision shape resource uh and add it
  316. 11:24as a child of the static body and set
  317. 11:25its shape to be the shape that we
  318. 11:27selected for it in the inspector
  319. 11:29otherwise we append a null because we
  320. 11:31need the array of colliders to have the
  321. 11:33same number of items as our instance
  322. 11:35count so now if we go back to the
  323. 11:37function distribute meshes uh you'll see
  324. 11:39that if this is the first update we
  325. 11:41generate the colliders and on all
  326. 11:43subsequent updates we find the right
  327. 11:46collider for this instance by looking up
  328. 11:48its index inside the collider array and
  329. 11:50then set the transform of the collider
  330. 11:52to be the same as this instance and that
  331. 11:54is pretty much it for LOD uh I have a
  332. 11:57script that builds a grid of vector
  333. 11:59three positions and for each grid point
  334. 12:01I spawn a cluster of trees as shown
  335. 12:03above and because they're separate multi
  336. 12:06mesh instance 3D nodes you can benefit
  337. 12:09from thrust and calling H and you can
  338. 12:10also pass in different meshes like
  339. 12:12simpler meshes for the lods that are
  340. 12:15further away so here for example I have
  341. 12:17three meshes for my tree with a
  342. 12:19descending level of detail and I use
  343. 12:21them in my grid uh I made these in a
  344. 12:24matter of minutes in blender you have
  345. 12:25this add-on called sapling tree gem uh
  346. 12:28which you need to enable in preferences
  347. 12:30and then just shift a uh go to curve and
  348. 12:32scroll all the way down for treen and
  349. 12:35you have a bunch of settings and some
  350. 12:36cool presets allowing you to create cool
  351. 12:39trees in seconds and that's exactly what
  352. 12:41I did and then I decimated them via a
  353. 12:43modifier to build those lower poly uh
  354. 12:46versions if you don't feel like writing
  355. 12:47a script to create the chunks you can
  356. 12:50literally just duplicate the instancer
  357. 12:52node several times and just lay them out
  358. 12:54manually it'll be the same thing just
  359. 12:55make sure that they have a shared parent
  360. 12:57and this my dear friends is it for today
  361. 12:59I realized that explaining code is not
  362. 13:02very entertaining usually but I thought
  363. 13:04that people especially people new to Gau
  364. 13:06may get some value out of this with that
  365. 13:08being said let me know in the comments
  366. 13:09if you think this kind of tutorial esque
  367. 13:12uh content is useful or I should just
  368. 13:14keep it at a higher level subscribe to
  369. 13:16the channel if you haven't follow me on
  370. 13:17X for more regular updates and I will
  371. 13:20see you shortly
  372. 13:22[Music]
  373. 13:27ciaoo

About this transcript

This page contains the full transcript of Traveling Trees - Explaining My Multimesh Instancer / Godot 4 Tutorial by devmar, generated from the public captions YouTube serves with the video. The transcript has 2,691 words across 373 segments, with the original timestamps preserved so you can click any line to jump to that moment in the embedded player.

What you can do with it

Use the transcript to take notes, quote the speaker, build a study guide, generate a summary with ChatGPT or Claude via the YouTube Summary tool, or export it as a timed subtitle file with YouTube to SRT. You can also re-open it in the transcriber to choose a caption track available on the video.

Free YouTube transcript tool

YouTube2Text is a free YouTube transcript generator — no signup, no daily limit. Paste any YouTube link and get the full transcript instantly, with timestamps, click-to-jump, caption language selection, AI prompts for ChatGPT, Claude, and Gemini, and exports to TXT, SRT, VTT, or Markdown.