#pragma kernel CSCullIndividual #pragma kernel CSCullCell struct GrassElement { float3 position; float rotation; float size; float colorBlend;//0-1 }; struct grassCell { uint grassElementIndexes[512];//map to grass elements }; //struct grassOcclusionCell { // uint grassCellIndex; // uint visibleCellIndexes[2048];//Map to occlusion cells // }; //General uint grassCount; float2 distanceBounts;//Start, end Texture2D ditherTex; int ditherTexSizeX; float ditherSize; //Input StructuredBuffer grassBuffer; //Frustrum culling float3 cameraPos; float4x3 cameraFrustumNormals; //settings int doOcclusion; //Cells uint grassCellCount; uint grassCellSize; StructuredBuffer grassCellBuffer; //Occlusion culling //StructuredBuffer grassOcclusionBuffer; //Output AppendStructuredBuffer outGrassBuffer; AppendStructuredBuffer outCellIndexBuffer; bool Is3DDither (float dist, float2 pos) { float distAmount = 1 - (dist-distanceBounts.x)/(distanceBounts.y-distanceBounts.x);//0-1 float2 relativePos = pos/ditherSize; float2 positivePos = float2(relativePos.x*sign(relativePos.x),relativePos.y*sign(relativePos.y)); float2 repeatingPos = float2(fmod(positivePos.x,ditherTexSizeX),fmod(positivePos.y,ditherTexSizeX)); float dit = ditherTex[repeatingPos].x; return distAmount - dit > 0; } [numthreads(16,16,4)] void CSCullIndividual (uint index : SV_GroupIndex, uint3 group : SV_GroupID) {//This only does frustrum culling //1. get index uint realIndex = index + 1024 * group.x;//id.x + id.y group.x + id.z group.x * group.y //2. index valid? if(realIndex < grassCount) { GrassElement data = grassBuffer[realIndex]; float3 pos = data.position; float3 posFromCamera = pos - cameraPos; float scale = data.size; //3. frustrum culling if( (dot(cameraFrustumNormals[0], posFromCamera) > -scale) && (dot(cameraFrustumNormals[1], posFromCamera) > -scale) && (dot(cameraFrustumNormals[2], posFromCamera) > -scale) && (dot(cameraFrustumNormals[3], posFromCamera) > -scale) ){ //3D dither culling (includes dist culling) float dist = length(posFromCamera); if(Is3DDither(dist,pos.xz)) { outGrassBuffer.Append(realIndex); } } } } [numthreads(8,8,1)] void CSCullCell (uint index : SV_GroupIndex, uint3 group : SV_GroupID) {//This does frustrum and occlusion culling on cells //1. get index uint realIndex = index + 8*8*group.x; //2. index valid? if(realIndex < grassCellCount) { //outGrassBuffer.Append(realIndex); //outCellIndexBuffer.Append(realIndex); grassCell cell = grassCellBuffer[realIndex]; //for(int i=0;i<512;i++) { // int k = cell.grassElementIndexes[i]; // if(k != 0)outGrassBuffer.Append(k); // } //Doing frustrum check with ranodom element from cell float3 pos = grassBuffer[cell.grassElementIndexes[0]].position; float3 posFromCamera = pos - cameraPos; float scale = grassCellSize; //3. frustrum culling if( (dot(cameraFrustumNormals[0], posFromCamera) > -scale) && (dot(cameraFrustumNormals[1], posFromCamera) > -scale) && (dot(cameraFrustumNormals[2], posFromCamera) > -scale) && (dot(cameraFrustumNormals[3], posFromCamera) > -scale) ){ if(length(posFromCamera) <= distanceBounts.y) {//Dist check if(doOcclusion == 1) { //TODO see if this chunk is visible from current chunk //TODO if yes then append chunk grass indexes } else { outCellIndexBuffer.Append(realIndex); } } } } } //group -> thread //SV_GroupThreadID = current threads num.xyz //SV_GroupIndex = num.x * num.y * num.z; //SV_GroupID = current gorup indices /* This works for some reason [numthreads(8,8,8)] void Converter (uint callIndex : SV_GroupIndex, uint3 groupID : SV_GroupID) { uint realIndex = groupID.x + groupID.y + groupID.z; uint cellIndex = grassCellIndexBuffer[realIndex]; grassCell cell = grassCellBuffer[ cellIndex ]; int elementIndex = callIndex;//Correct uint objIndex = cell.grassElementIndexes[elementIndex]; if(objIndex != 0) outGrassBuffer.Append(objIndex); } */