当前位置: 首页 > news >正文

Shader开发(十五)创建四边形

现代计算机图形学中,纹理映射技术是实现高质量视觉效果的核心技术之一。与仅依赖顶点颜色的传统渲染方式相比,纹理技术能够以更低的几何复杂度实现更丰富的视觉细节。本章将详细探讨纹理技术的基础——四边形网格的构建方法及其底层的索引缓冲区技术。


纹理技术的必要性

顶点颜色方案的局限性

使用纯顶点颜色渲染复杂图像存在以下技术限制:

  • 几何复杂度:渲染高细节图像(如图3-1所示的鹦鹉照片)需要数百万个顶点

  • 存储效率:每个顶点都需要独立的颜色数据,造成显著的内存开销

  • 维护成本:图像内容的修改需要重新构建整个网格结构

  • 性能影响:大量顶点数据的传输和处理会降低渲染性能

图3-1 鹦鹉照片

纹理映射技术优势

纹理映射通过将二维图像数据映射到三维网格表面,有效解决了上述问题:

  • 图像数据以纹理形式独立存储,网格仅需基本几何信息

  • 纹理内容可独立修改,无需重构网格

  • 单个片元可访问纹理的任意精度细节

  • 现代GPU对纹理采样操作进行了专门优化


纹理映射的技术原理

纹理坐标系统

纹理映射的核心机制包括以下组件:

  1. 纹理坐标(UV 坐标):为网格顶点指定 2D 坐标(范围通常 [0,1])。

  2. 插值:渲染管线在面间插值 UV 坐标,每个片元获得唯一 UV 值。

  3. 纹理采样:片元着色器根据 UV 坐标从纹理中提取颜色。

纹理采样流程

顶点UV坐标 → GPU插值计算 → 片元UV坐标 → 纹理采样 → 最终颜色

这一流程确保了纹理能够平滑地映射到任意复杂的三维表面。


四边形网格构建

从三角形到四边形的技术转换

在基于三角形的渲染系统中,四边形必须通过两个三角形的组合来实现。图3-2展示了这种基本的几何分解:

图3-2 由两个三角形拼成的四边形

构建四边形网格时,存在两种主要的数据组织方案:

  1. 独立顶点方案:为每个三角形创建独立的顶点数据(6个顶点)

  2. 索引缓冲区方案:创建共享顶点池,通过索引引用(4个顶点)

索引缓冲区方案在内存效率和渲染性能方面均优于独立顶点方案,是现代图形系统的标准实践。


索引缓冲区技术

顶点定义

首先定义四边形的四个顶点坐标:

