For those who are using recent versions of Unity (I'm using 2023.2.20f1) and the obstaclesTex does not affect the waves, try this: - Select your Orthographic camera - In the Rendering tab, check the option Custom Frame Settings - In the Rendering section, find Post-process - Check the left checkbox and uncheck the right checkbox This will prevent the camera to use post-processing and use "raw" image. It fixed for me. Hope this helps someone else :)
I am happy you liked 'em. I am currently working on the strategy game I started in these tutorials. I hope to continue with compute shaders once I release that game. sorry for the delay.
Not in this video, but in the next video you can see that displacement shaders can be used to extrude the wave in and out. ua-cam.com/video/5EyL0WpjdI8/v-deo.html&ab_channel=SpontaneousSimulations
Thank you for shearing your skills!! I tried your 2 water effect video's code on my unity. This time doesn't work correctly. Video's 33:14, wave reflects by block. But my wave doesn't reflects. Wave reflects only by the outside of WaterSurface(defined obstaclesTex.width and obstaclesTex.height). I think there are errors in my cords of definition of obstacles... Would you mind giving some advises?
There can be several reasons. Because we check the color of the texture for the obstacles, we need to make sure the red color is not tinted. It cud tint, if camera is not ortographic, or the material of the sprites that overlay the objects do not use Unlit shaders.
I suggest first make sure the obstacleTex is created properly. If then I suggest instead of cheking for red color in the code, check if color is NOT black. that cud remedy the issue
@@aoiti I checked both the obstacles camera is orthographic and obstacles(sprites from cube) are red. But I checked my code, I can't find red color. I don't know how to check obstaclesTex of objects are defined in Wavemanager.cs and waveCompute.
I was wondering, is there a way to not deform the water around the object when it is not moving? Like when a player is stationary, the water is not deformed around him, but it creates the waves when moving
Hello, very nice tutorial ! just one question, if we want the border conditions to absorb instead of reflect, how would we do that in the compute shader ? It is in 2D, so the formula shown by Haroon Stephen is not so clear to me when converted to 2D.
a rather irrelevant question: isnt every class passed by referece already? why would you need to put ref when passing it? doesnt it work without it? ( on initializetexture method)
It's a very good question. I think the reason is you create a copy class when you pass without ref keyword. The question is asked here if you would like to read: stackoverflow.com/questions/186891/why-use-the-ref-keyword-when-passing-an-object
I'm pretty sure I typed everything correctly, yet at 21:25 you get movement while I don't. Could this fail for me because of my system maybe? Running off an Intel UHD Graphics 620.
I am sorry you are having trouble implementing. To find where the problem occur, cud you try to print out the value at the center of the texture to console? Maybe the texture cud not be updated or maybe the compute shader is simply not being initiated.
How can I adjust the wave sizes/distortion/length, etc.. I keep changing values within the if statements in the compute shader file but the only thing I can see that truly changes it is the dispersion.
Hey, I used your Compute shader to get my ripples for a school assignment. I changed it so that I can get a ripple on the mouse position when I click and on the point of collision with an object. The issue now though is that when the collision ripple spawns the ripple based on the mouse position also spawns on the spot where I last clicked. Any clue why or how I could fix this? Clicking doesn't trigger the collision ripple btw. My WaveManager code that is of importance is the following: void Update() { Graphics.CopyTexture(NState, Nm1State); Graphics.CopyTexture(Np1State, NState); waveCompute.SetTexture(0, "NState", NState); waveCompute.SetTexture(0, "Nm1State", Nm1State); waveCompute.SetTexture(0, "Np1State", Np1State); waveCompute.SetVector("resolution", new Vector2(resolution.x, resolution.y)); waveCompute.SetFloats("dispersion", dispersion); Ray ray = cam.ScreenPointToRay(Input.mousePosition); RaycastHit hit = new RaycastHit(); if(Input.GetMouseButtonDown(0)){ if (Physics.Raycast(ray, out hit)){ texOrigin = hit.textureCoord; } effect.z = 2; }
waveCompute.SetVector("effect", effect); effect.z = 0; waveCompute.SetVector("rippleOrigin", new Vector2(resolution.x * texOrigin.x, resolution.y * texOrigin.y)); waveCompute.Dispatch(0, resolution.x / 8, resolution.y / 8, 1); //Send the main texture of the compute shader to the vertex shader to make the waves in 3D instead of 2D waveMat.mainTexture = NState; } private void OnCollisionEnter(Collision other) { RaycastHit colHit = new RaycastHit();
foreach(ContactPoint contact in other.contacts){ Ray ray = new Ray(contact.point-contact.normal, contact.normal); if(Physics.Raycast(ray, out colHit)){ Debug.Log(colHit.textureCoord); effect.z = 10; waveCompute.SetVector("effect", effect); waveCompute.SetVector("rippleOrigin", new Vector2(resolution.x * colHit.textureCoord.x, resolution.y * colHit.textureCoord.y)); waveCompute.Dispatch(0, resolution.x / 8, resolution.y / 8, 1); } } } The compute shader is the exact same. I tried making a different kernel for the collision ripple but that didn't work.
@@aoiti No worries, ended up removing the on click ripple. Found an other bug that might have caused it though. The balls shoot a raycast downwards and sometimes hit themselves with said raycast causing them to default to the last mouse position. I think that was the reason it happened. Having removed the click though I am not certain.
Good tutorial works perfect!, one question is it possible to make it work with Time.timeScale? i tried "if(frames >=Mathf.RoundToInt(Mathf.Lerp(8, 0, Time.timeScale)))" on Update and it seems to work but is there a better alternative?
It's a good question. I suggest running a coroutine in the background that calls for the wavecompute dispatch at every certain seconds. So it would look like; void Start() { InitializeTexture(ref NState); ... StartCoroutine(waveStep(0.1f)); //starts the coroutine with a time step of 100 ms } void Update() //no need to enter anything in here. { } IEnumerator waveStep(float timeStep) { while (true) //continues until the coroutine is halted externally. { Graphics.CopyTexture(NState, Nm1State); ... waveCompute.SetTexture(0, "NState", NSTate); ... waveCompute.Dispatch(0, Resolution.x / 8, Resolution.y / 8, 1); yield return new WaitForSeconds(timeStep); //wait by certain amount of time. } }
For those who are using recent versions of Unity (I'm using 2023.2.20f1) and the obstaclesTex does not affect the waves, try this:
- Select your Orthographic camera
- In the Rendering tab, check the option Custom Frame Settings
- In the Rendering section, find Post-process
- Check the left checkbox and uncheck the right checkbox
This will prevent the camera to use post-processing and use "raw" image. It fixed for me. Hope this helps someone else :)
I am a students in tech art and you have no idea how much it helped me, i am patiently waiting for the next one, thank you so much
I am glad you find them useful :)
Just came across your channel ..Ive subbed and hope to see more Tutorials !
perfect for beginners!! plz upload more, or may be upload some tutorials about using compute buffer/graphic buffer with vfx graph
I am happy you liked 'em. I am currently working on the strategy game I started in these tutorials. I hope to continue with compute shaders once I release that game. sorry for the delay.
is the surface always 2D, only creating the illusion of 3D water or does the surface actually change height?
Not in this video, but in the next video you can see that displacement shaders can be used to extrude the wave in and out. ua-cam.com/video/5EyL0WpjdI8/v-deo.html&ab_channel=SpontaneousSimulations
Thank you for shearing your skills!! I tried your 2 water effect video's code on my unity.
This time doesn't work correctly. Video's 33:14, wave reflects by block. But my wave doesn't reflects.
Wave reflects only by the outside of WaterSurface(defined obstaclesTex.width and obstaclesTex.height).
I think there are errors in my cords of definition of obstacles...
Would you mind giving some advises?
There can be several reasons. Because we check the color of the texture for the obstacles, we need to make sure the red color is not tinted. It cud tint, if camera is not ortographic, or the material of the sprites that overlay the objects do not use Unlit shaders.
I suggest first make sure the obstacleTex is created properly. If then I suggest instead of cheking for red color in the code, check if color is NOT black. that cud remedy the issue
@@aoiti
I checked both the obstacles camera is orthographic and obstacles(sprites from cube) are red.
But I checked my code, I can't find red color.
I don't know how to check obstaclesTex of objects are defined in Wavemanager.cs and waveCompute.
I was wondering, is there a way to not deform the water around the object when it is not moving?
Like when a player is stationary, the water is not deformed around him, but it creates the waves when moving
you can change the size or transparency of the child capsule depending on the transform speed. goodluck
@@aoiti That's a good idea, didn't think about that. Thanks! :D
please post this to github if you can. i'm at 20 minutes and not getting the same results as you despite checking for typos multiple times...
Hello, very nice tutorial ! just one question, if we want the border conditions to absorb instead of reflect, how would we do that in the compute shader ? It is in 2D, so the formula shown by Haroon Stephen is not so clear to me when converted to 2D.
If I recall correctly, all you need to do is to zero all the border heights before dispatching to GPU, just like in the cpu-run wave simulation
a rather irrelevant question: isnt every class passed by referece already? why would you need to put ref when passing it? doesnt it work without it? ( on initializetexture method)
It's a very good question. I think the reason is you create a copy class when you pass without ref keyword. The question is asked here if you would like to read: stackoverflow.com/questions/186891/why-use-the-ref-keyword-when-passing-an-object
Is this possible in Web? I tried on webgl (2023.3.0a14 WebGPU) , but TextureFormat doesn't support Snorm Format. and if No SNorm, Shader's not works
I'm pretty sure I typed everything correctly, yet at 21:25 you get movement while I don't. Could this fail for me because of my system maybe? Running off an Intel UHD Graphics 620.
I am sorry you are having trouble implementing. To find where the problem occur, cud you try to print out the value at the center of the texture to console? Maybe the texture cud not be updated or maybe the compute shader is simply not being initiated.
How can I adjust the wave sizes/distortion/length, etc.. I keep changing values within the if statements in the compute shader file but the only thing I can see that truly changes it is the dispersion.
Also, this was a great video so thank you no matter what!
Hey, I used your Compute shader to get my ripples for a school assignment. I changed it so that I can get a ripple on the mouse position when I click and on the point of collision with an object. The issue now though is that when the collision ripple spawns the ripple based on the mouse position also spawns on the spot where I last clicked. Any clue why or how I could fix this? Clicking doesn't trigger the collision ripple btw.
My WaveManager code that is of importance is the following:
void Update()
{
Graphics.CopyTexture(NState, Nm1State);
Graphics.CopyTexture(Np1State, NState);
waveCompute.SetTexture(0, "NState", NState);
waveCompute.SetTexture(0, "Nm1State", Nm1State);
waveCompute.SetTexture(0, "Np1State", Np1State);
waveCompute.SetVector("resolution", new Vector2(resolution.x, resolution.y));
waveCompute.SetFloats("dispersion", dispersion);
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
if(Input.GetMouseButtonDown(0)){
if (Physics.Raycast(ray, out hit)){
texOrigin = hit.textureCoord;
}
effect.z = 2;
}
waveCompute.SetVector("effect", effect);
effect.z = 0;
waveCompute.SetVector("rippleOrigin", new Vector2(resolution.x * texOrigin.x, resolution.y * texOrigin.y));
waveCompute.Dispatch(0, resolution.x / 8, resolution.y / 8, 1);
//Send the main texture of the compute shader to the vertex shader to make the waves in 3D instead of 2D
waveMat.mainTexture = NState;
}
private void OnCollisionEnter(Collision other) {
RaycastHit colHit = new RaycastHit();
foreach(ContactPoint contact in other.contacts){
Ray ray = new Ray(contact.point-contact.normal, contact.normal);
if(Physics.Raycast(ray, out colHit)){
Debug.Log(colHit.textureCoord);
effect.z = 10;
waveCompute.SetVector("effect", effect);
waveCompute.SetVector("rippleOrigin", new Vector2(resolution.x * colHit.textureCoord.x, resolution.y * colHit.textureCoord.y));
waveCompute.Dispatch(0, resolution.x / 8, resolution.y / 8, 1);
}
}
}
The compute shader is the exact same. I tried making a different kernel for the collision ripple but that didn't work.
Sorry. I have been busy with the game. I am not sure but I think you need to move the SetVector function into the Raycast check. Goodluck
@@aoiti No worries, ended up removing the on click ripple. Found an other bug that might have caused it though. The balls shoot a raycast downwards and sometimes hit themselves with said raycast causing them to default to the last mouse position. I think that was the reason it happened. Having removed the click though I am not certain.
@@GameOver-ol7ku Yes Raycasts can be very confısing. You can set your mesh to ignore outwards raycasts too, but I cant remember how atm.
@@aoiti I put the balls on the ignore raycast layer, worked well enough
Is this downloadable? Thank you.
sorry it is not.
Can this used on mobile ?
sorry i am a beginner
Sorry. I am not sure because it's quite GPU intensive.
thanks for your replay and could make a one for mobile if i will not annoy you
mybe put source?
omg I wish I could download this, its amazing
Glad you liked it. Once I add a nice shader to it, I will make it available on unity asset store.
Good tutorial works perfect!, one question is it possible to make it work with Time.timeScale?
i tried "if(frames >=Mathf.RoundToInt(Mathf.Lerp(8, 0, Time.timeScale)))" on Update and it seems to work but is there a better alternative?
It's a good question. I suggest running a coroutine in the background that calls for the wavecompute dispatch at every certain seconds. So it would look like;
void Start()
{
InitializeTexture(ref NState);
...
StartCoroutine(waveStep(0.1f)); //starts the coroutine with a time step of 100 ms
}
void Update() //no need to enter anything in here.
{
}
IEnumerator waveStep(float timeStep)
{
while (true) //continues until the coroutine is halted externally.
{
Graphics.CopyTexture(NState, Nm1State);
...
waveCompute.SetTexture(0, "NState", NSTate);
...
waveCompute.Dispatch(0, Resolution.x / 8, Resolution.y / 8, 1);
yield return new WaitForSeconds(timeStep); //wait by certain amount of time.
}
}
@@aoiti I don't know why that solution didn't cross my mind.
I just tried it and it works perfect, so thank you very much!👌