Hot questions for Using Lightweight Java Game Library in 3d

Question:

I'm trying to always show the front of a 3D font to the user. I tried rotating the font when rotating the camera, but never could get it to work.

I currently have this:

I'm trying to do this (font always faces front):

TrueTypeFont.java

package com.displee.render.font;

import lombok.AllArgsConstructor;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * A TrueType font implementation originally for Slick, edited for Bobjob's Engine
 * @original author James Chambers (Jimmy)
 * @original author Jeremy Adams (elias4444)
 * @original author Kevin Glass (kevglass)
 * @original author Peter Korzuszek (genail)
 * @new version edited by David Aaron Muhar (bobjob)
 */
public class TrueTypeFont {

    public final static int ALIGN_LEFT = 0, ALIGN_RIGHT = 1, ALIGN_CENTER = 2;
    /**
     * Array that holds necessary information about the font characters
     */
    private IntObject[] charArray = new IntObject[256];

    /**
     * Map of user defined font characters (Character <-> IntObject)
     */
    private Map customChars = new HashMap();

    /**
     * Boolean flag on whether AntiAliasing is enabled or not
     */
    private boolean antiAlias;

    /**
     * Font's size
     */
    private int fontSize = 0;

    /**
     * Font's height
     */
    private int fontHeight = 0;

    /**
     * Texture used to cache the font 0-255 characters
     */
    private int fontTextureID;

    /**
     * Default font texture width
     */
    private int textureWidth = 512;

    /**
     * Default font texture height
     */
    private int textureHeight = 512;

    /**
     * A reference to Java's AWT Font that we create our font texture from
     */
    private Font font;

    /**
     * The font metrics for our Java AWT font
     */
    private FontMetrics fontMetrics;


    private int correctL = 9, correctR = 8;

    private class IntObject {

        /**
         * Character's width
         */
        public int width;

        /**
         * Character's height
         */
        public int height;

        /**
         * Character's stored x position
         */
        public int storedX;

        /**
         * Character's stored y position
         */
        public int storedY;
    }


    public TrueTypeFont(Font font, boolean antiAlias, char[] additionalChars) {
        this.font = font;
        this.fontSize = font.getSize() + 3;
        this.antiAlias = antiAlias;

        createSet(additionalChars);

        fontHeight -= 1;
        if (fontHeight <= 0) {
            fontHeight = 1;
        }
    }

    public TrueTypeFont(Font font, boolean antiAlias) {
        this(font, antiAlias, null);
    }

    public void setCorrection(boolean on) {
        if (on) {
            correctL = 2;
            correctR = 1;
        } else {
            correctL = 0;
            correctR = 0;
        }
    }

    private BufferedImage getFontImage(char ch) {
        // Create a temporary image to extract the character's size
        BufferedImage tempfontImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = (Graphics2D) tempfontImage.getGraphics();
        if (antiAlias == true) {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        g.setFont(font);
        fontMetrics = g.getFontMetrics();
        int charwidth = fontMetrics.charWidth(ch) + 8;

        if (charwidth <= 0) {
            charwidth = 7;
        }
        int charheight = fontMetrics.getHeight() + 3;
        if (charheight <= 0) {
            charheight = fontSize;
        }

        // Create another image holding the character we are creating
        BufferedImage fontImage;
        fontImage = new BufferedImage(charwidth, charheight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D gt = (Graphics2D) fontImage.getGraphics();
        if (antiAlias == true) {
            gt.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        gt.setFont(font);

        gt.setColor(Color.WHITE);
        int charx = 3;
        int chary = 1;
        gt.drawString(String.valueOf(ch), (charx), (chary) + fontMetrics.getAscent());
        //fontImage = ImageUtils.flipVertically(fontImage);
        //fontImage = ImageUtils.flipHorizontally(fontImage);
        //fontImage = ImageUtils.flipHorizontallyAndVertically(fontImage);
        return fontImage;

    }

    private void createSet(char[] customCharsArray) {
        // If there are custom chars then I expand the font texture twice
        if (customCharsArray != null && customCharsArray.length > 0) {
            textureWidth *= 2;
        }

        // In any case this should be done in other way. Texture with size 512x512
        // can maintain only 256 characters with resolution of 32x32. The texture
        // size should be calculated dynamicaly by looking at character sizes.

        try {

            BufferedImage imgTemp = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = (Graphics2D) imgTemp.getGraphics();

            g.setColor(new Color(0, 0, 0, 1));
            g.fillRect(0, 0, textureWidth, textureHeight);

            int rowHeight = 0;
            int positionX = 0;
            int positionY = 0;

            int customCharsLength = (customCharsArray != null) ? customCharsArray.length : 0;

            for (int i = 0; i < 256 + customCharsLength; i++) {

                // get 0-255 characters and then custom characters
                char ch = (i < 256) ? (char) i : customCharsArray[i - 256];

                BufferedImage fontImage = getFontImage(ch);

                IntObject newIntObject = new IntObject();

                newIntObject.width = fontImage.getWidth();
                newIntObject.height = fontImage.getHeight();

                if (positionX + newIntObject.width >= textureWidth) {
                    positionX = 0;
                    positionY += rowHeight;
                    rowHeight = 0;
                }

                newIntObject.storedX = positionX;
                newIntObject.storedY = positionY;

                if (newIntObject.height > fontHeight) {
                    fontHeight = newIntObject.height;
                }

                if (newIntObject.height > rowHeight) {
                    rowHeight = newIntObject.height;
                }

                // Draw it here
                g.drawImage(fontImage, positionX, positionY, null);

                positionX += newIntObject.width;

                if (i < 256) { // standard characters
                    charArray[i] = newIntObject;
                } else { // custom characters
                    customChars.put(new Character(ch), newIntObject);
                }

                fontImage = null;
            }

            fontTextureID = loadImage(imgTemp);


            //.getTexture(font.toString(), imgTemp);

        } catch (Exception e) {
            System.err.println("Failed to create font.");
            e.printStackTrace();
        }
    }

    private void drawQuad(float drawX, float drawY, float drawX2, float drawY2, float srcX, float srcY, float srcX2, float srcY2, float z) {
        float DrawWidth = drawX2 - drawX;
        float DrawHeight = drawY2 - drawY;
        float TextureSrcX = srcX / textureWidth;
        float TextureSrcY = srcY / textureHeight;
        float SrcWidth = srcX2 - srcX;
        float SrcHeight = srcY2 - srcY;
        float RenderWidth = (SrcWidth / textureWidth);
        float RenderHeight = (SrcHeight / textureHeight);

        GL11.glTexCoord2f(TextureSrcX, TextureSrcY);
        GL11.glVertex3f(drawX, drawY, z);
        GL11.glTexCoord2f(TextureSrcX, TextureSrcY + RenderHeight);
        GL11.glVertex3f(drawX, drawY + DrawHeight, z);
        GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY + RenderHeight);
        GL11.glVertex3f(drawX + DrawWidth, drawY + DrawHeight, z);
        GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY);
        GL11.glVertex3f(drawX + DrawWidth, drawY, z);
    }

    public int getWidth(String whatchars) {
        int totalwidth = 0;
        IntObject intObject = null;
        int currentChar = 0;
        for (int i = 0; i < whatchars.length(); i++) {
            currentChar = whatchars.charAt(i);
            if (currentChar < 256) {
                intObject = charArray[currentChar];
            } else {
                intObject = (IntObject) customChars.get(new Character((char) currentChar));
            }

            if (intObject != null) {
                totalwidth += intObject.width;
            }
        }
        return totalwidth;
    }

    public int getHeight() {
        return fontHeight;
    }


    public int getHeight(String HeightString) {
        return fontHeight;
    }

    public int getLineHeight() {
        return fontHeight;
    }

    public void drawString(float x, float y, float z, String whatchars, float scaleX, float scaleY) {
        drawString(x, y, z, whatchars, 0, whatchars.length() - 1, scaleX, scaleY, ALIGN_LEFT);
    }

    public void drawString(float x, float y, float z, String whatchars, float scaleX, float scaleY, int format) {
        drawString(x, y, z, whatchars, 0, whatchars.length() - 1, scaleX, scaleY, format);
    }


    public void drawString(float x, float y, float z, String whatchars, int startIndex, int endIndex, float scaleX, float scaleY, int format) {

        IntObject intObject = null;
        int charCurrent;


        int totalwidth = 0;
        int i = startIndex, d, c;
        float startY = 0;


        switch (format) {
            case ALIGN_RIGHT: {
                d = -1;
                c = correctR;

                while (i < endIndex) {
                    if (whatchars.charAt(i) == '\n') {
                        startY -= fontHeight;
                    }
                    i++;
                }
                break;
            }
            case ALIGN_CENTER: {
                for (int l = startIndex; l <= endIndex; l++) {
                    charCurrent = whatchars.charAt(l);
                    if (charCurrent == '\n') {
                        break;
                    }
                    if (charCurrent < 256) {
                        intObject = charArray[charCurrent];
                    } else {
                        intObject = (IntObject) customChars.get(new Character((char) charCurrent));
                    }
                    totalwidth += intObject.width - correctL;
                }
                totalwidth /= -2;
            }
            case ALIGN_LEFT:
            default: {
                d = 1;
                c = correctL;
                break;
            }

        }

        java.util.List<QuadObject> list = new ArrayList<>(endIndex - startIndex);

        while (i >= startIndex && i <= endIndex) {

            charCurrent = whatchars.charAt(i);
            if (charCurrent < 256) {
                intObject = charArray[charCurrent];
            } else {
                intObject = (IntObject) customChars.get(new Character((char) charCurrent));
            }

            if (intObject != null) {
                if (d < 0) {
                    totalwidth += (intObject.width - c) * d;
                }
                if (charCurrent == '\n') {
                    startY -= fontHeight * d;
                    totalwidth = 0;
                    if (format == ALIGN_CENTER) {
                        for (int l = i + 1; l <= endIndex; l++) {
                            charCurrent = whatchars.charAt(l);
                            if (charCurrent == '\n') {
                                break;
                            }
                            if (charCurrent < 256) {
                                intObject = charArray[charCurrent];
                            } else {
                                intObject = (IntObject) customChars.get(new Character((char) charCurrent));
                            }
                            totalwidth += intObject.width - correctL;
                        }
                        totalwidth /= -2;
                    }
                    //if center get next lines total width/2;
                } else {
                    QuadObject quad = new QuadObject((totalwidth + intObject.width) * scaleX + x, startY * scaleY + y, totalwidth * scaleX + x, (startY + intObject.height) * scaleY + y, intObject.storedX + intObject.width, intObject.storedY + intObject.height, intObject.storedX, intObject.storedY, z);
                    list.add(quad);
                    if (d > 0) {
                        totalwidth += (intObject.width - c) * d;
                    }
                }
                i += d;

            }
        }

        float centerX = 0;
        for(QuadObject quad : list) {
            centerX += quad.drawX + (quad.drawX2 - quad.drawX);
        }
        centerX /= 2.0f;
        float centerY = 0;
        for(QuadObject quad : list) {
            centerY += quad.drawY + (quad.drawY2 - quad.drawY);
        }
        centerY /= 2.0f;

        //GL11.glTranslatef( -centerX, -centerY, -z);
        //GL11.glTranslatef(0, 0, -z);
        GL11.glRotatef(-Test3DFont.rotation.x, 0.0f, 0.0f, 0.0f);
        GL11.glRotatef(-Test3DFont.rotation.y, 0.0f, 1.0f, 0.0f);
        //GL11.glRotatef(-Test3DFont.rotation.z, 0.0f, 0.0f, 1.0f);
        //GL11.glTranslatef(0, 0, z);
        //GL11.glTranslatef(centerX, centerY, z); // M1 - 2nd translation

        GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureID);
        GL11.glBegin(GL11.GL_QUADS);
        for(QuadObject quad : list) {
            drawQuad(quad.drawX, quad.drawY, quad.drawX2, quad.drawY2, quad.srcX, quad.srcY, quad.srcX2, quad.srcY2, quad.z);
        }
        GL11.glDisable(GL11.GL_TEXTURE_2D);
        GL11.glEnd();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
    }

    public static int loadImage(BufferedImage bufferedImage) {
        try {
            short width = (short) bufferedImage.getWidth();
            short height = (short) bufferedImage.getHeight();
            //textureLoader.bpp = bufferedImage.getColorModel().hasAlpha() ? (byte)32 : (byte)24;
            int bpp = (byte) bufferedImage.getColorModel().getPixelSize();
            ByteBuffer byteBuffer;
            DataBuffer db = bufferedImage.getData().getDataBuffer();
            if (db instanceof DataBufferInt) {
                int intI[] = ((DataBufferInt) (bufferedImage.getData().getDataBuffer())).getData();
                byte newI[] = new byte[intI.length * 4];
                for (int i = 0; i < intI.length; i++) {
                    byte b[] = intToByteArray(intI[i]);
                    int newIndex = i * 4;

                    newI[newIndex] = b[1];
                    newI[newIndex + 1] = b[2];
                    newI[newIndex + 2] = b[3];
                    newI[newIndex + 3] = b[0];
                }

                byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI);
            } else {
                byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData());
            }
            byteBuffer.flip();


