Unity | Shader基础知识(第八集:案例<漫反射材质球>)

目录

一、本节介绍

1 上集回顾

2 本节介绍

二、什么是漫反射材质球

三、 漫反射进化史

1 三种算法结果的区别

2 具体算法

2.1 兰伯特逐顶点算法

a.本小节使用的unity自带结构体。

b.兰伯特逐顶点算法公式

c.代码实现——兰伯特逐顶点算法

2.2 代码实现——兰伯特逐像素算法

a.像素和顶点算法的区别

b.实现代码

 2.3 代码实现——半兰伯特算法

a.为什么会出现半兰伯特

b.半兰伯特公式

c.代码实现

四、下集介绍


一、本节介绍

1 上集回顾

本集讲了如何让图片和外部颜色叠加显示。

2 本节介绍

如何做一个漫反射材质球。

二、什么是漫反射材质球

1 之前的颜色材质球

我们目前只学过直接上色的材质球(如图1所示),还有上节课的颜色和图片叠加的材质球。

图1 材质球

2 现实的光照下的球

现实光照下的大部分材质球并不是纯色且全亮的,而是(如图2所示)。

图2 现实中的球

 这种模拟大部分现实世界物体发光的状态,就是漫反射材质球。

备注:

反射有两种:镜面反射和漫反射。像镜子的反光,非常光滑的物体反光(比如金属),属于镜面反射,其他大部分是漫反射。具体区别详见初中物理~自己百度哦o(* ̄︶ ̄*)o

三、 漫反射进化史

我们算到最后,对屏幕来说,仅仅想知道,我这个点应该用什么颜色。

所以,对这个颜色的计算出现了三种解法。

  • 兰伯特逐顶点算法
  • 兰伯特逐像素算法
  • 半兰伯特算法

备注:兰伯特是个人,他和别人一起研究出来了以上三个定律。

1 三种算法结果的区别

兰伯特逐顶点算法(白色和黑色交界处有些方块块的感觉、照不到的地方全黑)

兰伯特逐像素算法(白色和黑色交界处平滑过渡、照不到的地方全黑)

半兰伯特算法(白色和黑色交界处平滑过渡、照不到的地方不是全黑)

内容参考(侵权立删):

Unity Shader 漫反射(Lambert、Half Lambert) - 知乎

图3 三种算法得到的效果

2 具体算法

2.1 兰伯特逐顶点算法
a.本小节使用的unity自带结构体。
struct appdata_full {float4 vertex : POSITION;    //顶点坐标float4 tangent : TANGENT;    //切线float3 normal : NORMAL;      //法线float4 texcoord : TEXCOORD0;    //第一纹理坐标float4 texcoord1 : TEXCOORD1;//第二纹理坐标float4 texcoord2 : TEXCOORD2;//第三纹理坐标float4 texcoord3 : TEXCOORD3;//第四纹理坐标fixed4 color : COLOR;        //顶点颜色UNITY_VERTEX_INPUT_INSTANCE_ID    //ID信息
};
b.兰伯特逐顶点算法公式


公式解释:

屏幕上对应点的颜色 = (光的颜色*物体的颜色)*max(0,该点的法向量*该点的光照方向)


备注(max函数解释):

max(a,b),如果这里面a大,答案就是a

如果b大,答案就是b。

例:

max(5,20)=20

max(8,-9)=8

此处的作用:

因为颜色没有负数,如果n*l算出来小于0的时候,就直接为0,其他时候就是n*l的值。

其实就是起一个“一刀切”掉负数的作用。


得出结论:我们想计算漫反射的时候屏幕显示什么颜色,我们需要光的颜色物体的颜色该点的法向量(单位向量)该点的光照方向(单位向量)

备注:公式里的字母上带^就是单位向量的意思。

c.代码实现——兰伯特逐顶点算法

计算注意事项:

在计算n*l时,注意:该点的法向量(往往直接获取的是物体本地坐标),该点的光照方向(往往获取的是世界坐标)

这样是不能乘的,所以需要把他们都换算到一个坐标系,这里换算到世界坐标下。

会用到的方法:

UnityObjectToWorldNormal()     //把物体的法线坐标,换算到世界坐标下
normalize()                    //把任何一个向量变成单位向量
dot()                          //点乘
max()                          //上文讲过_WorldSpaceLightPos0           //世界坐标下的光线坐标//但是要引用#include "Lighting.cginc"才能找到

 实现的代码:

 SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"//新的引用#include "Lighting.cginc"//返回结构体        //引用结构体appdata_full vert (appdata_full v){    //模型顶点坐标转屏幕坐标v.vertex = UnityObjectToClipPos(v.vertex);//获取法线坐标并转换成世界坐标下的法线坐标float3 worldNormal = UnityObjectToWorldNormal(v.normal);//世界坐标下的光线坐标  //单位化坐标   //获取世界坐标下的光线坐标float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//上面的公式float3 diffuse =_LightColor0.rgb * v.color.rgb * max(0,dot(worldNormal,worldLight));//算出的值给颜色v.color = float4(diffuse,1);return v;}float4 frag (appdata_full v) : SV_Target{    //输出颜色    return float4(v.color,1) ;}ENDCG}}
2.2 代码实现——兰伯特逐像素算法
a.像素和顶点算法的区别
  • 从写法角度来看,顶点算法是在顶点着色器中写的,像素算法是在片元着色器中写的。
  • 从原理角度来说,因为顶点是初始值,经过一系列计算后,数据就会和我们想要的有些偏差。

例:让你拿笔写一个字,你可能就写了,但是让你拿竹竿上面绑个中性笔写字,你就写不准了,肯定是离画出来的地方越近,画出来越是自己想要的。

结论:像素着色器离最后的显示比较近,所以出来的结果和我们想要的更一致。

b.实现代码
Shader "Unlit/005_1"
{SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"appdata_full vert (appdata_full v){   v.vertex = UnityObjectToClipPos(v.vertex);//把法线转换成世界坐标,传进去v.normal = UnityObjectToWorldNormal(v.normal);return v;}float4 frag (appdata_full v) : SV_Target{//法线世界坐标float3 worldNormal = v.normal;//光线世界坐标float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//计算颜色float3 diffuse =_LightColor0.rgb * v.color.rgb * max(0,dot(worldNormal,worldLight));//把颜色传进去return float4(diffuse,1) ;}ENDCG}}
}
 2.3 代码实现——半兰伯特算法
a.为什么会出现半兰伯特

兰伯特的两个算法,得到的球,在没有光线照射的时候都是黑色的,但玩游戏的时候往往希望,虽然光线无法照到,但我们可以看见。

数学知识:公式中的n*l值的范围是【-1,1】之间,我们希望把这个区间改成【0,1】(前面的课学过),【-1,1】*0.5+0.5,就可以转成【0,1】,0的时候就是之前光照模型中黑色部分,越靠近1越亮。

因为我们实际上并不是需要它看不见,只是需要它要明暗变化,所以我们在环境光的基础上加上兰伯特公式计算出的值,就有了明暗变化。

于是就出现了第三种,半兰伯特。

b.半兰伯特公式

在上图基础上:

最终颜色  = 环境光+Cdiffuse

c.代码实现

这里其他代码都没有变,只更改了上图0.5的部分。最后输出前,再加入环境光。

备注:

获取环境光强度的方法:UNITY_LIGHTMODEL_AMBIENT.xyz

Shader "Unlit/005_2"
{SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"appdata_full vert (appdata_full v){v.vertex = UnityObjectToClipPos(v.vertex);v.normal = UnityObjectToWorldNormal(v.normal);return v;}float4 frag (appdata_full v) : SV_Target{float3 worldNormal = v.normal;float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//本节变动//获取环境光float3 anbient = UNITY_LIGHTMODEL_AMBIENT.xyz;//计算范围float halfLamient = dot(worldNormal,worldLight)*0.5+0.5;//计算反射强度float3 diffuse =_LightColor0.rgb * v.color.rgb *halfLamient;//反射光加光照强度float3 c = anbient + diffuse;return float4(c,1) ;}ENDCG}}
}

四、下集介绍

本集讲了3种计算反射光的方法。

下集讲光照计算,高光反射。(最晚更新日期,1月7日)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/236813.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】初识模板

本文目录 1. 泛型编程2. 函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 3. 类模板3.1 类模板的定义格式3.2 类模板的实例化 1. 泛型编程 如何实现一个通用的交换函数呢? void Swap(int& left, int&…

【控制器局域网】CAN报文学习笔记(四)之 字节排序、信号提取实例1

以下面的表格来表示字节顺序和位顺序,用红色表示高位MSB,蓝色表示低位LSB,绿色为LSB到MSB的过度 Bit oderMSB→→→→→→LSBByte oder\Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0MSBByte076543210↓Byte115141312111098↓Byte22322212019181716↓By…

【Proteus/8086】swjtu西南交大微机与接口技术实验:计时器

实验内容: 计时器基本功能: 1)CPU必须用8086 2)计时器最小计时单位为秒。 3)以00:00格式显示计时,前2位表示分钟,后2位表示秒。 4)计时器是正计时方式 5)有暂停、继续计时功能 6)有复位计时功能 7)每次按下暂停键,能显示计时间隔时间 参考…

Vue 2.5 入门学习记录

Vue 2.5 入门学习记录 1. 基础知识Vue 是什么Vue引入方式Vue特点Vue实例中的数据事件方法Vue中的属性绑定和双向绑定Vue中的v-if、v-show、v-fortoDoList制作局部组件&全局组件 2. vue-cli工程3. 工程案例实践使用vue-cli实现todoList及删除某个元素全局样式与局部样式 4. …

CentOS安装Python解释,CentOS设置python虚拟环境,linux设置python虚拟环境

一、安装python解释器 1、创建解释器安装的目录:/usr/local/python39 cd /usr/local mkdir python39 2、下载依赖 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel xz-devel …

