头歌实践教学平台:CG7-v2.0-实体消隐

第1关:立方体消隐

一. 任务描述

1. 本关任务

(1) 理解深度缓冲器算法(Z-Buffer)算法; (2) 将triangle函数和main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 代码会自动对将立方体进行模型变换、观察变换和投影变换; (3) 若代码填写正确,程序会对由立方体顶点生成的三角形面片triangleVertex1和triangleVertex2消隐,对应生成不同颜色的立方体面。其中代码中已给出颜色,在const PNGColor clr[6]中保存。

3. 输出

具体结果如下图所示:

test

二. 相关知识

1. 深度缓冲器(Z-Buffer)算法

如果我们先绘制一个距离较近的物体,在绘制距离较远的物体,则距离较远的位图因为后绘制,会把距离近的物体覆盖掉,如下面图片中先绘制红色再绘制黄色,那么红色图片就被覆盖掉了。有了深度缓冲区后,在绘制的时候只需要判断像素点的Z值(深度值),深度值大的(距离远)被覆盖,那么绘制物体的顺序就不那么重要了。实际上,只要存在深度缓冲区,都会把像素的深度值写入到缓冲区中。 如图,假定xoy面为投影面,z轴为观察方向,过屏幕上任意像素点(x,y)作平行于z轴的射线R,与物体表面相交于p1和p2点,p1和p2点的z值称为该点的深度值。

,

z-buffer算法比较p1和p 2的z值, 将最大的z值存入z缓冲器中显然,p1在p 前面,屏幕上(x,y)这一点将显示p1点的颜色 算法思想:先将Z缓冲器中各单元的初始值置为最小值。当要改变某个像素的颜色值时,首先检查当前多边形的深度值是否大于该像素原来的深度值(保存在该像素所对应的Z缓冲器的单元中)如果大于原来的z值,说明当前多边形更靠近观察点,用它的颜色替换像素原来的颜色。

2. P点z值计算

对于P点的z值,可以通过重心坐标来计算:我们把P点z值也可以看成三角形顶A,B,C的重心坐标的一个线性组合,即: P.z = A.z*a + B.z*b + C.z*c, 其中A,B,C为三角形顶点, a,b,c为重心坐标。 其实不仅仅是P点的z,对于P点的任意性质,只要是我们觉得可以用线性组合来看的,我们都可以用这个重心坐标来计算。

三. 操作说明

(1) 按要求补全代码; (2) 点击窗口右下角"测评"按钮,等待测评结果,如果通过后可进行下一关任务。

开始你的任务吧,祝你成功!

