Heightmap on custom cube sphere Unity

409 Views Asked by At

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.

1

There are 1 best solutions below

2
Ram.Type-0 On

I have tried using getPixel.grayscale to change the y position of verts but I just get a 3D pizza slice.

You should apply height as offset aligned to its vertex normal.

I think you are applying height as offset aligned to y-axis.