LibGDX - 使用 Modelbuilder.createBox 将单个纹理映射到盒子的每个面

2022-01-12 00:00:00 java libgdx

我有以下生成 3D 立方体的代码片段:

I have the following code snippet that generates a 3D cube:

ModelBuilder modelBuilder = new ModelBuilder();

box = modelBuilder.createBox(2f, 2f, 2f,
                new Material(TextureAttribute.createDiffuse(AssetLoader.tr[0])),
                VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates
        );

到目前为止一切顺利.问题是立方体的所有面都使用相同的纹理,而我想要的是 Assetloader.tr[],它是一个数组,每个面上分别出现 6 个单独的纹理.

So far so good. The problem is that all faces of the cube uses the same texture, whereas what I want is Assetloader.tr[], which is an array with 6 individual textures to appear on each face respectively.

我试过了

box.nodes.get(0).parts.get(0).material.set(new Material(TextureAttribute.createDiffuse(AssetLoader.tr[0])));
box.nodes.get(0).parts.get(1).material.set(new Material(TextureAttribute.createDiffuse(AssetLoader.tr[1])));
...

但不知何故,文档并没有给我任何关于如何正确执行它的提示.我有点卡在这里atm.

but somehow the documentation doesn't give me any hints for how to do it properly. I'm a bit stuck here atm.

推荐答案

有几个注意事项需要牢记.首先请务必仔细阅读:https://github.com/libgdx/libgdx/wiki/ModelBuilder%2C-MeshBuilder-and-MeshPartBuilder.

There are several considerations to keep in mind. First of all make sure to carefully read: https://github.com/libgdx/libgdx/wiki/ModelBuilder%2C-MeshBuilder-and-MeshPartBuilder.

其次,尽量避免使用 ModelBuilder#createXXX 方法.它们只是调试和测试目的的捷径.如果您查看 code 后面,你会发现它非常简单:

Secondly, try to avoid the ModelBuilder#createXXX methods. They are just a shortcut for debugging and testing purposes. If you look at the code behind it, you'll see that's very straightforward:

modelBuilder.begin();
modelBuilder.part("box", GL20.GL_TRIANGLES, 
        VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates,
        new Material(TextureAttribute.createDiffuse(AssetLoader.tr[0])))
    .box(2f, 2f, 2f);
box = modelBuilder.end();

正如您所见,这会为整个盒子创建一个部分,因此尝试访问第二个部分(如您在示例中所做的那样)将不起作用.但是因为您想为每个面使用不同的材料,所以您需要为每个面创建一个零件.

As you can see this creates a single part for the entire box, so trying to access a second part (as you do in your example) will not work. But because you want to use a different material for each face, you'll need to create a part for each face.

int attr = VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates;
modelBuilder.begin();
modelBuilder.part("front", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(AssetLoader.tr[0])))
    .rect(-2f,-2f,-2f, -2f,2f,-2f,  2f,2f,-2, 2f,-2f,-2f, 0,0,-1);
modelBuilder.part("back", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(AssetLoader.tr[1])))
    .rect(-2f,2f,2f, -2f,-2f,2f,  2f,-2f,2f, 2f,2f,2f, 0,0,1);
modelBuilder.part("bottom", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(AssetLoader.tr[2])))
    .rect(-2f,-2f,2f, -2f,-2f,-2f,  2f,-2f,-2f, 2f,-2f,2f, 0,-1,0);
modelBuilder.part("top", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(AssetLoader.tr[3])))
    .rect(-2f,2f,-2f, -2f,2f,2f,  2f,2f,2f, 2f,2f,-2f, 0,1,0);
modelBuilder.part("left", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(AssetLoader.tr[4])))
    .rect(-2f,-2f,2f, -2f,2f,2f,  -2f,2f,-2f, -2f,-2f,-2f, -1,0,0);
modelBuilder.part("right", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(AssetLoader.tr[5])))
    .rect(2f,-2f,-2f, 2f,2f,-2f,  2f,2f,2f, 2f,-2f,2f, 1,0,0);
box = modelBuilder.end();

但是,每个面都有一个零件确实意味着每个面都有一个渲染调用.确保所有 TextureRegion 共享相同的纹理并改为使用该纹理会更高效:

However, having a part for each face does imply a render call for each face. It is more performant to make sure that all TextureRegions share the same texture and use that instead:

int attr = VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates;
modelBuilder.begin();
MeshPartBuilder mpb = modelBuilder.part("box", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(AssetLoader.tr[0].getTexture())));
mpb.setUVRange(AssetLoader.tr[0]);
mpb.rect(-2f,-2f,-2f, -2f,2f,-2f,  2f,2f,-2, 2f,-2f,-2f, 0,0,-1);
mpb.setUVRange(AssetLoader.tr[1]);
mpb.rect(-2f,2f,2f, -2f,-2f,2f,  2f,-2f,2f, 2f,2f,2f, 0,0,1);
mpb.setUVRange(AssetLoader.tr[2]);
mpb.rect(-2f,-2f,2f, -2f,-2f,-2f,  2f,-2f,-2f, 2f,-2f,2f, 0,-1,0);
mpb.setUVRange(AssetLoader.tr[3]);
mpb.rect(-2f,2f,-2f, -2f,2f,2f,  2f,2f,2f, 2f,2f,-2f, 0,1,0);
mpb.setUVRange(AssetLoader.tr[4]);
mpb.rect(-2f,-2f,2f, -2f,2f,2f,  -2f,2f,-2f, -2f,-2f,-2f, -1,0,0);
mpb.setUVRange(AssetLoader.tr[5]);
mpb.rect(2f,-2f,-2f, 2f,2f,-2f,  2f,2f,2f, 2f,-2f,2f, 1,0,0);
box = modelBuilder.end();

虽然这可能对您有所帮助,但您确实应该重新考虑您的方法.如您所见,通过代码创建模型会很快变得一团糟.此外,在大多数情况下,为盒子创建单个模型远非最佳,除非您的目标是仅渲染单个盒子且仅渲染一个盒子.而是使用建模应用程序来创建模型.查看我的博客 http://blog.xoppa.com/ 了解更多信息.如果您真的想自己修改零件,请确保至少阅读并包括幕后"教程.

While this might help you do you want, you should really reconsider your approach. As you can see, creating a model by code can get messy really fast. And, moreover, creating a single model for a box is in most cases far from optimal unless your goal is to only render a single box and nothing more than a box. Instead use a modeling application to create your models. Have a look at my blog at http://blog.xoppa.com/ for more info. If you really want to modify parts yourself, then make sure to read at least up to and including the "behind the scenes" tutorials.

相关文章