This repository has been archived on 2024-11-16. You can view files and clone it, but cannot push or open issues or pull requests.

160 lines
4.5 KiB
C#
Raw Normal View History

2021-01-31 15:48:04 +08:00
using UnityEngine;
public class Fractal : MonoBehaviour
{
2021-01-31 16:25:50 +08:00
private struct FractalPart
{
2021-01-31 17:55:48 +08:00
public Vector3 direction, worldPosition;
public Quaternion rotation, worldRotation;
public float spinAngle;
2021-01-31 16:25:50 +08:00
}
FractalPart[][] parts;
2021-01-31 17:55:48 +08:00
Matrix4x4[][] matrices;
2021-01-31 15:48:04 +08:00
[SerializeField, Range(1, 8)]
int depth = 4;
2021-01-31 16:25:50 +08:00
[SerializeField]
Mesh mesh = default;
[SerializeField]
Material material = default;
static Vector3[] directions =
{
Vector3.up,
Vector3.right,
Vector3.left,
Vector3.forward,
Vector3.back
};
static Quaternion[] rotations =
2021-01-31 15:48:04 +08:00
{
2021-01-31 16:25:50 +08:00
Quaternion.identity,
Quaternion.Euler(0f, 0f, -90f),
Quaternion.Euler(0f, 0f, 90f),
Quaternion.Euler(90f, 0f, 0f),
Quaternion.Euler(-90f, 0f, 0f)
};
2021-01-31 17:55:48 +08:00
private FractalPart CreatePart(int childIndex)
2021-01-31 16:25:50 +08:00
{
return new FractalPart()
{
direction = directions[childIndex],
2021-01-31 17:55:48 +08:00
rotation = rotations[childIndex]
2021-01-31 16:25:50 +08:00
};
}
2021-01-31 15:48:04 +08:00
2021-01-31 17:55:48 +08:00
ComputeBuffer[] matricesBuffers;
static readonly int matricesId = Shader.PropertyToID("_Matrices");
static MaterialPropertyBlock propertyBlock;
private void OnEnable()
2021-01-31 16:25:50 +08:00
{
parts = new FractalPart[depth][];
2021-01-31 17:55:48 +08:00
matrices = new Matrix4x4[depth][];
matricesBuffers = new ComputeBuffer[depth];
int stride = 16 * 4;
2021-01-31 16:25:50 +08:00
for (int i = 0, length = 1; i < parts.Length; i++, length *= 5)
2021-01-31 15:48:04 +08:00
{
2021-01-31 16:25:50 +08:00
parts[i] = new FractalPart[length];
2021-01-31 17:55:48 +08:00
matrices[i] = new Matrix4x4[length];
matricesBuffers[i] = new ComputeBuffer(length, stride);
2021-01-31 15:48:04 +08:00
}
2021-01-31 17:55:48 +08:00
parts[0][0] = CreatePart(0);
2021-01-31 16:25:50 +08:00
for (int li = 1; li < parts.Length; li++)
{
FractalPart[] levelParts = parts[li];
for (int fpi = 0; fpi < levelParts.Length; fpi += 5)
{
for (int ci = 0; ci < 5; ci++)
{
2021-01-31 17:55:48 +08:00
levelParts[fpi + ci] = CreatePart(ci);
2021-01-31 16:25:50 +08:00
}
}
}
2021-01-31 17:55:48 +08:00
if (propertyBlock == null)
{
propertyBlock = new MaterialPropertyBlock();
}
2021-01-31 15:48:04 +08:00
}
2021-01-31 17:55:48 +08:00
private void OnDisable()
2021-01-31 15:48:04 +08:00
{
2021-01-31 17:55:48 +08:00
for (int i = 0; i < matricesBuffers.Length; i++)
{
matricesBuffers[i].Release();
}
parts = null;
matrices = null;
matricesBuffers = null;
}
void OnValidate()
{
if (parts != null && enabled)
{
OnDisable();
OnEnable();
}
}
2021-01-31 15:48:04 +08:00
2021-01-31 17:55:48 +08:00
private void Update()
{
float spinAngleDelta = 22.5f * Time.deltaTime;
2021-01-31 16:25:50 +08:00
FractalPart rootPart = parts[0][0];
2021-01-31 17:55:48 +08:00
rootPart.spinAngle += spinAngleDelta;
rootPart.worldRotation =
transform.rotation *
(rootPart.rotation * Quaternion.Euler(0f, rootPart.spinAngle, 0f));
rootPart.worldPosition = transform.position;
2021-01-31 16:25:50 +08:00
parts[0][0] = rootPart;
2021-01-31 17:55:48 +08:00
float objectScale = transform.lossyScale.x;
matrices[0][0] = Matrix4x4.TRS(
rootPart.worldPosition, rootPart.worldRotation, objectScale * Vector3.one
);
2021-01-31 16:25:50 +08:00
2021-01-31 17:55:48 +08:00
float scale = objectScale;
2021-01-31 16:25:50 +08:00
for (int li = 1; li < parts.Length; li++)
{
2021-01-31 17:55:48 +08:00
scale *= 0.5f;
2021-01-31 16:25:50 +08:00
FractalPart[] parentParts = parts[li - 1];
FractalPart[] levelParts = parts[li];
2021-01-31 17:55:48 +08:00
Matrix4x4[] levelMatrices = matrices[li];
2021-01-31 16:25:50 +08:00
for (int fpi = 0; fpi < levelParts.Length; fpi++)
{
2021-01-31 17:55:48 +08:00
var parent = parentParts[fpi / 5];
2021-01-31 16:25:50 +08:00
var part = levelParts[fpi];
2021-01-31 17:55:48 +08:00
part.spinAngle += spinAngleDelta;
part.worldRotation =
parent.worldRotation *
(part.rotation * Quaternion.Euler(0f, part.spinAngle, 0f));
part.worldPosition =
parent.worldPosition +
parent.worldRotation * (1.5f * scale * part.direction);
2021-01-31 16:25:50 +08:00
levelParts[fpi] = part;
2021-01-31 17:55:48 +08:00
levelMatrices[fpi] = Matrix4x4.TRS(
part.worldPosition, part.worldRotation, scale * Vector3.one
);
2021-01-31 16:25:50 +08:00
}
}
2021-01-31 17:55:48 +08:00
var bounds = new Bounds(rootPart.worldPosition, 3f * objectScale * Vector3.one);
for (int i = 0; i < matricesBuffers.Length; i++)
{
ComputeBuffer buffer = matricesBuffers[i];
buffer.SetData(matrices[i]);
propertyBlock.SetBuffer(matricesId, buffer);
Graphics.DrawMeshInstancedProcedural(mesh, 0, material, bounds, buffer.count, propertyBlock);
}
2021-01-31 15:48:04 +08:00
}
}