渲染文本时,OpenGL四边形渲染为黑色

时间:2017-08-23 02:02:17

标签: java opengl lwjgl

所以,我正在使用LWJGL和OpenGL渲染一些四边形和纹理。我的四边形一直很好,直到添加了一些纹理。具体来说,当我添加了向屏幕呈现文本的功能时,所有四边形颜色都变为黑色。我一直在寻找解决方案,但没有运气,最常见的答案是仅在绘制纹理时使用glEnable(GL_TEXTURE_2D);,否则在绘制四边形时禁用它。这对我来说似乎没有用,我的四边形仍然是黑色的。我已经在下面包含了我的渲染器,字体和纹理类,因为我很确定问题就在那里。

编辑:所以我做了一些测试,我甚至没有尝试绘制普通纹理(来自.png文件)但是,现在我已经尝试过这样做了好吧,我发现它们也是完全黑色的。到目前为止,唯一正确渲染的是我的字体/文本,即使我创建了一个纹理来渲染它们

Renderer.java

public class Renderer {

    private VertexArrayObject vao;
    private VertexBufferObject vbo;
    private ShaderProgram shaderProgram;

    private FloatBuffer vertices;
    private int numVertices;
    private boolean drawing;

    private Font fontSketchalot;

    public void drawQuad(float x, float y, float width, float height, Colors c) {
        glDisable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, 0);

        begin();

        if (vertices.remaining() < 5 * 7) flush();

        // Calculate Vertex positions
        float x1 = x;
        float y1 = y;
        float x2 = x + width;
        float y2 = y - height;

        // Calculate color
        float r = c.getR();
        float g = c.getG();
        float b = c.getB();

        // Put data into buffer
        vertices.put(x1).put(y1).put(r).put(g).put(b).put(0f).put(1f);
        vertices.put(x1).put(y2).put(r).put(g).put(b).put(0f).put(0f);
        vertices.put(x2).put(y2).put(r).put(g).put(b).put(1f).put(0f);
        vertices.put(x2).put(y1).put(r).put(g).put(b).put(1f).put(1f);

        // We drew X vertices
        numVertices += 4;

