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

Unity | Shader基础知识(第十四集:简单效果练习)

目录

前言

一、效果预览

1.弧形边缘光

二、效果制作

1. 制作弧形边缘光

2.弧形边缘光进阶

3.弧形边缘光调节渐变范围

4.边缘光突变

5.同心圆

 三、加入世界坐标做效果

1.绘制结界

2.斑马球

3.效果合并

 四、作者的碎碎念


前言

有粉丝建议说,让我继续更新Shader,我可以出一些简单常用的效果,带着大家写一下,我觉得这是个好主意。

换句话说,带着大家看一下,学到的知识,应该怎么去应用。

我会把常见的调节的一些细致过程逐步写下来,如果遇见没讲过的知识点,就详细讲解一下。

一、效果预览

1.弧形边缘光

这个效果是,对于圆形或者圆弧形的物体,在边缘发光。(如图1所示)

图1 边缘光

二、效果制作

1. 制作弧形边缘光

我们先统一一下思路,发光用到的语义是自发光,之前有讲过,详情看链接。

Unity | Shader基础知识(第十二集:颜色混合)_shade 颜色混合接口-CSDN博客

边缘发光就是当我们的视线和法线的点乘的值在0附近,或0以下的时候,就发光,也是之前讲的,看链接。(如图2所示)Unity | Shader基础知识(第十三集:编写内置着色器阶段总结和表面着色器的补充介绍)_unity viewdir-CSDN博客

图2 viewDir

后面写代码,讲太多遍的就不重新注释了,只注释没讲过的。

