Sculpting vertices in Procedural examples asset

Hi all,

I have been checking out Unity’s procedural examples asset and I have a question on the sculpting vertices script. Basically what I want to do is INVERT instead of EXTRUDE, which is what this script does to a sphere. Is this as simple as setting one of these values to a minus? Of course, I have tried and guessing its not, but this is really the extent of my knowledge on the subject … ‘try and set one of the values to minus and see if it reverses the process’… thanks for any help. Essentially what I want to do in my game is SCULPT something, in this case, clay… and I think I would be able to work with this asset after I can get it to invert

var radius = 1.0;
var pull = 10.0;
private var unappliedMesh : MeshFilter;

enum FallOff { Gauss, Linear, Needle }
var fallOff = FallOff.Gauss;

static function LinearFalloff (distance : float , inRadius : float) {
    return Mathf.Clamp01(1.0 - distance / inRadius);
}

static function GaussFalloff (distance : float , inRadius : float) {
    return Mathf.Clamp01 (Mathf.Pow (360.0, -Mathf.Pow (distance / inRadius, 2.5) - 0.01));
}

function NeedleFalloff (dist : float, inRadius : float)
{
    return -(dist*dist) / (inRadius * inRadius) + 1.0;
}

function DeformMesh (mesh : Mesh, position : Vector3, power : float, inRadius : float)
{
    var vertices = mesh.vertices;
    var normals = mesh.normals;
    var sqrRadius = inRadius * inRadius;
   
    // Calculate averaged normal of all surrounding vertices   
    var averageNormal = Vector3.zero;
    for (var i=0;i<vertices.length;i++)
    {
        var sqrMagnitude = (vertices[i] - position).sqrMagnitude;
        // Early out if too far away
        if (sqrMagnitude > sqrRadius)
            continue;

        var distance = Mathf.Sqrt(sqrMagnitude);
        var falloff = LinearFalloff(distance, inRadius);
        averageNormal += falloff * normals[i];
    }
    averageNormal = averageNormal.normalized;
   
    // Deform vertices along averaged normal
    for (i=0;i<vertices.length;i++)
    {
        sqrMagnitude = (vertices[i] - position).sqrMagnitude;
        // Early out if too far away
        if (sqrMagnitude > sqrRadius)
            continue;

        distance = Mathf.Sqrt(sqrMagnitude);
        switch (fallOff)
        {
            case FallOff.Gauss:
                falloff = GaussFalloff(distance, inRadius);
                break;
            case FallOff.Needle:
                falloff = NeedleFalloff(distance, inRadius);
                break;
            default:
                falloff = LinearFalloff(distance, inRadius);
                break;
        }
       
        vertices[i] += averageNormal * falloff * power;
    }
   
    mesh.vertices = vertices;
    mesh.RecalculateNormals();
    mesh.RecalculateBounds();
}

function Update () {

    // When no button is pressed we update the mesh collider
    if (!Input.GetMouseButton (0))
    {
        // Apply collision mesh when we let go of button
        ApplyMeshCollider();
        return;
    }
       
       
    // Did we hit the surface?
    var hit : RaycastHit;
    var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    if (Physics.Raycast (ray, hit))
    {
        var filter : MeshFilter = hit.collider.GetComponent(MeshFilter);
        if (filter)
        {
            // Don't update mesh collider every frame since physX
            // does some heavy processing to optimize the collision mesh.
            // So this is not fast enough for real time updating every frame
            if (filter != unappliedMesh)
            {
                ApplyMeshCollider();
                unappliedMesh = filter;
            }
           
            // Deform mesh
            var relativePoint = filter.transform.InverseTransformPoint(hit.point);
            DeformMesh(filter.mesh, relativePoint, pull * Time.deltaTime, radius);
        }
    }
}

function ApplyMeshCollider () {
    if (unappliedMesh && unappliedMesh.GetComponent(MeshCollider)) {
        unappliedMesh.GetComponent(MeshCollider).sharedMesh = unappliedMesh.sharedMesh;
    }
    unappliedMesh = null;
}

It really is just that. On line 64, we are adding the normal (times a couple of scaling factors) to the position of a vertex. The “normal” to a surface is a vector that points out, directly away from the surface at that point. So this code, as it is, causes the surface to bulge out.

If you change += to -=, so you’re subtracting the normal rather than adding it, then it will instead cause the surface to dent in.

Of course this is a long way from having something that acts like clay… a sculpting program gets very complicated, and should probably be based on something like isosurfaces or metaballs instead. (Wow, that just brought to mind a simple metaball modeler I made for POV-Ray, called Jam, back in 1999! Good times.)