泰州网站建设优化平台网站建设外包
- 作者: 五速梦信息网
- 时间: 2026年03月21日 08:23
当前位置: 首页 > news >正文
泰州网站建设优化,平台网站建设外包,昆明新闻最新消息今天,企业网站开发介绍文章目录 4.1 基本颜色理论4.2 缓存及其用途颜色缓存深度缓存 / z缓存 / z-buffer模板缓存 4.2.1 缓存的清除4.2.2 缓存的掩码 4.3 颜色与OpenGL4.3.1 颜色的表达与OpenGL4.3.2 平滑数据插值 4.4 片元的测试与操作4.4.1 剪切测试4.4.2 多重采样的片元操作4.4.3 模板测试模板查询… 文章目录 4.1 基本颜色理论4.2 缓存及其用途颜色缓存深度缓存 / z缓存 / z-buffer模板缓存 4.2.1 缓存的清除4.2.2 缓存的掩码 4.3 颜色与OpenGL4.3.1 颜色的表达与OpenGL4.3.2 平滑数据插值 4.4 片元的测试与操作4.4.1 剪切测试4.4.2 多重采样的片元操作4.4.3 模板测试模板查询 4.4.4 模板示例:绘制三角形黑色边框 4.1 基本颜色理论 计算机图形学的目的就是计算一幅图像中的颜色值。对于OpenGL来说图像通常是显示在计算机屏幕的窗口中的它本身是由规则矩形的像素数组构成的而每个像素都可以显示自己的颜色。OpenGL一般支持RGBA和sRGB颜色空间。 通常来说每个分量的强度都是使用一定数量的位来保存的(称为像素深度bitdepth)而每个分量的像素深度的总和(alpha分量除外)就决定颜色缓存的深度因此也就决定可以显示的颜色的总数量。 例如颜色缓存的一个通常格式是每个红色、绿色和蓝色分量都占用8位。因此我们得到了一个像素深度为 24位的颜色缓存这个颜色空间总共可以显示2的24次方种独立的颜色。 4.2 缓存及其用途 几乎所有图形程序共有的重要目标都是在屏幕上绘制图像(或者绘制到离屏的一处缓存中)。帧缓存(通常也就是屏幕)是由矩形的像素数组组成的分辨率每个像素都可以在图像对应的点上显示一小块方形的颜色值。经过光栅化阶段也就是执行片元着色器之后得到的数据还不是真正的像案——只是候选的片元。每个片元都包含与像素位置对应的坐标数据通常是OpenGL窗口以及颜色和深度的存储值。OpenGL窗口左下角的像素通常也就是(0,0)位置的像素。 假设屏幕为1920像素 x 1080像素颜色深度为rgb888即每个像素将存储至少3个字节的数据。每个像素中的颜色数据大小也不同。不过任何特定类型的颜色缓存记录到屏幕上每个像素的数据总量总是相同的。 颜色缓存只是记录像素信息的多个缓存中的一个。实际上一个像素可能会关联多个颜色缓存。一个显示系统的帧缓存(ftamebuffer)中包含了所有这些缓存类型我们也可以在自己的应用程序中使用多个帧缓存。OpenGL系统中通常包含以下几种类型的缓存(一般都是集成到帧缓存中) 一个或者多个可用的颜色缓存(color buffer)深度缓存(depth buffer)模板缓存(stencil buffer) 除了主颜色缓存之外通常不需要直接观察其他缓存的内容而是用来执行例如隐藏表面的去除、模板草走、动态纹理生成等。 当启动应用程序之后我们使用的是默认的帧缓存(default framebuffer)它是与应用程序窗口所关联的帧缓存。默认帧缓存总是会包含一个颜色缓存。不同的OpenGL实现可以决定自己可用的缓存以及缓存中的每个像素所包含的位数。不同的缓存有不同的特性包括数据存储形式数据类型和精度。多种视效方式或者窗口类型也可能需要更多不同的缓存。 颜色缓存 颜色缓存是我们通常进行绘制的缓存对象。它包含RGB或者SRGB形式的颜色数据也可能包含帧缓存中每个像素的alpha值。帧缓存中可能会含有多个颜色缓存其中默认帧缓存中的“主”颜色缓存需要特别对待因为它是与屏幕上的窗口相关联的所以绘制到“主”颜色缓存的图像都会直接显示到屏幕上其他颜色缓存和屏幕无关。颜色缓存中的像素可能是采用每个像素存储单一颜色值的形式也可能从逻辑上被划分为多个子像素用于多重采样(multisampling)的反走样技术。双重缓冲的实现需要将主颜色缓存划分为两个部分:直接在窗口中显示的前置缓存(fontbu0er)以及用来渲染新图像的后备缓存当执行交换缓存的操作时例如glfwSwapBuffers前置、后备缓存将进行交换。 只有默认帧缓存中的主颜色缓存可以使用双重缓冲的特性。自定义帧缓存只有一个主颜色缓存Color Attachment 0但是可以定义两自定义帧缓存来模拟双重缓冲。 立体显示就是每个颜色缓存(即使已经是双重缓冲的形式)都会再划分出左颜色缓存和右颜色缓存以展现立体图像。 深度缓存 / z缓存 / z-buffer 深度缓存为每个像素保存一个深度值它可以用来判断三维空间中物体的可见性。这里深度是物体与观察者眼睛的距离我们通过x和y值来描述屏幕的水平和竖直方向信息所以这里使用z来描述垂直于屏幕的距离值。深度缓存值较大的像素会被深度缓存值较小的像素所覆盖。这种特性是非常有用的。不过深度缓存的特性也可以通过“深度测试”的方式来改变。 模板缓存 可以用来限制屏幕特定区域的绘制。 例如模板缓存的一个经典用途就是模拟汽车的后视镜视角首先将镜子本身的形状渲染到模板缓存中然后绘制整个场景。此时模板缓存可以阻止所有在镜子形状之外的绘制操作。 4.2.1 缓存的清除 每帧都需要(至少)清除一次缓存。 // 如果设置buffer参数为GL COLOR那么关联的一个颜色缓存将被清除。 // drawbuffer指定需要清除的颜色缓存因为可以同时绘制多个颜色缓存但是一般至少有一个所以可以设置为0. // value是一个指向四个浮点数组成的数组的指针它表示清除颜色缓存之后的初始颜色值浮点数值依次表示红、绿、蓝和 alpha。 // 该函数也可以清楚深度缓存buffer需要设置为GL_DEPTHdrawbuffer必须设置为0因为只有一个深度缓存value指向一个浮点数即清除深度缓存之后的初始深度值。 void glClearBufferfv(GLenum buffer,GLint drawbuffer,const GLfloat * value);//清理函数还有一些替代的版本可以用来清除模板缓存(其中保存的是整数数据)。 void glClearBufferiv( GLenum buffer,GLint drawbuffer,const GLint * value);void glClearBufferuiv( GLenum buffer,GLint drawbuffer,const GLuint * value);// 可以同时清理深度和模板缓存这里buffer必须设置为GL_DEPTH_STENCIL drawbuffer必须为0 void glClearBufferfi( GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil);还有另一个方法来清理缓存 // 例如清理颜色可以将glClear和对应的clear函数搭配 // maskGL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT void glClear(GLbitfield mask);void glClearColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha); void glClearDepth(GLdouble depth); void glClearStencil( GLint s); 4.2.2 缓存的掩码 在写入数据之前可以对数据执行一次掩码操作。下面函数可设置用于控制写入不同缓存的掩码。所有 GLboolean 掩码的默认值均为 GL_TRUE而所有 GLuint掩码的默认值都是1。 void glColorMask(GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha);// 需要渲染到多个颜色缓存,该函数可以对特定的缓存对象设置颜色掩码。 void glColorMaski(GLuint buf,GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha);// 如果为GL_TRUE那么深度缓存可以写入否则无法写入 void glDepthMask(GLboolean flag);//mask参数用于与模板值进行按位“与”操作。 //如果对应位操作的结果为1那么像素的模板值可以写入; //如果为0则无法写入。 void glStencilMask(GLuint mask);//可以为多边形的正面和背面设置不同的模板掩码值。 void glStencilMaskSeparate( GLenum face,GLuint mask);glStencilMask中mask和glStencilFunc中的mask参数没有关系。 glStencilMask中mask是用于对模板位平面的写入的控制。glStencilFunc中的mask是用来控制模板测试时哪些位需要参与比较mask 是一个 8 位的无符号整数范围是 0x00 到 0xFF默认0xFF表示所有位都参与比较。 4.3 颜色与OpenGL 片元着色器可以不借助任何外部数据直接生成片元的颜色值。每个输人的顶点都会提供一个附加的颜色数据可以在其他着色阶段修改后再传人片元着色器并且用它来判断颜色值。数据的补充不只是特定的颜色值都可以在片元着色器中通过计算来生成颜色值。外部数据例如数字图像等也可以在片元着色器中引用用于查找颜色值(或者其他数据值)。这些数据保存在纹理贴图当中并且需要用到纹理映射(texture mapping)技术 4.3.1 颜色的表达与OpenGL 默认情况下OpenGL内部会使用浮点数来表示一个颜色分量并且负责维护它的精度直到数据保存到帧缓存中为止。即除非另有设置否则片元着色器的输入总是浮点数类型为片元颜色设置的数值也是如此并且这些值总是要限制在[0.0,1.01]范围内——称为归一化数值(normalized value)。 可以选择让OpenGL自动将非浮点数类型转换为归一化的浮点数即glVertexAttribPointer或 glVertexAttribN系列函数中的GLboolean normalized参数。此时 OpenGL把输入的数据类型转换到对应的归一化数值范围(范围与输入的数据类型相关例如有符号或者无符号数据类型)。 这样的颜色写人到帧缓存之后会被映射到帧缓存所支持的数值区间颜色空间内。 例如如果帧缓存的每个红色、绿色和蓝色分量都有8 位那么最后颜色分量的区间范围为[0,255]。 4.3.2 平滑数据插值 与其他的顶点数据类似颜色数据也必须保存到顶点缓存对象(VBO)当中。当数据从顶点着色器传递到片元着色器的时候OpenGL会沿着被渲染的图元的每个面对数据进行平滑的插值即Gouraud着色。Gouraud着色的简单片元着色器 const char fragmentShaderSource #version 450 core\n in vec4 vs_fs_color;\n layout (location 0) out vec4 color;\n void main()\n {\ncolor vs_fs_color;\n }\n\0;要注意的是输入到片元着色器的颜色vs_fs_color并不是直接来自于之前的着色阶段(即顶点着色器)而是来自光栅化的结果。 4.4 片元的测试与操作 当我们在屏幕上绘制几何体的时候OpenGL会按照下面的顺序来处理管线 首先执行当前绑定的顶点着色器然后依次是细分和几何着色器(如果它们存在于当前流水线中)。然后将最终几何体装配为图元并送人光栅化阶段这里将计算出窗口中哪些像素受到了几何体的影响。当OpenGL确定当前需要生成一个独立的片元时它将执行片元着色器的内容。然后再经过几个处理阶段判断片元是否可以作为像素绘制到帧缓存中以及控制绘制的方式。 例如如果片元超出了帧缓存的矩形区域或者它与当前帧缓存中同位置的像素相比距离视点更远那么正在处理的过程都会停止片元也不会被绘制。 5.片元的颜色会与当前帧缓存中的像素颜色进行混合。 而本节内容介绍的就是片元进入到帧缓存之前所需要经过的完整测试过程以及片元写入时可以执行的一些操作。 这些测试和操作大部分都可以通过glEnable和glDisable来分别启用和禁止。 如果一个片元在某个测试过程中丢弃那么之后所有的测试或者操作都不会再执行这些测试和操作的发生顺序如下 剪切测试(scissor test)多重采样的片元操作模板测试(stencil test)深度测试(depth test)融混(blending)逻辑操作 4.4.1 剪切测试 我们将程序窗口中的一个矩形区域称作一个剪切盒(scissor box)并且将所有的绘制操作都限制在这个区域内。使用glEnable(G_SCISSOR_TEST);开启测试或使用glDisable来禁止测试。如果片元位于矩形区域内那么它将通过剪切测试。使用glScissor设置剪切盒。 // 设置剪切矩形(或者剪切盒)的位置与大小。 // 参数定义了矩形的左下角(x,y)以及宽度(width)和高度(height)。 // 默认条件下剪切矩形与窗口的大小是相等的并且剪切测试是关闭的。 void glScissor( GLint x,。GLint y,GLsizei width,GLsizei height); 如果已经开启测试那么所有的渲染(包括窗口的清除)都被限制在剪切盒区域内而与之不同视口并不会限制屏幕的清楚操作。 glViewport(0, 0, 800, 600);正常情况下 glViewport(0, 0, 800, 600); glEnable(GL_SCISSOR_TEST); glScissor(0,0,400,300); 获取是否开启了剪切测试和查询剪切盒 // cap设置为GL_SCISSOR_TEST GLboolean glIsEnabled( GLenum cap); GLboolean glIsEnabledi( GLenum cap,GLuint index);// pname参数为GL_SCISSOR_BOX void glGetIntegerv( GLenum pname,GLint * data);参数cap的更多参考OpenGL实际上有多个剪切矩形。默认情况下所有的渲染测试都是在第一个矩形上完成的如果开启。如果要访问其他剪切盒需要使用几何着色器详见后文。 4.4.2 多重采样的片元操作 多重采样Multisampling 是一种抗锯齿Anti-Aliasing技术用于减少渲染图形时边缘的锯齿状走样Aliasing。采样点分布每个像素包含多个子采样点例如4x、8x这些点的位置由硬件或驱动决定。光栅化阶段 几何图元如三角形被覆盖时计算每个子采样点是否在图元内。若至少一个子采样点被覆盖该像素的片段会进入后续处理如着色器。最终的像素颜色由所有子采样点的覆盖率混合决定平滑边缘。 仅对几何边缘的像素进行多次采样其他区域保持单次采样性能高效。片段着色器仅运行一次结果被多个子采样点共享除非使用 sample 关键字修饰变量。每个子采样点独立进行深度和模板测试确保边缘精度。 默认情况下多重采样在计算片元的覆盖率时不会考虑alpha的影响。如果假设多重采样本身已经开启使用glEnable(GL_MULTISAMPLE);并且帧缓存已经关联了一个多重采样的缓存数据那么可用的特定模式如下 均可以使用glEnable // 使用片元的 alpha值来计算最后的采样覆盖率并且这一过程与具体的硬件实现无关。 GL_SAMPLE_ALPHA_TO_COVERAGE// 将片元的 alpha值设置为最大的 alpha值然后使用这个值来进行覆盖率的计算。 // 如果GL_SAMPLE_ALPHA_TO_COVERAGE也被启动那么系统将使用替代前的片元的alpha值。 GL_SAMPLE_ALPHA_TO_ONE// 将使用glSampleCoverage()中设置的数值。 GL_SAMPLE_COVERAGE// 设置多重采样覆盖率的参数以正确解算alpha值。 // invert是一个布尔变量用于设置这个临时覆盖值是否需要先进行位反转 //然后再与片元覆盖率进行合并(“与”操作)。 void glSampleCoverage( GLfloat value,GLboolean invert);多重采样的特定模式主要是为了解决对于使用透明纹理如树叶、栅栏、UI元素等的物体传统多重采样MSAA可能无法有效消除锯齿因为这些物体的边缘通常通过Alpha测试如discard硬性裁剪导致锯齿边缘且多重采样仅基于几何覆盖计算抗锯齿无法直接利用Alpha通道的渐变信息。而且开启特定模式对于每个片段Fragment根据其Alpha值自动生成一个覆盖掩码Coverage Mask。覆盖掩码的权重由Alpha值决定Alpha值越高越不透明覆盖的采样点越多Alpha值越低越透明覆盖的采样点越少。最后边缘的Alpha值会控制覆盖的采样点数量实现平滑过渡。注意如果启用了混合则需要保证渲染顺序正确否则混合结果可能异常一般是先不透明从后往前然后是透明的从深度高的到深度低的。 还可以设置精确的位掩码来计算和表达覆盖率而不是让opengl自己去生成这个掩码这个掩码与缓存中的每个采样值都有一位(bit)进行对应它将与片元的采样覆盖值再次进行“与”操作 // 设置一个32位的采样掩码mask。 // 掩码本身的索引位置通过index 来设置而新的掩码值通过 mask来设置。 // 当采样结果准备写入到帧缓存时只有当前采样掩码值中对应位的数据才会被更新 //而其他的数据将会被丢弃。 void glSampleMaski( GLuint maskNumber,GLbitfield mask);// 也可以在片元着色器中通过写入下方内置变量来设置采样掩码 // 是一个32位数据的数组。 gl_SampleMask如果当前帧缓存包含了多于32个采样数那么采样掩码的长度可能是多个32位大小的WORD字段组成其中第一个WORD表示前32位的数据第二个 WORD表示之后32位的数据以此类推。 4.4.3 模板测试 glEnable(GL_STENCIL_TEST)和glDisable(GL_STENCIL_TEST)启用和禁用模板测试默认禁止模板测试。只有在建立窗口的过程中有预先请求模板缓存的前提下才能使用模板测试否则没有模板缓存模板测试永远通过。模板测试过程中会取像素在模板缓存中的值然后与一个参考值进行比较然后根据比较 / 测试的结果不同还可以对模板缓存中的数据进行更改。可以使用各种特定的比较函数、参考值然后使用glStencilFunc和glStencilOp来完成修改操作。 //参考值将与板缓存中已有的值进行比较 //但是在此之前需要与mask参数进行按位“与”操作 //丢弃结果为0的位平面。 // funcGL_NEVER, GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL, GL_EQUAL, GL_NOTEQUAL, and GL_ALWAYS(默认) // 例如GL_LESS应该是ref比模板中的值更小时片元模板测试通过。 // mask主要用于判断当前片元是否要参与比较,默认所有位为1。 // ref 范围在0到2的n次方-1n为模板缓存位面数。 void glStencilFunc(GLenum func,GLint ref,GLuint mask);void glStencilFuncSeparate(GLenum face,GLenum func,GLint ref,GLuint mask);如果支持GL_ARB_shader_stencil_export可以通过在片元着色器向内置变量gl_FragStencilRefARB写入逐片元的值将会在glStencilFunc和glStencilFuncSeparate中当作ref的值使用。 // 设置当片元通过或者没有通过模板测试的时候要如何处理模板缓存中的数据。 // sfail,dpfail,dppass都可以设置为GL_KEEP(全部参数的默认), GL_ZERO, //GL_REPLACE, GL_INCR, GL_INCR_WRAP, GL_DECR, //GL_DECR_WRAP, and GL_INVERT。 // 加1和减1函数的结果值总是落在0到最大无符号整数值,即0到2的n次方-1n为模板缓存位面数。 //如果片元没有通过模板测试将执行sfai1函数; //如果通过了模板测试但是没有通过深度测试那么执行dpfail 函数. //如果通过深度测试或者没有开启深度测试则执行dppass函数。 void glStencilOp(GLenum sfail,GLenum dpfail,GLenum dppass);void glStencilOpSeparate(GLenum face,GLenum sfail,GLenum dpfail,GLenum dppass); GL_KEEP保持当前值。GL_ZERO替换为0值。GL_REPLACE替换为参考值ref。GL_INCR增加1使用饱和运算GL_INCR_WRAP增加1不使用饱和运算GL_DECR减少1使用饱和运算GL_DECR_WRAP减少1不使用饱和运算GL_INVERT按位反转 模板查询 通过glGetIntegerv来查询参数 void glGetIntegerv( GLenum pname,GLint * data);查询参数意义GL_STENCIL_FUNC模板函数GL_STENCIL_REF模板参考值GL_STENCIL_VALUE_MASK模板掩码GL_STENCIL_FAIL模板测试失败的处理函数GL_STENCIL_PASS_DEPTH_FAIL模板测试通过但是深度测试失败的处理函数GL_STENCIL_PASS_DEPTH_PASS模板测试和深度测试均通过的处理函数 glIsEnable(GL_STENCIL_TEST)判断模板测试是否已经开启。 4.4.4 模板示例:绘制三角形黑色边框 #includeglad/glad.h #include GLFW/glfw3.h #include iostream// Vertex Shader source code const char* vertexShaderSource #version 450 core\n layout (location 0) in vec4 position;\n layout (location 1) in vec4 color;\n out vec4 vs_fs_color;\n void main()\n {\ngl_Position position;\nvs_fs_color color;\n }\0; //Fragment Shader source code const char* fragmentShaderSource #version 450 core\n in vec4 vs_fs_color;\n layout (location 0) out vec4 color;\n void main()\n {\ncolor vs_fs_color;\n }\n\0;const GLfloat vertices[] {-0.5f, -0.5f, 0.0f,1.0f,0.5f, -0.5f, 0.0f,1.0f,0.0f, 0.5f, 0.0f,1.0f,};//const GLfloat verticesOutline[] //{ // -0.55f, -0.55f, -0.01f,1.0f, // 0.55f, -0.55f, -0.01f,1.0f, // 0.0f, 0.55f, -0.01f , 1.0f, // //};const GLfloat verticesOutline[] {-0.55f, -0.55f, 0.0f,1.0f,0.55f, -0.55f, 0.0f,1.0f,0.0f, 0.55f, 0.0f , 1.0f,};const GLfloat colors[] {0.0f, 0.0f, 0.0f,1.0f,0.0f, 0.0f, 0.0f,1.0f ,0.0f, 0.0f, 0.0f,1.0f ,};const GLubyte colorsNeedNormal[] {255, 255, 255,255,255, 255, 0,255 ,255, 0, 255,255 ,};// 编译链接着色器的辅助函数 unsigned int shaderProgram(const char* vertexSrc, const char* fragmentSrc) {// 创建并编译顶点着色器unsigned int vertexShader glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, vertexSrc, NULL);glCompileShader(vertexShader);int result;glGetShaderiv(vertexShader, GL_COMPILE_STATUS, result);if (result GL_FALSE){int length;glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, length);char* message (char*)alloca(length * sizeof(char));glGetShaderInfoLog(vertexShader, length, length, message);std::cout message std::endl;glDeleteShader(vertexShader);return -1;}// 创建并编译片段着色器unsigned int fragmentShader glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, fragmentSrc, NULL);glCompileShader(fragmentShader);glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, result);if (result GL_FALSE){int length;glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, length);char* message (char*)alloca(length * sizeof(char));glGetShaderInfoLog(fragmentShader, length, length, message);std::cout message std::endl;glDeleteShader(fragmentShader);return -1;}// 创建着色器程序并链接unsigned int program glCreateProgram();glAttachShader(program, vertexShader);glAttachShader(program, fragmentShader);glLinkProgram(program);// 删除临时着色器对象glDeleteShader(vertexShader);glDeleteShader(fragmentShader);return program; }int main() {// 初始化GLFWif (!glfwInit()) {std::cerr Failed to initialize GLFW std::endl;return -1;}// 创建窗口GLFWwindow* window glfwCreateWindow(800, 600, Stencil Border with Depth, NULL, NULL);if (!window) {std::cerr Failed to create GLFW window std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);gladLoadGL();// 启用深度测试//glEnable(GL_DEPTH_TEST);// 创建着色器程序unsigned int redShader shaderProgram(vertexShaderSource, fragmentShaderSource);//unsigned int whiteShader shaderProgram(vertexShaderSource, fragmentShaderWhiteSource);// 配置顶点数据unsigned int VAOs[2], VBOs[2];glGenVertexArrays(2, VAOs);glGenBuffers(2, VBOs);// 设置原始三角形VAOglBindVertexArray(VAOs[0]);glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) sizeof(colorsNeedNormal), NULL, GL_STATIC_DRAW);glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices), sizeof(colorsNeedNormal), colorsNeedNormal);glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const GLvoid)sizeof(vertices));glEnableVertexAttribArray(0);glEnableVertexAttribArray(1);// 设置边框三角形VAOglBindVertexArray(VAOs[1]);glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);glBufferData(GL_ARRAY_BUFFER, sizeof(verticesOutline) sizeof(colors), NULL, GL_STATIC_DRAW);glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verticesOutline), verticesOutline);glBufferSubData(GL_ARRAY_BUFFER, sizeof(verticesOutline), sizeof(colors), colors);glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid)sizeof(vertices));glEnableVertexAttribArray(0);glEnableVertexAttribArray(1);// 主渲染循环while (!glfwWindowShouldClose(window)) {// 清空缓冲//glClearColor(1.0f, 0.1f, 0.1f, 1.0f); // 深灰色背景//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);static const float black[] { 1.0f,0.0f,0.0f,0.0f };glClearBufferfv(GL_COLOR, 0, black);glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);// 启用模板测试glEnable(GL_STENCIL_TEST);glEnable(GL_DEPTH_TEST);// — 第1步绘制红色三角形 —glStencilFunc(GL_ALWAYS, 1, 0xFF); // 总是通过模板测试将三角形对应像素模板值写入1glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); // 通过时替换为1glUseProgram(redShader);glBindVertexArray(VAOs[0]);glDrawArrays(GL_TRIANGLES, 0, 3);// — 第2步绘制白色边框 —glStencilFunc(GL_NOTEQUAL, 1, 0xFF); // 仅模板值≠1的区域绘制glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // 不修改模板缓冲glBindVertexArray(VAOs[1]);// 关键设置启用深度测试但禁用深度写入//glDepthMask(GL_FALSE);glDrawArrays(GL_TRIANGLES, 0, 3);//glDepthMask(GL_TRUE);// 禁用模板测试glDisable(GL_STENCIL_TEST);// 交换缓冲区和处理事件glfwSwapBuffers(window);glfwPollEvents();}// 清理资源glDeleteVertexArrays(2, VAOs);glDeleteBuffers(2, VBOs);glDeleteProgram(redShader);glfwTerminate();return 0; }
- 上一篇: 泰州网站建设费用公司网站怎么做包括什么
- 下一篇: 泰州网站开发腾讯广告建站工具
相关文章
-
泰州网站建设费用公司网站怎么做包括什么
泰州网站建设费用公司网站怎么做包括什么
- 技术栈
- 2026年03月21日
-
泰州网站关键词优化面包屑 wordpress
泰州网站关键词优化面包屑 wordpress
- 技术栈
- 2026年03月21日
-
泰州企业网站模板建站精准粉丝引流推广
泰州企业网站模板建站精准粉丝引流推广
- 技术栈
- 2026年03月21日
-
泰州网站开发腾讯广告建站工具
泰州网站开发腾讯广告建站工具
- 技术栈
- 2026年03月21日
-
泰州网站模板汕头第一网告别单身
泰州网站模板汕头第一网告别单身
- 技术栈
- 2026年03月21日
-
泰州网站设计咨询淘宝做图片的网站
泰州网站设计咨询淘宝做图片的网站
- 技术栈
- 2026年03月21日
