头歌实践教学平台:投影变换v2.0

news2024/11/25 12:32:59

第2关:两点透视

一. 任务描述

1. 本关任务

(1) 理解透视投影变换的方法; (2) 将main函数中的空白部分补充完整。

2. 输入

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

test

(2) 代码自动将模型投影到二维平面中心生成一个边长为1的绿色立方体;

(3) 改变模型位置,产生两点透视: 将绿色立方体顶点分别沿y轴逆时针旋转45度,向y轴正方向平移1.2个单位,绘制一个红色立方体。再将红色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个红色立方体。最后对三个红立方体进行投影变换,变换矩阵Projection已给出;

(4) 改变视点与模型位置,产生两点透视(先模型变换再观察变换): 首先将立绿色方体的顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个绿色立方体。然后对三个绿色立方体分别进行观察变换,将参数eye沿y轴顺时针旋转45度作为相机坐标,中心点坐标为center,向上矢量为Vec3f(0, 1, 0)。最后对三个绿立方体进行投影变换,变换矩阵Projection已给出;

(5) 改变视点与模型位置,产生两点透视(先观察变换再模型变换): 首先对绿色立方体分别进行观察变换,将参数eye沿y轴顺时针旋转45度作为相机坐标,中心点坐标为center,向上矢量为Vec3f(0, 1, 0)。将绿色立方体向y轴负方向平移1.2个单位,绘制一个黄色立方体。再将黄色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个黄色立方体。最后对三个黄立方体进行投影变换,变换矩阵Projection已给出。

3. 输出

具体结果如下图所示:

test

二. 相关知识

1. 透视投影

透视投影相关知识点,请参考教材与课件或有关资料。

三. 操作说明

(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);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

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);

	Model *model = NULL;
	const int width = 800;
	const int height = 800;
	const int depth = 255;


	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");

	Vec3f eye(0, 0, 4);
	Vec3f center(0, 0, 0);
	Matrix ModelView = Matrix::identity(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++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);

			Matrix S0 = scale(0.4, 0.4, 0.4);
			Vec3f swp0 = S0 * wp0;
			Vec3f swp1 = S0 * wp1;
            float fx[3]={-1.2,0,1.2};
            // Please add the code here
            /********** Begin ********/
            


            //绿色
            Vec3f eye_xz= rotation_y(-45)*eye ;
            Matrix ModelView4 = lookat(eye_xz, center, Vec3f(0, 1, 0)); //视图变换矩阵
            Matrix Projection4 = projection(eye_xz, center);
            for(int i=0;i<3;i++){
                Matrix T4 = translation(Vec3f( fx[i],0, 0));
                Vec3f tr40 = ViewPort * Projection4 * ModelView4 * T4 *swp0;
                Vec3f tr41 = ViewPort * Projection4 * ModelView4 * T4 *swp1;
                line(tr40,tr41, image, green);//绿色

                Matrix R3 =rotation_y(45);//沿y轴逆时针旋转45度
                Matrix T3y =translation(Vec3f (fx[i],1.2,0));//向y轴正方向平移1.2个单位
                Vec3f tr30= ViewPort * Projection * T3y * R3 * swp0;
                Vec3f tr31= ViewPort * Projection * T3y * R3 * swp1;
                line(tr30,tr31, image, red);//红色

                Matrix T5y =translation(Vec3f (fx[i],-1.2,0));//向y轴负方向平移1.2个单位
                Vec3f tr50 = ViewPort * Projection4 * T5y *ModelView4 *swp0;
                Vec3f tr51 = ViewPort * Projection4 * T5y* ModelView4 *swp1;
                line(tr50,tr51, image, yellow);//黄色

            }

            
            



			
            /********** End ********/
		}
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step2/test.png");
	delete model;
	return 0;
}

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

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

相关文章

【MySQL | 第十篇】重新认识MySQL索引匹配过程

文章目录 10.重新认识MySQL索引匹配过程10.1匹配规则10.2举例&#xff1a;联合索引遇到范围查询&#xff08;>、<、between、like&#xff09;10.2.1例子一&#xff1a;>10.2.2例子二&#xff1a;>10.2.3例子三&#xff1a;between10.2.4例子四&#xff1a;like 10…

每日OJ题_DFS爆搜深搜回溯剪枝⑧_力扣980. 不同路径 III

目录 力扣980. 不同路径 III 解析代码 力扣980. 不同路径 III 980. 不同路径 III 难度 困难 在二维网格 grid 上&#xff0c;有 4 种类型的方格&#xff1a; 1 表示起始方格。且只有一个起始方格。2 表示结束方格&#xff0c;且只有一个结束方格。0 表示我们可以走过的空…

eclipse开启服务后,网页无法打开,如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

java发送请求2次开发-get请求json

因为你请求参数不为空&#xff0c;接口都会把这个参数带上 所以借鉴HttpPost类 继承这个类&#xff0c; 这个类是可以带消息的 httpgetwithentity&#xff0c;httpget请求带上消息 复写 构造方法复制过来进行使用 二次开发类让其get请求时可以发送json

U-boot 编译

引入 在嵌入式系统开发中&#xff0c;U-Boot 作为一个开源的引导加载程序&#xff08;bootloader&#xff09;&#xff0c;扮演着至关重要的角色。它负责在系统启动时初始化硬件&#xff0c;加载并启动操作系统。本文将详细介绍如何从 U-Boot 的源码开始&#xff0c;编译生成适…

【树 图论 阶乘 组合 深度优先搜索】1916. 统计为蚁群构筑房间的不同顺序

