OpenGL3.3绘制方法

目录

常规绘制

glDrawArrays(GLenum mode,GLint first,GLsizei count )

mode的类型有:
在这里插入图片描述
不能调用GL_POLYGON 改为了void glPolygonMode(GLenum face, GLenum mode);
起始位置为first 借宿位置为firsr+count-1

glDrawElements(GLenum mode,GLsizei count,GLenum type,consr GLvoid *indices)

使用count个元素来定义一系列几何图元 差不多就是多少个点形成一个图元
indices 定义了元素数组缓存中的偏移地址 也就是索引开始的位置
type必须时GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT中的一个 表示的是索引数据的类型

glDrawElementsBaseVertex(GLenum mode,GLsizei count,GLenum type,count GLvoid* indices,GLint basevertex)

实际上就是在basevertex个元素之后开始绘制 也就是 indices[i]+basevertex

glDrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid* indices)

是glDrawElements的一种严格形式 元素数组缓存中包含的任何一个索引值都会落入到start和end所定义的范围当中

glDrawRangeElementsBaseVertex(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid*indice,GLint basevertex)

实际上就是有basevertex和elements和range的结合

参数从GL_DRAW_INDIRECT_BUFFER缓存 间接绘制缓存中获取的结构体数据

glDrawArraysIndirect(GLenum mode, const GLvoid* indirect)

和glDrawArraysInstanced()完全一致 绘制命令的参数是从绑定到GL_DRAW_INDIRECT_BUFFER的缓存中获取的具体数据
indirect记录间接绘制缓存中的偏移地址 mode必须是glDrawArrays()所支持的某个图元类型
DrawArraysIndirectCommand结构体的声明
typedef struct DrawArraysIndirectCommand_t
{
GLuint count;
GLuint primCount;
GLuint firsr;
GLuint baseInstance;
}DrawArraysIndirectCommand;
这个结构体的所有域成员都会作为glDrawArrayInstanced的参数进行解析 first和count会被直接传递到内部函数中
primCount表示多实例的个数
baseInstance表示多实例顶点属性的偏移

glDrawElementsIndirect(GLenum mode, GLenum type,const GLvoid* indirect)(glDrawElements()的间接版本)

indirect记录了间接绘制缓存中的偏移地址 type指定了绘制命令调用时元素数组缓存中索引值的类型
glDrawArraysIndirect()的参数也来自于元素数组缓存中indirect偏移地址所存储的结构体
typedef struct DrawElementsIndirectCommand_t
{
GLuint count;
GLuint primCount;
GLuint firsrIndex;
GLuint baseVertex;
GLuint baseInstance;
}DrawElementsIndirectCommand;
其他的和上面那个函数一样 firsrIndex可以与type参数所定义的索引数据大小相结合 计算传递到glDrawElementsInstancedBaseVertex()的索引数据结果
baseInstace用来表示结果绘制命令中所有多实例顶点属性的实例偏移值

绘制多组几何图元集

说白了 这里就是自己把顶点数组规整好 可以绘制不同图元出来 类似于
vertex[]{
0.0,0.0,0.0,
1.0,0.0,0.0,
1.0,1.0,0.0,

2.0,0.0,0.0,
3.0,0.0,0.0,
3.0,1.0,0.0,
2.0,1.0,0.0}
first[]{
0.0,
1.0
}
count[]{
3.0,
4.0}
大概就是这样可以绘制一个三角形 一个正方形
说实话也可以自行拼接图形了
也就是并不一定要用三角形带画四边形

glMultiDrawArrays(GLenum mode,consr GLint* first,const GLint* count,GLsizei primcount)(绘制多个图元)

在一个OpenGL函数调用过程中绘制多组集合图元集
first和count都是数组的形式
glMultiDrawArrays(GLenum mode,consr GLint* first,const GLint* count,GLsizei primcount)
{
GLsizei i;
for(i = 0;i<primcount ; i++)
{
glDrawArrays(mode,first[i],count[i])
}
}

glMultiDrawElements(GLenum mode,const GLint* count,GLenum type,const GLvoid* const*indices,GLsizei primcount)

等价于
for(int i = 0;i<primcount;i++)
{
glDrawElements(mode,count[i],type,indices[i])
}

glMultiDrawElementsBaseVertex(GLenum mode,const GLint* count,GLenum type,const GLvoid* constindices,GLsizei primcount,consr GLint baseVertex)

基本一样 就是baseVertex[]也是数组

glMultiDrawArraysIndirect(GLenum mode,const GLvoid* indirext,GLsizei drawcount,GLsizei stride)

可以分发总共drawcount个独立的绘制命令
每个DrawArraysIndirectCommand结构体之间的间隔都是stride个字节

glMultiDrawElementsIndirect(GLenum mode,GLenum type,const GLvoid* indirext,GLsizei drawcount,GLsizei stride)

结构体是DrawElementsIndirectCommand

图元重启动

glPrimitiveRestartInde(GLuint index)

这个函数要和索引绘制配合使用
也就是在索引绘制的使用如果碰到了 index索引则跳过该索引 终止当前图元绘制 从下一个顶点索引重新开始渲染同一类型的图元集合
例如
static const GLushort index[]{
1,2,3,0xFFFF,3,1,2}
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(0xFFFF);
glDrawElements(GL_TRIANGLE_STRIP,7,GL_UNSIGNED_SHORT,NULL)
要不然就要使用两个glDrawElements()绘制了
7 包含了0xFFFF
通过管理Enable(GL_PRIMITIVE_RESTART)和Disable(GL_PRIMITIVE_RESTART)
默认重启索引是0

多实例渲染

是一种连续执行多条相同渲染命令的方法 并且每个渲染命令所产生的结果都会有轻微的差异
我觉得这个相对于多组集合图元集来说 这个是使用一组顶点 在多个地方绘制出来

glDrawArraysInstanced(GLenum mode,GLint first,GLsizei count,GLsizei primCount)

前面参数都一样 绘制它的primCount个实例 每个实例内置变量gl_InstanceID都会依次递增
当OpenGL执行这个函数的适合 他实际上会执行glDrawArrays的primVount次拷贝 其他类似函数也一样

glDrawElementsInstanced(GLenum mode,GLsizei count,GLenum type,count void*indices,GLsizei primCount)

DrawElementsIndtancedBaseVertex(GLenum mode,GLsizei count,GLenum type,const void* indices,GLsizei instanceCount,GLuint baseVertex);

类似于glDrawElementsInstancedBaseVertex()函数所需的独立函数

glDrawArraysInstancedBaseInstance(GLenum mode,Glint first,GLsizei count,GLsizei instanceCount,Gluint baseInstance)

对于每个实例 内置变量gl_InstanceID都会依次递增 baseInstance的值用来对实例化的顶点属性设置一个索引的偏移值 从而改变OpenGL取出索引的位置

glDrawElementsInstancedBaseInstance(GLenum mode, GLsizei count,GLenum type,count GLvoid* indices,GLsizei instanceCount,GLuint baseInstance)

glDrawElementsInstancedBaseVertexBaseInstance(GLenum mode,GLsizei count ,GLenum type,const GLvoid*indices,GLsizei instanceCount,GLuint baseInstance)

多实例的顶点属性

(控制顶点属性更新频率)glVertexAttribDivisor(GLuint index,GLuint divisor)

例子:如果设置了顶点颜色的索引位置为1 则可以
glVertexAttribDivisor(1,1);则代表颜色值在每更新一个实例时分配一个新的属性值
index表示设置多实例特性的顶点属性的索引位置
如果divisor值为0 则该属性的多实例特性将被禁用 其他的值则表示顶点着色器 每divisor个实例都会分配一个新的属性值 //这里没看懂 应该就是跟没设置一样
如果非0则顶点属性将启用多实例的特性 OpenGL从属性数组中每隔divisor个实例都会读取一个新的值(而不是之前的每个顶点)
instance表示当前的实例数目
divisor表示当前属性的更新频率值
每个实例中的所有顶点都会共享同一个属性值
如果divisor为2 则每两个实例会共享同一个属性值
如果某个顶点属性被设置了divisor则每个实例都会有一个独立的值 而实例当中所有顶点都会使用这一个值

