总览

  • 到目前为止,我们已经学习了如何使用矩阵变换来排列二维或三维空间中的对象。所以现在是时候通过实现一些简单的变换矩阵来获得一些实际经验了。在接下来的三次作业中,我们将要求你去模拟一个基于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. 分布式消息流平台:不要只想着Kafka,还有Pulsar

    摘要:Pulsar作为一个云原生的分布式消息流平台,越来越频繁地出现在人们的视野中,大有替代Kafka江湖地位的趋势. 本文分享自华为云社区<MRS Pulsar:下一代分布式消息流平台全新发布 ...

  2. 羽夏笔记——PE结构(不包含.Net)

    写在前面   本笔记是由本人独自整理出来的,图片来源于网络.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你 ...

  3. 【算法】使用Golang实现加权负载均衡算法

    背景描述 如下图所示,负载均衡做为反向代理,将请求方的请求转发至后端的服务节点,实现服务的请求. 在nginx中可以通过upstream配置server时,设置weight表示对应server的权重. ...

  4. Mysql - You can't specify target table '表名' for update in FROM clause 错误解决办法

    背景 在MySQL中,写SQL语句的时候 ,可能会遇到 You can't specify target table '表名' for update in FROM clause 这样的错误 错误含义 ...

  5. iNeuOS工业互联平台,PLC监测与控制应用过程案例。新闻:.NET 6 RC1 正式发布

    目       录 1.      概述... 1 2.      平台演示... 2 3.      应用过程... 2 1.   概述 iNeuOS工业互联网操作系统主要使用.netcore 3. ...

  6. [第三篇]——CentOS Docker 安装之Spring Cloud直播商城 b2b2c电子商务技术总结

    CentOS Docker 安装 Docker 支持以下的 64 位 CentOS 版本: CentOS 7 CentOS 8 更高版本... 使用官方安装脚本自动安装 安装命令如下: curl -f ...

  7. Prometheus 2.21.0 新特性

    Prometheus 2.21.0 现在(2020.09.11)已经发布,在上个月的 2.20.0 之后又进行了很多的修复和改进. 这个版本使用了 Go 1.15 进行编译,不赞成在TLS证书验证中使 ...

  8. Dockerfile 自动制作 Docker 镜像(三)—— 镜像的分层与 Dockerfile 的优化

    Dockerfile 自动制作 Docker 镜像(三)-- 镜像的分层与 Dockerfile 的优化 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云 ...

  9. pip3 install beautifulsoup4 出现错误 There was a problem confirming the ssl certificate

    chenhuimingdeMacBook-Pro:groceryList Mch$ sudo pip3 install beautifulsoup4 The directory '/Users/Mch ...

  10. PHP-设计模式之-中介者模式

    <?php//中介者模式 -- //抽象中介者abstract class UnitedNationa{ punlic abstract function Declared($message,c ...