Skip to content

Instantly share code, notes, and snippets.

@rngtm
Last active March 7, 2021 09:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rngtm/987133d7c19d5643412ad97ad2d92e1c to your computer and use it in GitHub Desktop.
Save rngtm/987133d7c19d5643412ad97ad2d92e1c to your computer and use it in GitHub Desktop.
レイマーチングで球をたくさん表示するシェーダーグラフカスタムノード
using System.Reflection;
using UnityEditor.ShaderGraph;
using UnityEngine;
/// <summary>
/// レイマーチングで球をたくさん表示するカスタムノード
/// </summary>
[Title ("Raymarching", "Raymarch Sphere")]
public class RaymarchingSphereNode : CodeFunctionNode {
public RaymarchingSphereNode () {
name = "Raymarching(Sphere)";
}
protected override MethodInfo GetFunctionToConvert () {
return GetType ().GetMethod ("RaymarchingNode_Function",
BindingFlags.Static | BindingFlags.NonPublic);
}
public override void GenerateNodeFunction (FunctionRegistry registry, GraphContext graphContext, GenerationMode generationMode) {
registry.ProvideFunction ("distance_func", s => s.Append (@"
// 距離関数: 点pからオブジェクトまでの距離を求める
#define INTERVAL interval
float distance_func(float3 p, float size, float interval) {
p = frac(p / INTERVAL) * INTERVAL - INTERVAL / 2.0; // -INTERVAL/2.0 ~ +INTERVAL/2.0 の繰り返しを作る
return length(p) - size;
}
"));
registry.ProvideFunction ("getNormal", s => s.Append (@"
// 法線の計算
float3 getNormal(float3 p, float size, float interval) {
float2 e = float2(0.0001, 0.0);
return normalize(float3(
distance_func(p + e.xyy, size, interval) - distance_func(p - e.xyy, size, interval),
distance_func(p + e.yxy, size, interval) - distance_func(p - e.yxy, size, interval),
distance_func(p + e.yyx, size, interval) - distance_func(p - e.yyx, size, interval)
));
}
"));
base.GenerateNodeFunction (registry, graphContext, generationMode);
}
static string RaymarchingNode_Function (
[Slot (0, Binding.MeshUV0)] Vector2 UV,
[Slot (1, Binding.None, 0f, 0f, 4f, 0f)] Vector3 CameraPos, // カメラ位置
[Slot (2, Binding.None, 0f, 0f, -1f, 0f)] Vector3 CameraDir, // カメラの向きベクトル
[Slot (3, Binding.None, 0f, 1f, 0f, 0f)] Vector3 CameraUp, // カメラの上方向ベクトル
[Slot (4, Binding.None, 1f, 0f, 0f, 0f)] Vector1 ObjectSize, // 球のサイズ
[Slot (5, Binding.None, 2f, 0f, 0f, 0f)] Vector1 ObjectInterval, // 球の配置間隔
[Slot (6, Binding.None, 32f, 0f, 0f, 0f)] Vector1 RaymarchLoop, // レイマーチングのループ回数(この数を大きくすると遠くまで描画されるようになりますが重くなります)
[Slot (7, Binding.None, 0f, 0f, 0f, 0f)] Vector1 RayStartLength,
[Slot (8, Binding.None, 1f, 1f, 1f, 0f)] Vector3 LightDir,
[Slot (10, Binding.None)] out Vector1 Hit, // レイがオブジェクトにぶつかったら1.0, ぶつからなかったら0.0
[Slot (11, Binding.None)] out Vector1 Distance, // レイマーチングでレイが進んだ距離
[Slot (12, Binding.None)] out Vector3 Normal, // オブジェクト上の法線
[Slot (13, Binding.None)] out Vector1 Specular, // オブジェクト上の法線
[Slot (14, Binding.None)] out Vector3 RayPos // レイの位置
) {
Normal = Vector3.zero;
RayPos = Vector3.zero;
return @"{
#define MAX_REPEAT 100
float2 p = UV - 0.5;
// カメラに関する情報(Position, Direction, Up)
#define cPos CameraPos
#define cDir normalize(CameraDir)
#define cUp normalize(CameraUp)
#define cSide normalize(cross(cUp, cDir))
// レイマーチング
float3 ray = normalize(p.x * cSide + p.y * cUp + 1.0 * cDir); // レイの向きベクトル
float3 rPos = cPos; // レイ位置
float rLength = RayStartLength;// レイが進む長さ
float dist = 0.0; // レイとオブジェクト間の距離
for (int i = 0; i < min(RaymarchLoop, MAX_REPEAT); i++)
{
dist = distance_func(rPos, ObjectSize, ObjectInterval); // レイ位置からオブジェクトまでの距離を求める
rLength += dist; // 距離を足す(レイを進める)
rPos = cPos + ray * rLength; // レイ位置の更新
}
Hit = step(dist, 0.01); // レイがオブジェクトにある程度近かったら1.0を出力、それ以外は0.0を出力
Distance = rLength; // レイが進んだ距離を出力
Normal = saturate(getNormal(rPos, ObjectSize, ObjectInterval)); // レイの交点におけるオブジェクト上の法線を出力
RayPos = rPos;
#define viewDir ray
#define lightDir LightDir
float NdotL = max(0, dot (Normal, lightDir));
float3 R = normalize( - lightDir + 2.0 * Normal * NdotL );
Specular = max(0, dot(R, viewDir));
}";
}
}
@rngtm
Copy link
Author

rngtm commented Dec 3, 2018

カメラの位置と向きを指定してレイマーチングできるカスタムノードです。

Distanceは1.0以上の値が返ってくることが多いのでReciprocalノードを使って逆数をとると扱いやすいと思います。

image

@rngtm
Copy link
Author

rngtm commented Dec 30, 2018

使用例: サイバー空間的な世界を作る

4

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment