简体   繁体   中英

Texturing a cube in libgdx 3D

I wrote the following class to create cube models in libgdx.

package io.github.l0lk.zombieyeti.block;

import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;

public enum BlockType {

    GRASS("dirt", 0, 0, 3, 0, 2, 0),
    STONE("stone", 1, 0, 1, 0, 1, 0),
    PLANK("plank", 4, 0, 4, 0, 4, 0),
    GLASS("glass", 1, 3, 1, 3, 1, 3);

    public static int TEXTURE_WIDTH = 16;

    String name;
    int textureTopX, textureTopY;
    int textureSideX, textureSideY;
    int textureBottomX, textureBottomY;

    TextureRegion textureRegionTop = null;
    TextureRegion textureRegionSide = null;
    TextureRegion textureRegionBottom = null;

    Model model;

    BlockType(String name, int textureTopX, int textureTopY, int textureSideX, int textureSideY, int textureBottomX, int textureBottomY) {
        this.name = name;
        this.textureTopX = textureTopX;
        this.textureTopY = textureTopY;
        this.textureSideX = textureSideX;
        this.textureSideY = textureSideY;
        this.textureBottomX = textureBottomX;
        this.textureBottomY = textureBottomY;
    }

    public static void createTexturesAndModels(Texture texture) {
        ModelBuilder modelBuilder = new ModelBuilder();

        for(BlockType type : values()) {
            type.textureRegionTop = new TextureRegion(texture, type.textureTopX * TEXTURE_WIDTH, type.textureTopY * TEXTURE_WIDTH, TEXTURE_WIDTH, TEXTURE_WIDTH);
            type.textureRegionSide = new TextureRegion(texture, type.textureSideX * TEXTURE_WIDTH, type.textureSideY * TEXTURE_WIDTH, TEXTURE_WIDTH, TEXTURE_WIDTH);
            type.textureRegionBottom = new TextureRegion(texture, type.textureBottomX * TEXTURE_WIDTH, type.textureBottomY * TEXTURE_WIDTH, TEXTURE_WIDTH, TEXTURE_WIDTH);

            int attr = VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates;
            modelBuilder.begin();
            MeshPartBuilder meshPartBuilder = modelBuilder.part("box", GL20.GL_TRIANGLES, attr, new Material(TextureAttribute.createDiffuse(type.textureRegionTop)));
            meshPartBuilder.setUVRange(type.textureRegionTop);
            meshPartBuilder.rect(-0.5f,-0.5f,-0.5f, -0.5f, 0.5f, -0.5f, 0.5f,0.5f,-0.5f, 0.5f,-0.5f,-0.5f, 0, 0, -1);
            meshPartBuilder.setUVRange(type.textureRegionSide);
            meshPartBuilder.rect(-0.5f,0.5f,0.5f, -0.5f,-0.5f,0.5f,  0.5f,-0.5f,0.5f, 0.5f,0.5f,0.5f, 0,0,1);
            meshPartBuilder.setUVRange(type.textureRegionSide);
            meshPartBuilder.rect(-0.5f,-0.5f,0.5f, -0.5f,-0.5f,-0.5f,  0.5f,-0.5f,-0.5f, 0.5f,-0.5f,0.5f, 0,-1,0);
            meshPartBuilder.setUVRange(type.textureRegionSide);
            meshPartBuilder.rect(-0.5f,0.5f,-0.5f, -0.5f,0.5f,0.5f,  0.5f,0.5f,0.5f, 0.5f,0.5f,-0.5f, 0,1,0);
            meshPartBuilder.setUVRange(type.textureRegionSide);
            meshPartBuilder.rect(-0.5f,-0.5f,0.5f, -0.5f,0.5f,0.5f,  -0.5f,0.5f,-0.5f, -0.5f,-0.5f,-0.5f, -1,0,0);
            meshPartBuilder.setUVRange(type.textureRegionBottom);
            meshPartBuilder.rect(0.5f,-0.5f,-0.5f, 0.5f,0.5f,-0.5f,  0.5f,0.5f,0.5f, 0.5f,-0.5f,0.5f, 1,0,0);
            type.model = modelBuilder.end();
        }
    }
}

This is the texture file I use as input.

纹理文件

That code produces the following cubes (depending on the texture). 渲染立方体的图像

Any idea how to fix this? I have tried to read about this but still cant fully understand the problem.

EDIT 1:

After setting every texture to null except in new Material(TextureAttribute.createDiffuse(type.textureRegionTop))); I got the following result:

结果图片

Let us review the classes Texture and TextureRegion in libGDX:

  • Teture : A tetxure is a (most commonly 2D) image where the intent is to paste it onto a 3D polygon to give it more visual detail.

  • TextureRegion : For efficiency and convenience multiple textures can be combined into a single file , as is the case with your image file. So for an image that is not a single texture by itself, you would define parts of the image as separate texture regions.

From a libGDX API perspective, there are two ways to tell it to use a TextureRegion:

  1. Call createDiffuse(TextureRegion) which sets a fixed region of your image file as texture.

  2. Call createDiffuse(Texture) to load the whole Texture as Material and then call setUVRange(TextureRegion) .

Your error is that you inappropriately mixed those two methods: You call createDiffuse(TextureRegion) and then ALSO call setUVRange(TextureRegion) , so you define a texture region TWICE. My guess is this results in a tetxure region within a texture region with the size of exactly a single pixel (as there are 16x16 textures of 16x16 pixels) which explains your flat color results.