本文设计知识点 树 图论 阶乘 组合 深度优先搜索 图论知识汇总 LeetCoce1916. 统计为蚁群构筑房间的不同顺序 你是一只蚂蚁&#xff0c;负责为蚁群构筑 n 间编号从 0 到 n-1 的新房间。给你一个 下标从 0 开始 且长度为 n 的整数数组 prevRoom 作为扩建计划。其中&#xff0…

聊聊持续测试

这是鼎叔的第九十六篇原创文章。行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。 本人新书《无测试组织-测试团队的敏捷转型》已出版&#xff08;机械工业出版社&#xff09;。 如果在测试部门只能推行一个技术建设项目&#xff0c;那鼎叔就会选择“持续测试”。 持续测…

【论文阅读笔记】Frequency Perception Network for Camouflaged Object Detection

1.论文介绍 Frequency Perception Network for Camouflaged Object Detection 基于频率感知网络的视频目标检测 2023年 ACM MM Paper Code 2.摘要 隐蔽目标检测&#xff08;COD&#xff09;的目的是准确地检测隐藏在周围环境中的目标。然而&#xff0c;现有的COD方法主要定位…

UI-Diffuser——使用生成式扩散模型的UI原型设计算法解析

概述。 移动UI是影响参与度的一个重要因素&#xff0c;例如用户对应用的熟悉程度和使用的便利性。如果你有一个类似的应用程序&#xff0c;你可能会选择一个具有现代、好看的设计的应用程序&#xff0c;而不是一个旧的设计。然而&#xff0c;要从头开始研究什么样的UI最适合应…

数据的表示和运算试题

01&#xff0e;若十进制数为137.5&#xff0c;则其八进制数为(). A.89.8 B.211.4 C.211.5 D.1011111.101 02.一个16位无符号二进制数的表示范围是()。 A. 0&#xff5e;65536 B.0~65535 c. -32768~32767 D.-32768~32768 03.下列说法有误的是( ). A.任何二进制整数都可以用十进…

若依框架详细使用教程

目录 若依简介 若依使用 搭建后端 搭建前端 若依的使用 若依简介 RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|开源后台系统|RuoYi|RuoYi-Vue|RuoYi-Cloud|RuoYi框架|RuoYi开源|RuoYi视频|若依视频|Ruo…

golang判断通道chan是否关闭的2种方式

chan通道在go语言的办法编程中使用频繁&#xff0c;我们可以通过以下2种方式来判断channel通道是否已经关闭&#xff0c;1是使用 for range循环&#xff0c;另外是通过 for循环中if 简短语句的 逗号 ok 模式来判断。 示例代码如下&#xff1a; //方式1 通过for range形式判断…

ZooKeeper知识点总结及分布式锁实现

最初接触ZooKeeper是之前的一个公司的微服务项目中&#xff0c;涉及到Dubbo和ZooKeeper&#xff0c;ZooKeeper作为微服务的注册和配置中心。好了&#xff0c;开始介绍ZooKeeper了。 目录 1.ZooKeeper的基本概念 2.ZooKeeper的节点&#xff08;ZNode&#xff09; 3. ZooKeep…

基于MSOGI的交叉对消谐波信号提取网络MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介&#xff1a; 此模型利用二阶广义积分器&#xff08;SOGI&#xff09;对基波电流和相应次的谐波电流进行取 &#xff0c;具体是通过多个基于二阶广义积分器的正交信号发生器 &#xff08; S&#xf…

基于Vue Router和element-ui的LayOut

一、展示 二、代码 app.vue <template><div id"app"><el-container style"border: 1px solid #eee; height: 100vh"><el-aside v-bind:width"asideWidth" style"background-color: rgb(48, 65, 86);"><…

【数据结构】这样学习串的朴素模式匹配算法,简直不要太容易……

串的朴素模式匹配算法 导读一、串的模式匹配1.1 模式匹配是什么&#xff1f;1.2 为什么要有模式匹配算法&#xff1f; 二、朴素模式匹配算法2.1 算法底层逻辑2.2 算法实现2.2.1 过程解析2.2.2 思路分析2.2.3 思路总结2.2.4 代码编写数据类型函数的三要素函数主体 2.2.5 代码测试…

【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解

一、线程概念 线程是进程的一个执行分支&#xff0c;是在进程内部运行的一个执行流。下面将从是什么、为什么、怎么办三个角度来解释线程。 1、什么是线程 上面是一张用户级页表&#xff0c;我们都知道可执行程序在磁盘中无非就是代码或数据&#xff0c;更准确点表述&#xff0…

python从0开始学习

目录 前言 1、print函数 2、input函数 3、保留字和标识符 总结 前言 本篇文章我们开辟一个新的学习模块&#xff1a;python。python是一个十分简洁实用的编程语言&#xff0c;我们将从0开始学习python 1、print函数 print(*args, sep , end\n, fileNone, flushFalse) pytho…

高手的黑箱:AI时代学习、思考与创作

课程目录 01 不要错过这个时代的巨大红利&#xff0c;AI时代竞争力养成指南.mp4 02 解密高手的黑箱——那些创作高手不告诉你的事.mp4 03 创作&#xff1a;人生发展中最重要的事.mp4 04 创作中最重要的事&#xff08;1&#xff09;&#xff1a;对过程的掌控力.mp4 05 创作…

FIFO Generate IP核使用——FIFO写操作详解及Status Flags页配置

本文介绍了FIFO的写操作及Status Flags页的配置信息。 1 FIFO 写入操作 当FIFO的写入使能&#xff08;write enable&#xff09;被置位&#xff0c;并且FIFO未满时&#xff0c;数据会从输入总线&#xff08;din&#xff09;被添加到FIFO中&#xff0c;并且写入确认&#xff0…