-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(rendering): replicate SkeletalMesh fields, fix debug skeleton scale #4897
fix(rendering): replicate SkeletalMesh fields, fix debug skeleton scale #4897
Conversation
Vector3f location = locationComponent.getWorldPosition(new Vector3f()); | ||
Quaternionf rotation = locationComponent.getWorldRotation(new Quaternionf()); | ||
Matrix4f transform = new Matrix4f().translationRotateScale(location, rotation, 1.0f); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to create new instances for the location vector, the rotation quaternion, and the transformation matrix with each render call for each entity?
You often raise concerns about code like this, so I'm wondering about all the instantiations in this code render code block that gets called quite often (if the debug feature is enabled).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
umm, I guess I could use a temporary Matrix. this is because we have custom offset and translation for the SkeletonComponent :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we need individual vectors here and cannot reuse a single temporary object instance for rendering the skeleton for all entities?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, we can cache it, I was just getting lazy. was looking at this at 10 something.
…f github.com:MovingBlocks/Terasology into bugfix/correct-SkeletonRenderer-debug-resolve-update
I'm not sure this works correctly yet 🤔 Note that the debug skeleton seems to be higher in the air than the actual model. @pollend did you only correct scaling the debug skeleton or also applying an offset? |
…f github.com:MovingBlocks/Terasology into bugfix/correct-SkeletonRenderer-debug-resolve-update
@jdrueckert this fixes the offset in the overlay rig but this kind of horrible so this offset will just offset the camera space and additionally we also have an additional translation on top of the rig itself to also offset things. everything in the cameras view for the rig is offset by that amount. not sure if that lines up with world coordinates at all? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all it's hard for me to review this because I don't understand the math behind this, so please add comments especially in the new code in SkeletonRenderer
that explain what the respective parts do.
Second, why do we need to offset the camera to have the debug skeleton match the actual one the model is matching? This does not seem to make sense to me? Where does this mismatch between debug skeleton and model come from? Is the model not matching the skeleton or is the rendered debug skeleton not matching the "real" skeleton?
Third, there's open checkstyle warnings.
engine/src/main/java/org/terasology/engine/rendering/opengl/OpenGLSkeletalMesh.java
Show resolved
Hide resolved
there is some code up a couple lines I'm just duplicating that logic. |
Can you please note on which of my three points you're talking about and reference specific lines? |
looks like I applied heightoffset twice |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests out fine in-game now, but I think we can improve on documentation here while we're at it 🙏
Vector3f worldPos = new Vector3f(); | ||
Vector3f worldPositionCameraSpace = new Vector3f(); | ||
worldPos.sub(cameraPosition, worldPositionCameraSpace); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a bit lengthy for
Vector3f worldPos = new Vector3f(); | |
Vector3f worldPositionCameraSpace = new Vector3f(); | |
worldPos.sub(cameraPosition, worldPositionCameraSpace); | |
Vector3f worldPositionCameraSpace = cameraPosition.negate(new Vector3f()); |
Vector3f location = locationComponent.getWorldPosition(new Vector3f()); | ||
Quaternionf rotation = locationComponent.getWorldRotation(new Quaternionf()); | ||
entityTransform.translationRotateScale(location, rotation, 1.0f); | ||
|
||
Vector3f worldPos = new Vector3f(); | ||
Vector3f worldPositionCameraSpace = new Vector3f(); | ||
worldPos.sub(cameraPosition, worldPositionCameraSpace); | ||
|
||
// same heightOffset is applied to worldPositionCameraSpace from #renderOpaque() | ||
// TODO: resolve repeated logic for transformation applied to bones | ||
worldPositionCameraSpace.y += skeletalMesh.heightOffset; | ||
|
||
Matrix4f matrixCameraSpace = new Matrix4f().translationRotateScale(worldPositionCameraSpace, new Quaternionf(), 1.0f); | ||
Matrix4f modelViewMatrix = new Matrix4f(worldRenderer.getActiveCamera().getViewMatrix()).mul(matrixCameraSpace); | ||
material.setMatrix4("projectionMatrix", worldRenderer.getActiveCamera().getProjectionMatrix()); | ||
material.setMatrix4("modelViewMatrix", modelViewMatrix, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As somebody that never really paid a lot of attention in my university computer graphics course, this is all Greek to me... can you please add some comments explaining what's happening here and why?
locCompA.getRelativeTransform(relMat.identity(), entity); | ||
result.set(entityTransform) | ||
.mul(relFinal.identity() | ||
.scale(skeletalMesh.scale) | ||
.translate(skeletalMesh.translate) | ||
.mul(relMat)) | ||
.transformPosition(currentPos.zero()); | ||
meshData.position.put(currentPos); | ||
|
||
|
||
locCompB.getRelativeTransform(relMat.identity(), entity); | ||
result.set(entityTransform) | ||
.mul(relFinal | ||
.identity() | ||
.scale(skeletalMesh.scale) | ||
.translate(skeletalMesh.translate) | ||
.mul(relMat)) | ||
.transformPosition(currentPos.zero()); | ||
meshData.position.put(currentPos); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here pls
…f github.com:MovingBlocks/Terasology into bugfix/correct-SkeletonRenderer-debug-resolve-update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the improved code comments! They are way more helpful!
locCompA.getRelativeTransform(relMat.identity(), entity); | ||
// entityTransform * (scale, translation) * relativeMat * [x,y,z,1] | ||
result.set(entityTransform) | ||
.mul(relFinal.identity() | ||
.scale(skeletalMesh.scale) | ||
.translate(skeletalMesh.translate) | ||
.mul(relMat)) // apply relative transformation for the skeletalMesh scale and transform | ||
.transformPosition(currentPos.zero()); | ||
meshData.position.put(currentPos); | ||
.mul(relMat)) | ||
.transformPosition(currentPos.zero()); // get the position of the start of the bone | ||
meshData.position.put(currentPos); // the start of the bone | ||
|
||
// relative transform around the root skeletalMesh.scale and skeletalMesh.translate are relative to root | ||
// need to calculate the relative transformation from the entity to the connecting bone | ||
locCompB.getRelativeTransform(relMat.identity(), entity); | ||
// entityTransform * (scale, translation) * relativeMat * [x,y,z,1] | ||
result.set(entityTransform) | ||
.mul(relFinal | ||
.identity() | ||
.scale(skeletalMesh.scale) | ||
.translate(skeletalMesh.translate) | ||
.mul(relMat)) // apply relative transformation for the skeletalMesh scale and transform | ||
.transformPosition(currentPos.zero()); | ||
meshData.position.put(currentPos); | ||
.mul(relMat)) | ||
.transformPosition(currentPos.zero()); // get the position to the connecting bone | ||
meshData.position.put(currentPos); // the end of the bone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those two sections seem to do pretty much the same apart from the difference between locCompA
and locCompB
which according to the doc comments are the start of the bone vs the connecting bone.
Do you think it would make sense to extract this into a separate function and call it with the respective locComp
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would require passing a lot of parameters. Will be overhauled by @pollend soon-ish anyway, at which point we should ensure a comprehensible structure of the logic. Accepting it as is for now.
I fixed two things, I corrected the debug display for the skeleton render and made sure to make scale and translate as replicated so this should fix the offset animated meshes in MetalRenegades.
I think we need to re-think how this works at the moment because there is a lot of back and forth between SkeletonRender <--> OpenGLSkeletalMesh <--> SkeletalMeshData. The coupling is very tight and a lot of state information is funneled between these three classes. I'm finding it hard to see how this fits together with how this is organized at the moment.