Unity3D-RayMarch-几何图元0

效果图:

将下面的shader代码对应的Material拖给一个面片,即可看到效果。

shader代码:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "RayMarch/Primitives0_diffuse"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            //###################################################################################
            //sdf:define primitives 
            float sdPlane(float3 p,float planeYPos)
            {
                return p.y - planeYPos;
            }

            float sdSphere(float3 p, float3 spherePos, float radius)
            {
                return length(p - spherePos) - radius;
            }
            //###################################################################################
        
            //###################################################################################
            //primitives boolean operation
            //求并集
            float2 opU(float2 d1, float2 d2)
            {
                return (d1.x<d2.x) ? d1 : d2;
            }    
            //###################################################################################

            // define the scene
            float2 map(in float3 pos)
            {
                //plane
                //float2(x,y)的第二个参数定义了该物体的材质id,在render环节,可以根据id做不同处理
                float2 plane = float2(sdPlane(pos, -0.5), 1);
                float2 ball_1 = float2(sdSphere(pos, float3(0, 0, 2), 0.5), 2);
                float2 ball_2 = float2(sdSphere(pos, float3(2, 0, 5), 0.5), 2);
                float2 ball_3 = float2(sdSphere(pos, float3(-2, 0, 5), 0.5), 2);
                //求物体的并集
                float2 res = opU(opU(opU(ball_1, ball_2), ball_3),plane);
                return res;
            }

            float2 castRay(in float3 ro, in float3 rd)
            {
                float tmin = 1.0;
                //射线最大允许经过的距离
                float tmax = 100.0;
                //当前已经过的距离
                float t = tmin;
                //材质id
                float m = -1.0;
                //最大迭代次数定位64
                for (int i = 0; i<64; i++)
                {
                    //距离精度随距离的增加而减小
                    float precis = 0.0005*t;
                    //获得场景中物体距离该点的距离,及距离最近物体的材质id
                    float2 res = map(ro + rd*t);
                    //如果与场景物体发生碰撞,或者射线行进距离超出最大范围,则跳出迭代
                    if (res.x<precis || t>tmax) break;
                    t += res.x;
                    m = res.y;
                }
                if (t>tmax) m = -1.0;
                return float2(t, m);
            }

            //计算碰撞点处物体表面的法线
            float3 calcNormal(in float3 pos)
            {
                float3 eps = float3(0.0005, 0.0, 0.0);
                float3 nor = float3(
                    map(pos + eps.xyy).x - map(pos - eps.xyy).x,
                    map(pos + eps.yxy).x - map(pos - eps.yxy).x,
                    map(pos + eps.yyx).x - map(pos - eps.yyx).x);
                return normalize(nor);
            }

            float3 render(in float3 ro, in float3 rd)
            {
                //投掷射线,获得与所场景物体的碰撞信息
                float2 res = castRay(ro, rd);
                float t = res.x;
                float m = res.y;
                float3 pos = ro + t*rd;
                float3 nor = calcNormal(pos);
                float3 ref = reflect(rd, nor);
                //漫反射着色
                fixed3 lightPos = fixed3(0, 3, 0);
                fixed3 lightDir = normalize(lightPos - pos);
                float dif = clamp(dot(nor, lightDir),0, 1);
                float3 col = float3(dif, dif, dif);
                return float3(clamp(col, 0.0, 1.0));

            }
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                //虚拟摄像机坐标
                float3 ro = float3(0,0,-1);
                //投影面某点坐标
                float3 p = float3(i.uv - float2(0.5, 0.5),0);
                //投掷射线
                float3 rd = normalize(p - ro);
                fixed4 col = fixed4(render(ro, rd).rgb, 1);
                // gamma校正
                col.rgb = pow(col.rgb, float3(0.4545, 0.4545, 0.4545));
                return col;
            }
            ENDCG
        }
    }
}

 

转载于:https://www.cnblogs.com/bluebean/p/7402042.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值