ObjReader Community

WIP => WIP => Topic started by: Patrice Terrier on December 07, 2017, 04:26:27 pm

Title: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on December 07, 2017, 04:26:27 pm
This is my next 3D challenge...

(http://www.objreader.com/download/images/peugeot-onyx.jpg)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on December 26, 2017, 04:00:23 pm
... without post processing i have to figure out for the best way to do it.

Post-processing is the ultimate goal yet there's a hint on how it  can be approximated for the time being.

Apart from the ambient, diffuse and specular illumination components we're using on our materials in both ObjReader and Objector, there's also the so-called emissive lighting component that defines if the material is supposed to look as if it would emit its own light (like e.g. red-hot or molten metal) and if yes, then how intense such emission should be and what color it should have. The material emissive color is not affected by the colors of scene lights nor does it light or colorize the other objects on the scene.

GL_EMISSION is handled through its own color array exactly like the other GL_AMBIENT/DIFFUSE/SPECULAR color components. For glMaterial(...,GL_AMBIENT,...), glMaterial(...,GL_DIFFUSE,...), glMaterial(...,GL_SPECULAR,...) to have any effect on the actual material color, the scene must also explicitly define the corresponding light sources (lights). For glMaterial(...,GL_EMISSION,...) to work, lights are not needed nor taken into account when OpenGL calculates the material's final color to render if the GL_AMBIENT/DIFFUSE/SPECULAR components for the material and corresponding lights aren't used/defined or are set to 0.

Some Wavefront Object dialects define this component through the material's Ke parameter. There may even be a separate dedicated emissive texture assigned to the mesh material via a map_Ke statement, that would define the mesh's "light emitting"/"glowing" regions against its other parts which are illuminated with the regular scene lights and own colors and thus don't appear glowing/neon-lit/red-hot/whatever. Google for the GL_EMISSION constant for further reading on this illumination component.

When the ordinary ambient, diffuse and lighting illumination of the scene isn't too bright and intense, OpenGL material emission color might be sufficient even to emulate genuine volumetric glow of GLSL post-processing shaders for simple alpha textured models or meshes.


FFP:

(https://www.tomdalling.com/images/posts/modern-opengl-08/emissive.png)

PPL:

(http://www.cs.utah.edu/~vpegorar/courses/cs6620/Assignment11/color.png)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on December 28, 2017, 05:55:22 pm
Merci beaucoup Patrice!

Now I have something to have fun with for the coming New Year holidays.  :D
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on December 30, 2017, 02:59:39 pm
Mike--

I am thinking to add a simple demo mode into ObjReader to perform auto-giration of the model (0-360) using
glRotatef(rangle, 0.0f, 1.0f, 0.0f);

That would help to create smooth video presentation of the model, your thought ?

See the attached video example  :)

Added:
I have attached the latest Main.cpp that allows the use of the new "Demo mode".
You can also use either '+' or '-' to speed up or slow down the rotation.
Next effects, could be light rotation and/or color change. ;)

By the way, i think i have completed the model by now, i am just waiting to see your own glow effect before posting the official version ...

Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on December 30, 2017, 08:05:49 pm
I am thinking to add a simple demo mode into ObjReader to perform auto-giration of the model (0-360) using
glRotatef(rangle, 0.0f, 1.0f, 0.0f);

Good idea, actually.

Quote
That would help to create smooth video presentation of the model, your thought ?

You mean, what would help? First, disable Vsync, if any, and thus allow the viewer render the scene at the fastest FPS rate it can deliver for a given model depending on the CPU calc power and the model's geo complexity, and second, choose the smallest corresponding rotation angle per frame. The simpler the model, the smaller the angle and the smoother the visible rotation. OpenGL is always one big compromise between what the PC can deliver and what you'd like to see.

At any rate, disabling Vsync will dramatically increase both CPU and GPU load for the models of such complexity, Patrice. That's why they will never be used without prior polygon crunching (i.e. simplification and re-triangulation) in real-time gaming contexts. :)

Quote
I have attached the latest Main.cpp that allows the use of the new "Demo mode".
You can also use either '+' or '-' to speed up or slow down the rotation.

Thanks, I will recompile my ObjReader to incorporate the rotation effect.

Quote
Next effects, could be light rotation and/or color change. ;)

Would be nice to have such options too. :)

Quote
i am just waiting to see your own glow effect before posting the official version ...

When (and if at all) I succeed, you will have to re-release your ObjReader again and, possibly, review the concept of other models as well. So the Onyx model isn't going to be in permanent stasis either. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on December 31, 2017, 02:45:46 am
No Patrice,

You won't be able to produce smooth animation with ca. 3.5M polies to dynamically process AND draw in each render frame. The renderer obviously lags behind your timer simply rejecting the extra draw calls its OpenGL buffers aren't ready to process because they are still drawing the frame that was requested three or four calls before.

By the looks of it, the real FPS rate in your ObjReader while animating the Onyx model isn't higher than some 10 or 12 frames at the most regardless of timer settings.

Rendering the same model in my Objector that delivers the maximum un-Vsync'ed FPS rate possible for a given model by invalidating the canvas immediately after draw in the WM_PAINT event, proves that fact. Objector has a somewhat faster render function written entirely in assembler, yet its historical readings are documenting the real FPS rate for this model at 10 or 11 frames per 1000 milliseconds. (see my screenshot below)

More or less smooth animation requires at least 30 frames per second. 24 FPS as in the cinema movie is the absolute minimum.

My compliments on the model's headlight glow. You did the absolute best that could ever be done with the materials and render techniques available. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on December 31, 2017, 09:48:57 am
Mike--

Thank you for the feedback.

I can realy see a huge difference between running it on my I5 ASUS Transformer, and my gaming ASUS G752VY.

On the gaming machine everything is smooth, even at the lowest rotation angle step of 0.25°.

I have already decimated some of the hidden meshes, but i shall see if i can do it further more.
I shall create UV's coordinate in c4d to be seen only from front, i don't know if that could make any difference.

Added
Currently on my ASUS G752VY, the frame rate i have with this model is 17 FPS, while it is twice as big with most of my other models.

Updated
While the maximum FPS could be 66, it has been limited to 34, to be more cooperative with the other applications, if i drop the limitation (and after a tedious work of decimation) i got a FPS of 21-22, instead of 17.

Currently the model has these values
Vertices 1939151
Triangles 3304388
Meshes 69
Materials 49
Indices 9913164



Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 01, 2018, 12:27:25 am
Triangles 3304388

300K tris is a win indeed! Congrats! :)

... i am just waiting to see your own glow effect before posting the official version ...

Patrice,

You're probably underestimating the importance of the task. I think it's more urgent at this moment than decimation, or auto-rotation, or both taken together.

Surprisingly enough, when I looked again into my Objector code after a year or so of near total oblivion, I found out it's been having everything it needs for cheap GL_EMISSION to work for at least 2 recent years.

Please take a look below.  GL_EMISSION is the material color property that doesn't depend on the material's or scene lights' other colors or intensity. That's what makes it particularly suitable for cheap glow emulations. But I'm sorry to say your current alpha glow texture is absolutely inadequate to implement GL_EMISSION up to its full potential.

I'm hereby proposing a deal as follows:

1. You generate an alpha texture véritable enough to pass for a headlight flare in your existing ObjReader/Onyx and map it appropriately to your headlight glow meshes. (I think this (https://www.google.by/search?client=firefox-b&dcr=0&biw=1144&bih=715&tbm=isch&sa=1&ei=OFFJWoCbGuzN6QT_67TgCA&q=headlight+glow+texture&oq=headlight+glow+texture&gs_l=psy-ab.3...177046.183874.0.184306.22.20.0.2.2.0.64.1175.20.20.0....0...1c.1.64.psy-ab..0.15.776...0j0i67k1j0i30k1j0i19k1j0i5i30i19k1j0i30i19k1.0.TCmvax9uxDQ#imgrc=Ek3poKDedf4vzM:) and this (https://www.youtube.com/watch?v=iUmX9QTtQRI) may help you do just that)

2. As soon as you send me one of those that I can accept, I'll send you back the Mobj/Main sources equipped to use GL_EMISSION for you to bring the model and its textures to perfection.

I am not talented enough to do that as easily as you undoubtedly can. :)


Is it a go?

P.S. I planned to attach a min. Objector.exe setup for you to test your glow texture attempts with but unfortunately, my sources somehow refuse to compile into a standalone exe. I.e. it works OK when JIT compiled directly to memory (my usual code test mode) but crashes on model load when compiled to a static exe ... :(

P.P.S. The below renders were made with the following glow material settings:

newmtl glowing
Ka 0 0.8 1
Kd 0 0.8 1
Ks 0 0.8 1
Ke 0 0.8 1
map_Kd glowing.png
Ns 512
d 0.7
illum 2


They help increase the glow material overall brightness against the other materials as the scene illumination brightness rises from 0 to 255/255 (0% to 100%). When the light intensity is nil then only Ke is seen, when it is 100% then the other K components add their cyan too. Thus the glow material stays just as bright against the other materials in the scene as it appeared in total darkness. But alas, the configuration of alpha mask is totally wrong and unrealistic for a car headlight flare... :(
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 02, 2018, 11:43:26 pm
Hi Patrice,

Is this flare above supposed to have another glow mesh geometry, not the one that's implemented in your last wip model? If the flare somehow fits in the existing glow mesh, can I have it too?

I've done most of coding and I'm planning to send you the files soon. But that's not going to be all. I'm also planning to add a simple extra dialog window for some interactive lighting adjustments. You'll see what and how the dialog gadgets tend to control, and then you'll (hopefully) re-implement the same functionality in your main window control pane using your skinned controls. Most of these options work for me through hotkeys in my Objector.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 03, 2018, 08:55:55 pm
Another one, using AlphaToCoverage
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 03, 2018, 10:27:15 pm
A2C may yield unwanted step-like transparency gradations rather than smooth transition gradients though of course the edges will be absolutely invisible against any backgrounds and colors and under any illumination intensities.

At any rate, you'll have more options to try when GL_EMISSION is there. I have updated the loader and renderers but I also would like to add a few lighting options. I couldn't physically manage to complete all that "in one sitting".

I'm a little overloaded with real life work after 4 days of holidays but my mods to ObjReader are materializing little by little. I'll send them to you in a day or two, as soon as I'm ready.


P.S. I also squeezed another 3 extra FPS for Onyx out of ObjReader renderer. I'm having now a stable 14FPS rate verified by Fraps. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 04, 2018, 10:01:44 pm
Patrice,

Quote
Here is a new WIP, with further decimation ...

Thanks, the flares look great! Watch them also in an A2C GL_EMISSION color... :)  (screen 1 below)

Quote
... reworked A2C materials

See the A2C transparency gradation steps I noted before? Of course they aren't noticeable at a distance thanks to your outstanding skills, but they're there nonetheless. They aren't your fault, they are inherent in the A2C dithering method. (screen 2 below)

Quote
Ideally it would be nice to apply A2C only to a specific material...

I've been talking about this all the time ever since we started. And not only A2C but also other features like face culling, both-sides lighting, multiple per-material colored light sources, etc. -- everything that's extra to the Wavefront Object vocabulary can be controlled by #metacommands placed inside the newmtl definitions, in which case they would only affect this particular newmtl. The #metacommands at the very top of .mtl where no newmtl is yet defined could stay global just the way they are now.

And yes Patrice, we will need billboard flares badly for our FFP mode where post-processing is impossible by OpenGL design. Billboard flares aren't post-processed; the size and orientation of their respective quads is simply and easily recalculated in real time every time the cursor button-down drag mode movement is detected.

Quote
To increase the FPS while in "Y rotation mode", try this...

Great! This yielded yet 1 more extra FPS for Onyx. Now I'm seeing 15FPS as reported by Fraps in the FFP mode. My video chips are a little less powerful than your gaming laptop's video card, hence a somewhat lower overall FPS rate.

Fraps is pretty exact, non-intrusive, both 32 and 64 bit friendly, and works for OpenGL and DirectX equally well. I can't use my GeForce Experience reliably with my SLI-bridged video cards under Windows 7 because it's glitchy when working with more than 1 card simultaneously. (screen 3 below)

Quote
a simple FPS counter, when using rotation

You might but SetWindowText() is usually too heavy for OpenGL to synchronize itself with when drawing very complex geometries. Generally it isn't recommended except in simple low-poly renderers. My Objector's renderer draws its gadgets in OpenGL and luckily allows me to add one or two FPS counters alongside a hellofalot of other stuff and still stay basically compatible with your FPS readings, even if all this data would only be relevant in the yet-unimplemented editing mode of Objector operation.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 04, 2018, 10:56:20 pm
Mike

Thank you for the report.

To display FPS i shall use what i have done so far in my OpenGL plugins, to avoid the use of SetWindowText.

So far i have been able to decimate a little more the model without noticeable quality loss.
I reworked again the flare to get the attached result, that i think looks quite realistic while in A2C mode.
The model must be seen very closely to see the A2C artefacts, but then they are plainty of other small defaults that become visible at this level of magnification. ;)

About bilboarding i wrote a generic function into GDImage for that purpose, you can see it in action in my 3D Chart demo project here: http://www.objreader.com/index.php?topic=17.0
I shall see if we can use it also with ObjReader.
In the 3D Chart project the first row of buble spheres are indeed bilboarded quads ;)

