前言:使用全屏shader将cubemap转换为全景图,发现这部分内容挺少的。不过比较简单就直接贴上去罢。
00-获取测试用的cubemap
直接使用反射探针bake一个,文件放在场景文件同级
01写一个转换shader
这个shader负责转换为等距柱状图,_TestCube输入之前bake好的cubemap。
Shader "Hidden/HD/CubemapOutput"
{
Properties
{
_idx("Index", Float) = 0
_TestCube("Test Cubemap", CUBE)= ""{}
}
SubShader
{
Tags{ "RenderPipeline" = "HDRenderPipeline" }
Pass
{
Cull Off
ZTest Always
ZWrite Off
Blend Off
HLSLPROGRAM
#pragma target 4.5
#pragma vertex Vert
#pragma fragment Frag
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
// #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#define PI 3.141592653589793
#define TWOPI 6.283185307179587
TEXTURECUBE(_TestCube);
int _idx;
SAMPLER(sampler_TestCube);
struct Attributes
{
uint vertexID : SV_VertexID;
//float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
Varyings Vert(Attributes input)
{
Varyings output;
output.vertex = GetFullScreenTriangleVertexPosition(input.vertexID);
// output.vertex = TransformObjectToHClip(input.vertex.xyz);
input.uv = (output.vertex.xy/output.vertex.w + 1) * 0.5;
#ifdef UNITY_UV_STARTS_AT_TOP
input.uv.y = 1 - input.uv.y;
#endif
output.uv = input.uv * float2(TWOPI, PI);
return output;
}
float4 Frag(Varyings i) : SV_TARGET
{
float theta = i.uv.y;
float phi = i.uv.x;
float3 unit = float3(0,0,0);
unit.x = sin(phi) * sin(theta) * -1;
unit.y = cos(theta) * -1;
unit.z = cos(phi) * sin(theta) * -1;
return SAMPLE_TEXTURECUBE(_TestCube,sampler_TestCube,unit);
}
ENDHLSL
}
}
}
03输出脚本
这里写了个mono脚本,然后重写了gui,之后面板大概长这样。gui重写脚本在04节
● Load按钮:负责创建render texture,然后记录shader的输出结果
● save按钮:创建texture2D,写入数据,保存
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using System.IO;
using Object = UnityEngine.Object;
[ExecuteInEditMode]
public class OutputPano : MonoBehaviour
{
private const string SAVE_SUFFIX = ".exr";
[SerializeField] private Material m_mat;
[Serializable]
public class SaveSettings
{
public string saveDir = "Assets/Output/";
public string saveName = "CurretHDRI";
public int2 resolution = new int2(2048, 1024);
}
public SaveSettings saveSettings = new SaveSettings();
private RenderTexture _rt;
// [SerializeField] private ComputeShader _computeShader;
private int _kernelIndex;
public void Load()
{
CreateRT();
}
private void CreateRT()
{
int resolution_x = saveSettings.resolution.x;
int resolution_y = saveSettings.resolution.y;
// m_mat = GetComponent<Renderer>().sharedMaterial;
_rt = new RenderTexture(resolution_x, resolution_y, 0, RenderTextureFormat.ARGBFloat){enableRandomWrite = true};//GraphicsFormat.R16G16B16A16_SFloat
_rt.Create();
Graphics.Blit(_rt, _rt,m_mat);
}
private void SaveTex(Texture2D tex)
{
string save_path = saveSettings.saveDir + saveSettings.saveName + SAVE_SUFFIX;
byte[] exrData = tex.EncodeToEXR();
File.WriteAllBytes(save_path,exrData);
Debug.Log("Success " + save_path);
}
public void ShadeRTtoTex()
{
Texture2D texTosave = new Texture2D(saveSettings.resolution.x,saveSettings.resolution.y, TextureFormat.RGBAFloat, false);
// RenderTexture.active = _rt;
Graphics.SetRenderTarget(_rt);
texTosave.ReadPixels(new Rect(0,0,saveSettings.resolution.x,saveSettings.resolution.y),0,0);
texTosave.Apply();
string save_path = saveSettings.saveDir + saveSettings.saveName + SAVE_SUFFIX;
byte[] exrData = ImageConversion.EncodeToEXR(texTosave);
File.WriteAllBytes(@save_path,exrData);
Debug.Log("Success " + save_path);
//RenderTexture.active = null;
Object.DestroyImmediate(texTosave);
}
}
04 GUI
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(OutputPano))]
public class OutputPanoScriptEditor : Editor
{
private OutputPano instance;
private void OnEnable()
{
instance = target as OutputPano;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
GUILayout.Space(30);
if (GUILayout.Button("Load", GUILayout.Height(30)))
{
instance.Load();
}
GUILayout.Space(30);
if (GUILayout.Button("Save To Disk", GUILayout.Height(30)))
{
instance.ShadeRTtoTex2();
}
}
}