User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

Simple Runtime Placement

The attached Unity package contains an example of a simple decal placement on a car.


Code

using UnityEngine;
using System.Collections;
using ch.sycoforge.Decal;

public class DecalPlacement : MonoBehaviour 
{
    //---------------------------------
    // Exposed Fields
    //---------------------------------
    
    public EasyDecal Decal;
    public float PlacementOffset = 4;

    public float RotationSpeed = 6;
    public float Rotation;

    public float ScaleSpeed = 1;
    public Vector2 Scale = Vector2.one;
    public bool Editable;

    //---------------------------------
    // Fields
    //---------------------------------
    private Camera ActiveCamera;

    //---------------------------------
    // Constants
    //---------------------------------
    private const string ROT_INPUT_NAME = "Mouse ScrollWheel";
    private const string VER_INPUT_NAME = "Vertical";
    private const string HOR_INPUT_NAME = "Horizontal";

    //---------------------------------
    // Mehods
    //---------------------------------

    private void Start() 
    {
        // Take main camera if no camera specified
        if(ActiveCamera == null)
        {
            ActiveCamera = Camera.main;
        }
    }


    private void Update () 
    {
        ChangeAtlasIndex();

        if(Input.GetKeyDown(KeyCode.E))
        {
            Editable = !Editable;

            Decal.Baked = !Editable;
        }

        if (!Editable) { return; }

        MoveRotateDecal();
        ScaleDecal();
        
    }

    private void ChangeAtlasIndex()
    {
        
        int dir = 0;
        if (Input.GetKeyDown(KeyCode.Y)) { dir = 1; }
        if (Input.GetKeyDown(KeyCode.X)) { dir = -1; }

        if(dir != 0)
        {
            Decal.Baked = false;
            Decal.AtlasRegionIndex += dir;
            Decal.LateBake();
        }
    }

    private void MoveRotateDecal()
    {
        float delta = Input.GetAxis(ROT_INPUT_NAME);

        // Scroll event received
        if (Mathf.Abs(delta) > 0f)
        {
            // Sum delta rotation
            Rotation += delta * RotationSpeed * Time.deltaTime * 1000.0f;
        }

        Vector2 screenPoint = Input.mousePosition;

        // Ray from camera's origin
        Ray ray = ActiveCamera.ScreenPointToRay(screenPoint);

        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, ActiveCamera.farClipPlane))
        {
            Vector3 avgNormal = AverageNormal(screenPoint, PlacementOffset);
            Quaternion quat = Quaternion.AngleAxis(Rotation, avgNormal) * Quaternion.FromToRotation(Vector3.up, avgNormal);

            // Apply decal transformations
            Decal.CachedTransform.position = hit.point + avgNormal * 0.2f;
            Decal.CachedTransform.rotation = quat;
        }
    }

    private void ScaleDecal()
    {
        float v = Input.GetAxis(VER_INPUT_NAME) * ScaleSpeed;
        float h = Input.GetAxis(HOR_INPUT_NAME) * ScaleSpeed;

        // Return if no input changes
        if (!(Mathf.Abs(v) > 0f || Mathf.Abs(h) > 0))
        {
            return;
        }

        // Sum delta scale
        Scale += new Vector2(h, v) * Time.deltaTime;

        Decal.CachedTransform.localScale = new Vector3(Scale.x, 1.0f, Scale.y);
    }

    private Vector3 AverageNormal(Vector2 screenPoint, float offset)
    {
        Vector3 normal = Vector3.zero;
        Camera cam = Camera.current;
        int hits = 0;

        Vector2[] offsets = new Vector2[]
            {
                new Vector2(0, offset), 
                new Vector2(offset, offset), 

                new Vector2(offset, 0), 
                new Vector2(offset, -offset), 

                new Vector2(0, -offset), 
                new Vector2(-offset, -offset),
 
                new Vector2(-offset, 0),
                new Vector2(-offset, offset)
            };

        for (int i = 0; i < offsets.Length; i++)
        {
            Ray ray = ActiveCamera.ScreenPointToRay(screenPoint + offsets[i]);

            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 1000.0f))
            {
                normal += hit.normal;
                hits++;
            }
        }

        return normal / hits;
    }
}

Download