ObjReader Community

WIP => WIP => Topic started by: Patrice Terrier on June 06, 2018, 02:57:31 pm

Title: Individual Mesh Rotation
Post by: Patrice Terrier on June 06, 2018, 02:57:31 pm
Mike

I have started to work on the individual mesh rotation, using a new meta #rotate rStep, rX, rY, rZ that is based on
glRotatef(rStep, rX, rY, rZ) to perform the rotation
at the end of struct MobjMat, i have added this new parameter
float rotate[4];  // PAT: 06-05-2018 dito glRotatef(rSpeed, rX, rY, rZ);

However in order to perform a correct rotation i need to use
glTranslatef(-x, -y, -z) // Move to center
glRotatef(rotation_angle, 0.0f, 0.0f, axisToUse)
glTranslate(x, y, z) // Restore the initial location

I was thinking to use something similar to what you have done in billboard and calcMeshBounds to retrieve the correct
x, y, z mesh bounds to apply the translation.

Do you think that it is the best way to do it ?

Added:
// Dirty code to test the rotation
if (pMaterial->rotate[0] != 0.0f) {
    userotate += 5.0;
    if (userotate > 360.0f) { userotate = userotate - 360.0f; }
    float rx = 1.0f; if (pMesh->centerPoint[0] > 0.0f) { rx = -1.0f; }
    float ry = 1.0f; if (pMesh->centerPoint[1] > 0.0f) { ry = -1.0f; }
    float rz = 1.0f; if (pMesh->centerPoint[2] > 0.0f) { rz = -1.0f; }
    glTranslatef(pMesh->centerPoint[0] * rx, pMesh->centerPoint[1] * ry, pMesh->centerPoint[2] * rz);
    glRotatef(userotate, 0.0f, 0.0f, 1.0f);
    rx = -rx; ry = -ry; rz = -rz;
    glTranslatef(pMesh->centerPoint[0] * rx, pMesh->centerPoint[1] * ry, pMesh->centerPoint[2] * rz);
}

To see the result look at the attached video
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 06, 2018, 09:22:22 pm
(http://www.i2symbol.com/pictures/emojis/a/f/f/2/aff22723ab391b694c9bcae65ee2da76_384.png)

Quote
in order to perform a correct rotation i need to use...

Exactly! The OpenGL primitive glRotate() works for an individual mesh within a model correctly only when this particular mesh's center point is placed at [0,0,0] in the world coordinate system. This is achieved by translating the model to [-meshCenterX, -meshCenterY, -meshCenterZ] (== world center [0,0,0]), performing the desired rotation, and then putting the model back in its original position by translating it to [meshCenterX, meshCenterY, meshCenterZ].

Quote
Do you think that it is the best way to do it ?

This is the only way to do it.

Quote
// Dirty code to test the rotation

Why not simply

    //float rx = pMesh->centerPoint[0] > 0.0f ? 1.0 : -1.0f;
    //float ry = pMesh->centerPoint[1] > 0.0f ? 1.0 : -1.0f;
    //float rz = pMesh->centerPoint[2] > 0.0f ? 1.0 : -1.0f;
    glTranslatef(-pMesh->centerPoint[0], -pMesh->centerPoint[1], -pMesh->centerPoint[2]);
    glRotatef(userotate, 0.0f, 0.0f, 1.0f);
    //rx = -rx; ry = -ry; rz = -rz;
    glTranslatef(pMesh->centerPoint[0], pMesh->centerPoint[1], pMesh->centerPoint[2]);


?
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 07, 2018, 08:51:25 am
Quote
Why not simply
Of course that was the first thing i played with, but that didn't work well.
(i can send you a WIP if you want to try it in context)

Next step would be to add audio support, to hear the engine, with the volume matching the zooming factor  ;D
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 07, 2018, 09:37:52 am
... that didn't work well.

 :o :o :o

Quote
(i can send you a WIP if you want to try it in context)

Yes, please do.

Quote
Next step would be to add audio support, to hear the engine, with the volume matching the zooming factor  ;D

(https://emojipedia-us.s3.amazonaws.com/thumbs/120/emoji-one/104/thumbs-up-sign_1f44d.png)

Yes, real time animation is the most exquisite effect in the entire 3D virtuality. :)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 07, 2018, 11:00:17 am
Here is another video, showing the Tron engine animated.

The problem is that the mesh must be correctly aligned to match the rotation axis, but the extra work is worth the result.

I shall prepare a WIP + object…
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 07, 2018, 11:07:01 am
(http://www.i2symbol.com/pictures/emojis/a/f/f/2/aff22723ab391b694c9bcae65ee2da76_384.png)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 07, 2018, 01:22:43 pm
tron_ani.zip (to put into your Tron folder)
prop.zip (to put into your Corsair folder)
mobj.zip (mobj.h search for "Test rotation" into Mobj_DrawUsingFixedFuncPipeline)

How to use it
in the View menu select:
1 - Show FPS counter (for now, you have to check it for the purpose of animation, until full code completion)
2 - Use fixed pipeline (not done yet into Mobj_DrawUsingProgrammablePipeline)

Of course you can use also Y rotation.

Material example:

newmtl propspinn
#rotate 5.0 0.0 0.0 1.0
Ka 0.1 0.1 0.1
Kd 0.75 0.75 0.75
Ks 0.75 0.75 0.75
Ns 10
d 0.25
illum 1
map_Kd prop.png


Airplane sound Library
https://www.freesoundeffects.com/free-sounds/airplane-10004/20/tot_sold/20/2/

Note: to invert the propeller rotation the first speed parameter must be negative.
#rotate -5.0 0.0 0.0 1.0
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 07, 2018, 03:51:44 pm
Thank you Patrice!

I'm expecting my friends to come to my place any minute now so I'll come back with my feedback to you tomorrow. :)
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 07, 2018, 05:34:40 pm
Of course that was the first thing i played with, but that didn't work well.

Patrice,

It should have worked! :-\ It must be the same glitch (probably in MS VC) I was observing when working out the billboard routine... Both implementations should essentially resolve to the exact same simple sign bit reversal but the simpler code fails.  :o >:(
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 07, 2018, 07:17:45 pm
Here is a patch, that performs rotation detection, to fire the animation accordingly.

Search for gP.nRotation.

rotation now works in both PPL and FFP mode.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 08, 2018, 05:16:55 am
Thank you Patrice, everything seems to be working fine for me.

Still I see it worthwhile to be able to stop all animation completely in order to have a chance to explore the model with all its meshes in complete stasis. On default, the animation effects may be on if available in the mat file but there should also be a checkbox or button to switch them off and inspect the model in its raw state if needed. If it's a checkbox, I think it can fit in logically very well somewhere near the existing model rotation checkbox. A couple of sliders could also be welcome to adjust the rotation and animation speeds in real time. If we sacrifice your magnificent alpha threshold control's rotating knob and segmented display, we would probably be able to squeeze in all the three sliders and the animation checkbox in the right-side panel space thus freed.

Regarding Tron, I think it can be more interesting and spectacular to have the bike bump-mapped tires, rather than the engine insides, rotating when animated. (will have to watch the movie once again though to verify if the original engine had any moving parts...)
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 08, 2018, 06:13:34 am
Patrice,

I want to know exactly how you cooked up this trick (what was your exact train of thought):

    float rx = pMesh->centerPoint[0] > 0.0f ? -1.0f : 1.0f;
    float ry = pMesh->centerPoint[1] > 0.0f ? -1.0f : 1.0f;
    float rz = pMesh->centerPoint[2] > 0.0f ? -1.0f : 1.0f;
    glTranslatef(pMesh->centerPoint[0] * rx, pMesh->centerPoint[1] * ry, pMesh->centerPoint[2] * rz);
    ........
    rx = -rx; ry = -ry; rz = -rz;
    glTranslatef(pMesh->centerPoint[0] * rx, pMesh->centerPoint[1] * ry, pMesh->centerPoint[2] * rz);


or if the trick wasn't yours, where did you pry it?
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 08, 2018, 10:31:50 am
Quote
everything seems to be working fine for me.
I wanted to do it for long ;)

Quote
I want to know exactly how you cooked up this trick
That was a pragmatic decision of my own.
Because negate failed, i took the decision to switch to brute force to let it work the way it should.
Perhaps the problem is because we are using pointers (pMesh->centerpoint), however i am not a C++ expert and i have no idea of the code optimization performed by the compiler.

Quote
Animation On/Off
Of course this is mandatory, and i have to think to the most ergonomic location…

Quote
Tron
I have reworked the rotating mesh engine altogether with a new texture, because the original was not perfectly aligned along the z axis. I am also using a slighty bigger engine

Things are much more complex when the mesh is using an angle along any of the x,y,z.
So far i am only dealing with perfect x,y,z alignments ...
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 08, 2018, 07:56:21 pm
We must compute the exact individual mesh centerpoint, based on the rotation axis being used.
We can't use the centerpoint computed by CalcMeshBounds.

Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 08, 2018, 08:54:03 pm
I have added the new "Mesh animation" check box.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 08, 2018, 09:07:05 pm
Quote
I wanted to do it for long ;)

I'm very glad you finally did it — yourself. It means there are two OpenGL developers in this project — you and me, rather than me alone. :)

Quote
That was a pragmatic decision of my own.

I can hardly believe this. I lost my peace of mind, my rest, and my sleep. I do not know how I can carry on programming in C++. From my point of view as a compiler developer, this is an obvious compiler or probably C++ FPU math specification bug that must have been revealed years, if not decades, ago.

Is this the first time in your C++ practice that you encounter this particular kind of bug and use this very tactics to correct it?

Quote
We must compute the exact individual mesh centerpoint, based on the rotation axis being used.
We can't use the centerpoint computed by CalcMeshBounds.

No, this is not so. It is your code that yields illogical results, not mine — and I can prove it. Recalculation of AABB or sphere center point on the fly is ridiculous and never done. The tactics used in calcMeshBounds() is industry standard and may not be questioned. Please read further below.

Quote
Perhaps the problem is because we are using pointers ... code optimization performed by the compiler

No, it works in the exact same way with all project-wide and file-specific optimizations switched off. Moreover, it works the same also in Intel C++ compiler. (yes Patrice, the ObjReader solution can be recompiled as-is in the most recent Intel System Studio (https://software.intel.com/en-us/c-compilers/iss))

Quote
Because negate failed...

No, it does not fail. It does exactly what it is supposed to do.

Use zTrace() to check the values of pMesh->centerPoint[0] and rx in the Corsair model. (Y also fails while Z is correct, which results in visible eccentricity of the propeller)

pMesh->centerPoint[0] is -0.000127, and -pMesh->centerPoint[0] yields 0.000127 as expected.

rx = pMesh->centerPoint[0] > 0.0f ? -1.0f : 1.0f yields rx = 1.000000 and leads to non-reversal of the pMesh->centerPoint[0] sign, which is logically, trigonometrically, and spatially incorrect. In order to work as it "works", there must be a matching mirror bug somewhere that writes the center point X value into pMesh->centerPoint[0] selectively with a wrong sign.

Or such a situation may also occur if the [0,0,0] and pMesh->centerPoint[0,1,2] are in fact given in different coordinate systems, and pMesh->centerPoint should first be e.g. multiplied by the inverse modelview matrix prior to sign reversal, whereby your > ? : and * +/- 1.0f actually emulates such matrix multiplication.

This is why I was, and still am, asking you: where did you get that hack from? One must be very, very smart indeed to take such a "pragmatic decision" by intuition having very little practical OpenGL background...
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 08, 2018, 09:23:45 pm
Quote
This is why I was, and still am, asking you: where did you get that hack from?
I already told you…

Would you like to have the latest WIP, or do you prefer to wait until i have fixed the mesh rotation offset. ?

Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 08, 2018, 09:34:48 pm
I already told you…

Which means you are very, very smart indeed, my friend. :)

Quote
Would you like to have the latest WIP, or do you prefer to wait until i have fixed the mesh rotation offset. ?

You probably won't need to fix anything if I find the correct solution to the problem. I suspect that our model center point might also have certain eccentricity with respect to the ideal [0,0,0] in the world coordinates. If this is the case, then mesh coordinate negation might be imprecise, and the exact amounts of negative translation should in fact be the difference between the mesh and model center points rather than the inverse of mesh center point alone...

This may be a side effect of the model being scaled up or down when we're trying to fit it into our viewport.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 09, 2018, 09:10:36 am
I am sorry Patrice, it was my own fault. I missed one && gP.nRotation flag in the PPL renderer. :-[

Please remove the donerotate flag because it is unnecessary.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 09, 2018, 05:26:49 pm
Not perfect yet (i couldn't mix several rotate axis altogether), however it is much better!

Test.mtl
Code: [Select]
#Light frontAmbient 0 0 0
#Light frontDiffuse 165 165 165
#Light frontSpecular 127 127 121

#Light leftAmbient 0 0 0
#Light leftDiffuse 127 127 121
#Light leftSpecular 127 127 121

#Light rightAmbient 0 0 0
#Light rightDiffuse 127 127 121
#Light rightSpecular 127 127 121

#wallpaper @background.jpg

newmtl sphere
#rotate 5.0 0.0 1.0 0.0
Ka 1 1 1
Kd 0.80000001192093 0.80000001192093 0.80000001192093
map_Kd engine.png
Ks 1 1 1
Ns 50
illum 7

newmtl tron
#billboard
ka 0.0 0.0 0.0
kd 0.75 0.75 0.75
ks 0.75 0.75 0.75
ke 1 1 1
ns 52
illum 2
d 0.999
map_kd logo.png

newmtl hex
ka 0.75 0.75 0.75
kd 0.75 0.75 0.75
ks 0.75 0.75 0.75
ke 0.75 0.75 0.75
ns 2
d 0.25
illum 2
map_kd hex.png

newmtl logol
ka 0.15 0.15 0.15
kd 0.75 0.75 0.75
ks 0.75 0.75 0.75
ke 1 1 1
ns 52
d 0.99
illum 2
map_kd logol.png

newmtl logor
ka 0.15 0.15 0.15
kd 0.75 0.75 0.75
ks 0.75 0.75 0.75
ke 1 1 1
ns 52
d 0.99
illum 2
map_kd logor.png

newmtl lens
ka 0.15 0.15 0.15
kd 0.75 0.75 0.75
ks 0.75 0.75 0.75
ke 1 1 1
ns 52
d 1.0
illum 2
map_kd lens.png

newmtl bordure
ka 2 2.8 3
kd 0 0.8 0.9
ks 2 2.8 3
ke 0 0.8 0.9
ns 52
illum 3
refl steel3.png

newmtl spot
ka 1 1 1
kd 1 1 1
ks 1 1 1
ke 0.5 0.5 0.5
map_kd spot.png
ns 2
illum 2

newmtl eye
ka 0.15 0.15 0.15
kd 0.75 0.75 0.75
ks 0.75 0.8 0.9
ke 0.5 0.8 0.9
map_kd eye.png
ns 2
illum 2

newmtl head
ka 0.15 0.15 0.15
kd 0.75 0.75 0.75
ks 0.75 0.8 0.9
ke 0.5 0.8 0.9
map_kd head.png
ns 2
illum 2

newmtl dash
ka 0.15 0.15 0.15
kd 0.75 0.75 0.75
ks 0.75 0.75 0.75
ke 0.75 0.75 0.75
map_kd dash.png
ns 2
illum 2

newmtl queue
ka 2 2.8 2.9
kd 0 0.8 0.9
ks 2 2.8 2.9
ke 0 0.8 0.9
map_kd tail.png
ns 2
illum 2

newmtl flares
#alphatocoverage
ka 0 0 0
kd 0 0.8 0.9
ks 0 0 0
ke 1 1 1
map_kd flares.png
ns 2
d 0.985
illum 2

newmtl glow
ka 0 0.08 0.9
kd 0 0.8 0.9
ke 0 0.8 0.9
ks 0 0.8 0.9
ns 512
illum 3
refl glow.jpg

newmtl moyeu
ka 2 2 2
kd 0.75 0.75 0.75
ks 2 2 3
ns 512
illum 3
refl steel3.png

newmtl phare
kd 0.15 0.15 0.15
ks 1 1 1
ke 0.21176470816135 0.54117649793625 0.89803922176361
ns 512
illum 3
refl color.png

newmtl visiere
kd 0 0 0
ks 0 0 0
ke 0.35 0.4 0.5
ns 2
d 0.6
illum 3
refl color.png

newmtl alu
ka 0.117 0.117 0.117
kd 1.0 1.0 1.0
ks 1.0 1.0 1.0
ns 912
d 1.0
illum 3
refl black.png

newmtl bike
ka 0.65 0.65 0.75
kd 0.0 0.35 0.75
ks 0.75 0.75 0.75
ns 512
illum 3
refl black.png

newmtl tire
kd 0 0 0
ks 0.15 0.15 0.15
ns 512
illum 3
refl black.png

newmtl engine
#rotate 7.5 0.0 0.0 1.0
ka 0 0 0
kd 0 0.4 0.45
ks 0 0 0
ke 0 0.8 0.9
illum 2
ns 2
map_kd engine.png
map_bump engine_bump.png

newmtl helmet
ka 0 0 0
kd 0.25 0.25 0.25
ks 1 1 1
ns 512
illum 3
refl black.png

newmtl glass
ka 0.15 0.15 0.9
kd 0.0 0.8 0.9
ks 2 3 3.5
ns 512
d 0.5
illum 3
refl steel6.png

newmtl stick
ka 0 0 0
kd 0.5 0.5 0.5
ks 0.75 0.75 0.75
illum 2
ns 52
map_kd stick_kd.png
map_bump stick_bump.png
map_ks stick_ks.png

newmtl body
ka 0 0 0
kd 0.35 0.35 0.35
ks 2 2 2
map_kd body_kd.png
map_ks body_ks.png
map_bump body_bump.png
illum 2
ns 512
refl black.png

newmtl body_glow
#alphatocoverage
ka 0 0.08 0.9
kd 0 0.8 0.9
ke 0 0.8 0.9
#ks 0 0.8 0.9
illum 2
ns 10
d 0.99
map_kd body_emss.png

newmtl bande
ka 0 0.08 0.9
kd 0 0.8 0.9
ke 0 0.8 0.9
ks 0 0.8 0.9
illum 2
ns 10

And here is the code being used to produce the attached video
Code: [Select]
            if ((pMaterial->rotate[0] != 0.0f) && gP.nRotation) {
                glPushMatrix();
                pMesh->pMaterial->rotangle += pMesh->pMaterial->rotate[0];
                float rx = pMesh->centerPoint[0]; if (pMesh->pMaterial->rotate[1]) { rx = -rx; }
                float ry = pMesh->centerPoint[1]; if (pMesh->pMaterial->rotate[2]) { ry = -ry; }
                float rz = pMesh->centerPoint[2]; if (pMesh->pMaterial->rotate[3]) { rz = -rz; }
                glTranslatef(rx, ry, rz);
                glRotatef(pMesh->pMaterial->rotangle, pMesh->pMaterial->rotate[1], pMesh->pMaterial->rotate[2], pMesh->pMaterial->rotate[3]);
                glTranslatef(-rx, -ry, -rz);    //glTranslatef(pMesh->centerPoint[0] * rx, pMesh->centerPoint[1] * ry, pMesh->centerPoint[2] * rz);
            }


Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 09, 2018, 06:37:01 pm
(http://movilarena.com/wp-content/uploads/Stickers-facebook.png)(http://s3.amazonaws.com/pix.iemoji.com/images/emoji/apple/ios-11/256/thumbs-up.png)


What about inclined axes of rotation though? ;)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 09, 2018, 06:59:04 pm
Quote
What about inclined axes of rotation though?
This is the reason why i wrote not perefect  ???

However it solves already most of my needs.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 09, 2018, 07:02:11 pm
OK OK I ain't criticizing. :D

BTW you may want to reduce pMesh->pMaterial->... to pMaterial->... in your rotation code because it is cached locally in both procedures. This saves a lot of indirection stuff that would otherwise resolve to quite a number of extra machine code instructions. As tested, the result is reliably the same. :)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 09, 2018, 07:15:24 pm
Quote
you may want to reduce pMesh->pMaterial->... to pMaterial->...
Done, thank you.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 09, 2018, 07:23:25 pm
That deserve a new version #2.52  :)
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 09, 2018, 07:26:00 pm
Yes.

And I'm also waiting for a family of spaceships with their antennas gloriously a-spinnin'. :D
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 09, 2018, 07:28:26 pm
And a 3D Rubik's Cube game. ;D
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 09, 2018, 07:33:02 pm
Helios, would be a good candidate.

But that means much mesh editing  :-\
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 09, 2018, 07:41:26 pm
But that means much mesh editing  :-\

... undoing your previous mesh/material mergers. :)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 10, 2018, 12:11:28 pm
So far i can rotate correctly only individual meshes, not a group of meshes that sould act as a single one (because they should use the same center point).

See the attached video.

That means we should compute an extra centerpoint for a group of meshes acting as a single entity.
And find an easy meta syntax to use in the mtl file.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 10, 2018, 06:18:51 pm
Thanks Patrice,

I got what you mean.

Let me remind you that the official Wavefront Object format allows us to define three kinds of groups of model components. So far we have ignored them but we can start using some or all of them, if needed. I am not sure if your Cinema 4D .OBJ export plugin can export them but there are at least two other professional 3D editors that support them in full: Autodesk 3ds Max and Maya. And I think AccuTrans can also do this in full or in part even though its usage is very unintuitive and awkward as almost everything else that's been developed in an indie style.

1. Material (mesh) groups:

A group begins at the g somename declaration and includes all the materials (meshes) that follow the initial declaration until the next g anothername declaration or EOF are found in the OBJ file. The original specification doesn't provide for any group parameters but we can augment it with our existing #rotate metadirective written on the line that immediately follows the group declaration in the OBJ file.

If #rotate follows the declaration then not only the mesh centerPoints but also the group's cumulative centerPoint will be calculated and written into each mesh of the group in the MobjMesh rotpoint[x,y,z] arrays.

If a non-grouped mesh should be rotated around its centerPoint as we do our rotations now, then its MobjMesh rotpoint[x,y,z] will duplicate its MobjMat centerPoint[x,y,z] values.

2. Polygon smoothing groups:

We're mostly dealing with models that have their normals precalculated in the editor. If there are no precalculated normals in the model, we're using our own procedure to generate them.

But our procedure is simplistic: it averages normals across the entire model, and as a result we cannot generate so exact and nice looking normals as C4D, 3ds Max or AccuTrans can. They average the normals of polies that fall into their respective smoothing groups only.

A smoothing group begins at the s someindex declaration and includes all the polies that follow the initial declaration until the next s anotherindex declaration or EOF are found in the OBJ file. Indices are usually between 0 and 31, which is sufficient even in very complex models to produce absolutely flat or nicely smoothed normals preserving sharp edges and creases as necessary. Smoothing groups have no default correlation with individual materials (meshes) but may be narrowed down to them if they follow the pattern of material (mesh) declarations.

3. Objects:

An object begins at the o somename declaration and includes everything that follows the initial declaration until the next o anothername declaration or EOF are found in the OBJ file.

The purpose of objects is not fully clear to me but I suspect that they describe multiple individual models placed in a common .OBJ file that in this case acts as the equivalent to a 3D scene.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 10, 2018, 06:51:47 pm
Mike

C4d is dealing with wavefront group, look at any of my .obj model and you will see that the "g group" is already being used for each individual mesh.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 10, 2018, 07:02:43 pm
There must be some C4D model component parameter that the exporter will interpret (if it is smart enough, of course) as an OBJ group, which is in fact a superset of several materials (or "meshes" in C4D parlance), rather than a simple, and thus useless, alias to an ordinary OBJ material (or "mesh" in C4D parlance).

In the Wavefront Object specification, the notions of groups and materials have no correlation and are interpreted as I have described above. A C4D "group" is a mesh, a cluster of model polies, while an OBJ "group" is a cluster of model materials. C4D is built around geometry while OBJ is built around materials.

You will have to edit your OBJ files manually in your Notepad if the C4D OBJ exporter isn't able to adapt its output to OBJ notions and vocabulary rather than its own (wild) interpretation of the same.

P.S. If we proceed as I have described then we will be able to ensure complex animations where individual meshes can rotate around their own center points while being able to concurrently rotate as a group around the group's common center of rotation. 8)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 10, 2018, 07:34:09 pm
I did further investigations, and it seems obvious to me that we have to handle things from the mtl file only, leaving the .obj file untouched.
We could use a new meta #group group_identifier for all meshes belonging to the same group.
And compute the correct group center…

I have attached a project of what we could get...
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 10, 2018, 07:52:22 pm
We're drifting farther and farther away from the original Alias Wavefront Object format. We're about to duplicate in our deviant MAT files what's already there in the OBJ file specification -- only because the C4D motherphuckers were not meticulous enough (carelessly or on purpose) to follow the OBJ specs thoroughly.

Another point is you don't want to walk an extra mile and edit the OBJ files manually as you're editing their MAT files. This I can understand too.

But still... ???
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 10, 2018, 08:15:19 pm
I have attached a project of what we could get...

Or we could have your "time machine" all spinning and glowing pretty much like in the original movie...  :D

OK, do as you like with #group group_identifier but let me test it before you take the final decision to release the next ObjReader build.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 10, 2018, 08:24:14 pm
Quote
OK, do as you like with #group group_identifier but let me test it before you take the final decision to release the next ObjReader build.

No decision taken yet, this is why your feedback is important to me my friend.

However i would say that #rotate is already not a valid Wavefront option, and as far as i know there is no rotation feature in it either.

...
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 10, 2018, 09:25:50 pm
Considering that our current "rotation" doesn't work correctly anyway, please proceed as follows:I will then add a calcGroupCenter() routine that will calc the "group" cumulative center and store it in the individual rotCenter[] arrays of "group" meshes.

Hopefully this is going to work for both the current abnormal "rotation" and future fixups with minimum major code re-writes.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 11, 2018, 10:20:56 am
Mike

Here is the new mobj.h, with the changes you asked for.
Search for the comments: PAT: 06-11-2018

I checked it with Test.obj and it worked fine with the current mtl file.

About the new pMaterial usegroup it must be a unique integer number
all meshes with the same usegroup number will belong to the same group.
My choice is for number, rather than verbose name, for ease of comparison, and smaller code.

Note: The post processing version will be also non-wavefront standard.
But the important thing is that we can keep reading/render a standard .obj file.

However if ever we go for our own binary format, we will use a new .orb file extension…

Added:
Very strange, i just checked using the new meta #group 1, and without doing anything else, i got this result (see the video).
 :o   ::)  ???
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 11, 2018, 03:00:47 pm
Here is the result once the rotating group is combined with the whole model…

That shouldn't be too hard to fix (just using plain negate without the extra trick) ;)
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 11, 2018, 03:02:18 pm
Thank you, Patrice.

Quote
Very strange, i just checked using the new meta #group 1, and without doing anything else, i got this result (see the video).

Sorry but that's too little info for me. I haven't got the model you're showing in the movie and that's why I can't guess what's wrong with what I'm seeing. ;)
_________________________________

Anyway, I've got rotation working correctly using trig and matrix math.

In mobj.h immediately below the existing void billBoard(...) function, copy the following three new functions:
Code: [Select]
__forceinline float dotVec3(float v1[], float v2[]) {
    return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}

__forceinline void mtxTranslate(float* m, float x, float y, float z) // Translate existing matrix by x, y, and z
{
    m[12] += m[0] * x + m[4] * y + m[8]  * z;
    m[13] += m[1] * x + m[5] * y + m[9]  * z;
    m[14] += m[2] * x + m[6] * y + m[10] * z;
}

void mtxRotate(float* m, float x, float y, float z, float deg) // Rotate existing matrix by angle in degrees around x, or y, or z
{
#define d2r .0174533f
    float rad = deg * d2r, s = sin(rad), c = cos(rad), t = 1 - c;
    float v1[] = { x * x * t + c,     x * y * t + z * s, x * z * t - y * s };
    float v2[] = { y * x * t - z * s, y * y * t + c,     y * z * t + x * s };
    float v3[] = { z * x * t + y * s, z * y * t - x * s, z * z * t + c     };

    for (int i = 0; i < 3; i++) {
        float v4[] = { m[0 + i], m[4 + i], m[8 + i] };
        m[0 + i] = dotVec3(v4, v1);
        m[4 + i] = dotVec3(v4, v2);
        m[8 + i] = dotVec3(v4, v3);
    }
#undef d2r
}

