写在前面
感谢所有点进来看的朋友。没错,我目前打算写一本关于Unity Shader的书。
出书的目的有下面几个:
- 总结我接触Unity Shader以来的历程,给其他人一个借鉴。我非常明白学Shader的艰难,在群里也见了很多人提出的问题。我觉得学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文。。。这对我有什么好处呢?强迫我对知识进行梳理,对细节问题把握更清楚。
- 第二个原因你懂的。
关于本书的定位问题:
- 面向Unity Shader初学者,但要:
- 有一定的编程经历,不然我说:在脚本里写一个函数XXX,您问我,脚本是啥?我:……。
- 希望您还记得初中高中的基本数学。起码能把数算清楚。我明白很多人早就把矩阵这些稍微复杂一点的数学还给了大学老师,所以我会单独在一个章节里介绍。
- 希望您有一定的耐心。为什么你老是觉得看不懂、学不会Shader,可以反思下自己是不是太急躁了,想要今天看一下明天就会。放弃吧,这是不可能的。
我写这本书的一个目标是,希望帮助初学者把基础打牢,没有基础任何上层建筑都是不可靠的。
- 我不是在写一本特效大全,所以你如果想要看到各种酷炫狂霸拽的特效,抱歉,这本书里几乎没有。这跟上一点有很大关系,仅靠一本书,我可以肯定一个初学者没有办法成为一个“Shader大神”。我希望所有读过这本书的人可以真正明白shader是个什么东西,而不是说:“哦,shader嘛,就是在Unity里右键Create->Shader得到的那个东西嘛”。关于特效大全的问题,如果将来我有十足的经验和资格了,可能会真的写一本,哈哈哈
写书是件很不容易的事情,希望我可以把它做好。
整体结构
我把这本书分为五大篇章:
- 基础篇:这是很重要的一章,主要是为了初学者普及基本的理论知识,以及所需的数学基础。我明白很多人看不懂网上的一些材料,我尽量讲得通俗。
- Shader初级篇:从最简单的shader开始,讲解shader中基础的光照模型、纹理、和透明效果等。同时,还会介绍一些shader的Debug技巧、shader里常见报错信息。
- Shader中级篇:这是进阶篇章,将讲解更加复杂的光照、高级纹理、以及如何用shader实现动画等一系列进阶内容;
- Shader高级篇:则涵盖了一些shader的高级用法,如使用缓冲区、实现屏幕特效、非真实感渲染等,同时,还会介绍一些优化技巧;
- 扩展篇:将会涵盖一些Unity Surface Shader背后的机制,还会针对Unity 5.0+版本中的一些新的特性进行简要分析。最后,希望向大家介绍一点学习shader的经验和资源。
目前目录已经初步定型,把目录记录在这里,但我会不断更新。
如果您对该书的目录和内容有任何意见和建议都可以在下方留言。如果您没有CSDN账号,也可以通过发邮件来告诉我:lelefeng1992 # gmail DOT com。我会根据您的意见对目录和内容做出一定的更改。
目录(更新到第11章)
* 前言
* 这本书讲些什么
* 读这本书之前你需要哪些知识
* 谁适合读这本书
* 谁暂时还不适合读这本书
* 约定
* 读者反馈
* 本书源码
第1部分 基础篇
- 第1章 欢迎来到Shader的世界
- 1.1 程序员的三大浪漫:为什么要学习Shader
- 1.2 这不是程序员一个人的战斗
- 1.3 世界这么大
- 第2章 渲染流水线
- 2.1 综述
- 2.1.1 什么是流水线
- 2.1.2 什么是渲染流水线
- 2.2 CPU和GPU的通信
- 2.2.1 把数据加载到显存中
- 2.2.2 设置渲染状态
- 2.2.3 调用Draw Call
- 2.3 GPU流水线
- 2.3.1 概述
- 2.3.2 顶点着色器
- 2.3.3 裁剪
- 2.3.4 屏幕映射
- 2.3.5 三角形设置
- 2.3.6 三角形遍历
- 2.3.7 片元着色器
- 2.3.8 逐片元操作
- 2.3.9 总结
- 2.4 一些容易困惑的地方
- 2.4.1 什么是OpenGL/DirectX
- 2.4.2 什么是HLSL、GLSL、CG
- 2.4.3 什么是Draw Call
- 2.4.4 什么是固定渲染管线(Fixed-Function Pipeline)
- 2.5 那么,你明白什么是Shader了吗
- 扩展阅读
- 2.1 综述
- 第3章 Unity Shader基础
- 3.1 Unity Shader概述
- 3.1.1 一对好兄弟:材质(Material)和Unity Shader
- 3.1.2 Unity中的材质
- 3.1.3 Unity中的Shader
- 3.2 Unity Shader的基础:ShaderLab
- 3.2.1 什么是ShaderLab
- 3.3 Unity Shader的结构
- 3.3.1 给我们的Shader起个名字:Shader
- 3.3.2 材质和Unity Shader的桥梁:Properties
- 3.3.3 重量级成员:SubShader
- 3.3.4 留一条后路:Fallback
- 3.3.5 ShaderLab还有其他的语义吗
- 3.4 Unity Shader的形式
- 3.4.1 Unity的宠儿:Surface Shader
- 3.4.2 最聪明的孩子:Vertex/Fragment Shader
- 3.4.3 抛弃的角落:Fixed Function Shader
- 3.4.4 那么,要选择哪种Unity Shader形式
- 3.5 本书使用的Unity Shader形式
- 3.6 答疑解惑
- 3.6.1 Unity Shader != 真正的Shader
- 3.6.2 Unity Shader和CG/HLSL之间的关系
- 3.6.3 我可以使用GLSL来写吗
- 扩展阅读
- 3.1 Unity Shader概述
- 第4章 学习Shader所需的数学基础
- 4.1 背景:农场游戏
- 4.2 笛卡尔坐标系
- 4.2.1 二维笛卡尔坐标系
- 4.2.2 三维笛卡尔坐标系
- 4.2.3 左手坐标系和右手坐标系
- 4.2.4 Unity使用的坐标系
- 4.2.5 练习题
- 4.3 点和矢量
- 4.3.1 点和矢量的区别
- 4.3.2 矢量运算
- 4.3.2.1 矢量和标量乘法/除法
- 4.3.2.2 矢量的加法和减法
- 4.3.2.3 矢量的模
- 4.3.2.4 单位矢量
- 4.3.2.5 矢量的点积
- 4.3.2.6 矢量的叉积
- 4.3.3 练习题
- 4.4 矩阵
- 4.4.1 矩阵的定义
- 4.4.2 和矢量联系起来
- 4.4.3 矩阵运算
- 4.4.3.1 矩阵和标量的乘法
- 4.4.3.2 矩阵和矩阵的乘法
- 4.4.4 特殊的矩阵
- 4.4.4.1 方块矩阵
- 4.4.4.2 单位矩阵
- 4.4.4.3 转置矩阵
- 4.4.4.4 逆矩阵
- 4.4.4.5 正交矩阵
- 4.4.5 行矩阵还是列矩阵
- 4.4.6 练习题
- 4.5 矩阵的几何意义:变换
- 4.5.1 齐次坐标
- 4.5.2 分解基础变换矩阵
- 4.5.3 平移矩阵
- 4.5.4 缩放矩阵
- 4.5.5 旋转矩阵
- 4.5.6 组合变换
- 4.5.7 练习题
- 4.6 坐标空间
- 4.6.1 为什么要使用这么多不同的坐标空间
- 4.6.2 坐标空间的变换
- 4.6.3 顶点的坐标空间变换过程
- 4.6.3.1 案例
- 4.6.4 模型空间
- 4.6.4.1 案例
- 4.6.5 世界空间
- 4.6.5.1 案例
- 4.6.6 观察空间
- 4.6.6.1 案例
- 4.6.7 裁剪空间
- 4.6.7.1 透视投影
- 4.6.7.2 正交投影
- 4.6.7.3 案例
- 4.6.8 屏幕空间
- 4.6.8.1 案例
- 4.6.9 总结
- 4.7 法线变换
- 4.8 Unity Shader中的内置变量(数学篇)
- 4.9 答疑解惑
- 4.9.1 使用3 x 3还是4 x 4的变换矩阵
- 4.9.2 Cg中的矢量和矩阵类型
- 4.9.3 Unity中的屏幕坐标:ComputeScreenPos/VPOS/WPOS
- 练习题答案
- 扩展阅读
第2部分初级篇
- 第5章 开始Unity Shader学习之旅
- 5.1 本书使用的软件和环境
- 5.2 一个最简单的Vertex/Fragment Shader
- 5.2.1 Vertex/Fragment Shader的基本结构
- 5.2.2 模型数据从哪来
- 5.2.3 顶点着色器和片元着色器之间如何通信
- 5.2.4 如何使用属性
- 5.3 强大的援手:Unity提供的内置文件和变量
- 5.3.1 内置的包含文件
- 5.3.2 内置的变量
- 5.4 Unity提供的Cg/HLSL语义
- 5.4.1 什么是语义
- 5.4.2 Unity支持的语义
- 5.4.3 如何定义复杂的变量类型
- 5.5 程序员的烦恼:Deeeeebug
- 5.5.1 使用假彩色图像
- 5.5.2 利用神器:Visual Studio
- 5.6 小心:渲染平台的差异
- 5.6.1 渲染纹理的坐标差异
- 5.6.2 Shader的语法差异
- 5.6.3 Shader的语义差异
- 5.6.4 其他平台差异
- 5.7 Shader整洁之道
- 5.7.1 float、half还是fixed
- 5.7.2 规范语法
- 5.7.3 避免不必要的计算
- 5.7.4 慎用分支和循环语句
- 5.7.5 不要除以0
- 扩展阅读
- 第6章 Unity中的基础光照
- 6.1 我们是如何看到这个世界的
- 6.1.1 光源
- 6.1.2 吸收和散射
- 6.1.3 着色
- 6.1.4 BRDF光照模型
- 6.2 标准光照模型
- 6.2.1 环境光
- 6.2.2 自发光
- 6.2.3 漫反射
- 6.2.4 高光反射
- 6.2.5 逐像素还是逐顶点
- 6.2.6 总结
- 6.3 环境光和自发光
- 6.4 漫反射光照模型
- 6.4.1 实践:逐顶点光照
- 6.4.2 实践:逐像素光照
- 6.4.3 改善技巧:半兰伯特模型
- 6.5 高光反射光照模型
- 6.5.1 实践:逐顶点光照
- 6.5.2 实践:逐像素光照
- 6.5.3 Blinn-Phong模型
- 6.6 召唤神龙:使用Unity内置的函数
- 6.6.1 使用内置函数改写Unity Shader
- 6.1 我们是如何看到这个世界的
- 第7章 基础纹理
- 7.1 单张纹理
- 7.1.1 实践
- 7.1.2 解释
- 7.1.3 纹理的属性
- 7.2 凹凸映射
- 7.2.1 高度纹理
- 7.2.2 法线纹理
- 7.2.3 实践
- 7.2.4 解释
- 7.2.5 Unity中的法线纹理类型
- 7.3 渐变纹理
- 7.3.1 实践
- 7.3.2 解释
- 7.4 遮罩纹理
- 7.4.1 实践
- 7.4.2 解释
- 7.4.3 其他遮罩纹理
- 7.1 单张纹理
- 第8章 透明效果
- 8.1 为什么渲染顺序很重要
- 8.2 Unity Shader的渲染顺序
- 8.3 透明度测试
- 8.3.1 实践
- 8.3.2 解释
- 8.4 透明度混合
- 8.4.1 实践
- 8.4.2 解释
- 8.5 开启深度写入的半透明效果
- 8.5.1 实践
- 8.5.2 解释
- 8.6 ShaderLab的混合命令
- 8.6.1 混合等式和参数
- 8.6.2 混合操作
- 8.6.3 常见的混合类型
第3部分 中级篇
- 第9章 更复杂的光照
- 9.1 Unity的渲染路径
- 9.1.1 前向渲染路径
- 9.1.1.1 前向渲染路径的原理
- 9.1.1.2 Unity中的前向渲染
- 9.1.1.3 内置的光照变量和函数
- 9.1.2 顶点照明渲染路径
- 9.1.2.1 Unity中的顶点照明渲染
- 9.1.2.1 可访问的内置变量和函数
- 9.1.3 延迟渲染路径
- 9.1.3.1 延迟渲染的原理
- 9.1.3.2 Unity中的延迟渲染
- 9.1.2.3 可访问的内置变量和函数
- 9.1.4 选择哪种渲染路径
- 9.1.1 前向渲染路径
- 9.2 Unity的光源类型
- 9.2.1 光源类型有什么影响
- 9.2.1.1 平行光
- 9.2.1.2 点光源
- 9.2.1.3 聚光灯
- 9.2.2 在前向渲染中处理不同的光源类型
- 9.2.2.1 实践
- 9.2.2.2 解释
- 9.2.2.3 实验:Base Pass和Additional Pass的调用
- 9.2.1 光源类型有什么影响
- 9.3 Unity的光照衰减
- 9.3.1 用于光照衰减的纹理
- 9.3.2 使用数学公式计算衰减
- 9.4 Unity的阴影
- 9.4.1 阴影是如何实现的
- 9.4.2 不透明物体的阴影
- 9.4.2.1 让物体投射阴影
- 9.4.2.2 让物体接收阴影
- 9.4.3 使用帧调试器查看阴影绘制过程
- 9.4.4 统一管理光照衰减和阴影
- 9.4.5 使用透明度测试的物体的阴影
- 9.1 Unity的渲染路径
- 第10章 高级纹理
- 10.1 立方体纹理
- 10.1.1 天空盒子
- 10.1.2 创建用于环境映射的立方体纹理
- 10.1.3 反射
- 10.1.4 折射
- 10.2 渲染纹理
- 10.2.1 镜子效果
- 10.3 程序纹理
- 10.3.1 在Unity中实现简单的程序纹理
- 10.3.2 Unity的程序材质
- 10.1 立方体纹理
- 第11章 让画面动起来
- 11.1 Unity Shader中的内置变量(时间篇)
- 11.2 纹理动画
- 11.2.1 序列帧动画
- 11.2.2 滚动的背景
- 11.3 顶点动画
- 11.3.1 流动的河流
- 11.3.2 广告牌
- 11.3.3 注意事项
第4部分 Shader高级篇
- 第11章 基于图像处理的渲染方法
- 11.1 伽马校正
- 11.2 抗锯齿
- 11.3 亮度、饱和度和对比度
- 11.4 实现类似Photoshop的混合模式
- 11.5 实现渐变叠加效果
- 11.6 实现晕影效果
- 第12章 使用深度和法线缓冲区
- 12.1 如何获取缓冲区
- 12.2 实践:景深效果
- 12.3 实践:边缘检测
- 第13章 非真实感渲染
- 13.1 卡通渲染
- 13.2 轮廓线渲染
- 13.3 手绘风格的渲染
- 第14章 在Shader中使用噪声
- 14.1 什么是噪声(Noise)
- 14.2 Perlin噪声
- 14.3 Worley噪声
- 14.4 实践
- 第15章 移动平台的优化
- 15.1 移动平台与台式机的区别
- 15.2 识别出影响性能的因素
- 15.2.1 CPU
- 15.2.2 Vertex的处理
- 15.2.3 Fragment的处理
- 15.2.4 带宽
- 15.2.5 Unity的性能分析工具:Profiler
- 15.3 优化几何体
- 15.4 使用LOD技术
- 15.5 使用遮挡剔除技术
- 15.6 控制绘制顺序
- 15.7 时刻警惕透明物体
- 15.8 减少实时光照
- 15.8.1 使用Lightmaps
- 15.8.2 使用God Rays
- 15.9 减少Draw Calls
- 15.9.1 静态批处理
- 15.9.2 动态批处理
- 15.9.3 如何选择
- 15.10 减少纹理大小
- 15.11 利用缩放
第5部分 扩展篇
- 第16章 Surface Shader探秘
- 16.1 基本流水线
- 16.2 Unity背后做了什么
- 第17章 基于物理的渲染——Physically Based Shading
- 17.1 理论
- 17.2 Unity的Standard Shader
- 第18章 Unity 5.0更新了什么
- 18.1 场景“更亮了”
- 18.2 Surface Shader更容易“报错了”
- 18.3 当家做主:自己控制非统一缩放的网格
- 18.4 Fixed function逐渐退出舞台
- 第19章 还有更多内容吗
- 19.1 如果你想深入了解shader的话
- 19.2 还是那句话:世界那么大
- 参考文献
- 索引
2015.06.28更新
这几天在写数学的部分,早就料到数学是最难讲的一部分,尤其是矩阵。我和很多人一样,对矩阵这个家伙简直是”深恶痛绝“,看到它就想躲过去。无奈,shader里面要时常跟它打交道,那么,就勇敢地面对它吧!
我很明白,为什么我们会这么”讨厌“矩阵。如果说矢量这种我们还可以通过可视化的方法来直观地理解,那么,矩阵,这个放在一个小方框里的东西,就很难用画的方式把它画出来。而我们人的大脑又是很懒惰的(恩,我只能为我的大脑代言),没图你说个XXX!我才懒得记!
实际上,我一直对数学怀抱一种敬畏的心态。世界上有很多的数学家同时也是哲学家、心理学家,感觉数学对理解这个世界都有非常重要的意义,而且那些数学家的生平都很有意思,让人敬佩。能够将其一生都贡献给数学的人都很伟大的,那些创造矩阵、空间、矢量这些的人是多么伟大,怎么就会想到用这样一种方式来描述这种现象呢?这真的是件很神奇的事情。而且,你会发现,怎么这样算就可以表示出这种意思呢,明明看起来没有任何关系啊!这种巧合真的是让人感叹数学的伟大。
好了,不再歪歪……回到真实的世界……在写的过程中,我会尽量用通俗、幽默、有图示的方式来讲这一章,效果怎么样,我也很忐忑,会不会反映说看不懂?现在一切都不得而知……
一个有趣的事情是,在讲左右手坐标系和左右手法则的时候,我拿自己的手做了模型:
哈,这个黄色的手的确是我的手,然后用Photoshop处理了一下。看起来还挺像那么回事的?谁敢说我手胖我跟谁急!
这几天一直在画图、看书、写文字、写公式(天哪,虽然用Markdown写公式已经很方便了,但一天要写那么多公式也真的是……)、算题,希望最后的结果是好的。加油吧!
2015.07.10更新
写了两个多星期,把数学一章的草稿基本完成了。今天更新了第2、3、4章的目录,有兴趣的可以看一下,欢迎提出各种意见和建议。
数学篇是我最想好好写的一篇(当然啦,其他章我也会好好写。。。)。数学之所以难学,一部分是因为它的抽象性,没办法,如果我们想要把一些规律从生活中提取出来,就必然要涉及到各种数学符号,这就要用到抽象。我用了很多图和案例来尽量让这个过程更加形象易懂,也使用了一些类似对话的方式,来解释一些常见的疑惑。
目前,本书的第一篇——基础篇基本成型。基础篇里每一章都有个小节叫做答疑解惑,意在总结一些常见的疑惑点,如果读者除了我上面写到的几点外还有其他的困惑,可以给我留言。我会视情况添加到这一章节。
除此之外,在数学一章里我添加了练习题的部分。其实我是有犹豫的,觉得可能大家都会跳过去,那不是白写了。。。之所以要设置这个练习题的部分,一方面的确是希望读者可以通过这些练习真的拿笔算一下,说真的,数学你不多算真的永远学不会。另一方面,是想把一些容易混淆的点通过练习题的方式提出来,让读者自己算一下加深理解。因为如果要把这些混淆点都写进书里,思路上会比较乱。希望能起到比较好的效果吧。。。
下面就会真正开始Unity Shader的部分了。加油!
2015.07.29更新
放假了大部分时间都拿来看资料、学习、写书了。半个多月写出了基本篇的草稿,不知道是快还是慢?我自信自己写的很详细了,比如第5章介绍了语义,第6章详细介绍了基本光照模型,第7章写到凹凸映射的时候也花了很大篇幅介绍实现的原理和细节,包括高度图,第8章的透明效果先介绍了渲染队列,我自己认为这个很重要的,应该在学习怎么实现透明之前就让读者知道渲染队列对透明来说是多么的重要。我觉得现在的安排对初学者足够友好了,当然写后面内容的时候可能还会对前面的内容进行改动,例如现在想在第4章数学里加一个在Unity脚本里的矩阵运算,但这本书是讲shader的,不知道加进去合不合适,但它的确是个容易出错的地方。
每次讲到新的内容时,我都尽量用图示来解释,每一幅图都是在OmniGraffle里认真做的,希望以后看到的人能get到我的意思。写书写太多感觉写博客都语无伦次了。。。
最近QQ群、私信和留言经常有人问题一些问题,我在这里统一回答一下。回答几个问题:
- 这书什么时候出版?
大家也看到了我的更新速度,目前写的了第8章(第一章介绍还没写),初步定的是19章,也就是说写了三分之一了,我现在大概花了一个多月,但是写书的确花费了很多时间,写完基本篇之后可能会放慢一下速度。总体来讲,我估测下大概还要三四个月的时间才能写完,因此出版的话最快年底,不然就是明年年初了。有一些人说太晚了,相信我,我比任何人都想让它赶紧出版,但是我不会影分身……好羡慕鸣人。
- 能不能增加些更高难度的技术?
一些童鞋大概看了前几章目录后觉得内容比较简单。怎么说呢,这本书的定位是面向初学者,因此肯定会是由易到难的,但我自信的是,即便是简单的内容我也写的很详细,很多很小的点也都写到了,很多地方都是其他资料里一带而过,而又很迷惑的点。如果是没有好好学过shader的,就算现在已经可以熟练写一些了我觉得这本书也是有用的。
更重要的是,我不想把它写成一本百科全书,一来我自己的确经验不够,写不来大全,二来我觉得一本大全的书肯定写不精、写不细,到头来又说看不懂怎么办?三来我觉得写shader是一个师傅领进门修行靠个人的活,一旦你了解了它的工作流程和基本思路,剩下的就是经验的积累,你看得写、写得多自然就厉害了,这不是一本基础书就可以让你做到的。
当然,我的确会写一些复杂的技术,这是高级篇和扩展篇的工作。如果你觉得有一些常用的复杂一些的技术想要在这本书里看到,可以告诉我。
- 是彩色书还是黑白书?
我自己当然希望是彩色书,一本讲画面效果的书竟然是黑白的那太遗憾了。不过编辑告诉我,彩色印刷会提高很多成本,那销量就会下降。我能够理解,但现在还没有一个定论,等写完之后会尽量争取。不过我也很好奇,大家觉得这样一本几百页的全彩书,你觉得多少价钱比较合适?
2015.09.04更新
断断续续把中级篇的草稿完成了。越往后面写感觉内容的安排越费劲,一些内容不知道把它们归入到哪一章更加合适,放的早了一些内容没讲担心读者看不明白,放的晚了又觉得内容不足单独成章。高级篇想必也会这样。目录还在不断调整中……
写第9章光照简直是除数学篇外最痛苦的一章,想要讲明白非常难啊,不管怎样,目前的内容我尽力了,希望可以有好的效果。因为内容多而且杂,所以这一章不知不觉就写了四万字,也是目前字数最多的章节了。即便这样,仍然对一些内容“念念不忘”,例如菲尼尔光照、边缘光照等,不知道以后会不会加入进去。
话说,写书的时候发现一个不错的免费纹理网站——http://opengameart.org/,写书的时候有一些纹理是从这里找到的,在这里也推荐给大家。当然,也有自己画的一些纹理。之前做游戏的时候做了一个2D水面,这次把它的实现也添加到了书里面。
呼,还有两大篇整体草稿就完成了。有些内容想偷点懒,使用点博客里写过的。。。9月估计要赶论文,进度会更慢。预计完成大概要11月或者12月了,希望大家可以耐心等待。我会加油的。
版权声明:本文为博主原创文章,未经博主允许不得转载。