# Question Raycasting to vertices.

Discussion in 'Physics' started by pineapuru, Nov 24, 2020.

1. ### pineapuru

Joined:
Mar 21, 2018
Posts:
46
Hi! My game has a few moments where the player walks on water, the game really doesn't have many moments where you fully interact with water, so I thought making water collision wasn't really necessary, although, I wish I could raycast below my character to verify if there's any vertice from the water to play water-splash particles.

My water has waves, I made a simple shader on shadergraph to make the water pretty, but is there a solution to spawn the particles only when my character step on the water itself and not on the mesh plane (as it sometimes the water is not there because of the waves)?

I made this sketch to show you all my idea lol

2. ### tjmaul

Joined:
Aug 29, 2018
Posts:
466
In my opinion the simplest way to do this is use a raycast to the ground and save the y value. Then use the same math that you’re using within shader graph and execute it for just that single raycast hit x/z position and compare. There’s no simple way to cast against a non-static mesh that’s deformed in a vertex shader that I know of.

Joined:
Jun 17, 2019
Posts:
1,548
Worth noting that C# Time and the Shader Graph Time node are in sync - so for example if you're animating waves using sine you can calculate whether a footstep would be in the water during any given frame for wherever it is. Just create a function that does the same as the portion of the graph affecting vertex position - then you can get the current wave height for any given Vector3 position(s).

4. ### pineapuru

Joined:
Mar 21, 2018
Posts:
46
Your solution sounds good, although, would that be applicable on the calculation with time instead of sine time? Also I'm wondering if it's possible to use my shader to make the effect, as my shader has random generated gradient noise.

I'm quite behind when it comes to shader math, but I think it would be impossible to calculate the position as the waves are always random right?

Joined:
Jun 17, 2019
Posts:
1,548
I believe Time.time and the Time node's time output always have the same value - so you'd just do the same in C# as your shader. Re randomness, you'd probably have to base your approach to noise on texture instead and sample from the same one(s) with GetPixel (or flattened index within raw image data) in your function. That way you'd have a fixed seed to write corresponding logic for. Another thought.. as it's possible to render a material to a texture, you could sample from that the same way, but in practice I think it might be too costly. However, if you did go about it that way, I'd try to keep the render reasonably low-res and a put a limiter on updates (i.e. once every 100ms or something / whatever precision you'd need), just sample from the render of the previous update until the next as needed.

pineapuru likes this.
6. ### tjmaul

Joined:
Aug 29, 2018
Posts:
466
There is no such thing as randomness when it comes to programs. The gradient noise function is just complicated enough so it looks sufficiently random. That means you can replicate exactly the same behaviour of the shader math in CPU (C#) land. To make things simpler, first change the input of the gradient noise from "UV0" to world coordinates like so:

This way, you don't have to figure out the UV coordinates of the object your player is touching. You probably have to adjust the scale so it fits your original look. Next, right click the gradient noise node and select "Show generated Code":

It'll open the HLSL code behind the Gradient Noise node:
Code (CSharp):
2.     {
3.         // Permutation and hashing used in webgl-nosie goo.gl/pX7HtC
4.         p = p % 289;
5.         float x = (34 * p.x + 1) * p.x % 289 + p.y;
6.         x = (34 * x + 1) * x % 289;
7.         x = frac(x / 41) * 2 - 1;
8.         return normalize(float2(x - floor(x + 0.5), abs(x) - 0.5));
9.     }
10.
11.     void Unity_GradientNoise_float(float2 UV, float Scale, out float Out)
12.     {
13.         float2 p = UV * Scale;
14.         float2 ip = floor(p);
15.         float2 fp = frac(p);
16.         float d00 = dot(Unity_GradientNoise_Dir_float(ip), fp);
17.         float d01 = dot(Unity_GradientNoise_Dir_float(ip + float2(0, 1)), fp - float2(0, 1));
18.         float d10 = dot(Unity_GradientNoise_Dir_float(ip + float2(1, 0)), fp - float2(1, 0));
19.         float d11 = dot(Unity_GradientNoise_Dir_float(ip + float2(1, 1)), fp - float2(1, 1));
20.         fp = fp * fp * fp * (fp * (fp * 6 - 15) + 10);
21.         Out = lerp(lerp(d00, d01, fp.y), lerp(d10, d11, fp.y), fp.x) + 0.5;
22.     }
Now you need to convert this code to C#:
- float2 -> Vector2
- floor -> Mathf.Floor
- frac(x) -> x - Mathf.Floor(x) // the decimal value of a float, eg. 50.23f -> 0.23f
- dot -> Vector2.Dot
- float2(1, 0) -> Vector2.up
- float2(0, 1) -> Vector2.right
- lerp -> Mathf.Lerp

As you can see, the noise function is really just some code. No actual noise there. I hope that gives enough pointers for you to go on by yourself