Shader 中的颜色计算
下面介绍 Shader 中 gl_FragColor 的计算与转换:
一、颜色计算
1. 加
这里要讲讲三原色和三基色:三原色一般指的是红、绿、蓝三种,简称 RGB,这是加色系。就是光源只含有特定的波段,本身就是色光,将不同颜色的光加在一起形成新的颜色。典型的例子是显示屏,关系如下:
显然,shader 中的颜色属于加色系。当我们把颜色相加时,会形成新的颜色,并且颜色会往白色靠拢。颜色的混合规律符合三原色规律。
顏色相加是指光的疊加,物理上是光的強度相加。例如多個光源照射到一個表面後反射至攝像機,就可以把各個光照的反射結果相加。而題目中的例子是Phong或Blinn材質的反射模型,其意義可以算是一種擬合,把材質的反射分解成漫反射和鏡面反射,然後把兩種反射光的結果相加。
2. 乘
讲完三原色,再讲讲三基色:一般指的是颜料三原色,在纯白光照射下颜色为绛红、黄、青,简称 CMYK,属于减色系。它们本身不发光,靠反光被看见。由于材料吸收特定波段的光,所以只有不被吸收的部分反射了回来。加上的颜色越多吸收的光也越多。
当我们使用乘法来做颜色混合时,其规律符合三基色的混合规律,这个时候又是减色系。
两个颜色相乘,会算出两个颜色中 RGB 值的乘积并合成一个新的颜色。而且颜色总会越来越暗,回不到原来的白色。通常将颜色和一个值相乘,来弱化这个颜色。实际应用中通常用于混合反射率、光照衰减等。
顏色相乘,其實並不是數學中常見的矢量積,而應該理解為顏色的非等比縮放。例如,光通過有色玻璃時,玻璃吸收某百分比的紅、藍、綠,就可以把光的紅藍綠強度分別乘以對應的百分比。漫反射也可以理解成材質吸收了某百分比的入射光後向各方向反射。漫反射贴图存的其实就是
对颜色为(1,1,1,1)的光的反射率。
3. 减
单纯的颜色相减似乎没有意义,不过通过1.0-color
可以实现颜色的反相。
4. 真正的颜色混合
在图片或视频滤镜中,一般不会直接使用加减乘除来做颜色混合。而是使用 mix() 函数,它的公式是:x*(1−a)+y*a
,其实也是颜色相加,但是算上了一定的比重。这样不会因为一个白色的颜色和其他颜色相加后只有白色,现实世界中也不是这样的。
mix()
可以做单通道或多通道的融合:
①. 简单的颜色渐变
回到上面的案例,通过加法来表示重叠区域:
通过 mix()
来混合两个颜色的过渡:
为什么加法和mix()
得到的过渡颜色不一样?各位可以思考一下。
②. 复杂的颜色渐变
为 rgb 三个通道赋以不同的函数变化曲线。plot 是封装好的画线函数,以xy
二维笛卡尔坐标系做曲线的绘制,pct 表示x
轴的变化速率,当x
是线性变化时,曲线为直线。当x
是非线性变化时,会有不一样的曲线,从而导致渐变色的多样变化:
二、颜色转换
1. 基于笛卡尔坐标系
RGB 是对机器很友好的色彩模式,但并不够人性化,因为我们对色彩的认识往往是”什么颜色?鲜艳不鲜艳?亮还是暗?”。HSL 模式和 HSV(HSB) 都是基于 RGB 的,是作为一个更方便友好的方法创建出来的 —— refer
- HSL 为 色相,饱和度,亮度
- HSV 为色相,饱和度,明度
- HSB 为 色相,饱和度,明度
下图表达了两种颜色模型对人类来说的易理解程度:
HSL 和 HSB/HSV 又有一些区别:
这里提供转换公式:
// RGB 转 HSB
vec3 rgb2hsb( in vec3 c ){
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz),
vec4(c.gb, K.xy),
step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r),
vec4(c.r, p.yzx),
step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
d / (q.x + e),
q.x);
}
// HSB 转 RGB
// Function from Iñigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix(vec3(1.0), rgb, c.y);
}
复制代码
那我们可以怎么应用 HSB 颜色呢?
当我们让色相 Hue 从0~1
递增时,你会发现所有颜色都一一取到了(这里的饱和度和亮度都设置为 1):
假设让亮度也一样从0~1
,看看效果会如何:
你会发现水平方向的亮度变化不好看,如果是垂直方向的呢?
再改一下垂直方向的饱和度,你会发现有了 HSB,一切颜色变化都更好理解了:
2. 极坐标系
HSB 原本是在极坐标下产生的(以半径和角度定义)而并非在笛卡尔坐标系(基于xy定义)下。将 HSB 映射到极坐标我们需要取得角度和到像素屏中点的距离。由此我们运用 length() 函数和 atan(y,x) 函数。
当用到矢量和三角学函数时,vec2, vec3 和 vec4 被当做向量对待,即使有时候他们代表颜色。我们开始把颜色和向量同等的对待,事实上你会慢慢发现这种理念的灵活性有着相当强大的用途。—— refer
Shader 中的颜色计算的更多相关文章
- 【Unity Shaders】Shader中的光照
写在前面 自己写过Vertex & Fragment Shader的童鞋,大概都会对Unity的光照痛恨不已.当然,我相信这是因为我们写得少...不过这也是由于官方文档对这方面介绍很少的缘故, ...
- 计算机中的颜色XIV——快速变换颜色的V分量
基本知识回顾: 计算机中的颜色Color,用RGB模式存储(用R.G.B三个分量表示颜色,每个分量的范围是0—255). 而计算机中的颜色除了用RGB模式表示以外,常见的还有HSV模式(或者是HSB. ...
- 【Unity Shaders】Diffuse Shading——在Surface Shader中使用properties
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- --关于null在oracle数据库中是否参与计算,进行验证,
--关于null在oracle数据库中是否参与计算,进行验证,with td as (select null id,1 name from dual ),td1 as ( select null id ...
- 数据库SQL语句中根据当前日期计算其他日期小结
问题描述:我们在写存储过程和函数的时候经常会碰到利用当前日期计算出上周开始日期.结束日期,或者计算上个月的开始日期结束日期等问题.最近写了几个存储过程和函数,其中都涉及到了日期计算问题,在这里简单做一 ...
- 第16/24周 SQL Server 2014中的基数计算
大家好,欢迎回到性能调优培训.上个星期我们讨论在SQL Server里基数计算过程里的一些问题.今天我们继续详细谈下,SQL Server 2014里引入的新基数计算. 新基数计算 SQL Serve ...
- 【组合数学+动态规划】在如下8*6的矩阵中,请计算从A移动到B一共有____种走法。要求每次只能向上或向右移动一格,并且不能经过P。
在如下8*6的矩阵中,请计算从A移动到B一共有__种走法.要求每次只能向上或向右移动一格,并且不能经过P. A:456 B:492 C:568 D:626 E:680 F:702 解析: 8*6的矩阵 ...
- openstack中彻底删除计算节点的操作记录
在使用openstack的过程中,我们经常会添加好几台计算节点来部署虚拟机,在后续使用中由于某些原因,一些计算节点出现了问题,需要将这些出了问题的计算节点从openstack的控制节点中踢出去!但是很 ...
- GLSL 中的光照计算
理论知识转载地址:http://blog.csdn.net/ym19860303/article/details/25545933 1.Lambert模型(漫反射) 环境光: Iambdiff = K ...
随机推荐
- ubuntu 服务器添加新磁盘
原文 Linux系统扩容根目录磁盘空间的操作方法 这篇文章主要介绍了Linux系统扩容根目录磁盘空间的操作方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下 一.使用背景 Linux根目录磁 ...
- 使用 EasyExcel 读取Excel(两种方式)
引入 jar 包 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel&l ...
- ValueError: Expecting property name: line 1 column 2 (char 1)
代码: import json str2 = '{"domain":"456"}' str1 = "{'domain':'123'}" pr ...
- Git 的核心概念
本文不是Git使用教学篇,而是偏向理论方面,旨在更加深刻的理解Git,这样才能更好的使用它,让工具成为我们得力的助手. 版本控制系统 Git 是目前世界上最优秀的分布式版本控制系统.版本控制系统是能够 ...
- 007_linuxC++之_构造函数的初级应用
(一)构造函数:用来在创建对象时初始化对象, 即为对象成员变量赋初始值 (二)构造函数的命名必须和类名完全相同 (三)更对具体的查看:构造函数 (四)直接分析程序 运行结果 解析上面程序: 1. 当程 ...
- CF788A Functions again dp
求一个最长子段和就完了,可以出T1? code: #include <bits/stdc++.h> #define N 100006 #define ll long long #defin ...
- Windows Storage 驱动开发 葵花宝典 - 翻译
Roadmap for Developing Windows Storage Drivers Last Updated: 4/20/2017 To create a storage driver, ...
- Selenium调用使用360浏览器,QQ浏览器,遨游浏览器,猎豹浏览器,Chromium
国产的360安全浏览器,360急速浏览器,QQ浏览器,遨游浏览器甚至新版还未上市的Edge浏览器都是基于Chrome浏览器的开源版本Chronium开发来的.所以360浏览器可以理解为一个定制的Chr ...
- MySQL数据分析(16)— 数据操作之增删改查
前面我们说学习MySQL要从三个层面,四大逻辑来学,三个层面就是库层面,表层面和数据层面对吧,数据库里放数据表,表里放数据是吧,大家可以回忆PPT中jacky的这图,我们已经学完了库层面和表层面,从本 ...
- 解决python中文乱码的方法
首先需要说明的是,windows下的文件路径,cmd窗口等默认编码都是gbk 但在windows下编写python程序的时候,我们一般采用的编码是utf-8 二者不一致是导致乱码的根本原因! 在pyc ...