第三章:光效果产生立体感

         本文是《从0开始图形学》笔记的第三章,上一章中我们已经将箱子的整个形状“找出来”了,但是还仅仅只是一个色块区域。这一节我们就利用光将整个箱子的立体感凸显出来。涉及到布林冯光照模型以及向量的点乘运算。

概念解说

        这里需要用到“布林冯”光照模型,该模型中将物体上反射出来光照分为三类:

        (1)环境光,来自环境周围的光照,不分方向,一般设置成固定值,其视觉感受就像在没有月光的野外看山的样子,只有一个大概的轮廓,如下图所示;

        (2)漫反射光,由入射光线在物体表面向各个方向(当然也包括相机方向)漫反射的光线,其强度和表面法向量及入射光线的夹角大小成反比,漫反射是让渲染立体化最重要的一个元素,如下图所示;

        (3)镜面反射光,由入射光线在物体表面的镜面反射光线产生,其强度和反射光线及眼睛接收光线的夹角大小成反比,如下图所示。

数学计算

        这其中就涉及到以下几个数学计算的问题

        (1)三角面的法向量的计算,使用上一节提到的叉乘即可获取;

        (2)向量之间的夹角计算,需要使用向量的另外一种乘法--向量点乘,简单的说,向量的点乘结果是一个值,同时该结果又有其几何意义。

        例如,向量A为[x1, y1, z1],向量B为[x2, y2, z2],那么其点乘结果为x1*x2+y1*y2+z1*z2,同时这个结果代表着几何意义,也可以表示为|A|*|B|*cosα(即两个向量模的成绩再乘上其夹角的cos值),所以cosα=(x1*x2+y1*y2+z1*z2)/(|A|*|B|);

        (3)三角面片中任意一个坐标[x, y]的对应z值的计算,同样使用向量叉乘原理,将计算点和三角面片中的任意一个顶点连接,其构成的向量和三角面片的法向量叉乘结果为0;

        (4)在计算镜面反射的时候,为计算方便,我们将“镜面反射光线和相机视线的夹角计算”转变成“相机视线和入射光线夹角平分线向量和三角面片法向量的夹角计算”,其数学结果是等效的,但是计算方便很多。这里涉及到两个向量夹角平分线向量的计算,还是以向量A为[x1, y1, z1],向量B为[x2, y2, z2]为例,假设A和B都是单位向量(即长度为1,非单位向量可先将其单位化),那么其夹角平分线的向量即为[x1+x2, y1+y2, z1+z2],夹角计算的画使用向量点乘即可解决。

C核心代码实现

        知道了上面的计算过程,代码上实现也就比较简单了

        首先,定义一个点光源的位置和颜色,定义环境光,漫反射光,镜面反射光的系数。这里还需要先将箱子面片的数据顺序做一个调整,原因下一节会讲到。

const char _backColor[3] = {0, 0, 0};               // 结果图的背景颜色
float _lightSourcePos[3] = { 550, 290, -500 };      // 光源位置
unsigned char _lightColor[3] = { 255, 255, 255 };   // 光源颜色
float _kA = 0.1, _kD = 0.4, _kS = 0.5;              // 环境光、漫反射光、镜面反射光系数int _planes[12][3] =      // 面的数据,12个3角形
{{4, 5, 6},{6, 7, 4},{1, 5, 6},{6, 2, 1},{0, 1, 5},{5, 4, 0},{3, 2, 6},{6, 7, 3},{0, 4, 7},{7, 3, 0},{0, 1, 2},     // 每个面3个角的顶点对应于索引值{2, 3, 0},
};

        为方便做向量的计算,我们封装几个相关的小函数,分别计算向量点乘,求向量模长度,向量单位化

float PointMultiply(float* v1, float* v2)
{return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}float LengthOfVector(float* v)
{return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}void NormalVector(float* v)
{float a = LengthOfVector(v);v[0] /= a;v[1] /= a;v[2] /= a;
}

        最后,就是在上一节的基础上,把画三角面片的代码从填颜色块改成填光影效果

