From Jobs
This commit is contained in:
184
Assets/Script/Fractal.cs
Normal file
184
Assets/Script/Fractal.cs
Normal file
@ -0,0 +1,184 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
using static Unity.Mathematics.math;
|
||||
using quaternion = Unity.Mathematics.quaternion;
|
||||
|
||||
public class Fractal : MonoBehaviour
|
||||
{
|
||||
[BurstCompile(FloatPrecision.Standard, FloatMode.Fast, CompileSynchronously = true)]
|
||||
private struct UpdateFractalLevelJob : IJobFor
|
||||
{
|
||||
public float spinAngleDelta;
|
||||
public float scale;
|
||||
|
||||
[ReadOnly]
|
||||
public NativeArray<FractalPart> parents;
|
||||
|
||||
public NativeArray<FractalPart> parts;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<float3x4> matrices;
|
||||
|
||||
public void Execute(int i)
|
||||
{
|
||||
var parent = parents[i / 5];
|
||||
var part = parts[i];
|
||||
part.spinAngle += spinAngleDelta;
|
||||
part.worldRotation = mul(parent.worldRotation,
|
||||
mul(part.rotation, quaternion.RotateY(part.spinAngle))
|
||||
);
|
||||
part.worldPosition =
|
||||
parent.worldPosition +
|
||||
mul(parent.worldRotation, 1.5f * scale * part.direction);
|
||||
parts[i] = part;
|
||||
|
||||
float3x3 r = float3x3(part.worldRotation) * scale;
|
||||
matrices[i] = float3x4(r.c0, r.c1, r.c2, part.worldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
private struct FractalPart
|
||||
{
|
||||
public float3 direction, worldPosition;
|
||||
public quaternion rotation, worldRotation;
|
||||
public float spinAngle;
|
||||
}
|
||||
|
||||
NativeArray<FractalPart>[] parts;
|
||||
|
||||
NativeArray<float3x4>[] matrices;
|
||||
|
||||
[SerializeField, Range(1, 8)]
|
||||
int depth = 4;
|
||||
|
||||
[SerializeField]
|
||||
Mesh mesh = default;
|
||||
|
||||
[SerializeField]
|
||||
Material material = default;
|
||||
|
||||
static float3[] directions =
|
||||
{
|
||||
up(), right(), left(), forward(), back()
|
||||
};
|
||||
|
||||
static quaternion[] rotations =
|
||||
{
|
||||
quaternion.identity,
|
||||
quaternion.RotateZ(-0.5f * PI), quaternion.RotateZ(0.5f * PI),
|
||||
quaternion.RotateX(0.5f * PI), quaternion.RotateX(-0.5f * PI)
|
||||
};
|
||||
|
||||
private FractalPart CreatePart(int childIndex)
|
||||
{
|
||||
return new FractalPart()
|
||||
{
|
||||
direction = directions[childIndex],
|
||||
rotation = rotations[childIndex]
|
||||
};
|
||||
}
|
||||
|
||||
ComputeBuffer[] matricesBuffers;
|
||||
|
||||
static readonly int matricesId = Shader.PropertyToID("_Matrices");
|
||||
|
||||
static MaterialPropertyBlock propertyBlock;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
parts = new NativeArray<FractalPart>[depth];
|
||||
matrices = new NativeArray<float3x4>[depth];
|
||||
matricesBuffers = new ComputeBuffer[depth];
|
||||
int stride = 12 * 4;
|
||||
for (int i = 0, length = 1; i < parts.Length; i++, length *= 5)
|
||||
{
|
||||
parts[i] = new NativeArray<FractalPart>(length, Allocator.Persistent);
|
||||
matrices[i] = new NativeArray<float3x4>(length, Allocator.Persistent);
|
||||
matricesBuffers[i] = new ComputeBuffer(length, stride);
|
||||
}
|
||||
|
||||
parts[0][0] = CreatePart(0);
|
||||
for (int li = 1; li < parts.Length; li++)
|
||||
{
|
||||
NativeArray<FractalPart> levelParts = parts[li];
|
||||
for (int fpi = 0; fpi < levelParts.Length; fpi += 5)
|
||||
{
|
||||
for (int ci = 0; ci < 5; ci++)
|
||||
{
|
||||
levelParts[fpi + ci] = CreatePart(ci);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (propertyBlock == null)
|
||||
{
|
||||
propertyBlock = new MaterialPropertyBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
for (int i = 0; i < matricesBuffers.Length; i++)
|
||||
{
|
||||
matricesBuffers[i].Release();
|
||||
parts[i].Dispose();
|
||||
matrices[i].Dispose();
|
||||
}
|
||||
parts = null;
|
||||
matrices = null;
|
||||
matricesBuffers = null;
|
||||
}
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
if (parts != null && enabled)
|
||||
{
|
||||
OnDisable();
|
||||
OnEnable();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
float spinAngleDelta = 0.125f * PI * Time.deltaTime;
|
||||
FractalPart rootPart = parts[0][0];
|
||||
rootPart.spinAngle += spinAngleDelta;
|
||||
rootPart.worldRotation = mul(transform.rotation,
|
||||
mul(rootPart.rotation, quaternion.RotateY(rootPart.spinAngle))
|
||||
);
|
||||
rootPart.worldPosition = transform.position;
|
||||
parts[0][0] = rootPart;
|
||||
float objectScale = transform.lossyScale.x;
|
||||
float3x3 r = float3x3(rootPart.worldRotation) * objectScale;
|
||||
matrices[0][0] = float3x4(r.c0, r.c1, r.c2, rootPart.worldPosition);
|
||||
|
||||
float scale = objectScale;
|
||||
JobHandle jobHandle = default;
|
||||
for (int li = 1; li < parts.Length; li++)
|
||||
{
|
||||
scale *= 0.5f;
|
||||
jobHandle = new UpdateFractalLevelJob
|
||||
{
|
||||
spinAngleDelta = spinAngleDelta,
|
||||
scale = scale,
|
||||
parents = parts[li - 1],
|
||||
parts = parts[li],
|
||||
matrices = matrices[li]
|
||||
}.ScheduleParallel(parts[li].Length, 5, jobHandle);
|
||||
}
|
||||
jobHandle.Complete();
|
||||
|
||||
var bounds = new Bounds(rootPart.worldPosition, float3(3f * objectScale));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Script/Fractal.cs.meta
Normal file
11
Assets/Script/Fractal.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bef3764eec961e04db4297ce68f82391
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
66
Assets/Script/FrameRateCounter.cs
Normal file
66
Assets/Script/FrameRateCounter.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class FrameRateCounter : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
TextMeshProUGUI display = default;
|
||||
|
||||
public enum DisplayMode { FPS, MS };
|
||||
|
||||
[SerializeField]
|
||||
DisplayMode displayMode = DisplayMode.FPS;
|
||||
|
||||
[SerializeField, Range(0.1f, 2.0f)]
|
||||
float sampleDuration = 1.0f;
|
||||
|
||||
int frames;
|
||||
|
||||
float duration;
|
||||
float bestDuration = float.MaxValue;
|
||||
float worstDuration = 0.0f;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
var frameDuration = Time.unscaledDeltaTime;
|
||||
frames++;
|
||||
duration += frameDuration;
|
||||
|
||||
if (frameDuration < bestDuration)
|
||||
{
|
||||
bestDuration = frameDuration;
|
||||
}
|
||||
if (frameDuration > worstDuration)
|
||||
{
|
||||
worstDuration = frameDuration;
|
||||
}
|
||||
|
||||
if (duration >= sampleDuration)
|
||||
{
|
||||
if (displayMode == DisplayMode.FPS)
|
||||
{
|
||||
display.SetText(
|
||||
"FPS\n{0:0}\n{1:0}\n{2:0}",
|
||||
1.0f / bestDuration,
|
||||
frames / duration,
|
||||
1.0f / worstDuration
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
display.SetText(
|
||||
"FPS\n{0:1}\n{1:1}\n{2:1}",
|
||||
1000.0f * bestDuration,
|
||||
1000.0f * duration / frames,
|
||||
1000.0f * worstDuration
|
||||
);
|
||||
}
|
||||
|
||||
frames = 0;
|
||||
duration = 0.0f;
|
||||
bestDuration = float.MaxValue;
|
||||
worstDuration = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Script/FrameRateCounter.cs.meta
Normal file
11
Assets/Script/FrameRateCounter.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db0de69e270b20648a07ce8befb7b34d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
21
Assets/Script/PartGPU.hlsl
Normal file
21
Assets/Script/PartGPU.hlsl
Normal file
@ -0,0 +1,21 @@
|
||||
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
|
||||
StructuredBuffer<float3x4> _Matrices;
|
||||
#endif
|
||||
|
||||
void ConfigureProcedural () {
|
||||
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
|
||||
float3x4 m = _Matrices[unity_InstanceID];
|
||||
unity_ObjectToWorld._m00_m01_m02_m03 = m._m00_m01_m02_m03;
|
||||
unity_ObjectToWorld._m10_m11_m12_m13 = m._m10_m11_m12_m13;
|
||||
unity_ObjectToWorld._m20_m21_m22_m23 = m._m20_m21_m22_m23;
|
||||
unity_ObjectToWorld._m30_m31_m32_m33 = float4(0.0, 0.0, 0.0, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ShaderGraphFunction_float (float3 In, out float3 Out) {
|
||||
Out = In;
|
||||
}
|
||||
|
||||
void ShaderGraphFunction_half (half3 In, out half3 Out) {
|
||||
Out = In;
|
||||
}
|
9
Assets/Script/PartGPU.hlsl.meta
Normal file
9
Assets/Script/PartGPU.hlsl.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ed85852d1001bf44b1fef32640df23b
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user