以下Python程序应在窗口的右上象限中绘制一个白色三角形.
import pygame
from OpenGL.GL import *
from ctypes import *
pygame.init ()
screen = pygame.display.set_mode ((800,600), pygame.OPENGL|pygame.DOUBLEBUF, 24)
glViewport (0, 0, 800, 600)
glClearColor (0.0, 0.5, 0.5, 1.0)
glEnableClientState (GL_VERTEX_ARRAY)
vertices = [ 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0 ]
vbo = glGenBuffers (1)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glBufferData (GL_ARRAY_BUFFER, len(vertices)*4, (c_float*len(vertices))(*vertices), GL_STATIC_DRAW)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
glClear (GL_COLOR_BUFFER_BIT)
glBindBuffer (GL_ARRAY_BUFFER, vbo)
glVertexPointer (3, GL_FLOAT, …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) 我试图绘制多个三角形条带只有一个调用glDrawElements,我对此事的研究告诉我,我需要使用退化三角形.也许我对这个问题的理解是错误的,但我认为这应该允许我从一个条带"跳"到另一个.
我的完整代码可以在我最近发布的问题上找到,如果你认为它是相关的,请看一下.
我基本上试图绘制2个四边形(为了简化目的),当然有4个三角形,但是彼此分开.为此,我使用这样的索引:
unsigned int indices[] = { 0, 256, 1, 257, 257, 2, 2, 258, 3, 259 };
Run Code Online (Sandbox Code Playgroud)
第一个条带的第一个顶点从0开始,第二个条带的第一个顶点从256开始.这是这个索引的最终结果:

这是正确的还是我认为"连接"2个四边形的线不应该存在?
我无法弄清楚如何在opengl es 2.0 for iphone中为我的地形使用顶点缓冲区对象.这是静态数据所以我希望通过使用VBO来提高速度.在常规OpenGL中,我使用显示列表和着色器没问题.但是,在opengl es 2.0中,我必须将顶点数据作为属性发送到着色器,并且不知道它如何与VBO一起工作.顶点缓冲区如何知道它在调用时将顶点数据绑定到哪个属性?这在opengl es 2.0中是否可行?如果没有,还有其他方法可以优化我的地形渲染是静态的吗?
我是否需要为每个网格使用一个顶点缓冲区,还是可以在一个顶点缓冲区中存储多个网格?如果是的话,我应该这样做,我该怎么做?
我有一个简单的OpenGL程序,我试图利用顶点缓冲区对象进行渲染而不是旧的glBegin() - glEnd().基本上用户点击指示起点的窗口,然后按下一个键以生成OpenGL作为一行绘制的后续点.
我已经使用glBegin()和glEnd()实现了这个,但是使用VBO还没有成功.我想知道问题是,在我初始化VBO之后,我添加了更多没有分配内存的顶点,因此不会显示它们.
编辑:另外,我对它如何确切知道顶点结构中哪些值用于x和y以及r,g,b有点困惑.我未能找到一个明确的例子.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <Math.h>
#include <iostream>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
struct vertex {
float x, y, u, v, r, g, b;
};
const int D = 10; // distance
const int A = 10; // angle
const int WINDOW_WIDTH = 500, WINDOW_HEIGHT = 500;
std::vector<vertex> vertices;
boolean start = false;
GLuint vboId;
void update_line_point() {
vertex temp;
temp.x = vertices.back().x + D * vertices.back().u;
temp.y = vertices.back().y + D …Run Code Online (Sandbox Code Playgroud) 我可以将颜色作为 4 个浮点发送到着色器 - 没问题。但是我想将其作为整数(或无符号整数,并不重要,重要的是 32 位)发送,并在着色器上的 vec4 中分解。
我使用 OpenTK 作为 OpenGL 的 C# 包装器(尽管它应该只是一个直接包装器)。
让我们考虑最简单的着色器之一,其顶点包含位置(xyz)和颜色(rgba)。
顶点着色器:
#version 150 core
in vec3 in_position;
in vec4 in_color;
out vec4 pass_color;
uniform mat4 u_WorldViewProj;
void main()
{
gl_Position = vec4(in_position, 1.0f) * u_WorldViewProj;
pass_color = in_color;
}
Run Code Online (Sandbox Code Playgroud)
片段着色器:
#version 150 core
in vec4 pass_color;
out vec4 out_color;
void main()
{
out_color = pass_color;
}
Run Code Online (Sandbox Code Playgroud)
让我们创建顶点缓冲区:
public static int CreateVertexBufferColor(int attributeIndex, int[] rawData)
{
var bufferIndex = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, bufferIndex);
GL.BufferData(BufferTarget.ArrayBuffer, sizeof(int) …Run Code Online (Sandbox Code Playgroud) 这似乎是一个 IHV 或另一个 IHV 一直以来都得到解答的问题,但最近我一直试图就顶点布局以及跨所有 IHV 和架构的现代渲染器的最佳实践达成共识。在有人说基准测试之前,我无法轻易做到这一点,因为我无法访问过去 5 年中每个 IHV 和每个架构的卡。因此,我正在寻找一些能够在所有平台上良好运行的最佳实践。
首先,显而易见的是:
Vertex类。现在来说说不太明显的事情。
许多人引用 NVIDIA 的话说,您应该始终交错,而且应该对齐到 32 或 64 字节。我还没有找到它的来源,但找到了 NVIDIA 的有关顶点着色器性能的文档,但它已经很旧了(2013 年),并且是关于移动而非桌面的 Tegra GPU。它特别说:
将顶点数据存储为交错的属性流(“结构数组”布局),这样属性的“过度获取”往往会预取可能对后续属性和顶点有用的数据。将属性存储为不同的、非交错的(“数组结构”)流可能会导致内存系统中的“页面抖动”,从而导致性能大幅下降。
快进 3 年到GDC 2016,EA 进行了一次演示,其中提到了应该对顶点缓冲区进行去交错的几个原因。然而,这个建议似乎与 AMD 架构相关,特别是 GCN。虽然他们提出了一个跨平台的案例来分离位置,但他们建议对所有内容进行去交错,并声明这将允许 GPU :
尽快清除缓存行
而且它对于 GCN (AMD) 架构来说是最佳的。
这似乎与我在其他地方听到的说法相冲突,即使用交错以充分利用缓存行。但同样,这与 AMD 无关。
拥有许多不同的 IHV,Intel、NVIDIA、AMD,现在还有 Apple 的 M1 GPU,而且每一个都有许多不同的架构,这让我完全不确定今天应该做什么(没有预算来测试数十个 GPU)。 GPU),以便最好地优化所有架构的性能,而不会导致
结果导致性能大幅下降
在某些架构上。特别是,去交错在 AMD 上仍然是最好的吗?它在 NVIDIA 上不再是问题,还是在桌面 NVIDIA GPU 上从来都不是问题?其他 IHV 又如何呢? …
我不明白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?
在顶点数组缓冲区的典型构建中,我尝试将 unsigned int 属性与其他经典属性(顶点、法线、纹理坐标...)一起传递。然而,该属性的值最终以某种方式错误:我不确定该值是否错误或该属性根本没有设置。
从一个简单的例子开始,假设我定义了以下 C++ 输入结构:
struct buffer_data_t
{
glm::vec3 vertex;
glm::vec3 normal;
glm::vec2 texCoords;
};
Run Code Online (Sandbox Code Playgroud)
准备我的顶点数组如下所示:
// Assume this 'shader.attribute(..)' is working and returns the attribute's position
unsigned int shadInputs[] = {
(unsigned int)shader.attribute("VS_Vertex"),
(unsigned int)shader.attribute("VS_Normal"),
(unsigned int)shader.attribute("VS_TexCoords"),
};
glGenBuffers(1, &glBuffer);
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
glBufferData(GL_ARRAY_BUFFER, vertice.size() * sizeof(buffer_data_t), &vertice[0], GL_STATIC_DRAW);
glGenVertexArrays(1, &glArray);
glBindVertexArray(glArray);
{
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
glVertexAttribPointer(shadInputs[0], 3, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 0));
glVertexAttribPointer(shadInputs[1], 3, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * 1));
glVertexAttribPointer(shadInputs[2], 2, GL_FLOAT, GL_FALSE, sizeof(buffer_data_t), (void*)(sizeof(glm::vec3) * …Run Code Online (Sandbox Code Playgroud)