            int internalFormat = GL11.GL_RGBA8, format = GL11.GL_RGBA;
            IntBuffer textureId = BufferUtils.createIntBuffer(1);
            ;
            GL11.glGenTextures(textureId);
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId.get(0));


            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);

            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);

            GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);


            GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL11.GL_UNSIGNED_BYTE, byteBuffer.order(ByteOrder.nativeOrder()));
            return textureId.get(0);

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }

        return -1;
    }

    public static boolean isSupported(String fontname) {
        Font font[] = getFonts();
        for (int i = font.length - 1; i >= 0; i--) {
            if (font[i].getName().equalsIgnoreCase(fontname)) {
                return true;
            }
        }
        return false;
    }

    public static Font[] getFonts() {
        return GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
    }

    public static byte[] intToByteArray(int value) {
        return new byte[]{(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value};
    }

    public void destroy() {
        IntBuffer scratch = BufferUtils.createIntBuffer(1);
        scratch.put(0, fontTextureID);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        GL11.glDeleteTextures(scratch);
    }

    @AllArgsConstructor
    private class QuadObject {
        private float drawX;
        private float drawY;
        private float drawX2;
        private float drawY2;
        private float srcX;
        private float srcY;
        private float srcX2;
        private float srcY2;
        private float z;
    }
}

Test3DFont.java

package com.displee.render.font;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.vector.Vector3f;

import java.awt.*;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.gluPerspective;

public class Test3DFont {

    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;

    private static final float FOV = 45f;
    private static final float NEAR = 0.1f;
    private static final float FAR = 1000f;

    private static boolean mousePressed;
    private static Vector3f startCoordinations = new Vector3f();
    private static float scale = 0.05f;

    public static Vector3f rotation = new Vector3f(0, 0, 0);
    private static Vector3f startRotation = new Vector3f();

    private static TrueTypeFont font;

    private static boolean running = true;

    public static void main(String[] args) throws Exception {
        initializeDisplay();
        font = new TrueTypeFont(new Font("serif", Font.PLAIN, 30), true);
        initializeGL();
        while(running) {
            glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
            handleMouse();

            font.drawString(0, 0, 0, "Test", 0.1f, 0.1f);

            loadDefaultRotation();
            setViewport();

            drawGrid();
            Display.sync(60);
            Display.update();

            if (Display.isCloseRequested()) {
                break;
            }
        }
        font.destroy();
        Display.destroy();
    }

    private static void initializeDisplay() throws LWJGLException {
        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.create();
        setViewport();
    }

    public static void set2DMode() {
        //GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glMatrixMode(GL11.GL_PROJECTION);                        // Select The Projection Matrix
        GL11.glPushMatrix();                                     // Store The Projection Matrix
        GL11.glLoadIdentity();                                   // Reset The Projection Matrix
        GL11.glOrtho(0, WIDTH, 0, HEIGHT, -1, 1);                          // Set Up An Ortho Screen
        GL11.glMatrixMode(GL11.GL_MODELVIEW);                         // Select The Modelview Matrix
        GL11.glPushMatrix();                                     // Store The Modelview Matrix
        GL11.glLoadIdentity();                                   // Reset The Modelview Matrix
    }

    public static void set3DMode() {
        GL11.glMatrixMode(GL11.GL_PROJECTION);                        // Select The Projection Matrix
        GL11.glPopMatrix();                                      // Restore The Old Projection Matrix
        GL11.glMatrixMode(GL11.GL_MODELVIEW);                         // Select The Modelview Matrix
        GL11.glPopMatrix();                                      // Restore The Old Projection Matrix
        //GL11.glEnable(GL11.GL_DEPTH_TEST);
    }

    private static void setViewport() {
        glViewport(0, 0, WIDTH, HEIGHT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(FOV, (float) WIDTH / (float) HEIGHT, NEAR, FAR);
        glMatrixMode(GL_MODELVIEW);
    }

    private static void initializeGL() {
        glShadeModel(GL_SMOOTH);
        glEnable(GL_NORMALIZE);
        glEnable(GL_BLEND);
        glCullFace(GL_BACK);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

    private static void handleMouse() {
        scale += Mouse.getDWheel() > 0 ? 0.005f : Mouse.getDWheel() < 0 ? -0.005f : 0;
        int x = Mouse.getY();
        int y = Mouse.getX();
        if (!mousePressed) {
            mousePressed = Mouse.isButtonDown(0);
            if (mousePressed) {
                startCoordinations.set((float) x, (float) y, 0.0f);
                startRotation = new Vector3f(rotation);
            }
        } else if (!Mouse.isButtonDown(0)) {
            mousePressed = false;
        }
        if (!mousePressed) {
            return;
        }
        float differenceX = x - startCoordinations.x;
        float differenceY = y - startCoordinations.y;
        rotation.set(startRotation.x - (differenceX * 0.5F), startRotation.y + (differenceY * 0.5F), 0);
    }

    private static void loadDefaultRotation() {
        glLoadIdentity();
        Vector3f cameraPosition = new Vector3f();
        glTranslatef(cameraPosition.x, cameraPosition.y, -10);
        glRotatef(rotation.x, 1.0F, 0.0F, 0.0F);
        glRotatef(rotation.y, 0.0F, 1.0F, 0.0F);
        glRotatef(rotation.z, 0.0F, 0.0F, 1.0F);
        glScalef(scale, scale, scale);
    }

    private static void drawGrid() {
        glColor4f(0.7176471f, 0.7176471f, 0.7176471f, 1.0f);
        glBegin(GL_LINES);
        float size = 50;
        float step = 10;
        for (float i = -size; i <= size; i += step) {
            glVertex3f(i, 0, size);
            glVertex3f(i, 0, -size);
            glVertex3f(size, 0, i);
            glVertex3f(-size, 0, i);
        }
        glEnd();
    }

    public static int[] getScreenCoords(double x, double y, double z) {
        FloatBuffer screenCoords = BufferUtils.createFloatBuffer(4);
        IntBuffer viewport = BufferUtils.createIntBuffer(16);
        FloatBuffer modelView = BufferUtils.createFloatBuffer(16);
        FloatBuffer projection = BufferUtils.createFloatBuffer(16);
        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView);
        GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
        GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
        boolean result = GLU.gluProject((float) x, (float) y, (float) z, modelView, projection, viewport, screenCoords);
        if (result) {
            return new int[] { (int) screenCoords.get(0), (int) screenCoords.get(1) };
        }
        return null;
    }

}

Can anyone help me with this? How can I make it so I always see the front of the font?

Update 1: I've got it almost working by rotating the quads. I've added the following code in the drawString method before enabling texture 2D:

GL11.glRotatef(-Test3DFont.rotation.x, 0.0f, 0.0f, 0.0f);
GL11.glRotatef(-Test3DFont.rotation.y, 0.0f, 1.0f, 0.0f);

I've updated the code. It currently looks like this:


Answer:

I finally fixed it by pushing a matrix and using the original x, y and z coords in the translation. I also had to subtract 180 from the rotation because that's my starting rotation. Ended up with the following code:

    GL11.glPushMatrix();
    GL11.glTranslatef(x, y, z);
    GL11.glRotatef(180 - rotation.y, 0.0f, 1.0f, 0.0f);
    GL11.glTranslatef(-x, -y, -z);

    GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureID);
    GL11.glBegin(GL11.GL_QUADS);
    for(QuadObject quad : list) {
        drawQuad(quad.drawX, quad.drawY, quad.drawX2, quad.drawY2, quad.srcX, quad.srcY, quad.srcX2, quad.srcY2, quad.z);
    }
    GL11.glDisable(GL11.GL_TEXTURE_2D);
    GL11.glEnd();
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);

    GL11.glPopMatrix();

Question:

I am trying to make a model get very close to the camera so that it can be seen better, but it is drawn so far away and I have no idea how to move it closer. I tried using GL11.glTranslatef(0,0,1); to get it to move closer, but for some odd reason the object just stays the same distance away and never gets closer. Then it dissapears outside of the near/far plane view. Any ideas on how I can fix this issue? There is a copy of the class below.

package engine;

import model.Face;
import model.Model;
import model.ObjLoader;

import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector3f;

public class Render {

    Model m = null;

    public Render() {

    }

    public void draw(){
        GL11.glClearColor(0, 0, 0, 1);
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
        GL11.glBegin(GL11.GL_TRIANGLES);
            for (Face f : m.faces){
                //This code draws the model.
                Vector3f n1 = m.normals.get((int)f.normalIndicies.x - 1);
                GL11.glNormal3f(n1.x, n1.y, n1.z);
                Vector3f v1 = m.vertecies.get((int)f.indicies.x - 1);
                GL11.glVertex3f(v1.x, v1.y, v1.z); //First vertex


                Vector3f n2 = m.normals.get((int)f.normalIndicies.y - 1);
                GL11.glNormal3f(n2.x, n2.y, n2.z);
                Vector3f v2 = m.vertecies.get((int)f.indicies.y - 1);
                GL11.glVertex3f(v2.x, v2.y, v2.z); //second vertex

                Vector3f n3 = m.normals.get((int)f.normalIndicies.z - 1);
                GL11.glNormal3f(n3.x, n3.y, n3.z);
                Vector3f v3 = m.vertecies.get((int)f.indicies.z - 1);
                GL11.glVertex3f(v3.x, v3.y, v3.z); // third vertex
            }
        GL11.glEnd();

        GL11.glTranslatef(0, 0, 1); // <---- Here is the issue!!!

    }

    public void initOpenGL(){
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        GL11.glOrtho(0, 800, 600, 0, 1, -100);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);


        try{
            m = ObjLoader.loadModel("bunnyWithNormals.obj");
        }catch (Exception e){
            e.printStackTrace();
        }
        GL11.glTranslatef(400f, 300f, 0); // moves it onto the screen
    }

}

Answer:

Use glFrustum()/glPerspective() instead of glOrtho().

Question:

So basically I'm implementing normal mapping in my 3d program and I'm having an issue where the normal mapping only seems to show on the negative axis, and when I get close to it it is offset and is in the wrong position.

I've tried to do a bunch of stuff including using different methods, multiplying the light direction and camera position instead of the normal map, using a transposed and inversed TBN matrix, checking the texture loading process and turning off all processes that could interfere and a ton more.

Here is my main method in my vertex shader:

gl_Position = ProjectionMatrix * EyeMatrix * ModelMatrix * vec4(Position, 1.0);
texCoords = TexCoords;
position = (ModelMatrix * vec4(Position, 1.0)).xyz;

vec3 n = normalize((ModelMatrix * vec4(Normal, 0.0))).xyz;
vec3 t = normalize((ModelMatrix * vec4(Tangent, 0.0))).xyz;

t = normalize(t - dot(t, n) * n);

vec3 b = cross(t, n);

tbnMatrix = mat3(t, b, n);

Here is how i calculate my lighting:

vec3 calculatePointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir, float energyConservation)
{
vec3 lightDir = normalize(light.position - fragPos);

float diff = max(dot(normal, normalize(lightDir + viewDir)), 0.0);

float spec = energyConservation * pow(max(dot(normal, normalize(lightDir + viewDir)), material.specularIntensity), material.specularDampening);

float distance    = length(light.position - fragPos);
float attenuation = 1.0 / (light.attenuation.constant + light.attenuation.linear * distance + 
             light.attenuation.quadratic * pow(distance, 2.2));    

vec3 ambient  = light.baseLight.ambient * vec3(texture(material.texture_diffuse, texCoords));
vec3 diffuse  = (light.baseLight.diffuse * light.baseLight.intensity) * diff * vec3(texture(material.texture_diffuse, texCoords));
vec3 specular = (light.baseLight.specular * light.baseLight.intensity) * spec * vec3(texture(material.texture_gloss, texCoords));

ambient  *= attenuation;
diffuse  *= attenuation;
specular *= attenuation;

return (ambient + diffuse + specular);
}

and here's the code for my normal map:

vec3 normal = normalize(tbnMatrix * (255.0/128.0 * texture(material.texture_normal, texCoords).xyz - 1));

Here is what the tangents look like:

Here is what the tangents look like with the TBN matrix applied:

Here is the T component loaded in (without any editions): Here is the B component (the one in the vertex shader): Here is the N component loaded in (without any editions):

And here is what I get when I render the scene with normal mapping:

Here is what it looks like without normal mapping (with mipmapping and anisotropic-filtering enabled):

(Keep in mind I have specular maps as well)


Answer:

So i found the issue after weeks, and it was a very simple mistake. During the texture loading processing i was using GL_SRGB instead of the normal GL_RGB, and the SRGB is a gamma corrected version of the texture instead of the actual pure image. So i had to make an option to disable and enable the SRGB loading in the constructor for normal, gloss and displacement maps basically anything that wasn't shown on the screen.

Question:

I have many problems unsolved, and i'm kind of new at LWJGL.

Here is a screen: http://image.noelshack.com/fichiers/2015/07/1423885261-sans-titre.png

(this is 20x20x20 simple cube)

But as you can see, my fps are not bigger than 40 and every face of the cube is showing. How can i fix the fps drop and hide the hidden block behind another one ?

I have glEnable(GL_DEPTH_TEST); and glEnable(GL_CULL_FACE); but it only work INSIDE the block :x ...

Sorry for my english too but i really need help :p


Answer:

Culling

If culling only works if you are inside a block your vertex winding order is most likely mixed up. If so you might want to change it from the default GL_CCW to GL_CW or fix your vertex order to the default. Reference here

SpeedUp

For this your question has too few information. If you are not doing so already you might want to switch to using Vertex_Buffer_Object. Preferably using a single geometry that is only translated.

An additional approach would be to only render objects that are in line of sight of the camera. One method for this is a Binary Search Tree

Question:

I have a 3D file made in Blender and exported to java (.OBJ file), which has his textures separated into some files. Inside this .obj file, it has some fields caled USEMTL and the name of its parts (textures files). However, when I draw it at the screen, he only shows the last USEMTL name. My question is: How can i proceed to make him read and texturize at the correct way? Without lapping other textures?

This is the class that have the .obj loader
    public MLoader(String path, Model m) throws IOException {
            @SuppressWarnings("resource")
            BufferedReader reader = new BufferedReader(new FileReader(new File(path)));
            String line;

    while ((line = reader.readLine()) != null) {
        if (line.startsWith("v ")) {
            float 
            v1 = Float.valueOf(line.split(" ")[1]), 
            v2 = Float.valueOf(line.split(" ")[2]), 
            v3 = Float.valueOf(line.split(" ")[3]);

            Vector3f v = new Vector3f (v1, v2, v3);

            m.vertex.add(v);
        } if (line.startsWith("usemtl ")){
            String name = String.valueOf(line.split(" ")[1]);
            m.nameTexture.add(name);
            continue;
        } if (line.startsWith("f ")) {
            float 
            v1 = Float.valueOf(line.split(" ")[1].split("/")[0]),
            v2 = Float.valueOf(line.split(" ")[2].split("/")[0]),
            v3 = Float.valueOf(line.split(" ")[3].split("/")[0]),

            n1 = Float.valueOf(line.split(" ")[1].split("/")[1]),
            n2 = Float.valueOf(line.split(" ")[2].split("/")[1]),
            n3 = Float.valueOf(line.split(" ")[3].split("/")[1]);

            Vector3f
            v = new Vector3f (v1, v2, v3),
            n = new Vector3f (n1, n2, n3);

            m.face.add(new Faces(v, n));
        }if (line.startsWith("vt ")) {
            float 
            vt1 = Float.valueOf(line.split(" ")[1]), 
            vt2 = Float.valueOf(line.split(" ")[2]);

            Vector2f vt = new Vector2f (vt1, vt2);

            m.vertexTexture.add(vt);
        } 
    }
}

As you can see, I created a IF statement, just to get this usemtl stuff (that is inside .obj file) - the texture names (which are into separate files) just to see if I could bind them individually. But I'm having trouble to do that (perhaps, logic isn't in my side). How to proceed?

Other classes:

Texture Class
public class Textures {
    public Texture[] tx;

    public void setNumTex(int i) {
        tx = new Texture[i];
    }

