Compare commits

...

5 Commits

Author SHA1 Message Date
d635eeadd2 Spin - Done! 2021-02-01 11:33:00 +08:00
e987949600 Sagging 2021-02-01 11:25:34 +08:00
7ee4755a6a Leaves 2021-02-01 11:10:33 +08:00
dd11842558 Arbitrary Colors 2021-02-01 09:25:22 +08:00
9e6b1592ef Color Gradient 2021-02-01 08:54:15 +08:00
4 changed files with 190 additions and 48 deletions

File diff suppressed because one or more lines are too long

View File

@ -152,7 +152,70 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
depth: 8 depth: 8
mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
leafMesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
material: {fileID: 2100000, guid: 8f3914ac4291e664ba60ae208ae66460, type: 2} material: {fileID: 2100000, guid: 8f3914ac4291e664ba60ae208ae66460, type: 2}
gradientA:
serializedVersion: 2
key0: {r: 0.764151, g: 0.18413278, b: 0, a: 0.3137255}
key1: {r: 1, g: 1, b: 0, a: 0.3529412}
key2: {r: 0, g: 0, b: 0, a: 0}
key3: {r: 0, g: 0, b: 0, a: 0}
key4: {r: 0, g: 0, b: 0, a: 0}
key5: {r: 0, g: 0, b: 0, a: 0}
key6: {r: 0, g: 0, b: 0, a: 0}
key7: {r: 0, g: 0, b: 0, a: 0}
ctime0: 0
ctime1: 65535
ctime2: 65535
ctime3: 0
ctime4: 0
ctime5: 0
ctime6: 0
ctime7: 0
atime0: 0
atime1: 65535
atime2: 0
atime3: 0
atime4: 0
atime5: 0
atime6: 0
atime7: 0
m_Mode: 0
m_NumColorKeys: 2
m_NumAlphaKeys: 2
gradientB:
serializedVersion: 2
key0: {r: 0.40392157, g: 0.14109339, b: 0, a: 0.54901963}
key1: {r: 0, g: 0.6320754, b: 0, a: 0.627451}
key2: {r: 1, g: 1, b: 0, a: 0}
key3: {r: 0, g: 0, b: 0, a: 0}
key4: {r: 0, g: 0, b: 0, a: 0}
key5: {r: 0, g: 0, b: 0, a: 0}
key6: {r: 0, g: 0, b: 0, a: 0}
key7: {r: 0, g: 0, b: 0, a: 0}
ctime0: 0
ctime1: 65535
ctime2: 65535
ctime3: 0
ctime4: 0
ctime5: 0
ctime6: 0
ctime7: 0
atime0: 0
atime1: 65535
atime2: 0
atime3: 0
atime4: 0
atime5: 0
atime6: 0
atime7: 0
m_Mode: 0
m_NumColorKeys: 2
m_NumAlphaKeys: 2
leafColorA: {r: 0.45882356, g: 0.97647065, b: 0.29803923, a: 0.49803922}
leafColorB: {r: 0.21568629, g: 0.4901961, b: 0.13333334, a: 0.9019608}
maxSagAngleA: 15
maxSagAngleB: 25
--- !u!4 &197491476 --- !u!4 &197491476
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -160,13 +223,13 @@ Transform:
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 197491472} m_GameObject: {fileID: 197491472}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0.17364816, w: 0.9848078}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 4 m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 20}
--- !u!1 &705507993 --- !u!1 &705507993
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -3,6 +3,7 @@ using Unity.Collections;
using Unity.Jobs; using Unity.Jobs;
using Unity.Mathematics; using Unity.Mathematics;
using UnityEngine; using UnityEngine;
using Random = UnityEngine.Random;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
using quaternion = Unity.Mathematics.quaternion; using quaternion = Unity.Mathematics.quaternion;
@ -12,8 +13,8 @@ public class Fractal : MonoBehaviour
[BurstCompile(FloatPrecision.Standard, FloatMode.Fast, CompileSynchronously = true)] [BurstCompile(FloatPrecision.Standard, FloatMode.Fast, CompileSynchronously = true)]
private struct UpdateFractalLevelJob : IJobFor private struct UpdateFractalLevelJob : IJobFor
{ {
public float spinAngleDelta;
public float scale; public float scale;
public float deltaTime;
[ReadOnly] [ReadOnly]
public NativeArray<FractalPart> parents; public NativeArray<FractalPart> parents;
@ -27,13 +28,34 @@ public class Fractal : MonoBehaviour
{ {
var parent = parents[i / 5]; var parent = parents[i / 5];
var part = parts[i]; var part = parts[i];
part.spinAngle += spinAngleDelta; part.spinAngle += part.spinVelocity * deltaTime;
part.worldRotation = mul(parent.worldRotation,
float3 upAxis =
mul(mul(parent.worldRotation, part.rotation), up());
float3 sagAxis = cross(up(), upAxis);
float sagMagnitude = length(sagAxis);
quaternion baseRotation;
if (sagMagnitude > 0f)
{
sagAxis /= sagMagnitude;
quaternion sagRotation =
quaternion.AxisAngle(sagAxis, part.maxSagAngle * sagMagnitude);
baseRotation = mul(sagRotation, parent.worldRotation);
}
else
{
baseRotation = parent.worldRotation;
}
part.worldRotation = mul(baseRotation,
mul(part.rotation, quaternion.RotateY(part.spinAngle)) mul(part.rotation, quaternion.RotateY(part.spinAngle))
); );
part.worldPosition = part.worldPosition =
parent.worldPosition + parent.worldPosition +
mul(parent.worldRotation, 1.5f * scale * part.direction); mul(part.worldRotation, float3(0f, 1.5f * scale, 0f));
parts[i] = part; parts[i] = part;
float3x3 r = float3x3(part.worldRotation) * scale; float3x3 r = float3x3(part.worldRotation) * scale;
@ -43,24 +65,39 @@ public class Fractal : MonoBehaviour
private struct FractalPart private struct FractalPart
{ {
public float3 direction, worldPosition; public float3 worldPosition;
public quaternion rotation, worldRotation; public quaternion rotation, worldRotation;
public float spinAngle; public float maxSagAngle, spinAngle, spinVelocity;
} }
NativeArray<FractalPart>[] parts; NativeArray<FractalPart>[] parts;
NativeArray<float3x4>[] matrices; NativeArray<float3x4>[] matrices;
[SerializeField, Range(1, 8)] [SerializeField, Range(3, 8)]
int depth = 4; int depth = 4;
[SerializeField] [SerializeField]
Mesh mesh = default; Mesh mesh = default, leafMesh = default;
[SerializeField] [SerializeField]
Material material = default; Material material = default;
[SerializeField]
Gradient gradientA = default, gradientB = default;
[SerializeField]
Color leafColorA = default, leafColorB = default;
[SerializeField, Range(0f, 90f)]
float maxSagAngleA = 15f, maxSagAngleB = 25f;
[SerializeField, Range(0f, 90f)]
float spinSpeedA = 20f, spinSpeedB = 25f;
[SerializeField, Range(0f, 1f)]
float reverseSpinChance = 0.25f;
static float3[] directions = static float3[] directions =
{ {
up(), right(), left(), forward(), back() up(), right(), left(), forward(), back()
@ -77,14 +114,22 @@ public class Fractal : MonoBehaviour
{ {
return new FractalPart() return new FractalPart()
{ {
direction = directions[childIndex], maxSagAngle = radians(Random.Range(maxSagAngleA, maxSagAngleB)),
rotation = rotations[childIndex] rotation = rotations[childIndex],
spinVelocity =
(Random.value < reverseSpinChance ? -1f : 1f) *
radians(Random.Range(spinSpeedA, spinSpeedB))
}; };
} }
ComputeBuffer[] matricesBuffers; ComputeBuffer[] matricesBuffers;
Vector4[] sequenceNumbers;
static readonly int colorAId = Shader.PropertyToID("_ColorA");
static readonly int colorBId = Shader.PropertyToID("_ColorB");
static readonly int matricesId = Shader.PropertyToID("_Matrices"); static readonly int matricesId = Shader.PropertyToID("_Matrices");
static readonly int sequenceNumbersId = Shader.PropertyToID("_SequenceNumbers");
static MaterialPropertyBlock propertyBlock; static MaterialPropertyBlock propertyBlock;
@ -93,12 +138,14 @@ public class Fractal : MonoBehaviour
parts = new NativeArray<FractalPart>[depth]; parts = new NativeArray<FractalPart>[depth];
matrices = new NativeArray<float3x4>[depth]; matrices = new NativeArray<float3x4>[depth];
matricesBuffers = new ComputeBuffer[depth]; matricesBuffers = new ComputeBuffer[depth];
sequenceNumbers = new Vector4[depth];
int stride = 12 * 4; int stride = 12 * 4;
for (int i = 0, length = 1; i < parts.Length; i++, length *= 5) for (int i = 0, length = 1; i < parts.Length; i++, length *= 5)
{ {
parts[i] = new NativeArray<FractalPart>(length, Allocator.Persistent); parts[i] = new NativeArray<FractalPart>(length, Allocator.Persistent);
matrices[i] = new NativeArray<float3x4>(length, Allocator.Persistent); matrices[i] = new NativeArray<float3x4>(length, Allocator.Persistent);
matricesBuffers[i] = new ComputeBuffer(length, stride); matricesBuffers[i] = new ComputeBuffer(length, stride);
sequenceNumbers[i] = new Vector4(Random.value, Random.value, Random.value, Random.value);
} }
parts[0][0] = CreatePart(0); parts[0][0] = CreatePart(0);
@ -131,6 +178,7 @@ public class Fractal : MonoBehaviour
parts = null; parts = null;
matrices = null; matrices = null;
matricesBuffers = null; matricesBuffers = null;
sequenceNumbers = null;
} }
void OnValidate() void OnValidate()
@ -144,9 +192,9 @@ public class Fractal : MonoBehaviour
private void Update() private void Update()
{ {
float spinAngleDelta = 0.125f * PI * Time.deltaTime; float deltaTime = Time.deltaTime;
FractalPart rootPart = parts[0][0]; FractalPart rootPart = parts[0][0];
rootPart.spinAngle += spinAngleDelta; rootPart.spinAngle += rootPart.spinVelocity * deltaTime;
rootPart.worldRotation = mul(transform.rotation, rootPart.worldRotation = mul(transform.rotation,
mul(rootPart.rotation, quaternion.RotateY(rootPart.spinAngle)) mul(rootPart.rotation, quaternion.RotateY(rootPart.spinAngle))
); );
@ -163,7 +211,7 @@ public class Fractal : MonoBehaviour
scale *= 0.5f; scale *= 0.5f;
jobHandle = new UpdateFractalLevelJob jobHandle = new UpdateFractalLevelJob
{ {
spinAngleDelta = spinAngleDelta, deltaTime = deltaTime,
scale = scale, scale = scale,
parents = parts[li - 1], parents = parts[li - 1],
parts = parts[li], parts = parts[li],
@ -173,12 +221,33 @@ public class Fractal : MonoBehaviour
jobHandle.Complete(); jobHandle.Complete();
var bounds = new Bounds(rootPart.worldPosition, float3(3f * objectScale)); var bounds = new Bounds(rootPart.worldPosition, float3(3f * objectScale));
int leafIndex = matricesBuffers.Length - 1;
for (int i = 0; i < matricesBuffers.Length; i++) for (int i = 0; i < matricesBuffers.Length; i++)
{ {
Mesh instanceMesh;
Color colorA, colorB;
if (i == leafIndex)
{
colorA = leafColorA;
colorB = leafColorB;
instanceMesh = leafMesh;
}
else
{
colorA = gradientA.Evaluate(i / (matricesBuffers.Length - 2f));
colorB = gradientB.Evaluate(i / (matricesBuffers.Length - 2f));
instanceMesh = mesh;
}
propertyBlock.SetColor(colorAId, colorA);
propertyBlock.SetColor(colorBId, colorB);
ComputeBuffer buffer = matricesBuffers[i]; ComputeBuffer buffer = matricesBuffers[i];
buffer.SetData(matrices[i]); buffer.SetData(matrices[i]);
float gradientInterpolator = i / (matricesBuffers.Length - 1f);
propertyBlock.SetColor(colorAId, gradientA.Evaluate(gradientInterpolator));
propertyBlock.SetColor(colorBId, gradientB.Evaluate(gradientInterpolator));
propertyBlock.SetBuffer(matricesId, buffer); propertyBlock.SetBuffer(matricesId, buffer);
Graphics.DrawMeshInstancedProcedural(mesh, 0, material, bounds, buffer.count, propertyBlock); propertyBlock.SetVector(sequenceNumbersId, sequenceNumbers[i]);
Graphics.DrawMeshInstancedProcedural(instanceMesh, 0, material, bounds, buffer.count, propertyBlock);
} }
} }
} }

View File

@ -2,6 +2,27 @@
StructuredBuffer<float3x4> _Matrices; StructuredBuffer<float3x4> _Matrices;
#endif #endif
float4 _ColorA, _ColorB;
float4 _SequenceNumbers;
float4 GetFractalColor () {
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
float4 color;
color.rgb = lerp(
_ColorA.rgb, _ColorB.rgb,
frac(unity_InstanceID * _SequenceNumbers.x + _SequenceNumbers.y)
);
color.a = lerp(
_ColorA.a, _ColorB.a,
frac(unity_InstanceID * _SequenceNumbers.z + _SequenceNumbers.w)
);
return color;
#else
return _ColorA;
#endif
}
void ConfigureProcedural () { void ConfigureProcedural () {
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED) #if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
float3x4 m = _Matrices[unity_InstanceID]; float3x4 m = _Matrices[unity_InstanceID];
@ -12,10 +33,12 @@ void ConfigureProcedural () {
#endif #endif
} }
void ShaderGraphFunction_float (float3 In, out float3 Out) { void ShaderGraphFunction_float (float3 In, out float3 Out, out float4 FractalColor) {
Out = In; Out = In;
FractalColor = GetFractalColor();
} }
void ShaderGraphFunction_half (half3 In, out half3 Out) { void ShaderGraphFunction_half (half3 In, out half3 Out, out half4 FractalColor) {
Out = In; Out = In;
FractalColor = GetFractalColor();
} }