create collision parts for water

This commit is contained in:
in0finite 2022-02-22 04:38:01 +01:00
parent 30b9d56e36
commit 6185f7089f
4 changed files with 163 additions and 19 deletions

View file

@ -0,0 +1,47 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1851338461656571883
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7995634715881356742}
- component: {fileID: 8546980230320474744}
m_Layer: 4
m_Name: WaterCollision
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7995634715881356742
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1851338461656571883}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!64 &8546980230320474744
MeshCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1851338461656571883}
m_Material: {fileID: 0}
m_IsTrigger: 1
m_Enabled: 1
serializedVersion: 4
m_Convex: 1
m_CookingOptions: 30
m_Mesh: {fileID: 0}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e6c6e08b2f4ea5146acb88b9f1fd1529
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -691,6 +691,11 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
WaterPrefab: {fileID: 100000, guid: 780611a67e8e941a2b3aa96e5915a793, type: 3}
m_waterCollisionPrefab: {fileID: 1851338461656571883, guid: e6c6e08b2f4ea5146acb88b9f1fd1529,
type: 3}
m_createCollisionObjects: 1
m_renderingObjects: []
m_collisionObjects: []
--- !u!1 &1000405462072482
GameObject:
m_ObjectHideFlags: 0

View file

@ -1,6 +1,7 @@
using SanAndreasUnity.Importing.Items;
using SanAndreasUnity.Importing.Items.Placements;
using SanAndreasUnity.Utilities;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@ -9,6 +10,12 @@ namespace SanAndreasUnity.Behaviours.World
public class Water : MonoBehaviour
{
public GameObject WaterPrefab;
[SerializeField] private GameObject m_waterCollisionPrefab;
[SerializeField] private bool m_createCollisionObjects = false;
[HideInInspector] [SerializeField] private List<Transform> m_renderingObjects = new List<Transform>();
[HideInInspector] [SerializeField] private List<Transform> m_collisionObjects = new List<Transform>();
public void Initialize(WaterFile file, Vector2 worldSize)
@ -43,22 +50,7 @@ namespace SanAndreasUnity.Behaviours.World
foreach (var face in faces)
{
for (int j = 0; j < face.Vertices.Length; j++)
{
vertices[verticesIndex + j] = face.Vertices[j].Position;
normals[verticesIndex + j] = Vector3.up;
}
for (var j = 0; j < face.Vertices.Length - 2; ++j)
{
var flip = j & 1;
indices[indicesIndex + j * 3 + 0] = verticesIndex + j + 1 - flip;
indices[indicesIndex + j * 3 + 1] = verticesIndex + j + 0 + flip;
indices[indicesIndex + j * 3 + 2] = verticesIndex + j + 2;
}
verticesIndex += face.Vertices.Length;
indicesIndex += (face.Vertices.Length - 2) * 3;
ProcessFace(face, vertices, normals, ref verticesIndex, indices, ref indicesIndex);
}
// add "infinite" water
@ -107,7 +99,9 @@ namespace SanAndreasUnity.Behaviours.World
mesh.normals = normals;
mesh.SetIndices(indices, MeshTopology.Triangles, 0);
var availableObjects = this.transform.GetFirstLevelChildren().ToQueueWithCapacity(this.transform.childCount);
m_renderingObjects.RemoveDeadObjects();
var availableObjects = m_renderingObjects.ToQueueWithCapacity(m_renderingObjects.Count);
var go = availableObjects.Count > 0
? availableObjects.Dequeue().gameObject
@ -116,7 +110,7 @@ namespace SanAndreasUnity.Behaviours.World
go.transform.localPosition = Vector3.zero;
go.transform.localRotation = Quaternion.identity;
go.name = "Water mesh";
go.name = "Water rendering mesh";
mesh.name = go.name;
var meshFilter = go.GetComponentOrThrow<MeshFilter>();
@ -126,7 +120,98 @@ namespace SanAndreasUnity.Behaviours.World
foreach (var availableObject in availableObjects)
F.DestroyEvenInEditMode(availableObject.gameObject);
m_renderingObjects.Clear();
m_renderingObjects.Add(go.transform);
if (m_createCollisionObjects)
CreateCollisionObjects(faces);
}
void ProcessFace(WaterFace face, Vector3[] vertices, Vector3[] normals, ref int verticesIndex, int[] indices, ref int indicesIndex)
{
for (int j = 0; j < face.Vertices.Length; j++)
{
vertices[verticesIndex + j] = face.Vertices[j].Position;
normals[verticesIndex + j] = Vector3.up;
}
for (var j = 0; j < face.Vertices.Length - 2; ++j)
{
var flip = j & 1;
indices[indicesIndex + j * 3 + 0] = verticesIndex + j + 1 - flip;
indices[indicesIndex + j * 3 + 1] = verticesIndex + j + 0 + flip;
indices[indicesIndex + j * 3 + 2] = verticesIndex + j + 2;
}
verticesIndex += face.Vertices.Length;
indicesIndex += (face.Vertices.Length - 2) * 3;
}
void CreateCollisionObjects(IEnumerable<WaterFace> faces)
{
if (null == m_waterCollisionPrefab)
{
Debug.LogError("Water collision prefab not set");
return;
}
m_collisionObjects.RemoveDeadObjects();
var availableObjects = m_collisionObjects.ToQueueWithCapacity(m_collisionObjects.Count);
m_collisionObjects.Clear();
int i = 0;
foreach (var face in faces)
{
Vector3[] vertices = new Vector3[face.Vertices.Length];
Vector3[] normals = new Vector3[face.Vertices.Length];
int numIndices = (face.Vertices.Length - 2) * 3;
int[] indices = new int[numIndices];
int verticesIndex = 0;
int indicesIndex = 0;
ProcessFace(face, vertices, normals, ref verticesIndex, indices, ref indicesIndex);
Vector3 center = Vector3.zero;
vertices.ForEach(v => center += v / vertices.Length);
for (int v = 0; v < vertices.Length; v++)
vertices[v] = vertices[v] - center;
var mesh = new Mesh();
mesh.vertices = vertices;
mesh.normals = normals;
mesh.SetIndices(indices, MeshTopology.Triangles, 0);
mesh.name = $"Water collision mesh {i}";
GameObject go = availableObjects.Count > 0
? availableObjects.Dequeue().gameObject
: Instantiate(m_waterCollisionPrefab, this.transform);
go.name = mesh.name;
go.transform.localPosition = center;
go.transform.localRotation = Quaternion.identity;
var meshCollider = go.GetComponentOrThrow<MeshCollider>();
if (meshCollider.sharedMesh != null && !EditorUtilityEx.IsAsset(meshCollider.sharedMesh))
F.DestroyEvenInEditMode(meshCollider.sharedMesh);
meshCollider.sharedMesh = mesh;
m_collisionObjects.Add(go.transform);
i++;
}
foreach (var availableObject in availableObjects)
F.DestroyEvenInEditMode(availableObject.gameObject);
}
void CreateQuad(Vector2 min, Vector2 max, Vector3[] vertexes, Vector3[] normals, ref int vertexIndex, int[] indexes, ref int indexesIndex)