Search Unity

Shader graph - get position from world space

Discussion in 'Shaders' started by grossimatte, Jul 10, 2018.

  1. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Hello,
    i am new to the shader-graph and shaders in general.

    What i am trying to do is to blend two materials using a mask. Also, the mask should then move according to the world coordinates of a given game-object so that i can use, let's say, a sphere to control the position of the mask that blends the two materials.

    upload_2018-7-10_15-6-39.png

    Which node should i use to fetch the world position coordinates of the sphere and how to connect it to that node?

    Thanks!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    A sphere is a distance from a point. So you need to get the distance from the world position from the sphere's center. If you want a smooth fade from the surface of the sphere to the center then divide that distance by the radius of the sphere. If you want to drive that fade by a texture you'll likely want a ramp texture rather than something like a particle texture, or you'll need to convert your normalized 0.0 to 1.0 radius to UVs that start at (0.5, 0.5) and go to the edge of the texture like (0.5, 1.0).
     
    funson likes this.
  3. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Hello bgolus,
    that makes sense, but i do not know how to fetch the sphere position to the nodes in the shader graph.

    Would you mind giving me more specific example?

    To be more clear, i want to use a different game object to drive the blend mask.

    For example, i have the shader with the two blending textures applied to a plane, and i have a separate game object (a sphere or anything) that i will move nearby the plane.

    I am expecting to see the blending mask moving on the plane surface according to the sphere world space position.

    Thanks!
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    You'd need to write a script that tracks the object and passes that information (via a Vector property) to the appropriate material, or sets it as a global shader property. For my own shaders I would likely use a single Vector4 value with the position as the xyz and the radius of the sphere as the w. Something like this:

    Shader.SetGlobalVector("_MySpherePosRadius", new Vector4(transform.position.x, transform.position.y, transform.position.z, transform.lossyScale.x));

    I'm not sure how to define global parameters in ASE, but you can also set it as a material property with the same name and it should work.
     
  5. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Hey bgolus,
    that is exactly as i approached it.

    upload_2018-7-11_1-9-57.png

    Only problem now is that the mask is projected onto the surface using a weird uvw.

    This is the texture i am using as mask:
    upload_2018-7-11_1-11-24.png

    But this is what i see:
    upload_2018-7-11_1-12-46.png

    The mask position follows the sphere position in world space, but the way the mask is projected to the surface seems wrong (it looks more like a ripple, rather than a faded 2d sphere).

    Any thoughts?

    Update:
    I think this is the missing part:

    "...or you'll need to convert your normalized 0.0 to 1.0 radius to UVs that start at (0.5, 0.5) and go to the edge of the texture like (0.5, 1.0)."

    Not sure what to do here.
     
    Last edited: Jul 11, 2018
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    Right, you have a texture:
    upload_2018-7-10_16-33-1.png
    The UVs for a texture are (0,0) in the bottom left and (1,1) in the top right.

    You're getting the distance from a point in space and passing that into the UVs of that texture. UVs are generally a float2, but you're passing a float1. That will automatically get converted into a float2 by copying the value into both components.

    So now you're sampling the texture like this:
    upload_2018-7-10_16-35-41.png

    Since the texture isn't clamped, for each world unit distance away from the center, the texture repeats.

    Really you shouldn't even need the texture at all. The distance value is already a gradient you can use. It starts at 0.0 and goes to world units. If you divide that distance by the radius of the sphere, clamp it to 0 to 1, and invert (1 - value) that gets you a nice gradient that's 1.0 at the center and 0.0 and the edge.
     
    Last edited: Jul 11, 2018
  7. grossimatte

    grossimatte

    Joined:
    Mar 15, 2013
    Posts:
    43
    Thank you bgolus,
    your explanation helped me getting as close as possible to what i was trying to achieve.

    upload_2018-7-11_11-15-18.png

    Not sure if this graph is optimised or redundant, but given my limited knowledge i am satisfied enough for the time being.

    Is there a way to scale the mask texture somehow?
    I am using a scale operand but i am not sure this is the right approach.

    Thanks!

    Update, using a Texture Coordinates node along with a float affecting the Tiling value (minus one in my case) did the job.
     
    Last edited: Jul 11, 2018
  8. kilik128

    kilik128

    Joined:
    Jul 15, 2013
    Posts:
    909
    any idea for make spherical uv please thank's
     
  9. Mrbloke97

    Mrbloke97

    Joined:
    Aug 27, 2015
    Posts:
    1
    Hi!

    Can someone help me with this? I have this same issue. I have a render texture that I use as a mask. It's rendered from a camera in ortographic view that follows the player(which has a mesh shape that only that camera can see). So I always have that black and white texture in a square frame. I made a script that takes the camera position and links it to my two floats in the shader (FogWarPositionX and FogWarPositionY). But I can't make this work. upload_2021-12-9_3-52-36.png

    Thanks!
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    Remove that distance node.

    You want something like:
    uv = (worldPosition.xz - fogPosition.xz) / scale

    where uv is what gets piped into the Sample Texture 2D node.