<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Unreal學(xué)習(xí)筆記2-繪制簡單三角形

      1. 概述

      之所以寫這個(gè)繪制簡單三角形的實(shí)例其實(shí)是想知道如何在Unreal中通過代碼繪制自定義Mesh,如果你會(huì)繪制一個(gè)三角形,那么自然就會(huì)繪制復(fù)雜的Mesh了。所以這是很多圖形工作者的第一課。

      2. 詳論

      2.1. 代碼實(shí)現(xiàn)

      Actor是Unreal的基本顯示對象,有點(diǎn)類似于Unity中的GameObject或者OSG中的Node。因此,我們首先要實(shí)現(xiàn)一個(gè)繼承自AActor的類

      頭文件CustomMeshActor.h:

      #pragma once
      
      // clang-format off
      #include "CoreMinimal.h"
      #include "GameFramework/Actor.h"
      #include "CustomMeshActor.generated.h"
      // clang-format on
      
      UCLASS()
      class UESTUDY_API ACustomMeshActor : public AActor {
        GENERATED_BODY()
      
       public:
        // Sets default values for this actor's properties
        ACustomMeshActor();
      
       protected:
        // Called when the game starts or when spawned
        virtual void BeginPlay() override;
      
        UStaticMesh* CreateMesh();
        void CreateGeometry(FStaticMeshRenderData* RenderData);
        void CreateMaterial(UStaticMesh* mesh);
      
       public:
        // Called every frame
        virtual void Tick(float DeltaTime) override;
      
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
        UStaticMeshComponent* staticMeshComponent;
      };
      

      實(shí)現(xiàn)CustomMeshActor.cpp:

      #include "CustomMeshActor.h"
      
      #include "Output.h"
      
      // Sets default values
      ACustomMeshActor::ACustomMeshActor() {
        // 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;
      }
      
      // Called when the game starts or when spawned
      void ACustomMeshActor::BeginPlay() {
        Super::BeginPlay();
      
        staticMeshComponent = NewObject<UStaticMeshComponent>(this);
      
        staticMeshComponent->SetMobility(EComponentMobility::Stationary);
        SetRootComponent(staticMeshComponent);
        staticMeshComponent->RegisterComponent();
      
        UStaticMesh* mesh = CreateMesh();
        if (mesh) {
          staticMeshComponent->SetStaticMesh(mesh);
        }
      }
      
      UStaticMesh* ACustomMeshActor::CreateMesh() {
        UStaticMesh* mesh = NewObject<UStaticMesh>(staticMeshComponent);
        mesh->NeverStream = true;
        mesh->SetIsBuiltAtRuntime(true);
      
        TUniquePtr<FStaticMeshRenderData> RenderData =
            MakeUnique<FStaticMeshRenderData>();
      
        CreateGeometry(RenderData.Get());
      
        CreateMaterial(mesh);
      
        mesh->SetRenderData(MoveTemp(RenderData));
        mesh->InitResources();
        mesh->CalculateExtendedBounds();  //設(shè)置包圍盒之后調(diào)用這個(gè)函數(shù)起效,否則會(huì)被視錐體剔除
        return mesh;
      }
      
      void ACustomMeshActor::CreateMaterial(UStaticMesh* mesh) {
        UMaterial* material1 = (UMaterial*)StaticLoadObject(
            UMaterial::StaticClass(), nullptr,
            TEXT("Material'/Game/Materials/RedColor.RedColor'"));
      
        mesh->AddMaterial(material1);
      
        UMaterial* material2 = (UMaterial*)StaticLoadObject(
            UMaterial::StaticClass(), nullptr,
            TEXT("Material'/Game/Materials/GreenColor.GreenColor'"));
      
        mesh->AddMaterial(material2);
      }
      
      void ACustomMeshActor::CreateGeometry(FStaticMeshRenderData* RenderData) {
        RenderData->AllocateLODResources(1);
        FStaticMeshLODResources& LODResources = RenderData->LODResources[0];
      
        int vertexNum = 4;
      
        TArray<FVector> xyzList;
        xyzList.Add(FVector(0, 0, 50));
        xyzList.Add(FVector(100, 0, 50));
        xyzList.Add(FVector(100, 100, 50));
        xyzList.Add(FVector(0, 100, 50));
      
        TArray<FVector2D> uvList;
        uvList.Add(FVector2D(0, 1));
        uvList.Add(FVector2D(0, 0));
        uvList.Add(FVector2D(1, 0));
        uvList.Add(FVector2D(1, 1));
      
        // 設(shè)置頂點(diǎn)數(shù)據(jù)
        TArray<FStaticMeshBuildVertex> StaticMeshBuildVertices;
        StaticMeshBuildVertices.SetNum(vertexNum);
        for (int m = 0; m < vertexNum; m++) {
          StaticMeshBuildVertices[m].Position = xyzList[m];
          StaticMeshBuildVertices[m].Color = FColor(255, 0, 0);
          StaticMeshBuildVertices[m].UVs[0] = uvList[m];
          StaticMeshBuildVertices[m].TangentX = FVector(0, 1, 0);  //切線
          StaticMeshBuildVertices[m].TangentY = FVector(1, 0, 0);  //副切線
          StaticMeshBuildVertices[m].TangentZ = FVector(0, 0, 1);  //法向量
        }
      
        LODResources.bHasColorVertexData = false;
      
        //頂點(diǎn)buffer
        LODResources.VertexBuffers.PositionVertexBuffer.Init(StaticMeshBuildVertices);
      
        //法線,切線,貼圖坐標(biāo)buffer
        LODResources.VertexBuffers.StaticMeshVertexBuffer.Init(
            StaticMeshBuildVertices, 1);
      
        //設(shè)置索引數(shù)組
        TArray<uint32> indices;
        int numTriangles = 2;
        int indiceNum = numTriangles * 3;
        indices.SetNum(indiceNum);
        indices[0] = 2;
        indices[1] = 1;
        indices[2] = 0;
        indices[3] = 3;
        indices[4] = 2;
        indices[5] = 0;
      
        LODResources.IndexBuffer.SetIndices(indices,
                                            EIndexBufferStride::Type::AutoDetect);
      
        LODResources.bHasDepthOnlyIndices = false;
        LODResources.bHasReversedIndices = false;
        LODResources.bHasReversedDepthOnlyIndices = false;
        // LODResources.bHasAdjacencyInfo = false;
      
        FStaticMeshLODResources::FStaticMeshSectionArray& Sections =
            LODResources.Sections;
        {
          FStaticMeshSection& section = Sections.AddDefaulted_GetRef();
      
          section.bEnableCollision = false;
          section.MaterialIndex = 0;
          section.NumTriangles = 1;
          section.FirstIndex = 0;
          section.MinVertexIndex = 0;
          section.MaxVertexIndex = 2;
        }
        {
          FStaticMeshSection& section = Sections.AddDefaulted_GetRef();
      
          section.bEnableCollision = false;
          section.MaterialIndex = 0;
          section.NumTriangles = 1;
          section.FirstIndex = 3;
          section.MinVertexIndex = 3;
          section.MaxVertexIndex = 5;
        }
      
        double boundArray[7] = {0, 0, 0, 200, 200, 200, 200};
      
        //設(shè)置包圍盒
        FBoxSphereBounds BoundingBoxAndSphere;
        BoundingBoxAndSphere.Origin =
            FVector(boundArray[0], boundArray[1], boundArray[2]);
        BoundingBoxAndSphere.BoxExtent =
            FVector(boundArray[3], boundArray[4], boundArray[5]);
        BoundingBoxAndSphere.SphereRadius = boundArray[6];
        RenderData->Bounds = BoundingBoxAndSphere;
      }
      
      // Called every frame
      void ACustomMeshActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); }
      

      然后將這個(gè)類對象ACustomMeshActor拖放到場景中,顯示結(jié)果如下:

      imglink1

      2.2. 解析:Component

      1. Actor只是一個(gè)空殼,具體的功能是通過各種類型的Component實(shí)現(xiàn)的(這一點(diǎn)與Unity不謀而合),這里使用的是UStaticMeshComponent,這也是Unreal場景中用的最多的Mesh組件。

      2. 這里組件初始化是在BeginPlay()中創(chuàng)建的,如果在構(gòu)造函數(shù)中創(chuàng)建,那么就不能使用NewObject,而應(yīng)該使用如下方法:

        // Sets default values
        ACustomMeshActor::ACustomMeshActor() {
            // 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;
        
            staticMeshComponent =
                CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SceneRoot"));
            staticMeshComponent->SetMobility(EComponentMobility::Static);
            SetRootComponent(staticMeshComponent);
        
            UStaticMesh* mesh = CreateMesh();
            if (mesh) {
                staticMeshComponent->SetStaticMesh(mesh);
            }
        }
        
      3. 承接2,在BeginPlay()中創(chuàng)建和在構(gòu)造函數(shù)中創(chuàng)建的區(qū)別就在于前者是運(yùn)行時(shí)創(chuàng)建,而后者在程序運(yùn)行之前就創(chuàng)建了,可以在未運(yùn)行的編輯器狀態(tài)下看到靜態(tài)網(wǎng)格體和材質(zhì)。

      4. 承接2,在構(gòu)造函數(shù)中創(chuàng)建的UStaticMeshComponent移動(dòng)性被設(shè)置成Static了,這時(shí)運(yùn)行會(huì)提示“光照需要重建”,也就是靜態(tài)對象需要烘焙光照,在工具欄"構(gòu)建"->"僅構(gòu)建光照"烘培一下即可。這種方式運(yùn)行時(shí)渲染效率最高。

      5. 對比4,運(yùn)行時(shí)創(chuàng)建的UStaticMeshComponent移動(dòng)性可以設(shè)置成Stationary,表示這個(gè)靜態(tài)物體不移動(dòng),啟用緩存光照法,并且緩存動(dòng)態(tài)陰影。

      2.3. 解析:材質(zhì)

      1. 在UE編輯器分別創(chuàng)建了紅色和綠色簡單材質(zhì),注意材質(zhì)是單面還是雙面的,C++代碼設(shè)置的要和材質(zhì)藍(lán)圖中設(shè)置的要保持一致。最開始我參考的就是參考文獻(xiàn)1中的代碼,代碼中設(shè)置成雙面,但是我自己的材質(zhì)藍(lán)圖中用的單面,程序啟動(dòng)直接崩潰了。

      2. 如果場景中材質(zhì)顯示不正確,比如每次瀏覽場景時(shí)的效果都不一樣,說明可能法向量沒有設(shè)置,我最開始就沒有注意這個(gè)問題以為是光照的問題。

      3. 單面材質(zhì)的話,正面是逆時(shí)針序還是順時(shí)針序?從這個(gè)案例來看應(yīng)該是逆時(shí)針。UE是個(gè)左手坐標(biāo)系,X軸向前,法向量是(0, 0, 1),從法向量的一邊看過去,頂點(diǎn)順序是(100, 100, 50)->(100, 0, 50)->(0, 0, 50),明顯是逆時(shí)針。

      2.4. 解析:包圍盒

      1. 包圍盒參數(shù)最好要設(shè)置,UE似乎默認(rèn)實(shí)現(xiàn)了視景體裁剪,不在范圍內(nèi)的物體會(huì)不顯示。如果在某些視角場景對象突然不顯示了,可能包圍盒參數(shù)沒有設(shè)置正確,導(dǎo)致視景體裁剪錯(cuò)誤地篩選掉了當(dāng)前場景對象。

        FBoxSphereBounds BoundingBoxAndSphere;
        //...
        RenderData->Bounds = BoundingBoxAndSphere;
        //...
        mesh->CalculateExtendedBounds();  //設(shè)置包圍盒之后調(diào)用這個(gè)函數(shù)起效,否則會(huì)被視錐體剔除
        
      2. 即使是一個(gè)平面,包圍盒的三個(gè)Size參數(shù)之一也不能為0,否則還是可能會(huì)在某些視角場景對象不顯示。

      2.5. 解析:Section

      Mesh內(nèi)部是可以進(jìn)行劃分的,劃分成多少個(gè)section就使用多少個(gè)材質(zhì),比如這里劃分了兩個(gè)section,最后就使用了兩個(gè)材質(zhì)。如下代碼所示:

      FStaticMeshLODResources::FStaticMeshSectionArray& Sections =
          LODResources.Sections;
      {
        FStaticMeshSection& section = Sections.AddDefaulted_GetRef();
      
        section.bEnableCollision = false;
        section.MaterialIndex = 0;
        section.NumTriangles = 1;
        section.FirstIndex = 0;
        section.MinVertexIndex = 0;
        section.MaxVertexIndex = 2;
      }
      {
        FStaticMeshSection& section = Sections.AddDefaulted_GetRef();
      
        section.bEnableCollision = false;
        section.MaterialIndex = 0;
        section.NumTriangles = 1;
        section.FirstIndex = 3;
        section.MinVertexIndex = 3;
        section.MaxVertexIndex = 5;
      }
      

      3. 其他

      除了本文介紹的方法之外,也有其他的實(shí)現(xiàn)辦法,具體可以參考文獻(xiàn)3-5。實(shí)在是沒有時(shí)間進(jìn)行進(jìn)一步的研究了,因此記錄備份一下。另外,文獻(xiàn)6-7可能對了解UE關(guān)于Mesh的內(nèi)部實(shí)現(xiàn)有所幫助,筆者反正是看麻了。不得不說,這么一個(gè)微小的功能涉及到的內(nèi)容還真不少,看來有的研究了。

      4. 參考

      1. UE4繪制簡單三角形(二)
      2. UE4之坐標(biāo)系
      3. [UE4 C++]三種方式繪制三角形
      4. Building a StaticMesh in C++ during runtime
      5. Build static mesh from description
      6. 虛幻 – StaticMesh 分析
      7. Creating a Custom Mesh Component in UE4

      上一篇
      目錄
      下一篇

      代碼地址

      posted @ 2023-02-01 20:39  charlee44  閱讀(757)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 免费观看全黄做爰大片| 国产影片AV级毛片特别刺激| 国产成人无码综合亚洲日韩| 久久国产精品精品国产色婷婷| 国产一区二区三区高清视频| 亚洲日本国产精品一区| 国产在线观看免费观看不卡| 亚洲综合一区二区三区不卡| 亚洲AV日韩精品久久久久| 欧美三级欧美成人高清| 精品国精品国自产在国产| 国产精品一二二区视在线| 越南毛茸茸的少妇| 福利一区二区1000| 久久精品天天中文字幕人妻| 99麻豆久久精品一区二区| 国产综合av一区二区三区 | 亚洲成在人线在线播放无码| 国产一区二区三区四区五区加勒比 | 成人性生交片无码免费看| 国产成人女人在线观看| 九九热精品视频在线免费| 熟女熟妇伦av网站| 99久久成人亚洲精品观看| 中文字幕国产日韩精品| 女厕偷窥一区二区三区| 久久久久久99av无码免费网站| 亚洲色一色噜一噜噜噜| 嘉荫县| 大色综合色综合网站| 欧美亚洲国产日韩电影在线| 国产对白老熟女正在播放| 国产免费午夜福利片在线| 激情 自拍 另类 亚洲| 国产中文字幕在线精品| 国产精品黄色片在线观看| 久久天天躁狠狠躁夜夜躁| 强奷白丝美女在线观看| 色吊丝二区三区中文写幕| 平武县| 二区三区亚洲精品国产|