198 lines
8.1 KiB
C#
198 lines
8.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using RebootKit.Engine.Foundation;
|
|
using RebootKit.Engine.Main;
|
|
using TriInspector;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
|
|
namespace RebootReality.jelycho.Ropes {
|
|
public class GutsRenderer : MonoBehaviour {
|
|
[SerializeField] RopesManager m_RopesManager;
|
|
|
|
[SerializeField] float m_RenderDistance = 100.0f;
|
|
|
|
[SerializeField] Material m_Material;
|
|
|
|
[SerializeField] int m_Layer;
|
|
|
|
[SerializeField] GutMeshGenerationConfig m_GutMeshGenerationConfig = new GutMeshGenerationConfig {
|
|
radius = 0.2f,
|
|
resolution = 16
|
|
};
|
|
|
|
readonly List<Mesh> m_Meshes = new List<Mesh>();
|
|
|
|
[ShowInInspector, TriInspector.ReadOnly]
|
|
int m_RenderCount = 0;
|
|
|
|
void OnDestroy() {
|
|
foreach (Mesh mesh in m_Meshes) {
|
|
Destroy(mesh);
|
|
}
|
|
|
|
m_Meshes.Clear();
|
|
}
|
|
|
|
void LateUpdate() {
|
|
m_RenderCount = 0;
|
|
|
|
for (int ropeIndex = 0; ropeIndex < m_RopesManager.RopesCount; ++ropeIndex) {
|
|
NativeArray<float3> ropePositions = m_RopesManager.PeekRopePositions(ropeIndex);
|
|
if (ropePositions.Length < 2) {
|
|
continue;
|
|
}
|
|
|
|
float distanceSquared = math.distancesq(m_RopesManager.GetRopeBounds(ropeIndex).center,
|
|
RR.MainCamera.transform.position);
|
|
if (distanceSquared > m_RenderDistance * m_RenderDistance) {
|
|
continue;
|
|
}
|
|
|
|
if (!m_RopesManager.IsRopeBoundsInFrustum(ropeIndex, RR.MainCamera)) {
|
|
continue;
|
|
}
|
|
|
|
int vertexCount = m_GutMeshGenerationConfig.resolution * ropePositions.Length;
|
|
int indexCount = m_GutMeshGenerationConfig.resolution * (ropePositions.Length - 1) * 6;
|
|
|
|
GenerateGutVertexDataJob job = new GenerateGutVertexDataJob {
|
|
Config = m_GutMeshGenerationConfig,
|
|
RopePositions = ropePositions,
|
|
Positions = new NativeArray<float3>(vertexCount, Allocator.TempJob),
|
|
Normals = new NativeArray<float3>(vertexCount, Allocator.TempJob),
|
|
UVs0 = new NativeArray<float2>(vertexCount, Allocator.TempJob),
|
|
UVs1 = new NativeArray<float2>(vertexCount, Allocator.TempJob),
|
|
Indices = new NativeArray<int>(indexCount, Allocator.TempJob)
|
|
};
|
|
|
|
job.Schedule().Complete();
|
|
|
|
Mesh mesh = GetOrCreateMesh(ropeIndex);
|
|
|
|
mesh.Clear();
|
|
mesh.SetVertices(job.Positions);
|
|
mesh.SetNormals(job.Normals);
|
|
mesh.SetUVs(0, job.UVs0);
|
|
mesh.SetUVs(1, job.UVs1);
|
|
mesh.SetIndices(job.Indices, MeshTopology.Triangles, 0, false);
|
|
|
|
job.Positions.Dispose();
|
|
job.Normals.Dispose();
|
|
job.UVs0.Dispose();
|
|
job.UVs1.Dispose();
|
|
job.Indices.Dispose();
|
|
|
|
Graphics.DrawMesh(mesh,
|
|
transform.localToWorldMatrix,
|
|
m_Material,
|
|
m_Layer,
|
|
null,
|
|
0,
|
|
null,
|
|
UnityEngine.Rendering.ShadowCastingMode.On,
|
|
true);
|
|
|
|
m_RenderCount += 1;
|
|
}
|
|
}
|
|
|
|
Mesh GetOrCreateMesh(int ropeIndex) {
|
|
if (ropeIndex < m_Meshes.Count) {
|
|
return m_Meshes[ropeIndex];
|
|
}
|
|
|
|
Mesh mesh = new Mesh {
|
|
name = $"GutMesh_{ropeIndex}",
|
|
indexFormat = UnityEngine.Rendering.IndexFormat.UInt32
|
|
};
|
|
mesh.MarkDynamic();
|
|
m_Meshes.Add(mesh);
|
|
return mesh;
|
|
}
|
|
|
|
[BurstCompile]
|
|
struct GenerateGutVertexDataJob : IJob {
|
|
[Unity.Collections.ReadOnly] public GutMeshGenerationConfig Config;
|
|
[Unity.Collections.ReadOnly] public NativeArray<float3> RopePositions;
|
|
|
|
[WriteOnly] public NativeArray<float3> Positions;
|
|
[WriteOnly] public NativeArray<float3> Normals;
|
|
[WriteOnly] public NativeArray<float2> UVs0;
|
|
public NativeArray<float2> UVs1;
|
|
[WriteOnly] public NativeArray<int> Indices;
|
|
|
|
public void Execute() {
|
|
float ropeLength = 0f;
|
|
|
|
for (int ropePositionIndex = 0; ropePositionIndex < RopePositions.Length; ++ropePositionIndex) {
|
|
bool isLast = ropePositionIndex >= RopePositions.Length - 1;
|
|
|
|
float3 start = RopePositions[ropePositionIndex];
|
|
float3 end = isLast ?
|
|
RopePositions[ropePositionIndex - 1] :
|
|
RopePositions[ropePositionIndex + 1];
|
|
|
|
float3 forward = math.normalize(end - start);
|
|
|
|
if (isLast) {
|
|
forward = -forward;
|
|
}
|
|
|
|
float3 right = math.normalize(math.cross(forward, math.abs(forward.x) > 0.99f ? new float3(0, 1, 0) : new float3(1, 0, 0)));
|
|
float3 up = math.cross(forward, right);
|
|
|
|
for (int i = 0; i < Config.resolution; ++i) {
|
|
float angle = (float) i / Config.resolution * math.PI * 2f;
|
|
float3 offset = (math.cos(angle) * right + math.sin(angle) * up) * Config.radius;
|
|
|
|
int vertexIndex = ropePositionIndex * Config.resolution + (i % Config.resolution);
|
|
Positions[vertexIndex] = start + offset;
|
|
Normals[vertexIndex] = math.normalize(offset);
|
|
UVs0[vertexIndex] = new float2((float) i / (Config.resolution - 1),
|
|
ropePositionIndex % 2 == 0 ? 0 : 1);
|
|
UVs1[vertexIndex] = new float2(ropeLength,
|
|
ropeLength);
|
|
}
|
|
|
|
ropeLength += math.distance(start, end);
|
|
}
|
|
|
|
for (int ropePositionIndex = 0; ropePositionIndex < RopePositions.Length; ++ropePositionIndex) {
|
|
for (int i = 0; i < Config.resolution; ++i) {
|
|
int vertexIndex = ropePositionIndex * Config.resolution + (i % Config.resolution);
|
|
UVs1[vertexIndex] = new float2(UVs1[vertexIndex].x,
|
|
ropeLength);
|
|
}
|
|
}
|
|
|
|
int index = 0;
|
|
for (int ropePositionIndex = 0; ropePositionIndex < RopePositions.Length - 1; ++ropePositionIndex) {
|
|
for (int i = 0; i < Config.resolution; ++i) {
|
|
int current = ropePositionIndex * Config.resolution + i;
|
|
int next = ropePositionIndex * Config.resolution + (i + 1) % Config.resolution;
|
|
int currentNextRow = (ropePositionIndex + 1) * Config.resolution + i;
|
|
int nextNextRow = (ropePositionIndex + 1) * Config.resolution + (i + 1) % Config.resolution;
|
|
|
|
Indices[index++] = current;
|
|
Indices[index++] = next;
|
|
Indices[index++] = currentNextRow;
|
|
|
|
Indices[index++] = currentNextRow;
|
|
Indices[index++] = next;
|
|
Indices[index++] = nextNextRow;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
struct GutMeshGenerationConfig {
|
|
[Min(0.01f)] public float radius;
|
|
[Range(3, 64)] public int resolution;
|
|
}
|
|
}
|
|
} |