init
This commit is contained in:
commit
f5c1616018
679 changed files with 188502 additions and 0 deletions
192
Assets/Pixel3D/Scripts/LeafInstancer.cs
Normal file
192
Assets/Pixel3D/Scripts/LeafInstancer.cs
Normal file
|
@ -0,0 +1,192 @@
|
|||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static System.Runtime.InteropServices.Marshal;
|
||||
|
||||
[RequireComponent(typeof(MeshSurfaceSampler))]
|
||||
public class LeafInstancer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] LayerMask _grassLayer;
|
||||
[SerializeField] Mesh _leafMesh;
|
||||
[SerializeField] Material _material;
|
||||
|
||||
MeshSurfaceSampler _meshSurfaceSampler;
|
||||
RenderParams _renderParams;
|
||||
|
||||
GraphicsBuffer commandBuffer;
|
||||
GraphicsBuffer.IndirectDrawIndexedArgs[] commandData;
|
||||
LeafData[] leafData;
|
||||
ComputeBuffer leafBuffer;
|
||||
|
||||
const int commandCount = 1;
|
||||
|
||||
struct LeafData
|
||||
{
|
||||
public Vector3 position;
|
||||
public Vector3 normal;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Setup();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
commandBuffer?.Release();
|
||||
commandBuffer = null;
|
||||
leafBuffer?.Release();
|
||||
leafBuffer = null;
|
||||
}
|
||||
|
||||
void Setup()
|
||||
{
|
||||
_meshSurfaceSampler = GetComponent<MeshSurfaceSampler>();
|
||||
if (_meshSurfaceSampler == null)
|
||||
Debug.LogError("MeshGenerator is null");
|
||||
|
||||
var meshRenderer = GetComponent<MeshRenderer>();
|
||||
if (meshRenderer == null)
|
||||
Debug.LogError("MeshRenderer is null");
|
||||
|
||||
if (_material == null)
|
||||
Debug.LogError("Material is null");
|
||||
|
||||
if (_leafMesh == null)
|
||||
Debug.LogError("Grass mesh is null");
|
||||
}
|
||||
|
||||
public void GeneratePoints()
|
||||
{
|
||||
_meshSurfaceSampler.GeneratePoints();
|
||||
}
|
||||
|
||||
public Bounds GetBoundingBox()
|
||||
{
|
||||
Bounds boundingBox = new Bounds();
|
||||
|
||||
if (_meshSurfaceSampler.points != null && _meshSurfaceSampler.points.Length > 0)
|
||||
{
|
||||
Vector3 minPoint = _meshSurfaceSampler.points[0];
|
||||
Vector3 maxPoint = _meshSurfaceSampler.points[0];
|
||||
|
||||
for (int i = 1; i < _meshSurfaceSampler.points.Length; i++)
|
||||
{
|
||||
minPoint = Vector3.Min(minPoint, _meshSurfaceSampler.points[i]);
|
||||
maxPoint = Vector3.Max(maxPoint, _meshSurfaceSampler.points[i]);
|
||||
}
|
||||
|
||||
boundingBox.SetMinMax(minPoint, maxPoint);
|
||||
}
|
||||
|
||||
var extrude = _material.GetFloat("_Extrude");
|
||||
boundingBox.Expand(boundingBox.size * extrude);
|
||||
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
public void Generate()
|
||||
{
|
||||
var count = _meshSurfaceSampler.points.Length;
|
||||
// var count = 1;
|
||||
|
||||
leafData = new LeafData[count];
|
||||
leafBuffer?.Release();
|
||||
leafBuffer = new ComputeBuffer(count, SizeOf<LeafData>());
|
||||
commandBuffer?.Release();
|
||||
commandBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, commandCount, GraphicsBuffer.IndirectDrawIndexedArgs.size);
|
||||
commandData = new GraphicsBuffer.IndirectDrawIndexedArgs[commandCount];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
leafData[i] = new LeafData
|
||||
{
|
||||
position = _meshSurfaceSampler.points[i],
|
||||
normal = _meshSurfaceSampler.normals[i]
|
||||
};
|
||||
}
|
||||
|
||||
// Set the buffers
|
||||
var indirectDrawIndexedArgs = new GraphicsBuffer.IndirectDrawIndexedArgs
|
||||
{
|
||||
indexCountPerInstance = _leafMesh.GetIndexCount(0),
|
||||
instanceCount = (uint)count,
|
||||
startIndex = _leafMesh.GetIndexStart(0),
|
||||
baseVertexIndex = _leafMesh.GetBaseVertex(0),
|
||||
startInstance = 0,
|
||||
};
|
||||
for (int i = 0; i < commandCount; i++)
|
||||
commandData[i] = indirectDrawIndexedArgs;
|
||||
|
||||
commandBuffer.SetData(commandData);
|
||||
leafBuffer.SetData(leafData);
|
||||
|
||||
// Set the render params
|
||||
var block = new MaterialPropertyBlock();
|
||||
block.SetBuffer("_LeafData", leafBuffer);
|
||||
|
||||
_renderParams = new RenderParams(_material)
|
||||
{
|
||||
layer = (int)Mathf.Log(_grassLayer.value, 2),
|
||||
worldBounds = new Bounds(Vector3.zero, 10000 * Vector3.one),
|
||||
matProps = block,
|
||||
receiveShadows = true,
|
||||
};
|
||||
|
||||
UpdateRotation();
|
||||
}
|
||||
|
||||
// Update the rotation of the grass
|
||||
void UpdateRotation()
|
||||
{
|
||||
var target = Camera.main.transform.position;
|
||||
var rotation = Quaternion.LookRotation(transform.position - target, Vector3.up);
|
||||
var quaternion = new Vector4(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
_renderParams.matProps.SetVector("_Rotation", quaternion);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Validation checks
|
||||
if (_meshSurfaceSampler == null)
|
||||
Setup();
|
||||
|
||||
if (!_meshSurfaceSampler.ArePointsGenerated())
|
||||
_meshSurfaceSampler.GeneratePoints();
|
||||
|
||||
// if (transform.lossyScale != Vector3.one)
|
||||
// Debug.LogWarning("GrassInstancer does not support scaling");
|
||||
|
||||
if (leafData == null || leafData.Length == 0)
|
||||
Generate();
|
||||
|
||||
UpdateRotation();
|
||||
|
||||
|
||||
// Frustum culling check for the chunk
|
||||
var frustumPlanes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
|
||||
if (!GeometryUtility.TestPlanesAABB(frustumPlanes, GetBoundingBox()))
|
||||
return;
|
||||
|
||||
// Render the grass
|
||||
Graphics.RenderMeshIndirect(_renderParams, _leafMesh, commandBuffer, commandCount);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Custom editor which adds a button to generate the terrain
|
||||
[CustomEditor(typeof(LeafInstancer))]
|
||||
public class LeafInstancerEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var script = (LeafInstancer)target;
|
||||
DrawDefaultInspector();
|
||||
GUILayout.Space(10);
|
||||
if (GUILayout.Button("Generate Leaves"))
|
||||
{
|
||||
script.GeneratePoints();
|
||||
script.Generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue