-
Notifications
You must be signed in to change notification settings - Fork 4
/
03_RaymarchingSphere.shader
122 lines (97 loc) · 3.96 KB
/
03_RaymarchingSphere.shader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
Shader "Unlit/03_RaymarchingSphere"
{
Properties { }
SubShader
{
Tags { "RenderType" = "Opaque" }
Pass
{
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex: POSITION;
float2 uv: TEXCOORD0;
};
struct v2f
{
float2 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = float4(v.vertex.xy * 2.0, 0.5, 1.0);
o.uv = v.uv;
// Direct3DのようにUVの上下が反転したプラットフォームを考慮します
#if UNITY_UV_STARTS_AT_TOP
o.uv.y = 1 - o.uv.y;
#endif
return o;
}
float sdSphere(float3 p, float r)
{
return length(p) - r;
}
float map(float3 p)
{
return sdSphere(p, 1.0);
}
float4 frag(v2f input): SV_Target
{
float3 col = float3(0, 0, 0);
// UVを -1~1 の範囲に変換します
float2 uv = 2.0 * input.uv - 1.0;
// アスペクト比を考慮します
uv.x *= _ScreenParams.x / _ScreenParams.y;
// カメラの情報
float3 cameraOrigin = float3(0, 0, -3);// カメラの位置
float3 cameraTarget = float3(0, 0, 0);// カメラのターゲット
float3 cameraUp = float3(0, 1, 0);// カメラのUPベクトル
float cameraFov = 60;// カメラのFOV
// UVに対応するレイを計算
float3 forward = normalize(cameraTarget - cameraOrigin);
float3 right = normalize(cross(cameraUp, forward));
float3 up = normalize(cross(forward, right));
float PI = 3.14159265359;
float3 ray = normalize(
right * uv.x +
up * uv.y +
forward / tan(cameraFov / 360 * PI)
);
// レイマーチング
float t = 0.0;// レイの進んだ距離
float3 p = cameraOrigin;// レイの先端の座標
int i = 0;// レイマーチングのループカウンター
bool hit = false;// オブジェクトに衝突したかどうか
for (i = 0; i < 99; i++)
{
float d = map(p);// 最短距離を計算します
// 最短距離を0に近似できるなら、オブジェクトに衝突したとみなして、ループを抜けます
if (d < 0.0001)
{
hit = true;
break;
}
t += d;// 最短距離だけレイを進めます
p = cameraOrigin + ray * t;// レイの先端の座標を更新します
}
if (hit)
{
// 何かに衝突したら白
col = float3(1, 1, 1);
}
else
{
// 何にも衝突しなかったら黒
col = float3(0, 0, 0);
}
return float4(col, 1);
}
ENDCG
}
}
}