我开始在Python中使用OpenGL 4(通过Pyglet和一些框架代码我从网上下载/自己编写用于加载着色器/程序),但我认为我理解的东西相当不错,所以我认为没有我代码中的某个问题.
那我的问题是什么?似乎当numpy数组或缓冲区达到一定大小时,我画画时会发生奇怪的事情.请查看链接的图片,看看我的意思. http://i.imgur.com/8Oym6VA.png?1
在图片上你可以看到我正在画一些"机器人",每个机器人都是由8个盒子组成的.机器人的数据只计算一次,使用基本的立方体顶点/颜色/索引数据,然后适当地平移/缩放/旋转并附加到更大的阵列中.在左边的图片中,我在一个VAO中绘制了172个这样的机器人,右边的图片有173个机器人.正如你所看到的,当我翻过那个"神奇"的数字时会发生奇怪的事情.看起来好像所有顶点都以某种方式连接到要在屏幕上绘制的第一个点(第一个绘制的机器人"身体"的右上方部分).如果我将第一个机器人移动到其他地方,所有点仍然连接到该点 - 以说明我确保图片中的点不以(0,0,0)或类似的为中心.左图有顶点和颜色数据,有131328个浮点数,索引数据长49248.右图有顶点和颜色数据,有132096个浮点数,而索引数据有49536个浮点数.如果我将数据分成多个VAO,那么我可以轻松地绘制100倍价值的机器人(当然有100个VAO)没有任何问题(即使1000个VAO的1000个机器人也运行良好,除了服用了很多记忆和工作约0.2 FPS).
为了测试Pyglets类(或我自己的)是否有任何问题,我还用OpenGL调用重写了整个事情,我遇到了同样的问题.那么,维也纳国际中心是不是意味着那么大(我不知何故怀疑维多利亚州立大学每个只有大约17k个三角形)?或者它与Numpy有关(我之前在Numpy中使用过更大的阵列,我不记得有任何问题)?哦顺便说一句,浮点数的大小似乎并不重要(如果所有顶点都在[-1,1]范围内,如果上升到[-35000,35000],则会发生同样的事情.
我已经非常广泛地搜索了这个主题,但我在搜索中没有遇到任何类似的东西 - 如果有的话,我道歉.我所能找到的只是使用非常大的numpy数组时的MemoryError,但是我的数组远远不能达到生成它所需的大小.
我的系统规格是:
虽然我几乎可以肯定我的代码没有任何问题,但我仍然会在这里弹出与绘图相关的片段(同样,我也尝试过基础OpenGL调用,但它没有更好的工作) .
首先,我有一个"Handler"类,它用于存储大量静态数据,因此我可以使用一个glDraw*调用(例如游戏级别或类似的东西)绘制它.它创建了添加到其数据的方法,初始化其VBO和VAO的方法以及绘制函数,该函数获取堆栈并使用它.它还获取它绘制的程序(顶点/颜色着色器).
class Handler:
def __init__(self, program):
self.vertexData = numpy.array((), dtype=GLfloat)
self.colorData = numpy.array((), dtype=GLfloat)
self.indexData = numpy.array((), dtype=GLshort)
self.program = program
def initBuffers(self):
self.vao = GLuint()
glGenVertexArrays(1, self.vao)
glBindVertexArray(self.vao)
#=======================================================================
# Vertices
#=======================================================================
self.vertexBufferObject = pyglet.graphics.vertexbuffer.create_buffer(self.vertexData.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
self.vertexBufferObject.bind()
self.vertexBufferObject.set_data(self.vertexData.ctypes.data)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0)
#=======================================================================
# …Run Code Online (Sandbox Code Playgroud) 我在构建图形引擎时正在研究arcsynthesis的优秀教程,并发现我不像我想象的那样理解VAO.
从教程第5章深入的对象
缓冲区绑定和属性关联
您可能会注意到glBindBuffer(GL_ARRAY_BUFFER)不在该列表中,即使它是用于渲染的属性设置的一部分.对GL_ARRAY_BUFFER的绑定不是VAO的一部分,因为当调用glBindBuffer(GL_ARRAY_BUFFER)时,缓冲区对象和顶点属性之间的关联不会发生.调用glVertexAttribPointer时会发生此关联.
当您调用glVertexAttribPointer时,OpenGL会将此调用时的任何缓冲区绑定到GL_ARRAY_BUFFER,并将其与给定的顶点属性相关联.将GL_ARRAY_BUFFER绑定视为glVertexAttribPointer读取的全局指针.因此,在进行glVertexAttribPointer调用之后,您可以自由地将任何您想要的内容绑定到GL_ARRAY_BUFFER; 它会影响最终渲染中的任何内容.因此VAO确实存储哪些缓冲区对象与哪些属性相关联; 但它们不存储GL_ARRAY_BUFFER绑定本身.
我最初错过了最后一行"......但他们没有存储GL_ARRAY_BUFFER绑定本身".在我注意到这一行之前,我认为一旦调用了glVertexAttribPointer,就会保存当前绑定的缓冲区.缺少这些知识,我构建了一个网格类,并且能够获得一个具有正确渲染的多个网格的场景.
下面列出了该代码的一部分.请注意,我不在draw函数中调用glBindBuffer.
// MESH RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(vertex), &_vertices[0], GL_STATIC_DRAW);
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_normal);
glEnableVertexAttribArray(e_aid_color);
glEnableVertexAttribArray(e_aid_tex);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, pos));
glVertexAttribPointer(e_aid_normal, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, norm));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, col));
glVertexAttribPointer(e_aid_tex, 2, GL_FLOAT, GL_FALSE, …Run Code Online (Sandbox Code Playgroud) 我不明白GL_ARRAY_BUFFEROpenGL 中绑定点(例如)的目的是什么.据我所知,glGenBuffers()创建了一种指向位于GPU内存中某处的顶点缓冲区对象的指针.
所以:
glGenBuffers(1, &bufferID)
Run Code Online (Sandbox Code Playgroud)
意味着我现在有一个句柄,bufferID,到图形卡上的1个顶点对象.现在我知道下一步是将bufferID绑定到绑定点
glBindBuffer(GL_ARRAY_BUFFER, bufferID)
Run Code Online (Sandbox Code Playgroud)
这样我就可以使用该绑定点使用如下glBufferData()函数发送数据:
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW)
Run Code Online (Sandbox Code Playgroud)
但为什么我不能只使用bufferID来指定我想要发送数据的位置呢?就像是:
glBufferData(bufferID, sizeof(data), data, GL_STATIC_DRAW)
Run Code Online (Sandbox Code Playgroud)
然后当调用绘图函数时,我也只是将任何ID放入我想要绘制绘图函数的VBO中.就像是:
glDrawArrays(bufferID, GL_TRIANGLES, 0, 3)
Run Code Online (Sandbox Code Playgroud)
为什么我们需要额外的间接步骤glBindBuffers?
基于这篇文章,我试图弄清楚如何在Haskell中使用VBO.我试着填写那里没有覆盖的位:
data Sprite = Sprite { spriteImage :: Image
, spritePosition :: Position
} deriving (Show, Eq)
spriteBatch :: [Sprite] -> [(TextureObject, [Sprite])]
spriteBatch = (map f) . toList . (groupedBy (imageTexture . spriteImage))
where f (t, s) = (t, s)
offset = plusPtr nullPtr
renderSprites :: [Sprite] -> IO ()
renderSprites l = (flip mapM_) (spriteBatch l) $ \(t, sps) -> do
textureBinding Texture2D $= Just t
let l = concat $ map sprToList sps
vbo <- …Run Code Online (Sandbox Code Playgroud) 我正在尝试着色通过的四边形顶点glDrawElements,我正在使用cocos2d libray,所以我已经能够清除源代码以准确理解发生了什么,代码如下:
glBindVertexArray( VAOname_ );
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(indices_[0])) );
glBindVertexArray(0);
Run Code Online (Sandbox Code Playgroud)
因此使用顶点数组对象.我正在尝试修改传递的对象的单个顶点颜色,它似乎工作但是有一个毛刺,如下图所示:

