gpt4 book ai didi

Libgdx 自定义着色器逐顶点属性

转载 作者:行者123 更新时间:2023-12-01 13:50:24 25 4
gpt4 key购买 nike

经过几天的挣扎,我来到了这里。我正在尝试将自定义的每顶点 vec3 属性传递给基于 this 的自定义着色器教程。本教程描述了如何传递实际工作正常的自定义制服。然而,当我尝试修改代码以传递我的自定义逐顶点属性时,似乎没有任何内容被传输到顶点着色器,我不知道如何让它工作。

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

我用 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");

在那之后,在自定义着色器的 render(Renderable) 方法中的 libgdx 端,我将缓冲区传递给 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 将属性数据传递给顶点的方式,但我仍然无法弄清楚如何让它工作。

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

完整代码:

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

最佳答案

我终于能够将自定义属性传递给顶点着色器了!非常感谢@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 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);
}

关于Libgdx 自定义着色器逐顶点属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32222957/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com