Skip to content

Instantly share code, notes, and snippets.

@yosun
Last active June 12, 2024 20:41
Show Gist options
  • Save yosun/072849508d550c8b0641ee3ad646d60a to your computer and use it in GitHub Desktop.
Save yosun/072849508d550c8b0641ee3ad646d60a to your computer and use it in GitHub Desktop.
input a depth mask, and get a mesh shaped based on that. includes Black version and Transparent version
using UnityEngine;
using System.Collections.Generic; // Added for the dictionary
public class HeightmapGeneratorCullBlack : MonoBehaviour
{
public Texture2D heightMap;
public Material material;
public Vector3 size = new Vector3(200, 30, 200);
void Start()
{
GenerateHeightmap();
}
public float threshold = .25f;
private void GenerateHeightmap()
{
// Create the game object containing the renderer
gameObject.AddComponent<MeshFilter>();
gameObject.AddComponent<MeshRenderer>();
if (material)
{
GetComponent<Renderer>().material = material;
}
else
{
GetComponent<Renderer>().material.color = Color.white;
}
// Retrieve a mesh instance
Mesh mesh = GetComponent<MeshFilter>().mesh;
int width = Mathf.Min(heightMap.width, 255);
int height = Mathf.Min(heightMap.height, 255);
// Determine the number of valid vertices
int validVertexCount = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (heightMap.GetPixel(x, y).grayscale > threshold)
{
validVertexCount++;
}
}
}
// Build vertices and UVs, skipping black pixels
Vector3[] vertices = new Vector3[validVertexCount];
Vector2[] uv = new Vector2[validVertexCount];
Vector4[] tangents = new Vector4[validVertexCount];
Vector2 uvScale = new Vector2(1.0f / (width - 1), 1.0f / (height - 1));
Vector3 sizeScale = new Vector3(size.x / (width - 1), size.y, size.z / (height - 1));
int vertexIndex = 0;
Dictionary<int, int> validVertexMap = new Dictionary<int, int>(); // Map original to valid index
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (heightMap.GetPixel(x, y).grayscale > threshold)
{
float pixelHeight = heightMap.GetPixel(x, y).grayscale;
Vector3 vertex = new Vector3(x, pixelHeight, y);
vertices[vertexIndex] = Vector3.Scale(sizeScale, vertex);
uv[vertexIndex] = Vector2.Scale(new Vector2(x, y), uvScale);
// Calculate tangent vector
Vector3 vertexL = new Vector3(x - 1, heightMap.GetPixel(x - 1, y).grayscale, y);
Vector3 vertexR = new Vector3(x + 1, heightMap.GetPixel(x + 1, y).grayscale, y);
Vector3 tan = Vector3.Scale(sizeScale, vertexR - vertexL).normalized;
tangents[vertexIndex] = new Vector4(tan.x, tan.y, tan.z, -1.0f);
validVertexMap[y * width + x] = vertexIndex; // Add to map
vertexIndex++;
}
}
}
// Assign them to the mesh
mesh.vertices = vertices;
mesh.uv = uv;
// Build triangle indices, adapting to the valid vertices
int[] triangles = new int[(validVertexCount - height) * 6]; // Adjust triangle count
int index = 0;
for (int y = 0; y < height - 1; y++)
{
for (int x = 0; x < width - 1; x++)
{
int v0 = y * width + x;
int v1 = (y + 1) * width + x;
int v2 = y * width + x + 1;
int v3 = (y + 1) * width + x + 1;
// Check validity AND get mapped index
if (validVertexMap.TryGetValue(v0, out v0) &&
validVertexMap.TryGetValue(v1, out v1) &&
validVertexMap.TryGetValue(v2, out v2) &&
validVertexMap.TryGetValue(v3, out v3))
{
triangles[index++] = v0;
triangles[index++] = v1;
triangles[index++] = v2;
triangles[index++] = v1;
triangles[index++] = v3;
triangles[index++] = v2;
}
}
}
// And assign them to the mesh
mesh.triangles = triangles;
// Auto-calculate vertex normals from the mesh
mesh.RecalculateNormals();
// Assign tangents after recalculating normals
mesh.tangents = tangents;
}
}
using UnityEngine;
using System.Collections.Generic;
public class HeightmapGenerator : MonoBehaviour
{
public Texture2D heightMap;
public Material material;
public Vector3 size = new Vector3(200, 30, 200);
void Start()
{
GenerateHeightmap();
}
private void GenerateHeightmap()
{
// Create the game object containing the renderer
gameObject.AddComponent<MeshFilter>();
gameObject.AddComponent<MeshRenderer>();
if (material)
{
GetComponent<Renderer>().material = material;
}
else
{
GetComponent<Renderer>().material.color = Color.white;
}
// Retrieve a mesh instance
Mesh mesh = GetComponent<MeshFilter>().mesh;
int width = Mathf.Min(heightMap.width, 255);
int height = Mathf.Min(heightMap.height, 255);
// Determine the number of valid vertices (non-black)
int validVertexCount = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (heightMap.GetPixel(x, y).grayscale > 0)
{
validVertexCount++;
}
}
}
// Build vertices and UVs, skipping black pixels
Vector3[] vertices = new Vector3[validVertexCount];
Vector2[] uv = new Vector2[validVertexCount];
Vector4[] tangents = new Vector4[validVertexCount];
Vector2 uvScale = new Vector2(1.0f / (width - 1), 1.0f / (height - 1));
Vector3 sizeScale = new Vector3(size.x / (width - 1), size.y, size.z / (height - 1));
int vertexIndex = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (heightMap.GetPixel(x, y).grayscale > 0)
{
float pixelHeight = heightMap.GetPixel(x, y).grayscale;
Vector3 vertex = new Vector3(x, pixelHeight, y);
vertices[vertexIndex] = Vector3.Scale(sizeScale, vertex);
uv[vertexIndex] = Vector2.Scale(new Vector2(x, y), uvScale);
// Calculate tangent vector (consider handling edge cases gracefully)
Vector3 vertexL = (x > 0) ? new Vector3(x - 1, heightMap.GetPixel(x - 1, y).grayscale, y) : vertex;
Vector3 vertexR = (x < width - 1) ? new Vector3(x + 1, heightMap.GetPixel(x + 1, y).grayscale, y) : vertex;
Vector3 tan = Vector3.Scale(sizeScale, vertexR - vertexL).normalized;
tangents[vertexIndex] = new Vector4(tan.x, tan.y, tan.z, -1.0f);
vertexIndex++;
}
}
}
// Assign vertices and UVs to the mesh
mesh.vertices = vertices;
mesh.uv = uv;
// Build triangle indices
List<int> trianglesList = new List<int>(); // Use a list for dynamic size
for (int y = 0; y < height - 1; y++)
{
for (int x = 0; x < width - 1; x++)
{
int v0 = y * width + x;
int v1 = (y + 1) * width + x;
int v2 = y * width + x + 1;
int v3 = (y + 1) * width + x + 1;
// Check if all four vertices are valid (non-black)
if (heightMap.GetPixel(x, y).grayscale > 0 &&
heightMap.GetPixel(x + 1, y).grayscale > 0 &&
heightMap.GetPixel(x, y + 1).grayscale > 0 &&
heightMap.GetPixel(x + 1, y + 1).grayscale > 0)
{
trianglesList.Add(v0 - CalculateSkippedVertices(v0, width, heightMap));
trianglesList.Add(v1 - CalculateSkippedVertices(v1, width, heightMap));
trianglesList.Add(v2 - CalculateSkippedVertices(v2, width, heightMap));
trianglesList.Add(v1 - CalculateSkippedVertices(v1, width, heightMap));
trianglesList.Add(v3 - CalculateSkippedVertices(v3, width, heightMap));
trianglesList.Add(v2 - CalculateSkippedVertices(v2, width, heightMap));
}
}
}
mesh.triangles = trianglesList.ToArray();
// Auto-calculate vertex normals from the mesh
mesh.RecalculateNormals();
// Assign tangents after recalculating normals
mesh.tangents = tangents;
}
// Helper function to calculate the number of skipped vertices
int CalculateSkippedVertices(int index, int width, Texture2D heightMap)
{
int skipped = 0;
int y = index / width;
int x = index % width;
for (int i = 0; i < y; i++)
{
for (int j = 0; j < width; j++)
{
if (heightMap.GetPixel(j, i).grayscale == 0)
{
skipped++;
}
}
}
for (int j = 0; j < x; j++)
{
if (heightMap.GetPixel(j, y).grayscale == 0)
{
skipped++;
}
}
return skipped;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment