Unity中写GLSL(十八)—— 创建Diffuse环境贴图和Specular环境贴图

本文介绍了一个Unity编辑器脚本,用于从原始立方体贴图生成漫反射和高光环境贴图。通过迭代所有像素并计算权重来实现光照整合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考了WIKI:https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Many_Light_Sources
具体的可以到这个wiki上面去看,我这里只给结果。(写太多东西太麻烦。。。)
这是生成的Diffuse环境贴图:
这里写图片描述

这是生成的Specular环境贴图:
这里写图片描述

下面是代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public enum EnvMapType
{
    Diffuse,
    Specular,
}

public class BuildEnvMap
{
    public static Cubemap originalCubeMap;
    public static Cubemap filteredCubeMap;

    public static string diffuseEnvMapPath = "Assets/Shader/PBR/Editor/DiffuseEnvMap.cubemap";
    public static string specularEnvMapPath = "Assets/Shader/PBR/Editor/SpecularEnvMap.cubemap";

    public static EnvMapType mapType;

    [MenuItem("CubeMap/BuildDiffuseEnvMap")]
    public static void BuildDiffuseEnvironmentMap()
    {
        mapType = EnvMapType.Diffuse;
        originalCubeMap = Selection.activeObject as Cubemap;
        if (originalCubeMap == null)
        {
            Debug.LogError ("没选中CubeMap吗???");
        }
        else
        {
            ComputeFilteredCubeMap ();

            if (filteredCubeMap != null)
            {
                AssetDatabase.CreateAsset (filteredCubeMap, diffuseEnvMapPath);
                Debug.Log("创建DiffuseEnvMap成功!!!");
            }
            else
            {
                Debug.LogError ("filteredCubeMap创建失败了?");
            }
        }
    }

    [MenuItem("CubeMap/BuildSpecularEnvMap")]
    public static void BuildSpecularEnvironmentMap()
    {
        mapType = EnvMapType.Specular;
        originalCubeMap = Selection.activeObject as Cubemap;
        if (originalCubeMap == null)
        {
            Debug.LogError ("没选中CubeMap吗???");
        }
        else
        {
            ComputeFilteredCubeMap ();

            if (filteredCubeMap != null)
            {
                AssetDatabase.CreateAsset (filteredCubeMap, specularEnvMapPath);
                Debug.Log("创建SpecularEnvMap成功!!!");
            }
            else
            {
                Debug.LogError ("filteredCubeMap创建失败了?");
            }
        }
    }

