SDFの視覚化(StackedPlane)
環境
Unity2022.2.14f1
概要

板ポリを視線奥方向に重ねることで、RayMarchingをしないで視覚化するという手法のテストです。
参考の記事に記載されているように、角ばったものや、3DTextureの視覚化には向かないようです。
雲や霧状のものの表現には使えそうではあります。
コード
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using static UnityEngine.GraphicsBuffer;
public unsafe class TestStackedPlane : MonoBehaviour
{
[SerializeField] private Material _material = null;
[SerializeField] private int _sliceNum = 64;
private GraphicsBuffer _gbMatrices = null;
private Bounds _bounds;
private static int _spMatrices = Shader.PropertyToID("_Matrices");
private static int _spSliceNum = Shader.PropertyToID("_SliceNum");
#if UNITY_EDITOR
private void OnValidate()
{
OnEnable();
}
#endif
private void OnEnable()
{
_gbMatrices = new GraphicsBuffer(Target.Structured, UsageFlags.LockBufferForWrite, 1, sizeof(Matrix4x4));
_material.SetBuffer(_spMatrices, _gbMatrices);
_material.SetInt(_spSliceNum, _sliceNum);
_bounds = new Bounds(Vector3.zero, new Vector3(10000.0f, 10000.0f, 10000.0f));
}
private void OnDisable()
{
if(_gbMatrices != null)
_gbMatrices.Dispose();
}
private void Update()
{
var matrices = _gbMatrices.LockBufferForWrite<Matrix4x4>(0, 1);
matrices[0] = transform.localToWorldMatrix;
_gbMatrices.UnlockBufferAfterWrite<Matrix4x4>(1);
Graphics.DrawProcedural(_material, _bounds, MeshTopology.Quads, _sliceNum * 4, 1);
}
}
Shader "Unlit/StackedPlane"
{
Properties
{
_Color("Color", Color) = (1, 1, 1, 1)
_SdfTex ("Sdf Texture", 3D) = "white" {}
}
CGINCLUDE
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap
#include "UnityCG.cginc"
#define EPSILON 0.00001
float _SliceNum;
fixed4 _Color;
sampler3D _SdfTex;
StructuredBuffer<float4x4> _Matrices;
struct appdata
{
uint vertexId : SV_VertexID;
uint instanceId : SV_InstanceID;
};
struct v2f
{
float4 posCS : SV_POSITION;
float3 posOS : TEXCOORD0;
};
ENDCG
SubShader
{
Tags
{
"Queue"="Transparent"
"RenderType"="Transparent"
"IgnoreProjector"="True"
}
ZWrite Off
Blend SrcAlpha One
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
v2f vert (appdata v)
{
v2f o;
unity_ObjectToWorld = _Matrices[v.instanceId];
const uint vnum = 4;
uint vertexId = v.vertexId % vnum;
uint faceId = v.vertexId / vnum;
const float2 vertices[] =
{
float2(-1, -1),
float2(-1, 1),
float2( 1, 1),
float2( 1, -1)
};
const float scale = 1.5;
o.posOS = float3(vertices[vertexId], ((float)faceId / (float)(_SliceNum - 1)) * 2.0 - 1.0) * scale;
o.posOS = mul(o.posOS, UNITY_MATRIX_V);
o.posCS = UnityObjectToClipPos(float4(o.posOS, 1.0));
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float4 color = float4(_Color.rgb, 0.0);
float alpha = 1.0 / (_SliceNum - 1);
float dist = tex3D(_SdfTex, i.posOS * 0.5 + 0.5);
if(dist < EPSILON)
color.a += alpha;
return color;
}
ENDCG
}
}
}
参考
Raymarchingではない3Dアプローチ - Qiita