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

【Unity3D】顶点和片段着色器

1 前言

        上文介绍了渲染管线、固定管线着色器和表面着色器,如下:

  • 渲染管线

  • 固定管线着色器一

  • 固定管线着色器二

  • 表面着色器

        固定管线着色器通过命令方式实现光照和贴图等效果,表面着色器通过给 SurfaceOutput 赋值实现光照、贴图和法线贴图等效果,它们都不用关注光照算法是如何实现的,只需要传值就行。

        顶点和片段着色器给用户提供了更灵活的用法,但使用也更困难。另外,顶点着色器可以通过控制 MVP 矩阵变换实现对模型位置和姿态的控制。

2 固定颜色

        在 Assets 窗口右键,依次选择【Create→Shader→Standard Surface Shader】创建 Shader 脚本,实现固定颜色 Shader 代码如下: 

        VFShader.shader

Shader "MyShader/VFShaderTest" {
	Properties
	{
		// 属性名 ("面板显示名称", 类型) = 默认值
		_MainColor ("显示颜色", Color) = (1, 0, 0, 1)
	}

	SubShader
	{
		Pass
		{
			CGPROGRAM // CG语言的开始
			// 编译指令 着色器名称 函数名称
			#pragma vertex vert // 顶点着色器, 每个顶点执行一次
			#pragma fragment frag // 片段着色器, 每个像素执行一次
			// 导入头文件
			#include "UnityCG.cginc"

			// 声明属性变量, 必须与外部属性变量名称一致
			fixed4 _MainColor;

			// 顶点着色器, 输入模型坐标, 输出屏幕坐标
			half4 vert(half4 vertexPos: POSITION): SV_POSITION
			{
				// 将模型坐标转换为屏幕坐标
				return UnityObjectToClipPos(vertexPos); // 等价于: mul(UNITY_MATRIX_MVP, vertexPos)
			}

			// 片段着色器, 输入模型坐标, 输出像素颜色
			fixed4 frag(): COLOR
			{
				return _MainColor;
			}

			ENDCG // CG语言的结束
		}
	}

	FallBack "Diffuse"
}

        创建一个 Material,并将 ShaderTest 绑定到该 Material 上,如下:

         将该 Material 拖拽到一个 Cube 和 Sphere 游戏对象上。选中绑定的 Material,在 Inspector 窗口调整 Shader 中固定颜色,显示效果如下:

3 光照

        VFShader.shader

Shader "MyShader/VFShaderTest" {
	Properties
	{
		// 属性名 ("面板显示名称", 类型) = 默认值
		_DiffuseColor ("漫反射颜色", Color) = (1, 0, 0, 1)
	}

	SubShader
	{
		Pass
		{
			Tags {"LightMode"="ForwardBase"}
			CGPROGRAM // CG语言的开始
			// 编译指令 着色器名称 函数名称
			#pragma vertex vert // 顶点着色器, 每个顶点执行一次
			#pragma fragment frag // 片段着色器, 每个像素执行一次

			// 导入头文件
			#include "UnityCG.cginc"

			// 声明属性变量, 必须与外部属性变量名称一致
			fixed4 _DiffuseColor;

			struct appdata // 顶点函数输入结构体
			{
				half4 vertexPos: POSITION; // 顶点坐标
				half3 vertexNormal: NORMAL; // 顶点法线向量
			};

			struct v2f // 顶点函数输出结构体
			{
				half4 screenPos: SV_POSITION; // 屏幕坐标
				half3 screenNormal: Normal; // 屏幕法线向量
			};

			// 顶点着色器, 输入模型坐标, 输出v2f
			v2f vert(appdata data)
			{
				v2f o;
				o.screenPos = UnityObjectToClipPos(data.vertexPos); // 等价于: mul(UNITY_MATRIX_MVP, data.vertexPos)
				o.screenNormal = mul(half4(data.vertexNormal, 1), unity_WorldToObject).xyz; // 将顶点法线转换为屏幕法线
				return o;
			}

			// 片段着色器, 输入模型坐标, 输出像素颜色
			fixed4 frag(v2f input): COLOR
			{
				half3 lightDir = normalize(_WorldSpaceLightPos0); // 光源照射方向向量, 由顶点指向光源
				half3 normalDir = normalize(input.screenNormal);
				// return _DiffuseColor * saturate(dot(lightDir, normalDir)) + UNITY_LIGHTMODEL_AMBIENT; // Lambert光照模型
				return _DiffuseColor * (0.5 * dot(lightDir, normalDir) + 0.5) + UNITY_LIGHTMODEL_AMBIENT; // 半Lambert光照模型
			}

			ENDCG // CG语言的结束
		}
	}

	FallBack "Diffuse"
}

        选中绑定的 Material,在 Inspector 窗口调整 Shader 中光照颜色,显示效果如下:

4 贴图

        VFShader.shader

Shader "MyShader/VFShaderTest" {
	Properties
	{
		// 属性名 ("面板显示名称", 类型) = 默认值
		_MainTex ("2阶贴图", 2D) = "white" {}
	}

	SubShader
	{
		Pass
		{
			Tags {"LightMode"="ForwardBase"}
			CGPROGRAM // CG语言的开始
			// 编译指令 着色器名称 函数名称
			#pragma vertex vert // 顶点着色器, 每个顶点执行一次
			#pragma fragment frag // 片段着色器, 每个像素执行一次

			// 导入头文件
			#include "UnityCG.cginc"

			// 声明属性变量, 必须与外部属性变量名称一致
			sampler2D _MainTex;

			struct appdata // 顶点函数输入结构体
			{
				half4 vertexPos: POSITION; // 顶点坐标
				half2 uv_MainTex: TEXCOORD0; // 纹理uv坐标
			};

			struct v2f // 顶点函数输出结构体
			{
				half4 screenPos: SV_POSITION; // 屏幕坐标
				half2 uv_MainTex: TEXCOORD0; // 纹理uv坐标
			};

			// 顶点着色器, 输入模型坐标, 输出v2f
			v2f vert(appdata data)
			{
				v2f o;
				o.screenPos = UnityObjectToClipPos(data.vertexPos); // 等价于: mul(UNITY_MATRIX_MVP, data.vertexPos)
				o.uv_MainTex = data.uv_MainTex;
				return o;
			}

			// 片段着色器, 输入模型坐标, 输出像素颜色
			fixed4 frag(v2f input): COLOR
			{
				return tex2D(_MainTex, input.uv_MainTex);
			}

			ENDCG // CG语言的结束
		}
	}

	FallBack "Diffuse"
}

        选中绑定的 Material,在 Inspector 窗口选择贴图图片,显示效果如下:

相关文章:

  • jmeter实战
  • 【零基础学QT】第十章 项目打包,利用Inno Setup制作软件安装包
  • LeetCode合并有序数组
  • 微信小程序分享一个视频给好友
  • 南大通用GBase8s 常用SQL语句(260)
  • Windows11 VMware-Ubuntu-Android12 源码下载和编译
  • javaMVC土特产交易平台系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  • 南大通用GBase8s 常用SQL语句(256)
  • 01-JVM-类加载篇
  • C#基础--泛型
  • 【云原生kubernetes从入门到实践系列教程 ] 四.docker volumes持久化
  • 如何用python自动化微信小程序
  • javaH5醉美南湾湖网站设计计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  • Windows11+VS2019驱动开发环境搭建
  • 文件防泄密系统如何保障企业文档的安全性?
  • [译]如何构建服务器端web组件,为何要构建?
  • JavaScript中的对象个人分享
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • node.js
  • Python学习笔记 字符串拼接
  • Theano - 导数
  • Vue 2.3、2.4 知识点小结
  • vue-loader 源码解析系列之 selector
  • Wamp集成环境 添加PHP的新版本
  • Xmanager 远程桌面 CentOS 7
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 从零开始在ubuntu上搭建node开发环境
  • 电商搜索引擎的架构设计和性能优化
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • ------- 计算机网络基础
  • 将回调地狱按在地上摩擦的Promise
  • 如何优雅地使用 Sublime Text
  • 时间复杂度与空间复杂度分析
  • 延迟脚本的方式
  • 一天一个设计模式之JS实现——适配器模式
  • 如何用纯 CSS 创作一个货车 loader
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #Ubuntu(修改root信息)
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (1)(1.13) SiK无线电高级配置(五)
  • (1)SpringCloud 整合Python
  • (Python第六天)文件处理
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (简单) HDU 2612 Find a way,BFS。
  • (译)计算距离、方位和更多经纬度之间的点
  • ***检测工具之RKHunter AIDE
  • ./configure,make,make install的作用
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .Net Web项目创建比较不错的参考文章
  • .NET 命令行参数包含应用程序路径吗?
  • [<死锁专题>]
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)