Hi,
I am trying to move from my CPU based procedural planet generation approach to a GPU based (when it comes to plane calculation and rendering).
Being fairly new new to shader programing at all, I am right now at the stage that I can hand over generation constants in a buffer to a compute shader, precalulcate the plane in a compute shader (vertice positions, norrmals, based on noise) and hand them over via the buffer for rendering (replacing the vertex positions of a prototype mesh with the ones from the buffer).
But right now I havent been able to render more than one plane at once. Guess this is due to some dependency I am not aware of (maybe the order of creating the buffers, materials, DrawMesh calls), or maybe I in the end need one gameobject per DrawMesh call?!.
Any hint on what I might be doing wrong would be very helpfull and appreciated.
So right now my (not working) approach is I moved the buffers into the QuadtreeTerrain class (a quadtree node), as well as the material (not sure if individual materials are necessary).
class QuadtreeTerrain {
// Quadtree classes
public QuadtreeTerrain parentNode; // The parent quadtree node
public QuadtreeTerrain childNode1; // A children quadtree node
public QuadtreeTerrain childNode2; // A children quadtree node
public QuadtreeTerrain childNode3; // A children quadtree node
public QuadtreeTerrain childNode4; // A children quadtree node
// Buffer
public ComputeBuffer generationConstantsBuffer;
public ComputeBuffer patchGeneratedDataBuffer;
// Material
public Material material;
....
}
In the SpaceObjectProceduralPlanet script, applied to a single game object, I hold six instances of quadtrees [=QuadtreeTerrain] then.
public class SpaceObjectProceduralPlanet : MonoBehaviour {
....
// QuadtreeTerrain
private QuadtreeTerrain quadtreeTerrain1;
private QuadtreeTerrain quadtreeTerrain2;
private QuadtreeTerrain quadtreeTerrain3;
private QuadtreeTerrain quadtreeTerrain4;
private QuadtreeTerrain quadtreeTerrain5;
private QuadtreeTerrain quadtreeTerrain6;
// We initialize the buffers and the material used to draw.
void Start()
{
...
// QuadtreeTerrain
this.quadtreeTerrain1 = new QuadtreeTerrain(0, edgeVector1, edgeVector2, edgeVector3, edgeVector4, quadtreeTerrainParameter1);
this.quadtreeTerrain2 = new QuadtreeTerrain(0, edgeVector2, edgeVector5, edgeVector4, edgeVector7, quadtreeTerrainParameter2);
this.quadtreeTerrain3 = new QuadtreeTerrain(0, edgeVector5, edgeVector6, edgeVector7, edgeVector8, quadtreeTerrainParameter3);
this.quadtreeTerrain4 = new QuadtreeTerrain(0, edgeVector6, edgeVector1, edgeVector8, edgeVector3, quadtreeTerrainParameter4);
this.quadtreeTerrain5 = new QuadtreeTerrain(0, edgeVector6, edgeVector5, edgeVector1, edgeVector2, quadtreeTerrainParameter5);
this.quadtreeTerrain6 = new QuadtreeTerrain(0, edgeVector3, edgeVector4, edgeVector8, edgeVector7, quadtreeTerrainParameter6);
CreateBuffers(this.quadtreeTerrain1);
CreateBuffers(this.quadtreeTerrain2);
CreateBuffers(this.quadtreeTerrain3);
CreateBuffers(this.quadtreeTerrain4);
CreateBuffers(this.quadtreeTerrain5);
CreateBuffers(this.quadtreeTerrain6);
CreateMaterial(this.quadtreeTerrain1);
CreateMaterial(this.quadtreeTerrain2);
CreateMaterial(this.quadtreeTerrain3);
CreateMaterial(this.quadtreeTerrain4);
CreateMaterial(this.quadtreeTerrain5);
CreateMaterial(this.quadtreeTerrain6);
Dispatch(this.quadtreeTerrain1);
Dispatch(this.quadtreeTerrain2);
Dispatch(this.quadtreeTerrain3);
Dispatch(this.quadtreeTerrain4);
Dispatch(this.quadtreeTerrain5);
Dispatch(this.quadtreeTerrain6);
}
// We compute the buffers.
void CreateBuffers(QuadtreeTerrain quadtreeTerrain)
{
.... preparing generation constants
quadtreeTerrain.generationConstantsBuffer.SetData(generationConstants);
// Buffer Output
quadtreeTerrain.patchGeneratedDataBuffer = new ComputeBuffer(nVerts, 16 + 12 + 4 + 12);
}
//We create the material
void CreateMaterial(QuadtreeTerrain quadtreeTerrain)
{
Material material = new Material(shader);
material.SetTexture("_MainTex", this.texture);
material.SetFloat("_Metallic", 0);
material.SetFloat("_Glossiness", 0);
quadtreeTerrain.material = material;
}
//We dispatch threads of our CSMain1 and CSMain2 kernels.
void Dispatch(QuadtreeTerrain quadtreeTerrain)
{
// Set Buffers
computeShader.SetBuffer(_kernel, "generationConstantsBuffer", quadtreeTerrain.generationConstantsBuffer);
computeShader.SetBuffer(_kernel, "patchGeneratedDataBuffer", quadtreeTerrain.patchGeneratedDataBuffer);
// Dispatch first kernel
_kernel = computeShader.FindKernel("CSMain1");
computeShader.Dispatch(_kernel, THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, THREADGROUP_SIZE_Z);
// Dispatch second kernel
_kernel = computeShader.FindKernel("CSMain2");
computeShader.Dispatch(_kernel, THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, THREADGROUP_SIZE_Z);
}
// We set the material before drawing and call DrawMesh on OnRenderObject
void OnRenderObject()
{
this.quadtreeTerrain1.material.SetBuffer("patchGeneratedDataBuffer", this.quadtreeTerrain1.patchGeneratedDataBuffer);
Graphics.DrawMesh(this.prototypeMesh, transform.localToWorldMatrix, this.quadtreeTerrain1.material, LayerMask.NameToLayer(GlobalVariablesManager.Instance.layerLocalSpaceName), null, 0, null, true, true);
this.quadtreeTerrain2.material.SetBuffer("patchGeneratedDataBuffer", this.quadtreeTerrain2.patchGeneratedDataBuffer);
Graphics.DrawMesh(this.prototypeMesh, transform.localToWorldMatrix, this.quadtreeTerrain2.material, LayerMask.NameToLayer(GlobalVariablesManager.Instance.layerLocalSpaceName), null, 0, null, true, true);
this.quadtreeTerrain3.material.SetBuffer("patchGeneratedDataBuffer", this.quadtreeTerrain3.patchGeneratedDataBuffer);
Graphics.DrawMesh(this.prototypeMesh, transform.localToWorldMatrix, this.quadtreeTerrain3.material, LayerMask.NameToLayer(GlobalVariablesManager.Instance.layerLocalSpaceName), null, 0, null, true, true);
this.quadtreeTerrain4.material.SetBuffer("patchGeneratedDataBuffer", this.quadtreeTerrain4.patchGeneratedDataBuffer);
Graphics.DrawMesh(this.prototypeMesh, transform.localToWorldMatrix, this.quadtreeTerrain4.material, LayerMask.NameToLayer(GlobalVariablesManager.Instance.layerLocalSpaceName), null, 0, null, true, true);
this.quadtreeTerrain5.material.SetBuffer("patchGeneratedDataBuffer", this.quadtreeTerrain5.patchGeneratedDataBuffer);
Graphics.DrawMesh(this.prototypeMesh, transform.localToWorldMatrix, this.quadtreeTerrain5.material, LayerMask.NameToLayer(GlobalVariablesManager.Instance.layerLocalSpaceName), null, 0, null, true, true);
this.quadtreeTerrain6.material.SetBuffer("patchGeneratedDataBuffer", this.quadtreeTerrain6.patchGeneratedDataBuffer);
Graphics.DrawMesh(this.prototypeMesh, transform.localToWorldMatrix, this.quadtreeTerrain6.material, LayerMask.NameToLayer(GlobalVariablesManager.Instance.layerLocalSpaceName), null, 0, null, true, true);
}
//When this GameObject is disabled we must release the buffers.
private void OnDisable()
{
ReleaseBuffer();
}
//Release buffers and destroy the material when play has been stopped.
void ReleaseBuffer()
{
// Destroy everything recursive in the quadtrees.
this.quadtreeTerrain1.generationConstantsBuffer.Release();
this.quadtreeTerrain1.patchGeneratedDataBuffer.Release();
this.quadtreeTerrain2.generationConstantsBuffer.Release();
this.quadtreeTerrain2.patchGeneratedDataBuffer.Release();
this.quadtreeTerrain3.generationConstantsBuffer.Release();
this.quadtreeTerrain3.patchGeneratedDataBuffer.Release();
this.quadtreeTerrain4.generationConstantsBuffer.Release();
this.quadtreeTerrain4.patchGeneratedDataBuffer.Release();
this.quadtreeTerrain5.generationConstantsBuffer.Release();
this.quadtreeTerrain5.patchGeneratedDataBuffer.Release();
this.quadtreeTerrain6.generationConstantsBuffer.Release();
this.quadtreeTerrain6.patchGeneratedDataBuffer.Release();
DestroyImmediate(this.quadtreeTerrain1.material);
DestroyImmediate(this.quadtreeTerrain2.material);
DestroyImmediate(this.quadtreeTerrain3.material);
DestroyImmediate(this.quadtreeTerrain4.material);
DestroyImmediate(this.quadtreeTerrain5.material);
DestroyImmediate(this.quadtreeTerrain6.material);
}
void Update() {
// Do nothing
}
}
Of course this is very bruteforce, but well this should work before I proceed as I need to figure out how to handle the buffers and draw calls and where to put them.