About FRAPS i don't think that it is working on Windows 10; but i can use the one provided by nVIDIA until we have our own tomorrow ;)

For the fun of it, i have attached a screen shot to show you the matching C4D's project. As you can see, there is a lot of imagination effort to do, just to figure what would be the result once rendered into ObjReader...

Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 04, 2018, 11:40:26 pm
Quote
I shall see if we can use it also with ObjReader.

It can be a good place to start with per-material #metacommands:

-- add a bool isBillboard property directly to your MobjMat structure
-- use #billboard metacommand just under its newmtl flare definition in the .MTL file
-- set isBillboard = true if the above #metacommand is read by Mobj_importMaterials() when importing this particular material
-- rotate the flare additionally in response to if (pMaterial->isBillboard) as appropriate in an extra call directly from Mobj_DrawUsingFixedFuncPipeline() just before the flare material is drawn

and you can do similar things for any other non-Wavefront material property (A2C included) used on a per-material basis via its respective #metacommand.

( Haven't seen my own 3D editors' development screens in years :D )
Title: BillBoarding
Post by: Patrice Terrier on January 05, 2018, 11:02:55 am
Mike

Here are the 2 GL functions i am using into GDImage to perform point billboarding.

Code: [Select]
void GL_BillBoard () { // dllexport
    // Create MultMatrix
    float mm[16] = {1.0f, 0.0f, 0.0f, 0.0f,
                    0.0f, 1.0f, 0.0f, 0.0f,
                    0.0f, 0.0f, 1.0f, 0.0f,
                    0.0f, 0.0f, 0.0f, 1.0f};

    float m[16]; glGetFloatv(GL_MODELVIEW_MATRIX, &m[0]);
    // Convert to OpenGL matrix notation
    mm[0] = m[0];
    mm[1] = m[4];
    mm[2] = m[8];
    mm[4] = m[1];
    mm[5] = m[5];
    mm[6] = m[9];
    mm[8] = m[2];
    mm[9] = m[6];
    mm[10] = m[10];
    glMultMatrixf(&mm[0]);
}
Code: [Select]
void GL_ChartPoint (IN float Radius, IN float rValue) { // dllexport
    glPushMatrix();
       glTranslatef(0, rValue, 0);
       long nJ;
       // Pre-computed circle.
       static long nDone;
       static vector<float> sint;
       static vector<float> cost;
       if (nDone == 0) { nDone = -1; CircleTable(sint, cost, -32); }

       // Always show it in front of the camera.
       GL_BillBoard();

       glBegin(GL_TRIANGLE_FAN);
          glNormal3f(0.0f, 0.0f, 1.0f);
          glTexCoord2f(0.5f, 0.5f);
          for (nJ = 32; nJ > -1; nJ--) {
             glTexCoord2f((cost[nJ] + 1) * 0.5f , (sint[nJ] + 1.0f) * 0.5f);
             glVertex3f(cost[nJ] * Radius, sint[nJ] * Radius, 0.0f);
          }
       glEnd();
    glPopMatrix();
}

Now i have to look back into my 3D Chart project, to remember the best way to use it ;)

To display the FPS i shall use my ZI_DrawGLText.
Better to re-use the code from the existing DLL rather than writing a new one.

Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 05, 2018, 05:58:27 pm
Mike--

Here is the new Main.zip, with the new menu option "Show IPS (Iteration/second)".

I have also attached the latest WIP project (indices 9432819).

Note:
IPS is the only thing that we can compute with accuracy, especially because of the queue used by the GPU.



...

Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 06, 2018, 02:31:45 am
Thank you Patrice,

Are you sure the other modules (especially your precompiled libraries) have not been updated as well?

I am not seeing the IPS counter on my screen after recompilation with the new Main.cpp... :(


P.S. Please be patient for a little while more. I'll send you the sources with individual per-component color and on/off control over all the 3 lights and total scene brightness in both the FFP and PPL this afternoon or evening.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 06, 2018, 10:19:49 am
Mike--

Here is the full project in VS2013 PRO version.
I have checked the IPS with it, and it works fine by me.

Note:
The Resource folder is empty to reduce the size of the zip file

Do a WinMerge first, to see the minor code changes.

I am waiting for your version before working on the new meta, but take your time there is no hurry, this is the privilege of retirement.  :)

Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 06, 2018, 02:59:59 pm
Thanks again Patrice,

But I'm sorry to say this latest ObjReader you sent me compiles just fine yet it doesn't show the IPS counter under Windows 7 either. But it does, under Windows 10.

Just don't tell me you aren't using Win 7 any more and you're living in the 22nd century. Us mortals still use Win 7 a lot and not being compatible with it is detrimental to the product. ;)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 06, 2018, 06:21:16 pm
Quote
doesn't show the IPS counter under Windows 7 either

That is very strange, because the code is the same than the one i am using into my BassBox plugins (written at the time of XP/VISTA).
And both WinLIFT and GDImage are compiled with VS2010 to produce smaller DLL.

BTW i just updated all my computers to the latest Windows 10 patch, to protect me from the new Spectre/Meltdown big threat, that affects all CPU computers build since 20 years, and ranking from Andoid to IOS (PC, tablet, and smartphone).

Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 06, 2018, 07:15:09 pm
Mike

Please try with the attached zip file provided with a new IPS.h include file, that you should be able to check in debug mode with Seven.

...
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 07, 2018, 04:05:04 am
... a new IPS.h include file, that you should be able to check in debug mode with Seven.

Thank you Patrice,

I'll try it as soon as I'm through with the lights.

I've installed the patch for my Win 10 that's on a separate PC, but I haven't yet, for my Win 7 that's the host OS on my main dev workstation. I hear the patch can make your CPU run up to 40% slower, which I wouldn't like to see on my WS. I rarely use it for surfing the web anyway, so I don't think anybody would be so eager or patient enough as to fish for my personal info on such a rare occasion...
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 07, 2018, 07:58:15 am
Patrice,

I've done all the lighting I planned for ObjReader. It's now even cooler than what I have in my own Objector. As far as the 3 static directional light sources in both FFP and PPL are concerned, this lighting is almost as strong as what you probably have in your C4D editor renderer.  8)

All that's left to program is a scene master illumination control whose slider I squeezed in to the right of alpha threshold knob for now. I guess you'll have to re-position and anchor it to your liking all by yourself. I put it there just for testing.

I need only to add 9 buffer color arrays more wherein the colors are going to be attenuated by the scene master illumination factor slider and fed to the GL_LIGHT sources. That's little to do but I'll finish it off later today. Need to zzzzzz a little after a sleepless night.

In the meantime, watch what acid lighting can easily do with your creations.  ;D

Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 07, 2018, 11:09:53 am
Mike--

Quote
I hear the patch can make your CPU run up to 40% slower
So far i didn't notice a speed degradation into my multimedia applications, at least on my gaming laptop.

Quote
this lighting is almost as strong as what you probably have in your C4D editor renderer.

Wow, you did a tremendous work, congratulations !

Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 07, 2018, 04:53:21 pm
Material support suggestion for both A2C and Billboarding

Code: [Select]
struct MobjMat {
    float ambient[4];
    float diffuse[4];
    float specular[4];
    float shininess;        // [0 = min shininess, 1 = max shininess]
    float alpha;            // [0 = fully transparent, 1 = fully opaque]

    std::string defMapFileName;
    std::string colorMapFilename; // ML: let those stay for a while; haven't decided yet if we need them at all h
    std::string bumpMapFilename;

    long illum;

    // ML: EXTRA
    std::string ambiMapFilename; // ditto
    std::string specMapFilename;
    std::string reflMapFilename;
    // To those IDs that follow below, assign *IN ADVANCE AND ONLY ONCE PER MATERIAL* whatever this code:
    // ....
    // if (memcmp(pszTextName, &pMaterial->color|bump|ambi|specMapFilename[0], strlen(pszTextName)) == 0) {
    //  glBindTexture(GL_TEXTURE_2D, gt_texObj[nCount].Texture);
    //  break;
    // }
    // ....
    // returns in its "gt_texObj[nCount].Texture" in every texture loop of your Mobj_DrawUsing...() procs
    // in every frame they render again and again. There is absolutely no need to do it that way. You're
    // killing your FPS rate with your own hands by comparing turtle slow string names all over again in
    // each frame.

    // This is your *ABSOLUTELY HIGHEST PRIORITY* task.

    // Please take any such loop out of render procs into a separate procedure and run it just once for
    // all the textures in all the materials of the model, so that
    // &pMaterial->ambi|diff|bump|specMapID = gt_texObj[nCount].Texture;
    // then delete all those loops from the render procs and just use
    // glBindTexture(GL_TEXTURE_2D, &pMaterial->ambi|diff|bump|specMapID);
    // as appropriate.
    long colorMapID;
    long ambiMapID; // OpenGL numeric texture "names" (IDs) to be assigned as I described above
    long bumpMapID;
    long specMapID;
    long reflMapID;
    long isA2C;       // PAT: 01-07-2018
    long isBillboard; // PAT: 01-07-2018
};

