16
8

More than 5 years have passed since last update.

【Unity】Skyboxでレイマーチング

Posted at

UnityのSkyboxシェーダーでレイマーチングをしてみました。

Skyboxシェーダーでは視線方向をTEXCOORD0で、カメラ位置を_WorldSpaceCameraPosを取得できるので、そのあたりを自分で計算せずにすぐにレイを飛ばすことができます。

output.gif

Skyboxシェーダーの書き方自体は私が以前書いた記事を参考にしてください。
【Unity】Skyboxシェーダーの書き方 - Qiita

やっていること自体はよくあるレイマーチングなので説明は割愛します。

Raymarching.Shader
Shader "Skybox/Raymarching"
{
    SubShader
    {
        Tags
        {
            "RenderType"="Background"
            "Queue"="Background"
            "PreviewType"="SkyBox"
        }

        Pass
        {
            ZWrite Off
            Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct appdata
            {
                float4 vertex : POSITION;
                float3 rayDir : TEXCOORD0;
            };

            struct v2f 
            {
                float4 vertex : SV_POSITION;
                float3 rayDir : TEXCOORD0;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.rayDir = v.rayDir;
                return o;
            }

            float sphere(float3 pos, float radius)
            {
                return length(pos) - radius;
            }

            float3 repeat(float3 pos, float3 span)
            {
                return abs(fmod(pos, span)) - span * 0.5;
            }

            float getDistance(float3 pos)
            {
                return sphere(repeat(pos, 10.0), 1.0f);
            }

            float3 getNormal(float3 pos) {
                float d = 0.001;
                return normalize(float3(
                    getDistance(pos + float3(d, 0, 0)) - getDistance(pos + float3(-d, 0, 0)),
                    getDistance(pos + float3(0, d, 0)) - getDistance(pos + float3(0, -d, 0)),
                    getDistance(pos + float3(0, 0, d)) - getDistance(pos + float3(0, 0, -d))
                ));
            }

            float3 raymarch(float3 cameraPos, float3 rayDir)
            {
                float3 pos = cameraPos;
                for (int i = 0; i < 200; i++) {
                    float d = getDistance(pos);
                    pos += d * rayDir;
                    if (d < 0.001) {
                        return getNormal(pos) * 0.5 + 0.5;
                    }
                }
                return 0;
            }

            fixed4 frag (v2f i) : SV_TARGET
            {
                float3 rayDir = normalize(i.rayDir);
                return fixed4(raymarch(_WorldSpaceCameraPos, rayDir), 1.0);
            }

            ENDCG
        }
    }
}
16
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
8