纹理运用

将一系列纹理打包到一个2D纹理数组中 然后将数组的序号通过实例化的顶点属性传递给每个实例 这样就可以使用不同的纹理来选软不同的几何体实例

gl_InstanceID

总是在顶点着色器中 变量是一个整型 从-开始计数 每当一个实例被渲染之后 这个值就会加一
gl_InstanceID的值可以作为uniform数组的索引使用 也可以作为纹理查找的参数使用 或者作为某个分析函数的输入

多实例模型矩阵配置

	/*这里是将model矩阵传进着色器 方便多实例绘制的使用*/
	/*模型矩阵 因为是mat4类型的数据 */
	glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(vertices)));
	glEnableVertexAttribArray(3);
	glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4) + sizeof(vertices)));
	glEnableVertexAttribArray(4);
	glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2*sizeof(glm::vec4) + sizeof(vertices)));
	glEnableVertexAttribArray(5);
	glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3*sizeof(glm::vec4) + sizeof(vertices)));
	glEnableVertexAttribArray(6);
	glVertexAttribDivisor(3, 1);
	glVertexAttribDivisor(4, 1);
	glVertexAttribDivisor(5, 1);
	glVertexAttribDivisor(6, 1);
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以这样绘制一个正方形: 1. 创建正方形的顶点数据,包括位置和纹理坐标。 2. 加载着色器,并使用着色器程序。 3. 将顶点数据传递到着色器。 4. 设置视图和投影矩阵。 5. 渲染正方形。 这是一个使用 OpenGL 3.3 绘制正方形的简单示例代码: ``` #include <GL/glew.h> #include <GLFW/glfw3.h> #include <iostream> #include <cstdio> const char *vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" "}\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}\n\0"; int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { std::cout << "Failed to initialize GLEW" << std::endl; return -1; } int vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexSh ### 回答2: OpenGL 是一种图形库和底层 API,用于在计算机上绘制 2D 和 3D 图形。OpenGL 版本 3.3 是比较旧的版本,但仍然可以使用来绘制基本的形状,如正方形。 要绘制一个正方形,我们需要做以下几个步骤: 1. 初始化 OpenGL 窗口和环境。这涉及到创建一个窗口和设置 OpenGL 环境参数,例如绘制方式、画布大小等。 2. 创建着色器程序。OpenGL 使用着色器程序来控制图形的绘制过程。我们需要创建顶点着色器和片段着色器。顶点着色器负责将顶点的位置传递给图形管线,片段着色器则控制像素的颜色输出。 3. 定义顶点数据。我们需要定义正方形的顶点坐标。一个正方形有四个顶点,每个顶点有 x、y 和 z 三个坐标值。 4. 编译和链接着色器程序。将顶点着色器和片段着色器编译成可执行代码,并将它们链接在一起。 5. 创建和绑定顶点缓冲区。将顶点数据发送到显存中的缓冲区,以供后续绘制使用。 6. 设置顶点属性指针。告诉 OpenGL 如何解析缓冲区中的顶点数据。 7. 绘制正方形。使用 OpenGL 提供的绘制函数,例如 glDrawArrays 或 glDrawElements 来绘制正方形。 8. 清除内存和销毁窗口。当绘制完成后,清除之前申请的内存,并销毁创建的窗口和环境。 通过以上步骤,我们可以使用 OpenGL 3.3 来绘制一个简单的正方形。这只是一个简单示例,实际的绘制流程可能更加复杂,需要按照项目的需求和设计来进行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值