5
\$\begingroup\$

While I have some experience with simple 2D games, I am new to more process-demanding 3D games. One basic question that has been concerning me recently and for which I am having difficulties to find a proper detailed answer, is the following.

I understand that when we instantiate an object, we are saving memory because the instantiated copy does not have to save mesh memory (like vertices' position, UV cood and normals). So, the instantiated copy only needs to save a transformation matrix in order to properly position, scale and rotate the mesh structure they share with the original mesh.

But can the instantiated copies have different texture or material from the original mesh from which they were instantiated? If so, then it means the instantiated objects actually save with themselves more than transformation matrices. I would love to read more on that, so suggestions are welcome.

\$\endgroup\$
  • \$\begingroup\$ what framework are you using, OpenGL, Unity, DirectX? It's not clear from your tags/question... \$\endgroup\$ – R1ck77 Nov 25 '15 at 13:22
  • 2
    \$\begingroup\$ @R1ck77 Sorry for that. It's UE4 and OpenGL. Although I would be particularly interested in learning if there is any difference in how OpenGL and DirectX handle the question I've asked. Thanks for your comment. \$\endgroup\$ – Bennton Nov 25 '15 at 13:29
  • \$\begingroup\$ no problem: just doing my civic duty (I would advise you to add the proper tags then, as they are where people will look for that piece of info ;-) ) \$\endgroup\$ – R1ck77 Nov 25 '15 at 13:36
  • \$\begingroup\$ Although the OP's question is not at all specific to OpenGL, I am not opposed to the question being edited as it was to include the tag "OpenGL". However, this question is not even remotely specific to UE4 just because the OP uses UE4. The editing that erased the tag "instancing" to include "ue4" is mistaken. It got rid of a very substantive tag to the given question, in favor a non-informative tag in what regards the given question. \$\endgroup\$ – MAnd Nov 25 '15 at 15:51
  • 1
    \$\begingroup\$ I myself don't think the changes in my tags made a lot of sense, either. \$\endgroup\$ – Bennton Nov 25 '15 at 18:09
10
\$\begingroup\$

since you admittedly don't have much experience with 3D and (presumably) OpenGL, I'll give you a "bird's eye" overview of the process.

I'll do my considerations about OpenGL, but the basic reasoning yields for other APIs too.

When you render something with a modern version of OpenGL you create objects that will reside into the GPU memory, and then mostly operate on them by reference.

Let's say you want to create a cube with a simple diffuse texture, what you will do is:

  1. load the mesh for the cube (or other object) in your program [the mesh now resides in your "main" memory and can be directly accessed by your code, and you can do C/Python/whatever stuff on it]
  2. load the previously loaded mesh into the GPU (by creating a buffer object in OpenGL, and filling it with the mesh data). After this operation, you have 2 copies of your mesh: one in the CPU's memory, and one in the GPU's.
  3. release the memory associated with the mesh data in your CPU (very loosely speaking... pass me this ;-)), keeping only a reference (nothing more than an int!) of the mesh that still resides in the GPU memory [now you cannot "touch the data directly anymore, but you can tell OpenGL/DirectX what to do]
  4. repeat steps 1. 2. and 3. for the UV (and if required normal) coordinates.

A similar sequence is involved with the texture:

  1. load the texture data, e.g. the png/jpg file [disk -> CPU memory]
  2. create and load a texture in the GPU [CPU memory -> GPU memory]
  3. release the texture memory, and use the texture by reference using the id returned to you by OpenGL [GPU].

The interesting part is that from now you can instantiate how many textures/meshes you want without spending extra memory to hold each copy.

It's not very different from what people do in 2D all the time, just with one extra layer between the CPU and the screen: in 2D graphics (e.g. a game rendered with tiles), you load an image, keep it in your CPU memory and then just "copy and paste it" on the video memory by blitting it repeatedly.

Doing 3D graphic you have an extra step, where you load the mesh/texture/whatever in the GPU and get a pointer of sorts for them as a "receipt", before being able to render anything.

About the details of your question:

While I have some experience with simple 2D games, I am new to more > process-demanding 3D games.

OpenGL/DirectX and other 3D frameworks are quite often used for 2D games too, and as soon as you get a good grasp of them you'll see why :)

I understand that when we instantiate an object, we are saving memory because the instantiated copy does not have to save mesh memory (like vertices' position, UV cood and normals). So, the instantiated copy only needs to save a transformation matrix in order to properly position, scale and rotate the mesh structure they share with the original mesh.

100% true.

But can the instantiated copies have different texture or material from the original mesh from which they were instantiated?

Yes! Unity (and most likely UE) treats the data in a very granular way and allows:

  • the same model to be instantiated with different materials
  • the same material to be used on different models
  • the same texture to be used on different materials
  • etc...

and it does this, to mimic the actual memory layout in the GPUs: the "instantiated objects" are just very complex, very high level constructs based on the same basic bricks used by the GPU to store information, bricks which get used and reused as much as possible to limit memory consumption/transfer (and improve performances).

Even a material, for instance, is not a "basic object", in the sense that is actually an OpenGL shader coupled with some textures and other additional data, providing opportunities for more memory/performances optimization.

Therefore, when you instantiate 100 objects using the same model (same geometry), with 100 different 3D transforms (each object will be at a distinct position, and will likely have a unique orientation and scale) and one of two materials (i.e. red and blue, which is a realistic example for red/blue tanks in a "Risk!" game), you are actually using:

  • a single shader
  • a single copy of the same 3D model (vertices, normal, UV) as 3 buffer objects (arrays of data in the GPU...)
  • 100 different modelview matrices (one for each tank).
  • two textures

this is a very quick and cursory account, mind you, but it's still reasonably accurate, and yields for low level APIs, like OpenGL/DirectX and for "complex" frameworks/editors like Unity and UE (basically because the hardware they are running on, the GPU, is the same in both cases, and this leads to the existence of what can be seen as a loosely "right way" to program it).

Hope this helps!

\$\endgroup\$
  • \$\begingroup\$ Many thanks for that very detailed answer. That's exactly the kind of conceptual explanation I've been seeking for. Great answer, I would upvote more times if I could. \$\endgroup\$ – Bennton Nov 25 '15 at 18:07
  • \$\begingroup\$ Glad you liked it: you are most welcome! :) \$\endgroup\$ – R1ck77 Nov 25 '15 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.