您需要 登录 才可以下载或查看,没有账号?注册
x
Hello . 大家好 今天给大家带来的是U3D渲染到CubeMap的切图保存工具 我是麦田
1
需求
因为自研引擎写GLSL暂时不支持直接采样HDR,只能够支持原生的6图模式的图片合成,如果通过手动切太浪费时间了,目前本插件还没有完善到完全自动化的程度,但是实现了基本的功能。
2
实现需求
Cube Map 通常在渲染引擎中充当天空盒、反射贴图等重要角色。Cube Map的制作往往通过采集的HDR图或者在3D渲染软件中渲染生成。一张完整的Cube Map 包含前后左右上下六张图。但是在一些特定平台并不能直接使用exr等其他HDR图,例如three.js H5 平台(使用纯原生threejs引擎的是支持的),所以就需要生成通用的6张PNG(不一定是PNG)的图。
如下图,这一个是Unity烘焙面板用来烘焙环境贴图的参数面板,本着实时渲染在手机端能省就省的原则,Unity这里采取的也是一个预先烘焙好环境贴图的方式(预积分),为了让贴图分辨率高一点,我这里设置成了1024。
Unity烘焙后的probe如下图,是被排列成一个6*1的矩阵形式的。Unity烘焙后的probe如下图,是被排列成一个6*1的矩阵形式的。
如何在Unity3D引擎中快速方便的生成六张图呢?下面,我们就开始编写。
我们先搭建一个用于渲染的场景:
通过引擎烘焙出一张 EXR 图(也可以直接使用Reflection Probe 来生成),插件还没有做到一件自动,这一步其实可以通过脚本调用的。
先添加一个 Reflection Probe 并调整好位置与角度。
然后在Unity中渲染反射贴图,渲染效果如下。
在Inspector面板将贴图标记为可读,否则会无法访问。
选择插件并切分:
插件主要功能是读取Cube Map 并生成六张图。
选择菜单栏后选择一张CubeMap(标记可读取后的),弹出路径选择面板后保存
建立对应的六张图片数组并将六张图片命名,方便调用:(代码都写了注释,纯API调用,没有难点,这里不再赘述)-
- var idx = (int)CubemapFace.PositiveX;
- var count = (int)CubemapFace.NegativeZ + 1;
- //使用一个 list 来存储cubemap的图片
- List<PickupCubemapTexInfo> texs = new List<PickupCubemapTexInfo>();
- Dictionary<CubemapFace, string> nameMap = new Dictionary<CubemapFace, string>();
- //设置存储的名称
- nameMap[CubemapFace.PositiveX] = "Right";
- nameMap[CubemapFace.NegativeX] = "Left";
- nameMap[CubemapFace.PositiveY] = "Upwards";
- nameMap[CubemapFace.NegativeY] = "Downward";
- nameMap[CubemapFace.PositiveZ] = "Forward";
- nameMap[CubemapFace.NegativeZ] = "Backward";
点击此处复制文本 使用字节流对每个图片进行编码与存储,注意填写图片大小,防止失真。
-
- if (string.IsNullOrEmpty(foldername) || !Directory.Exists(foldername))
- {
- // noop
- }
- else
- {
- //循环读出图片数据
- for (; idx < count; idx++)
- {
- var face = (CubemapFace)idx;
- var ps = cubemap.GetPixels(face);
- // 注意这里的texture2d 的width, height对应cubemap中的face size,但类中没定义,所以这里匹配好你的cubemap来使用就好了
- var newTex = new Texture2D(cubemap.width, cubemap.height);
- newTex.SetPixels(ps);
- texs.Add(new PickupCubemapTexInfo { tex = newTex, name = nameMap[face] });
- }
- foldername = foldername.Replace("\", "/");
- var cd = Directory.GetParent(Path.GetFullPath("Assets")).FullName;
- cd = cd.Replace("\", "/");
- Debug.Log([ DISCUZ_CODE_1 ]quot;cd:{cd}");
- foldername = Path.Combine(foldername, Selection.activeObject.name);
- if (!Directory.Exists(foldername))
- {
- Directory.CreateDirectory(foldername);
- }
- foldername = foldername.Replace("\", "/");
- Debug.Log([ DISCUZ_CODE_1 ]quot;append assetsname folder:{foldername}");
- //循环并输出图片资源
- foreach (var item in texs)
- {
- var fullname = Path.Combine(foldername, item.name + ".png");
- fullname = fullname.Replace("\", "/");
- fullname = fullname.Replace(cd + "/", "");
- Debug.Log([ DISCUZ_CODE_1 ]quot;fullname:{fullname}");
- //注意:图片可能上下反转 ,此步是将图片反转回来
- var tex = VerticalFlipTexture(item.tex);
- var bs = tex.EncodeToPNG();
- var fs = File.Open(fullname, FileMode.Create, FileAccess.Write);
- fs.Write(bs, 0, bs.Length);
- fs.Close();
- fs.Dispose();
- }
- AssetDatabase.SaveAssets();//保存资源
- AssetDatabase.Refresh();//刷新资源面板
- }
- }
点击此处复制文本
最后可以加一个进度条,方便查看进度。
-
- //加载一个可视化的进度条
- var title = "Select the directory which stored CubeMap Tex.";
- var filepath = AssetDatabase.GetAssetPath(Selection.activeObject);
- var folder = Directory.GetParent(filepath);
- var foldername = EditorUtility.OpenFolderPanel(title, folder.ToString(), string.Empty);
点击此处复制文本 之后使用插件将六张图片输出。
这六张图片可以作为反射贴图,也可以作为天空盒。下图是天空盒以及金属反射效果,使用Unity自带的CubeMapShader即可显示。
最后贴出插件代码,在Unity本地新建一个Editor文件后放入,即可使用。
-
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEditor;
- using System.IO;
- public class ReadEXRToPNG : Editor
- {
- [MenuItem("CustomTool/Cut CubeMap", false, 2)]
- public static void EXR2PNG()
- {
- Cubemap cubemap = null;
- Debug.Log(Selection.activeObject.GetType());
- //判断所选资源类型并过滤 Cubemap 资源
- if (Selection.activeObject.GetType() == typeof(Cubemap))
- {
- cubemap = Selection.activeObject as Cubemap;
- }
- //为空则跳出并报警告
- if (cubemap == null)
- {
- Debug.LogWarning([ DISCUZ_CODE_3 ]quot;Selecting one cubemap.");
- return;
- }
- var idx = (int)CubemapFace.PositiveX;
- var count = (int)CubemapFace.NegativeZ + 1;
- //使用一个 list 来存储cubemap的图片
- List<PickupCubemapTexInfo> texs = new List<PickupCubemapTexInfo>();
- Dictionary<CubemapFace, string> nameMap = new Dictionary<CubemapFace, string>();
- //设置存储的名称
- nameMap[CubemapFace.PositiveX] = "Right";
- nameMap[CubemapFace.NegativeX] = "Left";
- nameMap[CubemapFace.PositiveY] = "Upwards";
- nameMap[CubemapFace.NegativeY] = "Downward";
- nameMap[CubemapFace.PositiveZ] = "Forward";
- nameMap[CubemapFace.NegativeZ] = "Backward";
- try
- {
- //加载一个可视化的进度条
- var title = "Select the directory which stored CubeMap Tex.";
- var filepath = AssetDatabase.GetAssetPath(Selection.activeObject);
- var folder = Directory.GetParent(filepath);
- var foldername = EditorUtility.OpenFolderPanel(title, folder.ToString(), string.Empty);
- if (string.IsNullOrEmpty(foldername) || !Directory.Exists(foldername))
- {
- // noop
- }
- else
- {
- //循环读出图片数据
- for (; idx < count; idx++)
- {
- var face = (CubemapFace)idx;
- var ps = cubemap.GetPixels(face);
- // 注意这里的texture2d 的width, height对应cubemap中的face size,但类中没定义,所以这里匹配好你的cubemap来使用就好了
- var newTex = new Texture2D(cubemap.width, cubemap.height);
- newTex.SetPixels(ps);
- texs.Add(new PickupCubemapTexInfo { tex = newTex, name = nameMap[face] });
- }
- foldername = foldername.Replace("\", "/");
- var cd = Directory.GetParent(Path.GetFullPath("Assets")).FullName;
- cd = cd.Replace("\", "/");
- Debug.Log([ DISCUZ_CODE_3 ]quot;cd:{cd}");
- foldername = Path.Combine(foldername, Selection.activeObject.name);
- if (!Directory.Exists(foldername))
- {
- Directory.CreateDirectory(foldername);
- }
- foldername = foldername.Replace("\", "/");
- Debug.Log([ DISCUZ_CODE_3 ]quot;append assetsname folder:{foldername}");
- //循环并输出图片资源
- foreach (var item in texs)
- {
- var fullname = Path.Combine(foldername, item.name + ".png");
- fullname = fullname.Replace("\", "/");
- fullname = fullname.Replace(cd + "/", "");
- Debug.Log([ DISCUZ_CODE_3 ]quot;fullname:{fullname}");
- //注意:图片可能上下反转 ,此步是将图片反转回来
- var tex = VerticalFlipTexture(item.tex);
- var bs = tex.EncodeToPNG();
- var fs = File.Open(fullname, FileMode.Create, FileAccess.Write);
- fs.Write(bs, 0, bs.Length);
- fs.Close();
- fs.Dispose();
- }
- AssetDatabase.SaveAssets();//保存资源
- AssetDatabase.Refresh();//刷新资源面板
- }
- }
- catch (Exception er)
- {
- Debug.LogError(er);
- }
- finally
- {
- foreach (var item in texs)
- {
- Texture2D.DestroyImmediate(item.tex);
- }
- texs.Clear();
- }
- }
- //垂直翻转
- public static Texture2D VerticalFlipTexture(Texture2D texture)
- {
- //得到图片的宽高
- int width = texture.width;
- int height = texture.height;
- Texture2D flipTexture = new Texture2D(width, height);
- for (int i = 0; i < height; i++)
- {
- flipTexture.SetPixels(0, i, width, 1, texture.GetPixels(0, height - i - 1, width, 1));
- }
- flipTexture.Apply();
- return flipTexture;
- }
- }
- public class PickupCubemapTexInfo
- {
- public Texture2D tex;
- public string name;
- }
点击此处复制文本- End -
|