Code: [Select]
void Mobj_importMaterials(const char *pszFilename) {

    FILE* pFile = fopen(pszFilename, "r");
    if (pFile == 0) { return; }

    MobjMat* pMaterial = 0;
    long K = 0, nI = 0, nIllum = 0, nNumMaterials = 0;
    char szBuffer[MAX_PATH] = { 0 };
    char fullPath[MAX_PATH] = { 0 };

    Mobj_gl_cw(0, 1); // 10-29-2015
    Mobj_ambient(0, 1); // 11-19-2015
    Mobj_AlphathresholdValue(0.0f, 1); // 12-14-2015
    Mobj_bothsides(0, 1); // 05-02-2016
    Mobj_AlphaToCoverage(0, 1); // 12-11-2017

    long nGlobal = -1; // PAT: 01-07-2018

    // Count the number of materials in the MTL file.
    while (fscanf(pFile, "%s", szBuffer) != EOF) {
        CharLowerA(szBuffer);
        switch (szBuffer[0]) {
        case 'n': // newmtl
            if (strcmp(szBuffer, "newmtl") == 0) { // 12-12-2015 ML: n can also mean lowercase Ns
                ++nNumMaterials;
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
                nGlobal = 0;
            } else {
                fgets(szBuffer, sizeof(szBuffer), pFile);
            }
            break;
        case '#': // Shall we use a specific  wallpaper or clockwise polygons
            if (nGlobal) {
            if (strcmp(szBuffer, "#wallpaper") == 0) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s", szBuffer);
                memset(&gsw_wallpaper[0], 0, sizeof(WCHAR) * MAX_PATH);
                MultiByteToWideChar(CP_ACP, 0, szBuffer, (long)strlen(szBuffer), gsw_wallpaper, MAX_PATH);
            } else if (strcmp(szBuffer, "#gl_cw") == 0) {
                Mobj_gl_cw(-1, 1);
            } else if (strcmp(szBuffer, "#ambient") == 0) {
                Mobj_ambient(-1, 1);
            } else if(strcmp(szBuffer, "#bothsides") == 0) {
                Mobj_bothsides(-1, 1);
            } else if (strcmp(szBuffer, "#threshold") == 0) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s", szBuffer);
                Mobj_AlphathresholdValue((float) atof(szBuffer), 1);
            } else if(strcmp(szBuffer, "#alphatocoverage") == 0) {
                Mobj_AlphaToCoverage(-1, 1);
            } else {
                fgets(szBuffer, sizeof(szBuffer), pFile);
            }
            }
            break;
        default:
            fgets(szBuffer, sizeof(szBuffer), pFile);
            break;
        }
    }

    rewind(pFile);

    gnm_numberOfMaterials = nNumMaterials;
    gtm_materials.resize(gnm_numberOfMaterials);
    gnm_numberOfTextures = 0;
    nNumMaterials = 0;

    // Load the materials in the MTL file.
    while (fscanf(pFile, "%s", szBuffer) != EOF) {
        CharLowerA(szBuffer);
        switch (szBuffer[0]) {
        case 'n': // Ns
            if (szBuffer[1] == 's') {
                fscanf(pFile, "%f", &pMaterial->shininess);
                // Wavefront .MTL file shininess is from [0,1000].
                // Scale back to a generic [0,1] range.
                pMaterial->shininess /= 1000.0f;
            } else if (strstr(szBuffer, "newmtl") != 0) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
                // Material
                pMaterial = &gtm_materials[nNumMaterials];
                pMaterial->ambient[0] = 0.2f;
                pMaterial->ambient[1] = 0.2f;
                pMaterial->ambient[2] = 0.2f;
                pMaterial->ambient[3] = 1.0f;
                pMaterial->diffuse[0] = 0.8f;
                pMaterial->diffuse[1] = 0.8f;
                pMaterial->diffuse[2] = 0.8f;
                pMaterial->diffuse[3] = 1.0f;
                pMaterial->specular[0] = 0.0f;
                pMaterial->specular[1] = 0.0f;
                pMaterial->specular[2] = 0.0f;
                pMaterial->specular[3] = 1.0f;
                pMaterial->shininess = 1.0f;
                pMaterial->alpha = 1.0f;
                pMaterial->defMapFileName = szBuffer;
                pMaterial->colorMapFilename.clear();
                pMaterial->bumpMapFilename.clear();
                pMaterial->illum = 1;
                pMaterial->ambiMapFilename.clear();
                pMaterial->specMapFilename.clear();
                pMaterial->reflMapFilename.clear();
                pMaterial->colorMapID = 0;
                pMaterial->ambiMapID = 0;
                pMaterial->bumpMapID = 0;
                pMaterial->specMapID = 0;
                pMaterial->reflMapID = 0;

                m_materialCache[pMaterial->defMapFileName] = nNumMaterials;
                ++nNumMaterials;
            }
            break;

        case 'k': // Ka, Kd, or Ks
            switch (szBuffer[1]) {
            case 'a': // Ka
                fscanf(pFile, "%f %f %f",
                    &pMaterial->ambient[0],
                    &pMaterial->ambient[1],
                    &pMaterial->ambient[2]);
                pMaterial->ambient[3] = 1.0f;
                break;

            case 'd': // Kd
                fscanf(pFile, "%f %f %f",
                    &pMaterial->diffuse[0],
                    &pMaterial->diffuse[1],
                    &pMaterial->diffuse[2]);
                pMaterial->diffuse[3] = 1.0f;
                break;

            case 's': // Ks
                fscanf(pFile, "%f %f %f",
                    &pMaterial->specular[0],
                    &pMaterial->specular[1],
                    &pMaterial->specular[2]);
                pMaterial->specular[3] = 1.0f;
                break;

            default:
                fgets(szBuffer, sizeof(szBuffer), pFile);
                break;
            }
            break;

        case 't': // Tr
            switch (szBuffer[1]) {
            case 'r': // Tr
                if (pMaterial->alpha == 1.0f) { // 12-06-2015 ML: only if alpha is still default
                    fscanf(pFile, "%f", &pMaterial->alpha);
                    if (pMaterial->alpha > 0.0f) {
                        pMaterial->alpha = 1.0f - pMaterial->alpha; // 12-06-2015 ML: follow OBJ specs
                    }
                    if (pMaterial->alpha == 0.0f) { pMaterial->alpha = 1.0f; } // 02-05-2016
                } else {
                    fgets(szBuffer, sizeof(szBuffer), pFile); // 12-06-2015 ML: ignore
                }
                break;

            default:
                fgets(szBuffer, sizeof(szBuffer), pFile);
                break;
            }
            break;

        case 'd':
            fscanf(pFile, "%f", &pMaterial->alpha);
            break;

        case 'i': // illum
            fscanf(pFile, "%d", &nIllum);
            pMaterial->illum = nIllum;
            if (nIllum == 1) {
                pMaterial->specular[0] = 0.0f;
                pMaterial->specular[1] = 0.0f;
                pMaterial->specular[2] = 0.0f;
                pMaterial->specular[3] = 1.0f;
            }
            break;

        case 'm': // map_Kd, map_bump
            // 11-02-2015 added support for map_Ka, map_Ks
            if (strstr(szBuffer, "map_kd")) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
                Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
                if (FileExistA(fullPath)) {
                    pMaterial->colorMapFilename = fullPath;
                    ++gnm_numberOfTextures;
                }
            } else if (strstr(szBuffer, "map_bump")) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
                Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
                if (FileExistA(fullPath)) {
                    pMaterial->bumpMapFilename = fullPath;
                    ++gnm_numberOfTextures; // 03-24-2015
                }
                // 11-02-2015
            } else if (strstr(szBuffer, "map_ka")) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
                Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
                if (FileExistA(fullPath)) {
                    pMaterial->ambiMapFilename = fullPath;
                    ++gnm_numberOfTextures; // 03-24-2015
                }
                // 11-02-2015
            } else if (strstr(szBuffer, "map_ks")) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
                Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
                if (FileExistA(fullPath)) {
                    pMaterial->specMapFilename = fullPath;
                    ++gnm_numberOfTextures; // 03-24-2015
                }
            } else {
                fgets(szBuffer, sizeof(szBuffer), pFile);
            }
            break;

        case 'r': // refl
            if (strstr(szBuffer, "refl")) {
                fgets(szBuffer, sizeof(szBuffer), pFile);
                sscanf(szBuffer, "%s %s", szBuffer, szBuffer);
                Path_CombineA(fullPath, (char*)gsm_directoryPath.c_str(), szBuffer);
                if (FileExistA(fullPath)) {
                    pMaterial->reflMapFilename = fullPath;
                    ++gnm_numberOfTextures; // 03-24-2015
                }
            }
            break;

        case '#': // PAT: 01-07-2018 meta specific for material
            if (strcmp(szBuffer, "#alphatocoverage") == 0) {
                if (Mobj_AlphaToCoverage(0, 0) == 0) {
                    pMaterial->isA2C = -1;
                }
            } else if(strcmp(szBuffer, "#billboard") == 0) {
                pMaterial->isBillboard = -1;
            }
            break;

        default:
            fgets(szBuffer, sizeof(szBuffer), pFile);
            break;
        }
    }
    fclose(pFile);
}
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 07, 2018, 06:26:42 pm
Looks fine, Patrice!

May I also suggest once again that we take this opportunity and change the #ambient global metacommand to something more appropriate, e.g. like #multilight or similar? The term "ambient" has a very precise meaning in OpenGL, and this meaning differs dramatically from what the #ambient metacommand currently implies in the context of ObjReader's material library file...  ::)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 07, 2018, 06:38:11 pm
No problem, btw the A2C works great now per material into PPL i shall do the same for FFP;)

and we can still use the global one.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 07, 2018, 06:54:59 pm
Ok, now we can use the #multilight meta-command, and gP.nAmbientLight become gP.nMultiLight.

Reworking the ONYX.mtl to use A2C per material rather than global...

Added:
Onyx looks perfect ;)

Tell me if you want the new .mtl file, and the latest changes i have done into mobj.h and Main.cpp  :-[
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 08, 2018, 03:22:53 am
Patrice,

My suggestion is as follows.

1. I'm finished  with ObjReader's lights. My code comes in the zip below. There are many changes to Main/mobj but all of them are indispensable.

2. Compile them as-is and see/get accustomed to how the lights and GL_EMISSION now work in ObjReader. Do not criticize; what you don't like will most likely be something you're not yet accommodated well enough to.

3. Use WinMerge to merge your mods with my base code, not vice versa, little by little and see if anything in your mods breaks my functionality.

4. Once merged and fully working, you're free to trim the code making sure the functionality remains unaffected. Please do not attempt to camouflage my flag variables with your usual Mobj_xxxx() wrappers. Flags are supposed to work fast in time critical parts of the code, and extra function call overhead is the last thing we'd like to see e.g. in our render procs.


When it's all ready, I would be glad to get both the final sources AND the very latest glorious Onyx to match ObjReader's new capabilities.

Have fun! :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 08, 2018, 08:46:47 am
Thank you Michael for all your hard work, i shall now decipher the code and try to figure what is the best way to use it.

thank you again!

Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 08, 2018, 10:56:52 am
I can see all the potential to get better accurate lighting to match the default wallpaper background.

I did duplicate the light menu onto the main menu bar, for easiest selection.
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 08, 2018, 01:30:37 pm
Excellent! :)

To watch your Onyx headlights glow in the dark, start with the following material definition, switch off 'Multiple light sources', and dim the scene illumination to ca. 20%: (see screenshot)

newmtl glowing
Ke 0.15 0.35 0.95
map_Kd flare.png
Ns 512
d 0.9
illum 2


Now imagine the lights that are coded in the .MTL library with per-material #metacommands just like your A2C now is. The model is an elm tree alley late at night with a few stars in the sky; everything is lit very dimly with ambient-only GL_LIGHT0. On both sides of the alley, there are a few lampposts (a.k.a. street lights) whose top lamp meshes are made of a per-material GL_LIGHT0+1+2 #multilight material with a GL_EMISSION billboard flare in front of it! The scene is already giving me shivers and creeps even though Freddy Krueger is nowhere to be seen yet!!!  :D
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 08, 2018, 02:37:36 pm
Mike---

Both WinLIFT and GDImage support negative ranges with scrollbar sliders, for example -50, 50 is a perfect value; 0 being the medium value.
This means we must use signed values, aka: HIINT not HIWORD.

I am stamped with my BillBoarding function, i must remember how to use it ;)
currently it is always facing the camera that is good, but i would like that it follows the whole rotation of the model for the purpose of the quad flare effect.

I shall send you the new build as soon as i have sorted out my billboard problem.


Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 08, 2018, 03:30:28 pm
Illuminating (-/0/+), rather than the existing attenuating (0/100%), mode of scene brightness slider operation would be much, much more complicated to implement. Max values (255/255) of each color component of each amb/dif/spec property of a scene light would have to be monitored constantly in real time. Alternatively, brute force min/max clamping would have to be applied in each render frame to avoid overbrighting. Either way, the frame rate would suffer dramatically. I think the end result isn't worth the effort.

P.S. Please don't discard the camera front-facing billboard flare effect entirely! Make it a menu-selectable option!
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 09, 2018, 06:32:09 am
Patrice,

1. This ObjReader renders the IPS count for me in Win 7. That's good news. :)

2. The billboard function you're trying to use won't work in ObjReader. This hacker (!) function operates in object space coordinates (Objector's first-person shooter camera can use it) but ObjReader's current camera operates in world space coordinates. Some extra investigation is needed. That's neutral news.  ::)

3. I've found an extremely simple OBJ model without pre-calculated normals that crashes ObjReader badly. Objector loads it without problems. That's bad news.  :-\

P.S. Don't worry about the crash. The .OBJ file was invalid. It's just that FBSL is much more tolerant to memory issues because it has its own memory manager, which MS VC doesn't have. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 09, 2018, 10:33:03 am
Mike,

OK thank you for the feedback.

The IPS thing, never changed from the time of BassBox, i couldn't understand why it was not working by you on Seven  :-\

For the billboard thing, i have used the same code than in my SkinChart project, except that i am creating myself the billboarded point into GL_ChartPoint this way.

Code: [Select]
void CircleTable (OUT vector<float> &sint, OUT vector<float> &cost, IN long n) {
    // Table size, the sign of n flips the circle direction.
    long nSize = abs(n);
    // Determine the dAngle between samples.
    double dAngle;
    if (n == 0) { n = 1; }
    dAngle = 2.0f * PI / (float) n;
    // Allocate memory for n samples, plus duplicate of first entry at the end.
    sint.resize(nSize+1);
    cost.resize(nSize+1);
    // Compute cos and sin around the circle.
    sint[0] = 0.0f;
    cost[0] = 1.0f;
    for (long nI = 1; nI < nSize; nI++) {
       sint[nI] = (float) sin(dAngle * nI);
       cost[nI] = (float) cos(dAngle * nI);
    }
    // Last sample is duplicate of the first.
    sint[nSize] = sint[0];
    cost[nSize] = cost[0];
}

void GL_BillBoard () { // dllexport
    // Create MultMatrix
    float mm[16] = {1.0f, 0.0f, 0.0f, 0.0f,
                    0.0f, 1.0f, 0.0f, 0.0f,
                    0.0f, 0.0f, 1.0f, 0.0f,
                    0.0f, 0.0f, 0.0f, 1.0f};

    float m[16]; glGetFloatv(GL_MODELVIEW_MATRIX, &m[0]);
    // Convert to OpenGL matrix notation
    mm[0] = m[0];
    mm[1] = m[4];
    mm[2] = m[8];
    mm[4] = m[1];
    mm[5] = m[5];
    mm[6] = m[9];
    mm[8] = m[2];
    mm[9] = m[6];
    mm[10] = m[10];
    glMultMatrixf(&mm[0]);
}

void GL_ChartPoint (IN float Radius, IN float rValue) { // dllexport
    glPushMatrix();
       glTranslatef(0, rValue, 0);
       long nJ;
       // Pre-computed circle.
       static long nDone;
       static vector<float> sint;
       static vector<float> cost;
       if (nDone == 0) { nDone = -1; CircleTable(sint, cost, -32); }

       // Always show it in front of the camera.
       GL_BillBoard();

       glBegin(GL_TRIANGLE_FAN);
          glNormal3f(0.0f, 0.0f, 1.0f);
          glTexCoord2f(0.5f, 0.5f);
          for (nJ = 32; nJ > -1; nJ--) {
             glTexCoord2f((cost[nJ] + 1) * 0.5f , (sint[nJ] + 1.0f) * 0.5f);
             glVertex3f(cost[nJ] * Radius, sint[nJ] * Radius, 0.0f);
          }
       glEnd();
    glPopMatrix();
}

Added:
We must reset the lighting when loading a new model (see the attachment).
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 10, 2018, 02:29:18 am
I think that the front light looks gorgeous  8)

Terrrrrrrriblement terrrrrrrrific!!! :D


I got the billboard flare basically working and am now experimenting a bit more to see if various other billboard types may be of use in ObjReader/Objector. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 10, 2018, 11:47:01 am
Quote
I got the billboard flare basically working and am now experimenting a bit more to see if various other billboard types may be of use in ObjReader/Objector. :)

That is great!

Would be nice if it could work like in
http://www.objreader.com/index.php?topic=17.0

I also thought of an individual mesh billboarded rotation (gauge, clock, air jet spirale cone effect, etc.).

And with the latest feature another global #straylight % meta, to setup the default brightness percentage when loading a model.
BTW i changed the IDC_BRIGHT_CONTROL tooltip wording to "  Stray light  ", and reverted the slider orientation.  ;)

I am thinking also about a new auto-hide composited control panel, like in MediaBox when playing the plugins full screen.

See a slight Ke emission applyed to the tachymeter, and the new slider orientation...



Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 10, 2018, 03:41:20 pm
And with the latest feature another global #straylight % meta, to setup the default brightness percentage when loading a model.
BTW i changed the IDC_BRIGHT_CONTROL tooltip wording to "  Stray light  ", and reverted the slider orientation.  ;)

Great! :)

Quote
I am thinking also about a new auto-hide composited control panel, like in MediaBox when playing the plugins full screen.

Nice!! :)

Quote
See a slight Ke emission applyed to the tachymeter, and the new slider orientation...

Awesome!!! 8)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 10, 2018, 06:21:26 pm
Your 3DChart has become extremely attractive in recent years. :) No z-buffer fighting on the ground plane any more. :)

Now, exactly what is your rValue in your GL_ChartPoint (IN float Radius, IN float rValue)? I guess it must be the Y height of sprite center relative to the world center [0,0,0]. What are the actual limits of rValue in some absolute units or per cent of something?

Yes, I'd like to have any models you create. When I'm through with billboards, I'll also send you my Quake III torch models I'm using to test flares. :)


P.S. Re: "  Stray light  "

I think you could also call it "Light dimmer" or "fader".
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 10, 2018, 06:57:15 pm
As far as i can remember, in 3D Chart, the rValue must match the edge scale.  ;)

I am preparing the wip with the extra mesh, and the specific mtl file.

BTW i like fader because the word is short, however 100% means maximum brightness intensity (the current value), while zero is total darkness (this is the reason why i used "stray light"). Of course nothing is in concrete, so we can change the #straylight meta for something better.

Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 10, 2018, 07:15:08 pm
wip.zip = extra mesh + new mtl file (with new Ke settings)

Main_Mobj.zip = my latest work on meta and slider values.

note:
The static Mobj_ functions, are a survival of the Mobj.dll version.

But now with the current status of ObjReader, we could use a specific set of global properties to setup the GLOBAL mesh settings that must be restored to the .mtl settings.

Quote
I'll also send you my Quake III torch models I'm using to test flares. :)
I couldn't find it  :-[

After looking again at my 3D Chart, it becomes obvious that we must use translation in the ObReader billboard.
In charting for obvious reasons the 0,0 origine is like in the 2d world to help the users that are not familiar with world coordinates, i forgot this myself  ::)

See this
https://opengameart.org/content/lens-flares-and-particles
you can use any of them to replace the OR.png file


Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 10, 2018, 08:10:37 pm
wip.zip = extra mesh + new mtl file (with new Ke settings)

Main_Mobj.zip = my latest work on meta and slider values.

Downloading now, thanks!

Quote
... we could use a specific set of global properties to setup the GLOBAL mesh settings that must be restored to the .mtl settings.

Probably yes, we even should. Many of them are used directly in our render procs where every millisecond, if not microsecond, counts. We certainly need no extra function call overhead there.

Quote
Quote
I'll also send you my Quake III torch models I'm using to test flares. :)
I couldn't find it  :-[

I said:
Quote
When I'm through with billboards...
which I am not as of yet. :) Anyway, the models are attached below. :)

Quote
See this https://opengameart.org/content/lens-flares-and-particles you can use any of them to replace the OR.png file

Thank you for the link! :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 11, 2018, 10:50:54 pm
I could spend hours playing with the new settings, and trying to make the best mtl file.  ::)

I am thinking of a new global meta #background to be used like #wallpaper but using a specific texture materiel exclusive to the model.
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 12, 2018, 12:38:16 am
Re: spending hours

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

BTW you didn't tell me whether you do have a skinnable color picker among your stock of skinned widgets...

Re: #wallpaper vs. #background

Technically speaking, a #wallpaper is a material of sorts; it is in fact a diffuse-only textured quad made of otherwise default material. The only difference it makes is that its vertices are generated on the fly at run time rather than form part of the static model loaded for rendering.

Re: flares

Similar to #wallpaper, what you do with your 3D chart bubbles and what we should do with the flare meshes in the model is that we shouldn't have them defined, or shouldn't regard, as literal part of the model. We should generate their quads on the fly and draw them in the orthogonal, rather than modelview, projection.

Theoretically, it's possible to reposition and un-rotate the model and draw its flare(s) independently and then restore the entire model's position and rotation, but that would be one hell of a lot of work to be done, and time, to lose.

It would be much, much more reasonable to just draw the flare quad separately from the model bypassing its vertex array that's already loaded on the GPU because drawing just a quad in the orthogonal projection the way we draw a #wallpaper is way faster than messing with the entire model.

It is easy to un-rotate the flare that's positioned at the model's center. But it's a PITA to unwind and then rewind the model's entire geo for the sake of just one quad of four vertices when the flare is far off of the model center of origin.
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 13, 2018, 06:22:55 pm
Evening Patrice,

I think the list is rather complete. I have a few more effects in mind to add now that we're using a timer officially. But first of all I want to finish off billboarding. I'm still not through with it.

Now please tell me how is your Radius argument changed in your void GL_ChartPoint (IN float Radius, IN float rValue) function? Is it a constant for all the bubbles you're currently drawing in your 3D chart that defines how large the common bubble mesh (circle) is with respect to the other meshes in the scene? Or is it a variable you're modifying somehow elsewhere in your code e.g. to control a particular bubble's "perspective" size?

P.S. Can you confirm that all your other apps that use billboards (Bubble, Asleep, HUD, SUNLIGHT) utilize the exact same code we're using to control ObjReader's current camera? By "exact same" I mean exact to the same order of precedence of gluLookAt/glRotate(X/Y/Z) calls in the renderer and same code to derive dX and dY deltas to control rotation angles in response to mouse button down moves across the screen?
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 13, 2018, 07:31:11 pm
Quote
Can you confirm that all your other apps that use billboards (Bubble, Asleep, HUD, SUNLIGHT) utilize the exact same code we're using to control ObjReader's current camera? By "exact same" I mean exact to the same order of precedence of gluLookAt/glRotate(X/Y/Z) calls in the renderer and same code to derive dX and dY deltas to control rotation angles in response to mouse button down moves across the screen?

No, the BassBox plugins are using indeed a mini particle engine, 3D Chart is much simpler.
The initial value of radius is g_Chart.radius = 1.0f  :-[

I think that we must translate (invert) the camera pos, just before billlboard, the problem is to compute the correct z location.
I shall try it to see what i could get...

Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 13, 2018, 08:06:17 pm
Quote
I think that we must translate (invert) the camera pos

What you call "// Convert to OpenGL matrix notation" in your GL_BillBoard() is in fact the so called "matrix transpose", i.e. getting the inverse of current modelview (rotation) matrix. Multiplying the current matrix by its (transposed) inverse in the glMultMatrixf(&mm[0]) (in fact, glMultMatrixf(mm) in C notation) yields effectively an un-rotated identity modelview matrix with all of its three rotation angles reset to 0. At the same time, its translation/scaling components as set by gluLookAt() remain intact, and that is why the ONYX plate stays well sized and zoomable but glued to the same point of projection onto the screen plane -- in other words, doesn't follow the model's general rotation pattern any more.

This is sufficient for an FPS camera (pun not intended; FPS here means "first-person shooter") that moves relative to the static model, but it isn't, for an orbiting camera like in ObjReader that stays put at the world's [0,0,0] while the model is dragged/rotated following mouse movements.

So, for what it's worth GL_BillBoard() takes us only halfway through to our goal in ObjReader. We must go further and move the billboard quad to a correct point in the 2D screen space and also project it correctly to emulate its X rotation (cylindrical a.k.a. Y axis-aligned billboard -- "tree-like"), X/Y rotation (spherical billboard -- "particle-like"), or leave it as-is without projection distortion (HUD a.k.a. "text-like" billboard).

All manual transformations are highly dependent on the order of glTranslate, glScale and glRotate calls, and also on the methods of obtaining pitch/yaw/roll angles in response to mouse dragging.

These are the issues with the billboard problem we're currently facing in ObjReader.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 13, 2018, 08:48:21 pm
Mike--

We can move this billboard problem onto the back burner, until the rabbit pops up from the top hat...

Would you like to have the latest changes i have done, i didn't send it to you before, because i didn't wanted to interfer with your current work  :-X
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 13, 2018, 09:01:57 pm
I'd love to have them a.s.a.p. I have yet to learn how to use your custom color picker under field conditions. :) I haven't touched it since the days of SkinBox. :)

I remember I saw a possible solution to our billboard problem somewhere and I've been looking for it all over the net in the recent 48 hours but I still haven't found it. But I will. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 13, 2018, 09:37:45 pm
Got it Patrice, thanks a lot!

I'll be looking for the billboard solution for another 24 hours and I'll re-implement it if found. If not, I'll drop that for the time being and will try to add some more time-animated effects mostly with dynamic GL_TEXTURE matrix.

I'll also suggest adding an Autodesk Max-like scene mesh to the render view that'll allow us to skin the scene better and also use its bottom plane for real shadow projection purposes.

:)

P.S. Yes, I've downloaded the MP4 to watch it off-line. The DL speed was only ca. 180KB/sec and I couldn't watch it in real time. The overall effect is cool but it could be better with a true scene mesh I mentioned above. 8)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 13, 2018, 09:46:25 pm
(https://emojipedia-us.s3.amazonaws.com/thumbs/120/emoji-one/104/thumbs-up-sign_1f44d.png)

The time will come when we are going to have our own neon glow effect not worse than the one used in TRON. ;)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 14, 2018, 11:44:25 pm
Billboard link:

Thanks Patrice, I've seen it -- not our case, alas!  ;)

Ambient reflection and emission  :)

Cool!!! Good luck with the rework!  :)

__________________________________________________________________



Та-daaaaaaa!!!...

(https://emojipedia-us.s3.amazonaws.com/thumbs/160/facebook/65/grinning-face-with-smiling-eyes_1f601.png)


As I said, the idea isn't mine but the implementation is entirely my own. And I'm quite satisfied with it because it works in all the three cameras without any code changes -- even though it has a tiny glitch in the two non-FPS cameras. When looked upon from the very top in close proximity to the Y axis, the flare goes small and apparently flips backwards (it's a Y-axis aligned cylindrical billboard, after all!) but in all other positions and rotations it looks really impressive. :)

For now it is implemented in C in the Objector's fixed-function pipeline procedure only.

But no no no, don't rush me! First of all I need a coupla days of rest, and I need to wash up the dishes that have piled up in my kitchen sink, and I need to go out to the nearby food store to buy me some fresh food and drink, and the last but not the least, I need some good, sound, uninterrupted, peaceful sleep! ;D
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 15, 2018, 12:11:33 am
 Bravo my friend, have a good sleep, i can wait for a couple days, but not any longer   :) ;) :D ;D
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 16, 2018, 09:55:33 am
Patrice,

For now we are going to have a restriction on all our billboard and flare meshes hardwired in our .OBJ files:

Be they cylindrical, spherical or textual (HUD-like) by operation, they must all be equilateral squares.

Not elliptical, not circular, not even arbitrarily rectangular. Just regular equilateral foursquare. And they must be texture mapped to the four corners of square images, transparent or opaque.

The reason for this is that currently we aren't using full-featured AABB's (axis aligned bounding boxes) but rather only the mesh center points and bounding sphere radii stored in our mesh structures. Note that we aren't using the billboard's literal corner vertices hardwired in its mesh but rather its center point only, respective to which we reconstruct the four displaced (rotated) corner vertices on the fly using the only one other mesh structure member suitable for this purpose -- the mesh radius. These two mesh structure members are sufficient to reconstruct an equilateral foursquare to an exact size the billboard mesh has in the model without extra hints or parameters. But this is impossible to do for an arbitrary billboard circle mesh without an extra Boolean parameter to hint that it is in fact a circle. Neither is it possible for an arbitrary rectangle without at least one extra numeric parameter specifying its aspect ratio.

This isn't going to be much of a restriction in practice since extra margins can always be clipped with transparency. Yet this rule should be observed, else we won't be able to reproduce the exact metrics of our billboard and flare meshes meticulously hardwired in our models.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 16, 2018, 12:03:39 pm
Thanks for the feedback!

I think that having square quads is already a big step forwards...
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 16, 2018, 08:21:00 pm
Patrice,

Theoretically, dynamic vertex creation for billboards/flares can be emulated in GLSL fragment shaders at run time similar to what I showed in my GLSL demos on this site. However, it would be difficult for me to write such shaders myself. Moreover, I strongly suspect that each such emulation would require a unique per-billboard size fragment shader of its own.

My suggestion is to start using GLSL geometry shaders for that purpose. Geo shaders can generate vertex primitives that the regular fragment shaders would automatically accept as if the verts were coming from the model's usual vertex buffers.

GLSL allows the use of geo shaders starting with #version 330 and up. AFAIR we already agreed in the past to use advanced GLSL shaders in due time. I think the time has come. :)

Your thoughts?

______________________________________

;D : (some problems detected in ObjReader though; not all other flares in the group are maintaining correct sizes  :-\)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 16, 2018, 08:27:42 pm
My thoughts, is that being mostly a GLSL rookie, i have to follow your advice.
Do what you think is better, if that doesn't match your level of expectation, then we can always revert back.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 17, 2018, 09:20:49 am
I have reworked the IPS, it will shows up only in "demo mode".
And display almost the same values than in FRAPS, and nVIDIA FPS counter ...

Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 17, 2018, 11:54:35 am
Patrice,

I've looked into your IPS counter. I do not agree with what and how you're trying to calculate in you render proc. This is not a proper approach and this certainly is not an FPS rate.

Please consider this:

Code: [Select]
    static DWORD nFPS = 0, nNext = GetTickCount() + 1000;

    ............... <snip> .................

    if (gP.nUseFPS) {
        DWORD now = GetTickCount();
        if (now >= nNext) {
            nNext = now + 1000;
            Path_Combine(zMsg, L"FPS ", STRL(++nFPS));
            nFPS = 0;
        } else {
            ++nFPS;
        }
        ZI_DrawGLText(gP.hGL, gP.glfont, 10, 5, zMsg, 0xFF00FF00);
    }

No no, your thanks would be too much for me. Just remember how generous and undemanding I was ...  ;D
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 17, 2018, 12:20:57 pm
And the following is my problem. You see, ObjReader refuses to maintain stable flare sizes I'm reconstructing from the 64-bit MODELVIEW and flare mesh centerPoint and meshRadius...  ???

Strange. I do not see such a glitch in my 32-bit Objector in any OS I'm checking it under... The C code is absolutely identical...  :-\
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 17, 2018, 02:13:16 pm
I already reworked it, that way
Code: [Select]
    // Display FPS using GDImage bitmapped font.
    if (gP.nUseFPS) {
        if (nCount == 0) { nCount = GetTickCount(); }
        nFPS++;
        DWORD delta_ticks = GetTickCount() - nCount;
        if (delta_ticks > 999) {
            Path_Combine(zMsg, L"FPS ", STRL(nFPS));
            nFPS = 0; nCount = 0;
        }
        ZI_DrawGLText(gP.hGL, gP.glfont, 10, 5, zMsg, 0xFF00FF00);
    }

