ObjReader Community

WIP => WIP => Topic started by: Patrice Terrier on January 15, 2018, 10:51:15 am

Title: Tron Light Cycle
Post by: Patrice Terrier on January 15, 2018, 10:51:15 am
Mike

Here is the "Tron Light Cycle" downloaded from Free 3D, that i started with.

The only thing i changed into this one, was to split back the original meshes to match the mtl TGA textures.
Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 15, 2018, 06:06:25 pm
Thanks Patrice,

Haha no, it doesn't look very impressive now; too low-poly indeed, isn't it?

BTW next time you come across an .LWS or .LWO please note: LightWave does not have a decent OBJ exporter. It fuses all the meshes into one huge default material though it exports the .MTL file all right. Note also your .MTL isn't original; it differs from the one exported by LightWave.

But LightWave can also export 3DS, FBX, COLLADA, and VRML97 files that go well with 3DS Max that exports its own .OBJ files very nicely. Be aware that I now own a LightWave 2015 and a 3DS Max 2015. :)

Here are a couple of draft/preview renders made in my LightWave. Hope they can help you out in your remodeling effort.
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 16, 2018, 08:21:27 pm
My reworked candidate version...

With rotating wheel illusion, while in demo mode.

(http://www.objreader.com/download/images/TRON.png)

Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 16, 2018, 08:41:46 pm
Forget to say that for me, it is still a low polygon model, even if looks much more crisp than the original.  8)
Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 16, 2018, 09:02:23 pm
Patrice,

It looks stunningly awesome even at this WIP stage! Can't wait for the final release! :D


P.S. The wheels are an absolute killer!!!  8)

P.P.S. They are hypnotically viral!!! :D
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 16, 2018, 09:33:07 pm
I must say that i am already very pleased with that WIP, may be it will become the final version afterwards. :D
Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 16, 2018, 09:40:12 pm
Nah. We are going to have true volumetric glow post-processing in our renderers one day. And that's gonna be a reason for you to come back to this model and improve it yet further to perfection.  :D
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 16, 2018, 09:54:04 pm
I am very pleased to see that you are back with me, that gives me more motivation  ;D
Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 16, 2018, 10:33:42 pm
I've been enjoying every minute we spent on this project together with you ever since we started, my friend! :)
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 19, 2018, 11:41:10 am
Here is the latest TRON model, including the c4d R17 version i have used to rework all the meshes.

The mtl file has already all the light settings meta, however without the color properties that it is up to you to customize to match your preference.

To be used, of course, with OR version 2.00 ;)

This {low} polygon model is great to check with the C++ project while in debug mode.
Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 19, 2018, 02:02:38 pm
Thanks Patrice,

Nice work! :)  Still looking forward to the final release...

-- There seems to be some kind of slight z-buffer fighting at certain angles and distances on the front side of helmet's visor. Or is it just the effect of "reflective" texturing?
-- Why there are no protector grooves or texture on the tires?
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 20, 2018, 08:13:34 pm
Mike--

Here is a WIP project, to check with the future spherical billboard.

big_flare.png should always stay above and in front of logo.png.

Also, as long as we use a quad, it would be nice to handle rectangular mesh without any square-fit stretching (just like the wallpaper background).

C4D_project.png shows you how the meshes have been put horizontally in front of the cycle, with the star flare being put slightly above the tron logo.

Note: I have added in the C++ source code a few missing predefined color constants...




Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 21, 2018, 01:22:25 am
Here is a WIP project, to check with the future spherical billboard.

big_flare.png should always stay above and in front of logo.png.

Thank you, Patrice. I hope it will stay there -- some day.

Quote
Also, as long as we use a quad, it would be nice to handle rectangular mesh without any square-fit stretching (just like the wallpaper background).

You will have to exert yourself, my friend, to see it happen.

Now I have a request. I do not understand why ObjReader's camera behaves so weird with billboards. In fact, it refuses to support any type of billboarding and moreover, it fights against it going plain wild and crazy.

Apart from the three functions from your 3D chart bubble sprite sources that you have already published here, I need two more pieces of 3D chart camera code:

1. I need your exact 3D chart render routine -- the analog to gl_DrawScene() in the ObjReader sources. All of it without any abridgments or ommissions. I must know 100% exactly in what state OpenGL is when it draws the bubbles; if it's still in a LoadIdentity(), MODELVIEW and/or PROJECTION state, before/in the process of/after the drawing of wallpaper and other geometry, if that other geometry is already translated/rotated somehow or not yet and if yes then using pure OpenGL or rather your obscure GDImage magic, etc. etc. etc.

2. I need an abstract from your 3D chart message handling routine -- the analog to ProcessMouseInput() in the ObjReader sources in what concerns the handling of WM_LBUTTONDOWN/WM_RBUTTONDOWN/WM_MBUTTONDOWN/WM_MOUSEWHEEL and the entire WM_MOUSEMOVE. In fact, all parts that modify or affect in any way the rotation angles and/or translation distances, including possible transformations in what may be the analogs to ObjReader's Mobj_normalize(), Mobj_scale() and similar.

3. I need you absolute willingness to co-operate and advise me openly and thoroughly on all other matters that may arise when I study the sources as per items 1 and 2 above. I really wouldn't like having to make blind guesses or reverse engineer your other products when writing the ObjReader code for you.

Quote
C4D_project.png shows you how the meshes have been put horizontally in front of the cycle, with the star flare being put slightly above the tron logo.

No! Billboards -- cylindrical or spherical -- should never ever be put on the ground! Their centers must always exist in the model at their exact XZ positions and Y heights where you intend to be seeing them at view time!


( If someone's camera differs from everybody else's cameras in just one pixel, degree, radian, or degree of a radian -- just as little as your FPS counter differs from mine -- then it's a lost case and the project is f*cked up beyond all repair. That someone ends up in hell with a totally custom camera that can't utilize a single bit of the entire knowledge base from the net. >:( )
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 21, 2018, 10:43:28 am
I shall make a  simplified version of the 3d chart project with everything inside of the code (no GDImage call).
For tutorial purpose, and also to remember myself how i did it  8)
I shall also reset the correct orientation into c4d (indeed it was to test something else i had in mind) simulating a cheap rotating solar system  :o

Don't be upset, we will solve this problem, so far the main difference is the origin of the rotation center that is is not in world coordinates into 3d chart, but ranging from positive 0 to 100 for the X,Y coordinates, and negative 0 to -100 for Z.
This is by design, to help the display of numeric chart values, would be interresting to see what happens if using world coordinates with it...


Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 21, 2018, 12:19:27 pm
Thank you very much, Patrice. In fact, I did sound a bit hysterical but it was because I'm spending unpardonably much time for such trivial things as billboards due to my inability to perform precise object-to-world transforms because of the model half-height displacement to better fit in the renderer viewport.

Your Tron promises to be a very attractive model. The face idea is a killer, and the implementation seems to be superb. :)

However, the face helped me trace one more latent bug. You probably noticed that the face looks warmer in PPL than in FFP. That's because the OpenGL driver uses an intrinsic shader to emulate the immediate-mode function calls that the star-like flare is drawn with. And its settings (transparent to the user) remain uninitialized affecting subsequent draw calls.

You can also notice the face going colder if you smoothly zoom in on the face with you middle button. As soon as our custom visibility clipper starts to discard the flare mesh because it is too close and low to fit into the view frustum, the face colors become darker and colder. The quick fix below cures that problem Probably, now you would want to make the face material colors a little warmer by hand in the .MAT file to compensate for the fix. :)

Code: [Select]
void Mobj_DrawUsingProgrammablePipeline(IN HWND hCheckList, IN long nSpecularMode, IN long nUseTexture) {

...................................................

doneBillboard: // ML 01-21-2018: immediate mode for billboards is emulated by the OpenGL driver with an intrinsic shader,
               // so our billboard epilogue should also include disabling client states even though we didn't enable them.
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, 0);
            glClientActiveTexture(GL_TEXTURE0);

            if (Mobj_hasNormals()) { glDisableClientState(GL_NORMAL_ARRAY); }

            if (Mobj_hasTextureCoords()) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); }

            if (Mobj_hasPositions()) { glDisableClientState(GL_VERTEX_ARRAY); }

            if (pMaterial->isA2C) { glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } // PAT: 01-07-2018
        }
    }

    glUseProgram(0);
    glDisable(GL_BLEND);
}
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 21, 2018, 02:21:34 pm
Please, post the full code of the procedure, just to make sure we are using the same.
Because i don't see any visual difference by me...
Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 21, 2018, 08:53:29 pm
Quote
Because i don't see any visual difference by me...

