private void Update()
        {
            if (Input.GetKeyDown(KeyCode.C))
            {
                // Remove all projectors.
                while (m_DecalProjectors.Count > 0)
                {
                    m_DecalsMesh.ClearAll();
                    m_DecalProjectors.Clear();

                    // Clearing of the decals mesh means we need to initialize it again.
                    m_DecalsMesh.Initialize(m_DecalsInstance);
                }
                m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh);
            }

            if (Input.GetButtonDown("Fire1"))
            {
                Ray        l_Ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f));
                RaycastHit l_RaycastHit;
                if (Physics.Raycast(l_Ray, out l_RaycastHit, Mathf.Infinity))
                {
                    // Collider hit.

                    // Make sure there are not too many projectors.
                    if (m_DecalProjectors.Count >= m_MaximumNumberOfProjectors)
                    {
                        // If there are more than the maximum number of projectors, we delete
                        // the oldest one.
                        DecalProjector l_DecalProjector = m_DecalProjectors [0];
                        m_DecalProjectors.RemoveAt(0);
                        m_DecalsMesh.RemoveProjector(l_DecalProjector);
                    }

                    // Calculate the position and rotation for the new decal projector.
                    Vector3    l_ProjectorPosition = l_RaycastHit.point - (m_DecalProjectorOffset * l_Ray.direction.normalized);
                    Quaternion l_ProjectorRotation = ProjectorRotationUtility.ProjectorRotation(Camera.main.transform.forward, Vector3.up);

                    // Randomize the rotation.
                    Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f);
                    l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation;

                    TerrainCollider l_TerrainCollider = l_RaycastHit.collider as TerrainCollider;
                    if (l_TerrainCollider != null)
                    {
                        // Terrain collider hit.

                        Terrain l_Terrain = l_TerrainCollider.GetComponent <Terrain> ();
                        if (l_Terrain != null)
                        {
                            // Create the decal projector with all the required information.
                            DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex);

                            // Add the projector to our list and the decals mesh, such that both are
                            // synchronized. All the mesh data that is now added to the decals mesh
                            // will belong to this projector.
                            m_DecalProjectors.Add(l_DecalProjector);
                            m_DecalsMesh.AddProjector(l_DecalProjector);

                            // The terrain data has to be converted to the decals instance's space.
                            Matrix4x4 l_TerrainToDecalsMatrix = m_WorldToDecalsMatrix * Matrix4x4.TRS(l_Terrain.transform.position, Quaternion.identity, Vector3.one);

                            // Pass the terrain data with the corresponding conversion to the decals mesh.
                            m_DecalsMesh.Add(l_Terrain, l_TerrainToDecalsMatrix);

                            // Cut and offset the decals mesh.
                            m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh);
                            m_DecalsMesh.OffsetActiveProjectorVertices();

                            // The changes are only present in the decals mesh at the moment. We have
                            // to pass them to the decals instance to visualize them.
                            m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh);

                            // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
                            // based on the surface you have hit.
                            NextUVRectangleIndex();
                        }
                        else
                        {
                            Debug.LogError("Terrain is null!");
                        }
                    }
                    else
                    {
                        // We hit a collider. Next we have to find the mesh that belongs to the collider.
                        // That step depends on how you set up your mesh filters and collider relative to
                        // each other in the game objects. It is important to have a consistent way in order
                        // to have a simpler implementation.

                        MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> ();
                        MeshFilter   l_MeshFilter   = l_RaycastHit.collider.GetComponent <MeshFilter> ();

                        if (l_MeshCollider != null || l_MeshFilter != null)
                        {
                            Mesh l_Mesh = null;
                            if (l_MeshCollider != null)
                            {
                                // Mesh collider was hit. Just use the mesh data from that one.
                                l_Mesh = l_MeshCollider.sharedMesh;
                            }
                            else if (l_MeshFilter != null)
                            {
                                // Otherwise take the data from the shared mesh.
                                l_Mesh = l_MeshFilter.sharedMesh;
                            }

                            if (l_Mesh != null)
                            {
                                // Create the decal projector.
                                DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex);

                                // Add the projector to our list and the decals mesh, such that both are
                                // synchronized. All the mesh data that is now added to the decals mesh
                                // will belong to this projector.
                                m_DecalProjectors.Add(l_DecalProjector);
                                m_DecalsMesh.AddProjector(l_DecalProjector);

                                // Get the required matrices.
                                Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix;
                                Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix;

                                // Add the mesh data to the decals mesh, cut and offset it.
                                m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix);
                                m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh);
                                m_DecalsMesh.OffsetActiveProjectorVertices();

                                // The changes are only present in the decals mesh at the moment. We have
                                // to pass them to the decals instance to visualize them.
                                m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh);

                                // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
                                // based on the surface you have hit.
                                NextUVRectangleIndex();
                            }
                        }
                    }
                }
            }
        }
    private void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Ray        l_Ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f));
            RaycastHit l_RaycastHit;

            // Terrains have no uv2, so we just skip them.
            if
            (Physics.Raycast(l_Ray, out l_RaycastHit, Mathf.Infinity) &&
             l_RaycastHit.collider as TerrainCollider == null)
            {
                // Collider hit.

                // Make sure there are not too many decals instances.
                if (m_DecalsInstances.Count >= 50)
                {
                    m_DecalsInstances.RemoveAt(0);
                }


                // Instantiate the prefab and get its decals instance.
                GameObject l_Instance = Instantiate(decalsPrefab) as GameObject;
                DS_Decals  l_Decals   = l_Instance.GetComponentInChildren <DS_Decals> ();

                // Reuse the decals mesh, but be sure to initialize it always for the current
                // decals instance.
                m_DecalsMesh.Initialize(l_Decals);

                // Calculate the position and rotation for the new decal projector.
                Vector3    l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * l_Ray.direction.normalized);
                Vector3    l_ForwardDirection  = Camera.main.transform.up;
                Vector3    l_UpDirection       = -Camera.main.transform.forward;
                Quaternion l_ProjectorRotation = Quaternion.LookRotation(l_ForwardDirection, l_UpDirection);

                // Randomize the rotation.
                Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f);
                l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation;


                // We hit a collider. Next we have to find the mesh that belongs to the collider.
                // That step depends on how you set up your mesh filters and collider relative to
                // each other in the game objects. It is important to have a consistent way in order
                // to have a simpler implementation.

                MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> ();
                MeshFilter   l_MeshFilter   = l_RaycastHit.collider.GetComponent <MeshFilter> ();
                MeshRenderer l_MeshRenderer = l_RaycastHit.collider.GetComponent <MeshRenderer> ();

                if (l_MeshCollider != null || l_MeshFilter != null)
                {
                    Mesh l_Mesh = null;
                    if (l_MeshCollider != null)
                    {
                        // Mesh collider was hit. Just use the mesh data from that one.
                        l_Mesh = l_MeshCollider.sharedMesh;
                    }
                    else if (l_MeshFilter != null)
                    {
                        // Otherwise take the data from the shared mesh.
                        l_Mesh = l_MeshFilter.sharedMesh;
                    }

                    if (l_Mesh != null)
                    {
                        // Create the decal projector.
                        DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);

                        // All the mesh data that is now added to the decals mesh
                        // will belong to this projector.
                        m_DecalsMesh.AddProjector(l_DecalProjector);

                        // Get the required matrices.
                        Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix;
                        Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix;

                        // Add the mesh data to the decals mesh, cut and offset it before we pass it
                        // to the decals instance to be displayed.
                        m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix);
                        m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh);
                        m_DecalsMesh.OffsetActiveProjectorVertices();
                        l_Decals.UpdateDecalsMeshes(m_DecalsMesh);

                        // Lightmapping
                        l_Decals.DecalsMeshRenderers [0].MeshRenderer.lightmapIndex        = l_MeshRenderer.lightmapIndex;
                        l_Decals.DecalsMeshRenderers [0].MeshRenderer.lightmapTilingOffset = l_MeshRenderer.lightmapTilingOffset;

                        // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
                        // based on the surface you have hit.
                        NextUVRectangleIndex(l_Decals);
                    }
                }
            }
        }
    }