OpenGL 面剔除

news2024/9/20 9:07:10

1.简介

OpenGL能够检查所有面向观察者的面,并渲染它们,而丢弃那些背向的面,节省我们很多的片段着色器调用(它们的开销很大!)。但我们仍要告诉OpenGL哪些面是正向面,哪些面是背向面。OpenGL使用了一个很聪明的技巧,分析顶点数据的环绕顺序。

2.环绕顺序

当我们定义一组三角形顶点时,我们会以特定的环绕顺序来定义它们,可能是顺时针的,也可能是逆时针的。每个三角形由3个顶点所组成,我们会从三角形中间来看,为这3个顶点设定一个环绕顺序。

可以看到,我们首先定义了顶点1,之后我们可以选择定义顶点2或者顶点3,这个选择将定义了这个三角形的环绕顺序。

float vertices[] = {
    // 顺时针
    vertices[0], // 顶点1
    vertices[1], // 顶点2
    vertices[2], // 顶点3
    // 逆时针
    vertices[0], // 顶点1
    vertices[2], // 顶点3
    vertices[1]  // 顶点2  
};

OpenGL在渲染图元的时候将使用这个信息来决定一个三角形是一个正向三角形还是背向三角形。默认情况下,逆时针顶点所定义的三角形将会被处理为正向三角形。

在顶点数据中,我们定义的是两个逆时针顺序的三角形。然而,从观察者的方面看,后面的三角形是顺时针的,如果我们仍以1、2、3的顺序以观察者当面的视野看的话。即使我们以逆时针顺序定义后面的三角形,它现在还是变为顺时针。它正是我们打算剔除(丢弃)的不可见的面!

3.面剔除

要想启用面剔除,我们只需要启用OpenGL的GL_CULL_FACE选项:

glEnable(GL_CULL_FACE);

从这一句代码之后,所有背向面都将被丢弃。我们在渲染片段的时候能够节省50%以上的性能,但注意这只对像立方体这样的封闭形状有效。

OpenGL允许我们改变需要剔除的面的类型,可以调用glCullFace来实现:

glCullFace(GL_FRONT);

glCullFace函数有三个可用的选项:

  • GL_BACK:只剔除背向面。
  • GL_FRONT:只剔除正向面。
  • GL_FRONT_AND_BACK:剔除正向面和背向面。

glCullFace的初始值是GL_BACK。除了需要剔除的面之外,我们也可以通过调用glFrontFace,告诉OpenGL我们希望将顺时针的面(而不是逆时针的面)定义为正向面:

glFrontFace(GL_CCW);

默认值是GL_CCW,它代表的是逆时针的环绕顺序,另一个选项是GL_CW,它(显然)代表的是顺时针顺序。

4.示例

以下是原始图形:

开启面剔除以后:

    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);//剔除背向面
    glFrontFace(GL_CW);//顺时针的环绕顺序是正向面,逆时针的就会被剔除

 

修改一下顶点顺序:

 

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLTexture>
#include <QImage>
#include <QOpenGLShaderProgram>

class MyOpenGLWidget : public QOpenGLWidget,public QOpenGLFunctions_3_3_Core
{
public:
    MyOpenGLWidget(QWidget *parent = nullptr);

protected:
    virtual void initializeGL();
    virtual void paintGL();
    virtual void resizeGL(int w, int h);

private:
    QOpenGLTexture *m_wall;

    QOpenGLTexture *m_face;

    QOpenGLShaderProgram *m_program;
};

#endif // MYOPENGLWIDGET_H




#include "myopenglwidget.h"
#include <QMatrix4x4>
#include <QTime>
#include <QTimer>
#include <math.h>
#include <QVector3D>
#include <QVector>

float vertices[] = {
    //坐标                //纹理坐标
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
     0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

    0.5f, -0.5f,  0.5f,  1.0f, 0.0f,   //交换这两行顺序
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,   //交换这两行顺序

     0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
     0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

     0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
     0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
     0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
     0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
     0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
     0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
     0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
     0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
     0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
     0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};

GLuint indices[] = {
    0, 1, 3,
    1, 2, 3
};

//顶点着色器语言
const GLchar* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec2 texCoord;\n"
"out vec2 outTexCoord;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(position,1.0);\n"
"outTexCoord = texCoord;\n"
"}\n\0";

//片段着色器语言
//texture函数会使用之前设置的纹理参数对相应的颜色值进行采样
//mix按一定的比例,混合两个纹理颜色
const GLchar* fragmentShaderSource = "#version 330 core\n"
"out vec4 color;\n"
"uniform sampler2D ourTexture1;\n"
"uniform sampler2D ourTexture2;\n"
"in vec2 outTexCoord;\n"
"void main()\n"
"{\n"
"color = mix(texture(ourTexture1, outTexCoord),texture(ourTexture2, vec2(outTexCoord.x, outTexCoord.y)),0.45);\n"
"}\n\0";

GLuint VBO, VAO,EBO;
GLuint shaderProgram;

QTimer *timer;

QVector<QVector3D> cubePositions = {
  QVector3D( 0.0f,  0.0f,  0.0f),
  QVector3D( 2.0f,  5.0f, -15.0f),
  QVector3D(-1.5f, -2.2f, -2.5f),
  QVector3D(-3.8f, -2.0f, -12.3f),
  QVector3D( 2.4f, -0.4f, -3.5f),
  QVector3D(-1.7f,  3.0f, -7.5f),
  QVector3D( 1.3f, -2.0f, -2.5f),
  QVector3D( 1.5f,  2.0f, -2.5f),
  QVector3D( 1.5f,  0.2f, -1.5f),
  QVector3D(-1.3f,  1.0f, -1.5f)
};

MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    timer = new QTimer();
    timer->start(50);
    connect(timer,&QTimer::timeout,[=]{
        update();
    });
}

void MyOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    m_program = new QOpenGLShaderProgram();
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,vertexShaderSource);
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShaderSource);
    m_program->link();

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);//绑定VAO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);//顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把顶点数据复制到缓冲的内存中GL_STATIC_DRAW :数据不会或几乎不会改变。

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glBindVertexArray(0);//解绑VAO

    m_wall = new QOpenGLTexture(QImage("./container.jpg").mirrored());
    m_face = new QOpenGLTexture(QImage("./awesomeface.png").mirrored());

    m_program->bind();
    m_program->setUniformValue("ourTexture1",0);
    m_program->setUniformValue("ourTexture2",1);

    //设置透视投影矩阵
    QMatrix4x4 projection;
    projection.perspective(45,(float)(width())/(height()),0.1,100);
    m_program->setUniformValue("projection",projection);

    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);//剔除背向面
    glFrontFace(GL_CW);//顺时针的环绕顺序是正向面,逆时针的就会被剔除

}

void MyOpenGLWidget::paintGL()
{
    glClearColor(0.2f,0.3f,0.3f,1.0f);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 model;
    QMatrix4x4 view;

    view.translate(0,0,-4);

    m_program->bind();

    glBindVertexArray(VAO);//绑定VAO

    m_wall->bind(0);
    m_face->bind(1);

    //设置观察矩阵
    m_program->setUniformValue("view",view);

//    foreach(auto pos , cubePositions)
//    {
//        //设置为单位矩阵
//        model.setToIdentity();
//        //平移
//        model.translate(pos);
//        //设置模型矩阵
//        m_program->setUniformValue("model",model);
//        glDrawArrays(GL_TRIANGLES,0,36);
//    }
    model.setToIdentity();
    model.rotate(45,0.3,0.3);
    m_program->setUniformValue("model",model);
    glDrawArrays(GL_TRIANGLES,0,36);
}