在这里,我试图改变左下和右下顶点的颜色.结果是不同的,我想这是因为四边形被渲染为一对三角形,共享斜边位于从左下顶点到右上顶点的对角线上.所以这可能导致不同的结果.
现在我想对第一个案例也有第二个结果.有没有办法获得它?
看着这个问题从2010年,在现代OpenGL的有关顶点缓冲区,它仍然是国家直接访问是它们不可用的情况?我已经修改了我的大部分图形库以使用带有帧缓冲,纹理等的DSA但是我仍然需要"绑定"来设置我的顶点数组状态(绑定数组,绑定索引缓冲区,绑定顶点缓冲区,解绑数组等等). ).
更新1: 我无法理解BDL的答案中的参数.我对一个非常简单的顶点缓冲区(一个属性,一个位置)的单元测试给了我一个空白屏幕(它使用描述顶点流的旧方法工作正常).它应该只绘制一个三角形,不需要索引缓冲区.
这就是我正在做的事情,评论是我的理解:
::glEnableVertexArrayAttrib(vao, // VAO name.
0); // Attribute index (layout in shader).
::glVertexArrayVertexBuffer(vao, // VAO name.
0, // Binding point.
vbo, // VBO name.
12, // Stride (bytes).
0); // Offset (bytes).
::glVertexArrayAttribFormat(vao, // VAO name.
0, // Attribute index (layout in shader).
3, // Component count (x,y,z).
GL_FLOAT, // Type.
GL_FALSE, // Normalised.
0); // Offset (bytes).
::glVertexArrayAttribBinding(vao, // VAO name.
0, // Attribute index (layout in shader).
0); // Binding point.
Run Code Online (Sandbox Code Playgroud)
现在,我认为我对绑定点"了解".它们是我可以分配的任意数字,这样我就可以快速轻松地交换不同的属性集.所以在这里使用0进行这个简单的测试就足够了. …
在有关 OpenGL 3.0+ 的教程中,我们这样创建顶点数组对象和顶点缓冲区对象:
\n\nGLuint VAO, VBO; \nglGenVertexArrays(1, &VAO);\nglGenBuffers(1, &VBO);\nglBindVertexArray(VAO);\nglBindBuffer(GL_ARRAY_BUFFER, VBO);\nRun Code Online (Sandbox Code Playgroud)\n\n这里,VAO 是一个unsigned int( GLuint),我们传递 a\xcc\xb6 \xcc\xb6r\xcc\xb6e\xcc\xb6f\xcc\xb6e\xcc\xb6r\xcc\xb6e\xcc\xb6n\xcc\xb6c\xcc\ xb6e\xcc\xb6 是它在函数中的地址glGenVertexArray。但是,根据文档,函数的第二个参数应该是( )数组 。VBO 和. 我不明白为什么上面的代码适用于这样的参数。unsigned intGLuint*glGenBuffers
我尝试用此代码替换上面的代码(并在代码中的其他地方进行必要的修改):
\n\nGLuint VAO[1];\nGLuint VBO[1];\nglGenVertexArrays(1, VAO);\nglGenBuffers(1, VBO);\nglBindVertexArray(VAO[1]);\nglBindBuffer(GL_ARRAY_BUFFER, VBO[1]);\nRun Code Online (Sandbox Code Playgroud)\n\n它编译并执行,但我得到了意想不到的行为:我的纹理矩形使用第一个语法渲染,但不使用第二个语法渲染。我也不明白为什么会发生这种情况。
\n\n编辑:谢谢。如上所述,第二个代码中存在索引错误。
\nVAO 是顶点数组对象,VBO 是顶点缓冲区对象。创建和绑定/解除绑定 VAO 和 VBO 的调用具有如下通用格式:
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER,
sizeof(GLfloat)* 9,
vertices,
GL_STATIC_DRAW);
glVertexAttribPointer(0,
3, GL_FLOAT, GL_FALSE,
0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
Run Code Online (Sandbox Code Playgroud)
我在互联网上学习了一些教程,他们说 VBO 绑定到 VAO,但是在上面的代码中,我不明白 VBO 和 VAO 之间是如何建立“连接”或“绑定”的? 我的意思是我们怎么知道哪个 VBO 绑定到哪个 VAO 以及如果一个 VBO 绑定到多个 VAO 呢?
所以,基本问题是:VBO 绑定到 VAO 是什么意思,我们如何知道哪个 VBO 绑定到哪个 VAO 以及如何建立这种绑定?
所以我正在寻找关于命令glVertexAttribPointer的另一个SO问题,我遇到了一些轻微的混乱.这个问题的接受答案解释了,
但是当你进行调用时,还会有一个额外的隐含状态,它也会被存储为属性0:从当前绑定到GL_ARRAY_BUFFER的缓冲区中读取数据
这对我来说很有意义,但如果我有多个绑定的缓冲区GL_ARRAY_BUFFER呢?该glVertexAttribPointer()方法如何知道设置属性的方法?
例如,在我的代码中,我正在绘制一个渐变三角形.为此,我创建了2个VBO,一个是数组中的颜色数据,另一个是顶点位置.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
static const GLfloat points[] = {
//data here
};
static const GLfloat colors[] = {
//data here
};
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
vs = glCreateShader(GL_VERTEX_SHADER);
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vs, 1, &vertexShaderData, NULL);
glShaderSource(fs, 1, &fragShaderData, NULL);
glCompileShader(vs);
glCompileShader(fs);
sp=glCreateProgram();
glBindFragDataLocation(sp, 0, "outColor");
glAttachShader(sp, vs);
glAttachShader(sp, fs);
glLinkProgram(sp);
glUseProgram(sp);
glGenBuffers(1, &colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); …Run Code Online (Sandbox Code Playgroud) c++ opengl vertex-buffer vertex-attributes vertex-array-object
我正在尝试制作一个使用 NDK 和 JNI 在 Android Studio 中绘制图像的应用程序,以使用 OpenGL ES 调用 C++ 代码。我已经阅读了如何在 OpenGL 中执行此操作的教程:https : //learnopengl.com/#!Getting-started/Textures,它使用 GLSL 330 核心。但是,Android 模拟器不支持 OpenGL ES 3.0(此链接中的注意事项:https : //developer.android.com/ndk/guides/stable_apis.html)。
因此,我必须使用 GLSL ES #version 100 ,它不支持下面着色器中的“布局”、“输入”和“输出”。我应该如何编辑它们以便它们可以在 #version 100 中运行,如果我编辑它们,源代码是否有任何变化?感谢您的关注和帮助。
更新:搜索后,我发现我可以使用 glGetAttributeLocation 来获取顶点着色器中变量的位置,而不是使用 layout(location=0)。但是,GLSL ES #version 100 中没有 VAO,所以我仍然无法弄清楚它在没有 VAO 的情况下是如何工作的。
我的顶点着色器:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;
out vec3 ourColor;
out vec2 …Run Code Online (Sandbox Code Playgroud)