四.实验代码

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"using namespace std;
const double PI = acos(-1.0);void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{bool steep = false;if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y)){std::swap(p0.x, p0.y);std::swap(p1.x, p1.y);steep = true;}if (p0.x > p1.x){std::swap(p0.x, p1.x);std::swap(p0.y, p1.y);}int dx = p1.x - p0.x;int dy = std::abs(p1.y - p0.y);int y = p0.y;int d = -dx;for (int x = p0.x; x <= p1.x; x++){if (steep)image.set(y, x, color);elseimage.set(x, y, color);d = d + 2 * dy;if (d > 0){y += (p1.y > p0.y ? 1 : -1);d = d - 2 * dx;}}
}Vec3f barycentric(Vec3f *pts, Vec3f P)
{  //返回值是Vec3f(-1, 1, 1),如果z 分量不等于1则说明P点不在三角形内。//返回值是Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z),P点在pts三角形区域内。Vec3f u = Vec3f(pts[2].x - pts[0].x, pts[1].x - pts[0].x, pts[0].x - P.x) ^Vec3f(pts[2].y - pts[0].y, pts[1].y - pts[0].y, pts[0].y - P.y);/* `pts` and `P` has integer value as coordinatesso `abs(u[2])` < 1 means `u[2]` is 0, that meanstriangle is degenerate, in this case return something with negative coordinates */if (std::abs(u.z) < 1)return Vec3f(-1, 1, 1);return Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
}void triangle(Vec3f *pts, float *zbuffer, PNGImage &image, PNGColor color)
{//对每一个pts代表的三角形区域进行计算,更新zbuffer的值。如果zbuffer的值更新了,就得用color值对该点作色int minX = min({ pts[0].x, pts[1].x, pts[2].x });int maxX = max({ pts[0].x, pts[1].x, pts[2].x });int minY = min({ pts[0].y, pts[1].y, pts[2].y });int maxY = max({ pts[0].y, pts[1].y, pts[2].y });int width = image.get_width();int height = image.get_height();if (maxX >= width)maxX = width - 1;if (maxY >= height)maxY = height - 1;//P代表三角形区域的“包围盒区域”内的所有点,是以minX、maxX、minY、maxY控制的“长方形区域”内的所有点。该区域可以作色为三角形区域pts的颜色,也可以不变。不变是因为无深度值更新,即可能是背景色,也可能是其它三角形区域比当前三角形区域深度值大保持以前三角形区域的颜色。Vec3f P;for (P.x = minX; P.x <= maxX; P.x++) {for (P.y = minY; P.y <= maxY; P.y++) {Vec3f bc_screen = barycentric(pts, P);//bs_screen表示pts三角形区域重心坐标。if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0) continue;P.z = 0;for (int i = 0; i < 3; i++)// 请补充代码,计算P点的深度坐标z/********** Begin ********/P.z += pts[i].z * bc_screen[i];//P.z = A.z*a + B.z*b + C.z*c,/********** End **********/if (zbuffer[int(P.x + P.y*width)] < P.z) {/********** Begin ********/zbuffer[int(P.x + P.y*width)] = P.z;  image.set(P.x, P.y, color);/********** End **********/}}}
}Matrix projection(Vec3f eye, Vec3f center)
{Matrix m = Matrix::identity(4);m[3][2] = -1.f / (eye - center).norm();return m;
}Matrix viewport(int x, int y, int w, int h, int depth) {Matrix m = Matrix::identity(4);m[0][3] = x + w / 2.f;m[1][3] = y + h / 2.f;m[2][3] = depth / 2.f;m[0][0] = w / 2.f;m[1][1] = h / 2.f;m[2][2] = depth / 2.f;return m;
}Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {Vec3f z = (eye - center).normalize();Vec3f x = (up^z).normalize();Vec3f y = (z^x).normalize();Matrix res = Matrix::identity(4);for (int i = 0; i < 3; i++) {res[0][i] = x[i];res[1][i] = y[i];res[2][i] = z[i];res[i][3] = -center[i];}return res;
}Matrix translation(Vec3f v) {Matrix Tr = Matrix::identity(4);Tr[0][3] = v.x;Tr[1][3] = v.y;Tr[2][3] = v.z;return Tr;
}Matrix scale(float factorX, float factorY, float factorZ)
{Matrix Z = Matrix::identity(4);Z[0][0] = factorX;Z[1][1] = factorY;Z[2][2] = factorZ;return Z;
}Matrix rotation_x(float angle)
{angle = angle * PI / 180;float sinangle = sin(angle);float cosangle = cos(angle);Matrix R = Matrix::identity(4);R[1][1] = R[2][2] = cosangle;R[1][2] = -sinangle;R[2][1] = sinangle;return R;
}Matrix rotation_y(float angle)
{angle = angle * PI / 180;float sinangle = sin(angle);float cosangle = cos(angle);Matrix R = Matrix::identity(4);R[0][0] = R[2][2] = cosangle;R[0][2] = sinangle;R[2][0] = -sinangle;return R;
}Matrix rotation_z(float angle) {angle = angle * PI / 180;float sinangle = sin(angle);float cosangle = cos(angle);Matrix R = Matrix::identity(4);R[0][0] = R[1][1] = cosangle;R[0][1] = -sinangle;R[1][0] = sinangle;return R;
}int main(int argc, char** argv)
{const PNGColor white = PNGColor(255, 255, 255, 255);const PNGColor black = PNGColor(0, 0, 0, 255);const PNGColor red = PNGColor(255, 0, 0, 255);const PNGColor green = PNGColor(0, 255, 0, 255);const PNGColor blue = PNGColor(0, 0, 255, 255);const PNGColor yellow = PNGColor(255, 255, 0, 255);const PNGColor orange = PNGColor(255, 128, 0, 255);const PNGColor clr[6] = {green, yellow, blue, red, white, orange};Model *model = NULL;const int width = 800;const int height = 800;const int depth = 255;//generate some imagePNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encodeimage.init(black);model = new Model("cube.obj");float *zbuffer = new float[width*height];for (int i = 0; i < width * height; i++)zbuffer[i] = -numeric_limits<float>::max();Vec3f eye(0, 1.2, 4),center(0, 0, 0), up(0, 1, 0);Matrix ModelView = lookat(eye, center, up) * rotation_y(45) * scale(0.4, 0.4, 0.4);Matrix Projection = projection(eye, center);Matrix ViewPort = viewport(width / 4, width / 4, width / 2, height / 2, depth);for (int i = 0; i < model->nfaces(); i++){//对模型的每个面进行计算vector<int> face = model->face(i);if ((int)face.size() == 4){//模型的每个面都是4个点构成,就进行下面的计算Vec3f triangleVertex1[3], triangleVertex2[3];for (int j = 0; j < 3; j++){//每个四边形“分割”成2个三角形区域triangleVertex1和triangleVertex2//v1是triangleVertex1上的3个点之一,循环控制//v2是triangleVertex2上的3个点之一,循环控制Vec3f v1 = model->vert(face[j]);Vec3f v2 = model->vert(face[(j + 2) % 4]);triangleVertex1[j] = ViewPort * Projection * ModelView * v1;// 请补充代码,完成triangleVertex2[j]的计算/********** Begin ********/triangleVertex2[j] = ViewPort * Projection * ModelView * v2;/********** End **********/}// 请将triangle函数补充完整/********** Begin ********/			triangle(triangleVertex1,zbuffer , image,clr[i]);triangle(triangleVertex2, zbuffer, image,clr[i]);/********** End **********/}}image.flip_vertically(); // i want to have the origin at the left bottom corner of the imageimage.write_png_file("../img_step3/test.png");delete model;delete zbuffer;return 0;
}

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

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

相关文章

Kafka Exactly Once 语义实现原理:幂等性与事务消息

01 前言 在现代分布式系统中&#xff0c;确保数据处理的准确性和一致性是至关重要的。Apache Kafka&#xff0c;作为一个广泛使用的流处理平台&#xff0c;提供了强大的消息队列和流处理功能。随着业务需求的增长&#xff0c;Kafka 的事务消息功能应运而生&#xff0c;它允许应…

单链表的经典oj题(1)

前言 这次博客将要以图解的形式&#xff0c;把单链表的经典题目&#xff0c;讲解&#xff0c;绝对是干货&#xff0c;来吧兄弟萌 第一题 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 …

USB HID报告描述符学习

参考资料 HID 报告描述符 (qq.com)https://mp.weixin.qq.com/s?__bizMzU1ODI3MzQ1MA&mid2247485748&idx1&sn112bd8014eb96b03308b3b808549e8d4&chksmfc284ff1cb5fc6e770c2d2ece46c17bf2529901b45a357938978fa62163723556ad497b05c47&cur_album_id3340417…

三、VLAN间路由(三层交换)

VLAN间路由可以通过二层交换机配合路由器来实现&#xff0c;也可以通过三层交换机来实现。 目录 1.单臂路由 2.通过三层交换机实现不同vlan的互访 1.单臂路由 注&#xff1a; 1.三层接口不能正确识别带vlan tag的数据帧 2.所有子接口与主接口共享MAC地址 命令 int g0/0/0.1…

试用了三个Ai音乐工具,我的偶像河图要完蛋了

试了三个生成音乐的ai工具&#xff0c;分别是爆火的suno,后期新秀udio&#xff0c;还有我们国内的天工。 先说感受&#xff0c;suno和天工我觉得稍微靠前&#xff0c;udio可能我的配置风格有问题&#xff0c;啪啪啪连选了好几个风格&#xff0c;生成的东西有点怪。 我随手写了…

语音识别的基本概念

语音识别的基本概念​​​​​​​ ​​​​​​​ 言语是一种复杂的现象。人们很少了解它是如何产生和感知的。天真的想法常常是语音是由单词构成的&#xff0c;而每个单词又由音素组成。不幸的是&#xff0c;现实却大不相同。语音是一个动态过程&#xff0c;没有明确区分的…

linux学习:线程安全(信号量+互斥锁读写锁+条件变量+可重入函数)

目录 信号量 有名信号量 步骤 api 创建、打开一个POSIX有名信号量 对 POSIX 有名信号量进行 P、V 操作 关闭、删除 POSIX 有名信号量 例子 无名信号量 步骤 api 初始化、销毁 POSIX 无名信号量 互斥锁读写锁 例子 两条线程 使用互斥锁来互斥地访问标准输出 在加锁…

1.认识USB协议

