void OnEnable() { parts = new FractalPart[depth][]; matrices = new Matrix4x4[depth][]; matricesBuffers = new ComputeBuffer[depth]; int stride = 16 * 4; for (int i = 0, length = 1; i < parts.Length; i++, length *= 5) { parts[i] = new FractalPart[length]; matrices[i] = new Matrix4x4[length]; matricesBuffers[i] = new ComputeBuffer(length, stride); } parts[0][0] = CreatePart(0); for (int li = 1; li < parts.Length; li++) { FractalPart[] levelParts = parts[li]; // loop through 4 directions for (int fpi = 0; fpi < levelParts.Length; fpi += 5) { for (int ci = 0; ci < 5; ci++) { levelParts[fpi + ci] = CreatePart(ci); } } } }
private void OnEnable() { parts = new FractalPart[depth][]; matrices = new Matrix4x4[depth][]; matricesBuffers = new ComputeBuffer[depth]; int stride = 16 * 4; for (int i = 0, length = 1; i < parts.Length; i++, length *= 5) { parts[i] = new FractalPart[length]; matrices[i] = new Matrix4x4[length]; matricesBuffers[i] = new ComputeBuffer(length, stride); } parts[0][0] = CreatePart(0); 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++) { levelParts[fpi + ci] = CreatePart(ci); } } } if (propertyBlock == null) { propertyBlock = new MaterialPropertyBlock(); } }
public void Execute(int i) { FractalPart parent = parents[i / 5]; FractalPart part = parts[i]; part.spinAngle += part.spinVelocity * deltaTime; 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)) ); part.worldPosition = parent.worldPosition + mul(part.worldRotation, float3(0f, 1.5f * scale, 0f)); parts[i] = part; float3x3 r = float3x3(part.worldRotation) * scale; matrices[i] = float3x4(r.c0, r.c1, r.c2, part.worldPosition); }
private void OnEnable() { parts = new FractalPart[depth][]; matrices = new Matrix4x4[depth][]; matricesBuffers = new ComputeBuffer[depth]; propertyBlock ??= new MaterialPropertyBlock(); int stride = 16 * 4; // Matrix -> 16 float -> 16 *4 bytes for (int i = 0, length = 1; i < depth; i++, length *= 5) { parts[i] = new FractalPart[length]; matrices[i] = new Matrix4x4[length]; matricesBuffers[i] = new ComputeBuffer(length, stride); } parts[0][0] = CreatePart(0); for (int li = 1; li != depth; ++li) { FractalPart[] levelParts = parts[li]; for (int fpi = 0; fpi < levelParts.Length; fpi += 5) // 5 Fractal part is one group { for (int ci = 0; ci != 5; ++ci) { levelParts[fpi + ci] = CreatePart(ci); } } } }
void Update() { var deltaRotation = Quaternion.Euler(0f, 22.5f * Time.deltaTime, 0f); FractalPart rootPart = parts[0][0]; rootPart.rotation *= deltaRotation; rootPart.transform.localRotation = rootPart.rotation; parts[0][0] = rootPart; for (int li = 1; li < parts.Length; li++) { FractalPart[] parentParts = parts[li - 1]; FractalPart[] levelParts = parts[li]; for (int fpi = 0; fpi < levelParts.Length; fpi++) { Transform parentTransform = parentParts[fpi / 5].transform; FractalPart part = levelParts[fpi]; { part.rotation *= deltaRotation; part.transform.localRotation = parentTransform.localRotation * part.rotation; part.transform.localPosition = parentTransform.localPosition + parentTransform.localRotation * (1.5f * part.transform.localScale.x * part.direction); } levelParts[fpi] = part; } } }
private void Awake() { parts = new FractalPart[depth][]; parts[0] = new FractalPart[1]; for (int i = 0, size = 0; i < parts.Length; i++, size *= 5) { parts[i] = new FractalPart[size]; } CreatePart(0); }
private void Update() { float spinAngleDelta = 22.5f * Time.deltaTime; FractalPart rootPart = parts[0][0]; float objectScale = transform.lossyScale.x; matrices[0][0] = Matrix4x4.TRS( rootPart.worldPosition, rootPart.worldRotation, objectScale * Vector3.one ); float scale = objectScale; rootPart.spinAngle += spinAngleDelta; rootPart.worldRotation = rootPart.rotation * Quaternion.Euler(0f, rootPart.spinAngle, 0f); parts[0][0] = rootPart; for (int li = 1; li < parts.Length; li++) { scale *= 0.5f; FractalPart[] parentParts = parts[li - 1]; FractalPart[] levelParts = parts[li]; Matrix4x4[] levelMatrices = matrices[li]; for (int fpi = 0; fpi < levelParts.Length; fpi++) { FractalPart parent = parentParts[fpi / 5]; FractalPart part = levelParts[fpi]; part.spinAngle += spinAngleDelta; rootPart.worldRotation = transform.rotation * (rootPart.rotation * Quaternion.Euler(0f, rootPart.spinAngle, 0f)); rootPart.worldPosition = transform.position; levelParts[fpi] = part; levelMatrices[fpi] = Matrix4x4.TRS( part.worldPosition, part.worldRotation, scale * Vector3.one ); } } 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 ); } }
public void Execute(int i) { FractalPart parent = parents[i / 5]; FractalPart 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 void OnEnable() { if (propertyBlock == null) { propertyBlock = new MaterialPropertyBlock(); } parts = new NativeArray <FractalPart> [depth]; matrices = new NativeArray <float4x4> [depth]; matricesBuffers = new ComputeBuffer[depth]; int size = 1; int stride = 16 * 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 <float4x4>(length, Allocator.Persistent); matricesBuffers[i] = new ComputeBuffer(length, stride); size *= 5; } FractalPart rootPart = CreatePart(0); parts[0][0] = rootPart; rootPart.worldRotation = mul(transform.rotation, mul(rootPart.rotation, quaternion.RotateY(rootPart.spinAngle)) ); rootPart.worldPosition = transform.position; matrices[0][0] = float4x4.TRS( rootPart.worldPosition, rootPart.worldRotation, float3(ObjectScale)); for (int li = 1; li < parts.Length; li++) { NativeArray <FractalPart> parentParts = parts[li - 1]; NativeArray <FractalPart> levelParts = parts[li]; NativeArray <float4x4> levelMatrices = matrices[li]; for (int fpi = 0; fpi < levelParts.Length; fpi += 5) { for (int ci = 0; ci < 5; ci++) { levelParts[fpi + ci] = CreatePart(ci); } } } }
//Callback to UI thread private async void generateCallback(FractalPart part) { //Add generated fractal part to the UI await main.fractalgenerator.addFractalPartToUIAsync(part); //Add log entry with thread number log.Text += "\nThread: " + part.getPos() + " is done"; threadDone++; //Check if count of done threads equals amount of threads in generator if (threadDone == main.fractalgenerator.getTemplate().getNrOfThreads()) { //When all threads done stop the stopwatch and display the final time stopwatch.Stop(); log.Text += "\n\nTotal time to draw: " + stopwatch.Elapsed.ToString(); } }
void Update() { float spinAngleDelta = 22.5f * Time.deltaTime; FractalPart rootPart = parts[0][0]; rootPart.spinAngle += spinAngleDelta; rootPart.worldRotation = rootPart.rotation * Quaternion.Euler(0f, rootPart.spinAngle, 0f); parts[0][0] = rootPart; matrices[0][0] = Matrix4x4.TRS( rootPart.worldPosition, rootPart.worldRotation, Vector3.one ); float scale = 1f; for (int li = 1; li < parts.Length; li++) { scale *= 0.5f; FractalPart[] parentParts = parts[li - 1]; FractalPart[] levelParts = parts[li]; Matrix4x4[] levelMatrices = matrices[li]; for (int fpi = 0; fpi < levelParts.Length; fpi++) { FractalPart parent = parentParts[fpi / 5]; FractalPart part = levelParts[fpi]; 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); levelParts[fpi] = part; levelMatrices[fpi] = Matrix4x4.TRS( part.worldPosition, part.worldRotation, scale * Vector3.one ); } } for (int i = 0; i < matricesBuffers.Length; i++) { matricesBuffers[i].SetData(matrices[i]); } }
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); // job을 계속 등록. } jobHandle.Complete(); // 등록된 job을 일괄 계산. var bounds = new Bounds(rootPart.worldPosition, 3f * objectScale * Vector3.one); bounds.extents = Vector3.one * 0.5f; 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 ); } }
private void Update() { float spinAngleDelta = 22.5f * Time.deltaTime; FractalPart rootPart = parts[0][0]; rootPart.spinAngle += spinAngleDelta; rootPart.worldRotation = transform.rotation * (rootPart.rotation * Quaternion.Euler(0f, rootPart.spinAngle, 0f)); parts[0][0] = rootPart; // FractalPart is struct, thus have to reassign to copy the value float objectScale = transform.localScale.x; matrices[0][0] = Matrix4x4.TRS(rootPart.worldPosition, rootPart.worldRotation, objectScale * Vector3.one); float scale = objectScale; for (int li = 1; li != depth; ++li) { scale *= 0.5f; FractalPart[] parentParts = parts[li - 1]; FractalPart[] levelParts = parts[li]; Matrix4x4[] levelMatrices = matrices[li]; for (int fpi = 0; fpi < levelParts.Length; fpi++) { FractalPart parent = parentParts[fpi / 5]; FractalPart part = levelParts[fpi]; 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); levelParts[fpi] = part; levelMatrices[fpi] = Matrix4x4.TRS(part.worldPosition, part.worldRotation, scale * Vector3.one); } } Bounds 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); } }
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)) ); parts[0][0] = rootPart; 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, 1, jobHandle); } jobHandle.Complete(); var bounds = new Bounds(Vector3.zero, 3f * ObjectScale * Vector3.one); for (int i = 0; i < matricesBuffers.Length; i++) { ComputeBuffer buffer = matricesBuffers[i]; buffer.SetData(matrices[i]); propertyBlock.SetBuffer(matricesId, buffer); material.SetBuffer(matricesId, buffer); Graphics.DrawMeshInstancedProcedural(mesh, 0, material, bounds, buffer.count, propertyBlock); } }
// 将Awake改为OnEnable,为了在OnDisable时释放缓冲区 void OnEnable() { parts = new FractalPart[depth][]; matrices = new Matrix4x4[depth][]; matricesBuffers = new ComputeBuffer[depth]; // 4x4的矩阵有16个字节 int stride = 16 * 4; for (int i = 0, len = 1; i < depth; ++i, len *= 5) { parts[i] = new FractalPart[len]; matrices[i] = new Matrix4x4[len]; matricesBuffers[i] = new ComputeBuffer(len, stride); } /* 长度 * 深度0 1 * 深度1 5 * 深度2 25 * 深度3 125 */ // 创建根节点 parts[0][0] = CreatePart(0); // 创建所有子节点 for (int li = 1; li < depth; li++) { // 拿到那层的数组 var 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(); } }
public void Execute(int i) { FractalPart parent = parents[i / 5]; FractalPart 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; matrices[i] = float4x4.TRS( part.worldPosition, part.worldRotation, scale * Vector3.one ); }
public void Execute(int index) { FractalPart parent = parents[index / 5]; FractalPart part = parts[index]; 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[index] = part; // Bacause there is no TRS method for float3x4, so we have to // assemble the matri float3x3 r = float3x3(part.worldRotation) * scale; matrices[index] = float3x4(r.c0, r.c1, r.c2, part.worldPosition); }
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))); parts[0][0] = rootPart; // FractalPart is struct, thus have to reassign to copy the value float objectScale = transform.localScale.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 != depth; ++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, 10, jobHandle); } jobHandle.Complete(); Bounds 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); } }
public override int[,] calculate(FractalPart fa) { int w; //set max pixel value range from 0-255 int w_max = 255; int[,] pixels = new int[fa.getWidth(), fa.getHeight()]; double dx = (fa.x2 - fa.x1) / fa.getWidth(); double dy = (fa.y2 - fa.y1) / fa.getHeight(); double cr, ci, zr, zi, zr2, zi2, zrt; // For every pixel width x height of this FractalPart for (int Xcount = 0; Xcount < fa.getWidth(); Xcount++) { for (int Ycount = 0; Ycount < fa.getHeight(); Ycount++) { cr = fa.x1 + dx * Xcount; ci = fa.y1 + dy * Ycount; w = 0; zr = 0; zi = 0; zr2 = 0; zi2 = 0; // Calculate fractal while (((zr2 + zi2) < 4) && (w < w_max)) { zrt = zr2 - zi2 + cr; zi = 2 * zr * zi + ci; zr = zrt; zr2 = Math.Pow(zr, 2); zi2 = Math.Pow(zi, 2); w++; } pixels[Xcount, Ycount] = (w < w_max) ? w : w_max; } } return(pixels); }
public override int[,] calculate(FractalPart fa) { int w; //Max pixel value range 0-255 int w_max = 255; int[,] pixels = new int[fa.getWidth(), fa.getHeight()]; //real and imaginary part of the constant c, determinate shape of the Julia Set double cX, cY; double zx, zy; // The JuliaSet requires a Constant to draw wheras the MandleBrot recalculates this value. cX = -0.7; cY = -0.27015; // Loop through each for (int Xcount = 0; Xcount < fa.getWidth(); Xcount++) { for (int Ycount = 0; Ycount < fa.getHeight(); Ycount++) { w = 0; // Sets the actual value. zx = (fa.x2 - fa.x1) * (Xcount - fa.getWidth() / 2) / (0.5 * fa.getWidth()); zy = (fa.y2 - fa.y1) * (Ycount - fa.getHeight() / 2) / (0.5 * fa.getHeight()); // Calculate w to fill in the pixels. while (zx * zx + (zy * zy) < 4 && w < w_max) { double tmp = zx * zx - zy * zy + cX; zy = 2.0 * zx * zy + cY; zx = tmp; w++; } pixels[Xcount, Ycount] = (w < w_max) ? w : w_max; } } return(pixels); }
private void Awake() { parts = new FractalPart[depth][]; for (int i = 0, length = 1; i < depth; i++, length *= 5) { parts[i] = new FractalPart[length]; } float scale = 1.0f; parts[0][0] = CreatePart(0, 0, scale); for (int li = 1; li != depth; ++li) { scale *= 0.5f; FractalPart[] levelParts = parts[li]; for (int fpi = 0; fpi < levelParts.Length; fpi += 5) // 5 Fractal part is one group { for (int ci = 0; ci != 5; ++ci) { levelParts[fpi + ci] = CreatePart(li, ci, scale); } } } }
private void Update() { Quaternion deltaRotation = Quaternion.Euler(0f, 22.5f * Time.deltaTime, 0f); FractalPart rootPart = parts[0][0]; rootPart.rotation *= deltaRotation; rootPart.transform.localRotation = rootPart.rotation; parts[0][0] = rootPart; // FractalPart is struct, thus have to reassign to copy the value for (int li = 1; li != depth; ++li) { FractalPart[] parentParts = parts[li - 1]; FractalPart[] levelParts = parts[li]; for (int fpi = 0; fpi < levelParts.Length; fpi++) { Transform parentTransform = parentParts[fpi / 5].transform; FractalPart part = levelParts[fpi]; part.rotation *= deltaRotation; part.transform.localRotation = parentTransform.localRotation * part.rotation; part.transform.localPosition = parentTransform.localPosition + parentTransform.localRotation * (1.5f * part.transform.localScale.x * part.direction); levelParts[fpi] = part; } } }
private void Awake() { parts = new FractalPart[depth][]; for (int i = 0, length = 1; i < parts.Length; i++, length *= 5) { parts[i] = new FractalPart[length]; } float scale = 1f; parts[0][0] = CreatePart(0, 0, scale); for (int li = 1; li < parts.Length; li++) { scale *= 0.5f; FractalPart[] levelParts = parts[li]; for (int fpi = 0; fpi < levelParts.Length; fpi += 5) { for (int ci = 0; ci < 5; ci++) { levelParts[fpi + ci] = CreatePart(li, ci, scale); } } } }
public abstract int[,] calculate(FractalPart fa);
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))); parts[0][0] = rootPart; // FractalPart is struct, thus have to reassign to copy the value float objectScale = transform.localScale.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 != depth; ++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, 10, jobHandle); } jobHandle.Complete(); int leafIndex = matricesBuffers.Length - 1; Bounds bounds = new Bounds(rootPart.worldPosition, 3f * objectScale * Vector3.one); for (int i = 0; i < matricesBuffers.Length; ++i) { Color colorA, colorB = default; Mesh instanceMesh = null; if (i == leafIndex) { colorA = leafColorA; colorB = leafColorB; instanceMesh = leafMesh; } else { float gradientInterpolate = i / (matricesBuffers.Length - 1.0f); colorA = gradientA.Evaluate(gradientInterpolate); colorB = gradientB.Evaluate(gradientInterpolate); instanceMesh = mesh; } ComputeBuffer buffer = matricesBuffers[i]; buffer.SetData(matrices[i]); propertyBlock.SetColor(colorAID, colorA); propertyBlock.SetColor(colorBID, colorB); propertyBlock.SetBuffer(matricesId, buffer); propertyBlock.SetVector(sequenceNumbersId, sequenceNumbers[i]); Graphics.DrawMeshInstancedProcedural(instanceMesh, 0, material, bounds, buffer.count, propertyBlock); } }
void Update() { float deltaTime = Time.deltaTime; FractalPart rootPart = parts[0][0]; rootPart.spinAngle += rootPart.spinVelocity * deltaTime; 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 { deltaTime = deltaTime, scale = scale, parents = parts[li - 1], parts = parts[li], matrices = matrices[li] }.ScheduleParallel(parts[li].Length, 5, jobHandle); } jobHandle.Complete(); var bounds = new Bounds(Vector3.zero, 3f * objectScale * Vector3.one); int leafIndex = matricesBuffers.Length - 1; for (int i = 0; i < matricesBuffers.Length; i++) { ComputeBuffer buffer = matricesBuffers[i]; buffer.SetData(matrices[i]); Color colorA, colorB; Mesh instanceMesh; if (i == leafIndex) { colorA = leafColorA; colorB = leafColorB; instanceMesh = leafMesh; } else { float gradientInterpolator = i / (matricesBuffers.Length - 2f); colorA = gradientA.Evaluate(gradientInterpolator); colorB = gradientB.Evaluate(gradientInterpolator); instanceMesh = mesh; } propertyBlock.SetColor(colorAId, colorA); propertyBlock.SetColor(colorBId, colorB); propertyBlock.SetBuffer(matricesId, buffer); propertyBlock.SetVector(sequenceNumbersId, sequenceNumbers[i]); Graphics.DrawMeshInstancedProcedural( instanceMesh, 0, material, bounds, buffer.count, propertyBlock); } }