and renamed IPS to FPS, but i didn't posted my latest code... waiting for the new billboard ;)

BTW i have also been working on the new material Light setting meta.
Using these predifined constants
Code: [Select]
WCHAR zColor[] = L"aliceblue,0xf0f8ff,antiquewhite,0xfaebd7,aqua,0x00ffff,aquamarine,0x7fffd4,azure,0xf0ffff,beige,0xf5f5dc,bisque,0xffe4c4,black,0x000000,blanchedalmond,0xffebcd,blue,0x0000ff,blueviolet,0x8a2be2,brown,0xa52a2a,burlywood,0xdeb887,cadetblue,0x5f9ea0,chartreuse,0x7fff00,chocolate,0xd2691e,coral,0xff7f50,cornflowerblue,0x6495ed,cornsilk,0xfff8dc,crimson,0xdc143c,cyan,0x00ffff,darkblue,0x00008b,darkcyan,0x008b8b,darkgoldenrod,0xb8860b,darkgray,0xa9a9a9,darkgreen,0x006400,darkkhaki,0xbdb76b,darkmagenta,0x8b008b,darkolivegreen,0x556b2f,darkorange,0xff8c00,darkorchid,0x9932cc,darkred,0x8b0000,darksalmon,0xe9967a,darkseagreen,0x8fbc8b,darkslateblue,0x483d8b,darkslategray,0x2f4f4f,darkturquoise,0x00ced1,darkviolet,0x9400d3,deeppink,0xff1493,deepskyblue,0x00bfff,dimgray,0x696969,dodgerblue,0x1e90ff,firebrick,0xb22222,floralwhite,0xfffaf0,forestgreen,0x228b22,fuchsia,0xff00ff,gainsboro,0xdcdcdc,ghostwhite,0xf8f8ff,gold,0xffd700,goldenrod,0xdaa520,gray,0x808080,green,0x008000,greenyellow,0xadff2f,honeydew,0xf0fff0,hotpink,0xff69b4,indianred,0xcd5c5c,indigo,0x4b0082,ivory,0xfffff0,khaki,0xf0e68c,lavender,0xe6e6fa,lavenderblush,0xfff0f5,lawngreen,0x7cfc00,lemonchiffon,0xfffacd,lightblue,0xadd8e6,lightcoral,0xf08080,lightcyan,0xe0ffff,lightgoldenrodyellow,0xfafad2,lightgray,0xd3d3d3,lightgreen,0x90ee90,lightpink,0xffb6c1,lightsalmon,0xffa07a,lightseagreen,0x20b2aa,lightskyblue,0x87cefa,lightslategray,0x778899,lightsteelblue,0xb0c4de,lightyellow,0xffffe0,lime,0x00ff00,limegreen,0x32cd32,linen,0xfaf0e6,magenta,0xff00ff,maroon,0x800000,mediumaquamarine,0x66cdaa,mediumblue,0x0000cd,mediumorchid,0xba55d3,mediumpurple,0x9370db,mediumseagreen,0x3cb371,mediumslateblue,0x7b68ee,mediumspringgreen,0x00fa9a,mediumturquoise,0x48d1cc,mediumvioletred,0xc71585,midnightblue,0x191970,mintcream,0xf5fffa,mistyrose,0xffe4e1,moccasin,0xffe4b5,navajowhite,0xffdead,navy,0x000080,oldlace,0xfdf5e6,olive,0x808000,olivedrab,0x6b8e23,orange,0xffa500,orangered,0xff4500,orchid,0xda70d6,palegoldenrod,0xeee8aa,palegreen,0x98fb98,paleturquoise,0xafeeee,palevioletred,0xdb7093,papayawhip,0xffefd5,peachpuff,0xffdab9,peru,0xcd853f,pink,0xffc0cb,plum,0xdda0dd,powderblue,0xb0e0e6,purple,0x800080,red,0xff0000,rosybrown,0xbc8f8f,royalblue,0x4169e1,saddlebrown,0x8b4513,salmon,0xfa8072,sandybrown,0xf4a460,seagreen,0x2e8b57,seashell,0xfff5ee,sienna,0xa0522d,silver,0xc0c0c0,skyblue,0x87ceeb,slateblue,0x6a5acd,slategray,0x708090,snow,0xfffafa,springgreen,0x00ff7f,steelblue,0x4682b4,tan,0xd2b48c,teal,0x008080,thistle,0xd8bfd8,tomato,0xff6347,turquoise,0x40e0d0,violet,0xee82ee,wheat,0xf5deb3,white,0xffffff,whitesmoke,0xf5f5f5,yellow,0xffff00,yellowgreen,0x9acd32,";
and the matching global meta
// #frontAll
// #frontAmbient
// #frontDiffuse
// #frontSpecular

// #leftAll
// #leftAmbient
// #leftDiffuse
// #leftSpecular

// #rightAll
// #rightAmbient
// #rightDiffuse
// #rightSpecular

Thus
#frontAll aliceblue
will use the same 0xf0f8ff RGB color for the 3 front light parameters.



Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 17, 2018, 03:09:44 pm
Quote
I already reworked it, that way

Your own way is not always the best way, you know. When in Rome, do as the Romans do. (c)   (let alone code elegance, now count how many if's there are in your solution and then count the same in everybody else's -- the one that I suggested. Oh c'mon Patrice, don't be so stubborn! ;) )

Quote
... waiting for the new billboard ;)

Your mockery is somewhat untimely, my friend. ;) Look what your ObjReader stores in its mesh structures as meshRadius'es for the five exact same flare meshes you saw in the previous screenshot.  ;D

Needless to say my Objector wouldn't permit itself such frivolities. Not in my presence.  :D

Quote
Thus
#frontAll aliceblue
will use the same 0xf0f8ff RGB color for the 3 front light parameters.

EXCELLENT!
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 17, 2018, 03:33:24 pm
Quote
Look what your ObjReader stores in its mesh structures as meshRadius'es for the five exact same flare meshes you saw in the previous screenshot

I must say that i do not understand, nothing has been changed in this specific part of the code since the origine.
And this model has not been reworked into c4d, would be interresting to import/export inside of it, and see the result.
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 17, 2018, 03:53:19 pm
Quote
... nothing has been changed in this specific part of the code ...

I am not trying to blame you for this, Patrice. :)

Seriously, Objector uses the exact same C code in its calcMeshBounds() and everything's all right with it. There are evidently some other code permutations somewhere in ObjReader that affect the pMesh structure content adversely. We're using meshRadius'es in our mesh visibility checks. I'm currently trying to find out if ObjReader's C code might abuse the radius values in the process (Objector has its visibility checks written in assembly).
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 17, 2018, 03:58:25 pm
Oh, and I think there's no need for separate #frontAmbient, #frontDiffuse, etc. metacommands. Just let's have e.g.

#frontAll aliceblue

but for separate values lets have e.g.

#front aliceblue antiquewhite aquamarine

in the abmbient/diffuse/specular order.

I think this notation will match other statements of Wavefront Object vocabulary perfectly.  8)


P.S. Oh no no! Let them also stay for the cases e.g.

#frontDiffuse  255 255 0

where the per-component RGB's should be specified precisely!  :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 17, 2018, 04:28:59 pm
OK, i shall use IsAlpha or something like that, to parse correctly the string

Added:
Ideally we should have a command to save the light settings into the mtl file...
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 17, 2018, 07:51:22 pm
Ideally we should have a command to save the light settings into the mtl file...

Actually I like the way you're thinking now, Patrice, and I'm glad I lived long enough to see it happen. :)

I've always told you that having these things just as toy renderers would be a waste of time and effort. They should be equipped with adequate (editing) instruments to adjust what we're seeing on our monitors and save our adjustments for future use. :)

P.S. Tell you more.

Ultimately, we should also have a possibility to directly edit the material file in its other aspects, immediately discard the older material settings, reload the newly edited materials, and apply them to their respective meshes while the model stays on screen.

I think that when such an option is implemented, you'll be spending more time in front of your ObjReader than you're spending now in your C4D. 8)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 18, 2018, 06:02:18 am
 ;D ;D ;D ;D    :D :D :D :D   ;) ;) ;) ;)    :) :) :) :)    8) 8) 8) 8)

ObjReader's original Mobj_bounds() initialization code caused FPU overflow that made both model and mesh radii undefined. One may not evaluate a float for > 3.40000009536743e+38f (a.k.a. FLT_MAX) or < 8.43000030517578e-37f (a.k.a. FLT_MIN).

My calcMeshBounds() was a literal replica of your Mobj_bounds() and quite naturally made the same mistake.

_____________________________________________________

(took me 18+ hours to isolate...  :o  you owe me a few beers...  ::) )
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 18, 2018, 09:25:40 am
Dear Mike, i am very glad you found it, because i wouldn't have been able to diagnose this myself  8)

In the original code Mobj_bounds was defined like this:

Code: [Select]
void Mobj_bounds(float rCenter[3], float &rWidth, float &rHeight, float &rLength, float &rRadius) {

    float rxMax = 8.43000030517578e-37f;
    float ryMax = rxMax;
    float rzMax = rxMax;

    float rxMin = 3.40000009536743e+38f;
    float ryMin = rxMin;
    float rzMin = rxMin;

    float rX = 0.0f, rY = 0.0f, rZ = 0.0f;

    long numVerts = Mobj_getNumberOfVertices();

    for (long nI = 0; nI < numVerts; ++nI) {
        rX = gtm_vertexBuffer[nI].position[0];
        rY = gtm_vertexBuffer[nI].position[1];
        rZ = gtm_vertexBuffer[nI].position[2];

        if (rX < rxMin) { rxMin = rX; }
        if (rX > rxMax) { rxMax = rX; }
        if (rY < ryMin) { ryMin = rY; }
        if (rY > ryMax) { ryMax = rY; }
        if (rZ < rzMin) { rzMin = rZ; }
        if (rZ > rzMax) { rzMax = rZ; }
    }

    rCenter[0] = (rxMin + rxMax) / 2.0f;
    rCenter[1] = (ryMin + ryMax) / 2.0f;
    rCenter[2] = (rzMin + rzMax) / 2.0f;

    rWidth = rxMax - rxMin;
    rHeight = ryMax - ryMin;
    rLength = rzMax - rzMin;

    rRadius = max(max(rWidth, rHeight), rLength);
}

However, in the calcMeshBounds version, we are using since 03-14-2016
rxMax = FLT_MIN
rxMin = FLT_MAX
And the constant values are defined into float.h, like this:
#define FLT_MIN          1.175494351e-38F        // min normalized positive value
#define FLT_MAX          3.402823466e+38F        // max value

Code: [Select]
/////////////////////////
// V I S I B I L I T Y //  // ML: 03-14-2016
/////////////////////////

