Après plusieurs jours de lutte je suis venu ici. J'essaie de transmettre un attribut personnalisé par vertex vec3 à un shader personnalisé basé sur le tutoriel this. Le tutoriel décrit comment passer un uniforme personnalisé qui fonctionne bien. Cependant quand j'essaye de modifier le code pour passer mon attribut par-vertex personnalisé il semble que rien n'est transféré à vertex shader et je ne peux pas comprendre comment le faire fonctionner.Libgdx attribut shader par-vertex personnalisé
Jusqu'à présent, je l'ai fait ce qui suit:
J'ai créé plusieurs boîtes avec modelBuilder.createBox() (donc je sais que chaque modèle a 24 vertex)
Je » v a généré un FloatBuffer contenant des données d'attribut réelles comme ceci:
int[] data = new int[]{x1, y1, z1, x1, y1, z1, ...}
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
mAttributeBuffer = byteBuffer.asFloatBuffer();
mAttributeBuffer.put(data);
mAttributeBuffer.position(0);
Ensuite, j'initialisation de la variable d'emplacement d'attribut correspondant (avec succès, a_coord> = 0):
a_coord = program.getAttributeLocation("a_coord");
Après que le côté libgdx dans la méthode de shader personnalisée render(Renderable)
Je passe le tampon à OpenGL comme ceci:
program.setVertexAttribute(a_coord, 3, Gdx.gl20.GL_FLOAT, false, 0, mAttributeBuffer);
Mon vertex shader personnalisé est comme suit:
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord0;
uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
varying vec2 v_texCoord0;
//my custom attribute
attribute vec2 a_coord;
void main() {
v_texCoord0 = a_texCoord0;
float posY = a_position.y + a_coord.y;
gl_Position = u_projTrans * u_worldTrans * vec4(a_position.x, posY, a_position.z, 1.0);
}
Le problème
En ce moment a_coord est 0 pour ev ery vertex. Qu'est-ce qui me manque et comment passer correctement l'attribut personnalisé à vertex shader?
Je suppose que le problème est quelque part dans le champ VBO et la façon dont libGDX transmet les données d'attribut aux vertex, mais je n'arrive toujours pas à comprendre comment le faire fonctionner.
Je serai heureux si quelqu'un peut me diriger dans la bonne direction sur cette question.
Code complet:
principal AplicationListener classe:
public class ProtoGame implements ApplicationListener {
public ProtoGame()
{
super();
}
public PerspectiveCamera cam;
public CameraInputController camController;
public Model model;
public Array<ModelInstance> instances = new Array<ModelInstance>();
public ModelBatch modelBatch;
@Override
public void create() {
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(0f, 8f, 8f);
cam.lookAt(0,0,0);
cam.near = 1f;
cam.far = 300f;
cam.update();
camController = new CameraInputController(cam);
Gdx.input.setInputProcessor(camController);
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(1f, 1f, 1f,
new Material(),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates);
Color colorU = new Color(), colorV = new Color();
for (int x = -5; x <= 5; x+=2) {
for (int z = -5; z<=5; z+=2) {
ModelInstance instance = new ModelInstance(model, x, 0, z);
//this is where I'll put per-vertex attribute data for every instance
//but for now it's hardcoded in the Shader class so the data is the same across instances
TestShader.DoubleColorAttribute attr = new TestShader.DoubleColorAttribute(TestShader.DoubleColorAttribute.DiffuseUV,
colorU.set((x+5f)/10f, 1f - (z+5f)/10f, 0, 1),
colorV.set(1f - (x+5f)/10f, 0, (z+5f)/10f, 1));
instance.materials.get(0).set(attr);
instances.add(instance);
}
}
modelBatch = new ModelBatch(new BaseShaderProvider() {
@Override
protected Shader createShader(Renderable renderable) {
return new TestShader();
}
});
}
@Override
public void render() {
camController.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
for (ModelInstance instance : instances)
modelBatch.render(instance);
modelBatch.end();
}
@Override
public void dispose() {
model.dispose();
modelBatch.dispose();
}
}
classe shaders personnalisés libgdx:
public class TestShader implements Shader {
private FloatBuffer mAttributeBuffer;
ShaderProgram program;
Camera camera;
RenderContext context;
int u_projTrans;
int u_worldTrans;
int u_colorU;
int u_colorV;
int a_coord;
private static String getCustomVertexShader() {
return Gdx.files.internal("shader/test.vertex.glsl").readString();
}
private static String getCustomFragmentShader() {
return Gdx.files.internal("shader/test.fragment.glsl").readString();
}
@Override
public void init() {
program = new ShaderProgram(getCustomVertexShader(), getCustomFragmentShader());
if (!program.isCompiled())
throw new GdxRuntimeException(program.getLog());
//tutorial's logic to init custom uniform locations
u_projTrans = program.getUniformLocation("u_projTrans");
u_worldTrans = program.getUniformLocation("u_worldTrans");
u_colorU = program.getUniformLocation("u_colorU");
u_colorV = program.getUniformLocation("u_colorV");
//initing custom attribute location
a_coord = program.getAttributeLocation("a_coord");
//generating data and passing it to nio Buffer
float data[] = generateData();
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
mAttributeBuffer = byteBuffer.asFloatBuffer();
mAttributeBuffer.put(data);
mAttributeBuffer.position(0);
}
private float[] generateData() {
Vector3[] dataArray = new Vector3[1];
dataArray[0] = new Vector3(2, 2, 2);
int components = 3;
int vertexPerModel = 24;
float[] data = new float[dataArray.length * components * vertexPerModel];
for(int i = 0; i < dataArray.length; ++i){
int i3 = i * components;
for(int j = 0; j < vertexPerModel; ++j) {
int j3 = j * components;
data[i3 + 0 + j3] = dataArray[i].x;
data[i3 + 1 + j3] = dataArray[i].y;
data[i3 + 2 + j3] = dataArray[i].z;
}
}
return data;
}
@Override
public void dispose() {
program.dispose();
}
@Override
public void begin(Camera camera, RenderContext context) {
this.camera = camera;
this.context = context;
program.begin();
program.setUniformMatrix(u_projTrans, camera.combined);
context.setDepthTest(GL20.GL_LEQUAL);
context.setCullFace(GL20.GL_BACK);
}
@Override
public void render(Renderable renderable) {
program.setUniformMatrix(u_worldTrans, renderable.worldTransform);
//tutorial's logic to pass uniform
DoubleColorAttribute attribute = ((DoubleColorAttribute) renderable.material.get(DoubleColorAttribute.DiffuseUV));
program.setUniformf(u_colorU, attribute.color1.r, attribute.color1.g, attribute.color1.b);
program.setUniformf(u_colorV, attribute.color2.r, attribute.color2.g, attribute.color2.b);
//passing my custom attributes to the vertex shader
program.setVertexAttribute(a_coord, 3, Gdx.gl20.GL_FLOAT, false, 0, mAttributeBuffer);
renderable.mesh.render(program, renderable.primitiveType,
renderable.meshPartOffset, renderable.meshPartSize);
}
@Override
public void end() {
program.end();
}
@Override
public int compareTo(Shader other) {
return 0;
}
@Override
public boolean canRender(Renderable renderable) {
return renderable.material.has(DoubleColorAttribute.DiffuseUV);
}
}
Vous devez intégrer toutes les données que vous voulez dans le maillage. N'appelez pas vous-même 'setVertexAttribute', cela ne marchera pas.'ModelBuilder' (et' MeshBuilder') supporte les attributs personnalisés (fournissez juste le 'VertexAttributes' dans le constructeur, au lieu du masque de bits de commodité) mais dans ce cas, vous devrez modifier le mesh par la suite et définir les valeurs que vous voulez. être. – Xoppa
@Xoppa Merci beaucoup pour le super article et pour le signaler - j'étudie les sources de libGDX dans ce sens maintenant. En attendant peut-être il y a une sorte de tutoriel ou une paix de code dont vous êtes au courant et qui fait la même chose? J'ai creusé des tonnes d'articles les jours précédents sans aucune chance. –