]]>Ah...

in that case, I think I'll have to go back to the 'neighbours' method, but working in a Spherical coordinate system, as I mentioned above. Unfortunately, a GLSL compiler bug on my laptop prevents me from trying it at the moment, but I don't see why it wouldn't work, in theory...

I'll keep you posted.

Thanks for all your help,a|x

]]>After thinking some more about this, I realized that it will never work, because modifying a vertex also modifies the normals of the other vertices connected to the vertex. I'm afraid it's back to square one...

]]>@Kenneth Gorking

Did you remove the extra gl_NormalMatrix from your shader? Also, I think it should be 'orgVertex - newVertex' instead of what I wrote...

Yep, I removed the extra matrix-multiplication.

Swapping the order of the normal-calculation, as you suggested did make a difference, but didn't solve the problem, sadly.Here is the Vertex Shader as it currently stands:

`// // vertexnoise.vert: Vertex shader for warping the geometry with noise. // // author: Philip Rideout // // Copyright (c) 2005-2006: 3Dlabs, Inc. // // // See 3Dlabs-License.txt for license information // // Lighting + surface controls uniform vec4 AmbientColor, DiffuseColor; uniform vec3 LightPosition; uniform vec4 SurfaceColor; /////////////////////////// // Functions // /////////////////////////// // Varying-type variable for lighting color, sent to Fragment Shader. // Varyings are interpolated across polygons to give a smooth result in the FS. varying vec4 outColor; // Environment-Map function void envMapVS(in vec4 vert, in vec3 norm) { vec4 vWorld = gl_ModelViewMatrix * vert; vec3 nWorld = gl_NormalMatrix * norm; // Diffuse light vec3 vertToLight = normalize(LightPosition - vWorld.xyz); float diffuseLight = max(dot(vertToLight, nWorld), 0.0); // This varying variable is passed to the Fragment Shader outColor = AmbientColor + vec4(diffuseLight * DiffuseColor.xyz, DiffuseColor.w); // Environment mapping texture coordinates vec3 vWorldUnit = normalize(vWorld.xyz); vec3 f = reflect(vWorldUnit, nWorld); float m = 2.0 * sqrt(f.x * f.x + f.y * f.y + (f.z + 1.0) * (f.z + 1.0)); // Texture coordinates set // (determines which part of envMap to lookup in FS). // Also automatically interpolated between VS and FS. gl_TexCoord[0].xy = vec2(f.x / m + 0.5, -f.y / m + 0.5); } // 3D Noise controls uniform vec3 Offset; uniform float ScaleIn; uniform float ScaleOut; // 3D Noise function vec4 noise3D(in vec4 vert, in vec3 gridOffset) { vert.xyz += noise3(gridOffset + Offset + vert.xyz * ScaleIn) * ScaleOut; return vert; } // Structure to hold vertex position and normal struct posNorm {vec4 pos;vec3 norm;}; // Calculate and return vertex position and normal posNorm vNoise3D(in vec4 vert) { // Init output variable of custom type posNorm (defined above) posNorm result; // Calculate new vertex position using function defined above result.pos = noise3D(vert, vec3(0.0)); // Calculate normals result.norm = normalize(gl_Normal + normalize(vert.xyz - result.pos.xyz)); return result; } /////////////////////////// // Main Loop // /////////////////////////// void main(void) { // Initial vertex position vec4 vertex = gl_Vertex; // get final vertex position and normals posNorm outPut = vNoise3D(vertex); // Call envMapVS function, passing it vertex position and normal vec3 normal = gl_NormalMatrix * outPut.norm; // Apply environment-map lighting function envMapVS(vertex, normal); gl_Position = gl_ModelViewProjectionMatrix * outPut.pos; }`

a|x

]]>Did you remove the extra gl_NormalMatrix from your shader? Also, I think it should be 'orgVertex - newVertex' instead of what I wrote...

]]>Hi again.

@Kenneth GorkingAnother way to do it, is to pass along the original normal of the mesh, and then create a new modified normal from the direction between the old and new vertex. Something like: newNormal = normalize(orgNormal + normalize(newVertex - orgVertex));

Ah, great suggestion! So simple, too...

Unfortunately, it doesn't seem to work for me. I get the same jagged dark areas, and when I rotate the mesh relative to the light-source, the lighting behaves strangely- the light-source appears also to be moving, which is not the case if I use the original normal (though of course this is inaccurate after mesh distortion).

