Unity 3D : 解 3D LUT Cube 檔案

前言 :

解 3D LUT Cube 檔案

執行結果 :

这里写图片描述

偷吃步作法 :

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class Run : MonoBehaviour
{
    public Transform par;
    public Transform obj;

    void Start()
    {
        Cube cube = new Cube();

        float[,,,] cube_color64 = cube.GetCube("C:/A/My.cube");

        print("cube.size : " + cube.size);
        
        float[,,,] cube_color256 = new float[256, 256, 256, 3];

        int oSize = cube.size - 1;

        int targetSize = 256;

		// 預設是 += 8, 所以有空格,如果你用 ++,小心爆炸 !
        for (int z = 0; z < targetSize; z += 8)
        {
            for (int y = 0; y < targetSize; y += 8)
            {
                for (int x = 0; x < targetSize; x += 8)
                {
                    float targetX = x * (oSize / (float)targetSize);
                    float targetY = y * (oSize / (float)targetSize);
                    float targetZ = z * (oSize / (float)targetSize);

                    int x0 = (int)targetX;
                    int y0 = (int)targetY;
                    int z0 = (int)targetZ;
                    int x1 = x0 + 1;
                    int y1 = y0 + 1;
                    int z1 = z0 + 1;

                    float X = targetX - x1;
                    float Y = targetY - y1;
                    float Z = targetZ - z1;

                    float w1 = (1 - X) * (1 - Y) * (1 - Z);
                    float w2 = X * (1 - Y) * (1 - Z);
                    float w3 = (1 - X) * Y * (1 - Z);
                    float w4 = (1 - X) * (1 - Y) * Z;
                    float w5 = X * (1 - Y) * Z;
                    float w6 = (1 - X) * Y * Z;
                    float w7 = X * Y * (1 - Z);
                    float w8 = X * Y * Z;
                    
                    Color c000 = new Color(cube_color64[x0, y0, z0, 0], cube_color64[x0, y0, z0, 1], cube_color64[x0, y0, z0, 2]);
                    Color c100 = new Color(cube_color64[x1, y0, z0, 0], cube_color64[x1, y0, z0, 1], cube_color64[x1, y0, z0, 2]);
                    Color c010 = new Color(cube_color64[x0, y1, z0, 0], cube_color64[x0, y1, z0, 1], cube_color64[x0, y1, z0, 2]);
                    Color c001 = new Color(cube_color64[x0, y0, z1, 0], cube_color64[x0, y0, z1, 1], cube_color64[x0, y0, z1, 2]);
                    Color c101 = new Color(cube_color64[x1, y0, z1, 0], cube_color64[x1, y0, z1, 1], cube_color64[x1, y0, z1, 2]);
                    Color c011 = new Color(cube_color64[x0, y1, z1, 0], cube_color64[x0, y1, z1, 1], cube_color64[x0, y1, z1, 2]);
                    Color c110 = new Color(cube_color64[x1, y1, z0, 0], cube_color64[x1, y1, z0, 1], cube_color64[x1, y1, z0, 2]);
                    Color c111 = new Color(cube_color64[x1, y1, z1, 0], cube_color64[x1, y1, z1, 1], cube_color64[x1, y1, z1, 2]);

                    Transform t = Instantiate<Transform>(obj);
                    t.position = new Vector3(x, y, z);

                    t.GetComponent<Renderer>().material.color = new Color(
                        c000.r * w1 + c100.r * w2 + c010.r * w3 + c001.r * w4 + c101.r * w5 + c011.r * w6 + c110.r * w7 + c111.r * w8,
                        c000.g * w1 + c100.g * w2 + c010.g * w3 + c001.g * w4 + c101.g * w5 + c011.g * w6 + c110.g * w7 + c111.g * w8,
                        c000.b * w1 + c100.b * w2 + c010.b * w3 + c001.b * w4 + c101.b * w5 + c011.b * w6 + c110.b * w7 + c111.b * w8
                        );
                }
            }
        }
    }

    bool isShowCube = false;

    void ShowCube(float[,,,] cube_color)
    {
        isShowCube = true;
        for (int z = 0; z < cube_color.GetLength(2); z += 2)
        {
            for (int y = 0; y < cube_color.GetLength(1); y += 2)
            {
                for (int x = 0; x < cube_color.GetLength(0); x += 2)
                {
                    float R = cube_color[x, y, z, 0];
                    float G = cube_color[x, y, z, 1];
                    float B = cube_color[x, y, z, 2];

                    Transform t = Instantiate<Transform>(obj);
                    t.parent = par;
                    t.localPosition = new Vector3(R, G, B) * 48;
                    t.GetComponent<Renderer>().material.color = new Color(R, G, B);
                }
            }
        }
    }
}

好一點的作法 :

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class LUT3D : MonoBehaviour
{
    public Transform par;
    public Transform obj;

    public Texture2D inpurtTexture;
    public RawImage outputImage;


    void Start()
    {
        //float[,,,] table = LoadTable("C:/A/My.cube");

        float[,,,] table = LoadTable("C:/A/Fuji.cube");
        //float[,,,] table = LoadTable("C:/A/FLog_FGamut_to_FLog_BT.709_33grid_V.1.00.cube");


        //ShowCube(LoadTable("C:/A/Fuji.cube"), 8);
        //ShowCube(new Cube().GetCube("C:/A/Fuji.cube"), 1);

        //ShowCube(LoadTable("C:/A/My.cube"), 8);
        //ShowCube(new Cube().GetCube("C:/A/My.cube"), 2);

        //ShowCube(LoadTable("C:/A/FLog_FGamut_to_FLog_BT.709_33grid_V.1.00.cube"), 8);
        //ShowCube(new Cube().GetCube("C:/A/FLog_FGamut_to_FLog_BT.709_33grid_V.1.00.cube"), 1);



        Texture2D t = new Texture2D(inpurtTexture.width, inpurtTexture.height, TextureFormat.RGBAFloat, false);

        for (int y = 0; y < t.height; y++)
        {
            for (int x = 0; x < t.width; x++)
            {
                Color c = inpurtTexture.GetPixel(x, y);
                int r = Mathf.CeilToInt(c.r * 255);
                int g = Mathf.CeilToInt(c.g * 255);
                int b = Mathf.CeilToInt(c.b * 255);

                float R = table[r, g, b, 0];
                float G = table[r, g, b, 1];
                float B = table[r, g, b, 2];

                t.SetPixel(x, y, new Color(R, G, B));
            }
        }

        t.Apply();
        outputImage.texture = t;
    }

    float[,,,] LoadTable(string path)
    {
        Cube cube = new Cube();

        float[,,,] cube_color64 = cube.GetCube(path);

        print("cube.size : " + cube.size);

        float[,,,] cube_color256 = new float[256, 256, 256, 3];

        int oSize = cube.size;

        int targetSize = 256;

        int scale = targetSize / oSize;

        print("scale : " + scale);

        for (int z = 0; z < targetSize - scale; z++)
        {
            for (int y = 0; y < targetSize - scale; y++)
            {
                for (int x = 0; x < targetSize - scale; x++)
                {
                    float targetX = x * (oSize / (float)targetSize);
                    float targetY = y * (oSize / (float)targetSize);
                    float targetZ = z * (oSize / (float)targetSize);

                    int x0 = (int)targetX; // 0~63
                    int y0 = (int)targetY;
                    int z0 = (int)targetZ;

                    int x1 = x0 + 1; // 1~64
                    int y1 = y0 + 1;
                    int z1 = z0 + 1;

                    float X = targetX - x0;
                    float Y = targetY - y0;
                    float Z = targetZ - z0;

                    Color c000 = new Color(cube_color64[x0, y0, z0, 0], cube_color64[x0, y0, z0, 1], cube_color64[x0, y0, z0, 2]);
                    Color c100 = new Color(cube_color64[x1, y0, z0, 0], cube_color64[x1, y0, z0, 1], cube_color64[x1, y0, z0, 2]);
                    Color c010 = new Color(cube_color64[x0, y0, z1, 0], cube_color64[x0, y0, z1, 1], cube_color64[x0, y0, z1, 2]);
                    Color c001 = new Color(cube_color64[x0, y1, z0, 0], cube_color64[x0, y1, z0, 1], cube_color64[x0, y1, z0, 2]);
                    Color c101 = new Color(cube_color64[x1, y1, z0, 0], cube_color64[x1, y1, z0, 1], cube_color64[x1, y1, z0, 2]);
                    Color c011 = new Color(cube_color64[x0, y1, z1, 0], cube_color64[x0, y1, z1, 1], cube_color64[x0, y1, z1, 2]);
                    Color c110 = new Color(cube_color64[x1, y0, z1, 0], cube_color64[x1, y0, z1, 1], cube_color64[x1, y0, z1, 2]);
                    Color c111 = new Color(cube_color64[x1, y1, z1, 0], cube_color64[x1, y1, z1, 1], cube_color64[x1, y1, z1, 2]);

                    Color c00 = new Color(Mathf.Lerp(c000.r, c100.r, X), Mathf.Lerp(c000.g, c100.g, X), Mathf.Lerp(c000.b, c100.b, X));
                    Color c01 = new Color(Mathf.Lerp(c001.r, c101.r, X), Mathf.Lerp(c001.g, c101.g, X), Mathf.Lerp(c001.b, c101.b, X));
                    Color c10 = new Color(Mathf.Lerp(c010.r, c110.r, X), Mathf.Lerp(c010.g, c110.g, X), Mathf.Lerp(c010.b, c110.b, X));
                    Color c11 = new Color(Mathf.Lerp(c011.r, c111.r, X), Mathf.Lerp(c011.g, c111.g, X), Mathf.Lerp(c011.b, c111.b, X));

                    Color c0 = new Color(Mathf.Lerp(c00.r, c10.r, Z), Mathf.Lerp(c00.g, c10.g, Z), Mathf.Lerp(c00.b, c10.b, Z));
                    Color c1 = new Color(Mathf.Lerp(c01.r, c11.r, Z), Mathf.Lerp(c01.g, c11.g, Z), Mathf.Lerp(c01.b, c11.b, Z));

                    Color c = new Color(Mathf.Lerp(c0.r, c1.r, Y), Mathf.Lerp(c0.g, c1.g, Y), Mathf.Lerp(c0.b, c1.b, Y));

                    cube_color256[x, y, z, 0] = c.r;
                    cube_color256[x, y, z, 1] = c.g;
                    cube_color256[x, y, z, 2] = c.b;

                    //print(Mathf.CeilToInt(c.r * 255));

                    // 最後一個
                    int end = targetSize - scale - 1;
                    if (x == end || y == end || z == end)
                    {
                        for (int k = 1; k < scale + 1; k++)
                        {
                            // 這邊也要做插值,目前沒做
                            float r = cube_color64[x1, y1, z1, 0];
                            float g = cube_color64[x1, y1, z1, 1];
                            float b = cube_color64[x1, y1, z1, 2];

                            cube_color256[x + k, y + k, z + k, 0] = r;
                            cube_color256[x + k, y + k, z + k, 1] = g;
                            cube_color256[x + k, y + k, z + k, 2] = b;
                        }
                    }
                }
            }
        }
        return cube_color256;
    }

    void ShowCube(float[,,,] cube_color, int step)
    {
        for (int z = 0; z < cube_color.GetLength(2); z += step)
        {
            for (int y = 0; y < cube_color.GetLength(1); y += step)
            {
                for (int x = 0; x < cube_color.GetLength(0); x += step)
                {
                    float R = cube_color[x, y, z, 0];
                    float G = cube_color[x, y, z, 1];
                    float B = cube_color[x, y, z, 2];

                    Transform t = Instantiate<Transform>(obj);
                    t.parent = par;
                    t.localPosition = new Vector3(R, G, B) * 48;
                    t.GetComponent<Renderer>().material.color = new Color(R, G, B);

                    //print((int)(R * 255));
                }
            }
        }
    }
}

