ashima / webgl-noise

Procedural Noise Shader Routines compatible with WebGL
MIT License
2.8k stars 302 forks source link

Making perturbed normal bumps #24

Closed unicomp21 closed 3 years ago

unicomp21 commented 3 years ago

Hi @stegu @ijm

Any chance I could beg for your help on this one? We're having trouble making bumps w/ perturbed normals in babylon.js, would be grateful for your expertise. Here is the discussion link. Trying to make a simple example where the perturbed normal bumps look good, like in Fig. 5-11.

https://forum.babylonjs.com/t/discontinuities-in-simplex-noise/20611/12

unicomp21 commented 3 years ago

@snowymo @sebastianherscher any chance Dr. Perlin is available? ^^

stegu commented 3 years ago

Have you seen this short PDF of mine? With analytic gradients, normal perturbation is really very simple. You just need to remember to scale the gradient with the inner derivative of the 3D texture coordinates. I reinvented this particular wheel before I found the reference, but first publishing credit goes to Morten Mikkelsen (his PhD thesis from 2008).

https://weber.itn.liu.se/~stegu76/TNM084-2019/bumpmapping/bumpmapping.pdf

Some demo source code is in the link below. It's a file for Shadron, a very convenient tool for shader programming experiments, but the ".shadron" file is a plain text file with GLSL code included. It has code for recomputing normals at the vertex level (displacement mapping) as well as at the fragment level (bump mapping), using the same expressions for both. (Note that the noise function is in its separate .glsl file, which may or may not be identical to a file with the same name in the "webgl-noise" repo.) https://weber.itn.liu.se/~stegu76/TNM084-2019/shadron

/Stefan G

unicomp21 commented 3 years ago

Thanks @stegu !

unicomp21 commented 3 years ago

@stegu is that the same as 5.6?

https://developer.nvidia.com/gpugems/gpugems/part-i-natural-effects/chapter-5-implementing-improved-perlin-noise

stegu commented 3 years ago

That article uses the same bump computation, yes, although it doesn't explain how it works.

On Mon, 10 May 2021, 00:38 John Davis, @.***> wrote:

@stegu https://github.com/stegu is that the same as 5.6?

https://developer.nvidia.com/gpugems/gpugems/part-i-natural-effects/chapter-5-implementing-improved-perlin-noise

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ashima/webgl-noise/issues/24#issuecomment-835914581, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFGK2XTM6JGXHLP6GO2PITTM4FF3ANCNFSM44MVCBEA .

unicomp21 commented 3 years ago

Thanks. Is there any way to get a 5th order interpolation between mesh.position's in the shader? When using webgl?

stegu commented 3 years ago

I am sorry for my mushy brain: the perturbation cretated by subtracting the gradient from the normal without first projecting it to the surface tangent plane is wrong. Looks OK but does not correspond to any analytical surface normal. The projection described in my PDF and in Mikkelsen is the correct way to do it, and it is only a small amount of extra work.

I don't quite understand what you mean by a 5th order interpolation of mesh positions. The 5th order polynomial requires an input of 0..1, and that can of course be achieved by texture coordinates or the like. The interpolation is created in code, and if I'm not misremembering things, that is what my implementations of "classic noise" are doing in the webgl-noise repo.

Analytic gradients are a lot less work than finite difference approximations for simplex noise, but for classic noise the expressions for the derivative get quite nasty. I would not recommend that.

On Mon, 10 May 2021, 12:25 John Davis, @.***> wrote:

Thanks. Is there any way to get a 5th order interpolation between mesh.position's in the shader? When using webgl?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ashima/webgl-noise/issues/24#issuecomment-836523093, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFGK2XLEB4IKSNFPX65AVLTM6YCFANCNFSM44MVCBEA .

unicomp21 commented 3 years ago

and that can of course be achieved by texture coordinates or the like

I get the gist of what's being said, but not sure I could implement it. Any links/recommendations for reading? Maybe I need to understand Barycentric coordinates better? What all do I encode in a vertex, so that I can recover the surrounding triangle, in the shader?

stegu commented 3 years ago

By "it" in "implementing it", you would be referring to what exactly? If what I say below is a gross misunderstanding of the question, please ask again.

