Unity Shader入门精要第七章 基础纹理渐变纹理

2023-11-09

Unity系列文章目录

前言

尽管在一开始,我们在渲染中使用纹理是为了定义一个物体的颜色,但后来人们发现,纹理
其实可以用于存储任何表面属性。一种常见的用法就是使用渐变纹理来控制漫反射光照的结果。
在之前计算漫反射光照时,我们都是使用表面法线和光照方向的点积结果与材质的反射率相乘来
得到表面的漫反射光照。但有时,我们需要更加灵活地控制光照结果。这种技术在游戏《军团要
塞2》(英文名:《Team Fortress 2》)中流行起来,它也是由Valve 公司(提出半兰伯特光照技术的
公司)提出来的,他们使用这种技术来渲染游戏中具有插画风格的角色。Valve 发表了一篇著名
的论文来专门讲述在制作《军团要塞2》时使用的技术。
这种技术最初由Gooch 等人在1998 年他们发表的一篇著名的论文《A Non-Photorealistic
Lighting Model For Automatic Technical Illustration》中被提出,在这篇论文中,作者提出了一种基
于冷到暖色调(cool-to-warm tones)的着色技术,用来得到一种插画风格的渲染效果。使用这种
技术,可以保证物体的轮廓线相比于之前使用的传统漫反射光照更加明显,而且能够提供多种色
调变化。而现在,很多卡通风格的渲染中都使用了这种技术。我们在14.1 节中会专门学习如何编
写一个卡通风格的Unity Shader。

一、渐变纹理是什么

在本节中,我们将学习如何使用一张渐变纹理来控制漫反射光照。在学习完本节后,我们可
以得到类似图7.18 中的效果。
在这里插入图片描述
可以看出,使用这种方式可以自由地控制物体的漫反射光照。不同的渐变纹理有不同的特性。
例如,在左边的图中,我们使用一张从紫色调到浅黄色调的渐变纹理;而中间的图使用的渐变纹
理则和《军团要塞2》中渲染人物使用的渐变纹理是类似的,它们都是从黑色逐渐向浅灰色靠拢,
而且中间的分界线部分微微发红,这是因为画家在插画中往往会在阴影处使用这样的色调;右侧
的渐变纹理则通常被用于卡通风格的渲染,这种渐变纹理中的色调通常是突变的,即没有平滑过
渡,以此来模拟卡通中的阴影色块。
为了实现上述效果,我们需要进行如下准备工作。
(1)在Unity 中新建一个场景。在本书资源中,该场景名为Scene_7_3。在Unity 5.2 中,默
认情况下场景将包含一个摄像机和一个平行光,并且使用了内置的天空盒子。在Window ->
Lighting -> Skybox 中去掉场景中的天空盒子。
(2)新建一个材质。在本书资源中,该材质名为RampTextureMat。
(3)新建一个Unity Shader。在本书资源中,该Unity Shader 名为Chapter7-RampTexture。把
新的Unity Shader 赋给第2 步中创建的材质。
(4)向场景中拖曳一个Suzanne 模型,并把第2 步中的材质赋给该模型。
(5)保存场景。
打开新建的Chapter7-RampTexture,删除所有已有代码,并进行如下修改。
(1)首先,我们需要为这个Shader 起一个名字:
Sh ader “Unity Shaders Book/Chapter 7/Ramp Texture” {
(2)我们在Properties 语义块中声明一个纹理属性来存储渐变纹理:
Properties {
_Color (“Color Tint”, Color) = (1,1,1,1)
_RampTex (“Ramp Tex”, 2D) = “white” {}
_Specular (“Specular”, Color) = (1, 1, 1, 1)
_Gloss (“Gloss”, Range(8.0, 256)) = 20
}
(3)然后,我们在SubShader 语义块中定义了一个Pass 语义块,并在Pass 的第一行指明了该
Pass 的光照模式:
SubShader {
Pass {
Tags { “LightMode”=“ForwardBase” }
LightMode 标签是Pass 标签中的一种,它用于定义该Pass 在Unity 的光照流水线中的角色。
(4)然后,我们使用CGPROGRAM 和ENDCG 来包围住Cg 代码片,以定义最重要的顶点着
色器和片元着色器代码。我们使用#pragma 指令来告诉Unity,我们定义的顶点着色器和片元着色
器叫什么名字。在本例中,它们的名字分别是vert 和frag:
CGPROGRAM
#pragma vertex vert
#p ragma fragment frag
(5)为了使用Unity 内置的一些变量,如_LightColor0,还需要包含进Unity 的内置文件
Lighting.cginc:
#i nclude “Lighting.cginc”
(6)随后,我们需要定义和Properties 中各个属性类型相匹配的变量:
fixed4 _Color;
sampler2D _RampTex;
float4 _RampTex_ST;
fixed4 _Specular;
fl oat _Gloss;
我们为渐变纹理_RampTex 定义了它的纹理属性变量_RampTex_ST。
(7)定义顶点着色器的输入和输出结构体:
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
};
(8)定义顶点着色器:
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(_Object2World, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _RampTex);
return o;
}
我们使用了内置的TRANSFORM_TEX 宏来计算经过平铺和偏移后的纹理坐标。
(9)接下来是关键的片元着色器:
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
// Use the texture to sample the diffuse color
fixed halfLambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
fixed3 diffuseColor = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb *
_Color.rgb;
fixed3 diffuse = _LightColor0.rgb * diffuseColor;
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal,
halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}
在上面的代码中,我们使用6.4.3 节中提到的半兰伯特模型,通过对法线方向和光照方向的点
积做一次0.5 倍的缩放以及一个0.5 大小的偏移来计算半兰伯特部分halfLambert。这样,我们得
到的halfLambert 的范围被映射到了[0,1]之间。之后,我们使用halfLambert 来构建一个纹理坐
标,并用这个纹理坐标对渐变纹理_RampTex 进行采样。由于_RampTex 实际就是一个一维纹理(它
在纵轴方向上颜色不变),因此纹理坐标的u 和v 方向我们都使用了halfLambert。然后,把从渐
变纹理采样得到的颜色和材质颜色_Color 相乘,得到最终的漫反射颜色。剩下的代码就是计算高
光反射和环境光,并把它们的结果进行相加。相信读者已经对这些步骤非常熟悉了。
(10)最后,我们为该Unity Shader 设置合适的Fallback:
Fa llback “Specular”
保存后返回场景。我们在本书资源中提供了多种渐变纹理,如Ramp_Texture0.psd 和
Ramp_Texture1.psd 等。读者可以尝试把不同的渐变纹理拖曳到材质面板查看效果。
需要注意的是,我们需要把渐变纹理的Wrap Mode 设为Clamp 模式,以防止对纹理进行采样
时由于浮点数精度而造成的问题。图7.19
给出了Wrap Mode 分别为Repeat 和Clamp
模式的效果对比。
可以看出,左图(使用Repeat 模式)
中在高光区域有一些黑点。这是由浮点精
度造成的,当我们使用fixed2(halfLambert,
halfLambert)对渐变纹理进行采样时,虽
然理论上halfLambert 的值在[0, 1]之间,
但可能会有1.000 01 这样的值出现。如果
我们使用的是Repeat 模式,此时就会舍
弃整数部分,只保留小数部分,得到的值
就是0.000 01,对应了渐变图中最左边的值,即黑色。因此,就会出现图中这样在高光区域反而
有黑点的情况。我们只需要把渐变纹理的Wrap Mode 设为Clamp 模式就可以解决这种问题。
在这里插入图片描述
在这里插入图片描述

