You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: chapter-20/chapter-20.md
+86-42Lines changed: 86 additions & 42 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -670,17 +670,24 @@ The main changes are related to the way we access material information and textu
670
670
Now it is the turn to examine the changes in the `SceneRender` class. We will start by defining a set of constants that will be used in the code, one handle for the buffer that will have the indirect drawing instructions (`staticRenderBufferHandle`) and the number of drawing commands (`staticDrawCount`). We will need also to modify the `createUniforms` method according to the changes in the shaders shown before:
@@ -713,10 +720,10 @@ public class RenderBuffers {
713
720
}
714
721
```
715
722
716
-
The main changes are in the `render` method, which is defined like this:
723
+
The `entitiesIdxMap` will store the position in the list of entities associated to a model which each entity is located. We store that information in a `Map` using entity identifier as key. We will need this info later on since, the indirect drawing commands will be recorded iterating over meshes associated to each model. The main changes are in the `render` method, which is defined like this:
@@ -764,42 +784,21 @@ public class RenderBuffers {
764
784
}
765
785
```
766
786
767
-
You can see that we now have to bind the array of texture samplers and activate all the texture units. In addition to that, we iterate over the entities and set up the uniform values for the model matrices. After that, we call the `glMultiDrawElementsIndirect` function to perform the indirect drawing. Prior to that, we need to bind the buffers that hold drawing instructions (drawing commands) and the VAO that holds the meshes and indices data. But, when do we populate the buffer for indirect drawing=? The answer is that this not need to be performed each render call, if there are no changes in the number of entities, you can record that buffer once, and use it in each render call. In this specific example, we will just populate that buffer at start-up. This means, that, if you want to make changes in the number of entities, you would nee to re-create that buffer again (you should do that for your own engine).
787
+
You can see that we now have to bind the array of texture samplers and activate all the texture units. In addition to that, we iterate over the entities and set up the uniform values for the model matrices. The next step is to setup the `drawElements` array uniform withe the proper values for each of the entities that will point to the index of the model matrix and the material index. After that, we call the `glMultiDrawElementsIndirect` function to perform the indirect drawing. Prior to that, we need to bind the buffers that hold drawing instructions (drawing commands) and the VAO that holds the meshes and indices data. But, when do we populate the buffer for indirect drawing? The answer is that this not need to be performed each render call, if there are no changes in the number of entities, you can record that buffer once, and use it in each render call. In this specific example, we will just populate that buffer at start-up. This means, that, if you want to make changes in the number of entities, you would nee to re-create that buffer again (you should do that for your own engine).
768
788
769
-
The method that actually builds the indirect draw buffer is called `setupStaticCommandBuffer`and starts like this:
789
+
The method that actually builds the indirect draw buffer is called `setupStaticCommandBuffer`which is defined like this:
for (Model model : scene.getModelMap().values()) {
779
-
List<Entity> entities = model.getEntitiesList();
796
+
for (Model model : modelList) {
780
797
numMeshes += model.getMeshDrawDataList().size();
781
-
for (Entity entity : entities) {
782
-
entitiesIdxMap.put(entity.getId(), entityIdx);
783
-
entityIdx++;
784
-
}
785
798
}
786
-
...
787
-
}
788
-
...
789
-
}
790
-
```
791
-
792
-
We firs start by iterating over the models to get the position in the list of entity instances each instance is. We store that information in a `Map`` using entity identifier as key. We will need this info later on since, the indirect drawing commands will be recorded iterating over meshes associated to each model. In addition to that, we calculate the total number of meshes. After that, we will create the buffer that wil hold indirect drawing instructions and populate it:
@@ -839,13 +831,13 @@ public class RenderBuffers {
839
831
}
840
832
```
841
833
842
-
As you can see we firs allocate a `ByteBuffer`. This buffer will hold as many instruction sets as meshes. Each set of draw instructions si composed by five attributes, ech of the with a length of 4 bytes (total length of each set of parameters is what defines the `COMMAND_SIZE` constant). We cannot allocate this buffer using `MemoryStack` since we will run out of space quickly (the stack that LWJGL uses for this is limited in size). Therefore, we need to allocate it using `MemoryUtil` and remember to manually de-allocate that once we are done. Once we have the buffer we start iterating over the meshes associated to the model. You may have a look at the beginning of this chapter to check
834
+
We first calculate the total number of meshes. After that, we will create the buffer that wil hold indirect drawing instructions and populate it. As you can see we first allocate a `ByteBuffer`. This buffer will hold as many instruction sets as meshes. Each set of draw instructions si composed by five attributes, each of them with a length of 4 bytes (total length of each set of parameters is what defines the `COMMAND_SIZE` constant). We cannot allocate this buffer using `MemoryStack` since we will run out of space quickly (the stack that LWJGL uses for this is limited in size). Therefore, we need to allocate it using `MemoryUtil` and remember to manually de-allocate that once we are done. Once we have the buffer we start iterating over the meshes associated to the model. You may have a look at the beginning of this chapter to check
843
835
the struct that draw indirect requires. In addition to that, we also populate the `drawElements` uniform using the `Map` we calculated previously, to properly get the model matrix index for each entity. Finally, we just create a GPU buffer and dump the data into it.
844
836
845
837
We will need to update the `cleanup` method to free the indirect drawing buffer:
846
838
847
839
```java
848
-
publicclassRenderBuffers {
840
+
publicclassSceneRender {
849
841
...
850
842
publicvoidcleanup() {
851
843
shaderProgram.cleanup();
@@ -858,7 +850,7 @@ public class RenderBuffers {
858
850
We will need a new method to the set up the values for the materials uniform:
@@ -898,12 +890,32 @@ public class RenderBuffers {
898
890
899
891
We just check that we are not surpassing the maximum number of supported textures (`MAX_TEXTURES`) and just create an array of materials information with the information we used in the previous chapters. The only change is that we will need to store the index of the associated texture and normal maps in the material information.
900
892
893
+
We need another method to update the entities indices map:
894
+
```java
895
+
publicclassSceneRender {
896
+
...
897
+
privatevoidsetupEntitiesData(Scenescene) {
898
+
entitiesIdxMap.clear();
899
+
int entityIdx =0;
900
+
for (Model model : scene.getModelMap().values()) {
901
+
List<Entity> entities = model.getEntitiesList();
902
+
for (Entity entity : entities) {
903
+
entitiesIdxMap.put(entity.getId(), entityIdx);
904
+
entityIdx++;
905
+
}
906
+
}
907
+
}
908
+
...
909
+
}
910
+
```
911
+
901
912
To complete the changes in the `SceneRender` class, we will create a method that wraps the `setupXX` so it can be invoked from the `Render` class:
Changes in `ShadowRender` are also pretty similar as the ones in the `ScenRender` class:
960
+
Changes in `ShadowRender` are also pretty similar as the ones in the `SceneRender` class:
949
961
950
962
```java
951
963
publicclassShadowRender {
952
964
953
965
privatestaticfinalintCOMMAND_SIZE=5*4;
954
966
...
967
+
privateMap<String, Integer> entitiesIdxMap;
968
+
...
955
969
privateint staticRenderBufferHandle;
956
970
...
971
+
publicShadowRender() {
972
+
...
973
+
entitiesIdxMap =newHashMap<>();
974
+
}
975
+
957
976
publicvoidcleanup() {
958
977
shaderProgram.cleanup();
959
978
shadowBuffer.cleanup();
@@ -975,7 +994,7 @@ public class ShadowRender {
975
994
}
976
995
```
977
996
978
-
The `createUniforms` method needs to be update to use the new uniforms and the `cleanup` one needs to free the indirect draw buffer. The `render`methdod will use now the `glMultiDrawElementsIndirect`instead of submitting individal draw commands for meshes and entities:
997
+
The `createUniforms` method needs to be update to use the new uniforms and the `cleanup` one needs to free the indirect draw buffer. The `render`method will use now the `glMultiDrawElementsIndirect`instead of submitting individual draw commands for meshes and entities:
979
998
980
999
```java
981
1000
publicclassShadowRender {
@@ -1003,6 +1022,18 @@ public class ShadowRender {
0 commit comments