InstanceIndirect.hx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package h3d.shader;
  2. class InstanceIndirectBase extends hxsl.Shader {
  3. static var SRC = {
  4. @global var camera : {
  5. var position : Vec3;
  6. }
  7. @const var ENABLE_COUNT_BUFFER : Bool;
  8. @param var countBuffer : RWBuffer<Int>;
  9. @param var commandBuffer : RWBuffer<Int>;
  10. @param var instanceData : StoragePartialBuffer<{ modelView : Mat4 }>;
  11. @param var instanceCount : Int;
  12. // 16 by default because 16 * 4 floats = 256 bytes and cbuffer are aligned to 256 bytes
  13. @const var MAX_MATERIAL_COUNT : Int = 16;
  14. // x : indexCount, y : startIndex, z : minScreenRatio, w : in first lod => minScreenRatioCulling
  15. @param var matInfos : Buffer<Vec4, MAX_MATERIAL_COUNT>;
  16. @const var ENABLE_CULLING : Bool;
  17. @param var frustum : Buffer<Vec4, 6>;
  18. @const var ENABLE_LOD : Bool;
  19. @const var ENABLE_DISTANCE_CLIPPING : Bool;
  20. @param var maxDistance : Float = -1;
  21. var matID : Int = 0;
  22. var modelView : Mat4;
  23. var invocID : Int;
  24. function __init__() {
  25. {
  26. setLayout(64, 1, 1);
  27. invocID = computeVar.workGroup.x * 64 + computeVar.localInvocationIndex;
  28. }
  29. modelView = instanceData[invocID].modelView;
  30. }
  31. function emitInstance(instanceID : Int, indexCount : Int, instanceCount : Int, startIndex : Int, startVertex : Int, baseInstance : Int ) {
  32. var instancePos = instanceID * 5;
  33. commandBuffer[instancePos + 0] = indexCount;
  34. commandBuffer[instancePos + 1] = instanceCount;
  35. commandBuffer[instancePos + 2] = startIndex;
  36. commandBuffer[instancePos + 3] = startVertex;
  37. commandBuffer[instancePos + 4] = baseInstance;
  38. }
  39. function frustumCulling( pos : Vec3, radius : Float ) : Bool {
  40. var culled = false;
  41. if ( ENABLE_CULLING ) {
  42. @unroll for ( i in 0...6 ) {
  43. var plane = frustum[i];
  44. culled = culled || plane.x * pos.x + plane.y * pos.y + plane.z * pos.z - plane.w < -radius;
  45. }
  46. }
  47. return culled;
  48. }
  49. function distanceClipping( distToCam : Float, radius : Float ) : Bool {
  50. return ( ENABLE_DISTANCE_CLIPPING ) ? distToCam > maxDistance + radius : false;
  51. }
  52. function screenRatioCulling( screenRatio : Float ) : Bool {
  53. var minScreenRatioCulling = getMinScreenRatio();
  54. return screenRatio < minScreenRatioCulling;
  55. }
  56. function getLodCount() : Int {
  57. return 0;
  58. }
  59. function getLodScreenRatio( lod : Int ) : Float {
  60. return matInfos[lod + matID].z;
  61. }
  62. function getMinScreenRatio() : Float {
  63. return ENABLE_LOD ? matInfos[matID].w : 0.0;
  64. }
  65. function computeScreenRatio( distToCam : Float, radius : Float ) : Float {
  66. var screenRatio = radius / distToCam;
  67. return screenRatio * screenRatio;
  68. }
  69. function selectLod( screenRatio : Float, lodCount : Int ) : Int {
  70. var lod : Int = 0;
  71. if ( ENABLE_LOD ) {
  72. for ( i in 0...lodCount ) {
  73. var minScreenRatio = getLodScreenRatio(i);
  74. if ( screenRatio > minScreenRatio )
  75. break;
  76. lod++;
  77. }
  78. lod = clamp(lod, 0, int(lodCount) - 1);
  79. }
  80. return lod;
  81. }
  82. }
  83. }
  84. class SubPartInstanceIndirect extends InstanceIndirectBase {
  85. static var SRC = {
  86. // n : material offset, n + 1 : subPart ID
  87. @param var instanceOffsets: StorageBuffer<Int>;
  88. @const var MAX_SUB_PART_BUFFER_ELEMENT_COUNT : Int = 16;
  89. @param var subPartCount : Int;
  90. // x : lodCount, y : radius,
  91. @param var subPartInfos : Buffer<Vec4, MAX_SUB_PART_BUFFER_ELEMENT_COUNT>;
  92. var lodCount = 0;
  93. function getLodCount() : Int {
  94. return lodCount;
  95. }
  96. function main() {
  97. if ( invocID < instanceCount ) {
  98. var pos = vec3(0) * modelView.mat3x4();
  99. var vScale = abs(vec3(1) * modelView.mat3x4() - pos);
  100. var scaledRadius = max(max(vScale.x, vScale.y), vScale.z);
  101. var toCam = camera.position - pos.xyz;
  102. var distToCam = length(toCam);
  103. var id = invocID * 2;
  104. matID = instanceOffsets[id];
  105. var subPartID = instanceOffsets[id + 1];
  106. var subPartInfo = subPartInfos[subPartID / 2];
  107. var packedID = (subPartID & 1) << 1;
  108. lodCount = int(subPartInfo[packedID]);
  109. var radius = subPartInfo[packedID + 1];
  110. scaledRadius *= radius;
  111. var culled = dot(scaledRadius, scaledRadius) < 1e-6;
  112. culled = culled || frustumCulling(pos, scaledRadius);
  113. culled = culled || distanceClipping(distToCam, scaledRadius);
  114. var computeScreenRatio = computeScreenRatio(distToCam, scaledRadius);
  115. culled = culled || screenRatioCulling(computeScreenRatio);
  116. if ( ENABLE_COUNT_BUFFER ) {
  117. if ( !culled ) {
  118. var id = atomicAdd( countBuffer, 0, 1);
  119. var lod = selectLod(computeScreenRatio, lodCount);
  120. var matInfo = ivec4(matInfos[lod + matID]);
  121. emitInstance( id, matInfo.x, 1, matInfo.y, 0, invocID );
  122. }
  123. } else {
  124. if ( !culled ) {
  125. var lod = selectLod(computeScreenRatio, lodCount);
  126. var matInfo = ivec4(matInfos[lod + matID]);
  127. emitInstance( invocID, matInfo.x, 1, matInfo.y, 0, invocID );
  128. } else {
  129. emitInstance( invocID, 0, 0, 0, 0, 0 );
  130. }
  131. }
  132. }
  133. }
  134. }
  135. }
  136. class InstanceIndirect extends InstanceIndirectBase {
  137. static var SRC = {
  138. @param var radius : Float;
  139. @param var materialCount : Int;
  140. @param var lodCount : Int = 1;
  141. function getLodCount() : Int {
  142. return lodCount;
  143. }
  144. function main() {
  145. if ( invocID < instanceCount ) {
  146. var pos = vec3(0) * modelView.mat3x4();
  147. var vScale = abs(vec3(1) * modelView.mat3x4() - pos);
  148. var scaledRadius = max(max(vScale.x, vScale.y), vScale.z);
  149. var toCam = camera.position - pos.xyz;
  150. var distToCam = length(toCam);
  151. scaledRadius *= radius;
  152. var culled = dot(scaledRadius, scaledRadius) < 1e-6;
  153. culled = culled || frustumCulling(pos, scaledRadius);
  154. culled = culled || distanceClipping(distToCam, scaledRadius);
  155. var computeScreenRatio = computeScreenRatio(distToCam, scaledRadius);
  156. culled = culled || screenRatioCulling(computeScreenRatio);
  157. if ( ENABLE_COUNT_BUFFER ) {
  158. if ( !culled ) {
  159. var id = atomicAdd( countBuffer, 0, 1);
  160. for ( i in 0...materialCount ) {
  161. matID = i * lodCount;
  162. var lod = selectLod(computeScreenRatio, lodCount);
  163. var matInfo = ivec4(matInfos[lod + matID]);
  164. var instanceID = id + i * instanceCount;
  165. emitInstance( instanceID, matInfo.x, 1, matInfo.y, 0, invocID );
  166. }
  167. }
  168. } else {
  169. if ( !culled ) {
  170. for ( i in 0...materialCount ) {
  171. matID = i * lodCount;
  172. var lod = selectLod(computeScreenRatio, lodCount);
  173. var matInfo = ivec4(matInfos[lod + matID]);
  174. var instanceID = invocID + i * instanceCount;
  175. emitInstance( instanceID, matInfo.x, 1, matInfo.y, 0, invocID );
  176. }
  177. } else {
  178. for ( i in 0...materialCount ) {
  179. var instanceID = invocID + i * instanceCount;
  180. emitInstance( instanceID, 0, 0, 0, 0, 0 );
  181. }
  182. }
  183. }
  184. }
  185. }
  186. }
  187. }