参考

Unity Shader入门精要、
冯乐乐

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity Shader入门精要第七章 基础纹理渐变纹理 的相关文章

  • shiro拦截配置大全

    admins anon 表示该 uri 可以匿名访问 admins auth 表示该 uri 需要认证才能访问 admins authcBasic 表示该 uri 需要 httpBasic 认证 admins perms user add

随机推荐

  • 【文件I/O】(二)文件I/O

    文件I O 系统调用 一 文件I O基本概念 1 什么是文件I O 2 文件描述符 二 文件I O函数 head h 1 open close 打开 关闭文件 1 1open close函数API 1 2文件I O和标准I O文件打开方式对
  • [架构之路-181]-《软考-系统分析师》-19- 系统可靠性分析与设计 - 2-容错性: 软件容错技术

    目录 前言 1 9 4 软件容错技术 19 4 1 N 版本程序设计 1 与 通 常 软 件 开 发 过 程 的 区 别 2 其 他 需 要 注 意 的 问 题 19 4 2 恢复块方法 19 4 3 防卫式程序设计 预防性设计 广泛使用
  • HTML5移动开发常用meta标签

    html
  • 在IBM p6 570 LPAR之间动态切换磁盘机/光驱

    小机上的一些外设比如磁盘机和光驱平时用的不多 所以大多都是在一台小机的各LPAR之间共享使用的 这些IO设备在不同的LPAR之间使用时 只能被一个LPAR独占 所以必要的时候就必须要做切换 客户的一台p6 570 里面做了4个LPAR 需要
  • 回顾篇-mysql索引-读书笔记

    事务日志 事务日志可以帮助提高事务的效率 使用事务日志 存储引擎在修改表的数据时只需要修改其内存拷贝 再把该修改行为记录到持久在硬盘上的事务日志中 而不用每次都将修改的数据本身持久到磁盘 事务日志采用的是追加的方式 因此写日志的操作是磁盘上
  • STM32学习---时钟系统

    1 时钟树 STM32的时钟系统比较复杂 我们主要通过时钟树来了解单片机内部的时钟配置情况 时钟树可以从开发指南中找到 以f1为例 学习一下他的树 明确几个缩写定义 AHB 先进高速总线 APB1 先进设备总线1 APB2 先进设备总线2
  • ORM总结(单表,一对多,多对多)

    一 表记录的增删改查 单表操作 1 添加 时间的格式必须写成YYYY MM DD 2 删除 filter筛选多条记录 返回的是QuerySet集合对象 3 修改 这三种都是类 objects 4 查询 values是具体拿一个字段 不再拿整
  • Linux内核memcpy的不同实现

    目录 1 概述 2 高级SIMD和浮点寄存器介绍 2 NEON指令 2 1 VLDR 2 2 VLDM 2 3 VSTR 2 4 VSTM 3 ARM架构程序调用寄存器使用规则 3 1 ARM寄存器使用规则 3 2 NEON寄存器使用规则
  • 【Python】range函数

    range函数 Python3 range 函数返回的是一个可迭代对象 类型是对象 而不是列表类型 所以打印的时候不会打印列表 res range 6 print res gt gt gt range 0 6 打印出来的不是列表 Pytho
  • 2.1 主窗口

    Qt用QMainWindow和相关的类来管理主窗口 QMainWindow继承自QWidget类 以下介绍几种常用操作 1 close 关闭当前窗口 2 hide 隐藏当前窗口 相当于 setVisible false 设置窗口可见或是不可
  • CocosCreator3.0加载远程图片资源

    在微信小游戏平台 需要获取了微信头像 对于这个需求 需要这样来做 获取微信用户信息 得到微信小游戏头像的http地址 在Cocos引擎使用loadRemote来加载 这其中的问题在于 使用loadRemote加载时获得的对象和2 x的版本不
  • redis服务停止(NOAUTH Authentication required)问题处理

    redis服务停止报NOAUTH Authentication required错误 处理方法 命令处理 redis cli a 密码 p 6379 shutdown 脚本处理 进入脚本文件 stop命令增加密码 完整配置文件 bin ba
  • 【统计模型】生存分析基本知识介绍

    目录 一 生存分析介绍 1 生存分析用途 2 传统方法在分析随访资料时的困难 1 生存时间和生存结局都是我们关心的因素 2 存在大量失访 3 显然 将失访数据无论是算作死亡还是存活都不合理 3 生存分析的优劣势 1 优势 2 劣势 4 生存
  • 机器学习经典算法,原理及代码实现

    机器学习知识体系 岭回归和LASSO回归 朴素贝叶斯 支持向量机 Logistic回归 K 近邻算法 线性回归 决策树 EM最大期望算法 Apriori算法 自适应增强 Adaboost 算法 PageRank算法
  • java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.sql.Connection异常问题解决

    Connection proxy Connection Proxy newProxyInstance Connection class getClassLoader Connection class getInterfaces new In
  • 数据结构——线性结构(7)——链队列的实现

    链队列的实现 头文件 这部分文件实现我们之前所使用的queue类 它主要的原理为 后进后出 LILO ifndef Queue h define Queue h 类型 Queue
  • 使用vue-video-player,播放rtmp直播流

    可直接在新的页面复制使用 测试可用
  • 对cpu与load的理解及线上问题处理思路解读

    前言 2019双11还有不到2个月就要到来了 大家也都知道服务器在大促期间由于流量的增加势必导致机器的cpu与load变高 因此趁着这个时机正好再好好学习 巩固一下cpu和load的概念 为双11做准备的同时也是增加自己的技能储备 不过cp
  • 华为OD机试真题- 宜居星球改造计划-2023年OD统一考试(B卷)

    题目描述 2XXX年 人类通过对火星的大气进行宜居改造分析 使得火星已在理论上具备人类宜居的条件 由于技术原因 无法一次性将火星大气全部改造 只能通过局部处理形式 假设将火星待改造的区域为row column的网格 每个网格有3个值 宜居区
  • Unity Shader入门精要第七章 基础纹理渐变纹理

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一 渐变纹理是什么 参考 前言 尽管在一开始 我们在渲染中使用纹理是为了定义一个物体的颜色 但后来人们发现 纹理 其实可以用于存储任何表面属性 一种常见的用法就是使用渐变纹理来