and, instead of yours, use the following rotation code in both Mobj_DrawUsingProgrammablePipeline() and Mobj_DrawUsingFixedFuncPipeline():
Code: [Select]
........
            // Test rotation // MLL 06-11-2018:
            if ((pMaterial->rotate[0] != 0.0f) && gP.nRotation) {
                float m[16];
                glPushMatrix();
                pMaterial->rotangle += pMaterial->rotate[0];
                glGetFloatv(GL_MODELVIEW_MATRIX, m);
                mtxTranslate(m, pMesh->centerPoint[0], pMesh->centerPoint[1], pMesh->centerPoint[2]);
                if (pMaterial->rotate[1]) mtxRotate(m, pMaterial->rotate[1], 0, 0, pMaterial->rotangle);
                if (pMaterial->rotate[2]) mtxRotate(m, 0, pMaterial->rotate[2], 0, pMaterial->rotangle);
                if (pMaterial->rotate[3]) mtxRotate(m, 0, 0, pMaterial->rotate[3], pMaterial->rotangle);
                mtxTranslate(m, -pMesh->centerPoint[0], -pMesh->centerPoint[1], -pMesh->centerPoint[2]);
                glLoadMatrixf(m);
            }
........

The code looks somewhat heavy but alas, 3D rotations have never been easy.

