Animated mesh and lighting bug

BlitzMax Forums/MiniB3D Module/Animated mesh and lighting bug

Sake906(Posted 2010) [#1]
When loading an animated mesh that bears no animation and features a static pose, after loading animation sequences on it and playing them, the mesh faces are lit as if the mesh were still on a static pose; Imagine a character with the default "T" pose (arms horizontal, etc). The moment the character lowers it's arm and twists it, the backside that once stood on the side where light didn't reach it (now facing towards the light) still appears shaded, and if you guess, the side that was lit remains lit when turning and facing opposite from light's direction.

In essence, lighting doesn't take vertex bone transformation into account, thus vertices behave as if they were still "static" and on their former positions after the bones offset them. I tried calling "updatenormals" and other such things, nothing solves this problem; I made a search around the forums to see if any of you were having this issue, found nothing. Could it be something with my setup?

Last edited 2010


simonh(Posted 2010) [#2]
Yes, the vertex normals are not transformed when animating a mesh. This is normally not a problem, as it's hard to notice (I think you're the first person to flag it up).

Transforming the vertex normals can be done, but it will slow things down.

Last edited 2010


Sake906(Posted 2010) [#3]
I'm glad you know about this, but I'm afraid to mention that this is very noticeable and I spotted it right away.

Perhaps on the same way you alter vertex positions when their corresponding bones move, you can alter their normals?


jhocking(Posted 2010) [#4]
Do vertex shaders allow you to alter the normals on vertices? I'm pretty sure they do (have only just started writing shaders) but if not then setting normals on all the vertices is significantly more expensive than altering their positions for skeletal animation.


simonh(Posted 2010) [#5]
Perhaps on the same way you alter vertex positions when their corresponding bones move, you can alter their normals?

Yes, it's easy enough to do, just expensive to do in software as Joe says. Shaders would no doubt be a lot quicker.


Sake906(Posted 2010) [#6]
would shaders work on the normal minib3d for this purpose? I honestly think it's critical.

Then again I wonder, does this also happen when altering a mesh through the surface commands? I haven't checked.


simonh(Posted 2010) [#7]
If you're altering the mesh through the surface commands, then you have to specify everything yourself, nothing is changed for you.

Thinking about it, calling UpdateNormals after every UpdateWorld should probably work - are you sure it doesn't?

I don't know enough about shaders to say how it could work with them.


Sake906(Posted 2010) [#8]
I tried, it doesn't work.


simonh(Posted 2010) [#9]
Ah yes, UpdateNormals operates on the surf_list, whereas it would need to operate on the anim_surf_list to work.

You could add an UpdateAnimNormals function yourself, but you'd also need to add an GetAnimSurface method as well.


Sake906(Posted 2010) [#10]
I'm thinking that using a cubemap texture simulating shading, which reorients itself depending on light direction, could pose as a quick way to get around this for the time being; I've seen it being used on the "FastExt" library made for Blitz3D, then again I'm not sure if minib3d supports that type of cubemap and such reorientation procedures.

I will look into the normals thing, maybe it is not that slow in the end.


SLotman(Posted 2010) [#11]
To me, calling "UpdateNormals" (or making an UpdateAnimNormals) every time seems like a waste of processing power - couldn't the normals be pre-calculated for every keyframe, and then interpolated to the frames in-between?

(Just an idea, I don't know the animation system that well...)


jhocking(Posted 2010) [#12]
I don't think so. Interpolation is always a higher level abstraction on top of the low level graphics processing. At some point the value being interpolated (say, position) is calculated every frame in order to update, but that calculation may be done in the guts of the graphics engine so that a person using the engine doesn't have to do anything. Thing is, what we're talking about is a pretty low level adjustment to the engine.


Kryzon(Posted 2010) [#13]
I think it should be added to the VertexDeform function in TAnimation.BMX.

You see, inside VertexDeform, each vertex has its position changed based on the 4 bones that influence it (and their weights).
It's in that spot that the normal processing should be added - I think we need to multiply the normal coordinates with the bone's tform_mat matrix, tin the same way the vertex position is calculated (check VertexDeform() function inside TAnimation.BMX).


I'm thinking that using a cubemap texture simulating shading, which reorients itself depending on light direction, could pose as a quick way to get around this for the time being; I've seen it being used on the "FastExt" library made for Blitz3D, then again I'm not sure if minib3d supports that type of cubemap and such reorientation procedures.
I think you shouldn't. That's the fixed-function way of doing things.
With MiniB3D you finally have the capability of using GLSL shaders, and to process normals the "appropriate" way, in a vertex shader. This way you can accomplish Hardware Skinning - there is some literature on the subject; basically you need to pass the calculated bone matrices (these are being calculated inside the AnimateMesh function of TAnimation) as an array of uniform matrices; send another array for the bone IDs and for the weights (you can use the glColor attribute to store the 4 weights), and calculate everything in the vertex-shader.

Last edited 2010


Kryzon(Posted 2010) [#14]
Sake906, please test the following.

Replace your VertexDeform() function, located in TAnimation.BMX with this version:


Add the following line inside the Case "ANIM" block, located at line 596 of TModel.BMX. The line should be added just below the line "anim_surf.vert_coords=surf.vert_coords[..]", inside that block:
anim_surf.vert_norm=surf.vert_norm[..]

PS: This is a wild guess, and from the example "Anim.BMX" I couldn't see much of a difference. Make sure to test with whatever you used to notice the fault.

PS2: I'm using the SuperStrict version, in case you see any declarations that differ from yours.

Last edited 2010


Sake906(Posted 2010) [#15]
hmm tried this, the mesh is still not having the normals updated. What if this is related to the way I saved the b3d or the way I'm loading it?