gpt4 book ai didi

java - 纹理缓冲区和 glMultiDrawElements

转载 作者:行者123 更新时间:2023-11-29 09:10:10 45 4
gpt4 key购买 nike

背景故事:我正在尝试使用单个绘制调用在屏幕上绘制尽可能多的正方形。我正在使用专门用于 2D 绘图的自定义 glsl 顶点着色器,它应该是从 samplerBuffer 中提取正方形顶点的位置数据。因为我不需要担心旋转或缩放正方形,所以我需要做的就是将位置数据加载到缓冲区中,将纹理绑定(bind)到该缓冲区,然后使用采样器获取每个顶点在着色器中的位置。为了获得纹理的索引,我将每个元素索引存储为顶点的 z 分量。

对于大约一千个方格,一切似乎都很好,但在那之后我开始变得奇怪地眨眼。看起来它并没有在每个绘制步骤中绘制所有的正方形,或者可能没有使用所有的位置,所以许多正方形是重叠的。

奇怪的是,如果我使用 drawElements 而不是 drawElementsMulti,闪烁就会消失(但当然所有的方 block 都被绘制为一个单独的对象,这是我不想要的)

我的一个问题是我的位置数据是否受限于最大纹理大小或最大纹理缓冲区大小。如果我受限于更小的最大纹理尺寸,我该如何解决?所有的纹理缓冲区空间都在那里肯定是有原因的,但我显然不知道如何正确使用它。

我也在想,也许 glMultiDrawElements 正在做一些我没有考虑到采样器的事情。 Idk,此时我真的迷路了,但是......它非常适合较小数量的方 block ,所以我必须做正确的事情。

[编辑] 代码已更改以反射(reflect)下面的建议(以及为了可读性),但问题仍然存在。

好的,下面是一些代码。首先是顶点着色器:

uniform mat3 projection;
attribute vec3 vertex;

uniform samplerBuffer positionSampler;

attribute vec4 vertex_color;
varying vec4 color;

float positionFetch(int index)
{
// I've tried texelFetch here as well, same effect
float value = texelFetchBuffer(positionSampler, index).r;
return value;
}

void main(void)
{
color = vec4(1, 1, 1, 1);
// use the z-component of the vertex to look up the position of this instance in the texture
vec3 real_position = vec3(vertex.x + positionFetch(int(vertex.z)*2), vertex.y + positionFetch(int(vertex.z)*2+1), 1);
gl_Position = vec4(projection * real_position, 1);
}

现在是我的 GLRenderer,很抱歉有这么多代码,我只是想确保这里有足够的信息来获得答案。这真的让我抓狂,Java 的例子似乎很难找到(也许这段代码会帮助其他人完成他们的任务):

public class GLRenderer extends GLCanvas implements GLEventListener, WindowListener
{

private static final long serialVersionUID = -8513201172428486833L;

private static final int bytesPerFloat = Float.SIZE / Byte.SIZE;
private static final int bytesPerShort = Short.SIZE / Byte.SIZE;

public float viewWidth, viewHeight;
public float screenWidth, screenHeight;

private FPSAnimator animator;

private boolean didInit = false;

JFrame the_frame;
SquareGeometry geometry;

// Thought power of 2 might be required, doesn't seem to make a difference
private static final int NUM_THINGS = 2*2*2*2*2*2*2*2*2*2*2*2*2*2;

float[] position = new float[NUM_THINGS*2];

// Shader attributes
private int shaderProgram, projectionAttribute, vertexAttribute, positionAttribute;

public static void main(String[] args)
{
new GLRenderer();
}

public GLRenderer()
{
// setup OpenGL Version 2
super(new GLCapabilities(GLProfile.get(GLProfile.GL2)));

addGLEventListener(this);
setSize(1800, 1000);

the_frame = new JFrame("Hello World");
the_frame.getContentPane().add(this);
the_frame.setSize(the_frame.getContentPane().getPreferredSize());
the_frame.setVisible(true);
the_frame.addWindowListener(this);

animator = new FPSAnimator(this, 60);
animator.start();
}

// Called by the drivers when the gl context is first made available
public void init(GLAutoDrawable d)
{
final GL2 gl = d.getGL().getGL2();
IntBuffer asd = IntBuffer.allocate(1);
gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_BUFFER_SIZE, asd);
System.out.println(asd.get(0));
asd = IntBuffer.allocate(1);
gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_SIZE, asd);
System.out.println(asd.get(0));
shaderProgram = ShaderLoader.compileProgram(gl, "default");
gl.glLinkProgram(shaderProgram);

_getShaderAttributes(gl);

gl.glUseProgram(shaderProgram);
_checkGLCapabilities(gl);
_initGLSettings(gl);

// Calculate batch of vertex data from dirt geometry
geometry = new SquareGeometry(.1f);
geometry.buildGeometry(viewWidth, viewHeight);
geometry.finalizeGeometry(NUM_THINGS);

geometry.vertexBufferID = _generateBufferID(gl);
_loadVertexBuffer(gl, geometry);

geometry.indexBufferID = _generateBufferID(gl);
_loadIndexBuffer(gl, geometry);

geometry.positionBufferID = _generateBufferID(gl);

// initialize buffer object
int size = NUM_THINGS * 2 * bytesPerFloat;
System.out.println(size);

IntBuffer bla = IntBuffer.allocate(1);
gl.glGenTextures(1, bla);
geometry.positionTextureID = bla.get(0);

gl.glUniform1i(positionAttribute, 0);

gl.glActiveTexture(GL2.GL_TEXTURE0);
gl.glBindTexture(GL2.GL_TEXTURE_BUFFER, geometry.positionTextureID);
gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, geometry.positionBufferID);
gl.glBufferData(GL2.GL_TEXTURE_BUFFER, size, null, GL2.GL_DYNAMIC_DRAW);
gl.glTexBuffer(GL2.GL_TEXTURE_BUFFER, GL2.GL_R32F, geometry.positionBufferID);
}

private void _initGLSettings(GL2 gl)
{
gl.glClearColor(0f, 0f, 0f, 1f);
}

private void _loadIndexBuffer(GL2 gl, SquareGeometry geometry)
{
gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, geometry.indexBufferID);
gl.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, bytesPerShort*NUM_THINGS*geometry.getNumPoints(), geometry.indexBuffer, GL2.GL_STATIC_DRAW);
}

private void _loadVertexBuffer(GL2 gl, SquareGeometry geometry)
{
int numBytes = geometry.getNumPoints() * 3 * bytesPerFloat * NUM_THINGS;

gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, geometry.vertexBufferID);
gl.glBufferData(GL2.GL_ARRAY_BUFFER, numBytes, geometry.vertexBuffer, GL2.GL_STATIC_DRAW);
gl.glEnableVertexAttribArray(vertexAttribute);
gl.glVertexAttribPointer(vertexAttribute, 3, GL2.GL_FLOAT, false, 0, 0);
}

private int _generateBufferID(GL2 gl)
{
IntBuffer bufferIDBuffer = IntBuffer.allocate(1);
gl.glGenBuffers(1, bufferIDBuffer);

return bufferIDBuffer.get(0);
}

private void _checkGLCapabilities(GL2 gl)
{
// TODO: Respond to this information in a meaningful way.
boolean VBOsupported = gl.isFunctionAvailable("glGenBuffersARB") && gl.isFunctionAvailable("glBindBufferARB")
&& gl.isFunctionAvailable("glBufferDataARB") && gl.isFunctionAvailable("glDeleteBuffersARB");

System.out.println("VBO Supported: " + VBOsupported);
}

private void _getShaderAttributes(GL2 gl)
{
vertexAttribute = gl.glGetAttribLocation(shaderProgram, "vertex");
projectionAttribute = gl.glGetUniformLocation(shaderProgram, "projection");
positionAttribute = gl.glGetUniformLocation(shaderProgram, "positionSampler");
}

// Called by me on the first resize call, useful for things that can't be initialized until the screen size is known
public void viewInit(GL2 gl)
{
for(int i = 0; i < NUM_THINGS; i++)
{
position[i*2] = (float) (Math.random()*viewWidth);
position[i*2+1] = (float) (Math.random()*viewHeight);
}

gl.glUniformMatrix3fv(projectionAttribute, 1, false, Matrix.projection3f, 0);

// Load position data into a texture buffer
gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, geometry.positionBufferID);
ByteBuffer textureBuffer = gl.glMapBuffer(GL2.GL_TEXTURE_BUFFER, GL2.GL_WRITE_ONLY);
FloatBuffer textureFloatBuffer = textureBuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();

for(int i = 0; i < position.length; i++)
{
textureFloatBuffer.put(position[i]);
}

gl.glUnmapBuffer(GL2.GL_TEXTURE_BUFFER);
gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, 0);
}

public void display(GLAutoDrawable d)
{

if (!didInit || geometry.vertexBufferID == 0)
{
return;
}

//long startDrawTime = System.currentTimeMillis();
final GL2 gl = d.getGL().getGL2();

gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);


// If we were drawing any other buffers here we'd need to set this every time
// but instead we just leave them bound after initialization, saves a little render time
// No combination of these seems to fix the problem
//gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, geometry.vertexBufferID);
//gl.glVertexAttribPointer(vertexAttribute, 3, GL2.GL_FLOAT, false, 0, 0);
//gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, geometry.indexBufferID);
gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, geometry.positionBufferID);
//gl.glActiveTexture(GL2.GL_TEXTURE0);
//gl.glTexBuffer(GL2.GL_TEXTURE_BUFFER, GL2.GL_R32F, geometry.positionBufferID);