Put more spheres in the other quadrants and test if they also behave correctly. Note that rotation preserves the mesh dimensions correctly only when the pMaterial->rotate[1,2,3] values are strictly 1.0f or 0.0f, e.g. #rotate 5, 1, 0, 1. If the array values are other than those two, the mesh exhibits strange scaling effects. But I think you may find them amusing and probably useful too in some of your future implementations. :D
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 11, 2018, 03:17:15 pm
Test with the existing Tron/test in the meantime.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 11, 2018, 04:00:35 pm
Here is the Helios2 project (put it into the same folder than the original).

Note: Helios2 doesn't work with the changes you have done.
However Tron test, keep working.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 11, 2018, 04:15:41 pm
Patrice,

Please test my code (as it was before your #group changes) with extra balls in the Tron model, and if all the balls rotate correctly, then all models and #group should be made to work with it instead of your old rotation code which was imperfect and spatially incorrect.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 11, 2018, 04:24:12 pm
Patrice,

I don't agree with your #group notation in the MTL file. It is not in the spirit of Wavefront Object format.

I need to zzzZZZ a little but later I'll check your fixes in mobj.h and present my view.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 11, 2018, 09:23:45 pm
My dear friend, :)

Thank you very much for the balls. Before getting offended for your old rotation code !!! which was imperfect and spatially incorrect !!! try running the balls test in your code against complex rotations as in the test.mtl file from the attachment below. Your glRotate() primitives cannot produce such rotations in either one or three calls in a row.

