在Java中将图像转换为缓冲区

我正在尝试将一些简单的3D功能实现到我正在开发的游戏中.我正在利用LibGDX游戏引擎来实现这个目标,因为它似乎很好地与OpenGL ES集成,但是由于我无法弄清楚如何从
Java中的图像创建一个简单的Buffer对象而遇到了一个问题.

问题

我的目标是让一个立方体在3D空间中旋转,上面有一些纹理.问题是,虽然我设法渲染立方体并让它旋转,但我似乎找不到任何关于如何将图像实际解码到缓冲区以便纹理立方体的教程,代码示例或文档.我已经找到了很多例子来说明如何在Android中执行此操作,但这限制了您必须在Android SDK中使用BitmapFactory.decodeResource(< your_image here>)方法,这对我来说不是一个选项,因为我试图让我的代码可以移植到许多平台上.

正是出于这个原因,我得出的结论是,我必须找到一种方法将图像(.bmp文件)解码为缓冲区,以便利用我发现打包的Gdx.gl10.glTexImage2D()方法OpenGL ES.

我迄今为止所做的一切

我已经寻求了许多替代品来尝试寻找解决方案,其中一些包括:

>利用LibGDX包附带的Texture类中嵌入的Texture.bind()方法.
>尝试使用Java ImageIO软件包解码图像.
>使用其他解码工具,如image4j库.

一些代码

以下是我用于渲染多维数据集的一些代码.为了清楚起见,省略了很多OpenGL“切换翻转”,所以如果你认为我错过了什么,请发表评论,我会确认它是否只是在另一个班级的另一部分.

我知道这个代码对于筛选是相当令人窒息的,所以我尽力在必要时对其进行评论.

请注意,此代码表示我当前的实现,并且是与下面的“调试信息”部分相关联的代码.

public void draw(){

    // This is used to hold the OpenGL pointer to the texture      
    int[] textures = new int[1];

    // Tells the GPU to render the vertices in a clockwise manner   
    Gdx.gl10.glFrontFace(GL10.GL_CW);

    // Informs OpenGL of the location of the vertices
    Gdx.gl10.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);

    // Bind the texture pointer in OpenGL to the texture
    Gdx.gl10.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

    // This is the function I found in LibGDX that I think I am supposed to use?
    mTexture.bind();

    // Some "switch-flipping" in OpenGL
    Gdx.gl10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
            GL10.GL_NEAREST);

    Gdx.gl10.glTexParameterf(GL10.GL_TEXTURE_2D,
            GL10.GL_TEXTURE_MAG_FILTER,
            GL10.GL_LINEAR);

    Gdx.gl10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
            GL10.GL_CLAMP_TO_EDGE);

    Gdx.gl10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
            GL10.GL_CLAMP_TO_EDGE);

    Gdx.gl10.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
            GL10.GL_REPLACE);

    // This tells OpenGL to assign my Texture to the 3D Image
    Gdx.gl10.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGB, 256, 256, 0, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, mTexture);

    // Finally, this draws the objects to the screen
    Gdx.gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
}

我的问题

如何将图像直接解码为Java中的缓冲区?如果无法做到这一点,那么我该如何尝试在LibGDX中构建我的3D对象呢?我还应该咨询其他资源吗?

调试信息

最后更新:2013年3月19日美国东部时间下午12:45

以下是与我的应用程序的当前调试过程相关的一些信息.在我解决这个问题时,我会更新这个:

>目前,当我运行我的应用程序时,我收到错误无效的内存访问位置0x0 rip = 0x11dc77564,也许这个实现是正确的,我只是在其他地方缺少一些语法?
>我目前正在调查我在筛选一些论坛后发现的this额外资源.
>看来Mesh对象在这里是正确的路线.我会尝试继续这个实现并更新我的结果!我之前无法找到它,因为LibGDX团队认为它已被“弃用”,所以我不确定这是否会很快被替换.

补充信息

在回答我的问题时应该考虑的一些事项是:

>应该注意的是,我使用LibGDX Game Engine进行此操作,因此,我还将在论坛上发布有关此问题的信息.
>此外,似乎有很多方法可以从Image获取BufferedImage,但是没有办法从BufferedImage中提取Buffer.我只是忽略了这里明显的东西吗? BufferedImages真的应该是我需要的吗?
>我不希望仅在我的构建路径中包含Android SDK并使用其简单的BitmapFactory.decodeResource(< your_image_here>)方法.
>出于兼容性原因,我目前正在尝试使用OpenGL ES 1.0实现此功能.

最佳答案 我想你想避免原始的OpenGL纹理和缓冲API,并坚持使用Libgdx Mesh和Texture包装器.他们隐藏了一堆OpenGL细节.当然,如果您有兴趣了解OpenGL的详细信息,这将无济于事. (但也许你可以使用Libgdx API处理它们,然后查看它们的来源以查看真正发生的事情).

第一步是确保你的Mesh(或你的原始mVertexBuffer OpenGL顶点列表,如果你没有使用Mesh)包含每个顶点的有效(u,v)纹理坐标.这些坐标将在渲染时引用“当前”纹理.见https://code.google.com/p/libgdx/wiki/MeshColorTexture#Texture.

首先,定义网格以包含每个顶点的纹理信息:

mesh = new Mesh(true, 3, 3, 
            new VertexAttribute(Usage.Position, 3, "a_position"),
            new VertexAttribute(Usage.ColorPacked, 4, "a_color"),
            new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords"));

(此网格也有颜色数据,但如果您不想混合原始颜色数据,则可以使用“a_color”.)

另一个准备步骤是将纹理文件加载到Libgdx纹理中.假设文件打包在标准的“assets”位置,您应该只能使用相对路径加载它:

Texture texture = new Texture("path/to/image.bmp");

Libgdx通常可以加载和解析BMP,PNG和JPEG文件格式.对于其他格式,我认为您需要自己创建一个Pixmap对象,然后将其插入纹理.

其次,确保每个顶点都有与之关联的(u,v)纹理坐标:

mesh.setVertices(new float[] { -0.5f, -0.5f, 0, Color.toFloatBits(255, 0, 0, 255), 0, 1,
                                0.5f, -0.5f, 0, Color.toFloatBits(0, 255, 0, 255), 1, 1
                                0, 0.5f, 0, Color.toFloatBits(0, 0, 255, 255), 0.5f, 0 });

上面的每一行定义了每个顶点的“(x,y,z,rgba,u,v)”. (“rgba”是整个颜色压成一个浮子.)

此时,您已使用颜色信息和纹理(u,v)坐标定义了网格.

第二步是在渲染调用期间绑定纹理,因此Mesh中的(u,v)坐标有引用的东西:

texture.bind();
mesh.render(GL10.GL_TRIANGLES, 0, 3);

您不需要直接使用任何OpenGL纹理或顶点API.

点赞