tinyrenderer-渲染器着色

整理了代码,创建了一个相机类,控制镜头

class Camera
{
public:Camera(Vec3f cameraPos, Vec3f target, Vec3f up):cameraPos_(cameraPos), target_(target), up_(up) {}Matrix getView();Matrix getProjection();
private:Vec3f cameraPos_;Vec3f target_;Vec3f up_;
};

以及一个专门渲染的Rasterizer类

class Rasterizer
{
public:Rasterizer(Matrix viewport, int width, int height);void setModelView(Matrix modelView) { modelView_ = modelView; }void setProjection(Matrix projection) { projection_ = projection; }void draw(Model* model, IShader& shader, TGAImage& image);Matrix getProjection() { return projection_; }Matrix getModelView() { return modelView_; }
private:void triangle(Vec4f* pts, IShader& shader, TGAImage& image);Matrix viewport_;Matrix modelView_;Matrix projection_;std::vector<float> zBuffer_;int width_;int height_;
};

一个着色器结构,分别处理顶点着色,和片段着色

struct IShader
{virtual Vec3i vertex(int iface, int vertIdx) = 0;virtual bool fragment(Vec3f bar, TGAColor& color) = 0;
};

顶点着色是对模型的三角形顶点进行变换处理
片段是对三角形内部的每个点进行循环插值

void Rasterizer::draw(Model* model, IShader& shader, TGAImage& image) {for (int i = 0; i < model->faceSize(); i++) {Vec4f screencoords[3];for (int j = 0; j < 3; j++) {screencoords[j] = viewport_ * shader.vertex(i, j);}triangle(screencoords, shader, image);}
}void triangle(Vec4f* pts, IShader& shader, TGAImage& image) {//...for (int x = minX; x < maxX; x++) {for (int y = minY; y < maxY; y++) {//...bool discard = shader.fragment(Vec3f(alpha, beta, gamma), color);//...}}
}

在这里插入图片描述
出现了破面,破面问题基本上就是数据精度的误差,应该是更新了新的geometry.h文件,导致一些值的浮点数和整数的选择出现了新的误差
调整了一下
在这里插入图片描述
试了下教程的片段着色器,并且调整了下光源方向
在这里插入图片描述
flat shading

struct FlatShader :public IShader
{Vec3f vert[3];virtual Vec4f vertex(int iface, int vertIdx) {vert[vertIdx] = model->vert(model->face(iface)[vertIdx]);return rasterizer->getProjection() * rasterizer->getModelView() * embed<4>(vert[vertIdx]);}virtual bool fragment(Vec3f barycentricCoordinates, TGAColor& color) {Vec3f n = cross((vert[1] - vert[0]), (vert[2] - vert[0])).normalize();float I = std::max(0.f, n * light_dir);color = TGAColor(255, 255, 255) * I;return false;}
};

在这里插入图片描述
Phong shading

struct PhongShader :public IShader
{Vec3f n[3];virtual Vec4f vertex(int iface, int vertIdx) {n[vertIdx] = model->nverts(model->nface(iface)[vertIdx]);Vec3f v = model->vert(model->face(iface)[vertIdx]);return rasterizer->getProjection() * rasterizer->getModelView() * embed<4>(v);}virtual bool fragment(Vec3f barycentricCoordinates, TGAColor& color) {Vec3f normal = n[0] * barycentricCoordinates.x + n[1] * barycentricCoordinates.y + n[2] * barycentricCoordinates.z;float I = std::max(0.f, normal * light_dir);color = TGAColor(255, 255, 255) * I;return false;}
};

在这里插入图片描述
gouraud 纹理着色

struct GouraudTexShader :public IShader
{Vec3f intensity;mat<2, 3, float> uv;virtual Vec4f vertex(int iface, int vertIdx) {Vec3f n = model->nverts(model->nface(iface)[vertIdx]);intensity[vertIdx] = std::max(0.f, n * light_dir);Vec3f v = model->vert(model->face(iface)[vertIdx]);uv.set_col(vertIdx, model->tverts(model->tface(iface)[vertIdx]));return rasterizer->getProjection() * rasterizer->getModelView() * embed<4>(v);}virtual bool fragment(Vec3f barycentricCoordinates, TGAColor& color) {float I = intensity * barycentricCoordinates;Vec2f texcoords = uv * barycentricCoordinates;color = model->getDiffuseColor(texcoords.x, texcoords.y) * I;return false;}
};

在这里插入图片描述
flat纹理着色

struct FlatTexShader :public IShader
{Vec3f vert[3];mat<2, 3, float> uv;virtual Vec4f vertex(int iface, int vertIdx) {vert[vertIdx] = model->vert(model->face(iface)[vertIdx]);uv.set_col(vertIdx, model->tverts(model->tface(iface)[vertIdx]));return rasterizer->getProjection() * rasterizer->getModelView() * embed<4>(vert[vertIdx]);}virtual bool fragment(Vec3f barycentricCoordinates, TGAColor& color) {Vec3f n = cross((vert[1] - vert[0]), (vert[2] - vert[0])).normalize();float I = std::max(0.f, n * light_dir);Vec2f texcoords = uv * barycentricCoordinates;color = model->getDiffuseColor(texcoords.x, texcoords.y) * I;return false;}
};

在这里插入图片描述
Phong纹理着色

struct PhongTexShader :public IShader
{Vec3f n[3];mat<2, 3, float> uv;virtual Vec4f vertex(int iface, int vertIdx) {n[vertIdx] = model->nverts(model->nface(iface)[vertIdx]);Vec3f v = model->vert(model->face(iface)[vertIdx]);uv.set_col(vertIdx, model->tverts(model->tface(iface)[vertIdx]));return rasterizer->getProjection() * rasterizer->getModelView() * embed<4>(v);}virtual bool fragment(Vec3f barycentricCoordinates, TGAColor& color) {Vec3f normal = n[0] * barycentricCoordinates.x + n[1] * barycentricCoordinates.y + n[2] * barycentricCoordinates.z;float I = std::max(0.f, normal * light_dir);Vec2f texcoords = uv * barycentricCoordinates;color = model->getDiffuseColor(texcoords.x, texcoords.y) * I;return false;}
};

在这里插入图片描述
使用法线贴图shader

struct normalTexShader :public IShader {mat<2, 3, float> uv;virtual Vec4f vertex(int iface, int vertIdx) {Vec3f v = model->vert(model->face(iface)[vertIdx]);uv.set_col(vertIdx, model->tverts(model->tface(iface)[vertIdx]));return rasterizer->getProjection() * rasterizer->getModelView() * embed<4>(v);}virtual bool fragment(Vec3f barycentricCoordinates, TGAColor& color) {Vec2f texcoords = uv * barycentricCoordinates;Vec3f normal = model->getNormal(texcoords.x, texcoords.y);float I = std::max(0.f, normal * light_dir);color = model->getDiffuseColor(texcoords.x, texcoords.y) * I;return false;}
};

在这里插入图片描述
输出图片和教程源码的输出有些不一致
在这里插入图片描述
根据第5节课末尾的内容,假设模型资源里有某个点是(x,y,z,1),这个点对应的向量是(A,B,C,0)。
原本
在这里插入图片描述
如果此时模型的顶点数据经过了一些矩阵变换,可能导致与最初法线贴图记录的法线不再垂直。此时则需要将取出来的法线也做一些矩阵变换,使最终着色时的法线仍与对应顶点垂直
在这里插入图片描述
如图,右边的括号对应的是顶点的变换,则左边对应的是法向量所需的变换
在这里插入图片描述
如图M的逆转置矩阵就是法向量所需的变换
当变换矩阵M是均匀缩放/旋转和平移时,则等于对应的逆转置矩阵,但由于变换矩阵通常包含透视投影,所以一般不相等

struct normalTexShader :public IShader {mat<2, 3, float> uv;Matrix MVPT = (rasterizer->getProjection() * rasterizer->getModelView()).invert_transpose();//....Vec3f n = proj<3>(MVPT * embed<4>(normal)).normalize();float I = std::max(0.f, n * light_dir);//...}
};

在这里插入图片描述
和官方图片还是有误差,对比了下代码发现我的写法和教程源码有两点不同
1.教程的光源方向是对比模型的相对位置,光源方向也做了MVP变换

shader.uniform_M = Projection * ModelView;
Vec3f l = proj<3>(uniform_M * embed<4>(light_dir)).normalize();

我的光源位置是绝对位置
逻辑上都是对的,只是取决与具体需求
另一点不同的是,教程源码的法线取值,rgb对应的是zyx

Vec3f Model::normal(Vec2f uvf) {Vec2i uv(uvf[0]*normalmap_.get_width(), uvf[1]*normalmap_.get_height());TGAColor c = normalmap_.get(uv[0], uv[1]);Vec3f res;for (int i=0; i<3; i++)res[2-i] = (float)c[i]/255.f*2.f - 1.f;return res;
}

我取的法线值,rgb就是对应xyz

