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:
Call createDiffuse(TextureRegion)
which sets a fixed region of your image file as texture.
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:
After:
I also added transparency for glass using BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
:
And turned back-face culling off using IntAttribute.createCullFace(GL20.GL_NONE)
and DepthTestAttribute(false)
:
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.