If you don't see the difference then you probably didn't merge my previous code with yours correctly, because the placement of doneBillboard: label was distinctly different as was the order of epilogue function calls.

But never mind, here comes the entire function code:

Code: [Select]
void Mobj_DrawUsingProgrammablePipeline(IN HWND hCheckList, IN long nSpecularMode, IN long nUseTexture) {
    MobjMesh* pMesh = 0;
    MobjMat* pMaterial = 0;

    long nI = 0, nCount = 0, nTexture = 0, nFlagBump = 0, nChecked = -1, nGlassIsUsed = 0, doSpherical = 0;
    long nFlagTextures = Mobj_enableTextures(0, 0); // ML: 11-24-2015

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    long nVertexSize = Mobj_getVertexSize();
    long nMeshes = Mobj_getNumberOfMeshes();
    float rShine = 64.0f; // 128.0f;

    long nClockwise = Mobj_gl_cw(0, 0);
    long nLights = 3; // ML 02-01-2018: keep it a uniform for when number of lights becomes per-material :)
    long nLightFlags = gP.nLightFlags & 7; // ML 02-01-2018: another uniform with respective light on/off bitfield flags

    bool doRefresh = true; // ML 01-18-2018: need or not to refresh current MODELVIEW matrix
    long isBillboard = 0; // ML 01-18-2018: faster local cache (checked twice)

    for (nI = 0; nI < nMeshes; ++nI) {
        if (IsWindow(hCheckList)) {
            nChecked = ListView_GetCheckState(hCheckList, nI);
        }
        if (nChecked) {
            pMesh = Mobj_getMesh(nI);
            pMaterial = pMesh->pMaterial;
            isBillboard = pMaterial->isBillboard; // ML 01-18-2018:

            if (!isSphereInFrustum(grm_frustum, pMesh->centerPoint, pMesh->meshRadius)) continue; // ML: 03-14-2016

            if (pMaterial->isA2C) { glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } // PAT: 01-07-2018

            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, pMaterial->ambient);
            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pMaterial->diffuse);
            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, pMaterial->specular);
            glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, pMaterial->emissive); // ML 01-02-2018: glow
            glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, pMaterial->shininess * rShine);

            pMaterial->ambient[3] = pMaterial->alpha;
            pMaterial->diffuse[3] = pMaterial->alpha;
            pMaterial->specular[3] = pMaterial->alpha;
            pMaterial->emissive[3] = pMaterial->alpha; // ML 01-02-2018: glow

            nTexture = 0;
            doSpherical = 0; // ML: 11-26-2015
            if ((pMaterial->alpha < 1.0f) || (pMaterial->illum == 12)) { nGlassIsUsed = -1; } // 11-27-2015

            // 12-09-2015 ML: !!! can't do "Specular mode" in multishader !!!
            // ML 01-18-2018: diffuse only mapping for billboards for now
            if (!pMaterial->bumpMapID || nSpecularMode || isBillboard) {

                // Per fragment Blinn-Phong code path.
                glUseProgram(gnm_BlinnPhongShader);

                // Bind the color map texture.  // ML: 11-26-2015
                glActiveTexture(GL_TEXTURE0);
                glEnable(GL_TEXTURE_2D);
                if (nFlagTextures && !nSpecularMode) { // ML: 12-09-2015
                    if ((pMaterial->reflMapID) && (pMaterial->illum > 2)) { // 11-13-2015
                        doSpherical = 1;
                        if ((pMaterial->illum == 4) || (pMaterial->illum == 11)) { // global reflection
                            nTexture = nUseTexture;
                        } else {                     // individual reflection
                            nTexture = pMaterial->reflMapID;
                        }
                    } else if (pMaterial->illum == 11) {
                        doSpherical = 1;
                        nTexture = nUseTexture;
                    } else {
                        nTexture = pMaterial->colorMapID;
                        if (nTexture == 0) { nTexture = gnm_NullTexture; }
                    }
                } else {
                    if (nSpecularMode) {
                        doSpherical = 1;
                        if (nFlagTextures) {
                            if ((pMaterial->reflMapID) && (pMaterial->illum > 2)) {
                                nTexture = pMaterial->reflMapID;
                            } else {
                                nTexture = pMaterial->colorMapID;
                            }
                            if (nTexture == 0) { nTexture = nUseTexture; }
                        } else {
                            nTexture = nUseTexture;
                        }
                    } else {
                        nTexture = gnm_NullTexture;
                    }
                }
                GL_BindTexture(GL_TEXTURE_2D, nTexture);

                if (isBillboard) { // ML 01-18-2018: let it ride w/o shaders for the time being
                    cylindricalBillBoard(pMesh->centerPoint, pMesh->meshRadius, &doRefresh, isBillboard == -2);
                    goto doneBillboard;
                }

                // Update shader parameters.
                glUniform1i(glGetUniformLocation(gnm_BlinnPhongShader, "colorMap"), 0);
                glUniform1i(glGetUniformLocation(gnm_BlinnPhongShader, "nLights"), nLights); // ML: 12-11-2015
                glUniform1i(glGetUniformLocation(gnm_BlinnPhongShader, "nLightFlags"), nLightFlags); // ML 02-01-2018:
                glUniform1i(glGetUniformLocation(gnm_BlinnPhongShader, "doSpherical"), doSpherical); // ML: 11-26-2015
                glUniform1f(glGetUniformLocation(gnm_BlinnPhongShader, "materialAlpha"), pMaterial->alpha);

            } else {

                // Normal mapping code path.
                glUseProgram(gnm_NormalMappingShader);

                // Bind the specular map texture. // ML: 11-05-2015
                glActiveTexture(GL_TEXTURE2); nFlagBump = -1;
                glEnable(GL_TEXTURE_2D);
                glUniform1i(glGetUniformLocation(gnm_NormalMappingShader, "sSpecmap"), 2);
                if (nFlagTextures) { // ML: 11-24-2015
                    if (pMaterial->specMapID) {
                        nTexture = pMaterial->specMapID;
                    } else {
                        if (pMaterial->colorMapID) {
                            nTexture = pMaterial->colorMapID; // !!! ML: LEAVE IT BE !!!
                        } else {
                            nTexture = gnm_NullTexture;
                        }
                    }
                } else {
                    nTexture = gnm_NullTexture;
                }
                glBindTexture(GL_TEXTURE_2D, nTexture);

                // Bind the normal map texture. // ML: 11-05-2015
                glActiveTexture(GL_TEXTURE1); nFlagBump = -1;
                glEnable(GL_TEXTURE_2D);
                glUniform1i(glGetUniformLocation(gnm_NormalMappingShader, "sNormalmap"), 1);
                if (nFlagTextures) { // ML: 11-24-2015
                    if (pMaterial->bumpMapID) {
                        nTexture = pMaterial->bumpMapID;
                    } else {
                        nTexture = gnm_NullBump;
                    }
                } else {
                    nTexture = gnm_NullBump;
                }
                glBindTexture(GL_TEXTURE_2D, nTexture);

                // Bind the color map texture.
                glActiveTexture(GL_TEXTURE0);
                glEnable(GL_TEXTURE_2D);
                glUniform1i(glGetUniformLocation(gnm_NormalMappingShader, "sBasemap"), 0);
                if (nFlagTextures) { // ML: 11-24-2015
                    if (pMaterial->colorMapID) {
                        nTexture = pMaterial->colorMapID;
                    } else {
                        nTexture = gnm_NullTexture;
                    }
                } else {
                    nTexture = gnm_NullTexture;
                }
                glBindTexture(GL_TEXTURE_2D, nTexture);

                glUniform1i(glGetUniformLocation(gnm_NormalMappingShader, "nLights"), nLights); // ML: 12-11-2015
                glUniform1i(glGetUniformLocation(gnm_NormalMappingShader, "nLightFlags"), nLightFlags); // ML 02-01-2018:
                glUniform1f(glGetUniformLocation(gnm_NormalMappingShader, "materialAlpha"), pMaterial->alpha);
            }

            // Render mesh.
            glClientActiveTexture(GL_TEXTURE0);
            if (Mobj_hasPositions()) {
                glEnableClientState(GL_VERTEX_ARRAY);
                glVertexPointer(3, GL_FLOAT, nVertexSize, Mobj_getVertexBufferPosition());
            }

            if (Mobj_hasTextureCoords()) {
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                glTexCoordPointer(2, GL_FLOAT, nVertexSize, Mobj_getVertexBufferTexCoord());
            }

            if (Mobj_hasNormals()) {
                glEnableClientState(GL_NORMAL_ARRAY);
                glNormalPointer(GL_FLOAT, nVertexSize, Mobj_getVertexBufferNormal());
            }

            if (Mobj_hasTangents()) {
                glClientActiveTexture(GL_TEXTURE1);
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                glTexCoordPointer(4, GL_FLOAT, nVertexSize, Mobj_getVertexBufferTangent());
            }

            if (nFlagBump) {
                // ML: 11-05-2015
                if (Mobj_hasTextureCoords()) {
                    glClientActiveTexture(GL_TEXTURE2);
                    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                    glTexCoordPointer(2, GL_FLOAT, nVertexSize, Mobj_getVertexBufferTexCoord());
                }
            }

            nCount = pMesh->triangleCount * 3;
            const GLvoid* indices = Mobj_getIndexBuffer() + pMesh->startIndex;

            if (nGlassIsUsed) {  // if we are using transparency then get rid of artefacts
                glEnable(GL_CULL_FACE);
                glFrontFace(nClockwise ? GL_CCW : GL_CW);
                glDrawElements(GL_TRIANGLES, nCount, GL_UNSIGNED_INT, indices);
                glFrontFace(nClockwise ? GL_CW : GL_CCW);
            }

            glDrawElements(GL_TRIANGLES, nCount, GL_UNSIGNED_INT, indices);

            if (nGlassIsUsed) { // 11-27-2015
                if (!Mobj_CullBackFace(0, 0)) { glDisable(GL_CULL_FACE); }
            }

            if (nFlagBump) { // ML: 11-05-2015
                glActiveTexture(GL_TEXTURE2);
                glBindTexture(GL_TEXTURE_2D, 0);
                glDisable(GL_TEXTURE_2D);
                if (Mobj_hasTextureCoords()) {
                    glClientActiveTexture(GL_TEXTURE2);
                    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
                }
                nFlagBump = 0;
            } else { // ML 01-18-2018: else it's impossible to get rid of these shitty tex coords in immediate mode!
                if (doSpherical) {
                    glUniform1i(glGetUniformLocation(gnm_BlinnPhongShader, "doSpherical"), 0);
                }
            }

            glActiveTexture(GL_TEXTURE1);
            glBindTexture(GL_TEXTURE_2D, 0);
            glDisable(GL_TEXTURE_2D);

            if (Mobj_hasTangents()) {
                glClientActiveTexture(GL_TEXTURE1);
                glDisableClientState(GL_TEXTURE_COORD_ARRAY);
            }

doneBillboard: // ML 01-21-2018: immediate mode for billboards is emulated by the OpenGL driver with an intrinsic shader,
               // so our billboard epilogue should also include disabling client states even though we didn't enable them.
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, 0);
            glClientActiveTexture(GL_TEXTURE0);

            if (Mobj_hasNormals()) { glDisableClientState(GL_NORMAL_ARRAY); }

            if (Mobj_hasTextureCoords()) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); }

            if (Mobj_hasPositions()) { glDisableClientState(GL_VERTEX_ARRAY); }

            if (pMaterial->isA2C) { glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } // PAT: 01-07-2018
        }
    }

    glUseProgram(0);
    glDisable(GL_BLEND);
}
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 21, 2018, 09:50:51 pm
Thank you!
Title: Re: Tron Light Cycle
Post by: Patrice Terrier on January 22, 2018, 10:53:50 pm
Playing with colors...
Title: Re: Tron Light Cycle
Post by: Michael Lobko-Lobanovsky on January 23, 2018, 12:51:08 am
I am glad you enjoy our new options. :)