// 求得三角面片中对应于[x,y]坐标的z值,原理是根据互相垂直的两个向量点乘为0
float vTmp[3] = { x - _points[_planes[i][0]][0], y - _points[_planes[i][0]][1], 0 };
float z = (0 - vTmp[0] * normalOfPlane[0] - vTmp[1] * normalOfPlane[1]) / normalOfPlane[2] + _points[_planes[i][0]][2];
// 叠加【环境光】
lightRst = _kA;
// 叠加【漫反射光】
float vToLight[3] = {_lightSourcePos[0] - x, _lightSourcePos[1] - y, _lightSourcePos[2] - z}; // 当前点指向光源的向量
float cosLightAndNormal = PointMultiply(vToLight, normalOfPlane) / (LengthOfVector(vToLight) * LengthOfVector(normalOfPlane));if (cosLightAndNormal < 0) cosLightAndNormal = -cosLightAndNormal;lightRst += _kD * cosLightAndNormal;
// 叠加【镜面反射光】
float vEyeLight[3] = {0, 0, -z}; // 摄像机视线向量
NormalVector(vEyeLight);
NormalVector(vToLight);
float vSeperate[3] = { vEyeLight[0] + vToLight[0], vEyeLight[1] + vToLight[1], vEyeLight[2] + vToLight[2] };
float cosSeperateAndNormal = PointMultiply(vEyeLight, vToLight) / (LengthOfVector(vEyeLight) * LengthOfVector(vToLight));if (cosSeperateAndNormal < 0)
{cosSeperateAndNormal = 0;
}cosSeperateAndNormal = pow(cosSeperateAndNormal, 128);
lightRst += _kS * cosSeperateAndNormal;
//
_rstImage[y][x][0] = _lightColor[0] * lightRst;
_rstImage[y][x][1] = _lightColor[1] * lightRst;
_rstImage[y][x][2] = _lightColor[2] * lightRst;

渲染结果

        最终结果就是上面3张图的叠加效果,如下图所示

完整代码见开头的资源下载,或百度网盘

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

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

相关文章

C语言函数(三):数组和函数实现扫雷游戏

目录 1.扫雷游戏的分析和设计1.1.扫雷游戏的功能说明1.2.游戏的分析与设计1.2.1 数据结构的分析1.2.2 文件结构设计 2.扫雷游戏的代码实现 1.扫雷游戏的分析和设计 1.1.扫雷游戏的功能说明 使用控制台实现经典的扫雷游戏游戏可以通过菜单实现继续玩游戏或者退出游戏扫雷的棋盘…

网课:数独挑战——牛客(题解与疑问)

题目描述 数独是一种填数字游戏&#xff0c;英文名叫 Sudoku&#xff0c;起源于瑞士&#xff0c;上世纪 70 年代由美国一家数学逻辑游戏杂志首先发表&#xff0c;名为 Number Place&#xff0c;后在日本流行&#xff0c;1984 年将 Sudoku 命名为数独&#xff0c;即 “独立的数…

刘谦春晚纸牌魔术背后的数学—海明码原理简介

在昨天2024年的春晚舞台上&#xff0c;魔术大师刘谦以一场令人拍案叫绝的纸牌魔术再度震撼全场。他巧妙地利用了数学原理&#xff0c;精准无误地让观众“随机”选择的纸牌完成了配对&#xff0c;尤其是令人忍俊不禁的是主持人尼格买提的纸牌却没有如愿配对&#xff0c;小尼碎了…

机器学习复习(8)——逻辑回归

目录 逻辑函数&#xff08;Logistic Function&#xff09; 逻辑回归模型的假设函数 从逻辑回归模型转换到最大似然函数过程 最大似然函数方法 梯度下降 逻辑函数&#xff08;Logistic Function&#xff09; 首先&#xff0c;逻辑函数&#xff0c;也称为Sigmoid函数&#…

安全之护网(HVV)、红蓝对抗

文章目录 红蓝对抗什么是护网行动&#xff1f;护网分类护网的时间 什么是红蓝对抗红蓝对抗演练的目的什么是企业红蓝对抗红蓝对抗价值参考 红蓝对抗 什么是护网行动&#xff1f; 护网的定义是以国家组织组织事业单位、国企单位、名企单位等开展攻防两方的网络安全演习。进攻方…

C++ 贪心 区间问题 区间选点

给定 N 个闭区间 [ai,bi] &#xff0c;请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数 N &#xff0c;表示区间数。 接下来 N 行&#xff0c;每行包含两…

洛谷p4391 无限传输

考察字符串周期的题 题目链接 结论 要求字串 s s s的最短循环字串长就是&#xff1a; a n s n − p m t [ n ] ansn-pmt[n] ansn−pmt[n] 证明如下&#xff1a; 这是最大的前缀和后缀 现在我们做如下操作&#xff1a; 补全字段 a a a和字段 b b b&#xff0c;按子段 a a a的…

Linux操作系统基础(五):Linux的目录结构

文章目录 Linux的目录结构 一、Linux目录与Windows目录区别 二、常见目录介绍&#xff08;记住重点&#xff09; Linux的目录结构 一、Linux目录与Windows目录区别 Linux的目录结构是一个树型结构 Windows 系统 可以拥有多个盘符, 如 C盘、D盘、E盘 Linux 没有盘符 这个概…

AJAX——AJAX入门

1 什么是AJAX&#xff1f; Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种用于在Web应用程序中实现异步通信的技术。 简单点说&#xff0c;就是使用XMLHttpRequest对象与服务器通信。它可以使用JSON、XML、HTML和test文本等格式发送和接收数据。 AJAX最吸…

机器学习系列——(十一)回归

引言 在机器学习领域&#xff0c;回归是一种常见的监督学习任务&#xff0c;它主要用于预测数值型目标变量。回归分析能够通过对输入特征与目标变量之间的关系建模&#xff0c;从而对未知数据做出预测。 概念 回归是机器学习中的一种监督学习方法&#xff0c;用于预测数值型目…

一个坐标系查询网站python获取所有坐标系

技术路线选择 我是使用的vue 3开发的网页界面&#xff0c;element-plus构建网页组件&#xff0c;openlayer展示地图&#xff0c;express提供后端API&#xff0c;vercel进行在线部署。 python获取所有坐标系 想要展示所有坐标系&#xff0c;那需要先获取坐标系&#xff0c;怎么…

Openwifi 开源项目解读(一)

Openwifi 是一个关于wifi 系统的开源项目&#xff0c;是一个少有的优秀的关于wifi的开源项目&#xff0c;项目中包括了wifi的基带、lowmac、linux驱动 等三部分&#xff0c;其中基带、lowmac部分是在FPGA中实现&#xff0c;wifi驱动部分是运行在Linux下&#xff0c;因此openwif…

【资料分享】基于单片机大气压监测报警系统电路方案设计、基于飞思卡尔的无人坚守点滴监控自动控制系统设计(程序,原理图,pcb,文档)

基于单片机大气压监测报警系统电路方案设计 功能&#xff1a;实现的是大气压检测报警系统&#xff0c;可以通过传感器实时检测当前大气压值&#xff0c;可以设定大气压正常范围&#xff0c;当超过设定范围进行报警提示。 资料&#xff1a;protues仿真&#xff0c;程序&#x…

【教学类-47-01】UIBOT+IDM下载儿童古诗+修改文件名

背景需求&#xff1a; 去年12月&#xff0c;我去了其他幼儿园参观&#xff0c;这是一个传统文化德育教育特色的学校&#xff0c;在“古典集市”展示活动中&#xff0c;小班中班大班孩子共同现场念诵《元日》《静夜思》包含了演唱版本和儿歌念诵版本。 我马上也要当班主任了&a…

C++ 贪心 区间问题 最大不相交区间数

给定 N 个闭区间 [ai,bi] &#xff0c;请你在数轴上选择若干区间&#xff0c;使得选中的区间之间互不相交&#xff08;包括端点&#xff09;。 输出可选取区间的最大数量。 输入格式 第一行包含整数 N &#xff0c;表示区间数。 接下来 N 行&#xff0c;每行包含两个整数 ai…

基于鲲鹏服务NodeJs安装

准备工作 查看当前环境 uname -a查看鲲鹏云CPU架构 cat /proc/cpuinfo# 查看CPU architecture项&#xff0c;8表示v8&#xff0c;7表示v7下载Node.js NodeJs 选择 Linux Binaries (ARM) ARMv8 wget -c https://nodejs.org/dist/v12.18.3/node-v12.18.3-linux-arm64.tar.xz…

WWW 万维网

万维网概述 万维网 WWW (World Wide Web) 并非某种特殊的计算机网络。 万维网是一个大规模的、联机式的信息储藏所。 万维网用链接的方法能非常方便地从互联网上的一个站点访问另一个站点&#xff0c;从而主动地按需获取丰富的信息。 这种访问方式称为“链接”。 万维网是分…

【Kubernetes】在k8s1.24及以上版本基于containerd容器运行时测试pod从harbor拉取镜像

基于containerd容器运行时测试pod从harbor拉取镜像 1、安装高版本containerd2、安装docker3、登录harbor上传镜像4、从harbor拉取镜像 1、安装高版本containerd 集群中各个节点都要操作 yum remove containerd.io -y yum install containerd.io-1.6.22* -y cd /etc/containe…

Docker 有哪些常见的用途?

Docker 是一种容器化技术&#xff0c;它允许应用程序在不同的环境之间具有一致的运行环境。这使得 Docker 在开发和运维领域中非常受欢迎&#xff0c;因为它简化了应用程序的部署和管理。以下是 Docker 的一些常见用途&#xff1a; 快速部署应用程序 Docker 允许开发人员和运…

[NSSCTF]-Web:[SWPUCTF 2021 新生赛]easy_sql解析

查看网页 有提示&#xff0c;参数是wllm&#xff0c;并且要我们输入点东西 所以&#xff0c;我们尝试以get方式传入 有回显&#xff0c;但似乎没啥用 从上图看应该是字符型漏洞&#xff0c;单引号字符注入 先查看字段数 /?wllm2order by 3-- 没回显 报错了&#xff0c;说明…