Having parameters (0..1, 0..1) over a rectangle (two triangles) would amount to setting vertex attributes (e.g "texture coordinates") for the corners appropriately, let the vertex-to-fragment interpolation mechanism interpolate that linearly (in a perspective correct manner), and compute the 5th order polynomial weight (the "S-curve") in the fragment shader. The built-in GLSL "smoothstep()" is a third order polynomial (3x^2 - 2x^3), so the 5th order weight (6x^5 - 15x^4 + 10x^3) would need to be coded explicitly.

Per-primitive surface parameters (u,v) in the range 0..1 are (were) a staple of the Renderman standard, for every primitive except polygons, for which (u,v) are zero everywhere and texture coordinates (s,t) need to be specified explicitly for all vertices to handle surface mapping. Sadly, polygons is currently all we have in OpenGL, so per-primitive texture coordinates would be the way to go here. Note that local per-primitive texture coordinates makes it impossible to do any longer runs of quads or triangle strips/fans, because the texture coordinates for each shared vertex is different from one quad to the next. Therefore, only single quads or strips/fans of exactly two triangles are possible when sending the primitives to OpenGL for drawing.

/Stefan

unicomp21 commented 3 years ago

Exactly what I was looking for, thanks @stegu!

On Mon, May 10, 2021 at 10:40 AM Stefan Gustavson @.***> wrote:

By "it" in "implementing it", you would be referring to what exactly? If what I say below is a gross misunderstanding of the question, please ask again.

Having parameters (0..1, 0..1) over a rectangle (two triangles) would amount to setting vertex attributes (e.g "texture coordinates") for the corners appropriately, let the vertex-to-fragment interpolation mechanism interpolate that linearly (in a perspective correct manner), and compute the 5th order polynomial weight (the "S-curve") in the fragment shader. The built-in GLSL "smoothstep()" is a third order polynomial (3x^2 - 2x^3), so the 5th order weight (6x^5 - 15x^4 + 10x^3) would need to be coded explicitly.

Per-primitive surface parameters (u,v) in the range 0..1 are (were) a staple of the Renderman standard, for every primitive except polygons, for which (u,v) are zero everywhere and texture coordinates (s,t) need to be specified explicitly for all vertices to handle surface mapping. Sadly, polygons is currently all we have in OpenGL, so per-primitive texture coordinates would be the way to go here. Note that local per-primitive texture coordinates makes it impossible to do any longer runs of quads or triangle strips/fans, because the texture coordinates for each shared vertex is different from one quad to the next. Therefore, only single quads or strips/fans of exactly two triangles are possible when sending the primitives to OpenGL for drawing.

/Stefan

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/ashima/webgl-noise/issues/24#issuecomment-836854375, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAEFL7MAT7XDMBYN5EKOGXDTM745XANCNFSM44MVCBEA .

unicomp21 commented 3 years ago

@stegu see the distortion at the poles, on the sphere?

https://nodematerial-editor.babylonjs.com/#ND6Z9D#6

Think I'm not transforming the gradient properly? Any idea how I can fix it? Not sure how to transform into tangent space.

(using touchpad or mouse, scroll right pane down to bottom in order to see shader sphere w/ bumps)

stegu commented 3 years ago

I prefer not to transform to gradient space at all. World space 3D noise makes that possible to avoid. See the PDF I linked to originally. It really is a lot less cumbersome. Tangent space at the poles of a sphere with lat-long mapping is not well defined -- a classic problem you just won't have with 3D bump mapping.

On Wed, 12 May 2021, 13:32 John Davis, @.***> wrote:

@stegu https://github.com/stegu see the distortion at the poles, on the sphere?

https://nodematerial-editor.babylonjs.com/#ND6Z9D#6

Think I'm not transforming the gradient properly? Any idea how I can fix it? Not sure how to transform into tangent space.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ashima/webgl-noise/issues/24#issuecomment-839697891, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFGK2TBMLTJZEYGDIXUNCDTNJRLFANCNFSM44MVCBEA .

unicomp21 commented 3 years ago

@stegu I didn't realize that, thanks!

stegu commented 3 years ago

Sorry for the confusion. My PDF was written for my students, and it includes a repetition of the tangent space method. I forgot to say "page 3 has the juicy bits".

/Stefan G

On Mon, May 17, 2021 at 12:49 PM John Davis @.***> wrote:

@stegu https://github.com/stegu I didn't realize that, thanks!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ashima/webgl-noise/issues/24#issuecomment-842222390, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFGK2RFRFVYFTACDE5JOKLTODYCXANCNFSM44MVCBEA .

unicomp21 commented 3 years ago

Thanks @stegu !