1 前言

​ 着色器(Shader)是渲染管线中最重要的一环,Unity3D 底层基于 OpenGL 实现,读者可以通过 渲染管线 了解 Unity3D 渲染流程。

​ OpenGL 1.x 为固定管线,2.x 之后才支持可编程管线,Unity3D 固定管线着色器使用 ShaderLab 语言实现。ShaderLab 是 Unity Shader 的服务语言,是基于命令的语言。

​ 每个游戏对象需要绑定至少一个材质(Material)才能渲染,即使材质为 None,系统也会绑定一个默认的材质。每个材质都需要绑定一个Shader,系统一般默认绑定 Standard Shader,用户也可以绑定到自定义的 Shader 上。当用户创建好 Material 和 Shader 后,选中 Material,在 Inspector 窗口通过如下方式绑定到自定义 Shader 上:

2 Shader 代码框架

​ 在 Assets 窗口右键,依次选择【Create→Shader→Unity Shader】创建 Shader 脚本,其代码框架如下:

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 定义外部属性
} SubShader
{
Pass
{
Color(1, 0, 0, 1) // 固定渲染颜色
}
} Fallback "Diffuse"
}

​ 将 ShaderTest 绑定到一个 Material 上,并将该 Material 拖拽到一个 Cube 和 Sphere 游戏对象上,显示效果如下:

3 Shader 外部属性

1)定义外部属性

​ 在 Properties 模块中可以定义外部属性如下:

Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_FloatValue ("浮点数", Float) = 0.4
_RangeValue ("浮点数范围", Range(0, 1)) = 0.5
_VectorValue ("四维数", Vector) = (1, 2, 3, 4)
_ColorValue ("颜色", Color) = (1, 0, 0, 1)
_Texture2D ("2阶贴图", 2D) = "white" {}
_TextureRect ("非二阶贴图", Rect) = "white" {}
_TextureCube ("立方体贴图", Cube) = "" {}
}

​ 选中绑定的 Material,查看 Inspector 窗口如下,用户可以在这里调整 Properties 里定义的变量的值。

2)使用外部属性

​ 在 Pass 模块,用户可以通过 "[属性名]" 使用 Properties 里定义的变量,如下:

Pass
{
Color[_ColorValue]
Color([_ColorR], [_ColorG], [_ColorB], [_ColorA])
}

3)案例

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_ColorR ("Color_R", Range(0, 1)) = 0.5
_ColorG ("Color_G", Range(0, 1)) = 0.5
_ColorB ("Color_B", Range(0, 1)) = 0.5
_ColorA ("Color_A", Range(0, 1)) = 0.5
} SubShader
{
Pass
{
Blend SrcAlpha OneMinusSrcAlpha // Alpha混合
Color([_ColorR], [_ColorG], [_ColorB], [_ColorA])
}
} Fallback "Diffuse"
}

4)代码控制外部属性

​ 在 MonoBehaviour 脚本组件中获取和保存 Shader 中变量值的方法如下:

private void GetColor() { // 获取颜色
color[0] = meshRenderer.material.GetFloat("_ColorR");
color[1] = meshRenderer.material.GetFloat("_ColorG");
color[2] = meshRenderer.material.GetFloat("_ColorB");
color[3] = meshRenderer.material.GetFloat("_ColorA");
} private void SaveColor() { // 保存颜色
meshRenderer.material.SetFloat("_ColorR", color[0]);
meshRenderer.material.SetFloat("_ColorG", color[1]);
meshRenderer.material.SetFloat("_ColorB", color[2]);
meshRenderer.material.SetFloat("_ColorA", color[3]);
}

​ 说明:_ColorR、_ColorG、_ColorB、_ColorA 是 Shader 中定义的 Range 类型外部属性。

5)代码控制纹理缩放和偏移

​ 在 Shader 中定义 2D 类型外部属性,选中 Material 后,在 Inspector 窗口可以看到出现了 Tiling 和 Offset 属性,如下,这两个属性分别用于纹理缩放和偏移。

​ 在 MonoBehaviour 脚本组件中设置纹理缩放和偏移的方法如下:

meshRenderer.material.SetTexture("_Texture2D", texture) // 设置纹理
meshRenderer.material.SetTextureScale("_Texture2D", new Vector2(2, 2)) // 设置Tiling
meshRenderer.material.SetTextureOffset("_Texture2D", new Vector2(Time.time, 0)) // 设置Offset

​ 说明:_Texture2D 是 Shader 中定义的 2D 类型外部属性。

4 光照

​ 光照原理见→Blinn改进的冯氏光照模型

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_AmbientColor ("环境光颜色", Color) = (1, 1, 1, 1)
_DiffuseColor ("漫反射光颜色", Color) = (1, 1, 1, 1)
_SpecularColor ("镜面反射光颜色", Color) = (1, 1, 1, 1)
_EmissionColor ("自发光颜色", Color) = (1, 1, 1, 1)
_Shininess ("光泽度", Range(0, 1)) = 0.5
} SubShader
{
Pass
{
Lighting On // 开启顶点光照
SeparateSpecular On // 开启镜面反射光照
Material
{
Ambient[_AmbientColor] // 环境光颜色
Diffuse[_DiffuseColor] // 漫反射光颜色
Specular[_SpecularColor] // 镜面反射光颜色
// Emission[_EmissionColor] // 自发光颜色
Shininess[_Shininess] // 光泽度, 用于调整镜面反射范围
}
}
} Fallback "Diffuse"
}

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

5 贴图

1)贴图简单应用

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_Texture2D ("2阶贴图", 2D) = "white" {}
} SubShader
{
Pass
{
SetTexture[_Texture2D]
{
Combine Texture
}
}
} Fallback "Diffuse"
}

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

2)贴图与固定颜色混合

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_ConstantColor ("固定颜色", Color) = (1, 1, 1, 1)
_Texture2D ("2阶贴图", 2D) = "white" {}
} SubShader
{
Pass
{
SetTexture[_Texture2D]
{
// 可以用"+"号, 也可以用"*"号, "+"号偏亮, "*"号偏暗, 可以使用Double(2倍数)、Quad(4倍)调整亮度
ConstantColor[_ConstantColor]
Combine Texture + Constant // Constant指上面的固定颜色
}
}
} Fallback "Diffuse"
}

​ 选中绑定的 Material,在 Inspector 窗口选择贴图图片,并调整固定颜色,显示效果如下:

3)贴图与光照混合

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_DiffuseColor ("漫反射光颜色", Color) = (1, 1, 1, 1)
_Texture2D ("2阶贴图", 2D) = "white" {}
} SubShader
{
Pass
{
Lighting On // 开启顶点光照
Material
{
Diffuse[_DiffuseColor] // 漫反射光颜色
} SetTexture[_Texture2D]
{
// 可以用"+"号, 也可以用"*"号, "+"号偏亮, "*"号偏暗, 可以使用Double(2倍数)、Quad(4倍)调整亮度
Combine Texture * Primary Quad // Primary指上面的Material
}
}
} Fallback "Diffuse"
}

​ 选中绑定的 Material,在 Inspector 窗口选择贴图图片,并调整漫反射颜色,显示效果如下:

4)多图混合

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_MainTexture2D ("主贴图", 2D) = "white" {}
_SecondTexture2D ("次贴图", 2D) = "white" {}
} SubShader
{
Pass
{
SetTexture[_MainTexture2D]
{
Combine Texture
} SetTexture[_SecondTexture2D]
{
// 可以用"+"号, 也可以用"*"号, "+"号偏亮, "*"号偏暗, 可以使用Double(2倍数)、Quad(4倍)调整亮度
Combine Texture * Previous Double // Previous指上面的_MainTexture2D
}
}
} Fallback "Diffuse"
}

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

5)多图渐变混合

​ FixedShader.shader

Shader "MyShader/ShaderTest"
{
Properties
{
// 属性名 ("面板显示名称", 类型) = 默认值
_MainTexture2D ("主贴图", 2D) = "white" {}
_SecondTexture2D ("次贴图", 2D) = "white" {}
_Lerp ("插值", Range(0, 1)) = 0.5
} SubShader
{
Pass
{
SetTexture[_MainTexture2D]
{
Combine Texture
} SetTexture[_SecondTexture2D]
{
ConstantColor(0, 0, 0, [_Lerp])
Combine Texture lerp(Constant) Previous // Previous指上面的_MainTexture2D
}
}
} Fallback "Diffuse"
}

​ 选中绑定的 Material,在 Inspector 窗口选择 2 个贴图图片。

​ LerpController.cs

using UnityEngine;

public class LerpController : MonoBehaviour {
private MeshRenderer meshRenderer;
private float lerp;
private float increateSpeed = 0.15f; private void Start () {
meshRenderer = GetComponent<MeshRenderer>();
lerp = meshRenderer.material.GetFloat("_Lerp");
} private void Update () {
OperateLerp();
} private void OperateLerp() { // 操作插值
float ver = Input.GetAxis("Vertical");
if (Mathf.Abs(ver) > 0.1) {
lerp = Camp(lerp + ver * increateSpeed * Time.deltaTime, 0, 1);
meshRenderer.material.SetFloat("_Lerp", lerp);
}
} private float Camp(float value, float min, float max) {
return Mathf.Max(Mathf.Min(value, max), min);
}
}

​ 将 LerpController 脚本组件挂在 Cube 和 Sphere 上,运行后通过↑ ↓ 按键调整插值比例,效果如下:

​ 声明:本文转自【Unity3D】固定管线着色器一

【Unity3D】固定管线着色器一的更多相关文章

  1. Shader基础(固定管线着色器)

    在Shader的编码中,要养成不加空格的习惯,否则会有时候出现一些错误 固定管线着色器: 优点:实现简单 缺点:处理的效果比较差 //设置Shader的路径 Shader "MyFixedS ...

  2. Unity3D ShaderLab 布料着色器

    Unity3D ShaderLab布料着色器 布料着色器是我们在虚拟现实中经常使用的着色器.本篇就来完成一个较为简单的布料着色器. 新建Shader,Material,InteractiveCloth ...

  3. (原)Unreal渲染模块 管线 - 着色器(1)

    @author: 白袍小道 转载悄悄说明下 随缘查看,施主开心就好 说明: 本篇继续Unreal搬山部分的渲染模块的Shader部分, 主要牵扯模块RenderCore, ShaderCore, RH ...

  4. Unity3D内置着色器

    Unity内部提供了一些可以直接使用的着色器,这些内置着色器包括以下6个方面: (1)Performance of Unity shaders 着色器的性能和两个方面有关:shader本身和rende ...

  5. Unity3D学习笔记(三十四):Shader着色器(1)

    一.GPU:图形处理器,Graphics Processing Unit 显卡的处理器就是图形处理器.与CPU类似.   GPU和CPU的区别? 1.CPU主要是为了串行指令设计,GPU则是为了大规模 ...

  6. 编写Unity3D着色器的三种方式

    不管你会不会写Unity3D的shader,估计你会知道,Unity3D编写shader有三种方式,这篇东西主要就是说一下这三种东西有什么区别,和大概是怎样用的. 先来列一下这三种方式: fixed ...

  7. Shader开发之三大着色器

    固定功能管线着色器Fixed Function Shaders 固定功能管线着色器的关键代码一般都在Pass的材质设置Material{}和纹理设置SetTexture{}部分. Shader &qu ...

  8. [Unity] Shader(着色器)之固定管线

    在Unity中,固定管线Shader的性能是最好的. 什么是固定管线呢? 固定渲染管线 —— 这是标准的几何&光照(T&L)管线,功能是固定的,它控制着世界.视.投影变换及固定光照控制 ...

  9. Unity3d之Shader编程:子着色器、通道与标签的写法 & 纹理混合

    一.子着色器 Unity中的每一个着色器都包含一个subshader的列表,当Unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器. 我们知道,子着色器 ...

  10. 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 &amp; 纹理混合

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...

随机推荐

  1. 如何在Typora中跳转到文本内的指定位置?

    1.问题 网上写的使用HTML锚点,在typora并不适用 如 跳转 你好 2.解决 参考链接 https://segmentfault.com/q/1010000018057010 https:// ...

  2. Spring Boot+Vue实现汽车租赁系统(毕设)

    一.前言 汽车租赁系统,很常见的一个系统,但是网上还是以前的老框架实现的,于是我打算从设计到开发都用现在比较流行的新框架.想学习或者做毕设的可以私信联系哦!! 二.技术栈 - 后端技术 Spring ...

  3. ONVIF网络摄像头(IPC)客户端开发—最简RTSP客户端实现

    前言: 网上对于RTSP协议客户端的表述和实现非常不清晰,在实际使用中,FFMPEG和live555这些软件已经实现了RTSP客户端和服务端的所有功能,但是它们并没有将RTSP协议独立出来,通过看li ...

  4. [转帖]能使 Oracle 索引失效的六大限制条件

    Oracle 索引的目标是避免全表扫描,提高查询效率,但有些时候却适得其反. 例如一张表中有上百万条数据,对某个字段加了索引,但是查询时性能并没有什么提高,这可能是 oracle 索引失效造成的.or ...

  5. [转帖]Jmeter接口测试:参数化

    Jmeter接口请求中的参数经常需要通过参数进行赋值 引用形式:${} 变量时:${变量名} 函数时,${_函数名(参数1,参数2,参数3)} 值中"${n}"中,n为变量名:&q ...

  6. Oracle 核心列信息查看与处理

    Oracle 核心列信息查看与处理 背景 最近想对数据库表进行跨数据之间的比照 因为有一些自增列或者是时间戳的列不需要进行对比 后者是对比容易导致失真. 所以就准备选用其他方式进行一下处理. 本文主要 ...

  7. [转帖]java -d 参数(系统属性) 和 环境变量

    https://www.cnblogs.com/limeiyang/p/16565920.html 1. -d 参数说明 通过 java -h 查看可知: 注意:-D= : set a system ...

  8. vue3自定义指令(防抖指令)与vue3与vue2指令的对比

    定义指令的变化 根据vue3文档的描述 https://v3.cn.vuejs.org/guide/migration/introduction.html#%E6%B8%B2%E6%9F%93%E5% ...

  9. vue3中context.emit遇见的坑

    场景描述 今天遇见一个问题 ,子组件向上抛出去的事件. 被执行了两次,原因是 context.emit('click', item.id) 你的事件名是click 将click更改为其他事件名称,就可 ...

  10. 【笔记】学到几个 golang 代码小技巧

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 从这篇文章学到:10个令人惊叹的Go语言技巧,让你的代码更 ...