3D 텍스처는 표준 2차원이 아닌 3차원 정보를 포함하는 비트맵 이미지입니다. 3D 텍스처는 일반적으로 안개 또는 연기와 같은 볼류메트릭 효과를 시뮬레이션하거나 볼류메트릭 3D 메시를 근사화하거나 애니메이션 텍스처를 저장하고 서로 간에 부드럽게 블렌딩하는 데 사용됩니다.
3D 텍스처의 최대 해상도는 2048x2048x2048입니다.
메모리와 디스크의 3D 텍스처 크기는 해상도가 증가함에 따라 빠르게 증가합니다. 밉맵이 없고 해상도가 16 x 16 x 16인 RGBA32 3D 텍스처의 크기는 128KB이지만 해상도가 256 x 256 x 256인 텍스처의 크기는 512MB입니다.
셀로 분할된 소스 텍스처 파일에서 3D 텍스처를 임포트할 수 있습니다. 이를 플립북 텍스처라고 합니다. 이렇게 하려면 다음 단계를 따르십시오.
자세한 내용은 텍스처 임포트 설정을 참조하십시오.
Unity는 Texture3D 클래스를 사용하여 3D 텍스처를 표현합니다. 이 클래스를 사용하여 C# 스크립트에서 3D 텍스처와 상호작용할 수 있습니다.
다음 예제는Texture3D 클래스의 인스턴스를 생성하여 컬러 데이터로 채운 후 프로젝트에 직렬화된 에셋 파일로 저장하는 에디터 스크립트입니다.
using UnityEditor;
using UnityEngine;
public class ExampleEditorScript : MonoBehaviour
{
    [MenuItem("CreateExamples/3DTexture")]
    static void CreateTexture3D()
    {
        // Configure the texture
        int size = 32;
        TextureFormat format = TextureFormat.RGBA32;
        TextureWrapMode wrapMode =  TextureWrapMode.Clamp;
        // Create the texture and apply the configuration
        Texture3D texture = new Texture3D(size, size, size, format, false);
        texture.wrapMode = wrapMode;
        // Create a 3-dimensional array to store color data
        Color[] colors = new Color[size * size * size];
        // Populate the array so that the x, y, and z values of the texture will map to red, blue, and green colors
        float inverseResolution = 1.0f / (size - 1.0f);
        for (int z = 0; z < size; z++)
        {
            int zOffset = z * size * size;
            for (int y = 0; y < size; y++)
            {
                int yOffset = y * size;
                for (int x = 0; x < size; x++)
                {
                    colors[x + yOffset + zOffset] = new Color(x * inverseResolution,
                        y * inverseResolution, z * inverseResolution, 1.0f);
                }
            }
        }
        // Copy the color values to the texture
        texture.SetPixels(colors);
        // Apply the changes to the texture and upload the updated texture to the GPU
        texture.Apply();        
        // Save the texture to your Unity Project
        AssetDatabase.CreateAsset(texture, "Assets/Example3DTexture.asset");
    }
}
Unity 에디터는 3D 텍스처를 미리볼 수 있도록 세 가지의 시각화 모드를 제공합니다.
인스펙터에서 3D 텍스처를 미리보거나, Handles API를 사용하여 씬 뷰에서 3D 텍스처를 미리볼 수 있는 스크립트를 작성할 수 있습니다. 인스펙터를 사용하면 빠르고 편리하지만, 커스텀 그레디언트를 사용할 수 없습니다. Handles API를 사용하면 정확한 요구 사항에 맞게 미리보기를 설정하고 커스텀 그레디언트를 사용할 수 있습니다.
인스펙터 창에서 3D 텍스처를 미리보려면 다음 단계를 따르십시오.
이 시각화 모드에서는 Unity가 3D 텍스처를 반투명 큐브로 렌더링합니다.
다음 컨트롤을 툴바에서 이용할 수 있습니다.
| 컨트롤: | 기능: | 
|---|---|
| Ramp | 컬러 램프 시각화를 활성화 또는 비활성화합니다. 이미지에 미세한 디테일이 많은 경우 Ramp를 활성화하여 디테일 선명도를 높이십시오. | 
| Quality | 텍스처 픽셀 수당 샘플을 설정합니다. 값이 높을수록 렌더링 품질이 향상됩니다. | 
| Alpha | 시각화의 불투명도를 제어합니다. 값 1은 완전히 불투명하고 값 0은 완전히 투명합니다. 조정을 통해 내부 픽셀을 볼 수 있습니다. | 
이 시각화 모드에서는 Unity가 3D 텍스처의 각 축 평면의 슬라이스를 렌더링합니다.
다음 컨트롤을 툴바에서 이용할 수 있습니다.
| 컨트롤: | 기능: | 
|---|---|
| Ramp | 컬러 램프 시각화를 활성화 또는 비활성화합니다. 이미지에 미세한 디테일이 많은 경우 Ramp를 활성화하여 디테일 선명도를 높이십시오. | 
| X | x축의 슬라이싱 포지션을 텍스처 픽셀 단위로 설정합니다. 조정을 통해 특정 슬라이스를 볼 수 있습니다. | 
| Y | y축의 슬라이싱 포지션을 텍스처 픽셀 단위로 설정합니다. 조정을 통해 특정 슬라이스를 볼 수 있습니다. | 
| Z | z축의 슬라이싱 포지션을 텍스처 픽셀 단위로 설정합니다. 조정을 통해 특정 슬라이스를 볼 수 있습니다. | 
이 시각화 모드에서는 Unity가 3D 공간에서 Signed Distance Field 렌더링 모드를 사용하여 3D 텍스처를 렌더링합니다. 단, 이 시각화 모드는 비방향성 서명 거리 필드만 지원합니다.
다음 컨트롤을 툴바에서 이용할 수 있습니다.
| 컨트롤: | 기능: | 
|---|---|
| Scale | 광선 단계 크기에 곱하는 숫자입니다. 광선 단계 크기는 2개의 인접한 픽셀 간의 거리입니다. 시각화의 원거리 파트가 잘리는 경우 이 값을 늘리십시오. 시각화가 전혀 렌더링되지 않으면 이 값을 줄이십시오.  | 
| Offset | 표면이 렌더링되는 픽셀의 강도입니다. 이 값이 양수이면 Unity는 렌더링된 표면을 확장합니다. 이 값이 음수이면 Unity는 빈 공간을 표면으로 렌더링하고, 표면을 빈 공간으로 렌더링합니다. | 
Handles API를 사용하여 3D 텍스처를 미리보는 방법과 코드 예제는 다음 문서를 참조하십시오.
다음은 3D 텍스처를 사용하여 볼륨을 시각화하는 간단한 레이마칭 셰이더의 예제입니다.
Shader "Unlit/VolumeShader\"
{
    Properties
    {
        _MainTex ("Texture", 3D) = "white" {}
        _Alpha ("Alpha", float) = 0.02
        _StepSize ("Step Size", float) = 0.01
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }
        Blend One OneMinusSrcAlpha
        LOD 100
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            // Maximum amount of raymarching samples
            #define MAX_STEP_COUNT 128
            // Allowed floating point inaccuracy
            #define EPSILON 0.00001f
            struct appdata
            {
                float4 vertex : POSITION;
            };
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 objectVertex : TEXCOORD0;
                float3 vectorToSurface : TEXCOORD1;
            };
            sampler3D _MainTex;
            float4 _MainTex_ST;
            float _Alpha;
            float _StepSize;
            v2f vert (appdata v)
            {
                v2f o;
                // Vertex in object space this will be the starting point of raymarching
                o.objectVertex = v.vertex;
                // Calculate vector from camera to vertex in world space
                float3 worldVertex = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.vectorToSurface = worldVertex - _WorldSpaceCameraPos;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            float4 BlendUnder(float4 color, float4 newColor)
            {
                color.rgb += (1.0 - color.a) * newColor.a * newColor.rgb;
                color.a += (1.0 - color.a) * newColor.a;
                return color;
            }
            fixed4 frag(v2f i) : SV_Target
            {
                // Start raymarching at the front surface of the object
                float3 rayOrigin = i.objectVertex;
                // Use vector from camera to object surface to get ray direction
                float3 rayDirection = mul(unity_WorldToObject, float4(normalize(i.vectorToSurface), 1));
                float4 color = float4(0, 0, 0, 0);
                float3 samplePosition = rayOrigin;
                // Raymarch through object space
                for (int i = 0; i < MAX_STEP_COUNT; i++)
                {
                    // Accumulate color only within unit cube bounds
                    if(max(abs(samplePosition.x), max(abs(samplePosition.y), abs(samplePosition.z))) < 0.5f + EPSILON)
                    {
                        float4 sampledColor = tex3D(_MainTex, samplePosition + float3(0.5f, 0.5f, 0.5f));
                        sampledColor.a *= _Alpha;
                        color = BlendUnder(color, sampledColor);
                        samplePosition += rayDirection * _StepSize;
                    }
                }
                return color;
            }
            ENDCG
        }
    }
}
이 셰이더를 페이지 상단의 예제에서 생성된 3D 텍스처와 함께 사용하면 다음의 결과를 얻을 수 있습니다.
Texture3D