头歌实践教学平台:CG3-v2.0-图形几何变换

第1关:平移、缩放、旋转正方体

一. 任务描述

1. 本关任务

(1) 理解几何变换基本原理, 掌握平移、旋转、缩放变换的方法; (2) 根据平移算法原理补全translation、scale、rotation_x、rotation_y和rotation_z函数; (3) 根据几何变换基本原理,将main函数中的translation、scale、rotation_z参数补充完整。

2. 输入

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

test

(2) 代码自动将模型投影到二维平面上生成一个边长为1的白色正方形,并且代码会生成红色x轴,绿色y轴,具体图片如下所示:

test

(3) 将立方体的顶点坐标分别向x,y,z轴正方向平移0.5个单位距离,然后绘制一个红色正方形; (4) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个绿色正方形; (5) 将立方体的顶点坐标沿z轴逆时针方向旋转45度,然后绘制一个黄色正方形。

3. 输出

具体结果如下图所示:

test

二. 相关知识

几何变换:指对图形的几何信息经过平移、缩放、旋转等变换后产生的新图形。

1. 平移变换

平移变换:将某个点P(x,y,z)通过平移距离tx​ty​tz​加到P的坐标上平移到P′(x′,y′,z′)

写成矩阵的形式就是:

2. 缩放变换

缩放变换:是指点相对于坐标原点沿x、y和z方向分别放缩sx​sy​sz​倍,变换的齐次坐标计算形式如下:

3. 旋转变换

空间绕z轴旋转θ时,物体x、y坐标改变,而z坐标值在该变换中不改变,即

空间绕x轴旋转θ时,物体y、z坐标改变,而x坐标值在该变换中不改变,即

空间绕y轴旋转θ时,物体x、z坐标改变,而y坐标值在该变换中不改变,即

三. 操作说明

(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 viewport(int x, int y, int w, int h, int depth) {
	 //x,y是白色矩形(初始矩形)左下角点坐标值
    //w,h是白色矩形宽度和高度
    //depth是观察点位置(眼睛位置)
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;//m矩阵代表的图形绘制的坐标系,该值为坐标原点(红色线x轴、绿色线y轴交点)在世界坐标系(即OpenGL图形绘制窗口)的坐标x值
	m[1][3] = y + h / 2.f;//世界坐标系下原点y坐标值
	m[2][3] = depth / 2.f;//世界坐标系下原点z坐标值

	m[0][0] = w / 2.f;//延x轴缩放w/2=125倍
	m[1][1] = h / 2.f;//延y轴缩放h/2=125倍
	m[2][2] = depth / 2.f;//延z轴缩放depth/2=127倍
    /*
    125     0       0       250
    0       125     0       250
    0       0       127     127
    0       0       0       1  
    */
	return m;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
    // Please add the code here
    /********** Begin ********/
    Tr[0][3]=v.x;
    Tr[1][3]=v.y;
    Tr[2][3]=v.z;
    /********** End *********/
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
    /********** Begin ********/
    Z[0][0]=factorX;
    Z[1][1]=factorY;
    Z[2][2]=factorZ;

    /********** End *********/
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
	Matrix R = Matrix::identity(4);
    /********** Begin ********/
    R[1][1]=R[2][2]=cosangle;
    R[1][2]=-sinangle;
    R[2][1]=sinangle;

    /********** End *********/
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
    /********** Begin ********/
    R[0][0]=R[2][2]=cosangle;
    R[2][0]=-sinangle;
    R[0][2]=sinangle;

    /********** End *********/
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
    /********** Begin ********/
    R[0][0]=R[1][1]=cosangle;
    R[1][0]=sinangle;
    R[0][1]=-sinangle;

    /********** End *********/
	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 = 500;
	const int height = 500;
	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("../step3/cube.obj");
	Matrix VP = viewport(width / 4, width / 4, width / 2, height / 2, depth);
    /*
    125     0       0       250
    0       125     0       250
    0       0       127     127
    0       0       0       1  
    */

	{ // draw the axes画坐标,x轴红色,y轴绿色
		Vec3f x(1.f, 0.f, 0.f), y(0.f, 1.f, 0.f), o(0.f, 0.f, 0.f);//这个值是“相对值”,x方向的1,代表刻录125.
		o = VP*o;//(250,250,127,1)齐次坐标
		x = VP*x;//(375,250,127,1)齐次坐标
		y = VP*y;//(250,375,127,1)齐次坐标
		line(o, x, image, red);
		line(o, y, image, green);
	}

	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()]);
            //wp0,wp1是物体坐标,wp0,wp1是构成绘制图形的基本点坐标值
            //比如白色矩形框左下角点wp0齐次坐标是(-1,-1,1,1)
            //与VP相乘后得到(125,125,254,1)代表在绘图窗口的实际坐标
            //所以,可以认为循环语句产生所有用来绘制直线的端点的物体坐标,物体坐标坐标值1对应实际坐标的值125

			// draw the original model
			Vec3f op0 = VP*wp0;//物体坐标系和世界坐标系的关联矩阵VP,物体坐标系下物体关键点坐标wp0,两者相乘,可以算处关键点在世界坐标系下的坐标值。
			Vec3f op1 = VP*wp1;
			line(op0, op1, image, white);

			// draw the translated model
            // Please add the code here
            /********** Begin ********/
			Matrix T = translation(Vec3f(0.5  ,0.5   ,0.5   ));
            /********** End *********/
			Vec3f tp0 = VP*T*wp0;
			Vec3f tp1 = VP*T*wp1;
			line(tp0, tp1, image, red);

			// draw the scaled model
            // Please add the code here
            /********** Begin ********/            
			Matrix S = scale(0.5  ,0.5  ,0.5  );
            /********** End *********/
			Vec3f sp0 = VP*S*wp0;
			Vec3f sp1 = VP*S*wp1;
			line(sp0, sp1, image, green);

			// draw the rotated model
            // Please add the code here
            /********** Begin ********/   
			Matrix R = rotation_z(45 );
            /********** End *********/
			Vec3f rp0 = VP*R*wp0;
			Vec3f rp1 = VP*R*wp1;
			line(rp0, rp1, image, yellow);
		}
	}
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step3/test.png");
	delete model;
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RK3568 学习笔记 : Linux emmc 内核启动 rootfs 根文件系统无法正常挂载问题的分析

问题描述 平台 &#xff1a; NanoPi-R5C 开发板 RK3568 平台。 手动编译的 Linux 内核&#xff0c;结果发现大概率 emmc 无法正常初始化&#xff0c;导致 rootfs 根文件系统无法正常挂载 Linux 内核版本&#xff1a; 6.1 Linux 内核代码位置&#xff1a; https://github.com…

上网行为监控软件有哪些(上网审计软件)【收藏】

上网行为监控软件&#xff08;也被称为上网审计软件&#xff09;正逐渐成为企业信息安全管理的必备工具。 没错&#xff01; 这些软件通过对员工的上网行为进行全面、细致的监控和审计&#xff0c;帮助企业提升工作效率、保护数据安全&#xff0c;并规范员工的网络使用行为。 …

Springboot+vue项目健身房课程预约平台

开发语言&#xff1a;Java 开发工具:IDEA /Eclipse 数据库:MYSQL5.7 应用服务:Tomcat7/Tomcat8 使用框架:springbootvue JDK版本&#xff1a;jdk1.8 本系统主要实现了首页、个人中心、用户管理、教练管理、会员卡管理、购买会员管理、课程类型管理、课程信息管理、课程购买…

生信新包|LINGER·从单细胞多组学数据推断基因调控网络

题目&#xff1a;Inferring gene regulatory networks from single-cell multiome data using atlas-scale external data 原理 LINGER 是一个计算框架&#xff0c;旨在从单细胞多组学数据推断基因调控网络。 使用基因表达和染色质可及性的计数矩阵以及细胞类型注释作为输入&…

Linux下创建达梦数据库自动备份任务

分享一个自己用的银河麒麟下达梦数据库自动备份任务脚本。 达梦数据库备份脚本。按日期备份&#xff0c;备份后压缩为tar.gz文件&#xff0c;自动清理导出的文件。 备份脚本保留最后30天记录&#xff0c;以节省硬盘空间&#xff0c;可根据具体情况修改。 达梦数据库备份脚本 …

​​​【收录 Hello 算法】第 4 章 数组与链表

第 4 章 数组与链表 数据结构的世界如同一堵厚实的砖墙。 数组的砖块整齐排列&#xff0c;逐个紧贴。链表的砖块分散各处&#xff0c;连接的藤蔓自由地穿梭于砖缝之间。 本章内容 4.1 数组4.2 链表4.3 列表4.4 内存与缓存 *4.5 小结

解决github无法克隆私有仓库,Repository not found问题(2024最新)

一、背景 这个问题出现&#xff0c;是你用了其他主机设备&#xff0c;需要重新clone私有库时&#xff0c;发现一直报找不到仓库&#xff0c;如下报错&#xff1a; remote: Repository not found.二、解决方法 &#xff08;1&#xff09;账号密码方式&#xff08;已不支持&am…

CSDN上是不是有机器人点赞和收藏?

我在CSDN上写作&#xff0c;主要是本来是记录学习工作中的一些知识点&#xff0c;看得人不多本来就能预想到的。 但是今天发现五一写的一篇博客&#xff0c;出现了很奇怪的阅读、点赞、收藏数。只有2个人阅读&#xff0c;但是有8个点赞&#xff0c;还有5个收藏。 我不禁怀疑CS…

怎么扫描二维码看图片?在线制作图片二维码的方法

随着现在二维码的广泛使用&#xff0c;用这个方式来展现内容的情况越来越多&#xff0c;比如扫码看图就是一种很常见的一种类型。将图片生成二维码后通过扫码来调取云端存储的图片查看&#xff0c;这样可以一次预览多张图片并且不会占据内存&#xff0c;能够快速的实现图片内容…

Flutter笔记:Widgets Easier组件库(11)- 使用提示吐丝(Tip Toasts)

Flutter笔记 Widgets Easier组件库&#xff08;11&#xff09;使用提示吐丝 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this …

C++之QT文本处理QDir、QFileDialog、QStringList、QFile

一、相应的头文件 #include <QFileDialog> #include <QDir> #include <QStringList> 二、简介 1.QFileDialog 实际效果如下&#xff1a;比如需要选择打开的文件夹或者文件名&#xff0c;通过调用资源管理器的方式进行可视化操作。 代码示例为&#xff1a…

xss漏洞简介

漏洞简介 跨站脚本&#xff08;Cross-site scripting ,简称 XSS&#xff09;是一种经常出现在Web应用程序中的计算机安全漏洞&#xff0c;是由于web应用程序对用户的输入过滤不足而产生的&#xff0c;是代码注入的一种&#xff0c;XSS就是攻击者利用网站漏洞把恶意脚本代码&am…

4.5_shell的执行流控制

##1.for语句## &#xff08;1&#xff09;for语句作用 为循环执行动作 &#xff08;2&#xff09;for语句结构 for 定义变量 do 使用变量&#xff0c;执行动作 done 结束标志 &#xff08;3&#xff09;for语句的基本格式 格式1 格式1&#xff1a;#!/b…

flask框架的初步认识

flask框架的初步认识 这是一个轻量级的网页框架&#xff0c;在运行后&#xff0c;就相当于服务器&#xff0c;当用户输入URL就会触发对应的事件调用方法&#xff0c;返回给用户一个网页文件&#xff0c;并通过自动识别html标签&#xff0c;来为用户呈现对应的样式和效果&#…

日本极致产品力 |累计销量超100亿盒的酸奶品牌怎样炼成的?

明治保加利亚式酸奶是日本的国民酸奶&#xff0c;在日本每人每年要消费4盒。如此热销的大单品是如何塑造的呢? 日本酸奶的关键变革期 明治保加利亚式酸奶在开创之前&#xff0c;正处于产业关键变革时期。自可尔必思1919年在日本推出第一款乳酸菌饮料以来&#xff0c;明治、森…

Ansible-Playbook——部署LNMP架构

目录 环境准备 一、配置Nginx的Roles角色 1.创建Nginx所需的文件夹 2.编写Nginx配置文件 3.编写Nginx安装文件 4.编写Nginx控制器文件 5.编写Nginx任务文件 6.编写Nginx变量文件 二、配置Mysql的Roles角色 1.创建Mysql所需的文件夹 2.编写Mysql启动文件 3.编写Mysql…

高性价比开放式耳机有哪些?五大好评热卖开放式耳机推荐

近年来&#xff0c;开放式耳机凭借其独特的开放式声学设计&#xff0c;给用户带来了动态空间的音质享受。在佩戴等方面也带来了一定的舒适度。然而&#xff0c;面对满目的耳机品牌&#xff0c;新手小白往往会不知道如何挑选。那如何选择一款适合自己的产品呢&#xff1f;我整理…

瑞麦德机电设备有限公司将莅临2024第13届生物发酵展

参展企业介绍 河南瑞麦德机电设备有限公司是专业从事机械输送气力输送、称重配料、筛分、磁选设备研发和制造于一体的企业&#xff0c;公司采用国内外同行业产品的先进技术&#xff0c;经专业团队设计、研发、生产&#xff0c;产品满足“ISO9001”&#xff0c;“GMP”等标准要求…

【爬虫】爬取A股数据写入数据库(二)

前几天有写过一篇 【爬虫】爬取A股数据写入数据库&#xff08;一&#xff09;&#xff0c;现在继续完善下&#xff0c;将已有数据通过ORM形式批量写入数据库。 2024/05&#xff0c;本文主要内容如下&#xff1a; 对东方财富官网进行分析&#xff0c;并作数据爬取&#xff0c;使…

MATLAB添加自编写.m文件或.mat数据并永久全局调用方法

菜单栏选择设置路径&#xff0c;然后“添加并包含子文件夹”&#xff0c;在弹出窗口中找到目标文件夹即可。此方案可以永久地将文件夹加入MATLAB路径。 添加包含自编写.m文件的文件夹&#xff1a; 即可实现永久全局调用。
最新文章