_render(gl, geometry);

// Also tried these
//gl.glFlush();
//gl.glFinish();
}

public void _render(GL2 gl, SquareGeometry geometry)
{
gl.glMultiDrawElements(geometry.drawMode, geometry.countBuffer, GL2.GL_UNSIGNED_SHORT, geometry.offsetBuffer, NUM_THINGS);
// This one works, but isn't what I want
//gl.glDrawElements(GL2.GL_LINE_LOOP, count, GL2.GL_UNSIGNED_SHORT, 0);
}

public void reshape(GLAutoDrawable d, int x, int y, int width, int height)
{
final GL2 gl = d.getGL().getGL2();
gl.glViewport(0, 0, width, height);
float ratio = (float) height / width;

screenWidth = width;
screenHeight = height;
viewWidth = 100;
viewHeight = viewWidth * ratio;

Matrix.ortho3f(0, viewWidth, 0, viewHeight);

if (!didInit)
{
viewInit(gl);
didInit = true;
}
else
{
// respond to view size changing
}
}
}

最后一点是 SquareGeometry 类,它保存所有 bufferID 和顶点数据,但也负责正确填充顶点缓冲区,以便每个顶点的 z 分量可以作为位置纹理的索引:

public class SquareGeometry
{
public float[] vertices = null;

ShortBuffer indexBuffer;
IntBuffer countBuffer;
PointerBuffer offsetBuffer;
FloatBuffer vertexBuffer;

public int vertexBufferID = 0;
public int indexBufferID = 0;
public int positionBufferID = 0;
public int positionTextureID = 0;

public int drawMode;

protected float width = 0;
protected float height = 0;

public SquareGeometry(float size)
{
width = size;
height = size;
}

public void buildGeometry(float viewWidth, float viewHeight)
{
vertices = new float[4 * 2];
vertices[0] = -width/2;
vertices[1] = -height/2;
vertices[2] = -width/2;
vertices[3] = height/2;
vertices[4] = width/2;
vertices[5] = height/2;
vertices[6] = width/2;
vertices[7] = -height/2;

drawMode = GL2.GL_POLYGON;
}

public void finalizeGeometry(int numInstances)
{
if(vertices == null) return;

int num_vertices = this.getNumPoints();
int total_num_vertices = numInstances * num_vertices;

// initialize vertex Buffer (# of coordinate values * 4 bytes per float)
ByteBuffer vbb = ByteBuffer.allocateDirect(total_num_vertices * 3 * Float.SIZE);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();

for(int i = 0; i < numInstances; i++)
{
for(int v = 0; v < num_vertices; v++)
{
int vertex_index = v * 2;
vertexBuffer.put(vertices[vertex_index]);
vertexBuffer.put(vertices[vertex_index+1]);
vertexBuffer.put(i);
}
}
vertexBuffer.rewind();

// Create the indices
vbb = ByteBuffer.allocateDirect(total_num_vertices * Short.SIZE);
vbb.order(ByteOrder.nativeOrder());
indexBuffer = vbb.asShortBuffer();

for(int i = 0; i < total_num_vertices; i++)
{
indexBuffer.put((short) (i));
}
indexBuffer.rewind();

// Create the counts
vbb = ByteBuffer.allocateDirect(numInstances * Integer.SIZE);
vbb.order(ByteOrder.nativeOrder());
countBuffer = vbb.asIntBuffer();
for(int i = 0; i < numInstances; i++)
{
countBuffer.put(num_vertices);
}
countBuffer.rewind();

// create the offsets
offsetBuffer = PointerBuffer.allocateDirect(numInstances);
for(int i = 0; i < numInstances; i++)
{
offsetBuffer.put(num_vertices*i*2);
}
offsetBuffer.rewind();
}

public int getNumPoints()
{
return vertices.length/2;
}
}

最佳答案

好的,首先,您没有在着色器中设置 gl_Color,这可能是这里的问题,您只幸运地使用了少量数字。这是一个变化的,但你是否也有片段着色器来获取值?

您在任何时候都不能确保 NUM_THINGS*2 < GL_MAX_TEXTURE_SIZE。我不知道 FloatBuffer.put 的 react 如何;成为 Java 可能/希望是一个异常(exception)。

您还绑定(bind)了 positionBufferID 缓冲区,然后解除绑定(bind)但永远不会重新绑定(bind)它。

您创建了 positionTextureID 但从未将任何数据放在那里。这也是您放入采样器 positionSampler 并尝试访问的内容。

是的,有很多问题,但我的直觉告诉我最后一个问题可能是真正的问题。

关于java - 纹理缓冲区和 glMultiDrawElements,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12927523/

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