备份CatanBuilding瘦身独立工程
This commit is contained in:
239
LocalPackages/zzwater/Editor/WaterMesh.cs
Normal file
239
LocalPackages/zzwater/Editor/WaterMesh.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace zz.water.editor
|
||||
{
|
||||
[System.Serializable]
|
||||
public class WaterMesh
|
||||
{
|
||||
public enum Shape
|
||||
{
|
||||
Rectangle,
|
||||
Disk
|
||||
}
|
||||
public Shape shape;
|
||||
|
||||
[FormerlySerializedAs("size")]
|
||||
[Range(10, 1000)]
|
||||
public float scale = 100f;
|
||||
|
||||
[Tooltip("Distance between vertices")]
|
||||
[Range(0.15f, 10f)]
|
||||
public float vertexDistance = 1f;
|
||||
|
||||
public float UVTiling = 1f;
|
||||
|
||||
[Tooltip("Shifts the vertices in a random direction. Definitely use this when using flat shading")]
|
||||
[Range(0f, 1f)]
|
||||
public float noise;
|
||||
|
||||
[Min(0)]
|
||||
[Tooltip("The surface is normally flat, yet vertex displacement on the GPU such as waves can give the surface artificial height." +
|
||||
"\n\nThis can cause a Mesh Renderer to be prematurely culled, despite still actually being visible." +
|
||||
"\n\nThis value adds an artificial amount of height to the generate mesh's bounds, to avoid this from happening.")]
|
||||
public float boundsPadding = 4f;
|
||||
|
||||
/// <summary>
|
||||
/// Generated output mesh. Empty by default, use the Rebuild() function to generate one from the current settings.
|
||||
/// </summary>
|
||||
public Mesh mesh;
|
||||
|
||||
public Mesh Rebuild()
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case Shape.Rectangle: mesh = CreatePlane();
|
||||
break;
|
||||
case Shape.Disk: mesh = CreateCircle();
|
||||
break;
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public static Mesh Create(Shape shape, float size, float vertexDistance, float uvTiling = 1f, float noise = 0f)
|
||||
{
|
||||
WaterMesh waterMesh = new WaterMesh();
|
||||
waterMesh.shape = shape;
|
||||
waterMesh.scale = size;
|
||||
waterMesh.vertexDistance = vertexDistance;
|
||||
waterMesh.UVTiling = uvTiling;
|
||||
waterMesh.noise = noise;
|
||||
|
||||
return waterMesh.Rebuild();
|
||||
}
|
||||
|
||||
// Get the index of point number 'x' in circle number 'c'
|
||||
private int GetPointIndex(int c, int x)
|
||||
{
|
||||
if (c < 0) return 0;
|
||||
|
||||
x = x % ((c + 1) * 6);
|
||||
|
||||
return (3 * c * (c + 1) + x + 1);
|
||||
}
|
||||
|
||||
private Mesh CreateCircle()
|
||||
{
|
||||
Mesh m = new Mesh();
|
||||
m.name = "WaterDisk";
|
||||
|
||||
int subdivisions = Mathf.FloorToInt(scale / vertexDistance);
|
||||
|
||||
float distance = 1f / subdivisions;
|
||||
|
||||
var vertices = new List<Vector3>();
|
||||
var uvs = new List<Vector2>();
|
||||
var uvs2 = new List<Vector2>();
|
||||
vertices.Add(Vector3.zero); //Center
|
||||
var tris = new List<int>();
|
||||
|
||||
// First pass => build vertices
|
||||
for (int loop = 0; loop < subdivisions; loop++)
|
||||
{
|
||||
float angleStep = (Mathf.PI * 2f) / ((loop + 1) * 6);
|
||||
for (int point = 0; point < (loop + 1) * 6; ++point)
|
||||
{
|
||||
Vector3 vPos = new Vector3(
|
||||
Mathf.Sin(angleStep * point) ,
|
||||
0f,
|
||||
Mathf.Cos(angleStep * point));
|
||||
|
||||
UnityEngine.Random.InitState(loop + point);
|
||||
vPos.x += UnityEngine.Random.Range(-noise * 0.01f, noise * 0.01f);
|
||||
vPos.z -= UnityEngine.Random.Range(noise * 0.01f, -noise * 0.01f);
|
||||
|
||||
vertices.Add(vPos * (scale * 0.5f) * distance * (loop + 1));
|
||||
}
|
||||
}
|
||||
|
||||
//Planar mapping
|
||||
for (int i = 0; i < vertices.Count; i++)
|
||||
{
|
||||
uvs.Add(new Vector2(0.5f + (vertices[i].x) * UVTiling,0.5f + (vertices[i].z) * UVTiling));
|
||||
//Lightmap UV's
|
||||
uvs2.Add(new Vector2(0.5f + (vertices[i].x / scale),0.5f + (vertices[i].z / scale)));
|
||||
}
|
||||
|
||||
// Second pass => connect vertices into triangles
|
||||
for (int circ = 0; circ < subdivisions; ++circ)
|
||||
{
|
||||
for (int point = 0, other = 0; point < (circ + 1) * 6; ++point)
|
||||
{
|
||||
if (point % (circ + 1) != 0)
|
||||
{
|
||||
// Create 2 triangles
|
||||
tris.Add(GetPointIndex(circ - 1, other + 1));
|
||||
tris.Add(GetPointIndex(circ - 1, other));
|
||||
tris.Add(GetPointIndex(circ, point));
|
||||
|
||||
tris.Add(GetPointIndex(circ, point));
|
||||
tris.Add(GetPointIndex(circ, point + 1));
|
||||
tris.Add(GetPointIndex(circ - 1, other + 1));
|
||||
++other;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create 1 inverse triangle
|
||||
tris.Add(GetPointIndex(circ, point));
|
||||
tris.Add(GetPointIndex(circ, point + 1));
|
||||
tris.Add(GetPointIndex(circ - 1, other));
|
||||
// Do not move to the next point in the smaller circle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the mesh
|
||||
|
||||
m.SetVertices(vertices);
|
||||
m.SetTriangles(tris, 0);
|
||||
m.RecalculateNormals();
|
||||
m.RecalculateTangents();
|
||||
m.SetUVs(0, uvs);
|
||||
m.SetUVs(1, uvs2);
|
||||
m.colors = new Color[vertices.Count];
|
||||
|
||||
m.bounds = new Bounds(Vector3.zero, new Vector3(scale, boundsPadding, scale));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
private Mesh CreatePlane()
|
||||
{
|
||||
Mesh m = new Mesh();
|
||||
m.name = "WaterPlane";
|
||||
|
||||
scale = Mathf.Max(1f, scale);
|
||||
int subdivisions = Mathf.FloorToInt(scale / vertexDistance);
|
||||
|
||||
int xCount = subdivisions + 1;
|
||||
int zCount = subdivisions + 1;
|
||||
int numTriangles = subdivisions * subdivisions * 6;
|
||||
int numVertices = xCount * zCount;
|
||||
|
||||
Vector3[] vertices = new Vector3[numVertices];
|
||||
Vector2[] uvs = new Vector2[numVertices];
|
||||
Vector2[] uvs2 = new Vector2[numVertices];
|
||||
int[] triangles = new int[numTriangles];
|
||||
Vector4[] tangents = new Vector4[numVertices];
|
||||
Vector3[] normals = new Vector3[numVertices];
|
||||
Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);
|
||||
|
||||
int index = 0;
|
||||
float scaleX = scale / subdivisions;
|
||||
float scaleY = scale / subdivisions;
|
||||
|
||||
float noiseScale = vertexDistance * 0.5f;
|
||||
|
||||
for (int z = 0; z < zCount; z++)
|
||||
{
|
||||
for (int x = 0; x < xCount; x++)
|
||||
{
|
||||
vertices[index] = new Vector3(x * scaleX - (scale * 0.5f), 0f, z * scaleY - (scale * 0.5f));
|
||||
|
||||
UnityEngine.Random.InitState(index);
|
||||
vertices[index].x += UnityEngine.Random.Range(-noise * noiseScale, noise * noiseScale);
|
||||
vertices[index].z -= UnityEngine.Random.Range(noise * noiseScale, -noise * noiseScale);
|
||||
|
||||
tangents[index] = tangent;
|
||||
uvs[index] = new Vector2(0.5f + (vertices[index].x) * UVTiling, 0.5f + (vertices[index].z) * UVTiling);
|
||||
//Lightmap UV's
|
||||
uvs2[index] = new Vector2(0.5f + vertices[index].x / scale, 0.5f + vertices[index].z / scale);
|
||||
normals[index] = Vector3.up;
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
index = 0;
|
||||
for (int z = 0; z < subdivisions; z++)
|
||||
{
|
||||
for (int x = 0; x < subdivisions; x++)
|
||||
{
|
||||
triangles[index] = (z * xCount) + x;
|
||||
triangles[index + 1] = ((z + 1) * xCount) + x;
|
||||
triangles[index + 2] = (z * xCount) + x + 1;
|
||||
|
||||
triangles[index + 3] = ((z + 1) * xCount) + x;
|
||||
triangles[index + 4] = ((z + 1) * xCount) + x + 1;
|
||||
triangles[index + 5] = (z * xCount) + x + 1;
|
||||
index += 6;
|
||||
}
|
||||
}
|
||||
|
||||
m.vertices = vertices;
|
||||
m.triangles = triangles;
|
||||
m.uv = uvs;
|
||||
m.uv2 = uvs2;
|
||||
m.tangents = tangents;
|
||||
m.normals = normals;
|
||||
m.colors = new Color[vertices.Length];
|
||||
m.bounds = new Bounds(Vector3.zero, new Vector3(scale, boundsPadding, scale));
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
LocalPackages/zzwater/Editor/WaterMesh.cs.meta
Normal file
11
LocalPackages/zzwater/Editor/WaterMesh.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf7a83bc3b7bd442a8f8867464fed7cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
135
LocalPackages/zzwater/Editor/WaterMeshImporter.cs
Normal file
135
LocalPackages/zzwater/Editor/WaterMeshImporter.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEngine;
|
||||
|
||||
namespace zz.water.editor
|
||||
{
|
||||
|
||||
[ScriptedImporter(1, FILE_EXTENSION)]
|
||||
public class WaterMeshImporter : ScriptedImporter
|
||||
{
|
||||
private const string FILE_EXTENSION = "zwatermesh";
|
||||
|
||||
[SerializeField] public WaterMesh waterMesh = new WaterMesh();
|
||||
|
||||
public override void OnImportAsset(AssetImportContext context)
|
||||
{
|
||||
waterMesh.Rebuild();
|
||||
context.AddObjectToAsset("mesh", waterMesh.mesh);
|
||||
context.SetMainObject(waterMesh.mesh);
|
||||
}
|
||||
|
||||
//Handles correct behaviour when double-clicking a .watermesh asset assigned to a field
|
||||
//Otherwise the OS prompts to open it
|
||||
[UnityEditor.Callbacks.OnOpenAsset]
|
||||
public static bool OnOpenAsset(int instanceID, int line)
|
||||
{
|
||||
Object target = EditorUtility.InstanceIDToObject(instanceID);
|
||||
|
||||
if (target is Mesh)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(instanceID);
|
||||
|
||||
if (Path.GetExtension(path) != "." + FILE_EXTENSION) return false;
|
||||
|
||||
Selection.activeObject = target;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(WaterMeshImporter))]
|
||||
public class WaterMeshImporterEditor: ScriptedImporterEditor
|
||||
{
|
||||
private SerializedProperty waterMesh;
|
||||
|
||||
private SerializedProperty shape;
|
||||
|
||||
private SerializedProperty scale;
|
||||
private SerializedProperty UVTiling;
|
||||
|
||||
private SerializedProperty vertexDistance;
|
||||
|
||||
private SerializedProperty noise;
|
||||
private SerializedProperty boundsPadding;
|
||||
|
||||
private WaterMeshImporter importer;
|
||||
|
||||
private bool autoApplyChanges;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
importer = (WaterMeshImporter)target;
|
||||
|
||||
waterMesh = serializedObject.FindProperty("waterMesh");
|
||||
|
||||
shape = waterMesh.FindPropertyRelative("shape");
|
||||
scale = waterMesh.FindPropertyRelative("scale");
|
||||
UVTiling = waterMesh.FindPropertyRelative("UVTiling");
|
||||
vertexDistance = waterMesh.FindPropertyRelative("vertexDistance");
|
||||
noise = waterMesh.FindPropertyRelative("noise");
|
||||
boundsPadding = waterMesh.FindPropertyRelative("boundsPadding");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
EditorGUILayout.PropertyField(shape);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(scale);
|
||||
EditorGUILayout.PropertyField(vertexDistance);
|
||||
|
||||
int subdivisions = Mathf.FloorToInt(scale.floatValue / vertexDistance.floatValue);
|
||||
int vertexCount = Mathf.FloorToInt(subdivisions * subdivisions);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
|
||||
Rect rect = EditorGUILayout.GetControlRect();
|
||||
EditorGUI.ProgressBar(rect, (float)vertexCount/65535f, $"Vertex count: {vertexCount:N1}/{65535f:N1}");
|
||||
}
|
||||
if(vertexCount > 65535)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Vertex count (" + vertexCount + ") is too high. Decrease the scale, or increase the vertex distance.", MessageType.Error);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(UVTiling);
|
||||
EditorGUILayout.PropertyField(noise);
|
||||
EditorGUILayout.PropertyField(boundsPadding);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
autoApplyChanges = EditorGUILayout.Toggle("Auto-apply changes", autoApplyChanges);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
if (autoApplyChanges && HasModified())
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
this.SaveChanges();
|
||||
#else
|
||||
this.ApplyAndImport();
|
||||
#endif
|
||||
|
||||
importer = (WaterMeshImporter)target;
|
||||
}
|
||||
}
|
||||
|
||||
this.ApplyRevertGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
LocalPackages/zzwater/Editor/WaterMeshImporter.cs.meta
Normal file
11
LocalPackages/zzwater/Editor/WaterMeshImporter.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb1723d9808f34b8fa4c8c24d2a380d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
13
LocalPackages/zzwater/Editor/ZZWaterEditor.cs
Normal file
13
LocalPackages/zzwater/Editor/ZZWaterEditor.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace zz.water.editor
|
||||
{
|
||||
public class ZZWaterEditor
|
||||
{
|
||||
|
||||
[MenuItem("Assets/Create/ZZWater/Mesh")]
|
||||
private static void CreateWaterPlaneAsset() {
|
||||
ProjectWindowUtil.CreateAssetWithContent("NewWatermesh.watermesh", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
LocalPackages/zzwater/Editor/ZZWaterEditor.cs.meta
Normal file
11
LocalPackages/zzwater/Editor/ZZWaterEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50a0ab452c7c345b28e21848e21f41da
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
LocalPackages/zzwater/Editor/zzwater.editor.asmdef
Normal file
16
LocalPackages/zzwater/Editor/zzwater.editor.asmdef
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "zzwater.editor",
|
||||
"rootNamespace": "zz.water.editor",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
LocalPackages/zzwater/Editor/zzwater.editor.asmdef.meta
Normal file
7
LocalPackages/zzwater/Editor/zzwater.editor.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e0e85f981a1e47ecb3f4ed489b3234e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user