当前位置: 首页 > news >正文

Unity3D-RayMarch-几何图元-3添加阴影

效果图:

在RayMarch渲染算法中计算阴影非常简单,当射线碰撞到物体,从碰撞点逆着光源方向再次执行射线步进算法,如果这一过程中碰撞到了其他物体,则碰撞点被其他物体遮挡,该处具有阴影。

shader代码:

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

Shader "RayMarch/Primitives1_phong"
{
    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"

#define PointLightPos fixed3(0, 6, 0)
#define LightColor float3(1,1,1)
#define GlobalAmibent float3(0.01,0.01,0.01)

        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), 0);
        float2 ball_1 = float2(sdSphere(pos, float3(0, 0, 2), 0.5), 1);
        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), 3);
        //求物体的并集
        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 tmaxmax = 200;
        //当前已经过的距离
        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 = -clamp((t - tmax) / (tmaxmax - tmax), 0, 1);
        }
        return float2(t, m);
    }

    int IsInShadow(in float3 ro, in float3 rd) {
        int result = 1;
        float tmax = distance(ro, PointLightPos);
        float t = 0;
        for (int i = 0; i < 64; i++) {
            float precis = 0.0005*t;
            float2 res = map(ro + rd*t);
            if (res.x < precis) {
                result = 0;
                break;
            }
            if (t >= tmax) {
                result = 1;
                break;
            }
            t += res.x;
        }
        return result;
    }

    //计算碰撞点处物体表面的法线
    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);
    }

    void BasicPhong(fixed3 lightDir, fixed3 normalDir, fixed3 viewDir, float matIndex, out float3 color1, out float3 color2) {
        float Ka = 1, Kd = 1, Ks = 1, Shininess = 7;
        float3 matColor = float3(0.5, 0.5, 0);
        switch (matIndex) {
        case -1:
            //极远处
            matColor = float3(0, 0, 0); 
            Ka = 0; Ks = 0; Kd = 0;
            break;
        case 0:
            matColor = float3(0.1, 0.1, 0.1); 
            Ks = 0;
            break;
        case 1:
            matColor = float3(0.5, 0.5, 0); Shininess = 30;
            break;
        case 2:
            matColor = float3(0, 0.5, 0.5); 
            break;
        case 3:
            matColor = float3(0.5, 0, 0.5); 
            break;
        default:
            break;
        }
        if (matIndex < 0 && matIndex >-1) {
            Kd = lerp(Kd, 0, -matIndex);
            Ks = lerp(Ks, 0, -matIndex);
            Ka = lerp(Ka, 0, -matIndex);
        }
        float3 amibent = Ka * GlobalAmibent * matColor;
        float3 diffuse = Kd * LightColor * clamp(dot(normalDir, lightDir), 0, 1) * matColor;
        fixed3 reflectDir = reflect(-lightDir, normalDir);
        float3 specular = Ks * LightColor * pow(clamp(dot(viewDir, reflectDir), 0, 1), Shininess) * matColor;
        color1 = amibent;
        color2 = diffuse + specular;
    }

    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);
        fixed3 lightPos = PointLightPos;
        fixed3 lightDir = normalize(lightPos - pos);

        float3 c1, c2;
        BasicPhong(lightDir, nor, rd, m, c1, c2);
        float isInShadow = IsInShadow(pos, lightDir);
        float3 color = c1 + isInShadow * c2;
        return color;
    }
    
    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/7607626.html

相关文章:

  • es6--symbol
  • 元组、函数详解
  • jQuery基本过滤选择器
  • HTML5实现文字轮滚
  • App案例分析——XBMC
  • Hadoop- Hadoop详解
  • numpy的random模块
  • Django的思维导图
  • IPhone8才是真正的智能手机
  • Sublime Text 中配置 Eslint 代码检查和自动修复
  • JQuery UI 入门
  • 记录一下open***,填坑之路
  • 一个更好的可视化微服务架构的方式
  • get/set方法
  • 用C#实现字符串相似度算法(编辑距离算法 Levenshtein Distance)
  • 【comparator, comparable】小总结
  • 【刷算法】从上往下打印二叉树
  • Elasticsearch 参考指南(升级前重新索引)
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • js算法-归并排序(merge_sort)
  • Lsb图片隐写
  • mongo索引构建
  • Netty 4.1 源代码学习:线程模型
  • Sass Day-01
  • STAR法则
  • 阿里研究院入选中国企业智库系统影响力榜
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 程序员该如何有效的找工作?
  • 技术胖1-4季视频复习— (看视频笔记)
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 如何解决微信端直接跳WAP端
  • 算法-插入排序
  • 温故知新之javascript面向对象
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • 转载:[译] 内容加速黑科技趣谈
  • mysql面试题分组并合并列
  • ​ArcGIS Pro 如何批量删除字段
  • # Maven错误Error executing Maven
  • #Linux(权限管理)
  • #vue3 实现前端下载excel文件模板功能
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (黑马C++)L06 重载与继承
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (已解决)什么是vue导航守卫
  • ***利用Ms05002溢出找“肉鸡
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • ./和../以及/和~之间的区别
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .CSS-hover 的解释
  • .net core 控制台应用程序读取配置文件app.config
  • .Net小白的大学四年,内含面经