        end();
    }

    public void drawTextureFromTexture(Texture texture, float x, float y, float width, float height) {
        drawTexture(texture, x, y, x + width, y - height, 0, 0, 1, 1, Colors.white);
    }

    public void drawTextureFromFont(Texture texture, float x, float y, float width, float height, float s1, float t1, float sWidth, float sHeight, Colors c) {
        drawTexture(texture, x, y, x + width, y - height, s1, t1, s1 + sWidth, t1 + sHeight, c);
    }

    public void drawTexture(Texture texture, float x1, float y1, float x2, float y2, float s1, float t1, float s2, float t2, Colors c) {
        glEnable(GL_TEXTURE_2D);

        texture.prepare();

        begin();

        if (vertices.remaining() < 5 * 7) flush();

        // Calculate color
        float r = c.getR();
        float g = c.getG();
        float b = c.getB();

        // Put data into buffer
        vertices.put(x1).put(y1).put(r).put(g).put(b).put(s1).put(t2);
        vertices.put(x1).put(y2).put(r).put(g).put(b).put(s1).put(t1);
        vertices.put(x2).put(y2).put(r).put(g).put(b).put(s2).put(t1);
        vertices.put(x2).put(y1).put(r).put(g).put(b).put(s2).put(t2);

        // We drew X vertices
        numVertices += 4;

        end();

        texture.unbind();
    }

    public void drawText(String text, float x, float y, float scale, Colors c) {
        fontSketchalot.drawText(this, text, x, y, scale, c);
    }

    // Initialize renderer
    public void init(){

        // Create font
        fontSketchalot = new Font(Fonts.SKETCHALOT);

        // Set up shader programs
        setupShaderProgram();

        // Set wrapping and filtering values
        setParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
        setParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
        setParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        setParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        // Enable blending (?????)
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


    }

    // Set parameter of texture
    private void setParameter(int name, int value) {
        glTexParameteri(GL_TEXTURE_2D, name, value);
    }

    // Clears drawing area
    public void clear() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

    // Begin rendering
    public void begin() {
        if (drawing) throw new IllegalStateException("Renderer is already drawing.");
        drawing = true;
        numVertices = 0;
    }

    // End rendering
    public void end() {
        if (!drawing) throw new IllegalStateException("Renderer is not drawing.");
        drawing = false;
        flush();
    }

    // Flushes data to GPU to get rendered
    public void flush() {
        if (numVertices > 0) {
            vertices.flip();

            if (vao != null) vao.bind();
            else vbo.bind(GL_ARRAY_BUFFER);
            specifyVertexAttributes();
        }
        shaderProgram.use();

        // Upload the new vertex data
        vbo.bind(GL_ARRAY_BUFFER);
        vbo.uploadSubData(GL_ARRAY_BUFFER, 0, vertices);

        // Draw batch
        glDrawArrays(GL_QUADS, 0, numVertices);

        // Clear vertex data for next batch
        vertices.clear();
        numVertices = 0;
    }

    private void setupShaderProgram() {

        // Generate VertexArrayObject
        if (Game.is32Supported()) {
            vao = new VertexArrayObject();
            vao.bind();
        } else {
            throw new RuntimeException("OpenGL 3.2 not supported.");
        }

        // Generate VertexBufferObject
        vbo = new VertexBufferObject();
        vbo.bind(GL_ARRAY_BUFFER);



        // Create FloatBuffer
        vertices = MemoryUtil.memAllocFloat(4096);

        // Upload null data to allocate storage for the VBO
        long size = vertices.capacity() * Float.BYTES;
        vbo.uploadData(GL_ARRAY_BUFFER, size, GL_DYNAMIC_DRAW);

        // Initialize variables
        numVertices = 0;
        drawing = false;

        // Load Shaders:
        Shader vertexShader, fragmentShader;
        if (Game.is32Supported()) {
            vertexShader = Shader.loadShader(GL_VERTEX_SHADER, "res/shaders/default.vert");
            fragmentShader = Shader.loadShader(GL_FRAGMENT_SHADER, "res/shaders/default.frag");
        } else {
            throw new RuntimeException("OpenGL 3.2 not supported.");
        }

        // Create ShaderProgram
        shaderProgram = new ShaderProgram();
        shaderProgram.attachShader(vertexShader);
        shaderProgram.attachShader(fragmentShader);
        if (Game.is32Supported()) {
            shaderProgram.bindFragmentDataLocation(0, "fragColor");
        }
        shaderProgram.link();
        shaderProgram.use();

        // Delete linked shaders
        vertexShader.delete();
        fragmentShader.delete();

        // Get width & height of framebuffer
        long window = GLFW.glfwGetCurrentContext();
        int width, height;
        try (MemoryStack stack = MemoryStack.stackPush()) {
            IntBuffer widthBuffer = stack.mallocInt(1);
            IntBuffer heightBuffer = stack.mallocInt(1);
            GLFW.glfwGetFramebufferSize(window, widthBuffer, heightBuffer);
            width = widthBuffer.get();
            height = heightBuffer.get();
        }

        // Specify vertex pointers
        specifyVertexAttributes();

        // Set Model Matrix to identity matrix
        Matrix4f model = new Matrix4f();
        int uniModel = shaderProgram.getUniformLocation("model");
        shaderProgram.setUniform(uniModel, model);

        // Set View Matrix to identity matrix
        Matrix4f view = new Matrix4f();
        int uniView = shaderProgram.getUniformLocation("view");
        shaderProgram.setUniform(uniView, view);

        // Set Projection Matrix to an orthographic projection
        Matrix4f projection = Matrix4f.orthographic(0f, width, 0f, height, -1f, 1f);
        int uniProjection = shaderProgram.getUniformLocation("projection");
        shaderProgram.setUniform(uniProjection, projection);

    }

    // Specifies the vertex shader pointers (attributes)
    private void specifyVertexAttributes() {

        int posAttrib = shaderProgram.getAttributeLocation("position");
        shaderProgram.enableVertexAttribute(posAttrib);
        shaderProgram.pointVertexAttribute(posAttrib, 2, 7 * Float.BYTES, 0);

        int colAttrib = shaderProgram.getAttributeLocation("color");
        shaderProgram.enableVertexAttribute(colAttrib);
        shaderProgram.pointVertexAttribute(colAttrib, 3, 7 * Float.BYTES, 2 * Float.BYTES);

        int texAttrib = shaderProgram.getAttributeLocation("texcoord");
        shaderProgram.enableVertexAttribute(texAttrib);
        shaderProgram.pointVertexAttribute(texAttrib, 2, 7 * Float.BYTES, 5 * Float.BYTES);

        int uniTex = shaderProgram.getUniformLocation("texImage");
        shaderProgram.setUniform(uniTex, 0);

    }

}

