Skip to content

Instantly share code, notes, and snippets.

@kugimasa
Last active September 23, 2021 12:30
Show Gist options
  • Save kugimasa/cb6e91f7c0641c546ed46064c899ba12 to your computer and use it in GitHub Desktop.
Save kugimasa/cb6e91f7c0641c546ed46064c899ba12 to your computer and use it in GitHub Desktop.
Raymarching Sample in Unity
Shader "Custom/RaymarchingSample"
{
Properties
{
[KeywordEnum(WORLD, OBJECT)] _Coordinate ("Coordinate", int) = 0
[KeywordEnum(SPHERE, TORUS)] _Object ("Object", int) = 0
_MainTex ("Texture", 2D) = "white" {}
_MaxStep ("Max Step" , int) = 100
_MaxDist ("Max Ray Distance", int) = 1000
_SurfDist ("Surface Distance", float) = 0.01
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma shader_feature _COORDINATE_WORLD _COORDINATE_OBJECT
#pragma shader_feature _OBJECT_SPHERE _OBJECT_TORUS
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 ro : TEXCOORD1;
float3 hitPos : TEXCOORD2;
};
sampler2D _MainTex;
float4 _MainTex_ST;
int _MaxStep;
int _MaxDist;
float _SurfDist;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
#ifdef _COORDINATE_WORLD
// ワールド空間に描画
o.ro = _WorldSpaceCameraPos;
o.hitPos = mul(unity_ObjectToWorld, v.vertex);
#elif _COORDINATE_OBJECT
// オブジェクト空間に描画
o.ro = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1));
o.hitPos = v.vertex;
#endif
return o;
}
// 距離関数
float GetDist(float3 p)
{
float d = 0;
#ifdef _OBJECT_SPHERE
// 球
d = length(p) - 0.5f;
#elif _OBJECT_TORUS
// トーラス
d = length(float2(length(p.xz) - 0.5f, p.y)) - 0.1f;
#endif
return d;
}
// 点Pにおける法線ベクトル
float3 GetNormal(float3 p)
{
float2 eps = float2(1e-2, 0);
// distance delta from p
float3 dp = float3(GetDist(p - eps.xyy),
GetDist(p - eps.yxy),
GetDist(p - eps.yyx));
float3 n = GetDist(p) - dp;
return normalize(n);
}
// 点Pにおける法線ベクトル
// Central Difference method
float3 GetCentralDifferenceNormal(float3 p)
{
float2 eps = float2(1e-2, 0);
float3 n = float3(GetDist(p - eps.xyy) - GetDist(p + eps.xyy),
GetDist(p - eps.yxy) - GetDist(p + eps.yxy),
2.0f * eps.x);
return normalize(n);
}
// レイマーチ処理
float Raymarch(float3 ro, float3 rd)
{
// 原点からの距離
float dO = 0.0f;
// 最大ステップ数までレイを伸ばす
for (int i = 0; i < _MaxStep; i++)
{
float3 p = ro + rd * dO;
// 点pから
float dS = GetDist(p);
dO += dS;
// Ray is out of range or Intersect with surface
if (dO > _MaxDist || dS < _SurfDist) break;
}
return dO;
}
// フラグメントシェーダー
fixed4 frag (v2f i) : SV_Target
{
// レイの原点はカメラ
float3 ro = i.ro;
// レイ方向はカメラからオブジェクト方向
float3 rd = normalize(i.hitPos - ro);
// レイマーチ処理
float d = Raymarch(ro, rd);
fixed4 col = 0;
// レイの長さがMAXに到達した場合、描画しない
if (d >= _MaxDist)
{
discard;
}
// オブジェクトの描画
float3 p = ro + rd * d;
float3 n = GetCentralDifferenceNormal(p);
col.rgb = n;
return col;
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment