Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Decal System

Discussion in 'Assets and Asset Store' started by Dantus, Jun 29, 2012.

  1. yinono

    yinono

    Joined:
    Sep 15, 2010
    Posts:
    27
    I still have a problem I changed my code and now only the last projector decal is displayed,
    I'll appreciate any help.

    this is what I do every frame.
    Code (csharp):
    1.  
    2. m_decalMesh.ClearAll();
    3. for (int i = 0; i < m_fingers.Length; i++)
    4. {
    5.     m_projectors[i].transform.position = finger.transform.position;
    6.     m_projectors[i].transform.rotation = finger.transform.rotation;
    7.     m_projectors[i].transform.localScale = finger.transform.localScale;
    8.     m_decalMesh.AddProjector(m_wrappedProjectors[i]);
    9. }
    10. Matrix4x4 worldToMeshMatrix = m_meshFilter.transform.worldToLocalMatrix;
    11. Matrix4x4 meshToWorldMatrix = m_meshFilter.transform.localToWorldMatrix;
    12. m_decalMesh.Add(m_meshFilter.sharedMesh, worldToMeshMatrix, meshToWorldMatrix);
    13. m_decalsCutter.CutDecalsPlanes(m_decalMesh);
    14. m_decalMesh.OffsetActiveProjectorVertices();
    15. m_decals.UpdateDecalsMeshes(m_decalMesh);
    16.  
     
  2. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    If you are working with a decals mesh, the basic steps that must take place for each projector are:
    1. Add the projector
    2. Add all meshes for that projector, meaning everything that has to be affected
    3. Cut (this cuts only the added meshes for that projector)
    4. Offset (this offsets only the vertices for that projector)

    As the modifications are done, pass the changes to m_decals, such that they are shown.

    Code (csharp):
    1.     m_decalMesh.ClearAll();
    2.     Matrix4x4 worldToMeshMatrix = m_meshFilter.transform.worldToLocalMatrix;
    3.     Matrix4x4 meshToWorldMatrix = m_meshFilter.transform.localToWorldMatrix;
    4.     Mesh mesh = m_meshFilter.sharedMesh;
    5.     for (int i = 0; i < m_fingers.Length; i++)
    6.     {
    7.         m_projectors[i].transform.position = finger.transform.position;
    8.         m_projectors[i].transform.rotation = finger.transform.rotation;
    9.         m_projectors[i].transform.localScale = finger.transform.localScale;
    10.         m_decalMesh.AddProjector(m_wrappedProjectors[i]);
    11.         m_decalMesh.Add(mesh, worldToMeshMatrix, meshToWorldMatrix);
    12.         m_decalsCutter.CutDecalsPlanes(m_decalMesh);
    13.         m_decalMesh.OffsetActiveProjectorVertices();
    14.     }
    15.     m_decals.UpdateDecalsMeshes(m_decalMesh);
    Hope this clearifies it for you!
     
  3. Ali-Nagori

    Ali-Nagori

    Joined:
    Apr 9, 2010
    Posts:
    151
    first of all thanks a lot for this master piece.

    i would like to know how would i decal on the skinned meshes , for example if the a an skinned mesh get hit by a bullet it get a blood decal on it's front mesh.
     
    Last edited: Aug 29, 2012
  4. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    That's the expected behaviour. The visualization is only updated if a decals game object or one that belongs to it is changed. The decal's mesh is not duplicated and thus the duplicated decals instance starts with a new one that is empty at the beginning.

    Using the Decal System at runtime is far more complex than in the editor. Have you already checked the BulletExample script that is bundled in the demo? That should give you a pretty good impression of what has to be made from a coding point of view.

    Hope this helps.
     
  5. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You modified your post while I was writing the previous answer :) .

    For skinned meshes there is a special decals variant, meaning skinned decals. They somehow work, but it is a tricky topic. It is possible to use them at runtime too.
     
  6. Ali-Nagori

    Ali-Nagori

    Joined:
    Apr 9, 2010
    Posts:
    151
    yes i did :) because i found the solution was very simple , one of course by the bullet example , and then second when i turned off the interactive update from the decal setting window

    yes i really need that solution , and actually it was me again who was asking for the video :)
     
  7. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I see :)
     
  8. Ali-Nagori

    Ali-Nagori

    Joined:
    Apr 9, 2010
    Posts:
    151
  9. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
  10. rbarbosa

    rbarbosa

    Joined:
    Jun 20, 2012
    Posts:
    61
    @Dantus...I'm new here and I'm just kind of exploring possibilities with this system. Based on the vids, I'm amazed that you give this away for free. That's great for the community.

    I'm trying to understand, based on what I've read, what would be the best practice for using the decal system for identifying "ownership" of an object. It's kind of difficult to explain without actually having a project in mind...so let me try giving an example.

    Suppose I have an RTS with structures that can be built or captured. I want to project a colored "disc" around the base of the building that is red if owned by player 1 and blue if owned by player 2. Assuming mobile devices are an intended platform (and their limited performance), what would you recommend as a way forward?

    I guess it is safe to assume that the structures are statically positioned, so it would seem that a decal could be made in the editor and stored with the scene data (perhaps with the mesh renderer disabled by default). Then when the structure is captured/built, the appropriate material and/or color can be changed to match the team's color, then the mesh renderer could be enabled. Would this work?

    Would this be the best technique for doing something like this (again...assuming performance is at a premium), or would it be feasible to just create the decal at runtime on the fly with the associated sprites/materials/colors?

    On the one hand, it would seem to me that creating the projections at runtime would be slower, but I don't know if it would be significant. I'd assume we could not use a single prefab and instantiate it repeatedly because variations in terrain would require variations in the geometry of the mesh.

    Am I understanding the system properly?

    Thanks...and thanks again for what appears to be a great contribution to the community.
     
  11. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @rbarbosa: I have the impression that you are understanding the way the Decal System works very well. Without knowing more about the project and without having tested the performance of the Decal System on mobiles, it is impossible for me to give you a clear answer.
    Computing the decal in the editor would be the optimal case from a performance point of view, but that certainly doesn't work in all cases. So if you want to compute them at runtime, the performance heavily depends on the number of vertices/edges/triangles the ground has onto which you perform the projection.
    It is out of question that the computation of a decal is expensive, but with a simple ground geometry it may even work at runtime. But I can't promise anything.

    Very vague answer, I am aware of that. In the case that you are testing it, it would be awesome if you could share your experience!
     
  12. rbarbosa

    rbarbosa

    Joined:
    Jun 20, 2012
    Posts:
    61
    @Dantus...thanks for the quick reply. I wish I knew more about my project too. :)

    I don't actually have a project in mind...I'm just considering possibilities. I have downloaded the Decal system...and I will spend some time testing and playing around with it over the weekend...I will absolutely share my experience and right up a review for the product.

    Thanks again for the response!
     
  13. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,899
    hi rbarbosa,

    having a look at your special case i think a projected texture limited to a special plane would be the best solution.
    as projectors usually are very heavy to render it is absolutely necessary to limit it to this special plane which gets updated by the object’s position and the ground’s surface.
    as buildings should not be placed on rather uneven terrain i guess the plane does not have to be an accurate decal following excactly the terrain’s shape.
    the angry roots demo does so for the player’s ground shadow. just have a look at it!

    lars
     
    Last edited: Sep 12, 2012
  14. rbarbosa

    rbarbosa

    Joined:
    Jun 20, 2012
    Posts:
    61
    @Lars...you make a great point. For the most part, the land around an RTS structure is normally made level before plotting the building itself. So adding a small plane around the base of the structure (or even a cube...less vertices than the standard Unity plane mesh) that has the appropriate material/texture would work and perhaps be less expensive than using a decal projection.

    Nonetheless...this is mostly just for my experimentation to play around with the Decal System.

    Thanks for the advice, however!
     
  15. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    hi!
    just implemented your system into my game : )

    the problem is that i get very short but noticeable "stops" or "delays" when creating the decal at runtime.
    my world mesh is quite highres. ~50k tris objects.

    is there a way to compute the decal over several frames?
    or any way?

    thank you!
     
  16. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    50k... 50k! :)

    Let me quickly explain you what happens internally. You have a decals mesh and a certain projector according to which the cutting will be made. All the mesh data is added to the decals mesh and after that the 6 cuts take place, before the decals mesh data is passed to as DS_Decals game object that internally passes it to the actual mesh renderer.
    My performance tests showed that the expensive steps are the copy of the mesh data into the decals mesh and the cutting. To my own surprise it did not make sense to split the 6 cuts, because some tend to be very expensive (often just one and sometimes two) while the others are nearly "free". For that reason I didn't provide such a split over several frames functionality. On the other hand my tests were only made with 10k vertices :) .

    I sincerely hope that you don't need this for a mobile platform :) . In that case there may be alternatives. Instead of using the 50k objects, you may have some other meshes or at least the data of them that are not actually displayed, but could be used for the decals. In that case you may use fewer data for the decals computation, which would significantly improve the performance!
    Usually not the whole mesh data is needed, but only the vertices, normals and triangles. It is possible to pass only that data to the decals mesh!

    I can't imagine that it is practically possible to work with 50k object at the moment.

    Hope this helps.
     
  17. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    hi! thx for the answer!

    i had to find, and found a different solution(no decal system, different approach) . so i cant use your system.

    but i must say. for 50k it was very fast! if my game wasnt that fast, i would not have noticed it!
    i will definitely come back to your system if i need a decal system in the future!
     
  18. DHA

    DHA

    Joined:
    Aug 22, 2012
    Posts:
    2
    Hi, Dantus. I've been trying to implement your system into my game and encountered this problem: I'm trying to create decals at runtime and attach them to moving objects. As I've seen on your vid that I need to make the projector a child of that object so that they move together, but I can't access to the transform of the newly created l_DecalProjector ( as in your Bullet example ). Am I missing something here?
     
  19. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    DecalProjectors have no transform, but you can access the position directly. In that case that this doesn't help you, could you post your code here?
     
  20. DHA

    DHA

    Joined:
    Aug 22, 2012
    Posts:
    2
    Thanks for your reply, Dantus. I solved my problem by using DS_DecalProjector instead.
     
  21. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Great! Just for your information, it should also work with DecalProjector even if it has no transform.
     
    Last edited: Sep 20, 2012
  22. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Does this currently work with Unity 4? I'm getting this error when it tries to create a decal:

    (m_Channels[shaderChannelIndex].dimension != 0) == (((m_CurrentChannels (1 << shaderChannelIndex)) != 0))
    UnityEngine.Mesh:set_normals(Vector3[])
    Edelweiss.DecalSystem.Decals:ApplyToDecalsMeshRenderer(DecalsMeshRenderer, DecalsMesh)
    Edelweiss.DecalSystem.Decals:UpdateDecalsMeshes(DecalsMesh)

    I saw someone else asked about this error here: http://answers.unity3d.com/questions/310804/m-channelsshaderchannelindexdimension-0-m-currentc.html

    Also, in the thread for ex2D, someone mentioned getting the error for their product in Unity 4 as well. It seems that Unity 4 made some change to the way that UV's and normals are set? Or it might just be a weird bug that they introduced, since the error message is pretty incomprehensible.
     
  23. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You are absolutely right, it doesn't work properly in Unity 4 yet. I haven't decided yet how to go on. There are some changes in the pipeline and I haven't decided, if I want to make a Unity 4 update with or without the changes.
    But it is out of question that an compatible version is going to be available!
     
  24. ZuruSonaKitsune

    ZuruSonaKitsune

    Joined:
    Sep 25, 2012
    Posts:
    2
    Hi, I've started to use the decal system and it's quite amazing.
    I've been trying to modify the example to make it work with moving object but I was unable to do so correctly.

    I've attached a ds_decal gameObject as a child to the moving object and used the bulletExampleCS script with some slight modification to make it work with the moving object child ds_decal.

    When the object up vector is the same as the world up vector, the decal system works fine, but if the object up vector point to any other direction then decals are created only on some faces and not others.

    How can I make this works?
     
  25. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    It would be awesome if you could post your code here, such that I can reproduce your issue and see what is going wrong. It is nearly impossible to help just with a description.
     
  26. ZuruSonaKitsune

    ZuruSonaKitsune

    Joined:
    Sep 25, 2012
    Posts:
    2
    bullet code :

    Code (csharp):
    1.  
    2. void OnCollisionEnter(Collision Other)
    3. {
    4.     Ray ray = new Ray(positionAtCreation, directionAtCreation);
    5.     RaycastHit hit;
    6.  
    7.     if (Other.collider.Raycast (ray, out hit, 100.0f))
    8.     {
    9.          RealTimePerObjectDecalCreation decal = Other.gameObject.GetComponent("RealTimePerObjectDecalCreation") as RealTimePerObjectDecalCreation;
    10.            
    11.         if (decal != null)
    12.         {
    13.             decal.CreatePerObjectDecal(Other, hit.point, hit.normal);
    14.             Destroy(gameObject);
    15.          } 
    16.     }
    17. }
    18.  
    now the Decal script derived from the BulletExampleCS script from the example.
    The script is attached to the moving game Object and the decalPrefab is set manually.
    Code (csharp):
    1.  
    2.     public GameObject decalsPrefab;
    3.  
    4.     private void Start () {
    5.         m_Decals = decalsPrefab.GetComponentInChildren <DS_Decals> ();
    6.        
    7.         if (m_Decals == null) {
    8.             Debug.LogError ("The 'decalsPrefab' does not contain a 'DS_Decals' instance!");
    9.         } else {
    10.            
    11.                 // Create the decals mesh (intermediate mesh data) for our decals instance.
    12.                 // Further we need a decals mesh cutter instance and the world to decals matrix.
    13.             m_DecalsMesh = new DecalsMesh (m_Decals);
    14.             m_DecalsMeshCutter = new DecalsMeshCutter ();
    15.             m_WorldToDecalsMatrix = m_Decals.CachedTransform.worldToLocalMatrix;
    16.         }
    17.     }
    18.  
    19.     public void CreatePerObjectDecal( Collision collisionInfo,Vector3 contactPoint, Vector3 surfaceNormal)
    20.     {
    21.         // Make sure there are not too many projectors.
    22.         if (m_DecalProjectors.Count >= 50)
    23.         {  
    24.                 // If there are more than 50 projectors, we remove the first one from
    25.                 // our list and certainly from the decals mesh (the intermediate mesh
    26.                 // format). All the mesh data that belongs to this projector will
    27.                 // be removed.
    28.             DecalProjector l_DecalProjector = m_DecalProjectors [0];
    29.             m_DecalProjectors.RemoveAt (0);
    30.             m_DecalsMesh.RemoveProjector (l_DecalProjector);
    31.         }
    32.        
    33.         // Calculate the position and rotation for the new decal projector.
    34.         Vector3 l_ProjectorPosition = contactPoint + (decalProjectorOffset * surfaceNormal.normalized);
    35.         Vector3 l_ForwardDirection = Vector3.up;
    36.         Vector3 l_UpDirection = surfaceNormal;
    37.         Quaternion l_ProjectorRotation = Quaternion.LookRotation (l_ForwardDirection, l_UpDirection);
    38.        
    39.         // We hit a collider. Next we have to find the mesh that belongs to the collider.
    40.         // That step depends on how you set up your mesh filters and collider relative to
    41.         // each other in the game objects. It is important to have a consistent way in order
    42.         // to have a simpler implementation.
    43.        
    44.        
    45.         MeshCollider l_MeshCollider = collisionInfo.collider.GetComponent <MeshCollider> ();
    46.         MeshFilter l_MeshFilter = collisionInfo.collider.GetComponent <MeshFilter> ();
    47.  
    48.        
    49.         if (l_MeshCollider != null || l_MeshFilter != null) {
    50.             Mesh l_Mesh = null;
    51.             if (l_MeshCollider != null) {
    52.                
    53.                     // Mesh collider was hit. Just use the mesh data from that one.
    54.                 l_Mesh = l_MeshCollider.sharedMesh;
    55.             } else if (l_MeshFilter != null) {
    56.                
    57.                     // Otherwise take the data from the shared mesh.
    58.                 l_Mesh = l_MeshFilter.sharedMesh;
    59.             }
    60.            
    61.             if (l_Mesh != null) {
    62.                
    63.                     // Create the decal projector.
    64.                 DecalProjector l_DecalProjector = new DecalProjector (l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);
    65.  
    66.                     // Add the projector to our list and the decals mesh, such that both are
    67.                     // synchronized. All the mesh data that is now added to the decals mesh
    68.                     // will belong to this projector.
    69.                 m_DecalProjectors.Add (l_DecalProjector);
    70.                 m_DecalsMesh.AddProjector (l_DecalProjector);
    71.                
    72.                     // Get the required matrices.
    73.                 Matrix4x4 l_WorldToMeshMatrix = collisionInfo.collider.renderer.transform.worldToLocalMatrix;
    74.                 Matrix4x4 l_MeshToWorldMatrix = collisionInfo.collider.renderer.transform.localToWorldMatrix;
    75.                
    76.                     // Add the mesh data to the decals mesh, cut and offset it before we pass it
    77.                     // to the decals instance to be displayed.
    78.                 m_DecalsMesh.Add (l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix);                       
    79.                 m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh);
    80.                 m_DecalsMesh.OffsetActiveProjectorVertices ();
    81.                 m_Decals.UpdateDecalsMeshes (m_DecalsMesh);
    82.                
    83.                     // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
    84.                     // based on the surface you have hit.
    85.                 NextUVRectangleIndex ();
    86.             }
    87.         }
    88.     }
    89.  

    The rest of the code is exactly the same as the original file.
     
  27. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I had a closer look at the issue. I didn't have the time to analyze your code yet, but quickly made my own implementation. The first script is like the usual bullet example, but there is a if to find out, whether we are dealing with a dynamic object. In that case we call the method from the second script. The first script is a replacement for the bullet example script, while the secondary one is supposed to be placed in the dynamic object. I assume that the dynamic object has a rigidbody, but you can certainly change that.
    I am not entirely sure if there are culling angle issues. I had to increase it to 180 in order to get better results, but I couldn't have a close enough look yet in order to find out if it is working correctly.

    Hope this helps

    Code (csharp):
    1. //
    2. // Author:
    3. //   Andreas Suter (andy@edelweissinteractive.com)
    4. //
    5. // Copyright (C) 2012 Edelweiss Interactive (http://edelweissinteractive.com)
    6. //
    7.  
    8. #pragma strict
    9.  
    10. import System.Collections.Generic;
    11. import Edelweiss.DecalSystem;
    12.  
    13. public class BulletExampleDynamicJS extends MonoBehaviour {
    14.  
    15.         // The prefab which contains the DS_Decals script with already set material and
    16.         // uv rectangles.
    17.     var decalsPrefab : GameObject;
    18.    
    19.         // The reference to the instantiated prefab's DS_Decals instance.
    20.     private var m_Decals : DS_Decals;
    21.     private var m_WorldToDecalsMatrix : Matrix4x4;
    22.  
    23.         // All the projectors that were created at runtime.
    24.     private var m_DecalProjectors : List.<DecalProjector> = List.<DecalProjector> ();
    25.    
    26.         // Intermediate mesh data. Mesh data is added to that one for a specific projector
    27.         // in order to perform the cutting.
    28.     private var m_DecalsMesh : DecalsMesh;
    29.     private var m_DecalsMeshCutter : DecalsMeshCutter;
    30.    
    31.         // The raycast hits a collider at a certain position. This value indicated how far we need to
    32.         // go back from that hit point along the ray of the raycast to place the new decal projector. Set
    33.         // this value to 0.0f to see why this is needed.
    34.     var decalProjectorOffset : float = 0.5;
    35.    
    36.         // The size of new decal projectors.
    37.     var decalScale : Vector3 = Vector3 (0.2, 2.0, 0.2);
    38.     var cullingAngle : float = 90.0;
    39.     var meshOffset : float = 0.001;
    40.    
    41.         // We iterate through all the defined uv rectangles. This one indices which index we are using at
    42.         // the moment.
    43.     private var m_UVRectangleIndex : int = 0;
    44.  
    45.         // Move on to the next uv rectangle index.
    46.     private function NextUVRectangleIndex () {
    47.         m_UVRectangleIndex = m_UVRectangleIndex + 1;
    48.         if (m_UVRectangleIndex >= m_Decals.uvRectangles.Length) {
    49.             m_UVRectangleIndex = 0;
    50.         }
    51.     }
    52.    
    53.     function Start () {
    54.    
    55.             // Instantiate the prefab and get its decals instance.
    56.         var l_Instance = UnityEngine.Object.Instantiate (decalsPrefab);
    57.         m_Decals = l_Instance.GetComponentInChildren.<DS_Decals> ();
    58.        
    59.         if (m_Decals == null) {
    60.             Debug.LogError ("The 'decalsPrefab' does not contain a 'DS_Decals' instance!");
    61.         } else {
    62.        
    63.                 // Create the decals mesh (intermediate mesh data) for our decals instance.
    64.                 // Further we need a decals mesh cutter instance and the world to decals matrix.
    65.             m_DecalsMesh = new DecalsMesh (m_Decals);
    66.             m_DecalsMeshCutter = new DecalsMeshCutter ();
    67.             m_WorldToDecalsMatrix = m_Decals.CachedTransform.worldToLocalMatrix;
    68.         }
    69.     }
    70.  
    71.     function Update () {
    72.         if (Input.GetButtonDown ("Fire1")) {
    73.             var l_Ray = Camera.main.ViewportPointToRay (Vector3 (0.5f, 0.5f, 0.0f));
    74.             var l_RaycastHit : RaycastHit;
    75.             if (Physics.Raycast (l_Ray, l_RaycastHit, Mathf.Infinity)) {
    76.                
    77.                 if (l_RaycastHit.rigidbody == null) {
    78.                
    79.                         // Collider hit.
    80.                    
    81.                         // Make sure there are not too many projectors.
    82.                     if (m_DecalProjectors.Count >= 50) {
    83.                    
    84.                             // If there are more than 50 projectors, we remove the first one from
    85.                             // our list and certainly from the decals mesh (the intermediate mesh
    86.                             // format). All the mesh data that belongs to this projector will
    87.                             // be removed.
    88.                         var l_DecalProjectorForRemoval = m_DecalProjectors [0];
    89.                         m_DecalProjectors.RemoveAt (0);
    90.                         m_DecalsMesh.RemoveProjector (l_DecalProjectorForRemoval);
    91.                     }
    92.                    
    93.                         // Calculate the position and rotation for the new decal projector.
    94.                     var l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * l_Ray.direction.normalized);
    95.                     var l_ForwardDirection = Camera.main.transform.up;
    96.                     var l_UpDirection = - Camera.main.transform.forward;
    97.                     var l_ProjectorRotation = Quaternion.LookRotation (l_ForwardDirection, l_UpDirection);
    98.                    
    99.                         // Randomize the rotation.
    100.                     var l_RandomRotation = Quaternion.Euler (0.0f, Random.Range (0.0f, 360.0f), 0.0f);
    101.                     l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation;
    102.                    
    103.                     var l_TerrainCollider : TerrainCollider = l_RaycastHit.collider as TerrainCollider;
    104.                     if (l_TerrainCollider != null) {
    105.                    
    106.                             // Terrain collider hit.
    107.                    
    108.                         var l_Terrain : Terrain = l_TerrainCollider.GetComponent.<Terrain> ();
    109.                         if (l_Terrain != null) {
    110.                            
    111.                                 // Create the decal projector with all the required information.
    112.                             var l_TerrainDecalProjector = DecalProjector (l_ProjectorPosition, l_ProjectorRotation, decalScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);
    113.                            
    114.                                 // Add the projector to our list and the decals mesh, such that both are
    115.                                 // synchronized. All the mesh data that is now added to the decals mesh
    116.                                 // will belong to this projector.
    117.                             m_DecalProjectors.Add (l_TerrainDecalProjector);
    118.                             m_DecalsMesh.AddProjector (l_TerrainDecalProjector);
    119.                            
    120.                                 // The terrain data has to be converted to the decals instance's space.
    121.                             var l_TerrainToDecalsMatrix = Matrix4x4.TRS (l_Terrain.transform.position, Quaternion.identity, Vector3.one) * m_WorldToDecalsMatrix;
    122.                            
    123.                                 // Pass the terrain data with the corresponding conversion to the decals mesh.
    124.                             m_DecalsMesh.Add (l_Terrain, l_TerrainToDecalsMatrix);
    125.                        
    126.                                 // Cut the data in the decals mesh accoring to the size and position of the decal projector. Offset the
    127.                                 // vertices afterwards and pass the newly computed mesh to the decals instance, such that it becomes
    128.                                 // visible.
    129.                             m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh);
    130.                             m_DecalsMesh.OffsetActiveProjectorVertices ();
    131.                             m_Decals.UpdateDecalsMeshes (m_DecalsMesh);
    132.                            
    133.                                 // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
    134.                                 // based on the surface you have hit.
    135.                             NextUVRectangleIndex ();
    136.                         } else {
    137.                             Debug.Log ("Terrain is null!");
    138.                         }
    139.                        
    140.                     } else {
    141.                        
    142.                             // We hit a collider. Next we have to find the mesh that belongs to the collider.
    143.                             // That step depends on how you set up your mesh filters and collider relative to
    144.                             // each other in the game objects. It is important to have a consistent way in order
    145.                             // to have a simpler implementation.
    146.                        
    147.                         var l_MeshCollider = l_RaycastHit.collider.GetComponent.<MeshCollider> ();
    148.                         var l_MeshFilter = l_RaycastHit.collider.GetComponent.<MeshFilter> ();
    149.                        
    150.                         if (l_MeshCollider != null || l_MeshFilter != null) {
    151.                             var l_Mesh : Mesh = null;
    152.                             if (l_MeshCollider != null) {
    153.                            
    154.                                     // Mesh collider was hit. Just use the mesh data from that one.
    155.                                 l_Mesh = l_MeshCollider.sharedMesh;
    156.                             } else if (l_MeshFilter != null) {
    157.                            
    158.                                     // Otherwise take the data from the shared mesh.
    159.                                 l_Mesh = l_MeshFilter.sharedMesh;
    160.                             }
    161.                            
    162.                             if (l_Mesh != null) {
    163.                            
    164.                                     // Create the decal projector.
    165.                                 var l_DecalProjector = DecalProjector (l_ProjectorPosition, l_ProjectorRotation, decalScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);
    166.                                
    167.                                     // Add the projector to our list and the decals mesh, such that both are
    168.                                     // synchronized. All the mesh data that is now added to the decals mesh
    169.                                     // will belong to this projector.
    170.                                 m_DecalProjectors.Add (l_DecalProjector);
    171.                                 m_DecalsMesh.AddProjector (l_DecalProjector);
    172.                                
    173.                                     // Get the required matrices.
    174.                                 var l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix;
    175.                                 var l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix;
    176.                                
    177.                                     // Add the mesh data to the decals mesh, cut and offset it before we pass it
    178.                                     // to the decals instance to be displayed.
    179.                                 m_DecalsMesh.Add (l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix);                       
    180.                                 m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh);
    181.                                 m_DecalsMesh.OffsetActiveProjectorVertices ();
    182.                                 m_Decals.UpdateDecalsMeshes (m_DecalsMesh);
    183.                                
    184.                                 NextUVRectangleIndex ();
    185.                             }
    186.                         }
    187.                     }
    188.                    
    189.                 } else {
    190.                    
    191.                         // Dynamic object case.
    192.                     var l_BulletExampleDynamicObject = l_RaycastHit.collider.GetComponent.<BulletExampleDynamicObjectJS> ();
    193.                     l_BulletExampleDynamicObject.AddDecalProjector (l_Ray, l_RaycastHit);
    194.                 }
    195.             }
    196.         }
    197.     }
    198. }
    Code (csharp):
    1. //
    2. // Author:
    3. //   Andreas Suter (andy@edelweissinteractive.com)
    4. //
    5. // Copyright (C) 2012 Edelweiss Interactive (http://edelweissinteractive.com)
    6. //
    7.  
    8. #pragma strict
    9.  
    10. import System.Collections.Generic;
    11. import Edelweiss.DecalSystem;
    12.  
    13. public class BulletExampleDynamicObjectJS extends MonoBehaviour {
    14.  
    15.         // The prefab which contains the DS_Decals script with already set material and
    16.         // uv rectangles.
    17.     var decalsPrefab : GameObject;
    18.    
    19.         // The reference to the instantiated prefab's DS_Decals instance.
    20.     private var m_Decals : DS_Decals;
    21.     private var m_WorldToDecalsMatrix : Matrix4x4;
    22.  
    23.         // All the projectors that were created at runtime.
    24.     private var m_DecalProjectors : List.<DecalProjector> = List.<DecalProjector> ();
    25.    
    26.         // Intermediate mesh data. Mesh data is added to that one for a specific projector
    27.         // in order to perform the cutting.
    28.     private var m_DecalsMesh : DecalsMesh;
    29.     private var m_DecalsMeshCutter : DecalsMeshCutter;
    30.    
    31.         // The raycast hits a collider at a certain position. This value indicated how far we need to
    32.         // go back from that hit point along the ray of the raycast to place the new decal projector. Set
    33.         // this value to 0.0f to see why this is needed.
    34.     var decalProjectorOffset : float = 0.5;
    35.    
    36.         // The size of new decal projectors.
    37.     var decalScale : Vector3 = Vector3 (0.2, 2.0, 0.2);
    38.     var cullingAngle : float = 180.0;
    39.     var meshOffset : float = 0.001;
    40.    
    41.         // We iterate through all the defined uv rectangles. This one indices which index we are using at
    42.         // the moment.
    43.     private var m_UVRectangleIndex : int = 0;
    44.  
    45.         // Move on to the next uv rectangle index.
    46.     private function NextUVRectangleIndex () {
    47.         m_UVRectangleIndex = m_UVRectangleIndex + 1;
    48.         if (m_UVRectangleIndex >= m_Decals.uvRectangles.Length) {
    49.             m_UVRectangleIndex = 0;
    50.         }
    51.     }
    52.    
    53.     function Start () {
    54.    
    55.             // Instantiate the prefab and get its decals instance.
    56.         var l_Instance = UnityEngine.Object.Instantiate (decalsPrefab);
    57.         m_Decals = l_Instance.GetComponentInChildren.<DS_Decals> ();
    58.        
    59.             // Make sure the decals move with this dynamic object.
    60.         m_Decals.transform.parent = transform;
    61.         m_Decals.transform.localPosition = Vector3.zero;
    62.         m_Decals.transform.localScale = Vector3.one;
    63.        
    64.         if (m_Decals == null) {
    65.             Debug.LogError ("The 'decalsPrefab' does not contain a 'DS_Decals' instance!");
    66.         } else {
    67.        
    68.                 // Create the decals mesh (intermediate mesh data) for our decals instance.
    69.                 // Further we need a decals mesh cutter instance and the world to decals matrix.
    70.             m_DecalsMesh = new DecalsMesh (m_Decals);
    71.             m_DecalsMeshCutter = new DecalsMeshCutter ();
    72.             m_WorldToDecalsMatrix = m_Decals.CachedTransform.worldToLocalMatrix;
    73.         }
    74.     }
    75.  
    76.     function AddDecalProjector (a_Ray : Ray, a_RaycastHit : RaycastHit) {
    77.             // Make sure there are not too many projectors.
    78.         if (m_DecalProjectors.Count >= 50) {
    79.        
    80.                 // If there are more than 50 projectors, we remove the first one from
    81.                 // our list and certainly from the decals mesh (the intermediate mesh
    82.                 // format). All the mesh data that belongs to this projector will
    83.                 // be removed.
    84.             var l_DecalProjectorForRemoval = m_DecalProjectors [0];
    85.             m_DecalProjectors.RemoveAt (0);
    86.             m_DecalsMesh.RemoveProjector (l_DecalProjectorForRemoval);
    87.         }
    88.        
    89.             // Calculate the position and rotation for the new decal projector.
    90.         var l_ProjectorPosition = a_RaycastHit.point - (decalProjectorOffset * a_Ray.direction.normalized);
    91.         var l_ForwardDirection = Camera.main.transform.up;
    92.         var l_UpDirection = - Camera.main.transform.forward;
    93.         var l_ProjectorRotation = Quaternion.LookRotation (l_ForwardDirection, l_UpDirection);
    94.        
    95.             // Randomize the rotation.
    96.         var l_RandomRotation = Quaternion.Euler (0.0f, Random.Range (0.0f, 360.0f), 0.0f);
    97.         l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation;
    98.        
    99.        
    100.             // We hit a collider. Next we have to find the mesh that belongs to the collider.
    101.             // That step depends on how you set up your mesh filters and collider relative to
    102.             // each other in the game objects. It is important to have a consistent way in order
    103.             // to have a simpler implementation.
    104.        
    105.         var l_MeshCollider = a_RaycastHit.collider.GetComponent.<MeshCollider> ();
    106.         var l_MeshFilter = a_RaycastHit.collider.GetComponent.<MeshFilter> ();
    107.        
    108.         if (l_MeshCollider != null || l_MeshFilter != null) {
    109.             var l_Mesh : Mesh = null;
    110.             if (l_MeshCollider != null) {
    111.            
    112.                     // Mesh collider was hit. Just use the mesh data from that one.
    113.                 l_Mesh = l_MeshCollider.sharedMesh;
    114.             } else if (l_MeshFilter != null) {
    115.            
    116.                     // Otherwise take the data from the shared mesh.
    117.                 l_Mesh = l_MeshFilter.sharedMesh;
    118.             }
    119.            
    120.             if (l_Mesh != null) {
    121.            
    122.                     // Create the decal projector.
    123.                 var l_DecalProjector = DecalProjector (l_ProjectorPosition, l_ProjectorRotation, decalScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);
    124.                
    125.                     // Add the projector to our list and the decals mesh, such that both are
    126.                     // synchronized. All the mesh data that is now added to the decals mesh
    127.                     // will belong to this projector.
    128.                 m_DecalProjectors.Add (l_DecalProjector);
    129.                 m_DecalsMesh.AddProjector (l_DecalProjector);
    130.                
    131.                     // Get the required matrices.
    132.                 var l_WorldToMeshMatrix = a_RaycastHit.collider.renderer.transform.worldToLocalMatrix;
    133.                 var l_MeshToWorldMatrix = a_RaycastHit.collider.renderer.transform.localToWorldMatrix;
    134.                
    135.                     // Add the mesh data to the decals mesh, cut and offset it before we pass it
    136.                     // to the decals instance to be displayed.
    137.                 m_DecalsMesh.Add (l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix);                       
    138.                 m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh);
    139.                 m_DecalsMesh.OffsetActiveProjectorVertices ();
    140.                 m_Decals.UpdateDecalsMeshes (m_DecalsMesh);
    141.                
    142.                 NextUVRectangleIndex ();
    143.             }
    144.         }
    145.     }
    146. }
     
  28. Imre

    Imre

    Joined:
    Sep 27, 2012
    Posts:
    73
    Hi,
    First thanks for this excellent tool!
    Found one small issue when target object / mesh is rotated x=90, Y=180, decals are projected to wrong side of surface.
    Steps to reproduce.
    1. Create Cube (make sure it's rotated 0, 0, 0)
    2. Create "Decals", (random material, all default settings will work)
    3. Change projector so, that it projects image to cube.
    4. Rotate cube x=90, y=180
    5. Click Update All Projectors
    Decal is projected to inside.

    Thanks, i hope this helps to improve already excellent tool!
    Imre
     
  29. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Thanks for pointing that out! That one was reported just recently by mail and I was just able to resolved it. It will take one or two weeks until I can publish the next versions, because of a lack of time.

    Thanks a lot for taking the time and making it reproducible!
     
  30. Wolf5370

    Wolf5370

    Joined:
    Aug 31, 2012
    Posts:
    10
    Hi, just wanted to share an issue (self inflicted) that took me an age to work out, that others might fall into also.

    The system makes use of the tag MainCamera (used in the scripts too). I had more than one camera in my scene, the original Main Camera and the FPS Camera. Both were tagged with MainCamera (by default?). This caused the following issue that can be hard to sort out.

    Putting a sphere (for example) in the scene, using script such as BulletExampleCS/JS, then walking around shooting nice little holes in it. What I was getting was that I could shoot happily when facing the object or from +/- 90 from front on, but nothing from beyong these points (behind). The Decals Clone that is created on start, was not moving for shots from these angles at all. (This was maddening and hard to spot as other effects were kicking in - like sparks/blood splatter, ausio, etc, but not the decal).

    Obvious in hindsight that the fixed scene camera (which took presidence) was culling the reverse side as it saw it. Took me several hair pulling days to discover my faux pas - simply setting the tag to Untagged on the scene camera fixed it instantly. Doh!
     
  31. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    Hi!

    I changed my mind and implemented your decal system. works great, but one thing.

    sometimes it changes my blue decal texture into different colors like green. and after some time it just stops creating the decals.
    in the editor this happens rarely ( but still sometimes) but in the standalone exe it happens always.

    attached the script (yours slightly changed), and a screenshot.

    thanks!

    Code (csharp):
    1.  
    2. //
    3. // Author:
    4. //   Andreas Suter (andy@edelweissinteractive.com)
    5. //
    6. // Copyright (C) 2012 Edelweiss Interactive (http://edelweissinteractive.com)
    7. //
    8.  
    9. #pragma strict
    10.  
    11. import System.Collections.Generic;
    12. import Edelweiss.DecalSystem;
    13.  
    14.  
    15.  
    16.         // The prefab which contains the DS_Decals script with already set material and
    17.         // uv rectangles.
    18.  
    19.    
    20.         // The reference to the instantiated prefab's DS_Decals instance.
    21.     private var m_Decals : DS_Decals;
    22.     private var m_WorldToDecalsMatrix : Matrix4x4;
    23.  
    24.         // All the projectors that were created at runtime.
    25.     private var m_DecalProjectors : List.<DecalProjector> = List.<DecalProjector> ();
    26.    
    27.         // Intermediate mesh data. Mesh data is added to that one for a specific projector
    28.         // in order to perform the cutting.
    29.     private var m_DecalsMesh : DecalsMesh;
    30.     private var m_DecalsMeshCutter : DecalsMeshCutter;
    31.    
    32.         // The raycast hits a collider at a certain position. This value indicated how far we need to
    33.         // go back from that hit point along the ray of the raycast to place the new decal projector. Set
    34.         // this value to 0.0f to see why this is needed.
    35.     private var decalProjectorOffset : float = 0.5;
    36.    
    37.         // The size of new decal projectors.
    38.     private var decalScale : Vector3 = Vector3 (2, 2.0, 2);
    39.     private var cullingAngle : float = 90.0;
    40.     private var meshOffset : float = 0.005;
    41.    
    42.         // We iterate through all the defined uv rectangles. This one indices which index we are using at
    43.         // the moment.
    44.     private var m_UVRectangleIndex : int = 0;
    45.  
    46.         // Move on to the next uv rectangle index.
    47.     private function NextUVRectangleIndex () {
    48.         m_UVRectangleIndex = m_UVRectangleIndex + 1;
    49.         if (m_UVRectangleIndex >= m_Decals.uvRectangles.Length) {
    50.             m_UVRectangleIndex = 0;
    51.         }
    52.     }
    53.    
    54.     function Start () {
    55.    
    56.  
    57.         m_Decals = gameObject.Find("Bullet Decals").GetComponentInChildren.<DS_Decals> ();
    58.        
    59.  
    60.        
    61.                 // Create the decals mesh (intermediate mesh data) for our decals instance.
    62.                 // Further we need a decals mesh cutter instance and the world to decals matrix.
    63.             m_DecalsMesh = new DecalsMesh (m_Decals);
    64.             m_DecalsMeshCutter = new DecalsMeshCutter ();
    65.             m_WorldToDecalsMatrix = m_Decals.CachedTransform.worldToLocalMatrix;
    66.             transform.position.y = 9999;
    67.        
    68.     }
    69.  
    70.     function Update () {
    71.         if (transform.position.y < 800) {
    72.          transform.Translate(0, 0, -0.5, Space.Self);
    73.             // var l_Ray = Camera.main.ViewportPointToRay (Vector3 (0.5f, 0.5f, 0.0f));
    74.             var l_RaycastHit : RaycastHit;
    75.  if (Physics.Raycast (transform.position, transform.TransformDirection (Vector3(0.0,0.0,1)), l_RaycastHit, 100)) {
    76.                
    77.                     // Collider hit.
    78.                
    79.                     // Make sure there are not too many projectors.
    80.                
    81.                     // Calculate the position and rotation for the new decal projector.
    82.                 var l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * transform.TransformDirection (Vector3(0.0,0.0,2)));
    83.  
    84.                 var l_ProjectorRotation = Quaternion.LookRotation (transform.up, - transform.forward);
    85.                
    86.                     // Randomize the rotation.
    87.        
    88.                 l_ProjectorRotation = l_ProjectorRotation *  Quaternion.Euler (0.0f, Random.value *  360, 0.0f);
    89.                
    90.                
    91.    
    92.                    
    93.                         // We hit a collider. Next we have to find the mesh that belongs to the collider.
    94.                         // That step depends on how you set up your mesh filters and collider relative to
    95.                         // each other in the game objects. It is important to have a consistent way in order
    96.                         // to have a simpler implementation.
    97.                    
    98.                     var l_MeshCollider = l_RaycastHit.collider.GetComponent.<MeshCollider> ();
    99.                     //var l_MeshFilter = l_RaycastHit.collider.GetComponent.<MeshFilter> ();
    100.                    
    101.                     if (l_MeshCollider != null ) {
    102.                         var l_Mesh : Mesh = null;
    103.                         if (l_MeshCollider != null) {
    104.                        
    105.                                 // Mesh collider was hit. Just use the mesh data from that one.
    106.                             l_Mesh = l_MeshCollider.sharedMesh;
    107.                         }
    108.                         }
    109.                        
    110.                         if (l_Mesh != null) {
    111.                        
    112.                                 // Create the decal projector.
    113.                             var l_DecalProjector = DecalProjector (l_ProjectorPosition, l_ProjectorRotation, decalScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);
    114.                            
    115.                                 // Add the projector to our list and the decals mesh, such that both are
    116.                                 // synchronized. All the mesh data that is now added to the decals mesh
    117.                                 // will belong to this projector.
    118.                             m_DecalProjectors.Add (l_DecalProjector);
    119.                             m_DecalsMesh.AddProjector (l_DecalProjector);
    120.                            
    121.                                 // Get the required matrices.
    122.    
    123.                            
    124.                                 // Add the mesh data to the decals mesh, cut and offset it before we pass it
    125.                                 // to the decals instance to be displayed.
    126.                             m_DecalsMesh.Add (l_Mesh, l_RaycastHit.collider.renderer.transform.worldToLocalMatrix, l_RaycastHit.collider.renderer.transform.localToWorldMatrix);                       
    127.                             m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh);
    128.                             m_DecalsMesh.OffsetActiveProjectorVertices ();
    129.                             m_Decals.UpdateDecalsMeshes (m_DecalsMesh);
    130.                            
    131.                             transform.position.y = 9999;
    132.                             //NextUVRectangleIndex ();
    133.                        
    134.                    
    135.                 }
    136.             }
    137.         }
    138.     }
    139.  
    140.  
    141.  
     

    Attached Files:

  32. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Hi Lizzard4000

    Let's tackle the wrong colors first.
    I need to know which shader you are using? In the standalone it looks as if vertex colors are used, while this doesn't seem to be the case in the editor (or maybe just white or blue vertex colors).

    I am a little bit confused by your script changes. First it is not necessary to click in order to create a new projector, which means the whole place would be filled with decals, which is not the case in your screenshot.
    What I don't understand at all is, why do you change the position at all? The DS_Decals is in a child object and if you move the current game object around, it may become invisible. Could you explain that a little?
     
  33. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    hi!

    i have a gameobject with the DS_Decals script attached and the "Decals Mesh Renderer" as child. i didnt change much settings, just added the right material and one "UVrectangle".
    then i have another gameObject("BulletShoot") with the above script added.
    everytime i shoot i set the "bulletShoot" object to the position of the hit point. it executes the script because " if (transform.position.y < 800)" allows that.
    it creates the decals at that point and goes back to y=9999 with the last line "transform.position.y = 9999;".

    the color changeing happens with your and the builtin transparent shaders.

    Update: i tried a Cutout shader and it works perfectly! no more color changing and no more disappearing!
    so for me that fixxed it all : )

    thx
     
  34. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Now I see how you are using the transform, though it still seems unconventional :)

    It's great that it works now! Which shader have you used so far? Did you use the transparent one that comes with the Decal System? In that case I would try to resolve the issue.
     
  35. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    the problems happes with your shaders (transparent Diffuse / Colored) and the "Particles/Alpha Blended" shader.
    it works with all cutout shaders and, what i just found out, with the builtin "transparent/Difuse" works too.

    : )
     
  36. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The issue happens with both my Transparent Diffuse and Transparent Diffuse Colored shaders? That's unexpected because they are heavily built on Unity's Transparent Diffuse shader.
     
  37. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
  38. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    This issue is resolved with the newest version of the Decal System (1.2.1). Make sure that you extract Unity4.unitypackage to get the dll's for Unity 4.
     
  39. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I got a mail that Decal System 1.2.1 is accepted, but its status is currently Error. I am sure this is resolved real soon, stay tuned!
     
  40. pneill

    pneill

    Joined:
    Jan 21, 2007
    Posts:
    207
    Hi There,

    I'm trying to get the dynamic decal script to work that's based upon the Bullet Lightmap Example. The idea is to create a decal on the ground after a building is destroyed. The ground is a simple plane. The rubble prefab is pretty much an exact copy of the bullet Lightmap Decal prefab.

    When I try to create the decal, I get the following error

    Any idea what's happening?
     
  41. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Hey pneill,

    This happens if you decals instance requires uv2's, but the mesh you want to add to the decals mesh does not have them, or does not have the correct amount of uv2's. In that case the Decal System throws exactly this exception.
    So, I assume that the mesh you are trying to add does not have uv2's.
     
  42. pneill

    pneill

    Joined:
    Jan 21, 2007
    Posts:
    207
    Hi Dantus,

    One other other question. I'm trying create a dynamic decal effect that I want to fade in the decal. I thought about doing this with the material, but it looks like each decal shares the same material instance so it's not possible to dynamically adjust the alpha channel for a particular decal instance.

    Is there a recommended approach here for doing something like this?

    Thanks,
    Pat
     
  43. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    If you want to fade a whole decals instance (several projectors), you can just create a copy of the material and use the copy for that decals instance in order to fade all its projectors at once.
    On the other hand, if you want to fade some projectors of a decals instance, you can achieve that by using vertex colors for the fading. There is an example in the Decal System about how to use vertex colors named Colored Bullet Example or something in that direction.

    Hope this helps
     
  44. Ken-T

    Ken-T

    Joined:
    Jun 15, 2012
    Posts:
    19
    Hi, I've have been looking for example using SkinnedDecals. Can you point me
    to one?

    Also, am I correct in assuming it is for use when applying decals to
    object that have Skinned Mesh Renders?
     
  45. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    There is no example, yet. You are right that it is supposed to work with Skinned Mesh Renderers. Be warned that this is very tricky. First of all there are some technical issues that prevent you from having accurate skinned decals at all, further my implementation has some issues. It's also mentioned in the documentation that the skinned decals implementation is not yet production ready. I am pretty sure this is not what you wanted to hear, but I can't change it at the moment.
     
  46. Ken-T

    Ken-T

    Joined:
    Jun 15, 2012
    Posts:
    19
    How about a mesh cutting example? I can create a current mesh by applying the state of the bones to the
    sharedMesh. Therefore if I can cut a mesh, instantiate it, and then add texture, I can keep it in place by using
    lateUpdate and the bones. But I can figure out where you use the cutting classes.
     
  47. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The way to get skinned decals meshes through scripting is pretty identical to the decals meshes themselves. You can use that code to get an idea about how it works for skinned meshes. Instead of using an object of type DecalsMesh, it is of type SkinnedDecalsMesh. And you don't have to use the DecalsMeshCutter, but the SkinnedDecalsMeshCutter. The API itself is also very close.
    Don't hesitate to post a script here if something is not clear for you!
     
  48. Ken-T

    Ken-T

    Joined:
    Jun 15, 2012
    Posts:
    19
    So, I took your suggestion and I implemented a very simple Skinned Decal
    example. Here is a link https://dl.dropbox.com/u/2092395/EdelweissSkinnedTest.unitypackage
    You apply decal by clicking on the scene. It's built a simply as possible to avoid distractions. The decal is applied
    where the camera is looking.

    I have a couple of questions:

    1. Does it look like I'm doing things correctly?
    2. I've noticed the full decal doesn't always appear and depending where it is placed might not appear at all. Why? And can I adjust for this in code?


    Thanks!
     
  49. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Hey Ken

    My first impression of your code is that it looks correct. I need to have a closer look at it and I will compare it to the way it works in my editor code. This will take some time. Just wanted to let you know that I am looking into this issue.
    But once more, be aware that I don't see the Skinned Decals Mesh in a production ready state!
     
  50. janpec

    janpec

    Joined:
    Jul 16, 2010
    Posts:
    3,520
    This is must to use for me in future, will make purchase soon. Just one question maybe does each decal adds 1 drawcal?