void MyOpenGLWidget::resizeGL(int w, int h)
{

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/676138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Axure教程——走马灯

本文介绍用Axure中的动态面板制作走马灯效果 一、效果 预览地址&#xff1a;https://okjxsd.axshare.com 二、功能 1、图片自动播放并显示其状态 2、点击左右箭头&#xff0c;图片播放并显示其状态 三、制作 1、动态面板制作 拖进一个动态面板元件&#xff0c;设置尺寸&#…

RISC-V semi-hosting原理以及实践

嵌入式裸机调试需要在有限资源的目标硬件上尽可能挖掘更多的信息&#xff0c;比如打印寄存器等等&#xff0c;但是即便看似很简单的串口打印&#xff0c;在有的情况下也是奢望&#xff0c;针对这种情况&#xff0c;能够有效利用主机资源协同调试的semi-host&#xff08;半主机&…

B. Fish Graph(dfs找环)

Problem - 1817B - Codeforces 给定一个具有n个节点和m条边的简单无向图。请注意&#xff0c;该图不一定是连通的。节点从1到n标记。 如果图包含具有特殊节点u的简单循环&#xff0c;则定义图为Fish Graph。除循环中的边之外&#xff0c;图应恰好有2条额外的边。两条边都应连接…

设计模式之外观模式笔记

设计模式之外观模式笔记 说明Facade(外观)目录外观模式示例类图电灯类电视机类空调类智能音箱外观类测试类 说明 记录下学习设计模式-外观模式的写法。JDK使用版本为1.8版本。 Facade(外观) 意图:为子系统中的一组接口提供一个一致的界面&#xff0c;Facade模式定义了一个高…

【2023,学点儿新Java-23】初步了解Java中的修饰符:static及其作用、native特性、final的理解

前情回顾&#xff1a; 【2023&#xff0c;学点儿新Java-22】Java中package的作用是什么 | Java中import的用法 | Java中的权限修饰符&#xff1a;private、protected、public【2023&#xff0c;学点儿新Java-21】Java中default的语法格式 | 父类私有的方法能被重写吗&#xff…

三分钟学习一个python小知识3-----------我的对python的列表和元组的理解

我的目录 1、python是什么2、列表的应用3. 元组的应用&#xff1a;4、深层次地进一步理解列表和元组4.1. 列表示例&#xff1a;4.2. 元组示例&#xff1a; 总结 1、python是什么 在Python中&#xff0c;列表和元组都是用于存储多个数据项的数据结构&#xff0c;但是它们有一些…

JavaWeb Tomcat

1.Web分类 静态web html这样的静态网页&#xff0c;只展示预先设定好的内容每个用户看到的内容是一样的不连接数据库&#xff0c;无法持久化数据&#xff08;比如注册&#xff09;动态web 动态展示内容每个用户看到的内容是不一样的&#xff0c;比如会有个性化推荐连接数据库&…

TienChin 项目改造完善项目结构分析

项目改造完善 更改 Banner Banner 生成网站&#xff1a;https://bootschool.net/ascii 更改启动类中的 Banner !> 如果不生效&#xff0c;需要重新编译一下项目工程(出现了启动之后还没改变就需要执行一下这个步骤)&#xff1a; 出现的原因是可能你没有删除 .idea 文件与 .i…

夜不收见证:夫妻从内江到成都,从真诚到真相

他们从四川内江的一条小巷&#xff0c;走进了成都的大街小巷。那里的房屋挨挨挤挤&#xff0c;像是在讲述他们曾经的梦想和勇气。他们是那些在内江的土地上种下了友情种子的少年&#xff0c;他们在成都的大地上&#xff0c;硕果累累。 他们从初中的课桌前走到了成人的世界里&am…

模拟电路系列文章-滤波器常识

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 滤波是一个动作&#xff0c;对不同频率输入信号&#xff0c;实施不同的增益和相移&#xff0c;以形成输出。滤波器&#xff0c;是执行这种动作的硬件设备或者软件程序。无论滤…

DJ4-7 SDN、OpenFlow

目录 一、SDN 1、SDN 的引入 2、SDN 体系结构的特征 3、SDN 控制器 4、SDN 通用转发 二、OpenFlow 一、SDN 1、SDN 的引入 软件定义网络 (Software Defined Network) SDN 源自美国斯坦福大学 Clean Slate 研究组提出的一种新型网络创新架构&#xff0c;可通过软件编程…

OCC-BEV:基于三维场景重建的多摄像机统一预训练

论文&#xff1a;https://arxiv.org/pdf/2305.18829.pdf 代码&#xff1a;https://github.com/chaytonmin/Occ-BEV 多摄像机3D感知技术&#xff08;能够收集车辆周围360的环境信息&#xff09;已经成为自动驾驶领域的一个突出研究领域&#xff0c;为 Lidarb-based 解决方案提供…

EMC学习笔记(九)特殊信号的EMC处理(一)

特殊信号的EMC处理&#xff08;一&#xff09; 1.电源接口EMC防护滤波电路1.1 24VDC电源口1.2 电源地的EMC电路1.3 Flyback EMC电路1.4 BUCK电路EMC电路1.5 推挽电路 2.时钟电路的EMC防护2.1 有源时钟2.2 无源时钟2.3 差分时钟 3.复位电路EMC防护4.对外接口信号的EMC防护4.1 差…

简历不要随意给猎头!他们会胡乱投递,影响你之后求职!

猎头是求职的重要途径之一&#xff0c;但猎头群体良莠不齐&#xff0c;并不是每个猎头都值得信任。 一位网友就对猎头持怀疑态度&#xff0c;问大家&#xff1a; 简历可以随意给猎头吗&#xff1f;给他们的时候需要注意什么&#xff1f;他们会不会群发&#xff0c;对自己之后求…

软考A计划-系统集成项目管理工程师-一般补充知识-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

F429驱动TFT裸屏时LTDC

F429驱动TFT裸屏时LTDC时序配置说明&#xff08;以V6的7寸驱动为例&#xff09; 说明&#xff1a; 1. 经常有兄弟问到这个问题&#xff0c;所有这里就写一个帖子。 2. 基础知识学习&#xff1a; TFT LCD的DE模式和HV模式的区别&#xff1a;http://bbs.armfly.com/read.php?tid…

Kafka搭建部署

解压文件 启动zookeeper 配置kafka环境变量 查看Kafka的版本内容 分发Kafka文件到slave1、slave2 修改server.properties文件 在Master、slave1和slave2节点上分别启动Kafka 在Master节点上执行如下命令来创建Topic 解压文件 tar -zxvf kafka_2.12-2.4.1.tgz -C /opt …

2022(一等奖)基于哨兵2影像的典型地表参量和红边指数的特征空间石漠化遥感监测模型

作品介绍 1 监测模型设计概述 &#xff08;1&#xff09;应用背景 石漠化是危害人们安全的自然灾害之一&#xff0c;也是土壤荒漠化其中的一种。我国西南地区是全球石漠化现象最严重的地区之一&#xff0c;长期的人为干预使得生态环境变得非常敏感&#xff0c;地表植被破坏严…

升级系统到Proxmox VE 8

Proxmox VE 8.0正式版发布 Proxmox VE 需要升级到7.4&#xff0c;验证一下。 rootpve99:~# pveversion pve-manager/7.4-13/46c37d9c (running kernel: 5.13.19-6-pve) rootpve99:~# pve7to8 CHECKING VERSION INFORMATION FOR PVE PACKAGES Checking for package updates.…

【实战与杂谈】本地搭建自己的游戏王卡片生成器

声明&#xff1a; 1.游戏王卡片制作器本身就是由【kooriookami】开发的&#xff0c;用于DIY卡片因此我只是原有功能再现并不会追加新功能 2.其次数据和卡图均来源于网络&#xff0c;因此我也只提供网络能获取该内容的途径&#xff0c;并不会预先准备好 最近一直没有时间看回复…