Unity 生成原始LUT用于外部校色&相机不透明物体截图

在游戏制作后期,项目如果需要风格化校色会设置一个全局优先级最高的volume组件用于应用校色
勤快的项目组一般会准备多种预调色配置,调整各种校色组件及参数
一些的则会从网上直接下载成套校色图,替换color lookup组件中的素材

那么继续说懒的方式,如果需要有一两个特殊定制的风格效果时,下载的素材就体现出了不可定制性
我们可以通过unity导出lookup table,导入到各种校色工具中校色,再输出回unity的做法来实现

C#

public class ExportTEST : EditorWindow
{
     public enum TextureType
     {
          png = 0,
          exr = 1
     }
     private string _filePath = "...";
     private Material _mat;
     private TextureType _textureType = TextureType.png;
     
     [MenuItem("*TEST*/导出场景HDR格式图片")]
     private static void Init()
     {
          ExportHDR window = GetWindowWithRect<ExportHDR>(new Rect(0,0,300,150));
          window.titleContent = new GUIContent("导出HDR格式场景截图");
          window.Show();
     }

     private void OnGUI()
     {
          GUILayout.Label("保存到:" + _filePath);
          if (GUILayout.Button("保存位置"))
          {
               _filePath = EditorUtility.OpenFolderPanel("", "", "");
          }
          _textureType = (TextureType)EditorGUILayout.EnumPopup("选择LUT保存格式",_textureType);

          if (GUILayout.Button("生成原始LUT"))
          {
               try
               {
                    CreateLUTBase();
               }
               catch (Exception e)
               {
                    Console.WriteLine(e);
                    throw;
               }
          }
          if (GUILayout.Button("生成原始场景截图(tga)"))
          {
               try
               {
                    CreateSceneBase();
               }
               catch (Exception e)
               {
                    Console.WriteLine(e);
                    throw;
               }
          }
     }
     
    //我们在打开其他窗口时,焦点不在game视口,获得的screen宽高是激活窗口的
     public static Vector2 GetMainGameViewSize()
     {
     //通过反射获取game宽高
          System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
          System.Reflection.MethodInfo GetSizeOfMainGameView = T.GetMethod("GetSizeOfMainGameView",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
          System.Object Res = GetSizeOfMainGameView.Invoke(null,null);
          return (Vector2)Res;
     }
     
     void CreateSceneBase(out string state)
     {
          var path = _filePath + "/SceneColor_Base.tga";
          if(File.Exists(path)) File.Delete(path);
          
          if (_mat == null)
          {
               _mat = CoreUtils.CreateEngineMaterial("Hidden/ExportRT");
          }

          Vector2 size = GetMainGameViewSize();

			//这里只是设置图的宽高,实际图像尺寸需要在pipeline设置opaque图压缩质量
          RenderTexture rt = new RenderTexture((int)size.x, (int)size.y, 0);
          rt.format = RenderTextureFormat.ARGBFloat;
          rt.enableRandomWrite = true;
          rt.wrapMode = TextureWrapMode.Clamp;
          rt.Create();
          
          Graphics.Blit(null, rt, _mat);
          
          var originalRT = RenderTexture.active;
          RenderTexture.active = rt;
          
          var tex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
          tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
          tex.Apply();
          
          var bytes = tex.EncodeToTGA(EncodeToTGAExtension.Compression.None);
          if(File.Exists(path)) File.Delete(path);
          File.WriteAllBytes(path, bytes);
          DestroyImmediate(tex);
          rt.Release();
          RenderTexture.active = originalRT;
     }
     
     void CreateLUTBase(out string state)
     {
          var path = _filePath;
          if(File.Exists(path)) File.Delete(path);
//这里根据pipeline设置给参数,ldr是1024x32
          var tex = new Texture2D(1024,32, TextureFormat.RGBAFloat, false);
          tex.wrapMode = TextureWrapMode.Clamp;
          tex.filterMode = FilterMode.Point;
          
          var colors = new Color[1024,32];
          for (var b = 0; b < 32; b++)
          {
               for (var g = 0; g < 32; g++)
               {
                    for (var r = 0; r < 32; r++)
                    {
                         colors[r + b * 32, g] = new Color(r/32f,g/32f,b/32f);
                    }
               }
          }
          for (var h = 0; h < 1024; h++)
          {
               for (var v = 0; v < 32; v++)
               {
                    tex.SetPixel(h, v, colors[h, v]) ;
               }
          }
          tex.Apply();
          byte[] bytes;
          switch (_textureType)
          {
               case TextureType.png:
                    bytes=tex.EncodeToPNG();
                    path = path +"/UnityLUT_Base.png";
                    if(File.Exists(path)) File.Delete(path);
                    File.WriteAllBytes(path,bytes);
                    break;
               case TextureType.exr:
                    bytes=tex.EncodeToEXR(Texture2D.EXRFlags.None);
                    path = path +"/UnityLUT_Base.exr";
                    if(File.Exists(path)) File.Delete(path);
                    File.WriteAllBytes(path,bytes);
                    break;
          }
          
          DestroyImmediate(tex);
     }

}

Shader

Shader "Hidden/ExportRT"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D_float _CameraOpaqueTexture;
            //sampler2D_float _MainTex;
            
            float3 LinearToSRGB(float3 c)
            {
                float3 sRGBLo = c * 12.92;
                float3 sRGBHi = (pow(abs(c), float3(1.0/2.4, 1.0/2.4, 1.0/2.4)) * 1.055) - 0.055;
                float3 sRGB   = (c <= 0.0031308) ? sRGBLo : sRGBHi;
                return sRGB;
            }
            
            half3 SRGBToLinear(half3 c)
            {
                half3 linearRGBLo = c / 12.92;
                half3 linearRGBHi = pow(abs((c + 0.055) / 1.055), 2.4);
                half3 linearRGB = (c <= 0.04045) ? linearRGBLo : linearRGBHi;
                return linearRGB;
            }
     
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                // sample the texture
                float4 col = tex2D(_CameraOpaqueTexture, i.uv);
                //opaque图为linear状态,输出到图需要转sRGB,本身color lookup回读的也是sRGB图
                return float4(LinearToSRGB(col.rgb), col.a);
            }
            ENDCG
        }
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值