ObjReader Community
WIP => WIP => Topic started 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.
-
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.
-
My reworked candidate version...
With rotating wheel illusion, while in demo mode.
(http://www.objreader.com/download/images/TRON.png)
-
Forget to say that for me, it is still a low polygon model, even if looks much more crisp than the original. 8)
-
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
-
I must say that i am already very pleased with that WIP, may be it will become the final version afterwards. :D
-
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
-
I am very pleased to see that you are back with me, that gives me more motivation ;D
-
I've been enjoying every minute we spent on this project together with you ever since we started, my friend! :)
-
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.
-
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?
-
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...
-
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.
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.
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. >:( )
-
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...
-
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. :)
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);
}
-
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...
-
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:
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);
}
-
Thank you!
-
Playing with colors...
-
I am glad you enjoy our new options. :)