UStaticMesh几何数据相关(UE5.2)

news2024/12/22 15:06:20

UStaticMesh相关类图

8f663eb4989e48579fd3d47252243c43.png

 

UStaticMesh的数据构成

 

UStaticMesh的FStaticMeshSourceModel

UStaticMesh的Mesh几何元数据来自于FStaticMeshSourceModel, 一级Lod就存在一个FStaticMeshSourceModel. FStaticMeshSourceModel几何数据大致包含以下几类:

Vertex(点), VertexInstance(顶点), Edge(边),   Triangle(三角形),   Polygon(多边形)

总体上概念和Houdini的一些几何概念相似,每种几何元素都可以附带属性,比如点的“Position”, 顶点的“Normal,UV”等等。

下面介绍下如何获取Mesh元数据和相关属性

void AMyActor::TestMeshInfo() const
{
	if(!Mesh)
		return;

	// SourceModel
	const TArray<FStaticMeshSourceModel>& SourceModels = Mesh->GetSourceModels();
	for(int32 Index = 0; Index < SourceModels.Num(); Index++)
	{
		FMeshDescription* MeshDesc = Mesh->GetMeshDescription(Index);
		if(MeshDesc)
		{
			const FVertexArray& VertexArray =  MeshDesc->Vertices();

			// TVertexAttributesRef<FVector3f> VertexPositions = MeshDesc->VertexAttributes().GetAttributesRef<FVector3f>(MeshAttribute::Vertex::Position);
			TVertexAttributesRef<FVector3f> VertexPositions = MeshDesc->GetVertexPositions();

			//loop vertex postion
			for(const FVertexID VertexID : VertexArray.GetElementIDs())
			{
				FVector3f& Pos = VertexPositions[VertexID];
			}

			UE_LOG(LogTemp, Warning, TEXT("Vertex num = %d"), VertexArray.Num());


			//loop vertex instance attribute
			const FVertexInstanceArray& VertexInstanceArray = MeshDesc->VertexInstances();
			TVertexInstanceAttributesRef<FVector4f> VertexInstanceColors = MeshDesc->VertexInstanceAttributes().GetAttributesRef<FVector4f>(MeshAttribute::VertexInstance::Color);
			for(const FVertexInstanceID VertxInstanceId : VertexInstanceArray.GetElementIDs())
			{
				
			}

			UE_LOG(LogTemp, Warning, TEXT("VertexInstanceArray num = %d"), VertexInstanceArray.Num());

			//loop vertex edge attribute
			const FEdgeArray& EdgeArray = MeshDesc->Edges();
			TEdgeAttributesRef<bool> EdgeHardness = MeshDesc->EdgeAttributes().GetAttributesRef<bool>(MeshAttribute::Edge::IsHard);
			for (FEdgeID EdgeID : EdgeArray.GetElementIDs())
			{
				
			}

			UE_LOG(LogTemp, Warning, TEXT("EdgeArray num = %d"), EdgeArray.Num());

			// loop triangle attribute
			const FTriangleArray& TriangleArray = MeshDesc->Triangles();
			TTriangleAttributesRef<FVector3f> TriangleNormals = MeshDesc->TriangleAttributes().GetAttributesRef<FVector3f>(MeshAttribute::Triangle::Normal);
			for (FTriangleID TriangleID : TriangleArray.GetElementIDs())
			{
				
			}

			UE_LOG(LogTemp, Warning, TEXT("TriangleArray num = %d"), TriangleArray.Num());
			
			// loop polygon
			const FPolygonArray& PolygonArray =  MeshDesc->Polygons();
			TPolygonAttributesRef<int32> PatchGroups = MeshDesc->PolygonAttributes().GetAttributesRef<int32>(MeshAttribute::Polygon::PolygonGroupIndex);

			UE_LOG(LogTemp, Warning, TEXT("PolygonArray num = %d"), PolygonArray.Num());
		}


		if(Mesh->GetRenderData()->LODResources.Num() > Index)
		{
			TArray<FVector3f> Vertexs;
			auto& LodResource = Mesh->GetRenderData()->LODResources[Index];
			int32 VertexNum = LodResource.GetNumVertices();
			for(int32 I = 0; I < VertexNum; I++)
			{
				Vertexs.Add(LodResource.VertexBuffers.PositionVertexBuffer.VertexPosition(I));
			}

			int32 TriangleNum = LodResource.GetNumTriangles();
			TArray<uint32> Indexs;
			for(int32 I = 0; I < TriangleNum; I++)
			{
				Indexs.Add(LodResource.IndexBuffer.GetIndex(I * 3 + 0));
				Indexs.Add(LodResource.IndexBuffer.GetIndex(I * 3 + 1));
				Indexs.Add(LodResource.IndexBuffer.GetIndex(I * 3 + 2));
			}
			
		}
	}
}

 

 

如何填充数据生成一个UStaticMesh

主要是通过填充FMeshDescription的各种图元数据(Vertex, VertexInstance, Polygon, PolygonGroup等等)

void AMyActor::TestCreateStaticMesh()
{
	const FString ObjectName = "TestStaticMesh";
	const FString GameFoldPath = "/Game";
	const FString PackageName = FString::Printf(TEXT("%s/%s"), *GameFoldPath, *ObjectName);

	UPackage* Package = CreatePackage(*PackageName);
	UStaticMesh* MyMesh = NewObject<UStaticMesh>(Package, *ObjectName, RF_Standalone | RF_Public);
	FMeshDescription MeshDescription;
	FStaticMeshAttributes MeshAttribute(MeshDescription);
	MeshAttribute.Register();

	TArray<FDynamicMeshVertex> Vertices;
	Vertices.Add(FDynamicMeshVertex(FVector3f(500.0f, 500.0f, 200)));
	Vertices.Add(FDynamicMeshVertex(FVector3f(-500.0f, 500.0f, 200)));
	Vertices.Add(FDynamicMeshVertex(FVector3f(-500.0f, -500.0f, 200)));
	Vertices.Add(FDynamicMeshVertex(FVector3f(500.0f, -500.0f, 200)));

	TArray<int32> Indexs;
	Indexs.Add(0);
	Indexs.Add(3);
	Indexs.Add(1);

	Indexs.Add(1);
	Indexs.Add(3);
	Indexs.Add(2);
	
	MeshDescription.Empty();
	MeshDescription.ReserveNewVertices(Vertices.Num());
	MeshDescription.ReserveNewTriangles(Indexs.Num() / 3);
	MeshDescription.ReserveNewVertexInstances(Indexs.Num());

	TVertexAttributesRef<FVector3f> VertexPositions = MeshAttribute.GetVertexPositions();
	TVertexInstanceAttributesRef<FVector2f>	VertexInstanceUVs = MeshAttribute.GetVertexInstanceUVs();
	TVertexInstanceAttributesRef<FVector3f>	VertexInstanceNormals = MeshAttribute.GetVertexInstanceNormals();
	TVertexInstanceAttributesRef<FVector3f>	VertexInstanceTangents = MeshAttribute.GetVertexInstanceTangents();
	TPolygonGroupAttributesRef<FName> MaterialSlotNames = MeshAttribute.GetPolygonGroupMaterialSlotNames();
	TArray<UMaterialInterface*> MaterialInterfaces = {UMaterial::GetDefaultMaterial(MD_Surface)};
	for(int32 Index = 0; Index < MaterialInterfaces.Num(); Index++)
	{
		FPolygonGroupID PolygonGroupID = MeshDescription.CreatePolygonGroup();
		FStaticMaterial StaticMaterial = MaterialInterfaces[Index];
		MaterialSlotNames[PolygonGroupID] = StaticMaterial.MaterialSlotName;
	}

	//create vertex
	for(int32 Index = 0; Index < Vertices.Num(); Index++)
	{
		FVertexID VertexId = MeshDescription.CreateVertex();
		VertexPositions.Set(VertexId, Vertices[Index].Position);
	}

	//create vertex instance
	for(int32 Index = 0; Index < Indexs.Num(); Index++)
	{
		FVertexInstanceID VertexInstanceId = FVertexInstanceID(Index);
		FVertexID VertexID = FVertexID(Indexs[Index]);
		MeshDescription.CreateVertexInstanceWithID(VertexInstanceId, VertexID);
	}

	// set vertex instance normal/tangent/uv
	FPolygonGroupID PolygonGroupID(0);
	TArray<FVertexInstanceID> InstanceIds;
	for(int32 Index = 0; Index < Indexs.Num(); Index++)
	{
		FVertexInstanceID VertexInstanceId = FVertexInstanceID(Index);
		InstanceIds.Add(VertexInstanceId);
		const FDynamicMeshVertex& DynamicVertex = Vertices[Indexs[Index]];
		VertexInstanceUVs.Set(VertexInstanceId, DynamicVertex.TextureCoordinate[0]);
		VertexInstanceNormals.Set(VertexInstanceId, DynamicVertex.TangentX.ToFVector3f());
		VertexInstanceTangents.Set(VertexInstanceId, DynamicVertex.TangentZ.ToFVector3f());

		if(InstanceIds.Num() == 3)
		{
			TArray<FEdgeID> EdgeIds;
			MeshDescription.CreatePolygon(PolygonGroupID, InstanceIds, &EdgeIds);
			InstanceIds.Empty();
		}
	}

	// create source model lod0 and commit mesh desc
	const int32 LodIndex = 0;
	if(!MyMesh->IsSourceModelValid(LodIndex))
	{
		FStaticMeshSourceModel& SourceModel = MyMesh->AddSourceModel();
		SourceModel.BuildSettings.bRecomputeNormals = false;
		SourceModel.BuildSettings.bRecomputeTangents = false;
		SourceModel.BuildSettings.bGenerateLightmapUVs = false;
	}

	MyMesh->CreateMeshDescription(LodIndex, MeshDescription);
	MyMesh->CommitMeshDescription(LodIndex);

	MyMesh->ImportVersion = EImportStaticMeshVersion::LastVersion;
	MyMesh->CreateBodySetup();
	MyMesh->GetBodySetup()->CollisionReponse = EBodyCollisionResponse::BodyCollision_Disabled;
	MyMesh->Build(true);
	
	MyMesh->PostEditChange();
	MyMesh->MarkPackageDirty();
	FAssetRegistryModule::AssetCreated(MyMesh);
}

4cf12657eaea4f30b908fbb25d410d6f.png

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【源码】Spring Data JPA原理解析之Repository的自动注入(一)

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 4、Spring Data JPA的一对一、LazyInitializationException异常、一对多、多对多操作 5、Spring Data JPA自定…

4种现象表明你的血糖控制良好!

如果你出现以下4种现象&#xff0c;恭喜你&#xff0c;说明你的血糖控制的不错&#xff0c;需要继续坚持。 1.饥饿感减少&#xff0c;我们的脏腑能够吸收血液中的糖分了&#xff0c;就用不着饿了。&#xff0c;血液中的糖能够得到充分的利用&#xff0c;血糖自然降下去。 2.体…

找到字符串中所有字母异位词 ---- 滑动窗口

题目链接 题目: 分析: 要找的是在s中和p是异位词的子串, 也就是说子串大小和p相同, 那么就是窗口大小固定的滑动窗口问题可以使用哈希数组来记录每个元素出现的个数, 定义hash1存放p中的各元素个数定义left 0; right 0;进窗口 让right指向的元素进窗口, 即更新hash2中的元素…

vue3自定义指令​(通过指令钩子获得dom和钩子参数)

实现文本框自动获得焦点 Index.vue: <script setup> import { ref, onMounted } from vue import ./index.cssconst vFocus {mounted: (el, binding) > {el.focus()console.log(binding)} }onMounted(() > {}) </script><template><div class&qu…

C#委托以及在事件驱动编程中的使用

C#中的委托&#xff08;Delegate&#xff09;是一种类型&#xff0c;它可以存储对方法的引用&#xff0c;并且可以像其他类型一样传递给方法。委托提供了一种灵活的方式来实现事件处理、回调函数和多播委托等功能。以下是关于C#委托的详细介绍&#xff1a; 定义&#xff1a; …

量化研究---A股赚钱日历,上证指数为例,提供源代码

今天把A股的全部数据导出做了一些赚钱日历分析&#xff0c;看那个月赚钱容易&#xff0c;那个月赚钱困难 导入需要的库 import pandas as pdimport matplotlib.pyplot as pltimport quantstats as qsfrom trader_tool.index_data import index_datafrom trader_tool import j…

风电功率预测 | 基于BP神经网络的风电功率预测(附matlab完整源码)

风电功率预测 风电功率预测 | 基于BP神经网络的风电功率预测(附matlab完整源码)完整代码风电功率预测 | 基于BP神经网络的风电功率预测(附matlab完整源码) 基于BP神经网络的风电功率预测是一种常见的方法,它利用BP神经网络模型来预测风电场的发电功率。下面是一个基于BP神经…

HTML常用标签-表格标签

表格标签 1 常规表格2 单元格跨行3 单元格跨行 1 常规表格 table标签 代表表格 thead标签 代表表头 可以省略不写 tbody标签 代表表体 可以省略不写 tfoot标签 代表表尾 可以省略不写 tr标签 代表一行 td标签 代表行内的一格 th标签 自带加粗和居中效果的td 代码 <h…

【启程Golang之旅】环境设置、工具安装与代码实践

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

mysql,sqlserver数据库查询表,获得表结构,结构类型说明,获得这些数据,可以拿去创建表

mysql&#xff0c;sqlserver数据库查询表&#xff0c;获得表结构&#xff0c;结构类型说明&#xff0c;获得这些数据&#xff0c;可以拿去创建表 //表名p_order select * from information_schema.COLUMNS where TABLE_NAMEp_order;1、TABLE_CATALOG &#xff0c;nvarchar(128…

C++ | Leetcode C++题解之第89题格雷编码

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> grayCode(int n) {vector<int> ret(1 << n);for (int i 0; i < ret.size(); i) {ret[i] (i >> 1) ^ i;}return ret;} };

47 tcp网络程序

网路聊天 API详解 下面用到的API&#xff0c;都在sys/socket.h中 socket (): socket() 打开一个网络通讯端口&#xff0c;如果成功的话&#xff0c;就像open() 一样返回一个文件描述符应用程序可以像读文件一样用read/write在网络上收发数据如果调用出错返回-1对于IPv4&am…

读人工智能时代与人类未来笔记03_演变

1. 演变 1.1. 每个社会都找到了属于自己的一套适应世界的方法 1.1.1. 适应的核心&#xff0c;是有关人类心智与现实之间关系的概念 1.1.2. 人类认识周围环境的能力 1.1.2.1. 这种能力通过知识获得&#xff0c;同时也受到知识…

研发管理-选择研发管理系统-研发管理系统哪个好

选择研发管理系统-研发管理系统哪个好 选择研发管理系统时&#xff0c;并没有一个绝对的“最好”的系统&#xff0c;因为每个企业的需求和情况都是独特的。然而&#xff0c;我可以向您介绍一些在市场上广受欢迎且功能强大的研发管理系统&#xff0c;供您参考&#xff1a; 1、彩…

OpenAI 推出 GPT-4o:实现多模态 AI 交互

一、前言 OpenAI 推出了其最新的 AI 模型——GPT-4o&#xff0c;此次发布的并非 GPT-4.5 或 GPT-5&#xff0c;而是一款全新的“全模态模型(Omnimodel)”。这是一个将文本、语音和视觉能力集成到单一无缝 AI 体验中的突破性发展。 GPT-4o 于 2024 年 5 月 14 日发布&#xff0…

生产消费者模型-环形队列与信号量

文章目录 前言一、怎样的环形队列&#xff1f;二、什么是信号量三、使用步骤信号量的接口函数1. sem_init2.sem_destroy3.sem_wait4.sem_post 环形队列的设计测试用例 前言 之前我们使用互斥锁和条件变量实现过一个生产者消费者模型&#xff0c;那么那个生产消费者模型具有一个…

Github20K星开源团队协作工具:Zulip

Zulip&#xff1a;让团队协作的每一次交流&#xff0c;都精准高效。- 精选真开源&#xff0c;释放新价值。 概览 随着远程工作的兴起和团队协作的需求不断增加&#xff0c;群组聊天软件成为了日常工作中不可或缺的一部分。Zulip 是github上一个开源的团队协作工具&#xff0c;…

【问题实操】银河高级服务器操作系统实例分享,网卡drop问题分析

1.服务器环境以及配置 系统环境 物理机/虚拟机/云/容器 物理机 网络环境 外网/私有网络/无网络 私有网络 硬件环境 机型 华鲲振宇 TG225B1 处理器 kunpeng 920 内存 1024GB 主板型号 TG225B1 HZKY 整机类型/架构 aarch64 固件版本 6.57 软件环境 具体操作系…

谷歌Gemini时代来了!加固搜索护城河、赋能全家桶,Gemini 1.5 Pro升级至200万token

3 月中旬&#xff0c;谷歌宣布 Google I/O 定档北京时间 5 月 15 日凌晨 1 点。而当大会开幕时间临近&#xff0c;本应是讨论度最高的时候&#xff0c;「宿敌」OpenAI 却半路杀出&#xff0c;抢先一天&#xff0c;仅耗时 27 分钟就发布了颠覆性巨作 GPT-4o&#xff0c;将新一轮…

HTTP代理可以应用在那些领域呢

HTTP代理是IP代理领域中一个重要组成部分&#xff0c;它基于HTTP协议传输&#xff0c;使用海外服务器帮助用户绕开访问限制&#xff0c;浏览查看海外资讯信息。 HTTP代理可以应用在哪些领域呢&#xff1f; 1.保护使用者隐私 当今越来越数据被上传到网络云端上&#xff0c;用户…