UE4+Cubemap(jpg导入UE4生成Cubemap)_Rick0803的博客-程序员宝宝

技术标签: C++  UE4  Cubemap  Python  

VS:2019

虚幻引擎:4.25

Python:官方2.7版本

目的:通过加载外部的jpg全景图,直接在UE4中生成Texture Cube格式

起因:我们将一张外部的jpg导入UE4后,会在资源管理器中生成Texture纹理贴图资源,然后需要将Texture纹理贴图导出成HDR,之后再将HDR导入UE4中,才会生成Texture Cube格式。如果原始jpg分辨率高,图片多的话,整个流程会特别慢。

思路:分成两部分,第一部分通过读取jpg图片数据,直接在内存中生成Texture2D。第二部分我们可以通过SceneCaptureCube这个组件,去渲染球体场景,来填充RenderTargetCube,进而生成Texture Cube格式。而球体场景可以通过第一部分的Texture2D,作为球体材质实例的图片。

一、场景:
在这里插入图片描述
在这里插入图片描述
Content/RenderTargetCube目录说明:

  • M_Sphere是母材质
  • MI_Sphere是材质实例
  • T_Init是初始的材质贴图
  • RTC_Sphere是场景中SceneCaptureCube需要用到的RenderTargetCube

场景说明:

  • 场景里有个Sphere的静态模型,我们给它赋上自己创建的材质实例,注意Sphere模型的Scale值,z是-5和镜像有关。
  • 场景在球心的位置有一个SceneCaptureCube这个Actor,设置它的TextureTarget,以及一些设置,记得勾选CaptureRotation让旋转生效。然后注意它的Rotation,也是和镜像相关。

二、代码:

  • 加载jpg,创建Texture2D,并修改MI_Sphere材质实例的贴图

.h

UFUNCTION(BlueprintCallable)
	static UTexture2D* LoadTexture(UMaterialInstanceConstant* _MaterialInstanceConstant,const FString _Path, bool& _IsValid, int32& _OutWidth, int32& _OutHeight);

.cpp

static TSharedPtr<IImageWrapper> GetImageWrapperByExtention(const FString InImagePath)
{
    
	IImageWrapperModule& mImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
	if (InImagePath.EndsWith(".png"))
	{
    
		return mImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
	}
	else if (InImagePath.EndsWith(".jpg") || InImagePath.EndsWith(".jpeg"))
	{
    
		return mImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
	}
	else if (InImagePath.EndsWith(".bmp"))
	{
    
		return mImageWrapperModule.CreateImageWrapper(EImageFormat::BMP);
	}
	else if (InImagePath.EndsWith(".ico"))
	{
    
		return mImageWrapperModule.CreateImageWrapper(EImageFormat::ICO);

	}
	else if (InImagePath.EndsWith("exr"))
	{
    
		return mImageWrapperModule.CreateImageWrapper(EImageFormat::EXR);
	}
	else if (InImagePath.EndsWith(".icns"))
	{
    
		return mImageWrapperModule.CreateImageWrapper(EImageFormat::ICNS);
	}
	return nullptr;
}

UTexture2D* UExportTextureFunctionLibrary::LoadTexture(UMaterialInstanceConstant* _MaterialInstanceConstant, const FString _Path, bool& _IsValid, int32& _OutWidth, int32& _OutHeight)
{
    
	UTexture2D* mTexture2D = nullptr;

	_IsValid = false;

	// 判断路径下是否存在图片.
	if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*_Path))
	{
    
		return nullptr;
	}

	// 从文件中加载压缩的字节数据.
	TArray<uint8> mRawFileData;
	if (!FFileHelper::LoadFileToArray(mRawFileData, *_Path))
	{
    
		return nullptr;
	}

	// 使用ImageWrapper模块检测图像类型.
	TSharedPtr<IImageWrapper> ImageWrapper = GetImageWrapperByExtention(_Path);

	// 解压图像数据.
	if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(mRawFileData.GetData(), mRawFileData.Num()))
	{
    
		TArray<uint8> mUnCompressedRGBA;

		if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, mUnCompressedRGBA))
		{
    
			// 创建Texture2D.
			mTexture2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8);
			
			if (mTexture2D != nullptr)
			{
    
				_IsValid = true;

				_OutWidth = ImageWrapper->GetWidth();

				_OutHeight = ImageWrapper->GetHeight();

				void* TextureData = mTexture2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);

				FMemory::Memcpy(TextureData, mUnCompressedRGBA.GetData(), mUnCompressedRGBA.Num());

				mTexture2D->PlatformData->Mips[0].BulkData.Unlock();

				mTexture2D->UpdateResource();
			}
		}
	}
	// 修改MI_Sphere材质实例的贴图.
	if(mTexture2D)
		UMaterialEditingLibrary::SetMaterialInstanceTextureParameterValue(_MaterialInstanceConstant, FName(TEXT("Texture")), mTexture2D);

	return mTexture2D;
}
  • 刷新SceneCaptureCube,将最新的RTC_Sphere创建TextureCube

.h

UFUNCTION(BlueprintCallable)
	static void CreateCubemap(class UTextureRenderTargetCube* _TextureRenderTargetCube, FString _PackagePath, FString _AssetName);

.cpp

void UExportTextureFunctionLibrary::CreateCubemap(class UTextureRenderTargetCube* _TextureRenderTargetCube, FString _PackagePath, FString _AssetName)
{
    
	UPackage* mPackage = CreatePackage(NULL, *_PackagePath);

	UTextureCube* mTextureCube = _TextureRenderTargetCube->ConstructTextureCube(mPackage, _AssetName, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone);

	if (mTextureCube)
	{
    
		mTextureCube->MarkPackageDirty();

		mTextureCube->GetOuter()->MarkPackageDirty();

		FAssetRegistryModule::AssetCreated(mTextureCube);

		UE_LOG(LogTemp, Log, TEXT("cube full path:%s"), *(mTextureCube->GetFullName()));
	}
}
  • 我们通过python脚本,将这两部分连接起来,能够让加载进来的jpg,生成Texture2D,并修改MI_Sphere材质实例。然后场景中的SceneCaptureCube刷新,将最新的RTC_Sphere场景生成jpg对应的TextureCube。

jpg_to_cubemap.py

import unreal
import os

# part1 这部分是从外部导入jpg,需要的Setting.
def build_auto_import_data(filenames, destination_path):
    auto_import_data = unreal.AutomatedAssetImportData()

    # set filenames that need be imported
    auto_import_data.set_editor_property("filenames", filenames)    

    # set destination_path
    auto_import_data.set_editor_property("destination_path", destination_path)

    # set replace
    auto_import_data.set_editor_property("replace_existing", True)

    return auto_import_data

# part2 这部分是通过外部的路径,将jpg导入到UE4中.
def import_jpg():
    file_dir=r'C:\Users\Administrator\Desktop\Camera\202000000000009\images'

    file_list = os.listdir(file_dir)

    jpg_list = [item for item in file_list if item.endswith('.jpg')]

    jpg_os_list=[]

    jpg_ue_list=[]
    for jpg in jpg_list:
        jpg_os = os.path.join(file_dir, jpg)
        jpg_os_list.append(jpg_os)

        asset_name = str(jpg).split('.')[1]
        jpg_ue = '/Game/Texture/' + asset_name
        jpg_ue_list.append(jpg_ue)

    import_data=build_auto_import_data(jpg_os_list, '/Game/Texture')

    unreal.AssetToolsHelpers.get_asset_tools().import_assets_automated(import_data)

    unreal.EditorAssetLibrary.save_directory('/Game/Texture')

# part3 这部分是单张图片生成Cubemap.
def create_cubemap():
    mi_asset_path = '/Game/RenderTargetCube/MI_Sphere.MI_Sphere'
    mi_asset_data = unreal.AssetRegistryHelpers.get_asset_registry().get_asset_by_object_path(mi_asset_path)
    mi_asset_object = mi_asset_data.get_asset()

    tex_asset_path = '/Game/Texture/camera_1vB44rwa.camera_1vB44rwa'
    tex_asset_data = unreal.AssetRegistryHelpers.get_asset_registry().get_asset_by_object_path(tex_asset_path)
    tex_asset_object = tex_asset_data.get_asset()
    tex_asset_name = tex_asset_data.get_editor_property('asset_name')

    unreal.MaterialEditingLibrary.set_material_instance_texture_parameter_value(mi_asset_object, 'Texture', tex_asset_object)

    rtc_asset_path = '/Game/RenderTargetCube/RTC_Sphere.RTC_Sphere'
    rtc_asset_data = unreal.AssetRegistryHelpers.get_asset_registry().get_asset_by_object_path(rtc_asset_path)
    rtc_asset_object = rtc_asset_data.get_asset()

    scene_capture_cube_array = unreal.GameplayStatics.get_all_actors_of_class(unreal.EditorLevelLibrary.get_editor_world(), unreal.SceneCaptureCube)
    scene_capture_cube = scene_capture_cube_array[0]
    capture_component_cube = scene_capture_cube.get_editor_property('capture_component_cube')
    capture_component_cube.update_content()

    cubemap_package_path = '/Game/HDR/' + str(tex_asset_name)
    unreal.ExportTextureFunctionLibrary.create_cubemap(rtc_asset_object, cubemap_package_path, str(tex_asset_name))

# part4 这部分是通过加载图片,然后生成Cubemap.
def create_cubemap_by_texture2d():
    mi_asset_path = '/Game/RenderTargetCube/MI_Sphere.MI_Sphere'
    mi_asset_data = unreal.AssetRegistryHelpers.get_asset_registry().get_asset_by_object_path(mi_asset_path)
    mi_asset_object = mi_asset_data.get_asset()

    rtc_asset_path = '/Game/RenderTargetCube/RTC_Sphere.RTC_Sphere'
    rtc_asset_data = unreal.AssetRegistryHelpers.get_asset_registry().get_asset_by_object_path(rtc_asset_path)
    rtc_asset_object = rtc_asset_data.get_asset()

    scene_capture_cube_array = unreal.GameplayStatics.get_all_actors_of_class(unreal.EditorLevelLibrary.get_editor_world(), unreal.SceneCaptureCube)
    scene_capture_cube = scene_capture_cube_array[0]
    capture_component_cube = scene_capture_cube.get_editor_property('capture_component_cube')

    file_dir = r'C:\Users\Administrator\Desktop\Camera\202000000000009\images'

    file_list = os.listdir(file_dir)

    jpg_list = [item for item in file_list if item.endswith('.jpg')]

    for jpg_name in jpg_list:
        jpg_path = os.path.join(file_dir, jpg_name)

        tex_asset_name = str(jpg_name).split('.')[0]

        unreal.ExportTextureFunctionLibrary.load_texture(mi_asset_object, jpg_path)
    
        capture_component_cube.update_content()

        cubemap_package_path = '/Game/HDR/' + str(tex_asset_name)

        unreal.ExportTextureFunctionLibrary.create_cubemap(rtc_asset_object, cubemap_package_path, str(tex_asset_name))

# part5 这部分是part3的多张图的自动化操作.
def create_cubemap_auto():
    mi_asset_path = '/Game/RenderTargetCube/MI_Sphere.MI_Sphere'
    mi_asset_data = unreal.AssetRegistryHelpers.get_asset_registry().get_asset_by_object_path(mi_asset_path)
    mi_asset_object = mi_asset_data.get_asset()

    tex_asset_path = '/Game/Texture'
    tex_asset_data_array = unreal.AssetRegistryHelpers.get_asset_registry().get_assets_by_path(tex_asset_path)

    rtc_asset_path = '/Game/RenderTargetCube/RTC_Sphere.RTC_Sphere'
    rtc_asset_data = unreal.AssetRegistryHelpers.get_asset_registry().get_asset_by_object_path(rtc_asset_path)
    rtc_asset_object = rtc_asset_data.get_asset()

    scene_capture_cube_array = unreal.GameplayStatics.get_all_actors_of_class(unreal.EditorLevelLibrary.get_editor_world(), unreal.SceneCaptureCube)
    scene_capture_cube = scene_capture_cube_array[0]
    capture_component_cube = scene_capture_cube.get_editor_property('capture_component_cube')

    for tex_asset_data in tex_asset_data_array:
        tex_asset_object = tex_asset_data.get_asset()
        tex_asset_name = tex_asset_data.get_editor_property('asset_name')

        unreal.MaterialEditingLibrary.set_material_instance_texture_parameter_value(mi_asset_object, 'Texture', tex_asset_object)

        capture_component_cube.update_content()

        cubemap_package_path = '/Game/HDR/' + str(tex_asset_name)

        unreal.ExportTextureFunctionLibrary.create_cubemap(rtc_asset_object, cubemap_package_path, str(tex_asset_name))


if __name__ == "__main__":
    # import_jpg()

    # create_cubemap_auto()

	# all 只用这个就行.
    create_cubemap_by_texture2d()

这样,整个流程大幅提升。本人测试结果:16张全景图(6720x3360),导入UE4生成TextureCube,大约10s

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangmei126/article/details/116538336

智能推荐

记录 Charles map local 的一个问题_Eric_HYD的博客-程序员宝宝

一、问题说明用 Charles map local 后一直不生效,而且一直报错。按着网上的教程一遍遍尝试后依然不行。二、解决方案你需要用手机再请求一次才行,我之前改完 map local 以后总是习惯性通过 repeat 去测试,结果每次都不成功。So,切记:map local 只能用测试机发送请求,不能用 Charles 自带的 repeat 去测试。...

msr20-20升级失败总结_weixin_34361881的博客-程序员宝宝

给某银行做bims测试,因版本需要下载好最好版本,但由于路由器是银行提供,发现版本低于msr20-cmw520-r1618,只能通过论坛下载msr20-cmw520-r1618p10-bi.bin版本进行过渡升级。升级后再升级为msr20-cmw520-r1808-bi.bin失败,路由器不断重启。通过400讯问也一直未果。尝试升级最新的版本也未果。最后通过启动信息得知如下:...

批次处理错误解决办法_混子2008的博客-程序员宝宝

<br />错误信息:<br />严重: Servlet.service() for servlet action threw exception<br />java.sql.BatchUpdateException: 批次处理 0 update public.basestation set a_id='0', bs_longitude='123.0', bs_latitude='12.0', bs_km='12.0', bs_type='8002', bs_name='测试基站3', bs_style='

python中os库安装_python下 openpyxl 库文件安装方法_weixin_39695306的博客-程序员宝宝

pip install openpyxl安装openpyxl前提必须有pip安装器啊,所以得先安装pip,easy_install和Pip都是python下的包管理工具啊用管理员权限,在解压pip文件后,执行python setup.py install但是会报错Python安装模块出错(ImportError:Nomodulenamedsetuptools)解决方法Python第三方模...

AWS认证解决方案架构助理 - AWS EC2笔记_小朋友2D的博客-程序员宝宝

Cloud Computing ServiceChoose your OS, Storage, Memory, Network Throughput.Launch and SSH into your server within minutes.Elastic Compute Cloud (EC2) is a highly configurable server.EC2 is resizable compute capacity. It takes minutes to launch new inst

SAP簇表BSEG取数优化的方法_SAP剑客的博客-程序员宝宝

BSEG于一般的透明表不同,它是一个簇表。对于一个簇表来说,除了主键项目外,其他项目都被编辑到一个长文本项目中,一起存储在表簇RFBLG中的vardata项目中,这就决定了作为簇表的BSEG无法再建立键值以外的索引(INDEX),所以一般我们对于透明表来说当主键项目不全或完全没有时,追加索引的作法对于BSEG表来说就不好用了。而BSEG簇表又是SAP系统中FI 会计模块中最常被使用的数据表,所以运

随便推点

scala中那些令你容易头晕的下划线_码农110的博客-程序员宝宝

import scala._ // Wild card -- all of Scala is importedimport scala.{ Predef =&amp;gt; _, _ } // Exception, everything except Predefdef f[M[_]] // Higher kinded type parameterdef f(m: M[_]...

CSAPP HITICS 大作业 程序人生 Hello's P2P by Giere HIT_giere_zsz的博客-程序员宝宝

计算机系统大作业题 目 程序人生-Hello’s P2P专 业 计算机类学   号 1170500820班   级 1703008学 生 *周述哲     *指 导 教 师 *郑贵滨   *计算机科学与技术学院2018年12月摘 要摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息。摘要应包括本论文的目的、主要内容、方法、成果及其理论与实...

docker部署tomcat以及web应用_一溢孤行的博客-程序员宝宝_docker tomcat部署应用

1.部署成功前提服务器上已经安装docker8080端口已开放2.开始安装tomcat2.1 拉取镜像docker pull tomcat2.2 查看所有镜像docker images2.3 启动docker镜像docker run –d -p 8080:8080 tomcat# 注意,这个启动命令不要频繁使用,否则使用一次就创建一个tomcat容器2.4 查看正在运行的容器docker ps2.5 访问ip+端口号(8080)访问到tomcat主页即成功可能遇到的问

每日新闻:腾讯与东华软件拟战略合作;云基础设施服务Q3收入超170亿美元;三星计划推出AR云服务;四部门发布科创单位税收优惠政策..._Z1Y492Vn3ZYD9et3B06的博客-程序员宝宝

关注中国软件网最新鲜的企业级干货聚集地趋势洞察《财富》:未来赚大钱的是这三类公司据美国《财富》报道指出,在应用领域,很可能会有三类“大赢家”:首先,一些拥有海量数据的互联...

SpringBoot项目集成xxl-job分布式任务调度平台_vnjohn8的博客-程序员宝宝

导向公司的开发人员说xxl-job写定时任务挺好用、简单的,于是乎去了解了一番,但是学习过程中却也遇到了一些不顺利的事情,以下是这两天所拿下的bug及其前后所部署的操作了解xxl-job架构图介绍轻量级分布式任务调度平台主要基于spring quartz 框架搭建的, 修改了任务调度的模式,采用RPC调用来实现执行器的注册和任务的调度官方文档及demo链接: https://ww...

iOS自动化打包部署踩坑记_weixin_34088583的博客-程序员宝宝

前记由于为了提高工作效率,采用自动打包来解决问题,一开始在网上也是找到了很多的教程,还是很有信心的完成这个踩坑,但是没想到坑比想象得多。有的文章甚至是抄袭、过时,导致没能按照教程直接实现。网上的教程多数是jenkins的xcode插件、证书管理的教程,但是这里一个最坑的地方就是上传了描述文件的路径也无法进行识别,导致构建版本的时候无法正确配置证书,后来放弃了此方法。以及jenkins的安装方式...