如何正确地搞颜色?
如何正确地搞颜色?
如何正确地“搞颜色”?看到这里,你的脑海中是不是闪过了一些奇奇怪怪的东西?不,这是篇非常正经的科普!所以现在,让我来给大家看一张色图。很正经吧~这张图上的小可爱叫做色轮,它将是我们接下来的科普中的主角,现在请先记住它的样子吧!
本文中我将围绕色彩的基本知识、几种常见的配色方案逐一展开介绍。
颜色理论与配色模式
人类是如何看见颜色的?
在自然界中自然光从光源发出,到达物体的表面。大部分被照射到的物体会吸收掉其中的一部分光,将剩下的光线反射到我们的眼睛里,成为了我们所看到的这个物体的颜色。如果一个物体不吸收任何落在其表面的光线,也就是说呢它把所有照射在它身上的光线都原封不动的反射回去了,那么它在人眼看来就是白色的。而另一方面,如果一个物体吸收了所有照射到它表面的光,那么这个物体看起来就会是黑色的。
这种成色原理被称为减色法,在多媒体领域中对应于CMYK颜色模型。在日常生活中,这种颜色模型广泛应用于打印机等需要在不会自然发光的物体上显示颜色的场合。这是因为物体不会自发光,所 ...
全局渐变效果实现
我想试着实现一下下图中纪念碑谷中的全局渐变的效果。关于如何实现这种渐变效果之前和别人讨论过,一开始我认为是通过从下往上打光来实现的,后来同学说是利用了shader和雾。利用后者实现的效果更为缓和,而利用光照可能会造成底部过亮的问题,不好控制。
为什么我管这种效果叫“全局渐变”呢?因为当我移动模型的时候,渐变的范围并不是固定在模型身上的,而是在世界空间的“某个位置”(如下图所示)。实际上,我们可以自行规定这个渐变地平线的位置,只需要在shader里加个控制变量就可以了。
实现
变量
首先,我们需要这么几个变量:
顶部的颜色
底部的颜色
渐变混合的程度
光照的强度
渐变地平线
渐变纹理
1234567891011121314Properties{ // 光照的强度 _Contrast("Contrast",Range(0,1))=0.1 // 渐变纹理 _RampTex("渐变纹理", 2D) = "white"{} // 上下渐变色 _UpColo ...
程序棋盘格效果实现
为什么会写这篇文章呢…因为我已经在大大小小的场合中遇到三次相关的题目了,前几次答得挺不尽人意的。第一次是在剑心互娱的校招笔试上,要求画一个黑灰白三条杠(下左),第二次是字节的二面要求画一个棋盘格的效果(下右),还有一次忘了(
对于这两种效果,我们的思路其实是一样的(棋盘格只需要多一步加法)。
开始绘制
怎么用程序画东西呢?我们在做材质的时候似乎一直是基于贴图进行处理的。实际上,我们是可以直接对纹理映射(texcoord节点)下手的,如果将其连接到根节点的base color,我们会得到如下画面:
为什么是这个颜色?首先需要知道的是:texcoord只有uv两个量,而颜色具有三个分量。当我们默认第三个分量为0时,就会得到上述的颜色信息。而如果我们把第三个分量设置为1,就会得到:
数学处理
黑、灰、白
为了实现三条边、四条边甚至多边的情况,我们需要对texcoord进行缩放,这一步很简单,只需要让texcoord乘上一个用来控制的常量:
然后,对texcoord的值进行取整(floor节点)。这一步的目的是将贴图“阶梯化”,方便后续实现黑白分条的效果。下图好 ...
菲涅尔反射实现边缘光效果
在之前的项目中,我从网上抓了一个用菲涅尔反射写的边缘光shader。经过自己的魔改之后,加上了法线等用在后续的项目中。现在我们回过头来探寻一下菲涅尔效应是如何用来实现边缘光的。
参数
我们有三个至关重要的参数:边缘光的颜色、边缘光强度和强度系数。
边缘光颜色
这个没什么好说的,就是控制边缘光的颜色。但因为是光,所以当颜色调整为黑色时不论强度多少都是看不到效果的。
边缘光强度
这个值可以控制菲涅尔影响范围的大小,这个值越大,效果上越边缘化(上:强度为1.5;下:强度为4)。
边缘光强度系数
这个值控制菲涅尔反射的反射强度,值越大,反射越亮,反之越暗(上:强度为1.5;下:强度为12)。代码里的注释有错,因为原先的代码的强度系数在内部被原作者定死了。
片元着色器
边缘检测
这一步是实现边缘光效果的核心。
首先我们来理清一下思路,如何进行边缘检测?其实很简单的一种方式就是通过视线方向和片元的法线方向点乘进行判断。当我们差不多正视一个片元的时候,夹角通常都是小于45°的。而片元越靠近边缘,与视线的夹角越大,最终达到视线相切的90°,再大就看不到了。
所以我们对视线和片元法线归一 ...
解决Z-Fighting
解决Z-Fighting
Z-Fighting是在实际项目中困扰到场景布局的一大因素。从理论上来说,在相同深度值的地方有多个片元,这导致颜色缓冲区不知道该呈现哪个颜色比较合适,而当视角运动时就会出现糟糕的闪烁:
通过调整渲染队列并不能避免这种问题,就比如上图的半透明物体的渲染队列是在不透明物体之后的,但他们重叠时依然会发生z-fighting现象。
解决方法
Shaderlab语法中的Offset命令
12345678910Properties{ _OffsetFactor("深度斜率",Float) = 0 _OffsetUnit("深度偏移",Float) = 0 }SubShader{ Pass{ Tags{ "LightMode" = "ForwardBase" } Offset [_OffsetFactor],[_OffsetUnit] } ...
Oculus Quest电脑端有线连接教程
由于无线连接需要代理路由或代理wifi,所以走有线
本篇教程使用github作为图床,使用代理来加载图片
本教程的前提是你的设备已经激活并且连上手机。激活需要代理热点,比如刷了老毛子固件的路由器或者坐船去台湾,也可以通过oculus helper、SSTap等来实现
基础步骤
安装Oculus电脑客户端
从官网上下载Oculus Hub,点击oculus setup就可以直接安装,如下(如果你是开发者,可以安装Oculus Developer Hub):
安装建议使用科学上网,一个好的代理可以在半小时内下完5G多的资源,否则要五个小时。安装好之后桌面上会出现客户端图标:
这时候使用之前注册的开发者账户登录会出错,原因是国内墙的dns污染导致无法连接oculus的服务器。解决方式是打开电脑文件目录:
1C:\WINDOWS\System32\drivers\etc
里面有一个hosts文件,以记事本打开它,在末尾加上:
123157.240.217.51 graph.oculus.com157.240.195.51 graph.oculus.com157.240.199.54 gra ...
§2-2:基础纹理
基础概念
纹理映射(Texture Mapping)
纹理映射指的是将一张贴图映射在模型表面,逐纹素(texel)的控制模型的颜色。
纹理映射坐标(Texture-mapping Coordinates)
通过模型的纹理展开(展uv),我们可以获得一组纹理映射坐标,储存在每个顶点上。通常纹理映射坐标由(u, v)来表示,所以我们会简称纹理映射坐标为UV坐标。
不管贴图实际上有多大,UV坐标的范围通常被归于[0, 1]之间,并以纹理贴图的左下角为原点
纹理空间(Texture Image Sace)
纹理空间在纹理映射坐标的基础上乘以了纹理分辨率(如分辨率为256*256,新的uv坐标为(256u,256v))而得到的新坐标,用于寻找纹理贴图上对应的像素点的信息
纹理采样(Texture Sampleing)
我们获取纹理映射后对应纹理贴图像素点的过程
纹理管线的完整流程,可参考:https://zhuanlan.zhihu.com/p/393323667
Unity中的纹理属性
在向Unity导入纹理之后,检查器中可以对纹理进行一系列设置:
具体的设置见下:
纹理类型(Textu ...
§2-1:基础光照模型
光照模型分为两种:
一种是基于物理的光照模型(PBR),非常真实的反映了现实世界的光照,但是需要大量复杂的计算
另一种是经验光照模型(如兰伯特),用较为简单的方式模拟了物理光照,也能得到不错的效果
本章节主要介绍经验光照模型
基本概念
光源(Light Source)
光从光源中发射出来,照到物体表面。对于不同类型的光,需要设置不同种类的光源(例如影响全局的场景光、点光源以及投射灯等等)。
在Unity中,当我们选择创建光源时,有以下四种选项(反射球暂时先不考虑):
辐照度(Irradiance)
辐照度是衡量一个光源发出的光的多少使用的单位,用来量化光。
对于平行光,辐照度可以通过计算垂直于光源方向l的单位面积上单位时间内穿过的能量得到。
而存在一定夹角的时候,可以通过求光源方向l和法线之间的夹角的余弦值求得(就是投影到垂直平面的方向的分量)。
当光线间隔相同时,光与平面的夹角越大,单位面积内光的数量越少。
出射度(Exitance)
衡量出射光线的数量和方向的量,利用入射光线的数量和角度计算。和辐照度存在线性关系。
吸收和散射 ...
§1-4:光栅化/Rasterize
光栅(Raster)这个词最初来源于德语的“屏幕”一词,相当于英语中的Screen。那么光栅化的含义就比较明确了,指的是把图形从标准立方体(NDC)绘制到屏幕上的过程。
屏幕坐标系
我的笔记本电脑的主显示屏分辨率是1920*1080,代表长1920个像素,宽1080个像素,一共有1920*1080个像素。假设以屏幕左下角为原点建立坐标系,可以给每个像素一个坐标。但由于像素具有实际大小,每个像素的中心点坐标为(x+0.5,y+0.5)(x + 0.5, y + 0.5)(x+0.5,y+0.5)
从NDC到屏幕坐标系
屏幕映射(Screen Mapping)
NDC是一个长宽高范围均为[-1, 1]的标准立方体。在经过MVP矩阵变换与齐次除法之后,现在要做的就是把具有三维属性的NDC映射到只有二维属性的屏幕空间,怎么实现呢?
如果忽略z(深度信息),其实可以直接把NDC的x和y属性“拉伸”成屏幕空间的形状,使用视口变换矩阵:
M=(width200width20height20height200100001)M =
\begin{pmatrix}
\frac{width}{ ...
§1-3:坐标空间与MVP矩阵变换
从观察者的观察空间投影到屏幕空间
什么是MVP矩阵?MVP矩阵的三个字母指的是模型矩阵(Model)、观察矩阵(View)和投影矩阵(Projection)。回想一个模型从导出到最终呈现在屏幕上的过程,我们发现模型的顶点的坐标经历了这么些事:
在建模软件中,模型顶点的坐标是以模型中心为原点计算的
在把模型拖入场景之后,模型顶点的坐标是以世界中心为原点计算的
从摄像机出发观察模型
将模型投影到摄像机上,进行渲染,最终呈现在玩家眼前
实际上,这个变换就是使用了MVP矩阵。从模型空间的顶点,我们最终得到了投影在相机上的结果。再想想写shader的时候,顶点着色器往往包含以下语句:
12v2f o; // 传输到片元着色器o.pos = UnityObjectToClipPos(v.vertex); // 将顶点坐标从模型空间(Object)转换到裁剪空间(Clip)
我们知道,顶点着色器最基本的功能就是将顶点坐标从模型空间转换到裁剪空间。这里的UnityObjectToClipPos函数的作用即将顶点坐标乘上 ...