#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS) using UnityEngine; using UnityEngine.Rendering; using Unity.Jobs; using Unity.Collections; using Unity.Mathematics; using Unity.Burst; namespace Obi { public class BurstExtrudedRopeRenderSystem : ObiExtrudedRopeRenderSystem { public BurstExtrudedRopeRenderSystem(ObiSolver solver) : base(solver) { } public override void Setup() { base.Setup(); // Initialize each batch: for (int i = 0; i < batchList.Count; ++i) batchList[i].Initialize(layout, false); } public override void Render() { if (pathSmootherSystem == null) return; using (m_RenderMarker.Auto()) { var handles = new NativeArray(batchList.Count, Allocator.Temp); for (int i = 0; i < batchList.Count; ++i) { var batch = batchList[i]; var meshJob = new BuildExtrudedMesh { pathSmootherIndices = pathSmootherIndices.AsNativeArray(), chunkOffsets = pathSmootherSystem.chunkOffsets.AsNativeArray(), frames = pathSmootherSystem.smoothFrames.AsNativeArray(), frameOffsets = pathSmootherSystem.smoothFrameOffsets.AsNativeArray(), frameCounts = pathSmootherSystem.smoothFrameCounts.AsNativeArray(), sectionData = sectionData.AsNativeArray(), sectionOffsets = sectionOffsets.AsNativeArray(), sectionIndices = sectionIndices.AsNativeArray(), vertexOffsets = vertexOffsets.AsNativeArray(), triangleOffsets = triangleOffsets.AsNativeArray(), triangleCounts = triangleCounts.AsNativeArray(), pathData = pathSmootherSystem.pathData.AsNativeArray(), rendererData = rendererData.AsNativeArray(), vertices = batch.vertices, tris = batch.triangles, firstRenderer = batch.firstRenderer }; handles[i] = meshJob.Schedule(batch.rendererCount, 1); } JobHandle.CombineDependencies(handles).Complete(); handles.Dispose(); for (int i = 0; i < batchList.Count; ++i) { var batch = batchList[i]; batch.mesh.SetVertexBufferData(batch.vertices, 0, 0, batch.vertexCount, 0, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds); batch.mesh.SetIndexBufferData(batch.triangles, 0, 0, batch.triangleCount * 3, MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontRecalculateBounds); var rp = batch.renderParams; rp.worldBounds = m_Solver.bounds; Graphics.RenderMesh(rp, batch.mesh, 0, m_Solver.transform.localToWorldMatrix, m_Solver.transform.localToWorldMatrix); } } } [BurstCompile] struct BuildExtrudedMesh : IJobParallelFor { [ReadOnly] public NativeArray pathSmootherIndices; [ReadOnly] public NativeArray chunkOffsets; [ReadOnly] public NativeArray frames; [ReadOnly] public NativeArray frameOffsets; [ReadOnly] public NativeArray frameCounts; [ReadOnly] public NativeArray sectionData; [ReadOnly] public NativeArray sectionOffsets; [ReadOnly] public NativeArray sectionIndices; [ReadOnly] public NativeArray vertexOffsets; [ReadOnly] public NativeArray triangleOffsets; [ReadOnly] public NativeArray triangleCounts; [ReadOnly] public NativeArray rendererData; [ReadOnly] public NativeArray pathData; [NativeDisableParallelForRestriction] public NativeArray vertices; [NativeDisableParallelForRestriction] public NativeArray tris; [ReadOnly] public int firstRenderer; public void Execute(int u) { int k = firstRenderer + u; int s = pathSmootherIndices[k]; float3 vertex = float3.zero; float3 normal = float3.zero; float4 texTangent = float4.zero; int tri = 0; int sectionIndex = 0; int sectionStart = sectionOffsets[sectionIndices[k]]; int sectionSegments = (sectionOffsets[sectionIndices[k] + 1] - sectionStart) - 1; int verticesPerSection = sectionSegments + 1; // the last vertex in each section must be duplicated, due to uv wraparound. float smoothLength = 0; for (int i = chunkOffsets[s]; i < chunkOffsets[s + 1]; ++i) smoothLength += pathData[i].smoothLength; float vCoord = -rendererData[k].uvScale.y * pathData[chunkOffsets[s]].restLength * rendererData[k].uvAnchor; float actualToRestLengthRatio = smoothLength / pathData[chunkOffsets[s]].restLength; int firstVertex = vertexOffsets[k]; int firstTriangle = triangleOffsets[k]; // clear out triangle indices for this rope: for (int i = firstTriangle; i < firstTriangle + triangleCounts[k]; ++i) { int offset = i * 3; tris[offset] = 0; tris[offset+1] = 0; tris[offset+2] = 0; } // for each chunk in the rope: for (int i = chunkOffsets[s]; i < chunkOffsets[s + 1]; ++i) { int firstFrame = frameOffsets[i]; int frameCount = frameCounts[i]; for (int f = 0; f < frameCount; ++f) { // Calculate previous and next curve indices: int prevIndex = firstFrame + math.max(f - 1, 0); int index = firstFrame + f; // advance v texcoord: vCoord += rendererData[k].uvScale.y * (math.distance(frames[index].position, frames[prevIndex].position) / (rendererData[k].normalizeV == 1 ? smoothLength : actualToRestLengthRatio)); // calculate section thickness and scale the basis vectors by it: float sectionThickness = frames[index].thickness * rendererData[k].thicknessScale; // Loop around each segment: int nextSectionIndex = sectionIndex + 1; for (int j = 0; j <= sectionSegments; ++j) { // make just one copy of the section vertex: float2 sectionVertex = sectionData[sectionStart + j]; // calculate normal using section vertex, curve normal and binormal: normal.x = (sectionVertex.x * frames[index].normal.x + sectionVertex.y * frames[index].binormal.x) * sectionThickness; normal.y = (sectionVertex.x * frames[index].normal.y + sectionVertex.y * frames[index].binormal.y) * sectionThickness; normal.z = (sectionVertex.x * frames[index].normal.z + sectionVertex.y * frames[index].binormal.z) * sectionThickness; // offset curve position by normal: vertex.x = frames[index].position.x + normal.x; vertex.y = frames[index].position.y + normal.y; vertex.z = frames[index].position.z + normal.z; // cross(normal, curve tangent) texTangent.xyz = math.cross(normal, frames[index].tangent); texTangent.w = -1; vertices[firstVertex + sectionIndex * verticesPerSection + j] = new ProceduralRopeVertex { pos = vertex, normal = normal, tangent = texTangent, color = frames[index].color, uv = new float2(j / (float)sectionSegments * rendererData[k].uvScale.x, vCoord) }; if (j < sectionSegments && f < frameCount - 1) { int offset = firstTriangle * 3; tris[offset + tri++] = (firstVertex + sectionIndex * verticesPerSection + j); tris[offset + tri++] = (firstVertex + nextSectionIndex * verticesPerSection + j); tris[offset + tri++] = (firstVertex + sectionIndex * verticesPerSection + (j + 1)); tris[offset + tri++] = (firstVertex + sectionIndex * verticesPerSection + (j + 1)); tris[offset + tri++] = (firstVertex + nextSectionIndex * verticesPerSection + j); tris[offset + tri++] = (firstVertex + nextSectionIndex * verticesPerSection + (j + 1)); } } sectionIndex++; } } } } } } #endif