Hello everybody,
I've just made a small application, using LWJGL. I have added the OBJ loader of elias4444 to load objets in my 3D world. But the objets have a problem to load:
(http://www.livedj.be/documents/test.jpg)
Like you can see, the plane is not shown correctly.
How can I fix that ?
P.S.: Originally the plane was very very little inside the screen, so I have had to add a glScalef(10f,10f,10f) to be able to see it in an acceptable size.
There's several possible things that could be wrong there (one of which is my old code :P ).
I would recommend trying it with culling turned off first though. It's possible that the normals are messed up with the object. Or, at least, that's what it kinda looks like.
I went ahead and updated my texturetester demo (includes source for OBJ loader and TrueType Font Renderer). Thought the updated code might help you out a bit too.
www.tommytwisters.com/texturetester.jar (http://www.tommytwisters.com/texturetester.jar)
I also went ahead and posted a webstartable version of the texture tester at:
www.tommytwisters.com/texture/texture.jnlp (http://www.tommytwisters.com/texture/texture.jnlp)
I figure, that way you can run it and see how your OBJ file loads up in another application.
Thank you for your application.
I'll paste my code here, could you take a look and tell me what's going wrong?
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.glu.GLU;
import java.io.BufferedReader;
import java.io.FileReader;
/**
* Basic game
*
* @author Name <email>
* @version 1.0
*/
public class Main {
/** Game title */
public static final String GAME_TITLE = "My Game";
/** Desired frame time */
private static final int FRAMERATE = 60;
/** Exit the game */
private static boolean finished;
/** Angle of rotating square */
private static float angle;
/**
* Application init
* @param args Commandline args
*/
public static void main(String[] args) {
boolean fullscreen = (args.length == 1 && args[0].equals("-fullscreen"));
try {
init(fullscreen);
run();
} catch (Exception e) {
e.printStackTrace(System.err);
Sys.alert(GAME_TITLE, "An error occured and the game will exit.");
} finally {
cleanup();
}
System.exit(0);
}
/**
* Initialise the game
* @throws Exception if init fails
*/
private static void init(boolean fullscreen) throws Exception {
// Create a fullscreen window with 1:1 orthographic 2D projection (default)
Display.setFullscreen(fullscreen);
Display.setTitle(GAME_TITLE);
// Enable vsync if we can (due to how OpenGL works, it cannot be guarenteed to always work)
Display.setVSyncEnabled(true);
// Create default display of 640x480
Display.create();
}
/**
* Runs the game (the "main loop")
*/
private static void run() {
while (!finished) {
// Always call Window.update(), all the time - it does some behind the
// scenes work, and also displays the rendered output
Display.update();
// Check for close requests
if (Display.isCloseRequested()) {
finished = true;
}
// The window is in the foreground, so we should play the game
else if (Display.isActive()) {
logic();
render();
Display.sync(FRAMERATE);
}
// The window is not in the foreground, so we can allow other stuff to run and
// infrequently update
else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
logic();
// Only bother rendering if the window is visible or dirty
if (Display.isVisible() || Display.isDirty()) {
render();
}
}
}
}
/**
* Do any game-specific cleanup
*/
private static void cleanup() {
// Close the window
Display.destroy();
}
/**
* Do all calculations, handle input, etc.
*/
private static void logic() {
// Example input handler: we'll check for the ESC key and finish the game instantly when it's pressed
if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
finished = true;
}
// Rotate the square
angle += 2.0f % 360;
}
/**
* Render the current frame
*/
private static void render() {
// clear the screen
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
// center square according to screen size
GL11.glPushMatrix();
GL11.glTranslatef(Display.getDisplayMode().getWidth() / 2, Display.getDisplayMode().getHeight() / 2, 0.0f);
// rotate square according to angle
GL11.glRotatef(angle, 0f, 0f, 1.0f);
// render the square
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2i(-50, -50);
GL11.glVertex2i(50, -50);
GL11.glVertex2i(50, 50);
GL11.glVertex2i(-50, 50);
GL11.glEnd();
GL11.glPopMatrix();
GL11.glPushMatrix();
GL11.glTranslatef(Display.getDisplayMode().getWidth() / 3, Display.getDisplayMode().getHeight() / 3, -5f);
GL11.glRotatef(angle, 0, 1f, 0);
GL11.glScalef(10f,10f,10f);
try{
FileReader fr = new FileReader("C:/java/obj/p51_mustang.obj");
BufferedReader br = new BufferedReader(fr);
Object3D letest = new Object3D(br,false);
letest.opengldraw();
} catch (Exception e) {
e.printStackTrace(System.err);
Sys.alert(GAME_TITLE, "Une erreur est survenue durant le chargement");
}
GL11.glPopMatrix();
}
}
Thank you!
P.S.:
I've just implemented your new code into my application but I'm still having the same problem.
And, I can't see the plane in your Texture Tester.
iv had problems like this when:
* culling was enabled.
* the model or ".obj" has not been triangulated.
* texture is not to the power of 2 (eg 32, 64, 128, 256...)
* or texture has alpha channels and alpha blending is enabled.
Have you tried loading a different OBJ file? I'm really thinking it may be the object itself.
Yes, I tried with objects that work in your application too.
Ok, I looked at your code, and I found a couple of things. One, you're loading the OBJ file every frame. You should preload it, and then just call the opengldraw() command in your render loop. Also, you should call Display.update() AFTER you've rendered everything in the loop. As it stands now, you update the display, only to clear it again in the same loop. You may be gettings drawing artifacts.
Try those things, and see what happens.
OK,
The FPS is now way faster (thanks)
But I'm still having the problem with the plane (and other objects)
Ok, lets work on your openGL init function:
You'll want to add some of these:
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_NORMALIZE);
// Setup translucency
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glEnable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_DITHER);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
GL11.glDepthFunc(GL11.GL_LEQUAL);
GL11.glEnable(GL11.GL_DEPTH_TEST);
This will enable materials, transparency, and setup depth testing and things. Place it after your Display.create() call. Try it out, and let me know.
After adding your lines in the init method everyting disappreared.
After some searching, I have commented the line "GL11.glEnable(GL11.GL_DEPTH_TEST);", but now, I still have the same problem as in my very first post ...
May be you should try my code on your own computer, update it their, try what you can, and then say me if you found something.
Thank you very much
Here you go:
Issue was that you hadn't setup anything for depth, so 2D images would work fine, but not 3D. I also added the init functions you'd need for transparency and things.
import java.io.BufferedReader;
import java.io.FileReader;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import tools.Object3D;
/**
* Basic game
*
* @author Name <email>
* @version 1.0
*/
public class Main {
/** Game title */
public static final String GAME_TITLE = "My Game";
/** Exit the game */
private static boolean finished;
/** Angle of rotating square */
private static float angle;
/** The Object to Draw */
private Object3D letest;
/**
* Application init
* @param args Commandline args
*/
public static void main(String[] args) {
boolean fullscreen = (args.length == 1 && args[0].equals("-fullscreen"));
Main app = new Main();
try {
app.init(fullscreen);
app.run();
} catch (Exception e) {
e.printStackTrace(System.err);
Sys.alert(GAME_TITLE, "An error occured and the game will exit.");
} finally {
app.cleanup();
}
System.exit(0);
}
/**
* Initialise the game
* @throws Exception if init fails
*/
private void init(boolean fullscreen) throws Exception {
// Create a fullscreen window with 1:1 orthographic 2D projection (default)
Display.setFullscreen(fullscreen);
Display.setTitle(GAME_TITLE);
// Enable vsync if we can (due to how OpenGL works, it cannot be guarenteed to always work)
Display.setVSyncEnabled(true);
Display.setDisplayMode(new DisplayMode(640,480));
// Create default display of 640x480
Display.create();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_NORMALIZE);
// Setup translucency
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glEnable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_DITHER);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL11.glClearDepth(1.0);
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Testing To Do
GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
// OpenGL uses a backwards x,y coordinate system, so use GL_BACK for culling
GL11.glCullFace(GL11.GL_BACK);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity(); // reset projection matrix
GL11.glViewport(0,0,640,480);
GL11.glOrtho(-640/2,640/2,-480/2,480/2, -100f, 10000f);
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
GL11.glLoadIdentity();
try{
FileReader fr = new FileReader("C:/java/obj/p51_mustang.obj");
BufferedReader br = new BufferedReader(fr);
letest = new Object3D(br,false,"C:/java/obj/");
} catch (Exception e) {
e.printStackTrace(System.err);
Sys.alert(GAME_TITLE, "Une erreur est survenue durant le chargement");
}
}
/**
* Runs the game (the "main loop")
*/
private void run() {
while (!finished) {
// Check for close requests
if (Display.isCloseRequested()) {
finished = true;
}
// The window is in the foreground, so we should play the game
else if (Display.isActive()) {
logic();
render();
}
// The window is not in the foreground, so we can allow other stuff to run and
// infrequently update
else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
logic();
// Only bother rendering if the window is visible or dirty
if (Display.isVisible() || Display.isDirty()) {
render();
}
}
}
}
/**
* Do any game-specific cleanup
*/
private void cleanup() {
// Close the window
Display.destroy();
}
/**
* Do all calculations, handle input, etc.
*/
private void logic() {
// Example input handler: we'll check for the ESC key and finish the game instantly when it's pressed
if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
finished = true;
}
// Rotate the square
angle += 2.0f % 360;
}
/**
* Render the current frame
*/
private void render() {
// clear the screen
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
GL11.glLoadIdentity();
// center square according to screen size
GL11.glPushMatrix();
//GL11.glTranslatef(Display.getDisplayMode().getWidth() / 2, Display.getDisplayMode().getHeight() / 2, 0.0f);
GL11.glTranslatef(0, 0, 0);
// rotate square according to angle
GL11.glRotatef(angle, 0f, 0f, 1.0f);
// render the square
GL11.glColor4f(1, 1, 1, 1);
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2i(-50, -50);
GL11.glVertex2i(50, -50);
GL11.glVertex2i(50, 50);
GL11.glVertex2i(-50, 50);
GL11.glEnd();
GL11.glPopMatrix();
GL11.glPushMatrix();
GL11.glTranslatef(-100f,-100f,0);
GL11.glRotatef(angle, 0, 1f, 0);
GL11.glScalef(10f,10f,10f);
letest.opengldraw();
GL11.glPopMatrix();
// Always call Window.update(), all the time - it does some behind the
// scenes work, and also displays the rendered output
Display.update();
}
}
Thank you very much!
It works on my PC too ;)
Indeed, I took the code on the wiki for rendering a square. I thought it would work for 3D too.
It was a bit confusing because there is no 3D example on the whole lwjgl.org website :(
But thanks,
you really helped me!