raysan5 / raylib

A simple and easy-to-use library to enjoy videogames programming

Home Page:http://www.raylib.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[rmodels] "matModel" shader uniform is not multiplied with the push/pop matrix stack

denovodavid opened this issue · comments

Issue description

While making a transform hierarchy, I noticed that rmodels.c DrawMesh function does not set the "matModel" matrix shader uniform relative to the push/pop matrix stack. See here:

raylib/src/rmodels.c

Lines 1392 to 1398 in 9d67f47

// Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL
if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], transform);
// Accumulate several model transformations:
// transform: model transformation provided (includes DrawModel() params combined with model.transform)
// rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack
matModel = MatrixMultiply(transform, rlGetMatrixTransform());

"matModel" uniform is set to the model's local transform, then right after, a matModel variable is created, accumulated with push/pop matrix stack, and used for "matNormal" and "mvp" uniforms

This seems unintuitive, I expect "matModel" uniform to be the model space to world space transform, the same used calculate the "mvp" uniform, the same as the matModel variable.

However, I can work around this by getting the correct matModel in the shader by way of mat4 matModel = inverse(transpose(matNormal));

Issue Screenshot

Based on the Basic Lighting example, I have a player model that gets drawn after using rlPushMatrix() and rlTranslatef(player_position), it is incorrectly lit, as if it was positioned at {0, 0, 0}.

image

It should look like this:

image

commented

@denovodavid Actually, the push/pop functionality was mostly intended the immediate-mode-style batching system, not for the modern VBO-based models drawing system. model.transform is actually intended for that.

Not sure if applying matModel to the model.transform could derive in some issue. If you do some testing in that regards and nothing is broken, I can consider applying that additional transformation...

@denovodavid Actually, the push/pop functionality was mostly intended the immediate-mode-style batching system, not for the modern VBO-based models drawing system. model.transform is actually intended for that.

I see, though I think I can state my issue more clearly. The matrix stack is already used when calculating the model matrix used in mvp sent to the shader, matProjection and matView also come from the matrix stack. matModel (shader uniform) is just the local model.transform matrix, which means you cannot necessarily reconstruct the mvp in the shader from what should be its component parts.

// vertex shader
mvp != matProjection*matView*matModel;

This is what causes the incorrect lighting from my previous screenshots.

Not sure if applying matModel to the model.transform could derive in some issue. If you do some testing in that regards and nothing is broken, I can consider applying that additional transformation...

All I propose is to set (what I believe to be) the correct matModel value of the model matrix shader uniform.

 // Accumulate several model transformations: 
 //    transform: model transformation provided (includes DrawModel() params combined with model.transform) 
 //    rlGetMatrixTransform(): rlgl internal transform matrix due to push/pop matrix stack 
 matModel = MatrixMultiply(transform, rlGetMatrixTransform()); 

 // Model transformation matrix is sent to shader uniform location: SHADER_LOC_MATRIX_MODEL 
 if (material.shader.locs[SHADER_LOC_MATRIX_MODEL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_MODEL], matModel); 

I'll make a PR to show specifically.

commented

@denovodavid thanks for the detailed explanation! I missunderstood it on my first read. And thanks for the fix!