Vec3f Model::getNormal(float x, float y) {TGAColor n = normalTex_.get(x * normalTex_.get_width(), y * normalTex_.get_height());Vec3f res;for (int i = 0; i < 3; i++) {res[i] = n[i] / 255.f * 2 - 1.f;}return res;
}

这里为了检查后续的显示正确与否,我也先改成教程的逻辑处理
镜面反射

 Vec3f r = (n * (n * l * 2.f) - l).normalize();float spec = pow(std::max(r.z, 0.0f), model->getSpecularColor(texcoords.x, texcoords.y));float diff = std::max(0.f, n * l);TGAColor c = model->getDiffuseColor(texcoords.x, texcoords.y);color = c;for (int i = 0; i < 3; i++) color[i] = std::min<float>(5 + c[i] * (diff + .6 * spec), 255);

这里教程的逻辑其实比较模糊,没完整的解释光强,反射系数那些布林冯模型公式里的参数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
正常公式里的颜色系数*光强,在教程里是直接自定义了一些值,环境光的是5,漫反射的是1,镜面反射的是0.6.然后公式里的两个cos值就是教程里求出来的diff和spec,镜面反射贴图记录的就是镜面反射公式的指数p
在这里插入图片描述
项目跟随练习代码地址

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

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

相关文章

2024年区块链,物联网与信息技术国际会议(ICBITIT 2024)

2024年区块链&#xff0c;物联网与信息技术国际会议&#xff08;ICBITIT 2024&#xff09; 2024 International Conference on Blockchain, Internet of Things, and Information Technology 会议简介&#xff1a; 2024年区块链&#xff0c;物联网与信息技术国际会议&#xff…

css样式,点击 箭头方向上下转换

实现效果&#xff1a; 点击切换箭头方向 实现代码 <divclass"modelPart"click"showClick"><div class"modelPart_left"><img:srcaidefalutIconclass"sNodeIcon"><div>{{ selectModel }}</div><div …

Scala的简单认识

Scala编程基础 小白的Scala学习笔记 2024/5/21 上午某一时刻 文章目录 Scala编程基础spark是用Scala开发出来的Scala的优点 打开idea 搜索scala&#xff0c;安装 如果不小心点了取消&#xff0c;或者没有上图的提示&#xff0c;就在依赖里面添加 spark是用Scala开发出来的 类比…

英语学习笔记21+23——Which book?/Which glasses?

Which book?/Which glasses? 哪本书&#xff1f;/哪些杯子&#xff1f; 词汇 Vocabulary give v. 给 搭配&#xff1a;Give me five! 击掌庆祝 用法&#xff1a;give 人 东西     give 东西 to 人    把……东西给某人 例句&#xff1a;把这些苹果给 Bobby.   …

元宇宙vr美术虚拟展馆激发更多文化认同和互鉴

科技引领创新潮流&#xff0c;借助前沿的Web3D技术&#xff0c;我们为用户打造了一个沉浸式的纯3D虚拟空间体验平台&#xff1a;元宇宙线上互动展厅。您只需通过网页即可轻松访问这个充满未来感的互动平台。 在这个独特的虚拟环境中&#xff0c;用户可以轻松创建个性化角色&…

缓存三问与缓存预热-如何预防缓存崩溃

一、缓存三剑客 &#xff08;图片来源&#xff1a;什么是缓存雪崩、击穿、穿透&#xff1f; | 小林coding&#xff09; 缓存穿透 (Cache Penetration) 又称"空缓存"指用户请求的数据在缓存和数据库中都不存在,导致每次请求都去查询数据库,给数据库带来巨大压力。解…

【深度学习】【NLP】词表,分词,嵌入

