init
This commit is contained in:
commit
f5c1616018
679 changed files with 188502 additions and 0 deletions
185
Assets/Pixel3D/Scripts/MeshGenerator.cs
Normal file
185
Assets/Pixel3D/Scripts/MeshGenerator.cs
Normal file
|
@ -0,0 +1,185 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[RequireComponent(typeof(MeshFilter))]
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
public class MeshGenerator : MonoBehaviour
|
||||
{
|
||||
public Texture2D heightMap;
|
||||
public Vector3 size = new Vector3(10, 3, 10);
|
||||
public Vector2Int sampleCount = new Vector2Int(25, 25);
|
||||
public LayerMask terrainLayer;
|
||||
[HideInInspector] public MeshData meshData;
|
||||
[HideInInspector] public Mesh mesh;
|
||||
[HideInInspector] public RenderTexture colorTexture;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
var colorCameraObject = new GameObject("Color Camera");
|
||||
colorCameraObject.transform.parent = transform;
|
||||
colorCameraObject.transform.localPosition = Vector3.zero;
|
||||
var offset = new Vector3(0, size.y, 0);
|
||||
var rotation = Quaternion.Euler(90, 0, 0);
|
||||
colorCameraObject.transform.SetLocalPositionAndRotation(offset, rotation);
|
||||
|
||||
var colorCamera = colorCameraObject.AddComponent<Camera>();
|
||||
colorCamera.orthographic = true;
|
||||
colorCamera.orthographicSize = size.z / 2;
|
||||
colorCamera.aspect = size.x / size.z;
|
||||
colorCamera.nearClipPlane = 0;
|
||||
colorCamera.clearFlags = CameraClearFlags.Nothing;
|
||||
colorCamera.depthTextureMode = DepthTextureMode.None;
|
||||
colorCamera.cullingMask = 1 << (int)Mathf.Log(terrainLayer.value, 2);
|
||||
colorTexture = new RenderTexture(1024, 1024, 0, RenderTextureFormat.ARGB32);
|
||||
colorCamera.targetTexture = colorTexture;
|
||||
}
|
||||
|
||||
public void GenerateTerrainMesh()
|
||||
{
|
||||
// Check if the height map is null
|
||||
if (heightMap == null)
|
||||
{
|
||||
Debug.LogError("Height map is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the mesh data
|
||||
meshData = new MeshData(sampleCount.x, sampleCount.y);
|
||||
|
||||
// Loop through each vertex
|
||||
var index = 0;
|
||||
for (var y = 0; y < sampleCount.y; y++)
|
||||
{
|
||||
for (var x = 0; x < sampleCount.x; x++)
|
||||
{
|
||||
// Calculate the uv, vertex position
|
||||
var uv = new Vector2(x, y) / (sampleCount - Vector2.one);
|
||||
var vertex = (uv - Vector2.one / 2) * new Vector2(size.x, size.z);
|
||||
var heightValue = GetTrueHeight(uv);
|
||||
|
||||
// Set the vertex position and uv
|
||||
meshData.vertices[index] = new Vector3(vertex.x, heightValue, vertex.y);
|
||||
meshData.uvs[index] = uv;
|
||||
|
||||
// Add triangles if not at the edge
|
||||
if (x < sampleCount.x - 1 && y < sampleCount.y - 1)
|
||||
{
|
||||
meshData.AddTriangle(index, index + sampleCount.x + 1, index + sampleCount.x);
|
||||
meshData.AddTriangle(index + sampleCount.x + 1, index, index + 1);
|
||||
}
|
||||
|
||||
// Increment the index
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the mesh
|
||||
mesh = meshData.CreateMesh();
|
||||
|
||||
var meshFilter = GetComponent<MeshFilter>();
|
||||
if (meshFilter != null)
|
||||
meshFilter.sharedMesh = mesh;
|
||||
else
|
||||
Debug.LogError("Mesh filter is null");
|
||||
|
||||
var meshCollider = GetComponent<MeshCollider>();
|
||||
if (meshCollider != null)
|
||||
meshCollider.sharedMesh = mesh;
|
||||
}
|
||||
|
||||
// Get the height of the terrain at the given uv from the mesh
|
||||
public float GetMeshHeight(Vector2 uv)
|
||||
{
|
||||
// Calculate the precise indices
|
||||
float xIndexPrecise = uv.x * (sampleCount.x - 1);
|
||||
float zIndexPrecise = uv.y * (sampleCount.y - 1);
|
||||
|
||||
// Calculate the indices of the vertices around the point
|
||||
var xIndex = Mathf.FloorToInt(uv.x * (sampleCount.x - 1));
|
||||
var zIndex = Mathf.FloorToInt(uv.y * (sampleCount.y - 1));
|
||||
|
||||
// Ensure indices are within the bounds of the mesh
|
||||
xIndex = Mathf.Clamp(xIndex, 0, sampleCount.x - 2);
|
||||
zIndex = Mathf.Clamp(zIndex, 0, sampleCount.y - 2);
|
||||
|
||||
// Get the four vertices of the square (assuming row major and clockwise order)
|
||||
var v1 = meshData.vertices[zIndex * sampleCount.x + xIndex];
|
||||
var v2 = meshData.vertices[zIndex * sampleCount.x + xIndex + 1];
|
||||
var v3 = meshData.vertices[(zIndex + 1) * sampleCount.x + xIndex];
|
||||
var v4 = meshData.vertices[(zIndex + 1) * sampleCount.x + xIndex + 1];
|
||||
|
||||
// Bilinear interpolation
|
||||
var xRem = xIndexPrecise - xIndex;
|
||||
var zRem = zIndexPrecise - zIndex;
|
||||
var height1 = Mathf.Lerp(v1.y, v2.y, xRem);
|
||||
var height2 = Mathf.Lerp(v3.y, v4.y, xRem);
|
||||
return Mathf.Lerp(height1, height2, zRem);
|
||||
}
|
||||
|
||||
// Get the true height of the terrain at the given uv from the height map
|
||||
public float GetTrueHeight(Vector2 uv)
|
||||
{
|
||||
var x = Mathf.RoundToInt(uv.x * heightMap.width);
|
||||
var y = Mathf.RoundToInt(uv.y * heightMap.height);
|
||||
return heightMap.GetPixel(x, y).grayscale * size.y; ;
|
||||
}
|
||||
|
||||
// Check if the mesh and mesh data are generated
|
||||
public bool IsMeshGenerated()
|
||||
{
|
||||
return mesh != null && meshData != null;
|
||||
}
|
||||
}
|
||||
|
||||
// MeshData class which allows for easy mesh creation
|
||||
public class MeshData
|
||||
{
|
||||
public Vector3[] vertices;
|
||||
public int[] triangles;
|
||||
public Vector2[] uvs;
|
||||
|
||||
int triangleIndex;
|
||||
|
||||
public MeshData(int meshWidth, int meshHeight)
|
||||
{
|
||||
vertices = new Vector3[meshWidth * meshHeight];
|
||||
uvs = new Vector2[meshWidth * meshHeight];
|
||||
triangles = new int[(meshWidth - 1) * (meshHeight - 1) * 6];
|
||||
}
|
||||
|
||||
public void AddTriangle(int a, int b, int c)
|
||||
{
|
||||
triangles[triangleIndex] = a;
|
||||
triangles[triangleIndex + 1] = c;
|
||||
triangles[triangleIndex + 2] = b;
|
||||
triangleIndex += 3;
|
||||
}
|
||||
|
||||
public Mesh CreateMesh()
|
||||
{
|
||||
var mesh = new Mesh
|
||||
{
|
||||
vertices = vertices,
|
||||
triangles = triangles,
|
||||
uv = uvs
|
||||
};
|
||||
mesh.RecalculateNormals();
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Custom editor which adds a button to generate the terrain
|
||||
[CustomEditor(typeof(MeshGenerator))]
|
||||
public class MeshGeneratorEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var script = (MeshGenerator)target;
|
||||
DrawDefaultInspector();
|
||||
GUILayout.Space(10);
|
||||
if (GUILayout.Button("Generate Terrain"))
|
||||
script.GenerateTerrainMesh();
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue