Unity+Shader入门精要-1. 入门shader

今天开始正式整合学习的shader内容。

Simple Shader

主要介绍了大概的shader格式。

Shader "Unity Sgaders Book/Chapter 5/Simple Shader" //shader名
{Properties{//声明color类型的属性_Color("Color Tint", Color) = (1.0,1.0,1.0,1.0)}SubShader{Pass{Tags{"LightMode" = "ForwardBase"}CGPROGRAM#pragma vertex vert //顶点着色器函数#pragma fragment frag //片元着色器函数fixed4 _Color; //定义color类型//模型空间的输入顶点信息struct a2v {float4 vertex:POSITION; //模型空间的顶点坐标float3 normal:NORMAL;//模型空间的法线方向float4 texcoord:TEXCOORD0;//模型的第一套纹理坐标};//齐次裁剪空间的输出顶点信息struct v2f {float4 pos : SV_POSITION;//裁剪空间的顶点坐标fixed3 color : COLOR0;//颜色信息};//输入模型空间的顶点信息,经过顶点着色器函数,输出齐次裁剪空间的顶点信息v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);return o;}//输入齐次裁剪空间的顶点信息(经过插值之后),输出顶点颜色信息fixed4 frag(v2f i) : SV_Target{fixed3 c = i.color;c *= _Color.rgb;return fixed4(c,1.0);}ENDCG}}
}

其主要意义在于通过模型法线获取不同参数,从而在材质面板中(材质面板默认显示球体,球体上每一个顶点的法线都不一样)显示一个颜色拾取器。效果如下图所示:

False Color

假彩色图像(false-color image)用于可视化一些数据,以方便对shader进行调试。即将想要的数据映射到[0-1]区间,作为颜色输出到屏幕上,然后通过屏幕上显示的像素颜色来判断这个值是否正确。通常用于debug。shader代码如下:

Shader "Unity Sgaders Book/Chapter 5/False Color"
{SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float4 pos:SV_POSITION;fixed4 color : COLOR0;};v2f vert(appdata_full v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//可视化法线方向o.color = fixed4(v.normal * 0.5 + fixed3(0.5,0.5,0.5),1);//可视化切线方向//o.color = fixed4(v.tangent * 0.5 + fixed3(0.5,0.5,0.5),1);//可视化第一组纹理坐标//o.color = fixed4(v.texcoord.xy, 0, 1);//可视化顶点颜色//o.color = v.color;return o;}//不知道作者为何在这里只输出一个fixed参数,即只利用了第一个颜色参数,输出出来的只有红色fixed frag(v2f i) :SV_Target{return i.color;}ENDCG}}
}

比如输出法线可视化,效果如下:

Diffuse Vertex Level/Diffuse Pixel Level

漫反射光照即是入射光线经法线后的反射光线的强度与“入射光线和发现之间的点积”有正比关系。颜色方面,需要叠加材质的漫反射颜色和入射光线的颜色。于是得出以下公式:

可以写下如下代码(逐顶点光照):

Shader "Unity Sgaders Book/Chapter 5/Diffuse Vertex Level"
{Properties{//声明color类型的属性_Diffuse("Diffuse", Color) = (1,1,1,1)}SubShader{Pass{Tags{"LightMode" = "ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Diffuse;struct a2v{float4 vertex:POSITION;float3 normal:NORMAL;};struct v2f{float4 pos:SV_POSITION;fixed3 color : COLOR;};v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//模型空间坐标转换为齐次裁剪空间fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光照信息fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));//转换法线从模型空间转为世界空间fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//标准化世界光照向量信息//光照公式,等于自发光+漫反射+环境光//这一步求漫反射fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));//这一步求漫反射和环境光交互o.color = ambient + diffuse;return o;}fixed4 frag(v2f i) :SV_Target{return fixed4(i.color,1);}ENDCG}}
}

其中Diffuse为可调整的漫反射颜色。除了本身的漫反射计算以外,还需要考虑环境光的交互,所以需要加上环境光的颜色。

效果如下:

可以看到逐顶点光照的缺点就是有很明显的锯齿状,对于细分程度较低的模型会遇到。因此可以采用逐像素光照,即把color赋值的操作转移到frag函数中实现,在顶点着色器部分只处理和顶点有关的数据转换即可:

Shader "Unity Sgaders Book/Chapter 5/Diffuse Pixel Level"
{Properties{//声明color类型的属性_Diffuse("Diffuse", Color) = (1,1,1,1)}SubShader{Pass{Tags{"LightMode" = "ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Diffuse;struct a2v{float4 vertex:POSITION;float3 normal:NORMAL;};struct v2f{float4 pos:SV_POSITION;float3 worldNormal:TEXCOORD0;};v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//模型空间坐标转换为齐次裁剪空间o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));//转换法线从模型空间转为世界空间return o;}fixed4 frag(v2f i) :SV_Target{fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光照信息fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//标准化世界光照向量信息//光照公式,等于自发光+漫反射+环境光//这一步求漫反射fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(i.worldNormal, worldLight));//这一步求漫反射和环境光交互fixed3 color = ambient + diffuse;return fixed4(color,1);}ENDCG}}
}

效果如下:

可以看到光滑了很多。

Half Lambert

以上介绍的是兰伯特光照模型,使用max(0,dot(n,I))来保证点积为非负数。我们也同样可以做α倍的缩放和β的偏移,来让dot(n,I)从[-1,1]的范围映射到[0,1]的范围,如下公式:

绝大部分情况,α=β=0.5。

因此稍微修改之前的逐像素光照模型即可完成任务:

Shader "Unity Sgaders Book/Chapter 5/Half Lambert"
{Properties{//声明color类型的属性_Diffuse("Diffuse", Color) = (1,1,1,1)}SubShader{Pass{Tags{"LightMode" = "ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Diffuse;struct a2v{float4 vertex:POSITION;float3 normal:NORMAL;};struct v2f{float4 pos:SV_POSITION;float3 worldNormal:TEXCOORD0;};v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);//模型空间坐标转换为齐次裁剪空间o.worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));//转换法线从模型空间转为世界空间return o;}fixed4 frag(v2f i) :SV_Target{fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//环境光照信息fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);//标准化世界光照向量信息//光照公式,等于自发光+漫反射+环境光//这一步求漫反射fixed halfLambert = saturate(dot(i.worldNormal, worldLight)) * 0.5 + 0.5;fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;//这一步求漫反射和环境光交互fixed3 color = ambient + diffuse;return fixed4(color,1);}ENDCG}}
}

效果如下:

显而易见地观察到,它会比之前的光照模型要亮,是因为几乎没有diffuse=0的情况,几乎所有点都是亮的。

Specular Vertex Level/Specular Pixel Level

除了漫反射,还需要考虑高光反射,高光反射的计算公式如下:

即入射光的颜色和强度作用于带有高光属性的材质上,其与“视角方向和反射方向的点积”成正比关系。

 因此延续漫反射光照模型继续写下去,只是添加了高光数据,如下逐顶点光照:

Shader "Unity Sgaders Book/Chapter 5/Specular Vertex Level"
{Properties{_Diffuse("Diffuse", Color) = (1,1,1,1) //声明color类型的属性_Specular("Specular",Color) = (1,1,1,1) //高光反射颜色_Gloss("Gloss",Range(8,256)) = 20 //高光区域大小}SubShader{Pass{......fixed4 _Diffuse;fixed4 _Specular;float _Gloss;......v2f vert(a2v v){......//光照反射fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));//计算入射光关于法线的反射方向fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);//视角方向fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);//这一步求漫反射和环境光和高光o.color = ambient + diffuse + specular;return o;}......}}
}

同样有锯齿问题,于是引入逐像素光照,和diffuse pixel level类似,只需要在顶点着色器内部处理顶点相关信息,在片元着色器内部处理颜色信息即可:

Shader "Unity Sgaders Book/Chapter 5/Specular Pixel Level"
{Properties{_Diffuse("Diffuse", Color) = (1,1,1,1) //声明color类型的属性_Specular("Specular",Color) = (1,1,1,1) //高光反射颜色_Gloss("Gloss",Range(8,256)) = 20 //高光区域大小}SubShader{Pass{......fixed4 _Diffuse;fixed4 _Specular;float _Gloss;......fixed4 frag(v2f i) :SV_Target{......//光照反射fixed3 reflectDir = normalize(reflect(-worldLightDir, i.worldNormal));//计算入射光关于法线的反射方向fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);//视角方向fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);//这一步求漫反射和环境光和高光fixed3 color = ambient + diffuse + specular;return fixed4(color,1);}ENDCG}}
}

效果如下所示:

BlinnPhong

BlinnPhong光照模型和Phong模型的区别则是:Phong的高光计算是视角与“入射光相对法线反射之后的光”作点积运算,而BlinnPhong的高光计算则是法线与“视角和入射光相加后归一化”的向量作点积运算。

因此只需要修改部分Specular Pixel Level的片元着色器代码即可完成任务:

            fixed4 frag(v2f i) :SV_Target{......//光照反射fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));//视角方向fixed3 halfDir = normalize(viewDir+worldLightDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(halfDir, i.worldNormal)), _Gloss);//这一步求漫反射和环境光和高光fixed3 color = ambient + diffuse + specular;return fixed4(color,1);}

 相比于Phong模型的高光反射部分看起来会更大更亮一些:

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

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

相关文章

【Osek网络管理测试】[TG3_TC3]tSleepRequestMin_L

🙋‍♂️ 【Osek网络管理测试】系列💁‍♂️点击跳转 文章目录 1.环境搭建2.测试目的3.测试步骤4.预期结果5.测试结果 1.环境搭建 硬件:VN1630 软件:CANoe 2.测试目的 验证DUT进入NMLimpHome状态后请求睡眠的最短时间是否正确…

Linux网络-部署YUM仓库及NFS共享服务

目录 一.YUM仓库服务 1.YUM概述 1.1.YUM(Yellow dog Updater Modified) 2.准备安装源 2.1.软件仓库的提供方式 2.2.RPM软件包的来源 2.3.构建CentOS 7 软件仓库 2.4.在软件仓库中加入非官方RPM包组 3.一键安装软件包的工具: 好处&a…

leetcode53-Maximum Subarray

题目 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 示例 1: 输入:nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#xf…

unittest_parameterized批量测试测试用例

import unittest from parameterized import parameterizeddef add(x, y):return xy"""问题:如果有三组数据需要测试?[(1,1,2), (1,2,3), (0,3,3)] """def get_data():return [(1, 2, 3), (3, 0, 3), (2, 1, 3)]# 定义测试…

Spring+SpringMVC+Jsp实现校园二手交易系统

前言介绍 在社会快速发展的影响下,使校园二手交易系统的管理和运营比过去十年更加理性化。依照这一现实为基础,设计一个快捷而又方便的网上校园二手交易系统是一项十分重要并且有价值的事情。对于传统的管理控制模型来说,网上校园二手交易系…

Llama3-Tutorial之XTuner微调Llama3个人小助手

Llama3-Tutorial之XTuner微调Llama3个人小助手 使用XTuner微调llama3模型。 参考: https://github.com/SmartFlowAI/Llama3-Tutorial 1. web demo部署 参考上一节内容已经完成web demo部署,进行对话测试, 当前回答基于llama3官方发布的模型进行推理生成&…

【算法刷题 | 贪心算法09】4.30(单调递增的数字)

文章目录 16.单调递增的数字16.1题目16.2解法&#xff1a;贪心16.2.1贪心思路16.2.2代码实现 16.单调递增的数字 16.1题目 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的…

学QT的第一天~

#include "mywidget.h" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) { //窗口相关设置// this->resize(427,330); this->setFixedSize(427,330); //设置图标 this->setWindowIcon(QIcon("C:\\Users\\Admin\\Desktop\\pictrue\\dahz.jpg&q…

MyCat安装配置,及数据分片

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

以自动检测为前提推进开发

许多人认为在软件开发中&#xff0c;测试工程是在开发的种后期阶段才实施的。当然&#xff0c;如果从“确认是否按照设计阶段设计的式样那样实现的”这一角度来看&#xff0c;测试工程的确是中后期才开始的&#xff0c;然而近几年这一顺序正在发生改变。 在所谓测试驱动开发的开…

ubuntu重安装libc

问题 ubuntu20.04 默认libc为2.31&#xff0c;使用某种方式升级到了2.35后&#xff0c;再回到2.31。 步骤 更新 libc-bin sudo apt-get download libc-bin# 上面的命令会下载 libc-bin_2.31-0ubuntu9.15_amd64.deb 包chmod ax libc-bin_2.31-0ubuntu9.15_amd64.debsudo dpkg…

无人机+三维建模:倾斜摄影技术详解

无人机倾斜摄影测量技术是一项高新技术&#xff0c;近年来在国际摄影测量领域得到了快速发展。这种技术通过从一个垂直和四个倾斜的五个不同视角同步采集影像&#xff0c;从而获取到丰富的建筑物顶面及侧视的高分辨率纹理。这种技术不仅能够真实地反映地物情况&#xff0c;还能…

浏览器跨域详解

一、什么是跨域 浏览器跨域是指当一个Web应用程序试图访问另一个协议、主机或端口不同的资源时&#xff0c;所发生的情况。这主要是由于浏览器的同源策略造成的&#xff0c;它是为了网站的安全而设置的安全限制&#xff0c;防止一个网站恶意访问另一个网站的资源。当然这是比较…

解决python/pycharm中import导入模块时报红却能运行的问题

一、问题 导入时报红&#xff0c;如下 二、解决 右键单击项目&#xff0c;将项目Mark Directory as→Sources Root 三、效果 报红消失 学习导航&#xff1a;http://www.xqnav.top

linux 设置开机自启终端,并自动执行命令

在Ubuntu 22.04中&#xff0c;可以通过创建一个名为 custom.desktop 的文件并将其放置在 /etc/xdg/autostart/ 目录中来实现开机自动打开命令行窗口并执行命令。 custom.desktop文件内容如下 [Desktop Entry] Version1.0 TypeApplication Namecustom Comment Execpython3 mai…

01背包问题+完全背包问题+多重背包问题+多重背包问题+分组背包问题

文章目录 01背包问题完全背包问题多重背包问题 I多重背包问题 II分组背包问题01背包问题 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输…

基于C++基础知识的循环语句

一、while循环 while循环语句形式如下&#xff1a; while(表达式){语句 } 循环每次都是执行完语句后回到表达式处重新开始判断&#xff0c;重新计算表达式的值&#xff0c;一旦表达式的值为假就退出循环。用花括号括起来的多条简单语句&#xff0c;花括号及其包含的语句被称…

淡茶和浓茶的标准

按照《品深淡茶冲泡标准》&#xff0c;淡茶茶汤中的咖啡碱不得高于31.67mg/100mL&#xff0c;可可碱不得高于2.67mg/mL&#xff0c;茶碱不得高于1.50mg/100mL&#xff0c;茶多酚不得高于143mg/mL&#xff0c;按照各类茶叶中各物质的含量情况&#xff0c;茶水比例不得高于1:150&…

JRT1.6发布

经过51的三天努力&#xff0c;完成基于JRT的质控核心部分。框架部分已经达到了第一个可生产版本。 可生产包括以下部分&#xff1a; 1.Web开发基础和发布运维基础 2.Linux和WIndows客户端浏览器 3.Linux和WIndows客户端打印导出程序 4.Linux和WIndows初始化程序 5.Linux和WInd…

《自动机理论、语言和计算导论》阅读笔记:p428-p525

《自动机理论、语言和计算导论》学习第 14 天&#xff0c;p428-p525总结&#xff0c;总计 98 页。 一、技术总结 1.Kruskal’s algorithm(克鲁斯克尔算法) 2.NP-Complete Problems p434, We say L is NP-complete if the following statements are true about L: (1)L is …