Libgdx自定义着色器每个顶点属性

3
几天的挣扎后,我来到了这里。我正在尝试根据this教程将自定义每顶点vec3属性传递到自定义着色器中。该教程描述了如何传递自定义uniform,实际上运行良好。但是,当我尝试修改代码以传递我的自定义每顶点属性时,似乎没有东西被传递到顶点着色器中,我无法弄清楚如何使它工作。

到目前为止,我已经完成了以下工作:

我使用modelBuilder.createBox()创建了几个盒子(所以我确定每个模型都有24个顶点)

然后,我生成了一个包含实际属性数据的FloatBuffer,如下所示:

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); 

然后我正在初始化相应的属性位置变量(成功,a_coord >= 0):

a_coord = program.getAttributeLocation("a_coord");

在libgdx的自定义着色器的render(Renderable)方法中,我将缓冲区传递给OpenGL,代码如下:
program.setVertexAttribute(a_coord, 3, Gdx.gl20.GL_FLOAT, false, 0, mAttributeBuffer);

我的自定义顶点着色器如下:

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);
}

问题

目前每个顶点的 a_coord 都为0。我错过了什么,如何正确地将自定义属性传递给顶点着色器?

我猜问题可能出在 VBO 字段和 libGDX 传递属性数据到顶点的方式上,但我仍然无法弄清楚如何使其正常工作。

如果有人能指导我在这个问题上走向正确方向,我会很高兴。

完整代码:

Main AplicationListener 类:

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();
    }
}

自定义 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);
    }
}

1
你需要将任何想要的数据嵌入到网格中。不要自己调用 setVertexAttribute,那样行不通。ModelBuilder(和MeshBuilder)支持自定义属性(只需在构造函数中提供VertexAttributes,而不是方便的位掩码),但在这种情况下,您将不得不修改网格并设置所需的值。 - Xoppa
@Xoppa 非常感谢您的精彩文章和指出这一点 - 我现在正在研究libGDX的源代码。同时,您是否知道有类似功能的教程或代码片段?我已经搜索了很多文章,但都没有找到。 - vir us
3个回答

6

终于我能够将自定义属性传递给顶点着色器了!非常感谢@Xoppa指导我找到正确的方向。

这是迄今为止我得到的可行解决方案(我很乐意听取如何更加优雅地实现它的进一步建议):

首先,正如Xoppa在评论中所述,在构建模型时需要创建提供自定义顶点结构的模型。因此,模型的创建可能如下所示:

VertexAttribute posAttr = new VertexAttribute(VertexAttributes.Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE);
...
VertexAttribute customVertexAttr = new VertexAttribute(512, 3, "a_custom");
VertexAttributes vertexAttributes = new VertexAttributes(
        posAttr,
        ...
        customVertexAttr);

ModelBuilder modelBuilder = new ModelBuilder();
modelBuilder.begin();
modelBuilder.
        part("box", GL20.GL_TRIANGLES, vertexAttributes, new Material()).
        box(1f, 1f, 1f);
model = modelBuilder.end();

或者使用 MeshBuilder 来实现同样的功能:

MeshBuilder meshBuilder = new MeshBuilder();
VertexAttributes vertexAttributes = new VertexAttributes(...);
meshBuilder.begin(vertexAttributes);
meshBuilder.part("box", GL20.GL_TRIANGLES);
meshBuilder.setColor(color);
meshBuilder.box(1f, 1f, 1f);
Mesh mesh = meshBuilder.end();

这段代码将创建一个包含其他数据的顶点模型,根据提供的属性进行。现在是时候填充相应的顶点数组了。你需要一个网格来做到这一点 - 它存储顶点数组 - 一组打包后的属性,一个接一个地按顺序排列。因此,您需要每个顶点的属性数量以及需要修改的属性的偏移量。网格存储所有这些数据:
Mesh mesh = model.meshes.get(0);
int numVertices = mesh.getNumVertices();
// vertex size and offset are in byte so we need to divide it by 4
int vertexSize = mesh.getVertexAttributes().vertexSize / 4;
//it's possible to use usage int here passed previously to VertexAttribute constructor. 
VertexAttribute customAttribute = mesh.getVertexAttribute(512)
int offset = customAttribute.offset / 4;

float[] vertices = new float[numVertices * vertexSize];
mesh.getVertices(vertices);

我们已准备好传递数据:
List<Vector3> customData ...

for(int i = 0; i < numVertices; ++i){
    int index = i * vertexSize + offset;
    vertices[index + 0] = customData.get(i).x;
    vertices[index + 1] = customData.get(i).y;
    vertices[index + 2] = customData.get(i).z;
}

不要忘记将更新后的顶点数组传回网格:

mesh.updateVertices(0, vertices);

就是这样了。

以下是一个帮助方法的实现,可以使用 Usage 标志来创建默认属性的组合以及自定义属性:

private VertexAttributes createMixedVertexAttribute(int defaultAtributes, List<VertexAttribute> customAttributes){
    VertexAttributes defaultAttributes = MeshBuilder.createAttributes(defaultAtributes);
    List<VertexAttribute> attributeList = new ArrayList<VertexAttribute>();
    for(VertexAttribute attribute: defaultAttributes){
        attributeList.add(attribute);
    }
    attributeList.addAll(customAttributes);
    VertexAttribute[] typeArray = new VertexAttribute[0];
    VertexAttributes mixedVertexAttributes = new VertexAttributes(attributeList.toArray(typeArray));
    return mixedVertexAttributes;
}

全部源代码:

public class ProtoGame implements ApplicationListener {
    
    private static final int CUSTOM_ATTRIBUTE_USAGE = 512;

    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);


        Model model = createModelWithCustomAttributes();
        Mesh mesh = model.meshes.get(0);
        setCustomAttributeData(mesh);


        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);
                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();
    }

    private Model createModelWithCustomAttributes() {
        int defaultAttributes = VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates;
        VertexAttribute customVertexAttr = new VertexAttribute(CUSTOM_ATTRIBUTE_USAGE, 3, "a_custom");

        List<VertexAttribute> customAttributeList = new ArrayList<VertexAttribute>();
        customAttributeList.add(customVertexAttr);

        VertexAttributes vertexAttributes = createMixedVertexAttribute(defaultAttributes, customAttributeList);

        ModelBuilder modelBuilder = new ModelBuilder();
        modelBuilder.begin();
        modelBuilder.
                part("box", GL20.GL_TRIANGLES, vertexAttributes, new Material()).
                box(1f, 1f, 1f);
        return modelBuilder.end();
    }

    private void setCustomAttributeData(Mesh mesh) {
        int numVertices = mesh.getNumVertices();

        int vertexSize = mesh.getVertexAttributes().vertexSize / 4;
        int offset = mesh.getVertexAttribute(CUSTOM_ATTRIBUTE_USAGE).offset / 4;

        float[] vertices = new float[numVertices * vertexSize];
        mesh.getVertices(vertices);

        for(int i = 0; i < numVertices; ++i){
            int index = i * vertexSize + offset;
            vertices[index + 0] = i;
            vertices[index + 1] = i;
            vertices[index + 2] = i;
        }
        mesh.updateVertices(0, vertices);
    }    

    @Override
    public void dispose () {
        model.dispose();
        modelBatch.dispose();
    }

    private VertexAttributes createMixedVertexAttribute(int defaultAtributes, List<VertexAttribute> customAttributes){
        VertexAttributes defaultAttributes = MeshBuilder.createAttributes(defaultAtributes);
        List<VertexAttribute> attributeList = new ArrayList<VertexAttribute>();
        for(VertexAttribute attribute: defaultAttributes){
            attributeList.add(attribute);
        }
        attributeList.addAll(customAttributes);
        VertexAttribute[] typeArray = new VertexAttribute[0];
        VertexAttributes mixedVertexAttributes = new VertexAttributes(attributeList.toArray(typeArray));
        return mixedVertexAttributes;
    }


    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

顶点着色器:

attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord0;
    
uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;


varying vec2 v_texCoord0;

attribute vec3 a_custom;

void main() {
    v_texCoord0 = a_texCoord0;
    float posX =  a_position.x + a_custom.x;
    float posY =  a_position.y + a_custom.y;
    float posZ =  a_position.z + a_custom.z;
    gl_Position = u_projTrans * u_worldTrans * vec4(posX, posY, posZ, 1.0);
}

片元着色器

#ifdef GL_ES 
precision mediump float;
#endif
    
uniform vec3 u_colorU;
uniform vec3 u_colorV;
    
varying vec2 v_texCoord0;
    
void main() {
    gl_FragColor = vec4(v_texCoord0.x * u_colorU + v_texCoord0.y * u_colorV, 1.0);
}

0

实际上,可以直接调用setVertexAttributes并使其在不需要网格的情况下工作。只需要像这样扩展ShaderProgram即可

public class ShaderProgramExtended extends ShaderProgram {

    public ShaderProgramExtended(String v, String f){
        super(v,f);
    }

    /*
    This is VERY NAUGHTY. Mario and Nathan probably made it private for a reason
     */
    public int getProgram(){

        int result;
        try{
            Field field = ShaderProgram.class.getDeclaredField("program");
            field.setAccessible(true);
            Object value = field.get(this);
            field.setAccessible(false);
            if (value == null) {
                result =  0;
            }else{
                result = (Integer) value;
            }
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    public void begin(int program){
        Gdx.gl20.glUseProgram(program);
    }

    public void draw(int mode, int first, int count){
        Gdx.gl20.glDrawArrays(mode,first,count);
    }
}

然后像平常一样调用它,只需将着色器对象整数发送到新的begin方法即可

public class TestlibGDXv2 extends ApplicationAdapter {

    private final String tag = (this).getClass().getSimpleName();
    String message = "";

    private static final int FLOAT_BYTES = 4;
    FloatBuffer vertexData;
    FloatBuffer colorData;
    ShaderProgramExtended shader;

    private static final String COLOR_ATTRIBUTE = ShaderProgram.COLOR_ATTRIBUTE;
    private int aColourLocation;

    private static final String POSITION_ATTRIBUTE = ShaderProgram.POSITION_ATTRIBUTE;
    private int aPositionLocation;


    /*
    Anti-clockwise winding order. Note, we could share two of the vertices. Haven't for clarity.
    */
    float[] vertices = {
            -0.5f, -0.5f,
            0.5f, -0.5f,
            -0.5f, 0.5f,
            -0.5f, 0.5f,
            0.5f, -0.5f,
            0.5f, 0.5f
    };
    
    /*
    Need to colour each vertex, so need 6.
     */

    float[] colors = {1.0f, 0.0f, 0.0f, 1.0f,
            0.0f,1.0f,0.0f,1.0f,
            0.0f,0.0f,1.0f,1.0f,
            0.0f,0.0f,1.0f,1.0f,
            0.0f,1.0f,0.0f,1.0f,
            1.0f,0.0f,0.0f,1.0f
    };


    @Override
    public void create() {

        /*
        Convert from Dalvik VM to OpenGL native
         */
        vertexData = ByteBuffer.allocateDirect(vertices.length * FLOAT_BYTES)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();

        colorData = ByteBuffer.allocateDirect(colors.length * FLOAT_BYTES)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();

        vertexData.put(vertices).position(0);
        colorData.put(colors).position(0);

        initialiseShaders();

    }

    @Override
    public void render() {

        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        shader.begin(shader.getProgram());
        shader.setVertexAttribute(aPositionLocation, 2, GL20.GL_FLOAT, false, 0, vertexData);
        shader.enableVertexAttribute(aPositionLocation);
        shader.setVertexAttribute(aColourLocation, 4, GL20.GL_FLOAT, false, 0, colorData);
        shader.enableVertexAttribute(aColourLocation);

        shader.draw(GL20.GL_TRIANGLES, 0, 6);
        shader.end();
    }

    private void initialiseShaders() {


        String vertexShaderSource =
                        "#version 130\n" +
                        "attribute vec4 " + POSITION_ATTRIBUTE + ";\n" + // x,y,z and w
                        "attribute vec4 " + COLOR_ATTRIBUTE + ";\n" + // r,g,b and a
                        "varying vec4 v_color;\n" + // pass to fragment shader
                        "void main(){\n" +
                        "   v_color = "+ COLOR_ATTRIBUTE + ";\n" +
                        "   gl_Position = " + POSITION_ATTRIBUTE + ";\n" +
                        "}";

        String fragmentShaderSource =
                        "#version 130\n" +
                        "#ifdef GL_ES\n" +
                        "   precision mediump float;\n" + // medium a good balance between speed and quality
                        "#endif\n" +
                        "varying vec4 v_color;\n" + // incoming from vertex shader
                        "void main(){\n" +
                        "   gl_FragColor = v_color;\n" +
                        "}";

        shader = new ShaderProgramExtended(vertexShaderSource,fragmentShaderSource);
        aPositionLocation = shader.getAttributeLocation(POSITION_ATTRIBUTE);
        aColourLocation = shader.getAttributeLocation(COLOR_ATTRIBUTE);

    }
}

属性“a_color”(来自ShaderProgram.COLOR_ATTRIBUTE)同样可以被命名为“a_custom”。

我在学习OpenGL ES时使用了这种方法,参考的是WebGL书籍——相比libGDX OpenGL书籍,WebGL书籍更加丰富。然而,仅限于学习使用,该着色器现在不再由libGDX管理,因此在Android上当上下文丢失时无法正常工作。但在桌面端可以使用。

祝好

John


0

根据Xoppa的评论,我成功地让自定义属性工作了。这实际上非常简单!以下是一个ES 3.0的示例:

#version 300 es
//v30.glsl
in vec3 vertexPosition;
in vec3 vertexColor;
out vec3 outColor;
    
void main()
{
    outColor = vertexColor;
    gl_Position = vec4(vertexPosition, 1.0);
}

片段着色器:

#version 300 es
//f30.glsl
precision mediump float;
    
in vec3 outColor;
    
out vec4 fragColor;
    
void main()
{
    fragColor = vec4(outColor, 1.0);
}

Gl30Mesh.java

package com.example.jgles;
    
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
    
public class Gl30Mesh extends ApplicationAdapter
{
    private Mesh triangleMesh;
    private ShaderProgram passShader;
        
    @Override
    public void create()
    {
        final float [] combinedData = {
            -0.8f, -0.8f, 0.0f, 1.0f, 0.0f, 0.0f,
            0.8f, -0.8f, 0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.8f, 0.0f, 0.0f, 0.0f, 1.0f
        };
        VertexAttribute vertexChannel = new VertexAttribute(VertexAttributes.Usage.Generic, 3, "vertexPosition");
        VertexAttribute colorChannel = new VertexAttribute(VertexAttributes.Usage.Generic, 3, "vertexColor");
        String vertexShader = Gdx.files.internal("v30.glsl").readString();
        String fragmentShader = Gdx.files.internal("f30.glsl").readString();
        passShader = new ShaderProgram(vertexShader, fragmentShader);
        if (!passShader.isCompiled()){
            throw new IllegalStateException(passShader.getLog());
        }
        passShader.bind();
        triangleMesh = new Mesh(true, 3, 0, vertexChannel, colorChannel);
        triangleMesh.setVertices(combinedData);
    }
    
    @Override
    public void render()
    {
        Gdx.gl.glViewport(0, 0, 640, 480);
        Gdx.gl.glClearColor(0, 0, 1.0f, 0);
        Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
        triangleMesh.render(passShader, GL30.GL_TRIANGLES);
    }
}

在我看来,当您已经使用自定义着色器时,您应该使用着色器中命名的任何内容,而不是POSITION_ATTRIBUTE、NORMAL_ATTRIBUTE等。正如Xoppa所说,ShaderProgram.setVertexAttribute根本不起作用。


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