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

    gord0x64

    Joined:
    Nov 28, 2012
    Posts:
    7
    That would be difficult. The game itself is a minigame that's part of a larger game. That game is run on facebook. The minigame I'm having the decal issues with is loaded as a bundle from the main game. The pigeon spawns, behavior, etc is loaded via xml. The load of the game relies on objects from the previous scene being in scope and the end of the game sends off server calls.

    I'll get some of my other tasks out of the way and then begin making a new scene with as much of the current functionality as possible while keeping it independant of the main project. Might be a little while before I can accomplish that due to all the interdependencies. If anything comes to mind before I do that let me know. My email will alert me of replies. : ]

    thanks again.
     
  2. gord0x64

    gord0x64

    Joined:
    Nov 28, 2012
    Posts:
    7
    I put together an extremely simplified version of what's happening in a separate project. Nothing is there but the statue models. I've made gui buttons that when clicked drop a poop on the statue beneith.

    My findings are that the decals were actually working except were too small to see without zooming in very very closely with the editor. So I tried adjusting some scales on various objects in the prefab to see if I could make it bigger (i know this is bad as it distorts art assets but I just wanted to see the result) and nothing had changed in the visual of the decal once instantiated. After instanted if i were to manually move it, the editor script would recalc and I would see the decal at a larger size.

    What I would like to know is how to make the decals appear at the right size when instantiated at runtime. The size seen on the statues is like a mosquito bite. The size I would like is would be like being hit with a water balloon full of paint.

    Is there an email or other online medium of which I can send you the simplified project?
     
  3. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You can adjust the size of the individual projectors with the decalProjectorScale which is a variable from the script you posted.
    Sent you a pm with my email address.
     
  4. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Hey Dantus, I'm testing the decal system right now and after I got about 60 of them in my scene (just duplicated the projectors inside the Decals group) I noticed that when I click on a decal and try to move it (by selecting a translation arrow) there is a delay of almost 3 seconds before I can actually move the decal.

    Is that inherent to the system, or am I not using it correctly?
     
  5. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    It sounds as if your decals consist of too many vertices, such that more than one mesh has to be generated. In that case it is getting quite slow, especially at the moment when you change a newly selected projector. An option for you would be to have more than one decals instance in order to be better usable in the editor.
     
  6. gord0x64

    gord0x64

    Joined:
    Nov 28, 2012
    Posts:
    7
    To anyone following the thread. My issue was taken to skype and it was found that increasing the decalProjectorScale was at least in part the solution.

    Now it seems the UVs are being messed up. The decals sometimes look like square patches that seemingly are using a smaller portion of the selected section of the atlas. I then asked Dantus via Skype: "is it possible the scaling effects the UVs?"

    [04/12/2012 4:49:27 PM] Andy Suter: If you project something straight onto a surfuce, you see the decal nicely. But if you project along a surface, the whole decal is streched.
    That's probably what we are seeing. (Possibility 1)
    [04/12/2012 4:49:55 PM] Andy Suter: Or it could be that effect and a wrong uv index? Though that's unlikely because you would get an error message.
    [04/12/2012 4:50:29 PM] Andy Suter: If the issue happens because you are projecting along the surface, you may try to lower the culling angle.
    [04/12/2012 4:50:48 PM] Andy Suter: Just try it out in the editor what the actual effect is.
    [04/12/2012 4:51:19 PM] Gordon Jennings: Alright
    [04/12/2012 4:54:28 PM] Gordon Jennings: the projector doesn't seem to be part of the prefab. it's clearly instantiated, but i can't find any GOs in Hierarchy. So I can't change the angle while the game is running : /
    [04/12/2012 4:54:48 PM] Gordon Jennings: might have to be done in code
    [04/12/2012 4:55:57 PM] Gordon Jennings: anyway, I'm heading out for the day. I'll be back in the morning. Thanks again for your guidence.
    [04/12/2012 4:56:13 PM] Andy Suter: You're welcome!

    So now I'm back in the morning and I debugged out the culling angle which happened to be 90. I tried 30 and 0 which made the decals not visible or barely. I then tried 180, which seemed better than 90. However I'm still getting seemingly the wrong uvs so the decals look like squares of a smaller portion of the desired texture selection in the atlas.

    What do you mean by projecting "straight onto a surface" vs "project along the surface" ?
     
  7. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The uv's are correct from my point of view.

    Check the attached picture. On the left hand side, you see a projection straight onto the surface, while the one on the right hand side happens along the surface. Both projections use the identical uv rectangle and texture and both are correct.
     

    Attached Files:

  8. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    My conversation with gord0x64 may be a little confusing, because we also communicated e.g. over Skype.
    As a short summary, the issues that appeared are basically related to the project. The scaling trouble occurred because the meshes in the scene were larger than expected, that's why the projector sizes had to be increased as well. The projection trouble (wrong uv's) appears to happen, because the projection happens along the mesh. The solution for that is heavily project/mesh dependent. But in any case, the projector needs to be rotated toward to mesh to get better results and maybe adjust the culling angle.
     
  9. gord0x64

    gord0x64

    Joined:
    Nov 28, 2012
    Posts:
    7
    Ok, so I've been trying to give the projectors the proper rotation with varying combinations of implementation. None of what I've tried fully works. What I have tried that seems to have worked the best was having the falling poop projectiles look at the statue after they've disabled their rigidbodies and colliders and set off the particle. That way their position would be exactly where the poop hit and making them look at the statue from that point should give them the rotation the projector should use. When the decal is instantiated I pass in that rotation and give it to the projector.

    That didn't give the result I wanted..fully. So I got thinking that maybe it was backwards and so in the initialization of the decal I rotated the projector's rotation -180.0f on y. Which made the effect closer to what I wanted but still some straight edge cut offs in the decals.

    I'm going to send you a screen shot. The statue on the left seems to be looking how I want it. If not, very close. On the other two statues you can see some parts looking almost right and others where the cut offs are very obvious.
     
  10. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    It's hard to give hints, because that heavily depends on the meshes. You may think about having special sections on the meshes and define the impact rotation per section. Another idea would be to use vertex colors to minimize the cut off visibility.
     
  11. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    How would one clear all projectors from the DecalsMesh?

    I am using this atm but its not clearing everything and I get an out of range error after a few minutes "Im guessing its leaving everything else like Verts Normals Ect"

    Code (csharp):
    1.  
    2. DecalSystem.GetComponent<DS_Decals>().LinkedDecalsMesh.Triangles.Clear();
    How can I get a list of all the projectors to use the remove projector or is there a simple way to do this?

    Thanks for your help
     
    Last edited: Dec 17, 2012
  12. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You need to remove all projectors from the decals mesh (start with the last one due to performance reasons) and update it in the decals instance. Like that all projectors are removed and you can later on add them again.

    Hope this helps!
     
  13. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    Thanks

    How can I get a list of the projectors on the Decals Mesh?

    I don't know what projectors are on the Decals Mesh at any given time without storing them and that would be very complicated / not possible with what I am doing.

    How would you clear a Decals Mesh of all projectors without creating list of projectors as you create them?

    I essentially want to return the Decal System to a blank state "like when it was initiated"!
    I could destroy the prefab and then reload it but that is too intensive.

    Thanks again!
     
    Last edited: Dec 17, 2012
  14. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The DecalsMesh has an ActiveDecalProjector which is always the last one. While the active decal projector is not null, remove it. That should do it.
     
  15. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    Thanks for your help

    I got this, and its not working :(
    Code (csharp):
    1. DecalsMesh TargetDecalsMesh = (DecalsMesh)DecalSystem.GetComponent<DS_Decals>().LinkedDecalsMesh;
    2. while (TargetDecalsMesh.ActiveDecalProjector != null){
    3.     TargetDecalsMesh.RemoveProjector(TargetDecalsMesh.ActiveDecalProjector);
    4. }
     
  16. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You need to UpdateDecalsMeshes for the decals instance.
     
  17. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    Thanks Dantus

    I found the problem that I was having, it turns out that if all the projectors on a DecalsMesh are removed the DecalsMesh is destroyed :(
    So I needed to recreate a new DecalsMesh once all the projectors are removed.

    Do you know of a way to remove all the projectors while still keeping the DecalsMesh intact?
     
  18. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    The mesh creation/destruction happens automatically and you can't influence it at all.

    If you tell me a little more what you what you want to achieve exactly and in which context, I am sure we find a solution.
     
  19. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    Thank you again Dantus you very quick at support :p

    I have a solution working atm so its not a problem
    I was hoping that there was a way to keep the DecalsMesh intact so that it was not being recreated every time I wiped it but if that's not possible I can just do a check when adding a projector and if there is no DecalsMesh then just add one.

    What Im doing:
    Im creating a load of reusable functions for my project so that I can quickly add and manipulate Decals, so far I have:
    InitiateDecalSystem()
    AmmendDecalSystem()
    DestroyDecalSystem()
    UpdateDecalSystem()
    WipeDecalSystem()

    Im tagging every DecalSystem with "Decal" and then using this to find them:
    Code (csharp):
    1. public void UpdateDecalSystem(GameObject UpdateTarget){
    2.     GameObject[] ActiveDecalSystems = GameObject.FindGameObjectsWithTag("Decal");
    3.     foreach (GameObject DecalSystem in ActiveDecalSystems){
    4.          if (DecalSystem.name == UpdateTarget.name + "(Clone)"){
    5.                   //Do Stuff
    6.     } } }
     
    Last edited: Dec 17, 2012
  20. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    What do you mean with wipe? Do you simply want to hide all the decal projectors and use exactly those ones later on again?
     
  21. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    My idea for WipeDecalSystem() was to simply clear it of all projectors so that it could be reused with out having to be re-initiated.

    This is what I am doing: the pink capsules are units that can be selected and then the white circles are painted below them on the ground. as well as painting the pathfinder paths.

    when I select a diffrent player the Decal system is "Wiped" and then the new circles are drawn. Also the circles are animated and spin "but you cant see that :p".


    I know that I could more easily do this with flat planes but I plan to use rough terrain soon :p
     
    Last edited: Dec 17, 2012
  22. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Is there a performance issue with destroying the decals mesh? Or why is it an issue that this game object is deleted? And why do you need to access this one directly?
    So many questions :)
     
  23. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    Reading up on optimization I found that destroying and then re-initiating prefabs is not optimal "for some Unity specific reasons I don't understand :p" It is more optimal to reuse prefabs that are already loaded into memory. example "rather than destroying enemies when they are killed Hide it and use the same prefab when you re-spawn the enemy"

    How that affects your Decal System I am not sure, I was trying to be as optimal as possible. It may be that there is no load time for the Decal Prefabs as they are just empties with scripts? Although I suspect that the texture for the Decal prefab is loaded as well.

    My understanding is that if you destroy a Decal Prefab and then re-initiate it you will be removing the Decals texture from memory and then reloading it. But if you Keep the Decal Prefab loaded and just clear the DecalsMesh of projectors the texture should remain in memory and I should not incur a load time hit on performance.

    My tests seem to indicate a performance boost when I "wipe" rather than destroying and re-initiating but its hard to tell for sure.

    The down side to this is that a draw call is used even if the Decal System has no projectors.
     
    Last edited: Dec 17, 2012
  24. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    If destroying the game object has a too negative impact, I would propose you the following way for wipe:
    - Remove all projectors
    - DON'T UPDATE THE DECALS MESH
    - Deactivate all the decals mesh renderers (in the decals instance).

    You certainly need to make sure that you activate them again when the decal projectors have to become visible again.
     
  25. MCHammond

    MCHammond

    Joined:
    May 15, 2009
    Posts:
    74
    This is an Awesome tool :D

    I have been doing some more work with it and I am loving the results. I found that if you try and add a lot of projectors a frame you get a frame rate drop that can cause a jerk so I have been implementing a Coroutine system so that only four projectors are added per frame and any others are added in the next frames.

    I used it to create an interactive Pathfinder Visualization that you can see in this demo LINK
     
    Last edited: Dec 19, 2012
  26. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Thanks!

    I like the mechanics of your game a lot!
     
  27. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    hi!

    ran into another problem.
    decals dont work on Unlit materials. only on simple diffuse materials.

    they just dont show up.

    thx!
     
  28. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    That's probably related to the shader's offset. You need to make sure that the shader you are using for the decals has a higher offset than the one onto which you perform the projection.

    That issue also occurred to other and could be resolved here.

    Hope this helps.

     
  29. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    thank you for the answer, but how do i change the offset?

    by adding "Offset 999, 999" into the .shader file? that didnt do anything
     
  30. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    One higher than the other shader is usually sufficient. In the case that you can show both shaders, it would be easier to reproduce your issue.
     
  31. Lizzard4000

    Lizzard4000

    Joined:
    Mar 3, 2010
    Posts:
    101
    the weird thing is that it works in editor but not in the built/webplayer.

    i really dont know what could be wrong.
     
  32. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Maybe the fallback shaders are used in the webplayer... No idea without an actual project.
     
  33. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    I have a quick question... for a mobile game, in most cases a projector shadow will result in way excessive draw calls and will be way too slow. At the same time, I expect some geometrically complex environments where flat quad shadows may not cut it (would poke through things and hover in midair).
    So, is this decal framework fast enough to use for this purpose? This game is a multiplayer game and the maximum player limit per room is 32, so in the worst case scenario I would need to recalculate 32 shadow decals every frame. Is this possible?
    Thanks.
     
  34. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I have never tested the runtime performance of the Decal System on any mobile device. You have to try it out. I know some tricks to improve the performance that will also help on mobile platforms. But most of those tips are specific to specific scenarios and I would need to have a look at the meshes in the actual scenes to give you hints.
     
  35. Karmarama

    Karmarama

    Joined:
    Jul 11, 2011
    Posts:
    261
    Firstly, thank you so much for your decal system!

    From instantiated planes, to expensive projectors - and horribly looking into mesh instantiation and get/setpixels for decals, I think your system is shaping up to be one of the best performance wise!

    The only problem I have is exactly that of which I quoted, that you already know about. As I'm not using this just for bullets, and more for example a rocket decal or something that's a bit more in a radius formation, there's a few things I'd like to query.

    For the stretching on flat up surfaces (such as a flat plane, as the ground) I've been messing with some arrays of data that has been sent from the projectile object to the BulletExampleJS.js file - namely grabbing contact.point, contact.normal and contact.otherCollider.

    In BulletExampleJS.js I've tried replacing the camera and raytracing positions with the following:
    Code (csharp):
    1.  
    2.                     // Calculate the position and rotation for the new decal projector.
    3.                     var l_ProjectorPosition = contact + (decalProjectorOffset * contactNormal/2);
    4.                     var l_ForwardDirection = colliderHit.transform.up;
    5.                     var l_UpDirection = - Camera.main.transform.forward;
    6.                     var l_ProjectorRotation = Quaternion.LookRotation (l_ForwardDirection, l_UpDirection);
    7.  
    I've messed with various things, even trying to check what the current contactNormal is:

    Code (csharp):
    1.  
    2.                 print ("Normal facing direction is: " + contactNormal);
    3.                 //Left = -1,0,0 (right = 1,0,0) | Forward = 0,0,-1 (back = 0,0,1) | Top = 0,1,0 (bot = 0,-1,0)
    4.                 if (contactNormal.z == -1){
    5.                         //vars equal forward dir
    6.                 }
    7.  
    However this doesn't work really, and is likely inaccurate for any object that isn't a cube and has more incremental values.

    The other issue is at times when the projectile hits something more to it's side, or somesuch, the decal appears more cutoff at the edge and at times doesn't wrap around the other side of an object face (say, a cube). Speaking of which, decals are also only applied to the hit collider mesh. Is it possible to also check nearby objects, say if an explosion occurred near the bottom of a wall, the floor would also be covered in the remaining half of the decal that covers the entire explosion radius?

    I'm guessing a SphereCast would be used here?

    What would be your best approach to these issues?

    Much appreciated.
     
  36. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @Karmarama: Tough one!

    The projector rotation is tricky. Have you though about using more than one projector for rockets to achieve some kind of radius effect? It is really hard to help on that without having access to the actual game content.

    And for the other one, you should definitely use a SphereCastAll and just perform the same step you did for one mesh, for all of them. Pretty straight forward.

    Hope this helps
     
  37. Karmarama

    Karmarama

    Joined:
    Jul 11, 2011
    Posts:
    261
    Well, I'm not instantiating a projector per shot - rather adding it to the current system that the BulletExampleJS.js has.

    I've looked into an OverlapSphere, however with the current way the BulletExampleJS - and my array modifications - are currently setup, it seems quite difficult to put into place. I assume the overlapsphere would need to get all the colliders in it's radius, then assign it to l_mesh and such, but the problem then is possibly the contact.point and the indexes currently setup.

    I'd assume SphereCast is more performance intensive than OverlapSphere, hence my reasoning to try it this way.

    As for the rotations and contact normals, decals cutting off at edges of objects and all, I've included the package attachment.

    Edit: To shoot, press F
     

    Attached Files:

    Last edited: Dec 30, 2012
  38. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    I found the problem. Your forward and up direction are wrong for the rotation of the decal projector. It is already in the code snippet you posted, but I missed it. You are taking the transform of the object you are hitting, but you have to use the contact normal in order to compute the rotation for the projector. In the original I took the camera, because it was pretty easy to get the rotation like that.
     
  39. Karmarama

    Karmarama

    Joined:
    Jul 11, 2011
    Posts:
    261
    Thanks for taking a look.

    The reason they're a little mixed was due to experimenting with it - as it doesn't seem what I put as the forward/up direction makes much difference.

    In your original example, you had:
    Code (csharp):
    1.  
    2.                 var l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * l_Ray.direction.normalized);
    3.                 var l_ForwardDirection = Camera.main.transform.up;
    4.                 var l_UpDirection = - Camera.main.transform.forward;
    5.                 var l_ProjectorRotation = Quaternion.LookRotation (l_ForwardDirection, l_UpDirection);
    6.  
    Changing it to, what I thought would match:

    Code (csharp):
    1.  
    2.                     var l_ProjectorPosition = contact + (decalProjectorOffset * contactNormal/2);
    3.                     var l_ForwardDirection = contactNormal.up;
    4.                     var l_UpDirection = - contactNormal.forward;
    5.                     var l_ProjectorRotation = Quaternion.LookRotation (l_ForwardDirection, l_UpDirection);
    6.  
    Gives stretched results on sides, and doesn't work for the top of objects. Mainly the front.

    The idea of using the collider transform was to possibly do a comparison check as to what side of a mesh was hit, and then changing the rotation based on that. Although that didn't turn out so well, and likely wouldn't work on spheres etc.
     
  40. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @Karmarama: You can't use up and forward, because they are constant values and are independent of the contact normal value. You have to compute the projector rotation (quaternion) based on the contact normal.
    Give me a few minutes, I will try something.
     
  41. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    That's the projector rotation you should use:
    Code (csharp):
    1. var l_ProjectorRotation = Quaternion.FromToRotation (Vector3.down, - contactNormal);
     
  42. Karmarama

    Karmarama

    Joined:
    Jul 11, 2011
    Posts:
    261
    Well that fixes that portion! Thanks, much appreciated.

    Now the only issue is the decal texture stretching around edges and cutting off at edges.

    I'll keep messing with overlapsphere methods however.
     
  43. Zozo2099

    Zozo2099

    Joined:
    Jul 15, 2012
    Posts:
    478
    Please can I know if it is compatible with Unity 4? thanks.
     
  44. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Yes, it is compatible.

     
  45. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    You may try to play with the settings of the decals and projectors in the editor directly to get some good enough values to apply them in your code. I am pretty sure you can get better results like that for the stretching and cutting off. At least for many cases.
     
  46. Karmarama

    Karmarama

    Joined:
    Jul 11, 2011
    Posts:
    261
    I think the issue lies with the normal rotation, because it's not smoothing out between both faces of the cube. Something to do with how the values are interpolated?

    For arbitrary surfaces it seems to work fine, so what I've done is in Maya created a beveled cube for collisions - with the extra faces between the edges, it smooths the decals out across both sides.
     

    Attached Files:

  47. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    @Karmarama: This decal smoothing is not easily achievable within the Decal System. There is no general solution for that. That's why this kind of tweaking has to be done with custom scripts. Sorry, that's out of the scope of the decal system.
     
  48. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Yep, I've actually seen similar stretching in some cases in Team Fortress 2.
     
  49. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Hey Dantus, I was wondering: is there a way to make the decals mesh renderer themselves non-selectable?

    It's just that when I want to select the mesh upon which the decal is projected, I have to manually turn off the decals group in the hierarchy and then re-activate it again, and it's a bit cumbersome. But maybe there's already an option for that?
     
  50. Dantus

    Dantus

    Joined:
    Oct 21, 2009
    Posts:
    5,667
    Good point! I'll think about it. Keep in mind that there may be users who want to select the decals using the mesh instead of searching it in the hierarchy. Maybe there is a solution to have both of them in place.
    Thanks for the input!