I noticed that in my editor (github.com/wezu/koparka) the lighting of the terrain is all wrong. It looks like the light moves with the camera, but in fact I’ve got the normals wrong.
I generate the normals in the pixel shader based on some code I found on the net… and as it often is in code found in the net, it turns out it’s not what I expected. The generated normals are in object (model) space.
vec3 norm=vec3(0.0,0.0,1.0);
const vec3 vLeft=vec3(1.0,0.0,0.0);
const float pixel=1.0/512.0;
const float height_scale=100.0;
//normal vector...
vec4 me=texture2D(height,texUV);
vec4 n=texture2D(height,vec2(texUV.x,texUV.y+pixel));
vec4 s=texture2D(height,vec2(texUV.x,texUV.y-pixel));
vec4 e=texture2D(height,vec2(texUV.x+pixel,texUV.y));
vec4 w=texture2D(height, vec2(texUV.x-pixel,texUV.y));
//find perpendicular vector to norm:
vec3 temp = norm; //a temporary vector that is not parallel to norm
temp.x+=0.5;
//form a basis with norm being one of the axes:
vec3 perp1 = normalize(cross(norm,temp));
vec3 perp2 = normalize(cross(norm,perp1));
//use the basis to move the normal in its own space by the offset
vec3 normalOffset = -height_scale*(((n.r-me.r)-(s.r-me.r))*perp1 + ((e.r-me.r)-(w.r-me.r))*perp2);
norm += normalOffset;
norm = normalize(norm);
//TBN
vec3 tangent = normalize(cross(norm, vLeft));
vec3 binormal = normalize(cross(norm, tangent));
I need to either get the normal to view space or get the light vector (of a directional light) from view to object space… I honestly don’t know how to do that. Probably I’ve got to use a matrix of some sorts (gl_NormalMatrix stops the light from moving, but the normals are still wrong), then again passing a light vector from python might be a better idea.
Hmm… Looking at the list of matrices in the GLSL input list, have you tried putting your normals through the model-view matrix? (“uniform mat4 p3d_ModelViewMatrix;”)
I’m not sure that model-view is the correct matrix, but it seems like a decent guess.
Does “trans_model_to_world” exist in Panda’s support for GLSL? I see mention of the “trans_x_to_y” pattern in the list of CG inputs, but not the GLSL list…
trans_model_to_world in Panda can be getting as model.getMat(world) if I not mistaken. Usually world = render.
Also in my case (Blender’s shaders) if I works with lights, I should multiple they matrices with convert space Matrix
Mat4.convertMat(CSYupRight, CSDefault) * light.getMat(world) Not sure - is it Blender’s feature or GLSL.
AssertionError: Shader input model_to_world is not a nodepath.
There was some trick with a temp node… but is it really what I need? My “self.mesh” is at point 0,0,0 with a rotation of 0,0,0, and a scale of 1 - that info will get me a matrix to go from object (same as world in this case I think) to view? Because gl_LightSource[0].position will get me a view space light vector, right? (btw how do you get the light info without the fixed function pipeline in panda3d/glsl? )
So maybe it would be simpler to get the light vector in model space? I have one directional light with a hpr of (90, -45, 0), I’m not gonna move it (often) and I’m not gonna move the terrain at all. I’d just pass it as a shader input… if I’d only knew how to calculate it in the first place.
Okay, uh, trans_model_to_world exists in GLSL in 1.9, but it is equivalent to p3d_ModelMatrix. It is is recommended you use that instead (and p3d_ModelMatrixInverse if you want the opposite, you can also add Transpose to the end if necessary). trans_model_to_world will probably eventually be deprecated.
Also, before 1.9, setShaderInput only took a NodePath for setting matrices, like this:
In 1.9, this requirement is lifted, but it is still better to use p3d_ModelMatrix.
Panda3D currently provides no light info structure. It sounds like a useful feature to have. If you want this feature, I suggest you file a bug report.
Hmm… I think I must have the normals wrong. Maybe the x and y are switched or something…or it’s all just rubish
Anyway. I don’t think trans_model_to_world or p3d_ModelMatrix is what I need. I think the normals are in object or world space (should be the same in my case) and I need them in view space for lighting.
So the first thing I wanted to use (gl_NormalMatrix or p3d_NormalMatrix) should be the right thing.
// This is the upper 3x3 of the inverse transpose of the ModelViewMatrix. It is used
// to transform the normal vector into view-space coordinates.
uniform mat3 p3d_NormalMatrix;
I’ll need to make some debug model and shader to see how world/model normals should look like just to tell what’s wrong (flat surface should be blue (0,0,1) but I can’t tell the other colors).
Some light structure when gl_LightSource[] is not there would be nice… unless one can pass all the needed data from python with little to none performance hit. For now I have no need for it, I’m using the oldest glsl version that will work (120-150).
The left mound is a model with a cg shader dumped from the auto-shader where I just removed the parts where normlas are transformed and I write the normal to ‘o_color’.
The right mound is using my terrain shader.
Some directions are mixed, but I fixed that:
I was thinking ‘p3d_NormalMatrix’ is what I need but:
:display:gsg:glgsg(error): Unrecognized uniform matrix name ‘NormalMatrix’!
So I used gl_NormalMatrix in the hope it is the same, but things still look wrong:
Then again if I render it all with colors and the light… it looks sort of ok:
Ok, another question are you translate normals form (-1.0+1.0) diapason to (0.0+1.0) before write it to the image?
But yes, seems that Panda show normals in view space xyz = right, depth, up, and your normals in model space (?) Y - up
In fast test I get something similar your image:
vertex:
N = vec3(gl_ProjectionMatrix * vec4(normalize(gl_NormalMatrix * gl_Normal),1.0));
fragment:
gl_FragColor.xyz = (N*0.5+0.5).xzy;
The normals are calculated in the fragment shader. There’s quite a lot of detail in the height map that gets lost if I do it only on the verts - at least it was true when I used a 10k mesh, at some point I’ll test if it’s true for the 35k mesh that I use now - but first getting valid normals is more important for me then getting them faster.
Made a version that uses 6x diffuse texture +6x normal +2x attribute map + 1x height map + 1x walk map, for the editor all are needed but the walk map is not needed to be displayed for a game and the height can be packed to the alpha channel of either attribute maps. 6 textures should be enough if I can ad the ability to mix them at will (not present at the moment).
I’m running it on a radeon 3000 series, so the 4000 series should handle it ok.
texture2DLod error - looks like it’s not popular on some systems, it was a crude fix for grass quality anyway - fixed for grass
GL_EXT_draw_instanced - it’s just a warning, should be fine. I’m using GL_ARB_draw_instanced and GL_EXT_draw_instanced so one of them should work and the other will fail depending if you are on a ATI/AMD or Nvidia… might fail in both cases on Intel (can’t tell don’t have one) - ignored
GL_EXT_gpu_shader4 - fxaa will not work if this is not supported.
None of this is important to the normal problem, so I really should make a simpler example, but I’m stuck at getting my editor working again