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. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The Decal System Pro allows you to project selected parts of materials onto existing geometry. It has been designed to be intuitively usable and highly configurable at the same time.

    Main Features
    - Outstanding editor integration
    - Draw call optimization
    - Lightmapping and LOD support
    - Vertex Colors
    - Texture Atlas Assets
    - Affect Detail

    More Videos

     
    Last edited: Jul 23, 2014
    Deanit likes this.
  2. xandeck

    xandeck

    Joined:
    Apr 2, 2009
    Posts:
    563
    Really nice man, just saw the video... and free is totally nice too XD
     
  3. mrbdrm

    mrbdrm

    Joined:
    Mar 22, 2009
    Posts:
    510
    am i reading right ? Free ?
    thank you so much
     
  4. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Really nice work :)
     
  5. i-tech

    i-tech

    Joined:
    Jan 2, 2011
    Posts:
    195
    Expect an donation if the package will be stable :)
     
  6. jgodfrey

    jgodfrey

    Joined:
    Nov 14, 2009
    Posts:
    564
    Looks really nice Dantus!
     
  7. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Thanks for all the positive feedback and it has not even been released :)
     
  8. elias_t

    elias_t

    Joined:
    Sep 17, 2010
    Posts:
    1,367
    Nice!

    Looking forward to test it.
     
  9. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Looking great. Can't wait to test it. How does it fare performance wise?
    Thanks a lot :)
     
  10. Andrew_atl

    Andrew_atl

    Joined:
    Sep 21, 2010
    Posts:
    103
    Awesome! Will be sure to donate after I get a chance to play with it.
     
  11. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Great, such a lot of posts... :)

    @nuverian: Mesh based decals were always computationally expensive and will always be. I did my best to optimize it and there is certainly always room for improvements. In the case that it is not fast enough - and there will always be scenes for which this is true - you can deactivate the Interactive Update and manually update the projectors.
     
  12. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Thanks for info Dantus. I will keep that in mind. Looking forward to test it.
     
  13. Swearsoft

    Swearsoft

    Joined:
    Mar 19, 2009
    Posts:
    1,632
    Looks good.
     
  14. MarigoldFleur

    MarigoldFleur

    Joined:
    May 12, 2012
    Posts:
    1,353
    edit: Whoops, I missed the part where my question was answered in the first post.
     
    Last edited: Jun 30, 2012
  15. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    So the question is.... how many draw calls? Is it one per mesh? If you use the same texture for each mesh, is it only one draw call for all of them? Is this better or worse than the bootcamp decal system? Can you position, rotate and scale the decals through script during runtime? It looks awesome by the way!
     
  16. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @macdude2: Have a look at the introduction video. At 9:40 there is an explanation about the mesh creation and draw calls.
    I made some comparison with the Bootcamp implementation. What I can say is that the Decal System uses less memory and produces less geometry. On the other hand it was also slightly slower.
    It works at runtime and the project also contains a very simple implementation to demonstrate that. You can nearly to the same at runtime with scripting as can be done in the editor.
     
  17. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Added a download link in the first post while it is not available in the Asset Store.
     
  18. nuverian

    nuverian

    Joined:
    Oct 3, 2011
    Posts:
    2,087
    Thanks! Going to try this...now, and let you know.
     
  19. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    Just tried it out... excellent job! It will work perfectly for my upcoming project. I was trying to use the one from the bootcamp demo, but I think yours works a ton better. Love the UI and thanks so much for making it free.
     
  20. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @macdude2: Great you like it! Don't forget to rate, as soon as it is in the Asset Store :)
     
  21. Wild-Factor

    Wild-Factor

    Joined:
    Oct 11, 2010
    Posts:
    607
    Seam reeeaallly good!
    Thanks Dantus
     
  22. elias_t

    elias_t

    Joined:
    Sep 17, 2010
    Posts:
    1,367
    Ok I have tested it also.

    Excelent! It fits exactly my needs. I could not think of anything else to add in this system.
    I will donate soon.

    Thanks again.
     
    Last edited: Jul 4, 2012
  23. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
  24. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    I am having an extremely hard time figuring out how to make instances of the decals. Is it possible to generate new decals at run time? This feature would be greatly desired in an update if there is indeed no way to generate instances during runtime
     
  25. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @macdude2: My plan was to first polish the editor functionality, before going on to advertise the runtime integration :) . The demos already have that functionality. Just hit play, walk around and click the left mouse button. It creates bullet holes on the surfaces.
    The implementation is in BulletExample.cs. If you prefer UnityScript, I have already such a version ready for the next release. Just have a look at it and ask if you have any questions about it.
    The basic idea is to set up a decals instance in the editor, including material, projection, uv rectangles, ... . At runtime you create a decals mesh and add decal projectors to it or remove them. As soon as the cutting is performed, you have to apply that decals mesh to your decals instance. I understand if that looks complicated at first, but it is made like that to keep both the draw calls and memory consumption low.

    Hope this helps.
     
  26. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    Thanks for your help. I figured out how to make decal instances. However, it appears the instanced decal will only project onto the mesh that it hit when it was instantiated. Is there any way to make it project onto all meshes instead? Also, is there any way to create a mesh collider for the instanced decal? Thanks a lot for all your help.
     
    Last edited: Jul 7, 2012
  27. 10polarbears

    10polarbears

    Joined:
    Jul 4, 2010
    Posts:
    9
    I have been to the Asset store and am unable to download Decal System. The Purchase/download button doesn't exist.
     
  28. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @macdude2: I am going to answer in the next reply. That will take a little longer :)
    @10polarbears: That sounds strange. Is the Decal System the only package you can't download? It works for me. Please let me know if you still encounter that issue!
     
    Last edited: Jul 7, 2012
  29. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @macdude2: The bullet example is only supposed to work with the Bootcamp assets and as you found on your own, it only performs a projection onto one mesh.

    A general implementation may look as follows:
    - Raycast/All maybe in combination or only with SphereCast/All to find the colliders.
    - Compute the decal projector's position/rotation/scale based on those colliders.
    - Add the decal projector to the decals mesh.
    - Terrains have to be handled as shown in the example implementation.
    - Get all the meshes that correspond to the hit colliders.
    - Add those meshes to the decals mesh and perform the cutting, offsetting, ...
    - Apply the decals mesh to the decals instance.

    There is no built-in way to add mesh colliders. You can add them on your own. You get the mesh data of the decals instance using the DecalsMeshRenderers array property.
     
  30. Toad

    Toad

    Joined:
    Aug 14, 2010
    Posts:
    298
    This looks great, thanks!
     
  31. seventyfive

    seventyfive

    Joined:
    Jul 20, 2007
    Posts:
    34
    hi dantus, thanks for your excellent plugin. a.t.m. I am trying to get used to it and after reading the documentation a question rose up, which I couldn't answer by now: is it possible to bake the generated decals into the object's texture or into a separate one which one could blend for e.g. performance reasons? looking forward to any hint you might give :)
     
  32. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Thanks for all the positive feedback! Don't forget to rate in the asset store and write reviews :)

    @seventyfive: Baking the decals in any way was never taken into account so far. This is usually made in the modeling/texturing software. Can you explain why you would want to do that in Unity and not a 3d graphics application?
    Blending decals in/out can be done in the material. If you use one of the default decal shaders (not the mobile ones), you can modify the color in the material. In there you can change the alpha by script and achieve a fading effect at runtime.
    Hope this helps.
     
  33. macdude2

    macdude2

    Joined:
    Sep 22, 2010
    Posts:
    686
    Finally got everything working! It works extremely well. Thanks so much for making it free!
     
  34. Dantus

    Dantus

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

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @macdude2: How is the performance? Is it fast enough for your needs?
     
  36. Rico21745

    Rico21745

    Joined:
    Apr 25, 2012
    Posts:
    409
    I tested this out and its very interesting. I would definitely be interested in a future version with decals spawned at runtime, or at least an example that's a bit more intuitive.
     
  37. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I am aware that the example looks quite complex. That's another hint to add some more explanations (or explanations at all :) ) to that code. Though, the way it works in general can hardly be simplified. But I am sure that comments will make it at least more understandable.
    The reason why it required that complexity is that all the bullet holes are automatically combined and you only get one draw call and a very small memory consumption for all the computations.

    Thanks for your advice, I added it to my todo list!
     
  38. Rico21745

    Rico21745

    Joined:
    Apr 25, 2012
    Posts:
    409
    Yup I understand its complex, you're right, I meant a little more documentation on how things work, so we could figure out how to do it.

    Also, I was trying to rate your asset on the asset store, but for the life of me, I could not figure out where to go do it. Not even to leave a comment!

    I'll try to rate again tomorrow, must be Unity being finicky.
     
  39. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Before I upload this to the asset store, I would like to know if this is more understandable or still has to be improved.

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

    Rico21745

    Joined:
    Apr 25, 2012
    Posts:
    409
    It's a lot more understandable, thanks for the effort!
     
  41. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Let me know if there are sections that should be further enhanced.
     
  42. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    I am in need of a decal system, but on IOS. Is it working on Devices?

    thanks,

    Jean
     
  43. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Yes, it does. Decals that are created in the editor are no problem, because they are identical to any other mesh.
    Creating decals at runtime works too, but there may be performance issues. Try it out and if the performance is not good enough, we can talk about ways to improve it. There are strategies, such as caching the mesh data to avoid runtime allocations, but they heavily depend on the actual application.
     
  44. chrisall76

    chrisall76

    Joined:
    May 19, 2012
    Posts:
    667
    A question, how would I go about creating decals at runtime/at a raycast point? I tried my regular way for a gameobject and it didn't work.
     
  45. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The Decal System contains a BulletExample(CS/JS) script, did you have a look at it? The central thing for runtime situations is that you do not have to create decals (DS_Decals) at runtime, but projectors for a decals instance. If you go one page back in this thread, you find the BulletExample with code documentation. That one will be in the next version. Every step should be sufficiently explained. If not, let me know so I can improve it!

    Hope this helps.
     
  46. chrisall76

    chrisall76

    Joined:
    May 19, 2012
    Posts:
    667
    Works perfect, thanks. Amazing that this asset is free.
    Only problem I have is that I'm trying to get decals that move with the object
    They where attached to.
     
    Last edited: Jul 19, 2012
  47. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    If you want that the decals move with an object, that moving object needs to have its own DS_Decals component with its own projectors, such that the produced mesh moves with the object.
    That happens because the produced mesh is placed in a child of DS_Decals and that mesh is only moved if DS_Decals does so too.
     
  48. chrisall76

    chrisall76

    Joined:
    May 19, 2012
    Posts:
    667
    Think I can have a bit more information? I apply a DS_Decal script to the crate and use the regular way of setting it up. any step I'm missing?
     
  49. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Are you doing that at runtime or in the editor?
     
  50. seventyfive

    seventyfive

    Joined:
    Jul 20, 2007
    Posts:
    34
    the idea would be to have a flexible solution to place decals during runtime (meaning by the player) and to save the result to load it afterwards. e.g. if possible, to use a rendertexture as one layer on the material und to render the result of the projector into it. or am i missing something :) ?

    for example you want to put stickers on a wall and the like. but to keep it for later on (and save render time) baking would be useful, right?

    hope that clears up my intention?

    cheers!