Font.java

public class Font {

    private String fontPath;
    private java.awt.Font font;
    private Map<Character, Glyph> glyphs;
    private float fontHeight;
    private Texture texture;

    public Font(String fontPath) {
        System.out.println("Creating font...");
        this.fontPath = fontPath;
        loadFont();
        glyphs = new HashMap<>();
        texture = createFontTexture();
        System.out.println("Font created.");
    }

    public Font() {
        System.out.println("Creating font...");
        this.fontPath = "DEFAULT";
        font = new java.awt.Font(java.awt.Font.MONOSPACED, java.awt.Font.PLAIN, 30);
        glyphs = new HashMap<>();
        texture = createFontTexture();
        System.out.println("Font created.");
    }

    private void loadFont() {
        try {
            System.out.println("Loading font...");
            font = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, new FileInputStream(fontPath)).deriveFont(java.awt.Font.PLAIN, 30);
            System.out.println("Font loaded.");
        } catch (Exception e) {
            throw new RuntimeException("Could not load font.");
        }
    }

    private Texture createFontTexture() {
        int imageWidth = 0;
        int imageHeight = 0;

        //  Add up total width and height
        for (int i = 32; i < 256; i++) {
            if (i == 127) { // DEL control code
                continue;
            }
            char c = (char) i;
            BufferedImage ch = createCharImage(c);

            if (ch == null) {
                System.out.println("Could not load [CHAR: \"" + c + "\"] from font: " + fontPath);
                continue;
            }

            imageWidth += ch.getWidth();
            imageHeight = Math.max(imageHeight, ch.getHeight());
        }

        fontHeight = Converter.glfwCoordToOpenGLCoord(imageHeight);

        /* Image for the texture */
        BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();


        // Set up glyphs (Map<CHAR, GLYPH>)
        int xOffsetI = 0;
        float xOffsetF = 0;
        for (int i = 32; i < 256; i++) {
            if (i == 127) { // DEL control code
                continue;
            }

            char c = (char) i;
            BufferedImage charImage = createCharImage(c);

            if (charImage == null) {
                System.out.println("Could not load [CHAR: \"" + c + "\"] from font: " + fontPath);
                continue;
            }

            int charWidth = charImage.getWidth();
            int charHeight = charImage.getHeight();

            // Create glyph
            Glyph ch = new Glyph(Converter.glfwCoordToOpenGLCoord(charWidth), Converter.glfwCoordToOpenGLCoord(charHeight), ((float)charWidth / (float)imageWidth), (float)charHeight / (float)imageHeight, xOffsetF, 0.0f);
            // Draw char on image
            g.drawImage(charImage, xOffsetI, 0, null);
            xOffsetI += charWidth;
            xOffsetF += ch.sWidth;
            // Put in map
            glyphs.put(c, ch);
        }

        // Flip image Horizontal to get the origin to bottom left
        AffineTransform transform = AffineTransform.getScaleInstance(1f, -1f);
        transform.translate(0, -image.getHeight());
        AffineTransformOp operation = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        image = operation.filter(image, null);

        // Get char width & char height of image
        int width = image.getWidth();
        int height = image.getHeight();

        // Put pixel data into int[] pixels
        int[] pixels = new int[width * height];
        image.getRGB(0, 0, width, height, pixels, 0, width);

        // Put pixel data into byte buffer
        ByteBuffer buffer = MemoryUtil.memAlloc(width * height * 4);
        for (int i = 0; i < height; i++){
            for (int j = 0; j < width; j++) {
                // Pixel format : OxAARRGGBB
                int pixel = pixels[i * width + j];
                buffer.put((byte) ((pixel >> 16) & 0xFF));  // 0x000000RR
                buffer.put((byte) ((pixel >> 8) & 0xFF));   // 0x000000GG
                buffer.put((byte) ((pixel) & 0xFF));        // 0x000000BB
                buffer.put((byte) ((pixel >> 24) & 0xFF));  // 0x000000AA
                //buffer.put((byte)(0xFF));                 // Test
            }
        }

        buffer.flip(); // Set index back to 0

        Texture fontTexture = Texture.createTexture(width, height, buffer); // Create texture

        MemoryUtil.memFree(buffer); // Free buffer

        return fontTexture;


    }

    private BufferedImage createCharImage(char c) {
        // Begin by calculating proper width and height
        BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        if (Options.ANTIALIAS) {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        g.setFont(font);
        FontMetrics fontMetrics = g.getFontMetrics();
        g.dispose();

        int charWidth = fontMetrics.charWidth(c);
        int charHeight = fontMetrics.getHeight();

        if (charWidth == 0) return null;

        // Now set up the image
        image = new BufferedImage(charWidth, charHeight, BufferedImage.TYPE_INT_ARGB);
        g = image.createGraphics();
        if (Options.ANTIALIAS) {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        g.setFont(font);
        g.setPaint(Color.WHITE); // Use white so we can set the color while rendering
        g.drawString(String.valueOf(c), 0, fontMetrics.getAscent()); // Paint char onto image
        g.dispose();

        // Finally return the final image
        return image;

    }

    public void drawText(Renderer renderer, CharSequence text, float x, float y, float scale, Colors c) {

        float xOffset = 0;
        float yOffset = 0;

        texture.prepare();
        //renderer.begin();

        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            if (ch == '\n') {
                // If we start a new line, change the yOffset to reflect (then continue)
                yOffset -= fontHeight;
                continue;
            }
            if (ch == '\r') {
                // Skip carriage return
                continue;
            }
            Glyph g = glyphs.get(ch);
            renderer.drawTextureFromFont(texture, x + xOffset, y + yOffset, g.width * scale, g.height * scale, g.s, g.t, g.sWidth, g.sHeight, c);
            xOffset += g.width * scale;
        }

        //renderer.end();
        texture.unbind();

    }


}