IEEE TASLP | 联合语音识别与口音识别的解耦交互多任务学习网络

尽管联合语音识别(ASR)和口音识别(AR)训练已被证明对处理多口音场景有效,但当前的多任务ASR-AR方法忽视了任务之间的粒度差异。细粒度单元(如音素、声韵母)可用于捕获与发音相关的口音特征&…

Certum的ip数字证书

Certum是欧洲第一个通过WebTrust的CA认证机构,几十年来不断发展,旗下的数字证书产品也日益增多,不仅有各种类型的域名数字证书,还有专为公网IP地址准备的DV基础型IP证书。今天就随SSL盾小编了解Certum旗下的DV基础型IP证书。 1.C…

使用RedisCacheWriter#clean在线异步地批量扫描匹配删除缓存数据-spring-data-redis

1.背景 生产环境,某云的某个业务Redis实例,触发内存使用率,连续 3 次 平均值 > 85 %告警。 运维同学告知,看看需要怎么优化或者升级配置?分享了其实例RDB的内存剖析链接。 通过内存剖析详情发现,存在某…

【深入使用】PHP的PDO 基本使用

前言: PDO:数据库抽象层 简介:PDO扩展为PHP访问数据库定义了一个轻量级的、一致性的接口,PDO解决了数据库连接不统一的问题。是PHP 5新加入的一个重大功能 【为什么要使用PDO】? PDO是PHP5新加入的一个重大功能&a…

ansible在ubuntu下的安装和使用

ansible在ubuntu下的安装和使用 本文目录 ansible在ubuntu下的安装和使用安装和配置虚拟机配置安装和验证 简单使用创建 ansible cfg 和 inventory 文件创建剧本并执行使用 ansible vault 加密 安装和配置 中文文档:http://www.ansible.com.cn/docs/intro_installa…

力扣:203. 移除链表元素(Python3)

题目: 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 来源:力扣(LeetCode) 链接:力扣(LeetCode)官网 …

芋道前端框架上线之后发现element-ui的icon图标全部乱码

前言 最近发现线上有人反映图标全部是乱码,登录上去看确实乱码,刷新就好最后一顿搜,发现是sass版本不兼容导致的图标乱码问题 解决办法 1.先把sass升级到1.39.0 2.来到vue.config.js文件配置代码-如果是芋道前端框架不用配置自带 css: {lo…

使用Docker部署Nexus Maven私有仓库并结合Cpolar实现远程访问

文章目录 1. Docker安装Nexus2. 本地访问Nexus3. Linux安装Cpolar4. 配置Nexus界面公网地址5. 远程访问 Nexus界面6. 固定Nexus公网地址7. 固定地址访问Nexus Nexus是一个仓库管理工具,用于管理和组织软件构建过程中的依赖项和构件。它与Maven密切相关,可…

Ruckus Wireless Admin 命令执行漏洞复现(CVE-2023-25717)

0x01 产品简介 Ruckus Wireless Admin是ruckuswireless多个路由、硬件设备的后台管理系统。 0x02 漏洞概述 Ruckus Wireless Admin在10.4 及更早版本存在命令执行漏洞。攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限&#xff0c…

Axure之中继器的使用(交互动作reperter属性Item属性)

目录 一.中继器的基本使用 二.中继器的动作(增删改查) 2.1 新增 2.2 删除 2.3 更新行 2.4 效果展示 2.5 模糊查询 三.reperter属性 在Axure中,中继器(Repeater)是一种功能强大的组件,用于创建重复…

Spring Boot学习随笔- 文件上传和下载(在线打开、附件下载、MultipartFile)

学习视频:【编程不良人】2021年SpringBoot最新最全教程 第十二章、文件上传、下载 文件上传 文件上传是指将文件从客户端计算机传输到服务器的过程。 上传思路 前端的上传页面:提交方式必须为post,enctype属性必须为multipart/form-data开发…

html行内元素和块级元素的区别?

HTML中的元素可以分为两种类型:行内元素(inline)和块级元素(block) 文章目录 什么是行内元素什么是块级元素元素转换行内元素转块级元素块级元素转行内元素 区别总结 什么是行内元素 HTML的行内元素(inli…

VTK读写数据

png格式图片转jpg #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL2) VTK_MODULE_INIT(vtkInteractionStyle)#include <vtkSmartPointer.h> #include <vtkPNGReader.h> #include <vtkJPEGWriter.h> #include <vtkImageViewer2.h>…

论文中公式怎么降重 papergpt

大家好&#xff0c;今天来聊聊论文中公式怎么降重&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 论文中公式怎么降重 一、引言 在论文撰写过程中&#xff0c;公式是表达学…

php伪协议 [NISACTF 2022]easyssrf

打开题目 我们直接用 file:/// 协议读取看看flag文件 file:///flag 点击curl得到回响 得到提示告诉我们应该看看提示文件 file:///fl4g 跟着去访问了一下 再跟着去访问 从代码中我们可以看出 get传参file&#xff0c;我们用stristr检测file参数里面是否含有file&#xff…