Cube.cs :

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class Cube
{
    public string title;
    public int size;

    public float[,,,] GetCube(string path)
    {
        string[] lines = File.ReadAllLines(path);

        int index = 0;

        //index = GetTitle(lines, index, out title);
        //print("[ " + index + " ] Title : " + title);

        index = GetLut3DSize(lines, index, out size);
        //print("[ " + index + " ] LUT 3D Size : " + lut3DSize);

        float[,,,] cube = new float[size, size, size, 3]; // X, Y, Z, RGB

        int allSize = size * size * size;

        int x = 0, y = 0, z = 0;

        for (int i = index, k = 0; k < allSize; i++)
        {
            string line = lines[i];
            if (CanRead(line) == false) continue;

            string[] s = line.Split(' ');

            float R = float.Parse(s[0]);
            float G = float.Parse(s[1]);
            float B = float.Parse(s[2]);

            x = k % size;

            cube[x, y, z, 0] = R;
            cube[x, y, z, 1] = G;
            cube[x, y, z, 2] = B;

            if (x == size-1)
            {
                if (y == size-1)
                {
                    y = 0;
                    z++;
                }
                else
                {
                    y++;
                }
            }
            k++;
        }

        return cube;
    }

    bool CanRead(string line)
    {
        if (line.Length == 0) return false;
        if (line[0] == '#') return false;
        return true;
    }

    // 讀完後,指針往後一格
    int GetTitle(string[] lines, int index, out string title)
    {
        title = null;
        for (int i = index; i < lines.Length; i++)
        {
            string s = lines[i];
            if (s.IndexOf("TITLE") != -1)
            {
                int start = s.IndexOf("\"") + 1;
                int end = s.LastIndexOf("\"");
                int length = end - start;
                title = s.Substring(start, length);
                index = i + 1;
                break;
            }
        }
        return index;
    }

    // 讀完後,指針往後一格
    int GetLut3DSize(string[] lines, int index, out int size)
    {
        size = -1;
        for (int k = index; k < lines.Length; k++)
        {
            string s = lines[k];
            if (s.IndexOf("LUT_3D_SIZE") != -1)
            {
                string[] ss = s.Split(' ');
                for (int i = 1; i < ss.Length; i++)
                {
                    if (int.TryParse(ss[i], out size))
                    {
                        index = k + 1;
                        break;
                    }
                }
                break;
            }
        }
        return index;
    }
}

參考 :

https://www.lightillusion.com/luts.html
http://www.fallenempiredigital.com/blog/2012/12/04/luts-part-1-what-is-a-lut/
https://en.wikipedia.org/wiki/3D_lookup_table

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值