目录 前言 在嵌入式场景的具体体现 USB通信协议 总结 前言 在这之前&#xff0c;我们需要认识USB是什么东西&#xff0c;它是一种通信协议&#xff0c;协议只是规定数据的&#xff0c;在物理层面上&#xff0c;它可以有多种表现形式。在我们日常生活中也非常常见&#xff0…

FebHost:什么是挪威.no域名,如何注册?

挪威国家域名介绍 挪威是一个位于北欧的国家&#xff0c;北面和西面是大西洋和北海&#xff0c;东面和南面则与瑞典、芬兰接壤。挪威是一个高度发达的经济体&#xff0c;其政府在经济管理和可持续发展方面也取得了很多成就。挪威的人均GDP在世界范围内排名非常靠前&#xff0c…

【Unity】 使用代码分析(Roslyn Analyzers)实现自动代码审查(Code Review)

索引 Roslyn AnalyzersCode Review自动 Code Review 案例1.public、internal权限的字段建议以大写字母开头。2.private、protected权限的字段建议以下划线小写字母开头。3.不建议直接继承 MonoBehaviour&#xff0c;建议继承至 HTBehaviour。4.不建议使用 Input 判断输入或获取…

命令执行。

命令执行 在该项目的readme中&#xff0c;描述了怎么去调用的flink 通过java原生的runtime来调用flink&#xff0c;下一步就是去看看具体的调用过程了&#xff0c;是否存在可控的参数 找到具体提交命令的类方法CommandRpcClinetAdapterImpl#submitJob() 这里要确定command&am…

C++-6

使用模板类&#xff0c;实现顺序栈。 #include <iostream>using namespace std; template <typename T> class Seqlite {T data[30];int len0; public:void head_inst(T date);void head_dele();void show(); }; template <typename T> …

Phi-3-mini-4k-instruct 的功能测试

Model card 介绍 Phi-3-Mini-4K-Instruct 是一个 3.8B 参数、轻量级、最先进的开放模型&#xff0c;使用 Phi-3 数据集进行训练&#xff0c;其中包括合成数据和经过过滤的公开可用网站数据&#xff0c;重点是 高品质和推理密集的属性。 该型号属于 Phi-3 系列&#xff0c;Mini…

Django框架之ORM操作

一、选择数据库 1、默认数据库 Django默认的数据库是sqlite3数据库 DATABASES {default: {ENGINE: django.db.backends.sqlite3,NAME: BASE_DIR / db.sqlite3,} }2、指定数据库 修改连接到MySQL数据库 DATABASES {default: {ENGINE: django.db.backends.mysql,# 数据库名…

一、安装Redis并运行

Windows安装Redis 1.打开网址下载 下载地址&#xff1a;https://github.com/tporadowski/redis/releases。 Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择 我选择的是 然后一步步安装 可以参考&#xff1a;https://blog.csdn.net/zbx931197485/article/d…

李廉洋:4.29黄金原油最新走势分析,做单必看策略,

传统定价框架下&#xff0c;黄金兼具货币、商品和金融三重属性&#xff0c;对应货币、抗通胀和避险价值&#xff0c;因此通常与美元、美债利率反向变动。但近期这一定价规律“失灵”了&#xff0c;黄金、利率和美元同涨。三者同涨后&#xff0c;一个月后续转为下跌的频率超过一…

JS - 以工厂模式和原型模式方式建造对象、JS的垃级回收机制、数组的使用

创建对象的方式 使用工厂方法来建造对象 在JS中我们可以通过以下方式进行创建对象&#xff1a; var obj {name:"孙悟空",age:18,gender:"男",sayName:function(){alert(this.name);}};var obj2 {name:"猪八戒",age:28,gender:"男",…

【Java EE】总结12种锁策略以及synchronized的实现原理

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

基于yolov5实时实例分割

是一个结合了最新技术进展&#xff08;State-of-the-Art, SOTA&#xff09;的实时实例分割项目&#xff0c;基于著名的YOLOv5目标检测架构&#xff0c;并对其进行扩展以实现对图像中每个对象实例的精确像素级分割。以下是该项目的中文介绍&#xff1a; YOLOv5&#xff1a; YOL…

Java后端利用百度地图全球逆地理编码,获取地址

声明&#xff1a;本人是在实习项目的时候遇到的问题 一.使用Api分为四步骤全球逆地理编码 rgc 反geo检索 | 百度地图API SDK 步骤1,2自行完成 接下来去获取AK 二.申请AK 登录百度账号 点击创建应用&#xff0c;选择自己想用的服务&#xff0c;我只单选了逆地理编码&#xff…