The screenshots below show the mesh rotated on the X axis, with the light-source in a constant position:

I'm sure there's something basic I'm missing here.

Can you think of anything else I could try?

a|x

]]>Another way to do it, is to pass along the original normal of the mesh, and then create a new modified normal from the direction between the old and new vertex. Something like:

newNormal = normalize(orgNormal + normalize(newVertex - orgVertex));

]]>Hi Kenneth Gorking!

Thanks very much for getting back to me.

Doh! I've been very silly... of course, this only works with parametric surfaces, where, as you say, the input is a flat mesh...The offsets I used to calculate 'neighbours' were on the X and Y axis, which of course failed to take into account the fact the original mesh is a sphere.

Soo... since the mesh is spherical, maybe if I calculate spherical coordinates for the vertices, then base the noise on rho, theta and phi values, rather than X, Y and Z coordinates, and calculate neighbours using offsets to two of the spherical coordinates, it may just work...

Thanks for the pointer!

I'll let you know how it goes.

a|x

]]>I just looked over it again, and noticed tonfilm mentions that this only works with a 2D input mesh to be offset by the noise, like a flat terrain.@tonfilm

Assuming the input mesh is a grid in the xy-plane

Also, you seem to be multiplying the resulting normal twice with gl_NormalMatrix.

]]>If someone could tell me if I'm barking up the wrong tree completely with this one (ie is this particular method workable when using noise3()), I'd be really grateful.

Thanks in advance,

a|x

]]>Anyone?

a|x

]]>Hi,

I'm just trying to generate working normals in my simple Vertex Noise shader, and haven't been having much success.

I've been using GLSLs builtin noise3() function, and the simple 'neighbours' technique outlined by tonfilm on his blog

http://tonfilm.blogspot.com/2007/01/calculate-normals-in-shader.html for normal-estimation.

Just wondering if anyone can offer any advice on where I might be going wrong, or tell me whether or not this technique is suitable for use in this particular case.

Here is my vertex shader, which applies noise to the vertex position using noise3(), calculates a normal (wrongly), changes the texture coords for a simple Envmap lookup in the Fragment Shader, and sets a varying variable for basic diffuse lighting:

`// 3D Noise controls uniform vec3 Offset; uniform float ScaleIn; uniform float ScaleOut; // 3D Noise function vec4 noise3D(in vec4 vert, in vec3 gridOffset) { vert.xyz += noise3(gridOffset + Offset + vert.xyz * ScaleIn) * ScaleOut; return vert; } // Structure to hold vertex position and normal struct posNorm {vec4 pos;vec3 norm;}; // Calculate and return vertex position and normal posNorm vNoise3D(in vec4 vert) { // Init output variable of custom type posNorm (defined above) posNorm result; // Calculate new vertex position using function defined above result.pos = noise3D(vert, vec3(0.0)); // Calculate normals float gridOffset = 0.001; vec4 neighbourX0 = noise3D(vert, vec3(gridOffset, 0.0, 0.0)); vec4 neighbourY0 = noise3D(vert, vec3(0.0, gridOffset, 0.0)); vec3 tangent = neighbourX0.xyz - result.pos.xyz; vec3 bitangent = neighbourY0.xyz - result.pos.xyz; vec3 norm = cross(tangent, bitangent); norm = normalize(norm); norm = gl_NormalMatrix * norm; result.norm = norm; return result; } /////////////////////////// // Main Loop // /////////////////////////// void main(void) { // Initial vertex position vec4 vertex = gl_Vertex; // get final vertex position and normals posNorm outPut = vNoise3D(vertex); // Call envMapVS function, passing it vertex position and normal vec3 normal = gl_NormalMatrix * outPut.norm; // Apply environment-map lighting function envMapVS(vertex, normal); gl_Position = gl_ModelViewProjectionMatrix * outPut.pos; }`

I don't think I need to post the Fragment Shader, as it's very simple, and I think it's the normal-estimation in the VS that's the problem here.

The screenshots below show the result I'm getting (with the envmap effect turned off):

As you can see, some of the Normals are clearly 'flipped'Any advice on how I might solve this annoying issue much appreciated!

Thanks in advance,

a|x