Texture.java

public class Texture {

    // Store handle
    private final int id;

    private int width;
    private int height;

    private ByteBuffer image;

    // Draw texture using given renderer
    public void draw(Renderer renderer, float x, float y, float scale) {

        // Scale texture
        float w = ((float)width * scale * 2) / (Game.WIDTH);
        float h = ((float)height * scale * 2) / (Game.HEIGHT);

        renderer.drawTextureFromTexture(this, x, y, w, h);
    }

    // Create new texture
    public Texture() {
        id = glGenTextures();
    }

    // Prepare texture to be drawn
    public void prepare() {
        bind();
        uploadData(width, height, image);
    }

    // Bind texture
    public void bind() {
        glBindTexture(GL_TEXTURE_2D, id);
    }

    // Set parameter of texture
    private void setParameter(int name, int value) {
        glTexParameteri(GL_TEXTURE_2D, name, value);
    }

    // Upload image data with specified width and height
    public void uploadData(int width, int height, ByteBuffer data) {
        uploadData(GL_RGBA8, width, height, GL_RGBA, data);
    }

    // Upload image data with specified internal format, width, height, and image format
    public void uploadData(int internalFormat, int width, int height, int format, ByteBuffer data) {
        glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, data);
    }

    // Delete texture
    public void delete() {
        glDeleteTextures(id);
    }

    // Get width
    public int getWidth() {
        return width;
    }

    // Set width
    public void setWidth(int width) {
        if (width > 0) {
            this.width = width;
        }
    }

    // Get height
    public int getHeight() {
        return height;
    }

    // Set height
    public void setHeight(int height) {
        if (height > 0) {
            this.height = height;
        }
    }

    // Set image
    public void setImage(ByteBuffer image) {
        this.image = image;
    }

    public static Texture createTexture(int width, int height, ByteBuffer image) {
        Texture texture = new Texture();
        texture.setWidth(width);
        texture.setHeight(height);
        texture.setImage(image);

        texture.prepare();

        return texture;
    }

    public static Texture loadTexture(String path) {
        ByteBuffer image;
        int width, height;
        try (MemoryStack stack = MemoryStack.stackPush()) {
            IntBuffer w = stack.mallocInt(1);
            IntBuffer h = stack.mallocInt(1);
            IntBuffer comp = stack.mallocInt(1);

            // Load image
            stbi_set_flip_vertically_on_load(true);
            image = stbi_load(path, w, h, comp, 4);
            if (image == null) throw new RuntimeException("Could not load texture.");
            width = w.get();
            height = h.get();
        }

        return createTexture(width, height, image);

    }

    public void unbind() {
        glBindTexture(GL_TEXTURE_2D, 0);
    }

}

0 个答案:

没有答案