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

4
我正在开发一个游戏,希望将一些简单的3D功能加入其中。为了实现这个目标,我使用了LibGDX游戏引擎,因为它似乎很好地集成了OpenGL ES。然而,我遇到了一个问题,即无法弄清楚如何从Java中的图像创建一个简单的缓冲对象。
问题是,我希望在三维空间中有一个旋转的立方体,并贴上一些纹理。虽然我设法渲染出了立方体并让它旋转,但我似乎找不到任何教程、代码示例或文档来解码图像以便将其作为缓冲纹理应用到立方体上。我找到了很多在Android中完成此操作的示例,但这将限制您必须使用Android SDK中的BitmapFactory.decodeResource(<your_image here>)方法,这对我来说不是一个选项,因为我希望我的代码可以在许多平台上运行。
出于这个原因,我得出结论,必须以某种方式将图像(一个.bmp文件)解码为Buffer,以利用OpenGL ES中附带的Gdx.gl10.glTexImage2D()方法。

我已经尝试过的方法

我尝试了许多替代方案来寻找解决方案,其中包括:

  • 利用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中将图像直接解码为Buffer?如果无法完成,那么我应该如何尝试在LibGDX中为我的3D对象进行纹理处理?还有其他资源应该参考吗?

调试信息

最后更新时间:2013年3月19日下午12:45 EST

这里是与当前应用程序调试过程相关的一些信息。随着问题的进展,我会不断更新:

  • 目前,当我运行我的应用程序时,我收到一个错误 Invalid memory access of location 0x0 rip=0x11dc77564,也许这个实现是正确的,我只是在其他地方漏掉了一些语法?
  • 我目前正在调查this我在翻阅一些论坛后发现的额外资源。
  • 似乎Mesh对象将是正确的路线。 我将尝试追求这个实现并更新我的结果!由于LibGDX团队认为它已被“弃用”,所以我之前找不到它,因此我不确定这是否会很快被替换。

补充信息

回答我的问题时应考虑以下几点:

  • 需要注意的是,我正在使用LibGDX游戏引擎进行此操作,因此,我也将在他们的论坛上发布关于这个问题的帖子。

  • 此外,似乎有很多方法可以从图像中获取BufferedImage,但是然后没有办法从那个BufferedImage中提取一个Buffer。我是否只是忽略了一些非常明显的东西?BufferedImage真的是我所需要的全部吗?

  • 我不想只是将Android SDK包含在我的构建路径中,并使用他们简单的BitmapFactory.decodeResource(<your_image_here>)方法。

  • 目前,我正在尝试使用OpenGL ES 1.0实现这一点,以确保兼容性。


2
+1 鼓励你做好研究并清晰地解释你的情况。 - Zach Latta
1个回答

2
我认为您想避免使用原始的OpenGL纹理和缓冲区API,而是使用Libgdx的MeshTexture包装器。它们隐藏了一些OpenGL细节。当然,如果您有兴趣学习OpenGL细节,这并不会真正帮助您。(但也许您可以通过Libgdx API使事情正常运作,然后查看它们的源代码,了解实际发生的事情)。
第一步是确保您的Mesh(或者如果您没有使用Mesh,则是原始的mVertexBuffer OpenGL顶点列表)在每个顶点中都包含有效的(u, v)纹理坐标。这些坐标将在渲染时引用“当前”纹理。请参见https://code.google.com/p/libgdx/wiki/MeshColorTexture#Texture
首先,定义您的Mesh以包括每个顶点的纹理信息:
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对象,然后将其插入到Texture中。

其次,请确保每个顶点都有与之关联的(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)坐标的“网格”。
第二步是在“渲染”调用期间绑定纹理,以便“网格”中的(u,v)坐标有东西可以引用:
texture.bind();
mesh.render(GL10.GL_TRIANGLES, 0, 3);

你不需要直接使用任何OpenGL纹理或顶点的API。


谢谢你的回答!正如你从我的更新的“调试信息”中看到的,我也在他们的论坛上找到了这个文档!不过由于他们正在开发新的3D API,所以它很可能已经被弃用了。我非常感谢你详细和全面地解释了如何实现“Mesh”类,并且我将在下一次尝试中大量使用它! - Squagem
1
我对Libgdx 3D API并不太熟悉,除了知道它们仍在不断变化。无论它们做什么,最终都会归结为像这样的顶点列表,所以你不应该离谱太远。 - P.T.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接