3D 텍스처는 표준 2차원이 아닌 3차원 정보를 포함하는 비트맵 이미지입니다. 3D 텍스처는 일반적으로 안개 또는 연기와 같은 볼류메트릭 효과를 시뮬레이션하거나 볼류메트릭 3D 메시를 근사화하거나 애니메이션 텍스처를 저장하고 서로 간에 부드럽게 블렌딩하는 데 사용됩니다.
3D 텍스처의 최대 해상도는 2048x2048x2048입니다.
메모리와 디스크의 3D 텍스처 크기는 해상도가 증가함에 따라 빠르게 증가합니다. 밉맵이 없고 해상도가 16x 16x16인 RGBA32 3D 텍스처는 크기가 128KB이지만, 해상도가 256x256x256인 경우에는 크기가 512MB입니다.
셀로 분할된 소스 텍스처 파일에서 3D 텍스처를 임포트할 수 있습니다. 이를 플립북 텍스처라고 합니다. 이렇게 하려면 다음 단계를 따르십시오.
1.소스 텍스처를 Unity 프로젝트로 임포트합니다. 2. 프로젝트 뷰에서 결과 텍스처 에셋을 선택합니다. 그러면 인스펙터에 텍스처 임포트 설정이 표시됩니다. 3. 인스펙터에서 Texture Shape를 3D로 설정합니다. 그러면 Columns 및 Rows 프로퍼티가 표시됩니다. 4. Columns 및 Rows를 플립북 텍스처에 적합한 값으로 설정합니다. 5. Apply를 클릭합니다.
자세한 내용은 텍스처 임포트 설정을 참조하십시오.
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 텍스처와 함께 사용하면 다음의 결과를 얻을 수 있습니다.