如何用Java OpenGL渲染中文文本

最近在尝试学LWJGL,它的图形部分是opengl,但是找到的教程基本都是c++的,java的实在是太少了,尤其是渲染文字这里……有没有人能给个完整一点的渲染中文文字到窗口上的例子…

可以看看webgl


import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.Color;
import org.newdawn.slick.TrueTypeFont;
import org.newdawn.slick.util.ResourceLoader;

import java.awt.Font;
import java.io.InputStream;

import static org.lwjgl.opengl.GL11.*;

public class ChineseTextRenderingExample {

    public static void main(String[] args) {
        try {
            Display.setDisplayMode(new DisplayMode(800, 600));
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
            System.exit(0);
        }

        // Load a Chinese TrueTypeFont from a font file
        try {
            InputStream inputStream = ResourceLoader.getResourceAsStream("path/to/your/chinese/font.ttf");
            Font awtFont = Font.createFont(Font.TRUETYPE_FONT, inputStream);
            awtFont = awtFont.deriveFont(24f);
            TrueTypeFont font = new TrueTypeFont(awtFont, true);
            
            while (!Display.isCloseRequested()) {
                glClear(GL_COLOR_BUFFER_BIT);

                // Render Chinese text
                font.drawString(100, 100, "你好,世界!", Color.white);

                Display.update();
                Display.sync(60);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Display.destroy();
        }
    }
}

LWJGL是一个基于Java的开源游戏开发框架,包含OpenGL、OpenAL和OpenCL的Java绑定库。要在LWJGL中渲染文字,我们可以使用Slick2D或TrueTypeFont库提供的API。

以下是使用Slick2D渲染中文文字到窗口的示例代码:

import org.newdawn.slick.*;
import org.newdawn.slick.font.*;
import java.awt.Font;

public class Main extends BasicGame {

    private UnicodeFont textFont;

    public Main(String title) {
        super(title);
    }

    public void init(GameContainer gc) throws SlickException {
        // Create a TrueTypeFont object from a font file.
        Font font = new Font("SimSun", Font.PLAIN, 24);
        textFont = new UnicodeFont(font);
        // The anti-aliasing and fractional metrics options of the font must be set in order to support Chinese characters.
        textFont.addAsciiGlyphs();
        textFont.addGlyphs(0x4e00, 0x9fff); // Add Chinese characters.
        textFont.getEffects().add(new ColorEffect(java.awt.Color.WHITE)); // Set the text color to white.
        textFont.getEffects().add(new OutlineEffect(1, java.awt.Color.BLACK)); // Add a black outline to the text.
        textFont.addAsciiGlyphs();
        textFont.loadGlyphs();
    }

    public void render(GameContainer gc, Graphics g) throws SlickException {
        g.setFont(textFont);
        g.drawString("你好,世界!", 100, 100);
    }

    public void update(GameContainer gc, int delta) throws SlickException {
        // Update the game state.
    }

    public static void main(String[] args) throws SlickException {
        AppGameContainer app = new AppGameContainer(new Main("Hello World"));
        app.setDisplayMode(640, 480, false);
        app.start();
    }

}

在上述示例代码中,我们使用UnicodeFont类加载了一个TrueType字体文件(“SimSun”,使用24号字体大小),并配置它以支持中文字符。然后,我们将字体应用于Graphics对象,并使用drawString()函数在屏幕上绘制字符串("你好,世界!")。

请注意,UnicodeFont类是Slick2D库的一部分,但这种方法在LWJGL 3中已被弃用。如果使用LWJGL 3,您需要使用OpenGL库中提供的API来渲染文字。

给你个示例,是从newbing国际版找到的


import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import org.lwjgl.stb.STBTTAlignedQuad;
import org.lwjgl.stb.STBTTBakedChar;
import org.lwjgl.stb.STBTTFontinfo;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.GL_CLAMP_TO_EDGE;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL13.glActiveTexture;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.stb.STBTruetype.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.NULL;

public class Main {

    private long window;
    private int fontHeight = 24;
    private STBTTFontinfo fontInfo;
    private STBTTBakedChar.Buffer fontBuffer;
    private int fontTexture;

    public void run() {
        init();
        loop();
        cleanup();
    }

    private void init() {
        GLFWErrorCallback.createPrint(System.err).set();

        if (!glfwInit()) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

        window = glfwCreateWindow(800, 600, "LWJGL Unicode Text Rendering", NULL, NULL);
        if (window == NULL) {
            throw new RuntimeException("Failed to create the GLFW window");
        }

        try (MemoryStack stack = stackPush()) {
            IntBuffer pWidth = stack.mallocInt(1);
            IntBuffer pHeight = stack.mallocInt(1);

            glfwGetWindowSize(window, pWidth, pHeight);

            GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
            glfwSetWindowPos(window, (vidMode.width() - pWidth.get(0)) / 2, (vidMode.height() - pHeight.get(0)) / 2);
        }

        glfwMakeContextCurrent(window);
        glfwSwapInterval(1);
        glfwShowWindow(window);

        GL.createCapabilities();

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

        initFont();
    }

    private void initFont() {
        try {
            Path fontPath = Paths.get("path_to_your_truetype_font.ttf");
            byte[] fontBytes = Files.readAllBytes(fontPath);

            ByteBuffer fontBuffer = BufferUtils.createByteBuffer(fontBytes.length);
            fontBuffer.put(fontBytes);
            fontBuffer.flip();

            this.fontInfo = STBTTFontinfo.create();
            if (!stbtt_InitFont(fontInfo, fontBuffer)) {
                throw new RuntimeException("Failed to initialize font");
            }

            ByteBuffer bitmap = BufferUtils.createByteBuffer(512 * 512);
            this.fontBuffer = STBTTBakedChar.malloc(96);

            stbtt_BakeFontBitmap(fontBuffer, fontHeight, bitmap, 512, 512, 32, fontBuffer);

            fontTexture = glGenTextures();
            glBindTexture(GL_TEXTURE_2D, fontTexture);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512, 512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            glBindTexture(GL_TEXTURE_2D, 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void render() {
        glClear(GL_COLOR_BUFFER_BIT);

        try (MemoryStack stack = stackPush()) {
            FloatBuffer xBuffer = stack.floats(10.0f);
            FloatBuffer yBuffer = stack.floats(10.0f);

            String text = "你好,世界!";
            ByteBuffer textBuffer = MemoryUtil.memUTF8(text, true);

            float scaleFactor = stbtt_ScaleForPixelHeight(fontInfo, fontHeight);

            int[] width = new int[1];
            int[] height = new int[1];

            stbtt_GetScaledBitmapSize(fontInfo, 0, scaleFactor, width, height);

            STBTTAlignedQuad quad = STBTTAlignedQuad.mallocStack(stack);

            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, fontTexture);

            glBegin(GL_QUADS);
            for (int i = 0; i < textBuffer.capacity(); i++) {
                int ch = textBuffer.get(i) & 0xFF;

                if (ch == '\n') {
                    yBuffer.put(0, yBuffer.get(0) + fontHeight);
                    xBuffer.put(0, 10.0f);
                    continue;
                }

                stbtt_GetBakedQuad(fontBuffer, 512, 512, ch - 32, xBuffer, yBuffer, quad, true);

                glTexCoord2f(quad.s0(), quad.t1());
                glVertex2f(quad.x0(), quad.y1());

                glTexCoord2f(quad.s1(), quad.t1());
                glVertex2f(quad.x1(), quad.y1());

                glTexCoord2f(quad.s1(), quad.t0());
                glVertex2f(quad.x1(), quad.y0());

                glTexCoord2f(quad.s0(), quad.t0());
                glVertex2f(quad.x0(), quad.y0());
            }
            glEnd();

            glBindTexture(GL_TEXTURE_2D, 0);
            glDisable(GL_TEXTURE_2D);
        }

        glfwSwapBuffers(window);
    }

    private void loop() {
        while (!glfwWindowShouldClose(window)) {
            glfwPollEvents();
            render();
        }
    }

    private void cleanup() {
        stbtt_FreeBitmap(fontBuffer, 0);

        glDeleteTextures(fontTexture);

        glfwDestroyWindow(window);

        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    public static void main(String[] args) {
        Main app = new Main();
        app.run();
    }
}

引用chatgpt内容作答:
在使用Java的LWJGL和OpenGL来渲染中文文本时,你可以借助一些库来实现这个目标。一个常用的库是"JFont",它可以帮助你在OpenGL中渲染文字。以下是一个基本的步骤和示例代码,演示如何渲染中文文本到窗口上:

1、确保你已经配置好了LWJGL和OpenGL的环境。你需要导入LWJGL库,并设置OpenGL上下文。

2、引入相关库。你需要引入org.lwjgl和org.lwjgl.glfw包,以及JFont库。你可以通过Maven或手动下载添加这些库。

3、创建OpenGL窗口和上下文。这一步不在本例中展示,你可以查阅LWJGL的官方文档来了解如何创建窗口和OpenGL上下文。

4、使用JFont库渲染中文文本。

以下是一个简化的示例代码,演示如何在OpenGL中渲染中文文本:

import org.lwjgl.opengl.GL;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GLUtil;
import me.jartreg.lwjgltextrenderer.FontRenderer;

public class ChineseTextRenderer {
    public static void main(String[] args) {
        // 初始化GLFW
        if (!GLFW.glfwInit()) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        // 创建窗口和OpenGL上下文
        long window = GLFW.glfwCreateWindow(800, 600, "Chinese Text Renderer", 0, 0);
        if (window == 0) {
            throw new RuntimeException("Failed to create the GLFW window");
        }

        GLFW.glfwMakeContextCurrent(window);
        GL.createCapabilities();
        
        // 初始化JFont
        FontRenderer fontRenderer = new FontRenderer("path/to/your/font.ttf", 24); // 使用你的字体文件路径和字体大小

        // 渲染循环
        while (!GLFW.glfwWindowShouldClose(window)) {
            GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

            // 渲染中文文本
            fontRenderer.renderText("你好,世界!", 100, 100); // 文本内容和位置
            
            // 交换缓冲区和处理事件
            GLFW.glfwSwapBuffers(window);
            GLFW.glfwPollEvents();
        }

        // 清理资源
        fontRenderer.cleanup();
        GLFW.glfwDestroyWindow(window);
        GLFW.glfwTerminate();
    }
}

这只是一个简化的示例,你需要根据自己的需要进行适当的修改和优化。确保将"path/to/your/font.ttf"替换为你的字体文件的实际路径。

此外,FontRenderer的初始化可能需要更多的设置,以及对错误处理和资源清理的更多处理。你可以参考JFont库的文档来获得更详细的信息。

最后,记得要理解OpenGL渲染的基本概念和流程,以便更好地理解和修改上述示例。

【以下回答由 GPT 生成】

对于使用Java OpenGL渲染中文文本的问题,以下是一个解决方案的步骤:

步骤1: 设置环境 首先,确保你已正确设置OpenGL和LWJGL环境。在项目中引入LWJGL库,并确保可以正确编译和运行OpenGL程序。

步骤2: 添加中文字体文件 在项目中添加一个中文字体文件,通常是一个.ttf格式的文件。可以从开放字库(Open Font Library)或其他字体网站下载合适的字体文件。

步骤3: 加载字体 使用Java的字体库加载所选择的中文字体。可以使用Java中的Font类和Font.createFont()方法来加载字体文件,并使用Font.deriveFont()方法设置字体的大小和样式。

File fontFile = new File("path/to/your/font.ttf");
Font customFont = Font.createFont(Font.TRUETYPE_FONT, fontFile);
Font font = customFont.deriveFont(50f); // 设置字体大小和样式

步骤4: 创建纹理贴图 将字体渲染成纹理贴图。在OpenGL中,将字体渲染成纹理贴图是一种常见的做法,这样可以在渲染时以纹理的方式展示文本。

在这个步骤中,你需要使用Java的Graphics2D类绘制文本,并将其渲染到OpenGL纹理中。首先,创建一个BufferedImage对象,设置绘图属性,然后使用Graphics2D对象绘制文本。

// 创建BufferedImage对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

// 创建Graphics2D对象
Graphics2D g2d = (Graphics2D) image.getGraphics();

// 设置绘图属性
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setFont(font);
g2d.setColor(Color.WHITE);
g2d.setBackground(Color.TRANSPARENT);

// 绘制文本
g2d.drawString("你的中文文本", x, y);

注意,在绘制文本之前,可能需要设置BufferedImage的长和宽以适应你的文本。

步骤5: 将纹理映射到OpenGL对象 将文本渲染结果映射到OpenGL的纹理对象中,以便可以将其绘制到窗口上。

首先,创建一个新的OpenGL纹理对象,使用Java的BufferedImagegetRGB()方法将像素数据从BufferedImage中提取出来,并将其存储到OpenGL纹理对象中。

// 生成纹理对象
int textureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureID);

// 提取像素数据
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);

// 将像素数据传入OpenGL纹理对象
ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 4);
for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        int pixel = pixels[y * width + x];
        buffer.put((byte) ((pixel >> 16) & 0xFF)); // 红色分量
        buffer.put((byte) ((pixel >> 8) & 0xFF)); // 绿色分量
        buffer.put((byte) (pixel & 0xFF)); // 蓝色分量
        buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha分量
    }
}

buffer.flip();

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

步骤6: 渲染文本 使用OpenGL,将纹理绘制到窗口上。

在绘制文本之前,你需要设置OpenGL的视口(Viewport),使用glViewport()方法。

glViewport(0, 0, windowWidth, windowHeight);

接着,在绘制循环中,使用OpenGL的基本绘制函数,如glBegin()glVertex2f()glTexCoord2f()等,在窗口上绘制文本。

glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, windowWidth, windowHeight, 0, -1, 1); // 设置2D正交投影矩阵

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID);

glColor3f(1.0f, 1.0f, 1.0f); // 设置绘制颜色为白色

// 绘制文本
glBegin(GL_QUADS);
{
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);

    glTexCoord2f(1, 0);
    glVertex2f(width, 0);

    glTexCoord2f(1, 1);
    glVertex2f(width, height);

    glTexCoord2f(0, 1);
    glVertex2f(0, height);
}
glEnd();

glDisable(GL_TEXTURE_2D);

至此,你已经成功使用Java OpenGL渲染中文文本。完成以上步骤后,运行程序,应该能够在窗口中看到渲染的中文文本。

希望这个解决方案能对你有所帮助。如果你还有任何问题,请随时提问。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^