我使用顶点缓冲区对象渲染某些几何体时遇到问题.我打算绘制一个点平面,所以基本上是我空间中每个离散位置的一个顶点.但是,我无法渲染该平面,因为每次调用glDrawElements(...)时,应用程序崩溃都会返回访问冲突异常.我想,在初始化时肯定会有一些错误.
这是我到目前为止:
#define SPACE_X 512
#define SPACE_Z 512
typedef struct{
GLfloat x, y, z; // position
GLfloat nx, ny, nz; // normals
GLfloat r, g, b, a; // colors
} Vertex;
typedef struct{
GLuint i; // index
} Index;
// create vertex buffer
GLuint vertexBufferObject;
glGenBuffers(1, &vertexBufferObject);
// create index buffer
GLuint indexBufferObject;
glGenBuffers(1, &indexBufferObject);
// determine number of vertices / primitives
const int numberOfVertices = SPACE_X * SPACE_Z;
const int numberOfPrimitives = numberOfVertices; // As I'm going to render …Run Code Online (Sandbox Code Playgroud) 如何渲染网格(由三角形组成),其中每个三角形具有相同的颜色,而不是在顶点数组中为每个三角形指定该颜色3次.
假设我想绘制2个三角形.三角1:
Vertex 1, position:(x1,y1) , color: (r1,g1,b1,a1)
Vertex 2, position:(x2,y2) , color: (r1,g1,b1,a1)
Vertex 3, position:(x3,y3) , color: (r1,g1,b1,a1)
Run Code Online (Sandbox Code Playgroud)
三角2:
Vertex 4, position:(x4,y4) , color: (r2,g2,b2,a2)
Vertex 5, position:(x5,y5) , color: (r2,g2,b2,a2)
Vertex 6, position:(x6,y6) , color: (r2,g2,b2,a2)
Run Code Online (Sandbox Code Playgroud)
我知道这可以通过创建2个顶点缓冲区来完成:
Vertex Buffer 1:
[x1, y1]
[x2, y2]
[x3, y3]
[x4, y4]
[x5, y5]
[x6, y6]
Vertex Buffer 2:
[r1, g1, b1, a1]
[r1, g1, b1, a1]
[r1, g1, b1, a1]
[r2, g2, b2, a2]
[r2, g2, b2, a2]
[r2, g2, …Run Code Online (Sandbox Code Playgroud) 在我的跨平台OpenGL应用程序中,我想使用顶点缓冲区对象进行绘制.但是我遇到了调用glDrawRangeElements的问题.
glDrawRangeElements(GL_TRIANGLES, start, start + count, count,
GL_UNSIGNED_INT, static_cast<GLvoid *> (start * sizeof(unsigned int)));
Run Code Online (Sandbox Code Playgroud)
编译器(Mac OS X上的CLang)不喜欢最后一个参数"错误:无法从类型'unsigned long'转换为指针类型'GLvoid*'(又名'void*')".OpenGL API将最后一个参数的类型定义为const GLvoid*,并且当此api与顶点数组一起使用时需要一个指针.但是我知道当使用顶点缓冲区对象而不是指针时,应该将一个表示偏移量的整数值传递给缓冲区数据.这就是我想要做的事情,因此我必须施展.如何协调api要求与编译器进行严格的检查?
到目前为止,我只使用了glDrawArrays,并希望转而使用索引缓冲区和索引三角形.我正在绘制一个有点纹理坐标,法线和顶点坐标的复杂对象.所有这些数据都被收集到一个交错的顶点缓冲区中,并使用类似于(假设所有的serup都正确完成)的调用来绘制:
glVertexPointer( 3, GL_FLOAT, 22, (char*)m_vertexData );
glNormalPointer( GL_SHORT, 22, (char*)m_vertexData+(12) );
glTexCoordPointer( 2, GL_SHORT, 22, (char*)m_vertexData+(18) );
glDrawElements(GL_TRIANGLES, m_numTriangles, GL_UNSIGNED_SHORT, m_indexData );
Run Code Online (Sandbox Code Playgroud)
这是否允许m_indexData也与我的法线和纹理坐标以及标准位置索引数组的索引交错?或者它是否假设一个适用于整个顶点格式(POS,NOR,TEX)的线性列表?如果后者为真,那怎么可能用不同的纹理坐标或法线渲染相同的顶点?
我想这个问题也可以改为:如果我有3个单独的索引列表(POS,NOR,TEX),后者2不能重新排列以共享与第一个相同的索引列表,那么渲染它的最佳方法是什么.
我已经设法使用iOS的GLKit在Open GL ES 2.0中创建单个网格.我无法弄清楚的是如何创建第二个网格看起来与第一个网格相同,只是位置不同.
我认为最有帮助的是,如果有人可以简单地提供一些绘制多个网格的示例代码,我认为我认为这完全错了.尽管如此,这里列出了我为完成这项工作所做的工作.
但这不起作用.屏幕上只绘制一个对象.
通过查看其他人的问题和答案,听起来好像我应该有多个顶点缓冲区?我不知道; 我非常困惑.
你如何在PyOpenGL python绑定到OpenGL中使用glBufferData()?
当我运行以下代码时
import sys
from OpenGL.GL import *
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtOpenGL import *
class SimpleTestWidget(QGLWidget):
def __init__(self):
QGLWidget.__init__(self)
def initializeGL(self):
self._vertexBuffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self._vertexBuffer)
vertices = [0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5]
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW) # Error
def paintGL(self):
glViewport(0, 0, self.width(), self.height())
glClearColor(0.0, 1.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glEnableClientState(GL_VERTEX_ARRAY)
glBindBuffer(GL_ARRAY_BUFFER, self._vertexBuffer)
glVertexPointer(2, GL_FLOAT, 0, 0)
glColor3f(1.0, 0.0, 0.0)
glDrawArrays(GL_QUADS, 0, 4)
if __name__ == '__main__':
app = QApplication(sys.argv)
w …Run Code Online (Sandbox Code Playgroud) 在有关 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编辑:谢谢。如上所述,第二个代码中存在索引错误。
\n我正在尝试实现模型加载,但遇到一个问题。当我尝试绘制网格(出于测试目的而手工编写的单个纹理四边形)时,由于某种原因,与第一个顶点关联的重复数据被传递到顶点着色器(RenderDoc 屏幕)。
这是一个使用我的类的精简版本的示例,它仍然表现出这种行为:
#define TEST_MESH
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
struct Vertex {
float position[3];
float color[3];
};
class Mesh {
public:
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices);
~Mesh();
Mesh(const Mesh&) = delete;
Mesh& operator=(const Mesh&) = delete;
Mesh(Mesh&& other);
Mesh& operator=(Mesh&& other);
void Draw(unsigned int program_id);
std::vector<Vertex> m_Vertices;
std::vector<unsigned int> m_Indices;
private:
unsigned int m_VAO, m_VBO, m_EBO;
void Setup();
void Release();
};
int main() { …Run Code Online (Sandbox Code Playgroud) 我做了很多关于如何将顶点数据收集到通常称为批次的组中的研究。
对我来说,这是关于该主题的两篇主要有趣的文章:
https://www.opengl.org/wiki/Vertex_Specification_Best_Practices
http://www.gamedev.net/page/resources/_/technical/opengl/opengl-batch-rendering-r3900
Run Code Online (Sandbox Code Playgroud)
第一篇文章解释了如何操作 VBO 的最佳实践(最大大小、格式等)。
第二个提供了一个关于如何使用批处理管理顶点内存的简单示例。根据作者的说法,每个批次必须包含一个 VBO 实例(加上 VAO),并且他强烈坚持这样一个事实:VBO 的最大大小范围在 1Mo(1000000 字节)到 4Mo(4000000 字节)之间。第一篇文章提出了同样的建议。我引用“根据一份 nVidia 文档,1MB 到 4MB 是一个不错的大小。驱动程序可以更轻松地进行内存管理。对于所有其他实现以及 ATI/AMD、Intel、SiS 来说,情况应该相同。”
我有几个问题:
1)上面提到的最大字节大小是绝对规则吗?分配比 4Mo(例如 10 Mo)更重要的字节大小的 VBO 是否那么糟糕?
2) 对于总顶点字节大小大于 4Mo 的网格我们该怎么办?我需要将几何体分成几批吗?
3)一个批次是否不可避免地存储为一个唯一的VBO属性,或者多个批次可以存储在一个VBO中?(这是两种不同的方式,但第一种似乎是正确的选择)。你同意吗?
根据作者的说法,每个批次处理一个最大尺寸在 1 到 4 Mo 之间的唯一 VBO,并且整个 VBO 必须仅包含共享相同材质和变换信息的顶点数据。因此,如果我必须使用不同的材质对其他网格进行批处理(因此顶点无法与现有浴合并),我必须使用实例化的新 vbo 创建一个新批次。
因此,根据作者的说法,我的第二种方法是不正确的:不建议将多个批次存储到单个 VBO 中。
假设设备内存中有一个顶点缓冲区,以及一个与主机一致且可见的暂存缓冲区。还假设桌面系统具有独立的 GPU(因此独立的内存)。最后,假设正确的帧间同步。
我看到更新顶点缓冲区的两种常见可能方法:
Map++ memcpyunmap 到暂存缓冲区,然后是包含 的瞬态(单个命令)命令缓冲区vkCmdCopyBuffer,将其提交到图形队列并等待队列空闲,然后释放瞬态命令缓冲区。之后,像往常一样将常规帧绘制队列提交到图形队列。这是https://vulkan-tutorial.com上使用的代码(例如,此 .cpp 文件)。
与上面类似,只是在暂存缓冲区复制提交后使用额外的信号量发出信号,并在常规帧绘制提交中等待,从而跳过“等待空闲”命令。
#2 对我来说有点意义,我反复阅读不要在 Vulkan 中执行任何“等待空闲”操作,因为它使 CPU 与 GPU 同步,但我从未见过它在任何教程或中使用网上的例子。如果顶点缓冲区必须相对频繁地更新,专业人士通常会做什么?