Last active
September 23, 2021 12:30
-
-
Save kugimasa/cb6e91f7c0641c546ed46064c899ba12 to your computer and use it in GitHub Desktop.
Raymarching Sample in Unity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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