Now recompile ObjReader with my mobj.h from the attached zip and enjoy ball rotation as is coded in test.mtl.

I'm going to study your #group mods tonight.

Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 11, 2018, 10:12:54 pm
your code works great with test.obj and complex rotation.

Next step would be to have it working with the Helios2 group, but no rush there and take a good sleep first to save your neurones.
I am going to bed myself, because today i started to mown my lawn, and i have to get up early tomorrow to finish the second part of it.  :)
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 11, 2018, 11:10:52 pm
Yes Patrice,

There's a Russian proverb that says it's better to eat too much than to sleep too little. ;D
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 12, 2018, 07:31:51 pm
No Patrice,

This isn't a correct test case for the mesh center calc algo that we're using. The mesh must be mirror symmetrical to have its center of rotation coincide with our bounding sphere's center. This is a side effect requirement resulting from the fact that there may be several bounding spheres with different radii depending on the original spatial orientation of a non-symmetrical object.

A pentagon isn't mirror symmetrical for our algo while a hexagon is, and a heptagon isn't while an octagon is.

Look into my comments inside the calcMeshBounds() code:

        // MLL 02-09-2018: meshRadius is in fact AABB's half-diagonal,
        // i.e. half-distance between AABB's rMax and rMin point vectors.
        // This isn't the tightest possible mesh bounding sphere though...

where AABB stands for axis-aligned bounding box.

In other words, abs(rMax) != abs(rMin) for a non-mirror symmetrical mesh. Our bounding sphere center is closer to the topmost bolt of the mesh pentagon than the mesh's center of rotational symmetry because the two bottom-most bolts aren't protruding exactly as far downwards as the topmost one is protruding upwards.

If you want to rotate the car wheels then make sure you use 6-bolt meshes to fix the wheels to the wheel spindles, or merge the bolt and wheel materials together. :)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 12, 2018, 07:37:20 pm
Quote
If you want to rotate the car wheels then make sure you use 6-bolt meshes to fix the wheels to the wheel spindles, or merge the bolt and wheel materials together.
Ok, i just took them from an existing model…  8)
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 12, 2018, 07:45:58 pm
Anyway, I can try to compensate such eccentricities when calculating the mesh and group centers of rotation, in fact, recalculate the rotCenter[] arrays more precisely rather than copying the centerPoint[] values to them.

Don't rework your models yet. We'll see if I can succeed. I'll be using this test model to verify my attempts. :)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 12, 2018, 08:34:27 pm
I did find a solution for that specific one, however it couldn't be used for the rotating group of the Helios2.obj project.

The solution for the rim, is to mix the 5 bolts altogether with a hidden circle (see the screen shot)

And the most complex case would be to be able to rotate along the vertical axe to turn the front Wheel  ::)
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 12, 2018, 10:41:03 pm
Patrice,

I asked you not to fiddle with the models, didn't I? ;)

Your solution is nice but kinda brute force.

The point we're looking for is in fact a centroid (https://en.wikipedia.org/wiki/Centroid): c = [average(x), average(y), average(z)], whereby average() is the sum of respective vertex coordinates divided by the number of vertices in a mesh. Generally, the centroid of an asymmetrical 3D mesh doesn't coincide with the center of its AABB. But its calculus fits very nicely in our existing calcMeshBounds(). So, we can fill in each mesh's rotCenter[] array very easily regardless of whether it's going to actually rotate or not -- just in case, so to speak. :D

Your asymmetric bolts are now rotating very nicely together, and concentrically with, the car wheels in my ObjReader. 8)
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 12, 2018, 11:02:56 pm
Good work, thank you.

Have you been able to check it also with the Helios2.obj rotating group section ?
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 12, 2018, 11:16:08 pm
I'm still polishing the #group syntax. :)

The rotation of Helios2 meshes is perfectly concentric. Some meshes are rotating faster than the others.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 13, 2018, 09:22:29 am
Quote
Some meshes are rotating faster than the others.
I have checked the material file, they all use the same speed of 0.125.

Thus it must be related to the new rotation algo, i have attached the rot.obj model that is composed only from the Helios2 rotating group for test purpose.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 13, 2018, 10:52:04 am
And using the amazing c4d cogwheel spline vertex and manipulation tool.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 13, 2018, 12:23:46 pm
rot.zip   gears.zip

Thanks a lot, the models are excellent! :)

Quote
I have checked the material file, they all use the same speed of 0.125.

So did I and yes they do.

Quote
Thus it must be related to the new rotation algo ...

