Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to Jet Wash Vehicle Objects (like Farm Sim)?

Discussion in 'General Discussion' started by unitydude2021, Jan 11, 2021.

  1. unitydude2021

    unitydude2021

    Joined:
    Jan 11, 2021
    Posts:
    3
    Hi,

    I am looking for some advice for a prototype/concept!

    I want to replicate the jet washing mode of Farm Simulator, the tractor and trailers get dirty and you can park them up and spray them with the jet wash until they sparkle:



    How do i go about this?

    I can import a model from blender and using parenting i have a hierarchy allowing me to add a different material (in unity) to each part of the tractor (main body, doors, wheels, windows etc), but how do i go about adding a dirty texture that can then be cleaned based on a ray cast from a jet wash?

    I was thinking that i can add a dirty texture somehow that can have it's opacity turned down based on a raycast while using the jet wash or is there a better way?

    What options do i have to create the dirty textures, do i paint in blender, do i UV unwrap, can this be imported into unity, and how can i go about applying them to the model and then cleaning them?

    if someone can point me the right direction with regards to what to look into it would be appreciated and any advice would be great!

    Thanks
     
  2. JoNax97

    JoNax97

    Joined:
    Feb 4, 2016
    Posts:
    611
    I don't know a solution but you may have luck if you look for splatoon clone tutorials. The mechanic is very similar (although you're cleaning instead of painting, but the system is the same) and as it is a popular game, there should be tutorials
     
  3. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    I believe farming simulator did not track washing process PRECISELY. Meaning it didn't care where the raycast hit and you couldn't just wash a part of the vehicle, and keep everything else dirty. It slowly built up grime over time, and upon washing it would lose all of it at once.

    Meaning, you need to prepare two textures -dirty and clean, and make a material that will blend them at runtime.

    In case of PBR rendering you'll need to blend at least albedo and metallic/specular. And probbaly normalmap, if the model uses it.

    If you REALLY want precise tracking of washing process (bad idea, because it won't look right due to dirt not acting as liquid), then you'd need to implement a fiarly complex render-to texture technique similar to rendering shadows for pointlight.

    Models textre would need to be unwrapped in a way where it would have non-overlapping texture coordinates, then you'd need to use render to texture to update locations that has been washed.

    It is a rather unpleasant process, and it is not exactly worth it. It would be easier to use the "morphing material" but split model into parts and adjust "clean<->dirty" blending based on which part you hit.
     
  4. unitydude2021

    unitydude2021

    Joined:
    Jan 11, 2021
    Posts:
    3
    neginfinity, thanks for the reply, precision isn't a concern here so it sounds like the idea of blending two textures (dirty and clean) is the way forward, but hopefully i can still jet wash a section of the model if my raycast hits say the front tractor wheel? (assuming i use a new instance of that material/shader on that part of the model) and not clean other sections of the vehicle?

    is it also possible to paint transparency on a texture in realtime?
     
  5. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    You can split models into pieces and check for collisions individually, yes. Just alter material for the the parts you hit and not for the whole thing.

    Yes, but what I described was making a mask that is being updated in realtime. For the mask you can use RGB and not alpha to blend other textures. (the shader doesn't care)

    That can be done, but to implement it yourself, you pretty much should be able to implement shadow-casting spot light from scratch as a custom shader. If you can do that, you can implement realtime painting of the mask.

    Basically the player would normally want to wash their can and not play graffiti simulator. And doing it via texture would be a graffiti simulator.
     
  6. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    5,984
    To start off with, you can store the spray hit points as Vector3 positions in a script, which you pass to your shader.

    Then in your fragment shader you can compare the position of the fragment to the position of each of the hit points, and display the texture you want based on how far away it is.
     
  7. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    If you do that, the shader will progressively become slower as more points are added.

    Meanwhile a material that utilizes a texture mask will always run at the same speed.
     
  8. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    5,984
    You can define a fixed number of points, or a minimum distance between them. It might not look perfect but might be good enough and easier to prototype with.
     
  9. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    Minimum distance doesn't matter, because you'll have to check them ALL. It is like blending multiple point lights, one light per point. Except less heavy.
     
  10. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    5,984
    I mean the resolution doesn't have to be infinitely small.
     
  11. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    ...

    What you originally described appear to be passing an ARRAY of point coordinates to the shader.
    It can work this way, but you'll pretty much need calculate distance to each hit to see how it affects the model, and you'll be doing it for every pixel. More points would mean slower render.

    In this scenario resolution isn't a thing. Because there are only point coordinates.
    -------
    If you meant to use point coordinates to alter MASK, it can be done this way, except parts won't block each other, and sufficiently large "blob" radius might end up unmasking opposite side of the object. In this case performance won't be a concern, and it will be slightly easier to implement a projector-based mask painting.
     
  12. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    5,984
    That's exactly what I'm talking about. Resolution in this case means that you can specify that every additional hit point that's within a certain distance of a previous hit point is merged. That means that you don't 'run out' of hit points as you spray down the object, or start reusing them and having dirt suddenly reappearing in previously washed areas.

    Shader doesn't slow down since (far as I know) it's not possible to store dynamic arrays in a shader. All the possible hit points are checked every frame.

    It's obviously not as good-looking or accurate as writing over the texture, but it's quite simple to implement and might be an easier way for the OP to get started, or even be good enough for their needs. If you want to make things very accurate, then yeah painting over a mask is probably the way to go.
     
  13. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,321
    Let's just say that I wouldn't do it this way. Too much hassle, slower than mask texture, no gain.

    Uh, it is. Skeletal animation is dynamic arrays. The array will have maximum length, though.
    https://docs.unity3d.com/ScriptReference/Material.SetFloatArray.html
    Store an array and then store length of that array, and here you go. A dynamic array.

    Basically starting with either model 2.0 or 3.0 it became possible to loop through shader constants based on an integer shader parameter. You can do it in both vertex and fragment shaders, and basically it allows you to implement equialent of a fixedfunction pipeline all by yourself. By making an array of light sources, for example, and looping through them.

    But that's not all. You also have uniform access buffer, those can store ARBITRARY structured data, and you can write into them.

    So, yeah, you absolutely can. It is just in this usecase it is definitely not worth it.
     
    Billy4184 likes this.
  14. SunnyChow

    SunnyChow

    Joined:
    Jun 6, 2013
    Posts:
    360
    for spray effect (or spray wash), you need a RenderTexture for the dirt. and some custom script/shader to render the spray on this RenderTexutre using vector position as UV, and uv as position

    https://assetstore.unity.com/packages/vfx/shaders/fluid-flow-143786
    this plugin doesn't fully fit your goal, but i think you should take a look.
     
  15. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    628
    One fairly easy way would be to store a dirtiness value for each vertex in the model (use/abuse the vertex colour?), and update the mesh (or just it's vertex colours) as it's dirtied/cleaned.

    Doing this on the CPU could get slow if the mesh is big, but you could use compute shaders to update the dirtiness value if you store it in a separate compute buffer.