备份CatanBuilding瘦身独立工程

This commit is contained in:
JSD\13999
2026-05-26 16:15:54 +08:00
commit 2d0e6a61b7
12001 changed files with 2431925 additions and 0 deletions

View 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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf7a83bc3b7bd442a8f8867464fed7cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eb1723d9808f34b8fa4c8c24d2a380d9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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", "");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50a0ab452c7c345b28e21848e21f41da
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3e0e85f981a1e47ecb3f4ed489b3234e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: