Author Topic: Material Batching  (Read 1608 times)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Material Batching
« on: July 21, 2018, 07:26:24 pm »
Merging meshes in the absence of smoothing groups blurs the meshes' normals that, when recalculated for the new shapes that you thus create, tend to acquire orientations which weren't present in the distinct originals.

You may continue to ignore this fact or again prefer to minimize its impact on the model by adding extra millions of polies to the original model by subdivision as you do now. But you can't eliminate all the artifacts completely; some normal blur will still reside somewhere in the model no matter what you do for as long as you disregard smoothing groups.

OTOH preserving the numerous original meshes may over-stress the renderer that has to set up and reset continuously the pipeline for many more mesh-specific materials (textures, lighting and shaders) than is actually necessary. The mesh-specific materials may in fact appear to be one and the same base material (the one you're using to merge the meshes with). In this way, hundreds if not thousands of extra (and basically unnecessary) state changes (i.e. glXXXX function calls) are made in every frame rendered.

This can be corrected by what is called "material batching" as described below.

1. On loading, the meshes are sorted out in such a way that those of them which have the same base material are grouped to come one after another in the thus sorted mesh list.

2. Render procs are re-written in such a way that everything that comes after the glDrawElements() call (that's effectively the OpenGL state machine reset sequence of glXXXX function calls) appears at the very beginning of respective render procs -- before the state machine set sequence (textures/lighting/shaders).

3. If a material change is detected at the top of the mesh rendering loop iteration, then the state machine is first reset and then set to match the new material as it does now.

4. If no change in the current material is detected, then the state machine reset/set function calls are bypassed as necessary, and the glDrawElements() call occurs almost immediately thus sparing us a few dozens extra function calls in each iteration.


Do you think you will be able to implement material batching in ObjReader without my assistance following the above strategy, Patrice? This optimization could have a very good impact on our renderers.

(And yes, I would like to have the unmerged version too, please.)
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 951
    • zapsolution
Re: Material Batching
« Reply #1 on: July 21, 2018, 09:44:12 pm »
Here is the unmerged version with 143 meshes rather than 60, i shall bet that you won't see absolutly no difference, except for the size of the .obj file that is slightly bigger, and for the duplicated material names shown into the listview.

The .rar file doesn't comprise the textures, because they are the same, thus you can put the 2 versions into the same folder.

All the UV mapping have been reworked into c4d to produce the best result, and symmetry has been applied only after the UVW mapping has been computed using optimal angle alignment or optimal cubic mapping, this is one of the reason why it tooks me so much time to produce each of the OR's version, all the textures are first created in PSD with the corresponding transparent UV Mesh layer before producing the resulting .png, and i am using my own AlphaMask utility to produce complex transparent material (the hair texture of the supergirl is a good example of it).

Added:
Forget to say that the original had much more meshes than the 160 (indeed 5000 elements). Each bolt and nut was a distinct mesh !!!
« Last Edit: July 22, 2018, 08:50:11 am by Michael Lobko-Lobanovsky »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Re: Material Batching
« Reply #2 on: July 22, 2018, 08:49:46 am »
So, I guess this makes a "No!" in response to my question. :)

I wasn't mocking you or something; I just asked if you would like to switch over to programming for a change. I still think we could benefit greatly from this optimization and it could also spare you a lot of work you do merging the meshes. I acknowledge and appreciate the tremendous amount of work you're doing on every model you add to the collection.

Regarding separate bolts and nuts, it's an indication the model has been designed using a CAD system rather than some 3D sculpting software where you would deal with just one big piece of imaginary "clay". Besides being production ready, the separate meshes of CAD models are very easy to rig and animate for 3D gaming purposes, while merged meshes are going to preclude this even if we want to do it some time in the future.

Thank you for the model. I DL'ed it successfully and removed the zips.
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 951
    • zapsolution
Re: Material Batching
« Reply #3 on: July 22, 2018, 11:02:44 am »
Quote
So, I guess this makes a "No!" in response to my question.
As i said, i can't see any visual difference between the two versions, so i don't think it is worth the extra work, but if you think that it could provide an effective visual enhancement my answer is yes.  :)

If you want i can send you the one with 5000 elements, for stress purpose  ;)
I can make it a .fbx version if you want ?

When working in c4d, i could systematically sort all the meshes to match their specific materials, that could also save the extra work.

What i would like to focus next on my list, is the binary format to speed up the loading of huge models, as i wrote here:
http://www.objreader.com/index.php?topic=163.0

Quote
the separate meshes of CAD models are very easy to rig and animate for 3D gaming purposes
Do you know this Samsung video
https://www.youtube.com/watch?v=i8g_Z4_DkXI
This is something that could be done on complex models in introduction, to show all the hidden meshes, using the same approach than for rotation, that would be a great effect  8)


« Last Edit: July 22, 2018, 11:28:54 am by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Re: Material Batching
« Reply #4 on: July 23, 2018, 09:39:38 pm »
Incidentally, I do have a few starship models with huge numbers of distinct meshes in them but very low base material counts. Perfect for testing purposes when and if we proceed with the material batching optimization. :)

(Note the extremely low FPS rate due to hundreds of thousands of unnecessary extra function calls in each frame render)
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 951
    • zapsolution
Re: Material Batching
« Reply #5 on: July 23, 2018, 10:45:29 pm »
This one shows up at 75 FPS by me, as you can see on the attached video ???
with 165 meshes (rather than 32200) and 28 materials.

This is because i always load first the project into c4d, before saving it back to the a new .obj file.
Other way i would have also a rate of only 16 FPS.
« Last Edit: July 23, 2018, 11:02:29 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Re: Material Batching
« Reply #6 on: July 23, 2018, 11:34:21 pm »
75 FPS is for 165 rather than 32K meshes -- 200 times fewer meshes all in all, hence such a high frame rate. 16 FPS for 32K meshes against my 9 FPS is because your GPU has considerably more parallel graphics processors than mine.

Each one of 32,200 meshes requires ca. 35 OpenGL function calls to set up and reset its material, thus totaling over 1.1 mln unnecessary function calls of which only 35 function calls * 28 materials = 980 function calls are actually needed. No wonder the FPS rate is so low. I bet any other renderer would just drop dead against such a mesh count unless it supports material batching. 8)

___________________________________________


By the way, why does your ObjReader display the Mesh Animation check box in the video? This model has no animated meshes, to the best of my knowledge...
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 951
    • zapsolution
Re: Material Batching
« Reply #7 on: July 24, 2018, 12:03:20 am »
Fortunatly, with the help of c4d i am already doing some kind of material batching automatically, or we couldn't render the highly detailed McLaren 570s at 75 FPS.

BTW, these starship models have several small glitches that need to be fixed as usual  8)
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Re: Material Batching
« Reply #8 on: July 24, 2018, 01:53:57 am »
Some day you may find it desirable to:
  • switch to another -- better -- 3D editor that, alas, has no "automatic" batching side effect; and/or
  • not bother about mesh merging at all because ObjReader is optimized to do material batching fully automatically.
;)

Now please tell me still why I am seeing the Mesh Animation check box displayed for a static model?
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 951
    • zapsolution
Re: Material Batching
« Reply #9 on: July 24, 2018, 09:34:54 am »
Quote
Now please tell me still why I am seeing the Mesh Animation check box displayed for a static model?
Probably because of switching between full screen and window mode.
We should not show this control when restoring the window size, and check the gP.nRotation status, i shall fix it asap.

Added:
Here is the fix

void ToggleFullScreen() {

    static DWORD savedExStyle, savedStyle, screenWidth, screenHeight;
    static long OverLayVisible, AnimationVisible; // PAT: 02-05-2018
    static RECT rcSaved;
    static HRGN oldRgn = 0, newRgn = 0;
    long K = 0, nLeft = 0, nTop = 0;
    WINDOWPLACEMENT wp = { 0 };

    gP.nIsFullScreen = !gP.nIsFullScreen;

    if (GetWindowPlacement(gP.hMain, &wp)) { // 04-20-2015
        if (wp.showCmd == SW_SHOWMAXIMIZED) {
            //ShowWindow(gP.hMain, SW_RESTORE);
            skRestore(gP.hMain);
        }
    }

    if (gP.nIsFullScreen) { // Moving to full screen mode.
        long wasFPS = gP.nUseFPS; if (gP.nUseFPS) { gP.nUseFPS = 0; }

        GetWindowRgn(gP.hMain, oldRgn);

        GetWindowRect(gP.hMain, &rcSaved);

        AnimationVisible = IsWindowVisible(GetDlgItem(gP.hMain, IDC_ANIMATION));

        for (K = IDC_FIRST; K <= IDC_LAST; K++) {
            ShowWindow(GetDlgItem(gP.hMain, K), SW_HIDE);
        }
        OverLayVisible = IsWindowVisible(gP.hOverlay);

        // 01-05-2016 Changes to get rid of flickering in full screen mode
        //SetWindowPos(gP.hMain, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW);        // PAT: 02-12-2018
        //if (OverLayVisible) { // PAT: 02-11-2018                                                                              // PAT: 02-12-2018
        //    SetWindowPos(gP.hOverlay, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW); // PAT: 02-12-2018
        //}

        MONITORINFO tmi = { 0 };
        RECT rw = { 0 };
        HMONITOR hMonitor = MonitorFromWindow(gP.hMain, MONITOR_DEFAULTTONEAREST);
        tmi.cbSize = sizeof(tmi);
        GetWindowRect(gP.hMain, &rw);
        GetMonitorInfo(hMonitor, &tmi);
        screenWidth = abs(tmi.rcMonitor.right - tmi.rcMonitor.left);
        screenHeight = abs(tmi.rcMonitor.bottom - tmi.rcMonitor.top);
        nLeft = skGetSystemMetrics(SK_CXFRAMELEFT);
        nTop = skGetSystemMetrics(SK_CYCAPTION) + skGetSystemMetrics(SK_CYMENU);
        //rw.left = tmi.rcMonitor.left - nLeft + 1; // Pat: 01-05-2016
        rw.left = tmi.rcMonitor.left - nLeft; // Pat: 03-23-2016
        rw.top = tmi.rcMonitor.top - nTop; // Pat: 01-05-2016
        long RightPanelSize = ClientW - ClientWGL;

        // PAT: 02-06-2018 without minus Overlay, no way to let it work correctly
        // Windows do not like when an application take full control of the whole view port...
        rw.right = screenWidth + nLeft + skGetSystemMetrics(SK_CXFRAMERIGHT) + RightPanelSize; //- OverLayVisible; // PAT: 02-12-2018
        rw.bottom = screenHeight + nTop + skGetSystemMetrics(SK_CYFRAMEBOTTOM);
        MoveWindow(gP.hMain, rw.left, rw.top, rw.right, rw.bottom, FALSE);

        // PAT: 02-12-2018
        SetWindowLongPtr(gP.hGL, GWL_STYLE, WS_POPUP | WS_VISIBLE);                                          // PAT: 02-12-2018
        MoveWindow(gP.hGL, 0, 0, screenWidth, screenHeight + 1, FALSE);                                      // PAT: 02-12-2018
        SetWindowPos(gP.hOverlay, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);                        // PAT: 02-12-2018
        if (IsWindow(go.hTip)) { SetWindowPos(go.hTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } // PAT: 02-12-2018

        //newRgn = CreateRectRgn(nLeft - 1, nTop, nLeft + screenWidth - OverLayVisible, nTop + screenHeight); // Pat: 01-05-2016
        newRgn = CreateRectRgn(nLeft, nTop, nLeft + screenWidth, nTop + screenHeight); // PAT: 02-06-2018
        if (newRgn) { SetWindowRgn(gP.hMain, newRgn, TRUE); }

        gP.nUseFPS = wasFPS;

    } else { // Moving back to windowed mode.

        // PAT: 02-12-2018
        SetWindowLongPtr(gP.hGL, GWL_STYLE, WS_CHILD | WS_VISIBLE);                     // PAT: 02-12-2018
        SetWindowPos(gP.hOverlay, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // PAT: 02-12-2018

        for (K = IDC_FIRST; K <= IDC_LAST; K++) {
            if ((K == IDC_ANIMATION) && (!AnimationVisible)) { continue; }
            ShowWindow(GetDlgItem(gP.hMain, K), SW_SHOW);
        }
        if (OverLayVisible) { ShowWindow(gP.hOverlay, SW_SHOW); }

        screenWidth = rcSaved.right - rcSaved.left;
        screenHeight = rcSaved.bottom - rcSaved.top;
        SetWindowRgn(gP.hMain, oldRgn, FALSE);
        SetWindowPos(gP.hMain, HWND_NOTOPMOST, rcSaved.left, rcSaved.top, screenWidth, screenHeight, SWP_SHOWWINDOW);
        if (oldRgn) { SetWindowRgn(gP.hMain, oldRgn, TRUE); }
        if (newRgn) { DeleteObject(newRgn); }
        PostMessage(gP.hMain, WM_SIZE, 0, MAKLNG(screenWidth, screenHeight));
    }
}


Quote
because ObjReader is optimized to do material batching fully automatically
If you think it should be done, then go for it, but i will keep myself reworking/combining them to better serve my needs to produce the final OR version, as i have always done since we have version 2.00.
In other word that would be useful only for the models that haven't been reworked yet by me.  ;)

« Last Edit: July 24, 2018, 12:37:26 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Re: Material Batching
« Reply #10 on: July 24, 2018, 12:58:44 pm »
Thank you very much for the fix, Patrice!

Quote
... the models that haven't been reworked yet by me.

Do you plan to live forever? :D
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 951
    • zapsolution
Re: Material Batching
« Reply #11 on: July 24, 2018, 01:52:57 pm »
Quote
Do you plan to live forever?
Of course that would be handy for the peoples wanting to use directly the .obj files downloaded from the internet.
Or to quickly check them before they are reworked to match the OR specific material file.

But the model from Mark Kingsnorth (the one you used for batching test purpose, and all the others from his web site), need to be heavily reworked to remove all the artefacts around the window bays.
In their current state, they don't match my level of espectation to figure into the OR gallery :)
« Last Edit: July 24, 2018, 06:29:59 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Re: Material Batching
« Reply #12 on: July 24, 2018, 05:02:49 pm »
Quote
In their current state, they don't match my level of espectation to figure into the OR gallery :)

Sure they don't.  8)

But if while reworking them you also incidentally merge some blasters or antennas with the hull just because they all have one and the same material, you will never be able to #rotate them around their turrets with either the metacommands or skeletal bones. :D
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 951
    • zapsolution
Re: Material Batching
« Reply #13 on: July 24, 2018, 06:19:59 pm »
Mike

Try your batching material with that file (fbx format to reduce the archive size)
http://www.objreader.com/download/demo/r3pu.zip

« Last Edit: July 24, 2018, 06:27:18 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 777
Re: Material Batching
« Reply #14 on: July 24, 2018, 07:39:24 pm »
Show me what material you're using in your .MAT file to generate that video, please.
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)