void calcMeshBounds() {
    MobjMesh* pMesh;
    float rX, rY, rZ;
    long nI, nJ, nK;

    for (nI = 0; nI < gnm_numberOfMeshes; nI++) {
        float rxMax = FLT_MIN; // close to -INF
        float ryMax = rxMax;
        float rzMax = rxMax;

        float rxMin = FLT_MAX; // close to +INF
        float ryMin = rxMin;
        float rzMin = rxMin;

        pMesh = &gtm_meshes[nI];
        for (nJ = 0; nJ < pMesh->triangleCount * 3; nJ++) {
            nK = gnm_indexBuffer[pMesh->startIndex + nJ];

            rX = gtm_vertexBuffer[nK].position[0];
            rY = gtm_vertexBuffer[nK].position[1];
            rZ = gtm_vertexBuffer[nK].position[2];

            if (rX < rxMin) { rxMin = rX; } else if (rX > rxMax) { rxMax = rX; }
            if (rY < ryMin) { ryMin = rY; } else if (rY > ryMax) { ryMax = rY; }
            if (rZ < rzMin) { rzMin = rZ; } else if (rZ > rzMax) { rzMax = rZ; }
        }

        pMesh->centerPoint[0] = (rxMin + rxMax) * 0.5f;
        pMesh->centerPoint[1] = (ryMin + ryMax) * 0.5f;
        pMesh->centerPoint[2] = (rzMin + rzMax) * 0.5f;

        float rWidth = rxMax - rxMin;
        float rHeight = ryMax - ryMin;
        float rLength = rzMax - rzMin;

        pMesh->meshRadius = max(max(rWidth, rHeight), rLength);
    }
}

void normalizeVec(float v[4]) {
    float mult = 1 / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
    v[0] *= mult;
    v[1] *= mult;
    v[2] *= mult;
    v[3] *= mult;
}

void Mobj_CreateFrustum(float frust[6][4]) {
    long nI;
    float proj[16];
    float modl[16];
    float clip[16];
    float m0, m1, m2, m3;

    // Get current matrices
    glGetFloatv(GL_PROJECTION_MATRIX, proj);
    glGetFloatv(GL_MODELVIEW_MATRIX, modl);

    // Combine them (mult *modl* by *proj* into *clip*)
    for (nI = 0; nI < 4; nI++) {
        m0 = modl[nI * 4 + 0];
        m1 = modl[nI * 4 + 1];
        m2 = modl[nI * 4 + 2];
        m3 = modl[nI * 4 + 3];
        clip[nI * 4 + 0] = m0 * proj[0] + m1 * proj[4] + m2 * proj[8]  + m3 * proj[12];
        clip[nI * 4 + 1] = m0 * proj[1] + m1 * proj[5] + m2 * proj[9]  + m3 * proj[13];
        clip[nI * 4 + 2] = m0 * proj[2] + m1 * proj[6] + m2 * proj[10] + m3 * proj[14];
        clip[nI * 4 + 3] = m0 * proj[3] + m1 * proj[7] + m2 * proj[11] + m3 * proj[15];
    }

    // Build frustum
    frust[0][0] = clip[3]  - clip[0];
    frust[0][1] = clip[7]  - clip[4];
    frust[0][2] = clip[11] - clip[8];
    frust[0][3] = clip[15] - clip[12];
    normalizeVec(&frust[0][0]); // normalize here for sphere test!!!

    frust[1][0] = clip[3]  + clip[0];
    frust[1][1] = clip[7]  + clip[4];
    frust[1][2] = clip[11] + clip[8];
    frust[1][3] = clip[15] + clip[12];
    normalizeVec(&frust[1][0]); // normalize here for sphere test!!!

    frust[2][0] = clip[3]  + clip[1];
    frust[2][1] = clip[7]  + clip[5];
    frust[2][2] = clip[11] + clip[9];
    frust[2][3] = clip[15] + clip[13];
    normalizeVec(&frust[2][0]); // normalize here for sphere test!!!

    frust[3][0] = clip[3]  - clip[1];
    frust[3][1] = clip[7]  - clip[5];
    frust[3][2] = clip[11] - clip[9];
    frust[3][3] = clip[15] - clip[13];
    normalizeVec(&frust[3][0]); // normalize here for sphere test!!!

    frust[4][0] = clip[3]  - clip[2];
    frust[4][1] = clip[7]  - clip[6];
    frust[4][2] = clip[11] - clip[10];
    frust[4][3] = clip[15] - clip[14];
    normalizeVec(&frust[4][0]); // normalize here for sphere test!!!

    frust[5][0] = clip[3]  + clip[2];
    frust[5][1] = clip[7]  + clip[6];
    frust[5][2] = clip[11] + clip[10];
    frust[5][3] = clip[15] + clip[14];
    normalizeVec(&frust[5][0]); // normalize here for sphere test!!!
}

long isSphereInFrustum(float frustum[6][4], float center[3], float radius) {
    long nI;

    for (nI = 0; nI < 6; nI++) {
        float distance = frustum[nI][0] * center[0] + frustum[nI][1] * center[1] + frustum[nI][2] * center[2] + frustum[nI][3];
        if (distance < -radius * 0.5f) return 0;
    }
    return 1;
}
/////////////////////////

I already come accross this bug a few time, with the mesh becoming invisible...
I can make a video to show you how to replicate the problem with Tron.obj when swaping the Y,Z axes.
The front light become invisible when zooming in.

What are the new values you use now ?
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 18, 2018, 12:25:31 pm
Hi Patrice,

I'm also glad we've killed that beast of a bug! 8)

Two answers:

The short one: just use a pair of reasonably large and small values. I'm currently using -/+ 1,000,000.0f (w/o comma separators). I've never seen a vertex whose coords would exceed, say, -/+10,000.f on any axis even in the world coordinate system. This is usually the maximum setting of view frustum's far Z plane when observing vast 3D terrains with distant oceans and mountains.

The long one:

-- ObjReader's code is built around floats. Objector's 100% compatible C code is built around doubles. This is because it's tightly interleaved with high-level interpreted BASIC procedures for non-time critical parts of the program flow. BASIC interpreters historically use doubles for their floating point calc, and FBSL is no exception to this rule.

-- FPU casts in C are very costly because they aren't just textual preproc directives. Each such cast is rather coded by the compiler into a chain of FPU instructions to be executed by the FPU module on the processor's VLSI chip at run time(so use floating-point casts sparingly in your C code if you're after the fastest code possible!)

-- Consequently, Objector uses a double-precision set of C trig library and OpenGL functions like sin(), cos(), glNormal3d, glVertex3d, etc. where ObjReader would use single precision glNormal3f, glVertex3f and sinf(), cosf(), etc. overloads.

-- Mobj-bounds()'s original 8.43000030517578e-37f/3.40000009536743e+38f (FLT_MIN/FLT_MAX) are perfectly OK for Objector that runs in double precision but appeared too much for the FPU under the MS VC compiler digesting the ObjReader's sources.

-- Apart from different value ranges for single and double precision, the compiler may choose different sets of FPU instructions to machine-code the C sources with. FBSL's C JIT compiler prefers to use the faster set of FPU instructions that neglect FPU overflows and automatically and transparently recover the FPU state back to normal after the overflow occurs. Apparently the MS VC compiler prefers to follow another strategy under similar circumstances.

Seriously, a bug of such type would be difficult to crack for a casual C programmer. We are lucky to have a compiler developer in our ranks, even if for just one such latent bug in the entire set of ObjReader sources. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 18, 2018, 12:38:40 pm
And yes, please show me that glitch in WIP Trone.

I will probably also use that opportunity to explain why we're seeing so much z-buffer fighting in nearly every model exported as-is to OBJ files from LightWave, 3DS Max and other professional 3D editors.

P.S. No need for the video, Patrice. I'm seeing this glitch here too once my Y/Z axes are swapped in ObjReader or Objector alike. I'll look into a possible cause and will come back later with my findings. Evidently there's some spatial parameter or calc we overlooked to refresh after swapping the "up" direction. By the looks of it, it is our visibility code that mistakenly switches this mesh off.
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 18, 2018, 02:00:36 pm
Thank you for the heads up!

I am still working onto the new mtl lighting material, and took the decision to use these:

#Light frontAll 1 2 3
#Light frontAmbient aliceblue
#Light frontDiffuse antiquewhite
#Light frontSpecular 255 255 240

they are all prefixed with #Light to easily detect that it is a lighting parameter.

Added:
I shall have to move the new color macro definition into mobj.h, to setup lightings from the mtl file.

Question:
why do you divide the byte color by 256 rather than 255?
r / 256.0f;
for example if the red byte is 255, the float value should be 1.0f rather than 0.9960937f
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 18, 2018, 05:21:44 pm
... took the decision to use these:

That's a very wise decision. I like it.

Quote
I shall have to move the new color macro definition into mobj.h, to setup lightings from the mtl file.

Do as appropriate to make the new code work with minimum mods to the rest of project. When we have nothing else to do, we'll reshuffle the declarations and implementations in such a way that everything that is OBJ format specific will go into mobj.h, and everything that pertains to the bare-bones loader and renderer will be grouped in Main.c. And then we'll be ready to start a new m3ds.h include file and add it to the project. :)

Quote
why do you divide the byte color by 256 rather than 255?

Because I have a good friend of mine who has grinded his teeth against colors and their properties and who's gonna correct me patiently whenever he notices occasional flaws in my code. :)

Quote
... 1.0f rather than 0.9960937f

... and to whom I'm gonna give a helping hand too by silently reducing, from time to time, his wild floating point numbers (0.9960937f) to within the permissible ranges (0.996094f). :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 18, 2018, 05:37:03 pm
I think i have sorted it out, give me some more time to make sure of that.
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 18, 2018, 05:46:14 pm
Patrice,

I think I'll now try and add the billboard code to our PPL and then I'll send the sources to you for sync'ing, OK?
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 18, 2018, 06:52:39 pm
I think i am done with the lighting material.

I can wait for your code for sycing, or i can send you my current version if you want to check color material.

I shall update the white paper documentation, before i forget what i have done...

I have also the final Tron version, but i shall post officially the new 3D models only after we have a stable version 2.00  ;)
(2 extra meshes, and a new mtl file with empty color setting ready to check the new meta)

Added:
Documentation has been updated
http://www.objreader.com/index.php?topic=2.msg2323#msg2323
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 18, 2018, 10:48:27 pm
OK Patrice,

Here come the sources with the very basic implementation of Y-axis aligned cylindrical billboards.

Both FFP and PPL are supported. In fact, both pipelines now share one and the same immediate-mode billboard procedure. It should be fast enough as-is. At least, it features significantly fewer OpenGL function calls than a true GLSL geometric shader setup would require. :)

The #billboard meta now features an optional nodepth parameter that disables GL_DEPTH_TEST while drawing the billboard (or flare) quad. Sometimes it's very handy to draw e.g. elevated streetlamp flares unobscured by the surrounding foliage.

Use the following material with my Q3Flares model to see what I'm seeing in ObjReader and Objector now:

newmtl flame
#billboard nodepth
#alphatocoverage
  Ns 2
  d 0.99
  illum 2
  Kd 0 0 0
  Ka 0 0 0
  Ks 0 0 0
  Ke 1 1 1
  map_Kd flare.png


Try it also without the keyword nodepth in the #billboard statement. Use the flare image in the zip. (in fact the flare file is yours)

Enjoy and keep me informed. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 19, 2018, 09:30:29 am
Here is the merged version.

I have checked the new cylindrical biilboard, and that works great.
I think we should have more option to allow the exact replication of what i have done into my 3D Chart (to have the quads always facing the camera for the purpose of cheap spherical bubble effect). That would be also very handy to display a text legend.

About IPS/FPS, i am keeping the IPS wording, because of the specific refresh rate used in ObjReader, that is based on the low priority message WM_TIMER, and half the real display LCD refresh rate, giving a maximum IPS of 32-34 while in demo mode. This has been done by design to limit the CPU impact.

I shall post a new Tron project to let you play with the new light settings.

For the billboard options we could have:
- Flat (default, always facing the camera)
- Cylindrical (just like what you have done)
- Spherical

Your thought?

And thank you again for all your hard work to diagnose (and have solved) the billboard problem !!!


Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 19, 2018, 01:46:38 pm
Please add this to protect us from GPF

Unhandled exception at 0x00007FFEE6EA765C (ucrtbased.dll) in ObjReader64.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.
Quote
    _Check_return_opt_
    _CRT_STDIO_INLINE int __CRTDECL _vfscanf_l(
        _Inout_                       FILE*       const _Stream,
        _In_z_ _Printf_format_string_ char const* const _Format,
        _In_opt_                      _locale_t   const _Locale,
                                      va_list           _ArgList
        )
    #if defined _NO_CRT_STDIO_INLINE
    ;
    #else
    {
        return __stdio_common_vfscanf(
            _CRT_INTERNAL_LOCAL_SCANF_OPTIONS,
            _Stream, _Format, _Locale, _ArgList);
    }
    #endif


        case '#': // PAT: 01-07-2018 meta specific for material
            if (strcmp(szBuffer, "#alphatocoverage") == 0) {
                if (Mobj_AlphaToCoverage(0, 0) == 0) {
                    pMaterial->isA2C = -1;
                }
            } else if(strcmp(szBuffer, "#billboard") == 0) {
                pMaterial->isBillboard = -1;
                fgets(szBuffer, sizeof(szBuffer), pFile); // ML 01-18-2018: look for *optional* GL_DEPTH_TEST flag!
                CharLowerA(szBuffer);
                if (strstr(szBuffer, "nodepth") != 0) {
                    pMaterial->isBillboard = -2;
                } else {
                    fseek(pFile, -(long)strlen(szBuffer), SEEK_CUR); // ML 01-18-2018: rewind if no *such* flag found! If not
                }                                                    // rewound, fgets() may have chomped a meaningful keyword!
            } else {
                fgets(szBuffer, sizeof(szBuffer), pFile);
            }
            break;
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 19, 2018, 02:15:45 pm
Mike

Could you check the new Mobj_SetLightColor()
I am not sure of the best way to setup and use the new macro...

When using lighting materials i would like that all the matching parameters be set to VISIBLE mode at startup.

Code: [Select]
void Mobj_SetLightColor() {
    BYTE a, r, g, b;
    DWORD dwStyle = 0;
    if (gP.frontall) {
        zSplitColorARGB(gP.frontall, a, r, g, b);
        gP.light0ColorAll = false;
        DOCOLORALL(0);
        DOLIGHTON(0, 1, 2);
        DOCOLORCHEAP(0);
    } else {
        if (gP.frontambient) {
            zSplitColorARGB(gP.frontambient, a, r, g, b);
            DOLIGHTON(0, 1, 2);
            SETCOLORAMB(0);
        }
        if (gP.frontdiffuse) {
            zSplitColorARGB(gP.frontdiffuse, a, r, g, b);
            DOLIGHTON(0, 1, 2);
            SETCOLORDIF(0);
        }
        if (gP.frontspecular) {
            zSplitColorARGB(gP.frontspecular, a, r, g, b);
            DOLIGHTON(0, 1, 2);
            SETCOLORSPEC(0);
        }
    }

    if (gP.leftall) {
        zSplitColorARGB(gP.leftall, a, r, g, b);
        gP.light1ColorAll = false;
        DOCOLORALL(1);
        DOLIGHTON(1, 0, 2);
        DOCOLORCHEAP(1);
    } else {
        if (gP.leftambient) {
            zSplitColorARGB(gP.leftambient, a, r, g, b);
            DOLIGHTON(1, 0, 2);
            SETCOLORAMB(1);
        }
        if (gP.leftdiffuse) {
            zSplitColorARGB(gP.leftdiffuse, a, r, g, b);
            DOLIGHTON(1, 0, 2);
            SETCOLORDIF(1);
        }
        if (gP.leftspecular) {
            zSplitColorARGB(gP.leftspecular, a, r, g, b);
            DOLIGHTON(1, 0, 2);
            SETCOLORSPEC(1);
        }
    }

    if (gP.rightall) {
        zSplitColorARGB(gP.rightall, a, r, g, b);
        gP.light2ColorAll = false;
        DOCOLORALL(2);
        DOLIGHTON(2, 0, 1);
        DOCOLORCHEAP(2);

    } else {
        if (gP.rightambient) {
            zSplitColorARGB(gP.rightambient, a, r, g, b);
            DOLIGHTON(2, 0, 1);
            SETCOLORAMB(2);
        }
        if (gP.rightdiffuse) {
            zSplitColorARGB(gP.rightdiffuse, a, r, g, b);
            DOLIGHTON(2, 0, 1);
            SETCOLORDIF(1);
        }
        if (gP.rightspecular) {
            zSplitColorARGB(gP.rightspecular, a, r, g, b);
            DOLIGHTON(2, 0, 1);
            SETCOLORSPEC(2);
        }
    }
}

Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 19, 2018, 02:53:49 pm
Thanks Patrice,

Merged successfully.

Re: GPF

Done as advised, thanks for the fix!

Re: billboards

Spherical billboards are the ones that are always facing the camera as your bubbles and more realistic light flares do; cylindrical ones are primarily meant to emulate distant vegetation and monsters. And yes, the spherical ones are also suitable to display dynamically moving text legends. These are going to be my next task. The #billboard statement syntax will be expanded accordingly.

Flat billboards are to be "torn" from their models at run time (view time) and glued flat and immobilized to the predefined screen coords, like your Onyx plate did in your first experiments. In fact, these are a kind of model's own HUDs that exist on the screen without the viewer's assistance or control. They will be the last ones to implement because they aren't our immediate necessity.

Re: Tron

It's a pity you haven't preloaded the #light metacommands with some initial values other than the default lighting. Yes, I can generate some acid colors myself but I can't do it as good as you do. :)

Re: IPS

Of course you're in your own right to take the final decision on your counter's implementation, mon ami. But doin't blame me when I'm referring to Fraps citing your ObjReader's official FPS rate at some future point in time. ;)

Re: thanks

It is my pleasure and honor to be working with you on this project. :)
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 19, 2018, 03:07:46 pm
Re: Mobj_SetLightColor()

Frankly, I was planning to go out for a few hours. Can it wait till later in the evening? (we are here 3 hours ahead of your local time)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 19, 2018, 04:33:23 pm
Quote
But doin't blame me when I'm referring to Fraps citing your ObjReader's official FPS rate at some future point in time

While in "Demo mode", the nVIDIA FPS and my IPS are almost identical, and on Windows 10 there is no FRAPS ;)
Title: Re: Peugeot-Onyx (concept car)
Post by: Patrice Terrier on January 19, 2018, 05:14:43 pm
I am slowly making my way to setup correctly the colors from the mtl file...

Here is the new Mobj_SetLightColor to use
Code: [Select]
void Mobj_SetLightColor() {
    BYTE a, r, g, b;
    DWORD dwStyle = 0;
    bool IsVisible = false;
    if (gP.frontall) {
        zSplitColorARGB(gP.frontall, a, r, g, b);
        IsVisible = true;
        DOCOLORCHEAP(0);
    } else {
        if (gP.frontambient) {
            zSplitColorARGB(gP.frontambient, a, r, g, b);
            IsVisible = true;
            SETCOLORAMB(0);
        }
        if (gP.frontdiffuse) {
            zSplitColorARGB(gP.frontdiffuse, a, r, g, b);
            IsVisible = true;
            SETCOLORDIF(0);
        }
        if (gP.frontspecular) {
            zSplitColorARGB(gP.frontspecular, a, r, g, b);
            IsVisible = true;
            SETCOLORSPEC(0);
        }
    }
    if (IsVisible) {
        gP.isLight0_On = IsVisible;
        CheckMenuItem(gP.hLight0Menu, MENU_LIGHT0_ON, MF_CHECKED);
        gP.nLightFlags |= (1 << (0)); /* bin 001, 010, or 100 ==> dec 1, 2, or 4 ==> (1 << (0)) */
    }

    if (gP.leftall) {
        zSplitColorARGB(gP.leftall, a, r, g, b);
        gP.light1ColorAll = false;
        DOCOLORALL(1);
        DOLIGHTON(1, 0, 2);
        DOCOLORCHEAP(1);
    } else {
        if (gP.leftambient) {
            zSplitColorARGB(gP.leftambient, a, r, g, b);
            DOLIGHTON(1, 0, 2);
            SETCOLORAMB(1);
        }
        if (gP.leftdiffuse) {
            zSplitColorARGB(gP.leftdiffuse, a, r, g, b);
            DOLIGHTON(1, 0, 2);
            SETCOLORDIF(1);
        }
        if (gP.leftspecular) {
            zSplitColorARGB(gP.leftspecular, a, r, g, b);
            DOLIGHTON(1, 0, 2);
            SETCOLORSPEC(1);
        }
    }

    if (gP.rightall) {
        zSplitColorARGB(gP.rightall, a, r, g, b);
        gP.light2ColorAll = false;
        DOCOLORALL(2);
        DOLIGHTON(2, 0, 1);
        DOCOLORCHEAP(2);
    } else {
        if (gP.rightambient) {
            zSplitColorARGB(gP.rightambient, a, r, g, b);
            DOLIGHTON(2, 0, 1);
            SETCOLORAMB(2);
        }
        if (gP.rightdiffuse) {
            zSplitColorARGB(gP.rightdiffuse, a, r, g, b);
            DOLIGHTON(2, 0, 1);
            SETCOLORDIF(2);
        }
        if (gP.rightspecular) {
            zSplitColorARGB(gP.rightspecular, a, r, g, b);
            DOLIGHTON(2, 0, 1);
            SETCOLORSPEC(2);
        }
    }
}
Title: Re: Peugeot-Onyx (concept car)
Post by: Michael Lobko-Lobanovsky on January 20, 2018, 04:03:57 am
If you tell me again you don't want such beautiful emissive boosters for your Ramjet, I am not going to believe you. ;)