总览

  • 到目前为止,我们已经学习了如何使用矩阵变换来排列二维或三维空间中的对象。所以现在是时候通过实现一些简单的变换矩阵来获得一些实际经验了。在接下来的三次作业中,我们将要求你去模拟一个基于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 模型、视图、投影变换的更多相关文章

  1. WebGL简易教程(六):第一个三维示例(使用模型视图投影变换)

    目录 1. 概述 2. 示例:绘制多个三角形 2.1. Triangle_MVPMatrix.html 2.2. Triangle_MVPMatrix.js 2.2.1. 数据加入Z值 2.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 ...

  3. WebGL或OpenGL关于模型视图投影变换的设置技巧

    目录 1. 具体实例 2. 解决方案 1) Cube.html 2) Cube.js 3) 运行结果 3. 详细讲解 1) 模型变换 2) 视图变换 3) 投影变换 4) 模型视图投影矩阵 4. 存在 ...

  4. 【UE4】GAMES101 图形学作业3:Blinn-Phong 模型与着色

    总览 在这次编程任务中,我们会进一步模拟现代图形技术.我们在代码中添加了Object Loader(用于加载三维模型), Vertex Shader 与Fragment Shader,并且支持了纹理映 ...

  5. 【UE4】GAMES101 图形学作业2:光栅化和深度缓存

    总览 在上次作业中,虽然我们在屏幕上画出一个线框三角形,但这看起来并不是那么的有趣.所以这一次我们继续推进一步--在屏幕上画出一个实心三角形,换言之,栅格化一个三角形.上一次作业中,在视口变化之后,我 ...

  6. 【UE4】GAMES101 图形学作业5:光线与物体相交(球、三角面)

    总览 在这部分的课程中,我们将专注于使用光线追踪来渲染图像.在光线追踪中最重要的操作之一就是找到光线与物体的交点.一旦找到光线与物体的交点,就可以执行着色并返回像素颜色. 在这次作业中,我们要实现两个 ...

  7. 【UE4】GAMES101 图形学作业4:贝塞尔曲线

    总览 Bézier 曲线是一种用于计算机图形学的参数曲线. 在本次作业中,你需要实现de Casteljau 算法来绘制由4 个控制点表示的Bézier 曲线(当你正确实现该算法时,你可以支持绘制由更 ...

  8. 【UE4】GAMES101 图形学作业0:矩阵初识

    作业描述 给定一个点P=(2,1), 将该点绕原点先逆时针旋转45◦,再平移(1,2), 计算出变换后点的坐标(要求用齐次坐标进行计算). UE4 知识点 主要矩阵 FMatrix FBasisVec ...

  9. OpenGL(五) 三维变换之模型视图矩阵

    计算机三维图形学中,一个基本的任务是如何描述三维空间中一个物体位置的变化,也就是如何 描述物体的运动.通常情况下,物体位置的变化包含三个基本的变化:平移.旋转和缩放,物体的运动也可以用这三个基本的运动 ...

随机推荐

  1. Git 学习路线

    前言 感觉 Git 还是很重要,应该单独开一篇文章来讲 Git... 使用系列教程 Git 系列教程(1)- Git 简介 Git 系列教程(2)- Git 安装 Git 系列教程(3)- 初次运行 ...

  2. python库--tensorflow--数学函数

    官方API(需FQ) 中文API 方法 返回值类型 参数 说明 算数运算符 .add() Tensor x, y, name=N 加法(若x,y都为tensor, 数据类型需一致, 以下所有x,y都如 ...

  3. tomcat服务字符编码改为UTF-8

    -Dfile.encoding=UTF-8 --仅供参考

  4. Xamarin UIProgressView自定义

    Progress.ProgressImage = UIImage.FromFile ("progress.png"); Progress.TrackImage = UIImage. ...

  5. FastAPI(6)- get 请求 - 详解 Query

    可选参数 上一篇文章讲过查询参数可以不是必传的,可以是可选参数 from fastapi import FastAPI from typing import Optional import uvico ...

  6. Percolator模型及其在TiKV中的实现

    一.背景 Percolator是Google在2010年发表的论文<Large-scale Incremental Processing Using Distributed Transactio ...

  7. springboot 配置 application.properties相关

    springboot 有读取外部配置文件的方法,如下优先级: 第一种是在jar包的同一目录下建一个config文件夹,然后把配置文件放到这个文件夹下.第二种是直接把配置文件放到jar包的同级目录.第三 ...

  8. UML类图及其JAVA的代码实现

    推荐 : https://my.oschina.net/u/3635618/blog/3165129 http://www.uml.org.cn/oobject/201104212.asp

  9. Elasticsearch、XXLJob以及最近的学习记录

    Elasticsearch.XXLJob以及最近的学习记录 前言 在这九月的最后一周,来总结一下最近的学习记录,主要是对于Elasticsearch.XXLjob的初步学习,想着还是多记录点,以便后面 ...

  10. P6847-[CEOI2019]Magic Tree【dp,线段树合并】

    正题 题目链接:https://www.luogu.com.cn/problem/P6847 题目大意 \(n\)个点的一棵树上,每个时刻可以割掉一些边,一些节点上有果实表示如果在\(d_i\)时刻这 ...