Basic Bullet Hole

The following snippet shows how to implement a simple bullet hole creation component with EasyDecal.
 

using UnityEngine;
using ch.sycoforge.Decal;
 
/// <summary>
/// Demo class for runtime decal placement.
/// </summary>
public class DynamicDemo : MonoBehaviour 
{
 
    public EasyDecal DecalPrefab_A;
 
     
    // Update is called once per frame
    void Update () 
    {
        if (Input.GetMouseButtonUp(0))
        {
            // Shoot a ray thru the camera starting at the mouse's current screen space position
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
 
            // Check if ray hit something
            if (Physics.Raycast(ray, out hit, 200))
            {
                // Draw a line along the projection axis for visalizing the projection process.
                Debug.DrawLine(ray.origin, hit.point, Color.red);
 
                // Instantiate the decal prefab according the hit normal
                EasyDecal.ProjectAt(DecalPrefab_A.gameObject, hit.collider.gameObject, hit.point, hit.normal);
            }
        }
    }
}

 

Setting up a texture animation

Please follow the steps below to add a texture animation to your decal prefab.

 

Create a texture animation sheet in your programm of choice.

 

Create a new material in Unity and assign the recently created textures.

 

On your EasyDecal prefab set the Source Mode to Material and assign the material.

 

Add a DecalAnimation script to the component stack and enter the dimensions (amount of single frames per row/column) of your animation sheet. Set the input texture names according to the used shader.

 

The animation will start automatically when the decal gets instantiated.

 

 

Advanced Bullet Hole

The following snippet shows how to implement a more complex bullet hole creation component with EasyDecal.
 

using ch.sycoforge.Decal;
using UnityEngine;

/// <summary>
/// Demo class for advanced runtime decal placement.
/// </summary>
public class AdvancedBulletHoles : MonoBehaviour
{
    //------------------------------------
    // Fields
    //------------------------------------
    public EasyDecal DecalPrefab;
    public float CastRadius = 0.25f;

    //------------------------------------
    // Methods
    //------------------------------------

    public void Start()
    {
        if (DecalPrefab == null)
        {
            Debug.LogError("The AdvancedBulletHoles script has no decal prefab attached.");
        }
    }

    public void Update()
    {
        if (Input.GetMouseButtonUp(0))
        {
            // Shoot a ray thru the camera starting at the mouse's current screen space position
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            RaycastHit initialHit;

            // Check if ray hit something
            if (Physics.Raycast(ray, out initialHit, 200))
            {                    
                // Set the first hit as parent of the decal
                GameObject parent = initialHit.collider.gameObject;
                Vector3 position = initialHit.point;

                RaycastHit[] hits = Physics.SphereCastAll(ray, CastRadius, Vector3.Distance(Camera.main.transform.position, position) + 2);
                Vector3 averageNormal = initialHit.normal;

                // Check if sphere cast hit something
                if (hits.Length > 0)
                {
                    
                    foreach (RaycastHit hit in hits)
                    {
                        // Draw a line along the projection axis for visalizing the projection process.
                        Debug.DrawLine(ray.origin, hit.point, Color.red);

                        // Sum all collison point normals
                        averageNormal += hit.normal;
                    }
                }
                
                // Normalize normal
                averageNormal /= hits.Length + 1;
                    
                // Instantiate the decal prefab according the hit normal
                EasyDecal.ProjectAt(DecalPrefab.gameObject, parent, position, averageNormal);
            }
        }
    }
}

 

Decal Transform Animation

In some cases it's inefficient to create a new material animation for very basic transformations like rotation and scale. 

The Easy Decal framework allows to hook custom components to prefabs and process them after the first projection cycle took place.

It's important to always start any costum logic in the Start() method and not in the Awake(). When the decal prefab gets instantiated using the API, it's also necessary to release the geometry before any processing takes place. Since version 1.6.1 this can easily be achieved using the LateUnbake() method. Please keep in mind that every decal instance needs to be baked again after processing.

private void Start ()      
{         
    decal = GetComponent<EasyDecal>();         

    //Unbake decal in next frame         
    decal.LateUnbake();
}

The example component below demonstrates how a curve-controlled scale effect can be applied to decal.

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

/// <summary>
/// Simple component showing how to implement a geometry post effect with Easy Decal.
/// </summary>
[RequireComponent(typeof(EasyDecal))]
public class DecalScaleAnimation : MonoBehaviour 
{
    //-----------------------
    // Exposed Fields
    //-----------------------

    /// <summary>
    /// Final value of the animation.
    /// </summary>
    [Range(0.0f, 3.0f)]
    public float FinalScale = 2;

    /// <summary>
    /// Overall animation time.
    /// </summary>
    [Range(0.1f, 10.0f)]
    public float ScaleTime = 2;

    /// <summary>
    /// Animation tween curve. Should be clamped to [0, 0] -> [1, 1].
    /// </summary>
    public AnimationCurve Curve = new AnimationCurve(new Keyframe(0,0), new Keyframe(1,1));

    //-----------------------
    // Fields
    //-----------------------
    private float currentScaleFactor = 1;
    private Vector3 startLocalScale;
    private EasyDecal decal;

    //-----------------------
    // Methods
    //-----------------------
    private void Start () 
    {
        decal = GetComponent<EasyDecal>();

        //Unbake decal in next frame
        decal.LateUnbake();

        // Start scale routine
        StartAnimation();
    }

    /// <summary>
    /// Starts the animation.
    /// </summary>
    public void StartAnimation()
    {
        StartCoroutine(ScaleRoutine());
    }

    private IEnumerator ScaleRoutine()
    {
        // Initialize 
        float normalizedProgress = 0.0f;
        float elapsedTime = 0.0f;
        float sampledValue = 0.0f;

        // Reset scale factor
        currentScaleFactor = 1.0f;

        // Reset current local scale vector
        startLocalScale = this.transform.localScale;

        while (elapsedTime <= ScaleTime)
        {
            normalizedProgress = elapsedTime / ScaleTime;

            sampledValue = Curve.Evaluate(normalizedProgress);

            // Inegrate over time
            currentScaleFactor = sampledValue * FinalScale;

            // Sum overall animation time
            elapsedTime += Time.deltaTime;

            this.transform.localScale = startLocalScale * currentScaleFactor;

            yield return null;
        }

        // Bake after scale animation has been finished
        decal.LateBake();
    }
}

The component can simply be plugged to the component stack of the decal prefab.

Runtime Initialization

When initializing a decal at runtime, one has to do this in the Start() method, because of the decal system initializes itself in Awake() and OnEnable().

public DecalTextureAtlas atlas;
private EasyDecal decal;

public void Awake()
{
    decal = GetComponent<EasyDecal>();
}

public void Start() 
{ 
    decal.Atlas = atlas; 
    decal.AtlasRegionIndex = UnityEngine.Random.Range(0, 4);
}
 

 

 

 

 

 

Page 1 of 4

Copyright © 2020 by Sycoforge Technologies. All Rights Reserved.