How do I distort my custom cube sphere mesh with a heightmap texture? I would prefer to do this by script if possible.
I am trying to make a 3D model of the world but cannot figure out how to make a heightmap texture apply to my sphere. I have tried using getPixel.grayscale to change the y position of verts but I just get a 3D pizza slice. I have also tried to use the same method to change the radius at that point but still just a pizza slice.
My current sphere generation code is below I am using the cube sphere from Sebastian Lagues planet vidios.
Sphere.cs
public class Sphere : MonoBehaviour
{
private World world;
private ShapeSettings shapeSettings;
[HideInInspector]
public Material material;
[SerializeField, HideInInspector]
MeshFilter[] meshFilters;
SphereSide[] sphereSides;
public void GenerateSphere()
{
Initialize();
GenerateMesh();
}
void Initialize()
{
world = gameObject.GetComponentInParent<World>();
shapeSettings = world.shapeSettings;
if (meshFilters == null || meshFilters.Length == 0)
{
meshFilters = new MeshFilter[6];
}
sphereSides = new SphereSide[6];
Vector3[] directions = { Vector3.up, Vector3.down, Vector3.left, Vector3.right, Vector3.forward, Vector3.back };
for (int i = 0; i < 6; i++)
{
if (meshFilters[i] == null)
{
GameObject meshObj = new GameObject("mesh");
meshObj.transform.parent = transform;
meshObj.AddComponent<MeshRenderer>();
meshFilters[i] = meshObj.AddComponent<MeshFilter>();
meshFilters[i].sharedMesh = new Mesh();
}
meshFilters[i].GetComponent<MeshRenderer>().sharedMaterial = material;
sphereSides[i] = new SphereSide(world, meshFilters[i].sharedMesh, shapeSettings.resolution, directions[i]);
}
SphereCollider sc = gameObject.GetComponent<SphereCollider>();
if (sc == null)
{
sc = gameObject.AddComponent<SphereCollider>() as SphereCollider;
sc.radius = shapeSettings.worldRadius;
}
else if (sc.radius != shapeSettings.worldRadius)
sc.radius = shapeSettings.worldRadius;
}
public void OnSettingsUpdated(Material Material)
{
material = Material;
GenerateSphere();
}
void GenerateMesh()
{
foreach (SphereSide face in sphereSides)
{
face.ConstructMesh();
}
}
}
SphereSide.cs
public SphereSide(World world, Mesh mesh, int resolution, Vector3 localUp)
{
this.world = world;
this.mesh = mesh;
this.resolution = resolution;
this.localUp = localUp;
axisA = new Vector3(localUp.y, localUp.z, localUp.x);
axisB = Vector3.Cross(localUp, axisA);
}
private static Vector3 PointOnCubeToPointOnSphere(Vector3 p)
{
float x2 = p.x * p.x;
float y2 = p.y * p.y;
float z2 = p.z * p.z;
float x = p.x * Mathf.Sqrt(1 - (y2 + z2) / 2 + (y2 * z2) / 3);
float y = p.y * Mathf.Sqrt(1 - (z2 + x2) / 2 + (z2 * x2) / 3);
float z = p.z * Mathf.Sqrt(1 - (x2 + y2) / 2 + (x2 * y2) / 3);
return new Vector3(x, y, z);
}
public void ConstructMesh()
{
Vector3[] vertices = new Vector3[resolution * resolution];
Vector2[] uvs = new Vector2[vertices.Length];
int[] triangles = new int[(resolution - 1) * (resolution - 1) * 6];
int triIndex = 0;
for (int y = 0; y < resolution; y++)
{
for (int x = 0; x < resolution; x++)
{
int i = x + y * resolution;
Vector2 percent = new Vector2(x, y) / (resolution - 1);
Vector3 pointOnUnitCube = localUp + (percent.x - .5f) * 2 * axisA + (percent.y - .5f) * 2 * axisB;
Vector3 pointOnUnitSphere = PointOnCubeToPointOnSphere(pointOnUnitCube);
vertices[i] = pointOnUnitSphere * world.shapeSettings.worldRadius;
if (x != resolution - 1 && y != resolution - 1)
{
triangles[triIndex] = i;
triangles[triIndex + 1] = i + resolution + 1;
triangles[triIndex + 2] = i + resolution;
triangles[triIndex + 3] = i;
triangles[triIndex + 4] = i + 1;
triangles[triIndex + 5] = i + resolution + 1;
triIndex += 6;
}
}
}
for (int i = 0; i < uvs.Length; i++)
uvs[i] = new Vector2(vertices[i].x, vertices[i].z);
mesh.Clear();
mesh.vertices = vertices;
mesh.uv = uvs;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
Any help is much apreatiated.
You should apply height as offset aligned to its vertex normal.
I think you are applying height as offset aligned to y-axis.