The easiest way to fix it is using number 2 and replacing createDiffuse(type.textureRegionTop) with createDiffuse(texture) ! I will also demonstrate number 1 below for completeness.


Before:

图片1

After:

图像2

I also added transparency for glass using BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA) :

img3

And turned back-face culling off using IntAttribute.createCullFace(GL20.GL_NONE) and DepthTestAttribute(false) :

img4

The cubes are pointing to the side to due up-direction in OpenGL being the +Y-direction, but I think you'll manage to fix this yourself. (:


Here is a complete working example. Create a minimal libGDX project with their tool and save the texture as "minecraft.png" under eg android/assets . I used Kotlin rather than Java because I had a Kotlin project lying around, but you only need to change your code from two lines before modelBuilder.begin() to .end() anyway (and glClearColor):

package io.github.l0lk.zombieyeti.block;

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.graphics.g3d.*
import com.badlogic.gdx.graphics.g3d.attributes.*
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder

enum class BlockType(var nameca: String, var textureTopX: Int, var textureTopY: Int, var textureSideX: Int, var textureSideY: Int, var textureBottomX: Int, var textureBottomY: Int) {
    GRASS("dirt", 0, 0, 3, 0, 2, 0),
    STONE("stone", 1, 0, 1, 0, 1, 0),
    PLANK("plank", 4, 0, 4, 0, 4, 0),
    GLASS("glass", 1, 3, 1, 3, 1, 3);

    var textureRegionTop: TextureRegion? = null
    var textureRegionSide: TextureRegion? = null
    var textureRegionBottom: TextureRegion? = null
    var model: Model? = null

    companion object {
        var TEXTURE_WIDTH = 16
        fun createTexturesAndModels(texture: Texture?) {
            val modelBuilder = ModelBuilder()
            for (type in values()) {
                type.textureRegionTop = TextureRegion(texture, type.textureTopX * TEXTURE_WIDTH, type.textureTopY * TEXTURE_WIDTH, TEXTURE_WIDTH, TEXTURE_WIDTH)
                type.textureRegionSide = TextureRegion(texture, type.textureSideX * TEXTURE_WIDTH, type.textureSideY * TEXTURE_WIDTH, TEXTURE_WIDTH, TEXTURE_WIDTH)
                type.textureRegionBottom = TextureRegion(texture, type.textureBottomX * TEXTURE_WIDTH, type.textureBottomY * TEXTURE_WIDTH, TEXTURE_WIDTH, TEXTURE_WIDTH)
                val attr = (VertexAttributes.Usage.Position or VertexAttributes.Usage.Normal or VertexAttributes.Usage.TextureCoordinates).toLong()
                val materialAttrs = arrayOf(BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA), IntAttribute.createCullFace(GL20.GL_NONE), DepthTestAttribute(false))
                modelBuilder.begin()
                modelBuilder.part("box", GL20.GL_TRIANGLES, attr, Material(TextureAttribute.createDiffuse(type.textureRegionTop), *materialAttrs))
                        .rect(-0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0f, 0f, -1f)
                modelBuilder.part("box", GL20.GL_TRIANGLES, attr, Material(TextureAttribute.createDiffuse(type.textureRegionSide), *materialAttrs))
                        .rect(-0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0f, 0f, 1f)
                modelBuilder.part("box", GL20.GL_TRIANGLES, attr, Material(TextureAttribute.createDiffuse(type.textureRegionSide), *materialAttrs))
                        .rect(-0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0f, -1f, 0f)
                modelBuilder.part("box", GL20.GL_TRIANGLES, attr, Material(TextureAttribute.createDiffuse(type.textureRegionSide), *materialAttrs))
                        .rect(-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0f, 1f, 0f)
                modelBuilder.part("box", GL20.GL_TRIANGLES, attr, Material(TextureAttribute.createDiffuse(type.textureRegionSide), *materialAttrs))
                        .rect(-0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -1f, 0f, 0f)
                modelBuilder.part("box", GL20.GL_TRIANGLES, attr, Material(TextureAttribute.createDiffuse(type.textureRegionBottom), *materialAttrs))
                        .rect(0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 1f, 0f, 0f)
                type.model = modelBuilder.end()
            }
        }
    }
}

class Game : ApplicationAdapter() {

    lateinit var environment: Environment
    lateinit var cam: PerspectiveCamera
    lateinit var modelBatch: ModelBatch
    lateinit var models: List<ModelInstance>

    override fun create() {
        environment = Environment().apply { set(ColorAttribute(ColorAttribute.AmbientLight, 1f, 1f, 1f, 1f)) }
        BlockType.createTexturesAndModels( Texture(Gdx.files.internal("minecraft.png")) )
        modelBatch = ModelBatch()
        models = (0..3).map { ModelInstance(BlockType.values()[it].model).apply { transform.translate(it/1f, 0f, 0f) }}

        cam = PerspectiveCamera(67F, Gdx.graphics.width.toFloat(), Gdx.graphics.height.toFloat()).apply {
            position.set(4f, 2f, 2f)
            lookAt(2f, 0f, 0f)
            update()
        }
    }

    override fun render() {
        Gdx.gl.glViewport(0, 0, Gdx.graphics.width, Gdx.graphics.height)
        Gdx.gl.glClearColor(0f, 0f, 0f, 1f)
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT or GL20.GL_DEPTH_BUFFER_BIT)

        modelBatch.apply {
            begin(cam)
            models.forEach { render(it, environment) }
            end()
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM