3.10[A]cv

核心模块

  • rasterizer:光栅化器,负责三角形遍历和像素绘制
  • Shader:包含顶点着色器和多种片元着色器
  • Texture:纹理处理模块

顶点着色器的计算量一般远小于片元着色器。因为组成三角形的顶点相对有限,而片元需要基于顶点组成的三角形进行插值。

比如,一个100 * 100大小的矩形平面,有四个顶点,计算四次,但是片元着色器需要计算10000次。

也比较简单,模型自带了法线。注意,法线取值范围[-1, 1],需要映射到[0,1],再转换到[0, 255]

网格数据遍历与三角形构建

  • 外层循环for(auto mesh:Loader.LoadedMeshes)遍历模型的所有网格(Mesh),每个网格代表一个独立几何体(如物体的一个部件)

内层循环for(int i=0; ... i+=3)以步长3遍历顶点,将每三个顶点组成一个三角形面片(每个三角形由3个顶点构成)

该代码段是3D模型加载的核心逻辑,它将.obj模型文件中存储的顶点、法线、纹理坐标等原始数据转换为渲染管线可处理的三角形对象集合。这些数据为后续的MVP矩阵变换、光照计算(依赖法线)、纹理贴图(依赖纹理坐标)提供了输入基础

**newtri**

  • 这是经过MVP矩阵变换​(Model-View-Projection)和视口变换后的三角形对象,其顶点坐标已处于屏幕空间
  • 包含以下处理后的属性:
    • 顶点坐标:通过MVP矩阵变换和齐次除法后,再经过视口变换映射到屏幕坐标系

法线向量:通过逆变换矩阵将模型空间法线转换到视图空间,用于后续光照计算

*viewspace_pos**

  • 表示三角形顶点在视图空间(观察空间)​ 中的坐标,即经过 view * model 变换后的位置。
  • 用于光照计算中的视线方向计算(如Phong着色中的镜面反射分量)

光照模拟机制
通过修改模型表面的法线方向,改变光线反射角度,使平面在渲染时呈现凹凸、划痕等细节效果。例如:

  • 当光线照射到法线贴图标记的“凹陷”区域时,法线方向改变导致阴影和高光位置变化,从而欺骗人眼感知

双线性插值作用于片段着色器阶段的纹理采样过程。当纹理坐标(u,v)为浮点数时(非整数像素中心坐标),需通过插值计算颜色值

光照函数

每个函数的实现步骤大致如下:

  1. phong_fragment_shader:遍历光源,计算环境、漫反射、高光,累加结果。
  2. texture_fragment_shader:采样纹理颜色作为kd,其余同phong。
  3. bump_fragment_shader:计算TBN矩阵,扰动法线,更新法线后计算光照。
  4. displacement_fragment_shader:调整顶点位置,更新法线,再计算光照。

Blinn-Phong模型由环境光、漫反射和高光组成,其中高光部分使用半程向量(halfway vector)来计算。环境光是简单的常数乘以光强,漫反射是法线方向与光线方向的点积,而高光则是半程向量与法线的点积的幂次方。我需要遍历所有光源,计算每个光源的这三个分量,并累加到结果颜色中。要注意归一化各个向量,例如光线方向、视线方向和半程向量。

texture_fragment_shader,需要在Blinn-Phong的基础上将纹理颜色作为漫反射系数kd。

实现

void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos) 
{// 获取三角形顶点坐标(屏幕空间)auto v = t.toVector4();// 计算包围盒边界(网页1、网页4)float min_x = std::min(v[0].x(), std::min(v[1].x(), v[2].x()));float max_x = std::max(v[0].x(), std::max(v[1].x(), v[2].x()));float min_y = std::min(v[0].y(), std::min(v[1].y(), v[2].y()));float max_y = std::max(v[0].y(), std::max(v[1].y(), v[2].y()));// 转换为整数像素范围(网页4)int x_min = std::floor(min_x);int x_max = std::ceil(max_x);int y_min = std::floor(min_y);int y_max = std::ceil(max_y);// 遍历包围盒内所有像素(网页4)for (int x = x_min; x <= x_max; ++x) {for (int y = y_min; y <= y_max; ++y) {// 检查像素中心是否在三角形内(网页3)if (insideTriangle(x + 0.5, y + 0.5, t.v)) {// 计算重心坐标(网页1)auto [alpha, beta, gamma] = computeBarycentric2D(x + 0.5, y + 0.5, t.v);// 深度插值计算(网页1、网页4)float Z = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());float zp = alpha * v[0].z()/v[0].w() + beta * v[1].z()/v[1].w() + gamma * v[2].z()/v[2].w();zp *= Z;// 深度测试(网页4)if (zp < depth_buf[get_index(x, y)]) {// 更新深度缓冲区depth_buf[get_index(x, y)] = zp;// 属性插值(网页1、网页2)auto interpolated_color = interpolate(alpha, beta, gamma, t.color[0], t.color[1], t.color[2], 1.0f);auto interpolated_normal = interpolate(alpha, beta, gamma,t.normal[0], t.normal[1], t.normal[2], 1.0f).normalized();auto interpolated_texcoords = interpolate(alpha, beta, gamma,t.tex_coords[0], t.tex_coords[1], t.tex_coords[2], 1.0f);auto interpolated_shadingcoords = interpolate(alpha, beta, gamma,view_pos[0], view_pos[1], view_pos[2], 1.0f);// 构造着色器输入(网页1)fragment_shader_payload payload(interpolated_color,interpolated_normal,interpolated_texcoords,texture ? &*texture : nullptr);payload.view_pos = interpolated_shadingcoords;// 调用片段着色器(网页2)Eigen::Vector3f pixel_color = fragment_shader(payload);// 写入像素颜色(网页4)set_pixel(Eigen::Vector2i(x, y), pixel_color);}}}}
}

图形渲染管线

 

处理逻辑

在shader当中,是在shader.hpp中定义了片着色器的payload,然后在渲染的时候,是把插值后的属性传递给Payload,再把payload传递给一开始定义的r.set_fragment_shader(active_shader);

    for(auto mesh:Loader.LoadedMeshes){for(int i=0;i<mesh.Vertices.size();i+=3){Triangle* t = new Triangle();for(int j=0;j<3;j++){t->setVertex(j,Vector4f(mesh.Vertices[i+j].Position.X,mesh.Vertices[i+j].Position.Y,mesh.Vertices[i+j].Position.Z,1.0));t->setNormal(j,Vector3f(mesh.Vertices[i+j].Normal.X,mesh.Vertices[i+j].Normal.Y,mesh.Vertices[i+j].Normal.Z));t->setTexCoord(j,Vector2f(mesh.Vertices[i+j].TextureCoordinate.X, mesh.Vertices[i+j].TextureCoordinate.Y));}TriangleList.push_back(t);}}

是在一开始读取模型的时候,就按照网面设置好了三角形,并把三角形装进TriangleList中了,然后在最后绘制的时候,就是去绘制这个三角形

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

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

相关文章

mac使用Homebrew安装miniconda(mac搭建python环境),并在IDEA中集成miniconda环境

一、安装Homebrew mac安装brew 二、使用Homebrew安装miniconda brew search condabrew install miniconda安装完成后的截图&#xff1a; # 查看是否安装成功 brew list环境变量&#xff08;无需手动配置&#xff09; 先执行命令看能不能正常返回&#xff0c;如果不能正常…

多视图几何--相机标定--从0-1理解张正友标定法

1基本原理 1.1 单应性矩阵&#xff08;Homography&#xff09;的建立 相机模型&#xff1a;世界坐标系下棋盘格平面&#xff08;Z0&#xff09;到图像平面的投影关系为&#xff1a; s [ u v 1 ] K [ r 1 r 2 t ] [ X Y 1 ] s \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} K…

WWDG窗口看门狗原理

WWDG&#xff08;窗口看门狗&#xff09;在窗口期喂狗 作用&#xff1a; 原理&#xff1a; 框图 WWDG寄存器&#xff1a; WWDG_CR控制寄存器 WWDG_CFR配置寄存器 状态寄存器WWDG_SR 超时时间计算公式 最小最大超时值 HAL配置函数&#xff1a; 1. IWDG 和 WWDG 的区别 IWDG&…

无公网IP也能远程控制Windows:Linux rdesktop内网穿透实战

文章目录 前言1. Windows 开启远程桌面2. Linux安装rdesktop工具3. Win安装Cpolar工具4. 配置远程桌面地址5. 远程桌面连接测试6. 设置固定远程地址7. 固定地址连接测试 前言 如今远程办公已经从一种选择变成了许多企业和个人的必修课&#xff0c;而如何在Linux系统上高效地访…

Pygame实现射击鸭子游戏3-2

2 鸭子类Target的创建 2.1 __init__()函数 Target类的__init__()函数代码如图5所示。 图5 __init__()函数代码 其中&#xff0c;第18行将Target类声明为pygame.sprite.Sprite类的子类&#xff1b;第19行代码中&#xff0c;__init__()函数的img_path参数表示鸭子图片的文件名…

利用Java爬虫获取衣联网商品详情:实战指南

在电商领域&#xff0c;获取商品详情是数据分析和市场研究的重要环节。衣联网作为知名的电商平台&#xff0c;提供了丰富的服装商品资源。本文将详细介绍如何利用Java编写爬虫程序&#xff0c;通过商品ID获取衣联网商品详情。 一、准备工作 &#xff08;一&#xff09;环境搭…

五、OpenGL中Shader与C++数据传输

文章目录 一、概述二、Shader 代码文件的基本格式三、Shader的向量语法介绍四、Shader之间的数据传输五、Shader与C的数据传输uniform六、完整示例 一、概述 在 OpenGL 中&#xff0c;Shader&#xff08;着色器&#xff09;使用 GLSL&#xff08;OpenGL Shading Language&…

【3DMAX插件】3DMAX建筑大师插件MasterBuilder使用方法

3DMAX建筑大师插件是一款专为3DMAX设计的程序化&#xff08;参数化&#xff09;建筑建模工具&#xff0c;其最大特点是能够一键生成建筑模型&#xff0c;极大地提升了工作效率。该插件配备了多种结构控制选项&#xff0c;涵盖阳台、门窗、栏杆、楼顶水塔等附属建筑元素&#xf…

隐私保护在 Facebook 用户身份验证中的应用

在这个数字化的时代&#xff0c;个人隐私保护成为了公众关注的焦点。社交媒体巨头 Facebook 作为全球最大的社交平台之一&#xff0c;拥有数十亿用户&#xff0c;其在用户身份验证过程中对隐私保护的重视程度直接影响着用户的安全感和信任度。本文将探讨 Facebook 在用户身份验…

Swift Package Manager (SPM) 创建并集成本地库

在macOS 项目中&#xff0c;使用 Swift Package Manager (SPM) 创建并集成本地库的完整步骤。 创建一个macos应用程序&#xff0c;选择 swift、oc、swiftui都可以。 创建好应用之后&#xff0c;开始创建SPM本地库。 打开终端app&#xff0c;进入项目根目录&#xff0c;逐次输…

渗透测试之利用sql拿shell(附完整流程+防御方案)【下】

导读: 时刻保持谦逊,始终保持学习,探寻事物的本质,不要把事情复杂化 话不多说,书接上回 三、利用日志getshell 利用条件: 拥有网站的写入权限知道网站的绝对路径数据库日志开启 实际操作: (1)查看数据库日志是否开启以及路径 show variables like %general%; (2…

LeetCode 热题 100_每日温度(72_739_中等_C++)(栈)(暴力破解;栈(从左到右);栈(从右到左))

LeetCode 热题 100_每日温度&#xff08;72_739&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;暴力破解法(双重循环)&#xff09;&#xff1a;思路二&#xff08;栈&#xff1a;从左到右&#xff09;&…

【HarmonyOS Next之旅】DevEco Studio使用指南(二)

目录 1 -> 工程模板介绍 2 -> 创建一个新的工程 2.1 -> 创建和配置新工程 2.1.1 -> 创建HarmonyOS工程 2.2.2 -> 创建OpenHarmony工程 1 -> 工程模板介绍 DevEco Studio支持多种品类的应用/元服务开发&#xff0c;预置丰富的工程模板&#xff0c;可以根…

unity3d 背景是桌面3d数字人,前面是web的表单

是可以实现的&#xff0c;但涉及多个技术栈的结合&#xff0c;包括 Unity3D、Web 技术&#xff08;HTML、JavaScript&#xff09;、以及可能的 WebGL 或 WebRTC 技术。大致有以下几种实现方案&#xff1a; 方案 1&#xff1a;Unity 作为独立应用&#xff08;桌面端&#xff0…

猫耳大型活动提效——组件低代码化

1. 引言 猫耳前端在开发活动的过程中&#xff0c;经历过传统的 pro code 阶段&#xff0c;即活动页面完全由前端开发编码实现&#xff0c;直到 2020 年接入公司内部的低代码活动平台&#xff0c;满足了大部分日常活动的需求&#xff0c;运营可自主配置活动并上线&#xff0c;释…

深度学习系列79:Text2sql调研

参考 https://github.com/topics/text-to-sql 这里是一些资源&#xff1a;https://github.com/eosphoros-ai/Awesome-Text2SQL/blob/main/README.zh.md 这里是综述文章&#xff1a;https://zhuanlan.zhihu.com/p/647249972 1. 数据集 Spider: 一个跨域的复杂text2sql数据集&a…

Linux 系统负载过高的排查思路

技术探讨&#xff1a;Linux系统负载过高的排查思路 在Linux服务器运行过程中&#xff0c;如果系统负载过高&#xff0c;可能会导致性能下降和服务不稳定。以下是针对Linux系统负载过高问题的排查思路和解决方法&#xff1a; 1. 查看系统负载&#xff1a; 使用uptime或top命令查…

【互联网性能指标】QPS/TPS/PV/UV/IP/GMV/DAU/MAU/RPS

&#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》&#xff08;基础篇&#xff09;、&#xff08;进阶篇&#xff09;、&#xff08;架构篇&#xff09;清华大学出版社签约作家、Java领域优质创作者、CSDN博客专家、…

linux---天气爬虫

代码概述 这段代码实现了一个天气查询系统&#xff0c;支持实时天气、未来天气和历史天气查询。用户可以通过终端菜单选择查询类型&#xff0c;并输入城市名称来获取相应的天气信息。程序通过 TCP 连接发送 HTTP 请求&#xff0c;并解析返回的 JSON 数据来展示天气信息。 #in…

Java高频面试之集合-08

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;详细说说CopyOnWriteArrayList CopyOnWriteArrayList 详解 CopyOnWriteArrayList 是 Java 并发包&#xff08;java.util…