We use essential cookies for the website to function, as well as analytics cookies for analyzing and creating statistics of the website performance. To agree to the use of analytics cookies, click "Accept All". You can manage your preferences at any time by clicking "Cookie Settings" on the footer. More Information.

Only Essential Cookies
Accept All
GuidesScene KitDeveloping Your AppGood Culling (Object Occlusion and Culling Plugin)

Good Culling (Object Occlusion and Culling Plugin)

Content overview

This plugin can quickly calculate occlusions for 3D models. Based on the result, you can set not to draw the occluded models, improving the rendering performance. Good Culling is applicable to scenarios with complex occlusions, for example, scenarios with large amounts of vegetation and particle animations.

To calculate occlusion for 3D models, you only need to mark the models as occluders and occludees and then enter the vertex data and bounding box data of them.

Development Procedure

  1. Download the Good Culling package and decompress it to obtain the library file.
  2. Integrate the library file libCoreCulling.so and header file GoodCulling.h using a build tool such as CMake.
    Collapse
    Word wrap
    Dark theme
    Copy code
    1. cmake_minimum_required(VERSION 3.4.1)
    2. set(CMAKE_CXX_STANDARD 17)
    3. set(CMAKE_CXX_STANDARD_REQUIRED ON)
    4. include_directories(src/main/cpp/include)
    5. link_directories(src/main/jniLibs/arm64-v8a)
    6. add_library(native-lib # Sets the name of the library.
    7. SHARED # Set the library as a shared library.
    8. src/main/cpp/goodculling-demo.cpp
    9. )
    10. find_library( # Sets the name of the path variable.
    11. log-lib
    12. log
    13. )
    14. # Specify the libraries CMake should link to your target library. You
    15. # can link multiple libraries, such as the libraries you have defined in the
    16. # build script, pre-built third-party libraries, or system libraries.
    17. target_link_libraries( # Specify the target library.
    18. native-lib
    19. android
    20. ${log-lib}
    21. # Link the target library to the log library.
    22. libc++_shared.so
    23. libCoreCulling.so
    24. )
    NOTE

    Create the jniLibs directory in the project's root directory, place the libCoreCulling.so file in the jniLibs directory, and compile the goodculling-demo file.

  3. Create a culling instance, and add the vertex data and bounding box data of the occluder and occludee models.
    Collapse
    Word wrap
    Dark theme
    Copy code
    1. #include <stdlib.h>
    2. #include <iostream>
    3. #include <vector>
    4. #include <android/log.h>
    5. #include "include/goodculling.h"
    6. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "GoodCulling", __VA_ARGS__))
    7. #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "GoodCulling", __VA_ARGS__))
    8. #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "GoodCulling", __VA_ARGS__))
    9. #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "GoodCulling", __VA_ARGS__))
    10. using MeshData = OccluderData;
    11. struct Vec3 {
    12. Vec3() {}
    13. Vec3(float x1, float y1, float z1) : x(x1), y(y1), z(z1) {}
    14. ~Vec3() {}
    15. float x = 0.0f;
    16. float y = 0.0f;
    17. float z = 0.0f;
    18. };
    19. struct Object {
    20. int id = 0;
    21. int meshId = 0;
    22. MeshData meshData;
    23. Vec3 minBox;
    24. Vec3 maxBox;
    25. bool updateTranFlag = true;
    26. std::vector<float> transformMatrix;
    27. Vec3 position;
    28. Vec3 rotation;
    29. Vec3 scale;
    30. };
    31. int goodcullingId = 0;
    32. // Prepare view matrix.
    33. std::vector<float> viewMatrix = { 1.0f, 0.0f, 0.0f, 0.0f,
    34. 0.0f, 1.0f, 0.0f, 0.0f,
    35. 0.0f, 0.0f, -1.0f, 0.0f,
    36. 0.0f, -1.0f, -10.0f, 1.0f };
    37. // Prepare projection matrix.
    38. std::vector<float> projMatrix = { 0.3226795f, 0.0f, 0.0f, 0.0f,
    39. 0.0f, 1.732051f, 0.0f, 0.0f,
    40. 0.0f, 0.0f, -1.0006f, -1.0f,
    41. 0.0f, 0.0f, -0.60018f, 0.0f };
    42. const unsigned int VERTEX_DIMENSION_CNT = 3; // Each vertex contains three coordinates, for the X, Y, and Z axes respectively.
    43. std::vector<Object> senceObjArray;
    44. float* GetBoundingBox(Vec3 box)
    45. {
    46. std::vector<float> result = {box.x, box.y, box.z};
    47. return &result[0];
    48. }
    49. void CreateSence()
    50. {
    51. Object object_0;
    52. Object object_1;
    53. Object object_2;
    54. Object object_3;
    55. // Prepare mesh data.
    56. MeshData meshData;
    57. // Prepare vertex data.
    58. std::vector<float> vtxData = { 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f,
    59. 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f,
    60. 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, -0.5f,
    61. -0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
    62. 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
    63. -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f };
    64. meshData.vtxData = static_cast<void*>(vtxData.data());
    65. meshData.vtxStride = sizeof(float) * VERTEX_DIMENSION_CNT;
    66. meshData.vtxOffset = 0;
    67. meshData.vtxCount = static_cast<unsigned int>(vtxData.size()) / VERTEX_DIMENSION_CNT;
    68. // Prepare index data.
    69. std::vector<unsigned int> idxData = { 0, 2, 3, 0, 3, 1, 8, 4, 5, 8, 5, 9, 10, 6, 7, 10, 7, 11, 12, 13,
    70. 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 };
    71. meshData.idxData = static_cast<void*>(idxData.data());
    72. meshData.type = UINT_TYPE;
    73. meshData.indCount = static_cast<unsigned int>(idxData.size());
    74. // Prepare bounding box data in the format of {minX, minY, minZ, maxX, maxY, maxZ}.
    75. std::vector<float> boundBox = { -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
    76. meshData.boundBox = static_cast<void*>(boundBox.data());
    77. // Create object_0.
    78. bool occluderUpdateTranFlag = true;
    79. std::vector<float> occluderTransformMatrix = { 2.5f, 0.0f, 0.0f, 0.0f,
    80. 0.0f, 2.5f, 0.0f, 0.0f,
    81. 0.0f, 0.0f, 2.5f, 0.0f,
    82. -4.0f, 0.0f, 7.0f, 1.0f };
    83. object_0.id = 0;
    84. object_0.meshId = 0;
    85. object_0.meshData = meshData;
    86. object_0.updateTranFlag = occluderUpdateTranFlag;
    87. object_0.transformMatrix = occluderTransformMatrix;
    88. object_0.position = Vec3( -4.0f, 0.0f, 7.0f );
    89. object_0.rotation = Vec3( 0.0f, 0.0f, 0.0f );
    90. object_0.scale = Vec3( 2.5f, 2.5f, 2.5f );
    91. senceObjArray.push_back(object_0);
    92. // Create object_1.
    93. Vec3 minBox_oc0(-0.5f, -0.5f, -0.5f);
    94. Vec3 maxBox_oc0(0.5f, 0.5f, 0.5f);
    95. bool TranFlag_oc0 = true;
    96. std::vector<float> TransformMatrix_oc0 = { 0.72589f, 0.0f, 0.0f, 0.0f,
    97. 0.0f, 10.2f, 0.0f, 0.0f,
    98. 0.0f, 0.0f, 0.46233f, 0.0f,
    99. -4.5f, 0.76f, 12.0f, 1.0f };
    100. object_1.id = 1;
    101. object_1.meshId = 1;
    102. object_1.meshData = meshData;
    103. object_1.minBox = minBox_oc0;
    104. object_1.maxBox = maxBox_oc0;
    105. object_1.updateTranFlag = TranFlag_oc0;
    106. object_1.transformMatrix = TransformMatrix_oc0;
    107. object_1.position = Vec3( -4.5f, 0.76f, 12.0f );
    108. object_1.rotation = Vec3( 0.0f, 0.0f, 0.0f );
    109. object_1.scale = Vec3( 0.72589f, 10.2f, 0.46233f );
    110. senceObjArray.push_back(object_1);
    111. // Create object_2.
    112. Vec3 minBox_oc1(-0.5f, -0.5f, -0.5f);
    113. Vec3 maxBox_oc1(0.5f, 0.5f, 0.5f);
    114. bool TranFlag_oc1 = true;
    115. std::vector<float> TransformMatrix_oc1 = { 0.7257298f, 0.0f, -0.01520186f, 0.0f,
    116. 0.0003874408f, 3.53327f, 0.01849625f, 0.0f,
    117. 0.009682182f, -0.002420745f, 0.4622231f, 0.0f,
    118. -0.5299997f, 0.0f, 4.079999f, 1.0f };
    119. object_2.id = 2;
    120. object_2.meshId = 2;
    121. object_2.meshData = meshData;
    122. object_2.minBox = minBox_oc1;
    123. object_2.maxBox = maxBox_oc1;
    124. object_2.updateTranFlag = TranFlag_oc1;
    125. object_2.transformMatrix = TransformMatrix_oc1;
    126. object_2.position = Vec3( -0.5299997f, 0.0f, 4.079999f );
    127. object_2.rotation = Vec3( 0.2999997f, 1.199999f, 0.0f );
    128. object_2.scale = Vec3( 0.725889f, 3.533318f, 0.4623308f );
    129. senceObjArray.push_back(object_2);
    130. // Create object_3.
    131. Vec3 minBox_oc2(-0.5f, -0.5f, -0.5f);
    132. Vec3 maxBox_oc2(0.5f, 0.5f, 0.5f);
    133. bool TranFlag_oc2 = true;
    134. std::vector<float> TransformMatrix_oc2 = { 0.5122236f, 0.0f, 0.0f, 0.0f,
    135. 0.0f, 1.428458f, 0.0f, 0.0f,
    136. 0.0f, 0.0f, 0.3524071f, 0.0f,
    137. -5.32f, -0.84f, 9.0f, 1.0f };
    138. object_3.id = 3;
    139. object_3.meshId = 3;
    140. object_3.meshData = meshData;
    141. object_3.minBox = minBox_oc2;
    142. object_3.maxBox = maxBox_oc2;
    143. object_3.updateTranFlag = TranFlag_oc2;
    144. object_3.transformMatrix = TransformMatrix_oc2;
    145. object_3.position = Vec3( -5.32f, -0.84f, 9.0f );
    146. object_3.rotation = Vec3( 0.0f, 0.0f, 0.0f );
    147. object_3.scale = Vec3( 0.5122236f, 1.428458f, 0.3524071f );
    148. senceObjArray.push_back(object_3);
    149. }
    150. int Init()
    151. {
    152. CreateSence();
    153. goodcullingId = CreateGoodCulling();
    154. AddOccluder(senceObjArray[0].meshId, senceObjArray[0].meshData);
    155. AddOccludee(senceObjArray[1].meshId, GetBoundingBox(senceObjArray[1].minBox),
    156. GetBoundingBox(senceObjArray[1].maxBox));
    157. AddOccludee(senceObjArray[2].meshId, GetBoundingBox(senceObjArray[2].minBox),
    158. GetBoundingBox(senceObjArray[2].maxBox));
    159. AddOccludee(senceObjArray[3].meshId, GetBoundingBox(senceObjArray[3].minBox),
    160. GetBoundingBox(senceObjArray[3].maxBox));
    161. }
  4. Update the transform information of the models and obtain the occlusion result.
    Collapse
    Word wrap
    Dark theme
    Copy code
    1. void Render()
    2. {
    3. CleanUp(goodcullingId);
    4. UpdateViewMatrix(goodcullingId, &viewMatrix[0]);
    5. UpdateProjectionMatrix(goodcullingId, &projMatrix[0]);
    6. UpdateOccluderInfo(goodcullingId, senceObjArray[0].id, senceObjArray[0].meshId, senceObjArray[0].updateTranFlag,
    7. &senceObjArray[0].transformMatrix[0]);
    8. UpdateOccludeeInfo(goodcullingId, senceObjArray[1].id, senceObjArray[1].meshId, senceObjArray[1].updateTranFlag,
    9. &senceObjArray[1].transformMatrix[0]);
    10. UpdateOccludeeInfo(goodcullingId, senceObjArray[2].id, senceObjArray[2].meshId, senceObjArray[2].updateTranFlag,
    11. &senceObjArray[2].transformMatrix[0]);
    12. UpdateOccludeeInfo(goodcullingId, senceObjArray[3].id, senceObjArray[3].meshId, senceObjArray[3].updateTranFlag,
    13. &senceObjArray[3].transformMatrix[0]);
    14. // Rasterization and culling.
    15. RasterizationAndCulling(goodcullingId);
    16. bool result = GetCullingResult(goodcullingId, senceObjArray[1].id);
    17. 1 LOGI("occludee object_1 is visible: %d \n", result); // 1: visible.
    18. result = GetCullingResult(goodcullingId, senceObjArray[2].id);
    19. LOGI("occludee object_2 is visible: %d \n", result); // 1: visible.
    20. result = GetCullingResult(goodcullingId, senceObjArray[3].id);
    21. LOGI("occludee object_3 is visible: %d \n", result); // 0: invisible.
    22. }
  5. Delete the culling instance.
    Collapse
    Word wrap
    Dark theme
    Copy code
    1. void DeInit()
    2. {
    3. Disable(goodcullingId);
    4. RemoveAllOccluders();
    5. RemoveAllOccludees();
    6. DestroyGoodCulling(goodcullingId);
    7. }