【UE4】GAMES101 图形学作业1:mvp 模型、视图、投影变换
总览
- 到目前为止,我们已经学习了如何使用矩阵变换来排列二维或三维空间中的对象。所以现在是时候通过实现一些简单的变换矩阵来获得一些实际经验了。在接下来的三次作业中,我们将要求你去模拟一个基于CPU 的光栅化渲染器的简化版本。
- 本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵。给定三维下三个点v0(2.0, 0.0,−2.0), v1(0.0, 2.0,−2.0), v2(−2.0, 0.0,−2.0), 你需要将这三个点的坐标变换为屏幕坐标并在屏幕上绘制出对应的线框三角形。简而言之,我们需要进行模型、视图、投影、视口等变换来将三角形显示在屏幕上
- get_model_matrix(float rotation_angle)
逐个元素地构建模型变换矩阵并返回该矩阵。在此函数中,你只需要实现三维中绕 z 轴旋转的变换矩阵,而不用处理平移与缩放。 - get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
使用给定的参数逐个元素地构建透视投影矩阵并返回该矩阵。 - 当你在上述函数中正确地构建了模型与投影矩阵,光栅化器会创建一个窗口显示出线框三角形。由于光栅化器是逐帧渲染与绘制的,所以你可以使用A 和D 键去将该三角形绕z 轴旋转
基础与提高
- [5 分] 正确构建模型矩阵。
- [5 分] 正确构建透视投影矩阵。
- [10 分] 你的代码可以在现有框架下正确运行,并能看到变换后的三角形。
- [10 分] 当按A 键与D 键时,三角形能正确旋转。或者正确使用命令行得到旋转结果图像。
- [提高项5 分] 在main.cpp 中构造一个函数,该函数的作用是得到绕任意过原点的轴的旋转变换矩阵。
Eigen::Matrix4f get_rotation(Vector3f axis, float angle)
实现
投影变换矩阵
模型任意轴旋转
代码
创建 AActor 派生类 AActor_Assignmen1
AActor_Assignmen1.h
UCLASS()
class GAMES101_API AActor_Assignmen1 : public AActor
{
GENERATED_BODY() public:
// Sets default values for this actor's properties
AActor_Assignmen1(); protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override; public:
// Called every frame
virtual void Tick(float DeltaTime) override;
void DrawTriangleIn3D(); //主要函数
FMatrix get_view_matrix(FVector eye_pos);
FMatrix get_model_matrix(float rotation_angle);
FMatrix get_model_matrix_anyAxis(FVector axis, float angle);
FMatrix get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar); void RasterizerDraw(); public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (MakeEditWidget))
FTransform ponitA;
UPROPERTY(EditAnywhere,BlueprintReadWrite, meta = (MakeEditWidget))
FTransform ponitB;
UPROPERTY(EditAnywhere,BlueprintReadWrite, meta = (MakeEditWidget))
FTransform ponitC; UPROPERTY()
USceneComponent* root; UPROPERTY()
TArray<FVector> Points;
int32 width, height;
FVector eye_loc;
float angle; FMatrix modelMatrix;
FMatrix viewMatrix;
FMatrix projectionMatrix;
};
AActor_Assignmen1.cpp
#include "Actor_Assignmen1.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetMathLibrary.h"
#include "GameFramework/HUD.h"
#include "Kismet/GameplayStatics.h"
#include "MyHUD.h" // Sets default values
AActor_Assignmen1::AActor_Assignmen1()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
root = CreateDefaultSubobject<USceneComponent>("root");
SetRootComponent(root); // 三个点v0(2.0, 0.0,−2.0), v1(0.0, 2.0,−2.0), v2(−2.0, 0.0,−2.0),
Points.Add(FVector(2.0f, 0, -2.0f));
Points.Add(FVector(0, 2.0f,-2.0f));
Points.Add(FVector(-2.0f, 0,-2.0f)); // 初始化
width = height = 700;
eye_loc = FVector(0, 0, 5);
angle = 0; modelMatrix.SetIdentity();
viewMatrix.SetIdentity();
projectionMatrix.SetIdentity(); ponitA.SetTranslation(Points[0]);
ponitB.SetTranslation(Points[1]);
ponitC.SetTranslation(Points[2]);
} // Called every frame
void AActor_Assignmen1::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
FVector2D ViewportSize;
GetWorld()->GetGameViewport()->GetViewportSize(ViewportSize);
width = height = ViewportSize.X / 2; // 绕z轴
//modelMatrix = get_model_matrix(angle); //绕任意轴
modelMatrix = get_model_matrix_anyAxis(FVector(0, 0, 5), angle);
viewMatrix = get_view_matrix(eye_loc);
projectionMatrix = get_projection_matrix(45, 1, 0.1, 50); RasterizerDraw();
angle += 0.5;
root->SetWorldRotation(FRotator(0, angle, 0));
} FMatrix AActor_Assignmen1::get_view_matrix(FVector eye_pos)
{
FMatrix view = FMatrix::Identity; FMatrix translate = FMatrix(
FPlane(1, 0, 0, -eye_pos.X),
FPlane(0, 1, 0, -eye_pos.Y),
FPlane(0, 0, 1, -eye_pos.Z),
FPlane(0, 0, 0, 1)); view = translate * view;
return view;
} // 绕 Z 轴旋转
FMatrix AActor_Assignmen1::get_model_matrix(float rotation_angle)
{
FMatrix model = FMatrix::Identity; // TODO: Implement this function
// Create the model matrix for rotating the triangle around the Z axis.
// Then return it.
float fcos = UKismetMathLibrary::DegCos(rotation_angle);
float fsin = UKismetMathLibrary::DegSin(rotation_angle);
FMatrix rotate = FMatrix(
FPlane(fcos, -fsin, 0, 0),
FPlane(fsin, fcos, 0, 0),
FPlane( 0, 0, 1, 0),
FPlane( 0, 0, 0, 1)); model = rotate * model; return model;
} // 任意轴旋转
FMatrix AActor_Assignmen1::get_model_matrix_anyAxis(FVector axis, float rotation_angle)
{
FMatrix model = FMatrix::Identity; axis.Normalize(0.0001);
FMatrix N = FMatrix(
FPlane(0, -axis.Z, axis.Y, 0),
FPlane(axis.Z, 0, -axis.X, 0),
FPlane(-axis.Y, axis.X, 0, 0),
FPlane(0, 0, 0, 0)); FMatrix rotate4f = FMatrix::Identity * UKismetMathLibrary::DegCos(rotation_angle); // nnt = axis x axis的转置
FMatrix nnT = FMatrix(
FPlane(axis.X*axis.X, axis.X*axis.Y, axis.X*axis.Z, 0),
FPlane(axis.Y*axis.X, axis.Y*axis.Y, axis.Y*axis.Z, 0),
FPlane(axis.Z*axis.X, axis.Z*axis.Y, axis.Z*axis.Z, 0),
FPlane(0, 0, 0, 0)); rotate4f += nnT * (1 - UKismetMathLibrary::DegCos(rotation_angle)); rotate4f += N * UKismetMathLibrary::DegSin(rotation_angle); rotate4f.M[3][3] = 1;
model = rotate4f * model;
return model;
} FMatrix AActor_Assignmen1::get_projection_matrix(float eye_fov, float aspect_ratio, float zNear, float zFar)
{
// Students will implement this function
FMatrix projection = FMatrix::Identity; float t = zNear * UKismetMathLibrary::DegTan(eye_fov / 2);
float b = -t;
float r = t * aspect_ratio;
float l = -r; FMatrix translate = FMatrix(
FPlane(2 * zNear / (r - l), 0, -(r + l) / (r - l), 0),
FPlane(0, 2 * zNear / (t - b), -(t + b) / (t - b), 0),
FPlane(0, 0, -(zNear + zFar) / (zNear - zFar), 2 * zNear * zFar / (zNear - zFar)),
FPlane(0, 0, 1, 0));
projection = translate * projection; return projection;
} void AActor_Assignmen1::RasterizerDraw()
{
FMatrix mvp = projectionMatrix * viewMatrix * modelMatrix; float f1 = (100 - 0.1) / 2.0;
float f2 = (100 + 0.1) / 2.0;
TArray<FVector4> v;
for (FVector& p : Points) {
v.Add(mvp.GetTransposed().TransformFVector4(FVector4(p.X, p.Y, p.Z, 1.0f)));
} for (FVector4& vert : v) {
vert *= 1/vert.W;
vert.X = 0.5 * width * (vert.X + 1.0);
vert.Y = 0.5 * height * (vert.Y + 1.0);
vert.Z = vert.Z * f1 + f2;
} TArray<FVector> triangleVerts;
for (FVector4& vert : v) {
triangleVerts.Add(UKismetMathLibrary::Conv_Vector4ToVector(vert));
} // 调用AHUD 屏幕绘制函数
AMyHUD* myHUD = Cast<AMyHUD>(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetHUD());
if (myHUD) {
myHUD->rasterize_wireframe(triangleVerts);
}
/*
UKismetSystemLibrary::PrintString(GetWorld(), triangleVerts[0].ToString());
UKismetSystemLibrary::PrintString(GetWorld(), triangleVerts[1].ToString());
UKismetSystemLibrary::PrintString(GetWorld(), triangleVerts[2].ToString());
UKismetSystemLibrary::PrintString(GetWorld(), TEXT("----------"));
*/
} // 场景里的绘线
void AActor_Assignmen1::DrawTriangleIn3D() {
UKismetSystemLibrary::DrawDebugLine(GetWorld(), Points[0], Points[1], FLinearColor::Green, 0.02f, .2f);
UKismetSystemLibrary::DrawDebugLine(GetWorld(), Points[1], Points[2], FLinearColor::Green, 0.02f, .2f);
UKismetSystemLibrary::DrawDebugLine(GetWorld(), Points[2], Points[0], FLinearColor::Green, 0.02f, .2f);
}
创建蓝图派生类,添加面片
创建 AHUD 派生类 AMyHUD
自创建gamemode 并指定HUD,用于绘制屏幕上的线段
MyHUD.h
UCLASS()
class GAMES101_API AMyHUD : public AHUD
{
GENERATED_BODY() public:
virtual void DrawHUD() override;
// 重载用于绘制
void rasterize_wireframe(TArray<FVector>& t);
// 存储三角形的三个点
TArray<FVector> TriangleVerts;
};
MyHUD.cpp
void AMyHUD::DrawHUD()
{
Super::DrawHUD();
if (TriangleVerts.IsValidIndex(0)) {
DrawLine(TriangleVerts[0].X, TriangleVerts[0].Y, TriangleVerts[1].X, TriangleVerts[1].Y,FLinearColor::Red);
DrawLine(TriangleVerts[1].X, TriangleVerts[1].Y, TriangleVerts[2].X, TriangleVerts[2].Y,FLinearColor::Red);
DrawLine(TriangleVerts[2].X, TriangleVerts[2].Y, TriangleVerts[0].X, TriangleVerts[0].Y,FLinearColor::Red);
}
} void AMyHUD::rasterize_wireframe(TArray<FVector>& t)
{
TriangleVerts = t;
}
效果
【UE4】GAMES101 图形学作业1:mvp 模型、视图、投影变换的更多相关文章
- WebGL简易教程(六):第一个三维示例(使用模型视图投影变换)
目录 1. 概述 2. 示例:绘制多个三角形 2.1. Triangle_MVPMatrix.html 2.2. Triangle_MVPMatrix.js 2.2.1. 数据加入Z值 2.2.2. ...
- three.js中的矩阵变换(模型视图投影变换)
目录 1. 概述 2. 基本变换 2.1. 矩阵运算 2.2. 模型变换矩阵 2.2.1. 平移矩阵 2.2.2. 旋转矩阵 2.2.2.1. 绕X轴旋转矩阵 2.2.2.2. 绕Y轴旋转矩阵 2.2 ...
- WebGL或OpenGL关于模型视图投影变换的设置技巧
目录 1. 具体实例 2. 解决方案 1) Cube.html 2) Cube.js 3) 运行结果 3. 详细讲解 1) 模型变换 2) 视图变换 3) 投影变换 4) 模型视图投影矩阵 4. 存在 ...
- 【UE4】GAMES101 图形学作业3:Blinn-Phong 模型与着色
总览 在这次编程任务中,我们会进一步模拟现代图形技术.我们在代码中添加了Object Loader(用于加载三维模型), Vertex Shader 与Fragment Shader,并且支持了纹理映 ...
- 【UE4】GAMES101 图形学作业2:光栅化和深度缓存
总览 在上次作业中,虽然我们在屏幕上画出一个线框三角形,但这看起来并不是那么的有趣.所以这一次我们继续推进一步--在屏幕上画出一个实心三角形,换言之,栅格化一个三角形.上一次作业中,在视口变化之后,我 ...
- 【UE4】GAMES101 图形学作业5:光线与物体相交(球、三角面)
总览 在这部分的课程中,我们将专注于使用光线追踪来渲染图像.在光线追踪中最重要的操作之一就是找到光线与物体的交点.一旦找到光线与物体的交点,就可以执行着色并返回像素颜色. 在这次作业中,我们要实现两个 ...
- 【UE4】GAMES101 图形学作业4:贝塞尔曲线
总览 Bézier 曲线是一种用于计算机图形学的参数曲线. 在本次作业中,你需要实现de Casteljau 算法来绘制由4 个控制点表示的Bézier 曲线(当你正确实现该算法时,你可以支持绘制由更 ...
- 【UE4】GAMES101 图形学作业0:矩阵初识
作业描述 给定一个点P=(2,1), 将该点绕原点先逆时针旋转45◦,再平移(1,2), 计算出变换后点的坐标(要求用齐次坐标进行计算). UE4 知识点 主要矩阵 FMatrix FBasisVec ...
- OpenGL(五) 三维变换之模型视图矩阵
计算机三维图形学中,一个基本的任务是如何描述三维空间中一个物体位置的变化,也就是如何 描述物体的运动.通常情况下,物体位置的变化包含三个基本的变化:平移.旋转和缩放,物体的运动也可以用这三个基本的运动 ...
随机推荐
- Excel 列名转int索引(C#版)
/// <summary> /// 获取Excel实际列索引 /// </summary> /// <param name="columnName"& ...
- HashMap 为什么线程不安全?
作者:developer http://cnblogs.com/developer_chan/p/10450908.html 我们都知道HashMap是线程不安全的,在多线程环境中不建议使用,但是其线 ...
- ☕【Java技术指南】「并发编程专题」CompletionService框架基本使用和原理探究(基础篇)
前提概要 在开发过程中在使用多线程进行并行处理一些事情的时候,大部分场景在处理多线程并行执行任务的时候,可以通过List添加Future来获取执行结果,有时候我们是不需要获取任务的执行结果的,方便后面 ...
- IKEv2协议关键知识点总结整理
文章目录 @[toc] 1. IKEv2基本原理 2. IKEv2协议重点注意事项 2.1 情景一:==IKEv2协商密钥逻辑== ①密钥协商流程 ②函数调用关系 ③流程简述 2.2 情景二:==使用 ...
- 推荐一款编程字体:Iosevka
最近发现一款很好用的编程字体:Iosevka.它是一款现代化的编程字体集合,除了等宽.oO0 iIl1明显区分等基本特性外,还有很多非常现代的特性,比如: 多种风格:有非常多的字形可供选择,衬线/非衬 ...
- linux 下 I/O 多路复用初探
本文内容整理自B站up主 free-coder 发布的视频:[并发]IO多路复用select/poll/epoll介绍 引入 一般来讲,服务器在处理IO请求(一般指的是socket编程)时,需要对so ...
- 【第十二篇】- Git 服务器搭建之Spring Cloud直播商城 b2b2c电子商务技术总结
Git 服务器搭建 上一章节中我们远程仓库使用了 Github,Github 公开的项目是免费的,2019 年开始 Github 私有存储库也可以无限制使用. 这当然我们也可以自己搭建一台 Git 服 ...
- Oracle列值拼接
最近在学习的过程中,发现一个挺有意思的函数,它可实现对列值的拼接.下面我们来看看其具体用法. 用法: 对其作用,官方文档的解释如下: For a specified measure, LISTAGG ...
- NPOI相关资料
http://blog.csdn.net/heyangyi_19940703/article/details/52292755 http://www.cnblogs.com/zhengjuzhuan/ ...
- 从 1 开始学 JVM 系列 | JVM 类加载器(一)
从 1 开始学 JVM 系列 类加载器,对于很多人来说并不陌生.我自己第一次听到这个概念时觉得有点"高大上",觉得只有深入 JDK 源码才会触碰到 ClassLoader,平时都是 ...