Hardly. I think the glitch is related to either the #rotate parser or improper modelview matrix push/pop. I've also noticed another glitch: when I uncheck the visibility of some material (don't remember which one exactly ) in the listview control, rot_Storage_Colour_Light starts to spin twice slower than usual.

And using the amazing c4d cogwheel spline vertex and manipulation tool.

The gears are awesome! :D
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 13, 2018, 01:14:55 pm
Quote
I think the glitch is related to either the #rotate parser or improper modelview matrix push/pop.
I don't know if this could help or not, however the rot group alone was working with the older rotating code, it failed only when mixed with the other non-rotating meshes.

Combined rotating orientation, works only with spherical/cubic objects, and produces bad looking transformations for any other shapes.

In my StarGate64 project, i am using several embedded push/pop matrix to render correctly each of the monolith rotation, pulsating on the music tempo (each one rotating along its own axis).
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 13, 2018, 04:12:34 pm
Quote
... works only with spherical/cubic objects, and produces bad looking transformations for any other shapes.

I am afraid this isn't so. Try and rotate your test.obj tires on two or three axes simultaneously -- there are no "bad looking transformations" in sight, and these meshes aren't spheroid or cuboid at all. Moreover, even your asymmetrical bolt meshes spin quite reliably around their centroids.

This kind of rotation was initiated by you, Patrice, not me. This is rotation around the mesh "center of mass", or centroid, and it is "axial" and more or less pleasing to the eye only when the mesh is generally orientated along one of the model's orthogonal axes.
_____________________________________

There is another kind of rotation -- around an arbitrarily inclined axis (-es), which requires a different type of matrix calc. But I think you still have a ton of meshes in the existing models that can be animated as-is to make them more attractive to the user. With time, when the #group syntax works and there are no more glitches, we could add axis rotation too, enriching our #rotate options accordingly.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 13, 2018, 05:54:13 pm
Code: [Select]
there are no "bad looking transformations" in sight, and these meshes aren't spheroid or cuboid at all.
I shall wait for your new mobj.h, because the one i am using doesn't preserve the correct axis alignment as you can see on the attached screen shot.

Test.mtl being used
Code: [Select]
#wallpaper ambiant.png

newmtl tire_4
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.18823529779911 0.18823529779911 0.18823529779911
illum 7

newmtl tire_3
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.18823529779911 0.18823529779911 0.18823529779911
illum 7

newmtl tire_2
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.18823529779911 0.18823529779911 0.18823529779911
illum 7

newmtl tire_1
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.18823529779911 0.18823529779911 0.18823529779911
illum 7

newmtl bolt_4
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.75 0.0 0.0
Ks 1 0 0
Ns 50
illum 7

newmtl bolt_3
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.75 0.0 0.0
Ks 1 0 0
Ns 50
illum 7

newmtl bolt_2
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.75 0.0 0.0
Ks 1 0 0
Ns 50
illum 7

newmtl bolt_1
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.75 0.0 0.0
Ks 1 0 0
Ns 50
illum 7

newmtl rim_4
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.86274510622025 0.86274510622025 0.86274510622025
Ks 1 1 1
Ns 50
illum 7

newmtl rim_3
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.86274510622025 0.86274510622025 0.86274510622025
Ks 1 1 1
Ns 50
illum 7

newmtl rim_2
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.86274510622025 0.86274510622025 0.86274510622025
Ks 1 1 1
Ns 50
illum 7

newmtl rim_1
#rotate 1.0 1.0 0.0 0.5
Ka 1 1 1
Kd 0.86274510622025 0.86274510622025 0.86274510622025
Ks 1 1 1
Ns 50
illum 7

Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 13, 2018, 07:47:10 pm
Test.mtl being used

Patrice,

You aren't using the values correctly. You are supposed to use +-1/0 or +-1.f/0.f to specify the optional rotation directions and axes, just like when using glRotate().

glRotate() normalizes non-nulls to +-1.f, which #rotate doesn't do. I warned you about that because I thought you might find some interesting usages for this effect. But regretfully, you didn't:

If the array values are other than those two, the mesh exhibits strange scaling effects. But I think you may find them amusing and probably useful too in some of your future implementations. :D

No big thing tho. I can apply normalization to non-nulls when parsing the #rotate meta.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 15, 2018, 10:45:08 am
Mike

Would it be possible to have the change(s) you have done in mobj.h, to avoid me to use an extra hidden circle around the objects ?

Thank you.
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 15, 2018, 07:36:03 pm
Here you are, Patrice.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 15, 2018, 08:30:47 pm
Thank you my friend.
Title: Re: Individual Mesh Rotation
Post by: Patrice Terrier on June 18, 2018, 05:57:57 pm
Mike

Don't you think that we could release officially version #2.52.
New SyncTimer
New #rotate meta
both seems to be quite reliable for now, then i could post updated animated projects showing the rotation feature in context.

Your thought ?
Title: Re: Individual Mesh Rotation
Post by: Michael Lobko-Lobanovsky on June 18, 2018, 08:01:58 pm
Yes, please do, Patrice.

But if somebody wants the sources, I think it will be reasonable to provide the older mobj.h (the way it was in my latest zip) -- without the attempted #group meta. It isn't working yet as I think it should, so its implementation may change with time, and until then it's going to be just dead code.