I need help with creating a gradient in world space

Hi guys,

I’m currently working on a shader that let’s me put a gradient on an object in world space. My end goal with this shader is to put an object somewhere into world space and then color it with a gradient going from full white at the top to full black at the bottom of the mesh. This should “ignore” rotations of the mesh, meaning that the gradient will always be parallel to the ground of the world.

I’m pretty far with the shader and it’s working for boxes, spheres and capsules, but I’m running into bugs with custom meshes and I don’t understand why.

Here’s my node setup:

Now, the BoundingBoxHeight variable is fed via script in which I calculate the height of the mesh. The script looks as follows:

[ExecuteInEditMode]
public class GradientScript : MonoBehaviour {

private Material m_Material;
public MeshFilter meshFilter;
public Mesh mesh;

public float height;
private Bounds bounds;

void Start() {
    meshFilter = GetComponent<MeshFilter>();
    m_Material = gameObject.GetComponent<Renderer>().material;
}

void Update() {
    if (!mesh) {
        return;
    }

    var vertices = mesh.vertices;
    if (vertices.Length <= 0) return;

    // TransformPoint converts the local mesh vertice dependent on the transform
    // position, scale and orientation into a global position
    var min = transform.TransformPoint(vertices[0]);
    var max = min;

    // Iterate through all vertices
    // except first one
    for (var i = 1; i < vertices.Length; i++) {
        var V = transform.TransformPoint(vertices[i]);

        // Go through X,Y and Z of the Vector3
        for (var n = 0; n < 3; n++) {
            max[n] = Mathf.Max(V[n], max[n]);
            min[n] = Mathf.Min(V[n], min[n]);
        }
    }

    bounds = new Bounds();
    bounds.SetMinMax(min, max);
    height = bounds.size.y;
    if(m_Material != null) {
        m_Material.SetFloat("_BoundingBoxHeight", height);
    }
}

private void OnDrawGizmos() {
    Gizmos.color = Color.green;
    Vector3 min = new Vector3(0, bounds.min.y, 0);
    Vector3 max = new Vector3(0, bounds.max.y, 0);

    Gizmos.DrawWireCube(bounds.center, bounds.size);
    Gizmos.DrawSphere(bounds.center, 0.1f);
    Gizmos.DrawSphere(min, 0.1f);
    Gizmos.DrawSphere(max, 0.1f);
}

}

Here’s what it looks like in the scene:
[I wanted to post a screenshot right here, but new users are not allowed to include more than one screenshot, so I will put in a reply I guess]

So, as you can see it works for scaled and rotated boxes for example, but the gradient is starting to repeat on the suzanne mesh. This only occurs when the model is rotated a certain way, but I might not be able to see the right values in other rotations since the values might just be slightly off and it only becomes more visible in other rotations.

I don’t understand why it’s not working for the custom mesh since the gizmos show that the height is calculated correctly? I don’t understand why it’s only working for primitive shapes.

Any hints on how I could debug this or what kind of problem you find in the shader/script would be highly appreciated!

So, here’s the missing screenshot:

Turns out instead of using the object to world node using the min. y-position of the bounding box works well (offset needs to be taken out of the shader as well).