立方体贴图数组是一个包含有大小和格式均相同的立方体贴图的数组,GPU 可以将其作为单个纹理资源进行访问。立方体贴图数组通常用于实现高效的反射探针、光照和阴影系统。
在您的 Unity 项目中,Unity 编辑器将立方体贴图数组表示为纹理资源。要配置纹理资源的导入设置,您可以使用 Inspector,或使用 TextureImporter API 编写一个脚本。在 Unity 引擎中,Unity 使用 CubemapArray 类来表示立方体贴图数组。
要在项目中创建立方体贴图数组,必须使用脚本。
下面的示例是一个编辑器脚本,该脚本创建一个 CubemapArray
类的实例,用颜色数据填充该实例,然后作为纹理资源保存到项目中。
using UnityEngine;
public class CreateCubeArrayTexture : MonoBehaviour
{
[UnityEditor.MenuItem("CreateExamples/CubemapArray")]
static void CreateCubemapArray()
{
// 配置立方体贴图数组和颜色数据
int faceSize = 16;
int arraySize = 4;
int[] kCubeXRemap = new int[] { 2, 2, 0, 0, 0, 0 };
int[] kCubeYRemap = new int[] { 1, 1, 2, 2, 1, 1 };
int[] kCubeZRemap = new int[] { 0, 0, 1, 1, 2, 2 };
float[] kCubeXSign = new float[] { -1.0F, 1.0F, 1.0F, 1.0F, 1.0F, -1.0F };
float[] kCubeYSign = new float[] { -1.0F, -1.0F, 1.0F, -1.0F, -1.0F, -1.0F };
float[] kCubeZSign = new float[] { 1.0F, -1.0F, 1.0F, -1.0F, 1.0F, -1.0F };
var baseCols = new Color[] { Color.white, new Color(1, .5f, .5f, 1), new Color(.5f, 1, .5f, 1), new Color(.5f, .5f, 1, 1), Color.gray };
// 创建 CubemapArray 的实例
var tex = new CubemapArray(faceSize, arraySize, TextureFormat.ARGB32, true);
tex.filterMode = FilterMode.Trilinear;
// 遍历每个立方体贴图
var col = new Color[tex.width * tex.width];
float invSize = 1.0f / tex.width;
for (var i = 0; i < tex.cubemapCount; ++i)
{
var baseCol = baseCols[i % baseCols.Length];
// 遍历当前立方体贴图的每个面
for (var face = 0; face < 6; ++face)
{
var idx = 0;
Vector3 signScale = new Vector3(kCubeXSign[face], kCubeYSign[face], kCubeZSign[face]);
// 遍历当前的面的每个像素
for (int y = 0; y < tex.width; ++y)
{
for (int x = 0; x < tex.width; ++x)
{
// 计算当前像素的"法线方向"的颜色
Vector3 uvDir = new Vector3(x * invSize * 2.0f - 1.0f, y * invSize * 2.0f - 1.0f, 1.0f);
uvDir = uvDir.normalized;
uvDir.Scale(signScale);
Vector3 dir = Vector3.zero;
dir[kCubeXRemap[face]] = uvDir[0];
dir[kCubeYRemap[face]] = uvDir[1];
dir[kCubeZRemap[face]] = uvDir[2];
// 将颜色移至 0.4..1.0 范围
Color c = new Color(dir.x * 0.3f + 0.7f, dir.y * 0.3f + 0.7f, dir.z * 0.3f + 0.7f, 1.0f);
// 将模式添加到一些像素中,以使 Mipmap 更清晰可见
if (((x ^ y) & 3) == 1)
c *= 0.5f;
// Tint the color with the baseCol tint
col[idx] = baseCol * c;
++idx;
}
}
// 将此面的颜色值复制到纹理
tex.SetPixels(col, (CubemapFace)face, i);
}
}
// 将更改应用到纹理并将更新后的纹理上传到 GPU
tex.Apply();
// 将该纹理保存到您的 Unity 项目
AssetDatabase.CreateAsset(tex, "Assets/ExampleCubemapArray.asset");
UnityEditor.AssetDatabase.SaveAssets();
}
}
要在 Inspector 窗口中预览立方体贴图数组,请导航到 Project 窗口并选择 Texture Asset。Inspector 现在显示此纹理资源的纹理导入设置,Unity 会在 Inspector 底部渲染立方体贴图数组的预览。
工具栏中会显示以下控件:
控制 | 功能 |
---|---|
Filter Mode | 用于预览的过滤。请参阅有关过滤模式的文档 |
下面是一个使用立方体贴图数组的着色器示例。
Shader "CubemapArrayShaderExample" {
Properties {
_MainTex ("CubemapArray", CubeArray) = "" {}
_Mip ("Mip", Float) = 0.0
_Intensity ("Intensity", Float) = 1.0
_SliceIndex ("Slice", Int) = 0
_Exposure ("Exposure", Float) = 0.0
}
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "ForceSupported" = "True"}
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma require sampleLOD
#pragma require cubearray
#include "UnityCG.cginc"
struct appdata {
float4 pos : POSITION;
float3 nor : NORMAL;
};
struct v2f {
float3 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
uniform int _SliceIndex;
float _Mip;
half _Alpha;
half _Intensity;
float _Exposure;
v2f vert (appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.pos);
float3 viewDir = -normalize(ObjSpaceViewDir(v.pos));
o.uv = reflect(viewDir, v.nor);
return o;
}
half4 _MainTex_HDR;
UNITY_DECLARE_TEXCUBEARRAY(_MainTex);
fixed4 frag (v2f i) : COLOR0
{
fixed4 c = UNITY_SAMPLE_TEXCUBEARRAY(_MainTex, float4(i.uv, _SliceIndex));
fixed4 cmip = UNITY_SAMPLE_TEXCUBEARRAY_LOD(_MainTex, float4(i.uv, _SliceIndex), _Mip);
if (_Mip >= 0.0)
c = cmip;
c.rgb = DecodeHDR (c, _MainTex_HDR) * _Intensity;
c.rgb *= exp2(_Exposure);
c = lerp (c, c.aaaa, _Alpha);
return c;
}
ENDCG
}
}
Fallback Off
}
如果将此着色器用于在页面顶部的示例中创建的立方体贴图,则结果将如下所示:
[立方体贴图数组支持]添加于 2020.1 NewIn20201
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.