Shader "Custom/010"
{Properties{//设置自发光的颜色_Color("Color",Color)=(0,0.5,0.5,0)}SubShader{CGPROGRAM#pragma surface surf Lambertfloat4 _Color;struct Input{//直接获取viewDirfloat3 viewDir;};void surf(Input IN,inout SurfaceOutput o){//点乘后,如果接近1,说明在视线正中,接近0则在视线边缘          half dotp =dot(IN.viewDir,o.Normal);//设置自发光,我们需要当正中时没有颜色,就是*0,在边缘有颜色,就是*1//和上面的数字刚好相反,所以我们用(1-dotp)来得到上面的效果o.Emission =_Color.rgb*(1-dotp);}ENDCG}
}

 得到效果为(如图3所示)

图3 发光球

2.弧形边缘光进阶

大部分模型都是有自己贴图的,所以我们在发光的基础上,加上贴图

Shader "Custom/010"
{Properties{//放图片进入_MainTex("MainTex",2D)="white"{} //设置自发光的颜色_Color("Color",Color)=(0,0.5,0.5,0)}SubShader{CGPROGRAM#pragma surface surf Lambertsampler2D _MainTex;float4 _Color;struct Input{float2 uv_MainTex;//直接获取viewDirfloat3 viewDir;};void surf(Input IN,inout SurfaceOutput o){//这都是之前讲过的,不进行二次讲解了o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb;//点乘后,如果接近1,说明在视线正中,接近0则在视线边缘          half dotp =dot(IN.viewDir,o.Normal);//设置自发光,我们需要当正中时没有颜色,就是*0,在边缘有颜色,就是*1//和上面的数字刚好相反,所以我们用(1-dotp)来得到上面的效果o.Emission =_Color.rgb*(1-dotp);}ENDCG}
}

得到的效果为(如图4所示)

图4 弧形边缘光进阶

3.弧形边缘光调节渐变范围

大部分时候,上面的发光范围都是有点大了,所以我们需要加个参数进行调节。

数学知识:

_Color.rgb*(1-dotp)中的(1-dotp)是一个线性变化的数据,变化是平均的,就像数数一样:0.1,0.2,0.3......

我们怎么才能让它的增长变快?前面一直比较小,越往后越大。

有一个非常简单的方法:平方

{0.1^{2}}{0.2^{2}}{0.3^{2}}.......

如果你觉得平方变化不满意,可以是其他次方

 所以我们增加一个参数,来改变光范围。

函数知识:

次方的公式是pow(底数,次方)

Shader "Custom/010"
{Properties{_MainTex("MainTex",2D)="white"{} _Color("Color",Color)=(0,0.5,0.5,0)//边缘光范围参数_Power("Power",Range(0.8,8)) = 3}SubShader{CGPROGRAM#pragma surface surf Lambertsampler2D _MainTex;float4 _Color;//接入参数float _Power;struct Input{float2 uv_MainTex;float3 viewDir;};void surf(Input IN,inout SurfaceOutput o){o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb;         half dotp =dot(IN.viewDir,o.Normal);//重新设置范围变化曲线o.Emission =_Color.rgb*pow((1-dotp),_Power);}ENDCG}
}

效果(如图5所示)

图5 弧形边缘光调节渐变范围
4.边缘光突变

截止到上图,虽然我们把边缘光可以锁定在非常边缘,但它的过度还是一个渐变的,如果我希望它不要渐变,而是突然出现,怎么办?

答:做条件判断(但在此之前,为了后面计算方便,我们对数据做一个简单的处理)

我们知道前面的乘积最终结果是(-1,1),但实际我们应用时,小于-1的部分,我们完全不需要,因为都是看不见的部分和0的效果一样。

函数知识:

当数据小于0时,直接取0,当数据大于1时,直接取1,其他数据不变。

saturate()

因为前面的代码没变,这里只复制修改过的代码块。(要么太长了)

    void surf(Input IN,inout SurfaceOutput o){o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb; //把小于0的数据都删掉half dotp =saturate(dot(IN.viewDir,o.Normal));o.Emission =_Color.rgb*pow((1-dotp),_Power);}

为了方便计算,我们把(1-dotp)也合并到上面。

    void surf(Input IN,inout SurfaceOutput o){o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb; //合并计算half dotp =1-saturate(dot(IN.viewDir,o.Normal));o.Emission =_Color.rgb*pow(dotp,_Power);}

我们可以进行突变判断,当dotp>0.8时,显示边缘光,反之不显示。

    void surf(Input IN,inout SurfaceOutput o){o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb; //合并计算half dotp =1-saturate(dot(IN.viewDir,o.Normal));//渐变边缘光(暂时废弃)//o.Emission =_Color.rgb*pow(dotp,_Power);//突变边缘光       //如果大于0.8,就等于1,反之等于0o.Emission =_Color.rgb*dotp>0.8?1:0;}

效果(如图6所示)

图6 突变边缘光

如果你还是希望有一点渐变,不太明显,哈哈~可以自己尝试。

        //有一点渐变o.Emission =_Color.rgb*dotp>0.8?dotp:0;
5.同心圆

同样继续利用这个规律,我们可以做出同心圆。打了注释的地方是有增加,其他地方不变。

Shader "Custom/010"
{Properties{_MainTex("MainTex",2D)="white"{} //外圈颜色_Color("Color",Color)=(0,0.5,0.5,0)//内圈颜色_Color2("Color2",Color)=(0,0.5,0.5,0)_Power("Power",Range(0.8,8)) = 3}SubShader{CGPROGRAM#pragma surface surf Lambertsampler2D _MainTex;//外圈声明float4 _Color;//内圈声明float4 _Color2;float _Power;struct Input{float2 uv_MainTex;float3 viewDir;};void surf(Input IN,inout SurfaceOutput o){o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb; half dotp =1-saturate(dot(IN.viewDir,o.Normal));//同心圆o.Emission =dotp>0.5?_Color.rgb:_Color2.rgb;}ENDCG}
}

效果(如图7所示)

图7 同心圆

备注:多层同心圆

//多层同心圆                                            //用了个绿色
o.Emission =dotp>0.8?_Color.rgb:dotp>0.5?_Color2.rgb:float4(0,1,0,0);
图8 多层同心圆

 三、加入世界坐标做效果

1.绘制结界

动画片里经常有那种从地底下穿越上来,东西就变色了,这里也可以做这种效果,不过,我们需要先加入世界坐标。

其他的代码还是用之前的,改了改了哪里下面就替换哪部分!!!

    struct Input{float2 uv_MainTex;float3 viewDir;//加入世界坐标float3 worldPos;};

当y>0时,变色~

    void surf(Input IN,inout SurfaceOutput o){o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb; half dotp =1-saturate(dot(IN.viewDir,o.Normal));//绘制结界o.Emission =IN.worldPos.y>0?_Color:float4(1,1,1,1);}

效果(如图9所示)

图9 结界球
2.斑马球

 我们继续对世界坐标做文章,无论我们球的y坐标是多少,我们把奇数染成白的,偶数染成黑的。

数学知识:

整数位是偶数,除以2,结果的小数位在0~0.5之间

整数位是奇数,除以2,结果的小数位在0.5~1之间

备注:你们可以验证一下

3.2/2=1.6,因为3.2的整数位3是奇数,所以结果的小数位0.6,在0.5~1之间。

函数知识:

取小数的函数。

frac()

例:frac(16.89)=0.89

因为我们的球目前本来就不大,所以我们把y坐标都乘10,然后再计算。

    void surf(Input IN,inout SurfaceOutput o){half dotp =1-saturate(dot(IN.viewDir,o.Normal));//绘制斑马                                    //黑色        //白色o.Emission = frac(IN.worldPos.y*10/2)>0.5?float4(1,1,1,1):float4(0,0,0,0);}

效果(如图10所示)

图10 斑马球
3.效果合并

我们可以把之前的边缘光效果和贴图效果再打开。

    void surf(Input IN,inout SurfaceOutput o){//打开贴图o.Albedo =tex2D(_MainTex,IN.uv_MainTex).rgb; half dotp =1-saturate(dot(IN.viewDir,o.Normal));//绘制斑马o.Emission = frac(IN.worldPos.y*10/2)>0.5?//颜色乘了边缘光那会的数值    
float4(1,1,1,1)*dotp:float4(0,0,0,0)*dotp;}

效果(如图11所示)

图11 效果合并

是不是有那味了~ 

 四、作者的碎碎念

考虑到好多宝宝,学了功能也不知道怎么去用, 专门出了这个简单应用专题,供大家练习。

喜欢的话希望大家给我点赞,收藏加关注哦~ღ( ´・ᴗ・` )比心

相关文章:

  • 22.2 正则表达式-数据验证、数据变换
  • 广东工业大学领导一行莅临泰迪智能科技参观交流
  • 分数布朗运动FBM期权定价模型
  • SpringCloud 网关Gateway配置并使用
  • .NET MAUI Sqlite程序应用-数据库配置(一)
  • Luma AI如何注册:文生视频领域的新星
  • target目录的文件上传controller,无需做静态映射。以及上传路径配置
  • TQZC706开发板教程:10G光口ping测试
  • C++中的解释器模式
  • Java -jar 运行 报 MalformedInputException: Input length = 1
  • Mongodb数据库基本操作
  • jeecg快速启动(附带本地运行可用版本下载)
  • 可穿戴设备:苹果“吃老底”、华为“忙复苏”、小米“再扩容”
  • Java数据类型及运算符及数组(与C语言对比)
  • 数据治理:让数据提取更高效、更准确的关键
  • 3.7、@ResponseBody 和 @RestController
  • 77. Combinations
  • CSS相对定位
  • Flex布局到底解决了什么问题
  • Git初体验
  • interface和setter,getter
  • Java 23种设计模式 之单例模式 7种实现方式
  • JavaScript 奇技淫巧
  • JavaScript设计模式之工厂模式
  • JavaScript中的对象个人分享
  • JAVA多线程机制解析-volatilesynchronized
  • leetcode讲解--894. All Possible Full Binary Trees
  • Linux中的硬链接与软链接
  • Map集合、散列表、红黑树介绍
  • node和express搭建代理服务器(源码)
  • Object.assign方法不能实现深复制
  • 今年的LC3大会没了?
  • 删除表内多余的重复数据
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • #pragma once与条件编译
  • (Git) gitignore基础使用
  • (第61天)多租户架构(CDB/PDB)
  • (分布式缓存)Redis哨兵
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (转)用.Net的File控件上传文件的解决方案
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • ******IT公司面试题汇总+优秀技术博客汇总
  • .bat批处理出现中文乱码的情况
  • .mysql secret在哪_MySQL如何使用索引
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .NET:自动将请求参数绑定到ASPX、ASHX和MVC(菜鸟必看)
  • .NET上SQLite的连接
  • .Net中ListT 泛型转成DataTable、DataSet