    public static Cubemap ComputeFilteredCubeMap()
    {
        filteredCubeMap = new Cubemap(originalCubeMap.width, 
            originalCubeMap.format, true);

        int filteredSize = filteredCubeMap.width;
        int originalSize = originalCubeMap.width;

        // Compute all texels of the diffuse environment cube map 
        // by itterating over all of them
        for (int filteredFace = 0; filteredFace < 6; filteredFace++) 
            // the six sides of the cube
        {
            for (int filteredI = 0; filteredI < filteredSize; filteredI++)
            {
                for (int filteredJ = 0; filteredJ < filteredSize; filteredJ++)
                {
                    Vector3 filteredDirection = 
                        GetDirection(filteredFace, 
                            filteredI, filteredJ, filteredSize).normalized;
                    float totalWeight = 0.0f;
                    Vector3 originalDirection;
                    Vector3 originalFaceDirection;
                    float weight;
                    Color filteredColor = new Color(0.0f, 0.0f, 0.0f);

                    // sum (i.e. integrate) the diffuse illumination 
                    // by all texels in the original environment map
                    for (int originalFace = 0; originalFace < 6; originalFace++)
                    {
                        originalFaceDirection = GetDirection(
                            originalFace, 1, 1, 3).normalized; 
                        //the normal vector of the face

                        for (int originalI = 0; originalI < originalSize; originalI++)
                        {
                            for (int originalJ = 0; originalJ < originalSize; originalJ++)
                            {
                                originalDirection = GetDirection(
                                    originalFace, originalI, 
                                    originalJ, originalSize); 
                                // direction to the texel 
                                // (i.e. light source)
                                weight = 1.0f 
                                    / originalDirection.sqrMagnitude; 
                                // take smaller size of more 
                                // distant texels into account
                                originalDirection = 
                                    originalDirection.normalized;
                                weight = weight * Vector3.Dot(
                                    originalFaceDirection, 
                                    originalDirection); 
                                // take tilt of texel compared 
                                // to face into account
                                switch (mapType)
                                {
                                case EnvMapType.Diffuse:
                                    weight = weight * Mathf.Max(0.0f, 
                                        Vector3.Dot(filteredDirection, 
                                            originalDirection)); 
                                    break;
                                case EnvMapType.Specular:
                                    weight = weight * Mathf.Pow(Mathf.Max(0.0f, 
                                        Vector3.Dot(filteredDirection, 
                                            originalDirection)), 50.0f);
                                    break;
                                default:
                                    break;
                                }

                                totalWeight = totalWeight + weight; 

                                filteredColor = filteredColor + weight 
                                    * originalCubeMap.GetPixel(
                                        (CubemapFace)originalFace, 
                                        originalI, originalJ);
                            }
                        }
                    }
                    filteredCubeMap.SetPixel(
                        (CubemapFace)filteredFace, filteredI, 
                        filteredJ, filteredColor / totalWeight); 
                }
            }
        }

        // Avoid seams between cube faces: average edge texels 
        // to the same color on each side of the seam
        int maxI = filteredCubeMap.width - 1;
        for (int i = 0; i < maxI; i++)
        {
            SetFaceAverage(ref filteredCubeMap, 
                0, i, 0, 2, maxI, maxI - i);
            SetFaceAverage(ref filteredCubeMap, 
                0, 0, i, 4, maxI, i);
            SetFaceAverage(ref filteredCubeMap, 
                0, i, maxI, 3, maxI, i);
            SetFaceAverage(ref filteredCubeMap, 
                0, maxI, i, 5, 0, i);

            SetFaceAverage(ref filteredCubeMap, 
                1, i, 0, 2, 0, i);
            SetFaceAverage(ref filteredCubeMap, 
                1, 0, i, 5, maxI, i);
            SetFaceAverage(ref filteredCubeMap, 
                1, i, maxI, 3, 0, maxI - i);
            SetFaceAverage(ref filteredCubeMap, 
                1, maxI, i, 4, 0, i);

            SetFaceAverage(ref filteredCubeMap, 
                2, i, 0, 5, maxI - i, 0);
            SetFaceAverage(ref filteredCubeMap, 
                2, i, maxI, 4, i, 0);
            SetFaceAverage(ref filteredCubeMap, 
                3, i, 0, 4, i, maxI);
            SetFaceAverage(ref filteredCubeMap, 
                3, i, maxI, 5, maxI - i, maxI);
        }

        // Avoid seams between cube faces: 
        // average corner texels to the same color 
        // on all three faces meeting in one corner
        SetCornerAverage(ref filteredCubeMap, 
            0, 0, 0, 2, maxI, maxI, 4, maxI, 0);
        SetCornerAverage(ref filteredCubeMap, 
            0, maxI, 0, 2, maxI, 0, 5, 0, 0);
        SetCornerAverage(ref filteredCubeMap, 
            0, 0, maxI, 3, maxI, 0, 4, maxI, maxI);
        SetCornerAverage(ref filteredCubeMap, 
            0, maxI, maxI, 3, maxI, maxI, 5, 0, maxI);
        SetCornerAverage(ref filteredCubeMap, 
            1, 0, 0, 2, 0, 0, 5, maxI, 0);
        SetCornerAverage(ref filteredCubeMap, 
            1, maxI, 0, 2, 0, maxI, 4, 0, 0);
        SetCornerAverage(ref filteredCubeMap, 
            1, 0, maxI, 3, 0, maxI, 5, maxI, maxI);
        SetCornerAverage(ref filteredCubeMap, 
            1, maxI, maxI, 3, 0, 0, 4, 0, maxI);

        filteredCubeMap.Apply(); //apply all SetPixel(..) commands

        return filteredCubeMap;
    }

    public static void SetFaceAverage(ref Cubemap filteredCubeMap, 
        int a, int b, int c, int d, int e, int f)
    {
        Color average = 
            (filteredCubeMap.GetPixel((CubemapFace)a, b, c) 
                + filteredCubeMap.GetPixel((CubemapFace)d, e, f)) / 2.0f;
        filteredCubeMap.SetPixel((CubemapFace)a, b, c, average);
        filteredCubeMap.SetPixel((CubemapFace)d, e, f, average);
    }

    public static void SetCornerAverage(ref Cubemap filteredCubeMap, 
        int a, int b, int c, int d, int e, int f, int g, int h, int i)
    {
        Color average = 
            (filteredCubeMap.GetPixel((CubemapFace)a, b, c) 
                + filteredCubeMap.GetPixel((CubemapFace)d, e, f) 
                + filteredCubeMap.GetPixel((CubemapFace)g, h, i)) / 3.0f;
        filteredCubeMap.SetPixel((CubemapFace)a, b, c, average);
        filteredCubeMap.SetPixel((CubemapFace)d, e, f, average);
        filteredCubeMap.SetPixel((CubemapFace)g, h, i, average);
    }

    public static Vector3 GetDirection(int face, int i, int j, int size)
    {
        switch (face)
        {
        case 0:
            return new Vector3(0.5f, 
                -((j + 0.5f) / size - 0.5f), 
                -((i + 0.5f) / size - 0.5f));
        case 1:
            return new Vector3(-0.5f, 
                -((j + 0.5f) / size - 0.5f), 
                ((i + 0.5f) / size - 0.5f));
        case 2:
            return new Vector3(((i + 0.5f) / size - 0.5f), 
                0.5f, ((j + 0.5f) / size - 0.5f));
        case 3:
            return new Vector3(((i + 0.5f) / size - 0.5f), 
                -0.5f, -((j + 0.5f) / size - 0.5f));
        case 4:
            return new Vector3(((i + 0.5f) / size - 0.5f),  
                -((j + 0.5f) / size - 0.5f), 0.5f);
        case 5:
            return new Vector3(-((i + 0.5f) / size - 0.5f), 
                -((j + 0.5f) / size - 0.5f), -0.5f);
        default:
            return Vector3.zero;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值