    public void setTexture(String format, String name, int i) {
        try {
            tx[i] = TextureLoader.getTexture(format, new FileInputStream(new File("res/Textures/" + name + format)));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void texturing(Vector2f ft1, Vector2f ft2, int indexx) {
        for (int i=0; i<indexx; i++) {
            tx[i].bind();
        }
        glTexCoord2f(ft1.x, ft1.y);
        glTexCoord2f(ft2.x, ft2.y);
    }
}
Render Class
public class Renderer {
    Model m;

    public void loadContent(String objPath) {
        //Everithing that is loading is been putting here
        m = Model.getModel("res/Models/" + objPath);

        m.loadTex();
    }

    public void render() {
        glEnable(GL_SMOOTH);

        m.renderModel();
    }
}
Model Class
public class Model {
    Textures tx;

    List<Vector3f> vertex, norms;
    List<Vector2f> vertexTexture;
    List<Faces> face;
    List<String> nameTexture;
    String name[];

    private int numTex = 0;

    Vector2f 
    t1 = new Vector2f(), t2 = new Vector2f();

    Vector3f
    v1 = new Vector3f(), v2 = new Vector3f(), v3 = new Vector3f(),
    n1 = new Vector3f(), n2 = new Vector3f(), n3 = new Vector3f(),

    public Model(String path)throws 
    LWJGLException, FileNotFoundException, IOException {
        vertex = new ArrayList<Vector3f>();
        norms = new ArrayList<Vector3f>();
        vertexTexture = new ArrayList<Vector2f>();
        face = new ArrayList<Faces>();
        nameTexture = new ArrayList<String>();

        tx = new Textures();

        new MLoader(path, this);
    }

    public static Model getModel(String path, Vector3f position, Vector3f rotation) {
        try {
            return new Model(path, position, rotation);
        } catch (LWJGLException | IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public void loadTex() {
        name = new String[nameTexture.toArray().length];
        tx.setNumTex(nameTexture.toArray().length);

        for (int i=0; i<name.length; i++) {
            name[i] = nameTexture.get(i);
            numTex += 1;

            tx.setTexture(".TGA", name[i], i);
        }
    }

    public void renderModel() {
        glPushMatrix();
        glPolygonMode(GL_FRONT_AND_BACK, GL_DEPTH_BUFFER_BIT);
        glEnable(GL_TEXTURE_2D);
        glBegin(GL_TRIANGLES);
        {
            for (Faces f : face) {
                v1 = vertex.get((int) f.v.x - 1);
                v2 = vertex.get((int) f.v.y - 1);
                v3 = vertex.get((int) f.v.z - 1);
                n1 = vertex.get((int) f.n.x - 1);
                n2 = vertex.get((int) f.n.y - 1);
                n3 = vertex.get((int) f.n.z - 1);
                t1 = vertexTexture.get((int) f.n.x - 1); //
                t2 = vertexTexture.get((int) f.n.y - 1); // 

                //Vertexes
                glVertex3f(v1.x, v1.y-3.4f, v1.z-0.53f);
                glVertex3f(v2.x, v2.y-3.4f, v2.z-0.53f);
                glVertex3f(v3.x, v3.y-3.4f, v3.z-0.53f);

                //Normals
                glNormal3f(n1.x, n1.y-3.4f, n1.z-0.53f);
                glNormal3f(n2.x, n2.y-3.4f, n2.z-0.53f);
                glNormal3f(n3.x, n3.y-3.4f, n3.z-0.53f);

                //Texture
                tx.texturing(t1, t2, numTex);
                //tx.texturing(n1, n2, n3);             
            }
        }
        glEnd();
        glDisable(GL_TEXTURE_2D);
        glPopMatrix();
    }
}

Answer:

I will not put any code as your question is pretty complex for a 2 line solution.But here how it is usually works in a simple 3D engine.Multiple texturing of a mesh implies that the mesh is broken into 2 or more sub-meshes.I am not blender specialist but I am sure it is capable of exporting the mesh with its sub-mesh tree just like Autodesk 3D studio max.Now,when you import such a mesh into your program you should be able to parse all those sub-meshes into separate entities.Every such a sub-mesh has its own vertices,texture coordinates and normals. When issuing the draw call you would iterate over all the sub-meshes one by one and draw each of them in its own draw call.So on on each draw call you should be able also to attach a unique texture to be used for that specific sub-mesh.That's all.Now it is up to you how to design such a system. Hope it helps.

Question:

I have a simple 16 x 16 grid to which I apply a single texture. The texture file is divided into four parts - each a different color. By default each square is colored green (upper left part of the file). If you click a square I apply the red portion (upper right part of the file). Now I want to make the square disappear entirely when clicked. I suppose I can use a transparent texture but I was hoping I wouldn't have to so as to avoid loading / reloading two different texture files.

Here is the code I use to update the texture vbo:

  //I don't bother offsetting my changes.  I simply update the 'UVs'
  //array and then copy the entire thing to the floatbuffer.   
  public void updateTexture(int offset)
  {

      //populate the texture buffer
      //fbtex is a floatbuffer (16x16x8 in size). UVs is an array, same size.
      fbtex.put( UVs );
      fbtex.rewind();

      glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(TEXTURE_IDX)); //the texture data
      glBufferSubData(GL_ARRAY_BUFFER, offset, fbtex);
      fbtex.clear(); //don't need this anymore  
  }

The VBO will contain up to 256 instances of my co-ords for Green:

public float[] UV_0 = { 0.02f,0.02f, 
                        0.02f,0.24f,
                        0.24f,0.24f,
                        0.24f,0.02f};

or less if includes a few of my co-ords for Red:

public float[] UV_1 = { 0.24f,0.02f, 
                        0.48f,0.02f,
                        0.48f,0.24f,
                        0.24f,0.24f};

Is there anything I can do to the VBO data to draw a section invisible? So the objects in the background can be seen for example?


Answer:

You can just not render parts of the VBO. Normally you draw the entire data with something like

glDrawArrays(GL_TRIANGLES, 0, numElements);

glDrawArrays takes a first and count parameter which you can use to render only a part of the VBO. So if you wanted to not render some data, you would render all data before and then after this data in two draw calls.

Question:

I'm writing a 3D application in Java. I'm loading fields that contain around 65000 vertices each. These fields can translate, rotate etc. When a field scrolls out of the frustum it is culled, VBOs are cleared and the element arrays are stored in a memory buffer. I buffer a max of 5 of these fields. Any more than that they start going to file.

When I hit around 8 visible fields (520000) vertices the program crashes with system out of memory. I thought I was overloading the gpu memory but using GPU Shark I can see it only hits about 25%. My system has 8GB of RAM and looking via Task manager the memory usage barely registers. It sits at about 51%. So what am I running out of?

I use Concurrent Hashmaps to store my vertex data. I don't explicitly destroy/nullify them when not in use but that has never caused problems before.

I am using the OpenGL library via LWJGL.


Answer:

If you are using eclipse, try to increase the eclipse heap size and then again try it out. JVM do not allow your whole RAM to the heap.

How to increase application heap size in Eclipse?

Question:

I want to make a game where you are a player on a 3D plane, who is able to collide with objects around him. I plan to do collisions by wrapping all 3D models in the game with invisible rectangles that cannot be entered. I have written code to calculate the min/max of the X,Y, and Z of each vertex to find the highest and lowest point of each vertex. How would I make this into a rectangular prism?

Here is my code so far:

public CollisionModel(List<Vector3f> vert) {
    float xLow = 1000;
    float xHigh = 0;
    float yLow = 1000;
    float yHigh = 0;
    float zLow = 1000;
    float zHigh = 0;
    for(Vector3f v : vert) {
        if(v.x > xHigh) {
            xHigh = v.x;
        } else if(v.x < xLow) {
            xLow = v.x;
        }
        if(v.y > yHigh) {
            yHigh = v.y;
        } else if(v.y < yLow) {
            yLow = v.y;
        }
        if(v.z > zHigh) {
            zHigh = v.z;
        } else if(v.z < zLow) {
            zLow = v.z;
        }
    }
}

Answer:

  1. the initial value of the min,max should be the first vertex not hard-coded 0,1000 !!!
  2. you find min,max that gives you bounding box which is what you called prism.

Now you need to do collision testing. The problem is that your object can most likely move/rotate ... so you need apply transformations to your box first. So let construct the bounding box vertexes first. In 3D it is 8 points:

p0 = ( xLow  , yLow , zLow  )
p1 = ( xHigh , yLow , zLow  )
p2 = ( xHigh , yHigh, zLow  )
p3 = ( xLow  , yHigh, zLow  )
p4 = ( xLow  , yLow , zHigh )
p5 = ( xHigh , yLow , zHigh )
p6 = ( xHigh , yHigh, zHigh )
p7 = ( xLow  , yHigh, zHigh )

Now apply object transformations to each of them. And lastly you need to add collision test. So you most likely want to test if 2 bounding boxes collide or not. For that you need test if any edge line of bbox1(q0..q7) intersects any face from bbox2(p0..p7). The faces are:

p0,p1,p2,p3
p4,p5,p6,p7
p0,p1,p5,p4
p1,p2,p6,p5
p2,p3,p7,p6
p3,p0,p4,p7

and edge lines are:

q0,q1
q1,q2
q2,q3
q3,q0
q4,q5
q5,q6
q6,q7
q7,q4
q0,q4
q1,q5
q2,q6
q3,q7

For the intersection itself you need to google the equation (I am too lazy to derive or search it for you) but here first google hit I found:

Yes you can use triangle vs. line intersection as you face is 2 joined triangles ... There is also another option and that is convert the lines to coordinate system of the other bbox and then compute points for each line where one of the x,y,z = min and max and then just test if other two coordinates are in range or not ..

Question:

Im trying to find the components/head of a 3D vector with in java. I have a already got the x,y,z variables setup and the corresponding rotation variables. Using these variables and vector math, I want to find the components after they have been rotated. You can think the x,y,z variables as a vector being translated.

Using the math from this post: Rotating a Vector in 3D Space

I wrote some code that was supposed to calculate position based on that last post:

//Rotate Z
x = (( x * Math.cos(radz)) - (y * Math.sin(radz)));
y = (( x * Math.sin(radz)) + (y * Math.cos(radz)));
//Ignore Z ###############################################

//Rotate Y
x = (( x * Math.cos(rady)) - (z * Math.sin(rady)));
//Ignore Y ###############################################
z = (( x * Math.sin(rady)) + (z * Math.cos(rady)));

//Rotate X 
//Ignore X ###############################################
y = (( y * Math.cos(radx)) - (z * Math.sin(radx)));
z = (( y * Math.sin(radx)) + (z * Math.cos(radx)));

Where x, y and z are the positions that need to be changed and radx, rady and radz are the degrees of rotation in radians.

Using this code, if you set the variables like so:

double radx = Math.toRadians(0f);
double rady = Math.toRadians(90f);
double radz = Math.toRadians(0f);

double x = 1;
double y = 0;
double z = 0;

System.out.println(x + " " + y + " " + z);

It outputs: 6.123233995736766E-17 0.0 6.123233995736766E-17

Which im fairly sure isn't accurate. . .

What am I doing wrong with this code? Is there a easier way to find the head of a 3D vector java?

Also I do have the joml library, but it seems to have the same issue with the vec.rotateX method.


Answer:

You are updating your variables early. Try to:

//Rotate Z
double newX = (( x * Math.cos(radz)) - (y * Math.sin(radz)));
y = (( x * Math.sin(radz)) + (y * Math.cos(radz)));
//Ignore Z ###############################################

x = newX;

//Rotate Y
newX = (( x * Math.cos(rady)) + (z * Math.sin(rady)));
//Ignore Y ###############################################
z = (( x * -Math.sin(rady)) + (z * Math.cos(rady)));

x = newX;

//Rotate X 
//Ignore X ###############################################
double newY = (( y * Math.cos(radx)) - (z * Math.sin(radx)));
z = (( y * Math.sin(radx)) + (z * Math.cos(radx)));

y = newY;

Question:

Good evening, I have a problem with the LWJGL library, my idea is to make a procedural ground where a vehicle can move, I've already built both ground and vehicle management to make it stick to the ground each time it moves, To do this, the height of the ground is calculated according to the new position and the object is placed at the altitude just calculated but what I can not do is to rotate the vehicle according to the slope of the ground. I have already tried to calculate the altitudes at the edge of the vehicle and use them to get the rotation angles (x axis, z) but I managed to run it only for one direction but if the object rotates around the axis y it will not work more. I tried to use quaternions but they also failed.

Here is the class that realizes the terrain https://github.com/maurizioterreni/OpenGL/blob/master/src/com/unifi/ing/engine/terrains/Terrain.java

While here the class that manages the vehicle https://github.com/maurizioterreni/OpenGL/blob/master/src/com/unifi/ing/engine/entity/Rover.java


Answer:

The up vector of your object should be in line with the normal vector of the terrain. By doing this, the game object/entity will then be orthogonal/perpendicular to the terrain.

Question:

I've managed to display a two-dimensional triangle in a OpenGL 4.2 window using LWJGL 3. Here's the code I used:

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryUtil;

public class TestClass
{
    private static long window;
    private static int WIDTH = 1280;
    private static int HEIGHT = 720;

    public static void main (String[] args)
    {
        if (glfwInit() == GL_FALSE)
        {
            System.out.println ("GLFW initialization failed.");
            System.exit (1);
        }

        glfwWindowHint (GLFW_RESIZABLE, GL_FALSE);
        window = glfwCreateWindow (WIDTH, HEIGHT, "GLFW Window", MemoryUtil.NULL, MemoryUtil.NULL);
        glfwMakeContextCurrent (window);
        glfwSwapInterval (1);
        GL.createCapabilities();
        glMatrixMode (GL_PROJECTION);
        glLoadIdentity();
        glOrtho (0, 12, 12, 0, 1, -1);
        glClearColor (0, 0.7f, 1, 0);
        glMatrixMode (GL_MODELVIEW);
        glfwShowWindow (window);

        while (glfwWindowShouldClose (window) == GL_FALSE)
        {
            glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            glBegin (GL_TRIANGLES);
            glColor3f (1, 0, 0.7f);
            glVertex3f (6, 4, 0); // Vertex one
            glColor3f (1, 0, 0.7f);
            glVertex3f (4, 8, 0); // Vertex two
            glColor3f (1, 0, 0.7f);
            glVertex3f (8, 8, 0); // Vertex three
            glEnd();

            glfwSwapBuffers (window);
            glfwPollEvents();
        }

        glfwDestroyWindow (window);
        glfwTerminate();
    }
}

If I set the Z value of any of my three vertices to something greater than 1 or less than -1, the triangle partially disappears around that vertex. And when I do set the Z value to something between 1 and -1, I can see no difference between that and having the value equal 0. I'm a bit stuck here. Could somebody provide an explanation of how to get this triangle to exist on a plane that is not completely parallel to the viewing angle?

Cheers, Nebula


Answer:

this happens because you aren't using a perspective view, rather an orthogonal view. When you call glOrtho(), you request that the matrix that is used fro projection be set to an orthogonal matrix, which does not account for depth and does not do a perspective calculation. This is why you do not see a change in the triangle. as for the vertices disappearing in when the value exceeds the range of (-1, 1), that is because you set the last two parameters of your glOrtho() call to 1 and -1 respectively. this tells openGL to discard vertices outside this range (because of the way normalized device coordinates and matrix math work together, which you will probably learn about if you continue using openGL and work with later releases).

Now, in LWJGL 3, the glu (Utility package) was removed. This makes it a bit harder to initialize a perspective matrix for the fixed pipeline. here is a good post on how to do it, but since its written for c++, I'll provide you with the java equivalent.

// Replaces gluPerspective. Sets the frustum to perspective mode.
// fov     - Field of vision in degrees in the y direction
// aspect   - Aspect ratio of the viewport
// zNear    - The near clipping distance
// zFar     - The far clipping distance
private static void perspectiveGL(float fov, float aspect, float zNear, float zFar) {
    float fH = (float) Math.tan(fov / 360 * Math.PI) * zNear;
    float fW = fH * aspect;
    glFrustum( -fW, fW, -fH, fH, zNear, zFar );
}

The glFrustum() call is the important part of this function and is what creates a perspective matrix, however, its parameters aren't very user friendly.

Hope this helped!

Question:

When I try to put my project and run it on my laptop, everything works fine but 3D picking is messed up. It picks different objects when I click a 3D object.

I have tried in another laptop and it gives the same result. Then I tried fixing my desktop computer's monitor to my laptop to see weather its a resolution problem. But still it gives the same result. But it totally works fine in my desktop computer.

I have a Nvidia 760gtx gpu on my desktop and laptop only has the Intel HD 4500 gpu. Is it because of the gpu? me. I'm lost. I tried everything. This is my code to pick 3D objects.

public void select(int xx, int yy )
{
        // The selection buffer
        IntBuffer selBuffer = ByteBuffer.allocateDirect(1280).order(ByteOrder.nativeOrder()).asIntBuffer();
        int buffer[] = new int[256];

        IntBuffer vpBuffer = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder()).asIntBuffer();
        // The size of the viewport. [0] Is <x>, [1] Is <y>, [2] Is <width>, [3] Is <height>
            int[] viewport = new int[4];

        // The number of "hits" (objects within the pick area).
        int hits;
        // Get the viewport info
            GL11.glGetInteger(GL11.GL_VIEWPORT, vpBuffer);
            vpBuffer.get(viewport);


        // Set the buffer that OpenGL uses for selection to our buffer
        GL11.glSelectBuffer(selBuffer);

        // Change to selection mode
        GL11.glRenderMode(GL11.GL_SELECT);

        // Initialize the name stack (used for identifying which object was selected)
        GL11.glInitNames();
        GL11.glPushName(0);

        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glPushMatrix();
        GL11.glLoadIdentity();

        /*  create 5x5 pixel picking region near cursor location */
        GLU.gluPickMatrix( (float) xx, (float) yy, 0.001f, 0.001f,IntBuffer.wrap(viewport));

        GLU.gluPerspective(fov, screenResolutionx/screenResolutiony, near, far);
        render();
        GL11.glPopMatrix();
        // Exit selection mode and return to render mode, returns number selected
        hits = GL11.glRenderMode(GL11.GL_RENDER);
        System.out.println("hits: " + hits);

        selBuffer.get(buffer);
            // Objects Were Drawn Where The Mouse Was

            if (hits > 0) {
                  // If There Were More Than 0 Hits
                  choose = buffer[3]; // Make Our Selection The First Object
                  int depth = buffer[1]; // Store How Far Away It Is
                  for (int i = 1; i < hits; i++) {
                        // Loop Through All The Detected Hits
                        // If This Object Is Closer To Us Than The One We Have Selected
                        if (buffer[i * 4 + 1] <  depth) {
                              choose = buffer[i * 4 + 3]; // Select The Closer Object
                              depth = buffer[i * 4 + 1]; // Store How Far Away It Is
                        }
                  }
                  System.out.println("Chosen: " + choose);
            }




}

Answer:

Finally i figured it out. It is because of the GPU. I tried this method in a nvidia GPU (840m) laptop and it did work fine. But when i switch the gpu to Intel HD 5500 ,selection is not working properly. So my conclusion is using GL11.glRenderMode(GL11.GL_SELECT) method for 3D object picking works only with a nvidia GPU. It might work on a ATI GPU (not tested) also but not on Intel.

Question:

I am trying to create a FPS camera using LWJGL, but my code does not seem to work. -_- It just creates a white block in front of the screen, player can not move or rotate. What is the problem?

public class LocalWindow 
{
public void Launch() 
{
    try 
    { 
        Display.setDisplayMode (new DisplayMode (800, 600));
        Display.setTitle("Historica");
        Display.create();
    } 
    catch (LWJGLException e) 
    {
            e.printStackTrace();
    }
}
public void Render()
{
    initMatrix();
    while (!Display.isCloseRequested())
            //&& !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE))
    {

        initControls();
        frameRefresh();
        initCamera();




        Block s = new Block(0, 0, -4);
        s.setBlock();






        Display.update();
    }
}
private void initCamera()
{
    Camera player = new Camera();
    player.setView();
}
private void frameRefresh()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
}
private void initControls()
{
    Mouse.setGrabbed(true);
    Controls controls = new Controls();
    controls.moveForward(0.1f);
    controls.moveBackward(0.1f);
    controls.strafeLeft(0.1f);
    controls.strafeRight(0.1f);
    controls.lookingAround(0.1f);
}
private void initMatrix()
{
    Matrix matrix = new Matrix();
    matrix.initMatrix();
}

}

The Camera class:

public class Camera {
public float x;
public float y;
public float z;
public float rx;
public float ry;
public float rz;
public float fov = 70;
public float aspect = (float)Display.getWidth()/(float)Display.getHeight();
public float near = 0.3f;
public float far = 1000;
public float dx;
public float dy;



public void setView(){
    glRotatef(rx,1,0,0);
    glRotatef(ry,0,1,0);
    glRotatef(rz,0,0,1);
    glTranslatef(x,y,z);
}
}

The Controls class:

import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;


public class Controls extends Camera {
boolean W = Keyboard.isKeyDown(Keyboard.KEY_W);
boolean S = Keyboard.isKeyDown(Keyboard.KEY_S);
boolean A = Keyboard.isKeyDown(Keyboard.KEY_A);
boolean D = Keyboard.isKeyDown(Keyboard.KEY_D);

public void moveForward(float amount)
{
    if(W)
    {
    x += amount * Math.cos(Math.toRadians(ry + 90));
    z += amount * Math.sin(Math.toRadians(ry + 90));
    }
}

public void moveBackward(float amount)
{
    if(S)
    {
    x -= amount * Math.cos(Math.toRadians(ry + 90));
    z -= amount * Math.sin(Math.toRadians(ry + 90));
    }
}
public void strafeLeft(float amount)
{
    if(A);
    {
    x -= amount * (float)Math.sin(Math.toRadians(ry-90));
    z += amount * (float)Math.cos(Math.toRadians(ry-90));
    }
}
public void strafeRight(float amount)
{
    if(D)
    {  
    x -= amount * (float)Math.sin(Math.toRadians(ry+90));
    z += amount * (float)Math.cos(Math.toRadians(ry+90));
    }
}
public void lookingAround(float amount)
{
    dx = Mouse.getDX();
    dy = Mouse.getDY();
    ry += dx * amount;
    rx -= dy * amount;
}
}

The Matrix class:

public class Matrix extends Camera{
public void initMatrix(){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(fov, aspect, near, far);
    glMatrixMode(GL_MODELVIEW); 
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
}

}

Class Block works entirely properly (It creates a 3D block on the given coordinates).


Answer:

The reason why your camera doesn't move is that you create a new instance of player and controls in every frame. In addition to this, you change the members only in controls, but use the values in player to set the view.

Question:

I'm trying to develop a Minecraft like. This is a screenshot of my work : The rendering is satisfactory, but when i'm looking at my FPS, it's horrible : 90 FPS ! I'm rending 4*4* chunks of 16*16*16 blocks. This is really bad... To render my world, I render my chunks, which render their blocks. I'm rendering my blocks like this :

public void renderTop(){
    glTexCoord2f((0)/NBFACES+offs,(0+this.type)/NBBLOCKS+offs); glVertex3f(this.x       , this.y+TAILLE, this.z       );
    glTexCoord2f((1)/NBFACES-offs,(0+this.type)/NBBLOCKS+offs); glVertex3f(this.x+TAILLE, this.y+TAILLE, this.z       );
    glTexCoord2f((1)/NBFACES-offs,(1+this.type)/NBBLOCKS-offs); glVertex3f(this.x+TAILLE, this.y+TAILLE, this.z+TAILLE);
    glTexCoord2f((0)/NBFACES+offs,(1+this.type)/NBBLOCKS-offs); glVertex3f(this.x       , this.y+TAILLE, this.z+TAILLE);
}

public void renderBottom(){
    glTexCoord2f((0+1)/NBFACES+offs,(0+this.type)/NBBLOCKS+offs); glVertex3f(this.x       , this.y       , this.z+TAILLE);
    glTexCoord2f((1+1)/NBFACES-offs,(0+this.type)/NBBLOCKS+offs); glVertex3f(this.x+TAILLE, this.y       , this.z+TAILLE);
    glTexCoord2f((1+1)/NBFACES-offs,(1+this.type)/NBBLOCKS-offs); glVertex3f(this.x+TAILLE, this.y       , this.z       );
    glTexCoord2f((0+1)/NBFACES+offs,(1+this.type)/NBBLOCKS-offs); glVertex3f(this.x       , this.y       , this.z       );
}

 ...

Actualy, i'm rendering blocks face per face if they haven't got neighbors. So if I walk through the ground, i will not see blocks below the other grass blocks. Do you know how can i optimize my rendering ? That's too weak :-/ Thx.


Answer:

Try using backface culling, frustrum culling. That should boost FPS exponentially.