void ofApp::setup() {// 定义四边形的四个顶点(逆时针顺序)quad.addVertex(glm::vec3(-1, -1, 0));  // 左下角 - 索引0quad.addVertex(glm::vec3(-1,  1, 0));  // 左上角 - 索引1quad.addVertex(glm::vec3( 1,  1, 0));  // 右上角 - 索引2quad.addVertex(glm::vec3( 1, -1, 0));  // 右下角 - 索引3

顶点属性

为每个顶点分配颜色属性(用于调试和验证):

    // 为调试目的分配顶点颜色quad.addColor(ofDefaultColorType(1, 0, 0, 1)); // 红色quad.addColor(ofDefaultColorType(0, 1, 0, 1)); // 绿色quad.addColor(ofDefaultColorType(0, 0, 1, 1)); // 蓝色quad.addColor(ofDefaultColorType(1, 1, 1, 1)); // 白色

索引缓冲区构建

通过索引数组定义两个三角形的顶点连接关系:

    // 定义索引缓冲区:两个三角形共享顶点ofIndexType indices[6] = { 0, 1, 2, 2, 3, 0 };quad.addIndices(indices, 6);

索引序列解析:

  • 第一个三角形:顶点0 → 顶点1 → 顶点2

  • 第二个三角形:顶点2 → 顶点3 → 顶点0

图3-3 标记了每个顶点索引的四边形网格

  • 索引缓冲区:数组指定顶点连接顺序(0-1-2 为第一个三角形,2-3-0 为第二个)。重用顶点 0 和 2,节省内存。

  • 优势:适用于复杂网格,如游戏角色,避免冗余数据。

  • 渲染效果:使用之前的着色器,将显示渐变色填充窗口。

四边形效果如下图:


索引缓冲区的特性

顶点属性的原子性

索引缓冲区中的每个索引值引用的是完整的顶点数据,包括:

  • 顶点位置坐标

  • 顶点颜色属性

  • 纹理坐标(后续添加)

  • 其他自定义属性

这种原子性设计确保了顶点数据的一致性和完整性。

内存优化效果

相比独立顶点方案,索引缓冲区技术实现了:

  • 内存节省:四边形仅需4个顶点而非6个

  • 缓存友好:共享顶点数据提高了GPU缓存命中率

  • 带宽优化:减少了顶点数据的传输量


项目代码参考

项目结构
项目根目录/
├── src/
│   ├── ofApp.h
│   ├── ofApp.cpp
│   └── main.cpp
└── bin/data/├── first_vertex.vert└── first_fragment.frag
ofApp.h
#pragma once#include "ofMain.h"class ofApp : public ofBaseApp{public:void setup();void update();void draw();void keyPressed(int key);void keyReleased(int key);void mouseMoved(int x, int y );void mouseDragged(int x, int y, int button);void mousePressed(int x, int y, int button);void mouseReleased(int x, int y, int button);void mouseEntered(int x, int y);void mouseExited(int x, int y);void windowResized(int w, int h);void dragEvent(ofDragInfo dragInfo);void gotMessage(ofMessage msg);ofMesh quad;ofShader shader;
};
ofApp.cpp
#include "ofApp.h"//--------------------------------------------------------------
void ofApp::setup()
{// 定义四边形的四个顶点(逆时针顺序)quad.addVertex(glm::vec3(-1, -1, 0));  // 左下角 - 索引0quad.addVertex(glm::vec3(-1,  1, 0));  // 左上角 - 索引1quad.addVertex(glm::vec3( 1,  1, 0));  // 右上角 - 索引2quad.addVertex(glm::vec3( 1, -1, 0));  // 右下角 - 索引3// 为调试目的分配顶点颜色quad.addColor(ofDefaultColorType(1, 0, 0, 1)); // 红色quad.addColor(ofDefaultColorType(0, 1, 0, 1)); // 绿色quad.addColor(ofDefaultColorType(0, 0, 1, 1)); // 蓝色quad.addColor(ofDefaultColorType(1, 1, 1, 1)); // 白色// 定义索引缓冲区:两个三角形共享顶点ofIndexType indices[6] = { 0, 1, 2, 2, 3, 0 };quad.addIndices(indices, 6);shader.load("vertex_color.vert", "vertex_color.frag");
}//--------------------------------------------------------------
void ofApp::update(){}//--------------------------------------------------------------
void ofApp::draw(){shader.begin();quad.draw();shader.end();}//--------------------------------------------------------------
void ofApp::keyPressed(int key){}//--------------------------------------------------------------
void ofApp::keyReleased(int key){}//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){}//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){}//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){}//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){}//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){}//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){}//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){}//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){}//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){}
main.cpp
#include "ofMain.h"
#include "ofApp.h"//========================================================================
int main() {ofGLWindowSettings glSettings;glSettings.setSize(1024, 768); //was 748 verticalglSettings.windowMode = OF_WINDOW;glSettings.setGLVersion(4, 1);ofCreateWindow(glSettings);printf("%s\n", glGetString(GL_VERSION));ofRunApp(new ofApp());}
vertex_color.vert
#version 410// 布局限定符:指定顶点属性的输入位置
layout(location = 0) in vec3 position;  // 位置属性
layout(location = 1) in vec4 color;     // 颜色属性// 输出变量:传递给片元着色器
out vec4 vertex_color;  // 将颜色传递给下一阶段void main()
{// 变换顶点位置gl_Position = vec4(position, 1.0);// 传递颜色数据vertex_color = color;
}
vertex_color.frag
#version 410// 输入变量:接收来自顶点着色器的数据
in vec4 vertex_color;  // 插值后的颜色// 输出变量:最终像素颜色
out vec4 output_color;void main()
{// 直接使用插值后的颜色output_color = vertex_color;
}

http://www.dtcms.com/a/339241.html

相关文章:

  • 【工作笔记】VMware安装 - 安装程序检测到主机启用了Hyper-V或Device/Credential Guard……提示解决方法
  • 在CentOS系统中查询已删除但仍占用磁盘空间的文件
  • 深入解析:Unity、Unreal Engine与Godot引擎中的Uniform变量管理
  • 【CV 图像分割】①——目标分割介绍
  • 网络编程day4
  • 牛客面经 - 2025/8/19
  • C++高频知识点(二十八)
  • 数据库-MYSQL配置下载
  • 前端性能优化实战手册:从网络到运行时,一套可复制落地的清单
  • 基于提示词工程和MCP构建垂直Agent应用
  • Go语言中的优雅并发控制:通道信号量模式详解
  • JS 中的 this
  • AI-调查研究-55-机器人 百年进化史:从Unimate到人形智能体的技术跃迁
  • Navicat 使用超详细教程:从下载到实战案例
  • Vue.prototype 的作用
  • AJAX (一)
  • 【深度学习-pytorch】mnist数字识别
  • Java 大视界 -- Java 大数据机器学习模型在自然语言处理中的多语言翻译与文化适应性优化
  • go.uber.org/zap 日志库高性能写入
  • 结合BI多维度异常分析(日期-> 商家/渠道->日期(商家/渠道))
  • 常见BI工具
  • 变电站智能辅助监控系统:结构框架、功能模块及配套设备指南
  • 【国内电子数据取证厂商龙信科技】Python数据分析环境搭建
  • 科技云报到:AI推理破局,金融服务如何“逆天改命”
  • JavaWeb开发笔记合集
  • 工厂MES管理系统的五大核心应用场景
  • 功能上新:燕千云ITSM如何让高频重复问题自动总结推送
  • Cursor+Apifox MCP Server接口自动化新范式探索
  • 二分法专题训练
  • 基础分类决策树