from transformers import AutoTokenizertokenizer AutoTokenizer.from_pretrained("prajjwal1/bert-tiny") tokenizer.save_pretrained("./bert-tiny/")input_string "Your input string here 我是中文" token_ids tokenizer.encode(input_s…

【PID算法详解】

PID算法 PID算法介绍用途pid数学表达式及其含义P算法D算法I算法 PID总结数学公式转换代码设计实际运用PID代码实现 PID算法介绍 PID控制器是一种广泛应用于工业控制系统的反馈控制器&#xff0c;它通过比例&#xff08;Proportional&#xff09;、积分&#xff08;Integral&am…

快写猪好用吗 #知识分享#笔记#学习方法

快写猪是一个非常好用的论文写作工具&#xff0c;它提供了强大的查重降重功能&#xff0c;帮助用户轻松完成论文写作任务。无论是在学术研究还是日常写作中&#xff0c;快写猪都能提供高效、准确的检测&#xff0c;确保文本的原创性和质量。 首先&#xff0c;快写猪的查重降重功…

c 系统宏有多少

在C语言中&#xff0c;系统宏&#xff08;也称为预定义宏或内置宏&#xff09;的数量并不是固定的&#xff0c;因为它们取决于C标准、编译器以及可能的其他因素。然而&#xff0c;有一些常见的预定义宏是几乎所有C编译器都支持的。 以下是一些常见的C预定义宏&#xff1a; __…

利用预测大模型完成办公室饮水机剩余热水量

背景 在每天上班的时候&#xff0c;很多同事都有喝热水的习惯&#xff0c;但是饮水机内的热水量总是比较少的&#xff0c;如何避免等待&#xff0c;高效的接到热水是我接下来要做的事情的动机。 理论基础 在大量真实数据的情况下&#xff0c;可以分析出用水紧张的时间段和用水…

【css3】01-css3新特性样式篇

目录 1 背景 1.1 设置背景图片的定位 1.2 背景裁切-规定背景的绘制区域 1.3 设置背景图片尺寸 2 边框 2.1 盒子阴影box-shadow 2.2 边框图片border-image 3 文本 -文字阴影text-shadow 1 背景 1.1 设置背景图片的定位 background-origin&#xff1a;规定背景图片的定位…

科技守护,河流水文监测保障水资源安全!

中小河流是城乡水资源的补给&#xff0c;又是不可或缺的排放渠道&#xff0c;维系着城乡水资源的平衡与生态的健康。然而&#xff0c;随着工业化、城市化的快速推进&#xff0c;河流生态环境面临着越来越大的压力。为了有效保护和合理利用河流资源&#xff0c;河流水文监测成为…

2024年新算法-红嘴蓝鹊优化器(RBMO)优化BP神经网络回归预测

2024年新算法-红嘴蓝鹊优化器(RBMO)优化BP神经网络回归预测 亮点&#xff1a; 输出多个评价指标&#xff1a;R2&#xff0c;RMSE&#xff0c;MSE&#xff0c;MAPE和MAE 满足需求&#xff0c;分开运行和对比的都有对应的主函数&#xff1a;main_BP, main_RBMO, main_BPvsBP_R…

亡羊补牢,一文讲清各种场景下GIT如何回退

系列文章目录 手把手教你安装Git&#xff0c;萌新迈向专业的必备一步 GIT命令只会抄却不理解&#xff1f;看完原理才能事半功倍&#xff01; 常用GIT命令详解&#xff0c;手把手让你登堂入室 GIT实战篇&#xff0c;教你如何使用GIT可视化工具 GIT使用需知&#xff0c;哪些操作…

区块链的运行原理与演示

目录 前言 具体演示 1、在浏览器中输入区块链演示网址&#xff1a; 2、创建新区块 3、篡改区块信息使其无效 4、新增P2P 网络节点。 5、节点连接。 6、区块信息同步 总结 前言 区块链系统是由一系列分布在全球各地的分布式节点组成的。这些节点互不隶属&#xff0c;通过…

Mesa GL Dispatch分发分析与理解

Mesa GL Dispatch分发分析与理解 引言 这篇博客的核心是从OpenGL应用程序的典型api入手&#xff0c;分析gl api 调用到用户态驱动后端的过程&#xff0c;进而总结出一个典型的调用栈。理解了这个典型调用栈&#xff0c;对后续任何一个API的调用过程分析&#xff0c;都是a piec…

文本匹配.grep与Select-String用法对比

Linux Shell与PowerShell上匹配字符串 grep与Select-String用法对比 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article…

家居厨房安全无小事:可燃气体报警器探头校准检测重要性解析

家居厨房作为日常生活中烹饪美食的重要场所&#xff0c;其安全问题不容忽视。 近年来&#xff0c;随着家庭用气设备的普及&#xff0c;煤气泄露事件时有发生&#xff0c;给人们的生命财产安全带来了严重威胁。 因此&#xff0c;安装可燃气体报警器探头&#xff0c;及时检测并…

Python Orange3库:数据挖掘与机器学习的终极利器

更多Python学习内容&#xff1a;ipengtao.com Orange3是一个开源的数据挖掘和机器学习库&#xff0c;提供了丰富的工具和算法来处理和分析数据。Orange3的图形用户界面使得非编程用户也能轻松进行数据分析&#xff0c;而其Python API则为编程用户提供了强大的灵活性。本文将详细…