I’m curious why you use the normal vector to adjust the position of the point before the second round of raymarching rather than the reflection/refraction vector? Is it just to avoid issues when the angle is very shallow?
I think it's to avoid hitting the face you just checked again with the ray March. Makes sure you're clear of previous face when you start stepping along direction vector
That's a good question. I suppose you could step along the reflected vector, but the point is to get away from the surface and the normal direction is the fastest way to do that. If you stepped along the reflected vector, for a fixed small distance, you might still be within SURFDIST and have a wrongful direct hit.
I will be using your video as apart of my final for uni this semester in my Critical Code class. Thank you for making these complex ideas easy to understand for someone like me!
Two quick questions: 1. Would we also want to check for a (0, 0, 0) result from the first refract(...) call as well and handle that scenario or can the first refract never return (0, 0, 0) ? 2. Does the shader language have some form of vec3::ZERO definition that we could use for determining if refract returned (0, 0, 0) instead of the dot(...) calculation? It seems like 3 comparison operations of (x, y, z) might be faster than even a dot calculation?
For #1, that's exactly what was happening before he had the IOR inverted, as if we were inside glass looking into a cube of air. It only occurs when the second medium has an IOR less than the first.
I'm back here again ;) ... and though I'm sure I've said (written) it before (and will again) I have to express my gratitude and admiration You for Your excellent videos, and for all the work You do to share Your knowledge with us. It is in my opinion people like You that make RUclips great ! Kind thoughts and best regards.
Really cool stuff! And a lot more pitfalls than expected, nice to get good explanations and solutions to the different issues when making this work! :)
@@RayBellis A real recursion is not allowed in GLSL, but any recursion can be implemented in a loop. The number of loop iterations would be limited by the driver and the desired quality/performance tradeoff. In any case, I think a loop that would perform "keepReflectingUntilRefractsOrMaxIterationsAreReached" would make the result more realistic.
This is great and perfect timing in finding this, as I just been charmed by seeing lots of applications of real time refraction in Unreal (like the hardware raytracing prism ones) and others and researching various methods of approaching this, including larger mediums like bodies of water or an atmosphere. Thanks! Looking forward to the continuation of this.
Great job as usual, I just like the way you are now moving to the physics and optics side, which is perfect, hope that we will reach to the hard-core PBR soon :) Thanks Martijn ✋
Really great video and explanations as always ! I’m wondering how you got the rgb shift working in the example at the start of the video? I would love to see a tutorial about this beautiful shape and the more accurate refractions !
Very nice video, the rendering is very good :-) One thing : the refraction angle equation is n1*sin(theta1) = n2*sin(thêta2) with n1 and n2 the indices of refraction of both touching medium so if the angle of incidence is thêta1, the angle of refraction is sin-1(n1/n2*sin(theta1)) The n1/n2 factor is because it goes from medium 1 to 2,and it is the inverse if you go from medium 2 to 1 It is not a matter of who's denser, you just have to use both indices and divide according to the direction
Thanks for uploading! I come from a pixel array background where I make functions to draw stuff onto a pixel array and render it. The only thing I really actually got how it works in shader programming is the sphere. I still dont quite get the code for a cube. What helped you getting into the thought process behind fragment shader programming?
Great video. You taught me almost everything I know about sdfs. I tried your code with an sdSphere() and it looks a bit wonky. Maybe there is a problem with the way you calculate the normals? Furthermore, why don't you use a recursion or a loop to do this refraction/reflection cycle multiple times? With your current solution, only the "exiting surface" can reflect and then the refraction on the way out is ignored. I would love to see a more sophisticated solution.
Great tutorial as usual! Just a nit in the total internal reflection diagram, the solid is a denser medium so the angle of the incident ray on the air side should be larger than the refraction angle. :P
Very cool stuff! But that internal reflection still needs to get refracted out eventually (perhaps after a few more reflections inside the object). As it is now, the internal reflection just goes straight to the cube map (which is obviously not correct).
Even though perhaps inefficient for realtime apllications, perhaps a workaround is possible, if we know what that internal reflection being refracted out would look like? Perhaps need to compare it to some ground truth situation in order to compare more easily what part of the 'visual experience' you're missing.
This whole video my cat was fixated with on your head and insisted on attacking you. Another great video, thanks!
I love your tutorials! Very well explained, and topics that I have a hard time finding other places on YT.
I’m curious why you use the normal vector to adjust the position of the point before the second round of raymarching rather than the reflection/refraction vector? Is it just to avoid issues when the angle is very shallow?
I think it's to avoid hitting the face you just checked again with the ray March. Makes sure you're clear of previous face when you start stepping along direction vector
That's a good question. I suppose you could step along the reflected vector, but the point is to get away from the surface and the normal direction is the fastest way to do that. If you stepped along the reflected vector, for a fixed small distance, you might still be within SURFDIST and have a wrongful direct hit.
I will be using your video as apart of my final for uni this semester in my Critical Code class. Thank you for making these complex ideas easy to understand for someone like me!
Awesome! Glad I could help :)
Thank you god of shaders for blessing us with another video!
your skills are impressive. Thanks for the tutorial.
Thank you so much i was looking ALL over the place for something like this
Two quick questions:
1. Would we also want to check for a (0, 0, 0) result from the first refract(...) call as well and handle that scenario or can the first refract never return (0, 0, 0) ?
2. Does the shader language have some form of vec3::ZERO definition that we could use for determining if refract returned (0, 0, 0) instead of the dot(...) calculation? It seems like 3 comparison operations of (x, y, z) might be faster than even a dot calculation?
For #1, that's exactly what was happening before he had the IOR inverted, as if we were inside glass looking into a cube of air. It only occurs when the second medium has an IOR less than the first.
I love your videos, these are my biggest motivations in computer graphics! Thanks for the good work!
I'm back here again ;) ... and though I'm sure I've said (written) it before (and will again) I have to express my gratitude and admiration You for Your excellent videos, and for all the work You do to share Your knowledge with us.
It is in my opinion people like You that make RUclips great !
Kind thoughts and best regards.
Thanks!
Really cool stuff! And a lot more pitfalls than expected, nice to get good explanations and solutions to the different issues when making this work! :)
Really cool! Keep up the great work!
Your videos never disappoints. Thank you for making them.
Fantastic explaininations as usual 👍
Would it be more accurate to do the inside march again if you reflect inside the object? Obviously there's a speed trade off though.
yes, strictly speaking there should be yet another ray march when that happens. In a recursive language this is easy, but in WebGL, not so much...
@@RayBellis A real recursion is not allowed in GLSL, but any recursion can be implemented in a loop. The number of loop iterations would be limited by the driver and the desired quality/performance tradeoff. In any case, I think a loop that would perform "keepReflectingUntilRefractsOrMaxIterationsAreReached" would make the result more realistic.
This is great and perfect timing in finding this, as I just been charmed by seeing lots of applications of real time refraction in Unreal (like the hardware raytracing prism ones) and others and researching various methods of approaching this, including larger mediums like bodies of water or an atmosphere.
Thanks! Looking forward to the continuation of this.
Great job as usual, I just like the way you are now moving to the physics and optics side, which is perfect, hope that we will reach to the hard-core PBR soon :) Thanks Martijn ✋
Keep on going, love your vids.
this is so beautiful
Really great video and explanations as always ! I’m wondering how you got the rgb shift working in the example at the start of the video? I would love to see a tutorial about this beautiful shape and the more accurate refractions !
All that is coming next week. Stay tuned!
I appreciate your work so much!
Aww thanks. And thanks for watching!
Amazing.
Thank you from brazil for the great tutorial
Very nice video, the rendering is very good :-)
One thing : the refraction angle equation is n1*sin(theta1) = n2*sin(thêta2) with n1 and n2 the indices of refraction of both touching medium so if the angle of incidence is thêta1, the angle of refraction is sin-1(n1/n2*sin(theta1))
The n1/n2 factor is because it goes from medium 1 to 2,and it is the inverse if you go from medium 2 to 1
It is not a matter of who's denser, you just have to use both indices and divide according to the direction
Map caps lock to escape gang here. Great stuff. Thanks!
Thanks for uploading! I come from a pixel array background where I make functions to draw stuff onto a pixel array and render it. The only thing I really actually got how it works in shader programming is the sphere. I still dont quite get the code for a cube. What helped you getting into the thought process behind fragment shader programming?
Great video. You taught me almost everything I know about sdfs.
I tried your code with an sdSphere() and it looks a bit wonky. Maybe there is a problem with the way you calculate the normals?
Furthermore, why don't you use a recursion or a loop to do this refraction/reflection cycle multiple times?
With your current solution, only the "exiting surface" can reflect and then the refraction on the way out is ignored.
I would love to see a more sophisticated solution.
GLSL does not support recursion. He explained this in the previous video (at about 11 minutes).
A loop should be possible though.
That caps lock rant in the middle :)
coooool!!! is it possible to use refract without texture too?
Sure. You can just continue ray marching
@@TheArtofCodeIsCool amazing thanks!
Really cool tutorial ! Thanks you.
Oh my god I love it so much!!
This is amazing!
Great tutorial as usual! Just a nit in the total internal reflection diagram, the solid is a denser medium so the angle of the incident ray on the air side should be larger than the refraction angle. :P
Agree with you about caps lock
nice video
Very cool stuff! But that internal reflection still needs to get refracted out eventually (perhaps after a few more reflections inside the object). As it is now, the internal reflection just goes straight to the cube map (which is obviously not correct).
Sure, I guess I should have mentioned that. In computer graphics we often settle for 'good enough' in the interest of framerate ;)
Even though perhaps inefficient for realtime apllications, perhaps a workaround is possible, if we know what that internal reflection being refracted out would look like?
Perhaps need to compare it to some ground truth situation in order to compare more easily what part of the 'visual experience' you're missing.
Nice stuff. But the Link to the Shadertoy(End Point) doesn't seem to work. Forgot to make the shader public?
Fixed, thanks for the heads-up
U are the man
So cool !
CAPSLOCK is used for SQL and preprocessor macros
lol obviously .. and GWBASIC haha
that's like the historical reason for CapsLock to exist ^.^
Awesome!
I remapped my CapsLock to CTRL
you're basically god
★★★★★
Now that i think about caps lock is pretty useless indeed, when has anyone ever turned caps lock on intentionally
+1
I wrote a program that detects if caps is on and turns it off
Truly a useless button
NO ITS NOT11
edit: yes