PlayCanvas PBR材质shader代码分析(pixel shader)
#version es
#define varying in
out highp vec4 pc_fragColor;
#define gl_FragColor pc_fragColor
#define texture2D texture
#define textureCube texture
#define texture2DProj textureProj
#define texture2DLodEXT textureLod
#define texture2DProjLodEXT textureProjLod
#define textureCubeLodEXT textureLod
#define texture2DGradEXT textureGrad
#define texture2DProjGradEXT textureProjGrad
#define textureCubeGradEXT textureGrad
#define GL2
precision highp float;
#ifdef GL2
precision highp sampler2DShadow;
#endif
varying vec3 vPositionW;
varying vec3 vNormalW;
uniform vec3 view_position;
uniform vec3 light_globalAmbient;
float square(float x) {
return x*x;
}
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
vec3 saturate(vec3 x) {
return clamp(x, vec3(0.0), vec3(1.0));
}
vec4 dReflection;
vec3 dAlbedo;
vec3 dNormalW;
vec3 dVertexNormalW;
vec3 dViewDirW;
vec3 dReflDirW;
vec3 dDiffuseLight;
vec3 dSpecularLight;
vec3 dSpecularity;
float dGlossiness;
float dAlpha;
void getNormal() {
dNormalW = normalize(dVertexNormalW);
}
vec3 gammaCorrectInput(vec3 color) {
return pow(color, vec3(2.2));
}
float gammaCorrectInput(float color) {
return pow(color, 2.2);
}
vec4 gammaCorrectInput(vec4 color) {
return vec4(pow(color.rgb, vec3(2.2)), color.a);
}
vec4 texture2DSRGB(sampler2D tex, vec2 uv) {
vec4 rgba = texture2D(tex, uv);
rgba.rgb = gammaCorrectInput(rgba.rgb);
return rgba;
}
vec4 texture2DSRGB(sampler2D tex, vec2 uv, float bias) {
vec4 rgba = texture2D(tex, uv, bias);
rgba.rgb = gammaCorrectInput(rgba.rgb);
return rgba;
}
vec4 textureCubeSRGB(samplerCube tex, vec3 uvw) {
vec4 rgba = textureCube(tex, uvw);
rgba.rgb = gammaCorrectInput(rgba.rgb);
return rgba;
}
vec3 gammaCorrectOutput(vec3 color) {
#ifdef HDR
return color;
#else
color += vec3(0.0000001);
return pow(color, vec3(0.45));
#endif
}
uniform float exposure;
// 线性toneMap整体颜色亮度调节
vec3 toneMap(vec3 color) {
return color * exposure;
}
vec3 addFog(vec3 color) {
return color;
}
// 这里RGBM解码是pc引擎专门修改过的 编码做了pow(0.5) 最大值调整为了8.0
vec3 decodeRGBM(vec4 rgbm) {
vec3 color = (8.0 * rgbm.a) * rgbm.rgb;
return color * color;
}
vec3 texture2DRGBM(sampler2D tex, vec2 uv) {
return decodeRGBM(texture2D(tex, uv));
}
vec3 textureCubeRGBM(samplerCube tex, vec3 uvw) {
return decodeRGBM(textureCube(tex, uvw));
}
vec3 fixSeams(vec3 vec, float mipmapIndex) {
float scale = 1.0 - exp2(mipmapIndex) / 128.0;
float M = max(max(abs(vec.x), abs(vec.y)), abs(vec.z));
if (abs(vec.x) != M) vec.x *= scale;
if (abs(vec.y) != M) vec.y *= scale;
if (abs(vec.z) != M) vec.z *= scale;
return vec;
}
vec3 fixSeams(vec3 vec) {
float scale = 1.0 - 1.0 / 128.0;
float M = max(max(abs(vec.x), abs(vec.y)), abs(vec.z));
if (abs(vec.x) != M) vec.x *= scale;
if (abs(vec.y) != M) vec.y *= scale;
if (abs(vec.z) != M) vec.z *= scale;
return vec;
}
vec3 fixSeamsStatic(vec3 vec, float invRecMipSize) {
float scale = invRecMipSize;
float M = max(max(abs(vec.x), abs(vec.y)), abs(vec.z));
if (abs(vec.x) != M) vec.x *= scale;
if (abs(vec.y) != M) vec.y *= scale;
if (abs(vec.z) != M) vec.z *= scale;
return vec;
}
vec3 cubeMapProject(vec3 dir) {
return dir;
}
vec3 processEnvironment(vec3 color) {
return color;
}
#undef MAPFLOAT #undef MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE
#ifdef MAPCOLOR
uniform vec3 material_diffuse;
#endif
#ifdef MAPTEXTURE
uniform sampler2D texture_diffuseMap;
#endif
// 获取基础色
void getAlbedo() {
dAlbedo = vec3(1.0);
#ifdef MAPCOLOR
dAlbedo *= material_diffuse.rgb;
#endif
#ifdef MAPTEXTURE
dAlbedo *= texture2DSRGB(texture_diffuseMap, UV).CH;
#endif
#ifdef MAPVERTEX
dAlbedo *= gammaCorrectInput(saturate(vVertexColor.VC));
#endif
}
#undef MAPFLOAT #undef MAPCOLOR
#define MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE
#ifdef MAPCOLOR
uniform vec3 material_emissive;
#endif
#ifdef MAPFLOAT
uniform float material_emissiveIntensity;
#endif
#ifdef MAPTEXTURE
uniform sampler2D texture_emissiveMap;
#endif
// 获取自发光颜色
vec3 getEmission() {
vec3 emission = vec3(1.0);
#ifdef MAPFLOAT
emission *= material_emissiveIntensity;
#endif
#ifdef MAPCOLOR
emission *= material_emissive;
#endif
#ifdef MAPTEXTURE
emission *= texture2DSAMPLE(texture_emissiveMap, UV).CH;
#endif
#ifdef MAPVERTEX
emission *= gammaCorrectInput(saturate(vVertexColor.VC));
#endif
return emission;
}
float antiAliasGlossiness(float power) {
return power;
}
#undef MAPFLOAT
#define MAPFLOAT #undef MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE
// 通过金属性计算各个颜色通道镜面反射强度系数,调整基础色颜色亮度
void processMetalness(float metalness) {
const float dielectricF0 = 0.04;
dSpecularity = mix(vec3(dielectricF0), dAlbedo, metalness);
dAlbedo *= 1.0 - metalness;
}
#ifdef MAPFLOAT
uniform float material_metalness;
#endif
#ifdef MAPTEXTURE
uniform sampler2D texture_metalnessMap;
#endif
// 获取镜面反射强度系数
void getSpecularity() {
float metalness = 1.0;
#ifdef MAPFLOAT
metalness *= material_metalness;
#endif
#ifdef MAPTEXTURE
metalness *= texture2D(texture_metalnessMap, UV).CH;
#endif
#ifdef MAPVERTEX
metalness *= saturate(vVertexColor.VC);
#endif
processMetalness(metalness);
}
#undef MAPFLOAT
#define MAPFLOAT #undef MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE
#ifdef MAPFLOAT
uniform float material_shininess;
#endif
#ifdef MAPTEXTURE
uniform sampler2D texture_glossMap;
#endif
// 计算光泽度
void getGlossiness() {
dGlossiness = 1.0;
#ifdef MAPFLOAT
dGlossiness *= material_shininess;
#endif
#ifdef MAPTEXTURE
dGlossiness *= texture2D(texture_glossMap, UV).CH;
#endif
#ifdef MAPVERTEX
dGlossiness *= saturate(vVertexColor.VC);
#endif
dGlossiness += 0.0000001;
}
// Schlick's approximation
uniform float material_fresnelFactor; // unused
// 计算菲尼尔系数并且调整镜面反射系数
void getFresnel() {
float fresnel = 1.0 - max(dot(dNormalW, dViewDirW), 0.0);
float fresnel2 = fresnel * fresnel;
fresnel *= fresnel2 * fresnel2;
fresnel *= dGlossiness * dGlossiness;
dSpecularity = dSpecularity + (1.0 - dSpecularity) * fresnel;
}
#ifndef PMREM4
#define PMREM4
uniform samplerCube texture_prefilteredCubeMap128;
#endif
uniform float material_reflectivity;
// 添加ibl全局光镜面反射颜色
void addReflection() {
float bias = saturate(1.0 - dGlossiness) * 5.0; // multiply by max mip level #ifdef ENABLE_ENVROT
vec3 fixedReflDir = fixSeams(cubeMapProject(environmentRotate(dReflDirW)), bias);
#else
vec3 fixedReflDir = fixSeams(cubeMapProject(dReflDirW), bias);
#endif
fixedReflDir.x *= -1.0;
vec3 refl = processEnvironment(decodeRGBM( textureCubeLodEXT(texture_prefilteredCubeMap128, fixedReflDir, bias) ).rgb);
dReflection += vec4(refl, material_reflectivity);
}
// 漫反射 * 基础色 * (1.0 - 镜面反射强度) + (镜面反射 + 环境反射) * 镜面反射强度
// 这里漫反射包含了直接光+ibl全局光
vec3 combineColor() {
return mix(dAlbedo * dDiffuseLight, dSpecularLight + dReflection.rgb * dReflection.a, dSpecularity);
}
#ifndef PMREM4
#define PMREM4
uniform samplerCube texture_prefilteredCubeMap128;
#endif // 获取ibl全局光漫反射颜色
void addAmbient() {
#ifdef ENABLE_ENVROT
vec3 fixedReflDir = fixSeamsStatic(environmentRotate(dNormalW), 1.0 - 1.0 / 4.0);
#else
vec3 fixedReflDir = fixSeamsStatic(dNormalW, 1.0 - 1.0 / 4.0);
#endif
fixedReflDir.x *= -1.0;
dDiffuseLight += processEnvironment(decodeRGBM( textureCubeLodEXT(texture_prefilteredCubeMap128, fixedReflDir, 5.0) ).rgb);
}
// 获取V向量
void getViewDir() {
dViewDirW = normalize(view_position - vPositionW);
}
// 获取R向量
void getReflDir() {
dReflDirW = normalize(-reflect(dViewDirW, dNormalW));
}
void main(void) {
// 漫反射颜色
dDiffuseLight = vec3();
// 镜面反射颜色
dSpecularLight = vec3();
// ibl全局环境反射
dReflection = vec4();
// 镜面反射强度系数
dSpecularity = vec3();
// 顶点世界空间法线
dVertexNormalW = vNormalW;
dAlpha = 1.0;
getViewDir();// 计算 view - pos
getNormal();// 计算世界空间法线
getReflDir();// 计算反射方向
getAlbedo();// 计算基础色,一般走diffuseMap、顶点颜色、材质diffuse颜色直接取出
getSpecularity();// 计算镜面反射强度系数, 镜面反射强度通过金属性系数来计算,金属性越强反射强度越大漫反射越弱,金属性越弱反射强度越小漫反射颜色越强,从而漫反射和镜面反射遵循能量守恒
getGlossiness();// 计算光泽度(相当于粗糙度的相反叫法) 通过外部给材质设定系数或者走光泽度贴图获取
getFresnel(); // 计算菲尼尔效果
addAmbient(); // 计算环境光颜色(间接光漫反射颜色)
addReflection(); // 计算环境光反射(间接光镜面高光颜色)
gl_FragColor.rgb = combineColor(); // 组合漫反射、基础色、镜面反射输出颜色
gl_FragColor.rgb += getEmission(); // 累加自发光颜色
gl_FragColor.rgb = addFog(gl_FragColor.rgb); // 雾化效果计算
#ifndef HDR
gl_FragColor.rgb = toneMap(gl_FragColor.rgb); // tonemap计算
gl_FragColor.rgb = gammaCorrectOutput(gl_FragColor.rgb);// gamma矫正回到gama颜色空间
#endif
gl_FragColor.a = 1.0;
}
PlayCanvas PBR材质shader代码分析(pixel shader)的更多相关文章
- PlayCanvas PBR材质shader代码分析(vertex shader)
顶点shader主要对顶点坐标变换,将顶点坐标从local->world->view->clip 空间变换 local空间:模型物体坐标系 world空间:世界空间坐标系 view空 ...
- 【OpenGL】Shader实例分析(七)- 雪花飘落效果
转发请保持地址:http://blog.csdn.net/stalendp/article/details/40624603 研究了一个雪花飘落效果.感觉挺不错的.分享给大家,效果例如以下: 代码例如 ...
- 【OpenGL】Shader实例分析(九)- AngryBots中的主角受伤特效
转发请保持地址:http://blog.csdn.net/stalendp/article/details/40859441 AngryBots是Unity官方的一个非常棒的样例.非常有研究价值. 曾 ...
- 片元着色器(Fragment Shader)被称为像素着色器(Pixel Shader),但
片元着色器(Fragment Shader)被称为像素着色器(Pixel Shader),但片元着色器是一个更合适的名字, 因为此时的片元并不是一个真正意义上的像素.
- [工作积累] D3D10+ 中 Pixel Shader 的input semantic和参数顺序
由于semantic的使用,我们有理由相信 vertex shader的output 和 pixel shader的input是按照semantic来匹配的,而跟传入顺序无关.印象dx9时代是这样. ...
- 今天写shader流光效果,shader代码少了个括号,unity shader compiler卡死且不提示原因
今天写shader流光效果,shader代码少了个括号,unity shader compiler卡死且不提示原因 好在找到了原因,shader 代码如下,原理是提高经过的颜色亮度 void surf ...
- UE制作PBR材质攻略Part 1 - 色彩知识
目录 一.前言 二.色彩知识 2.1 色彩理论 2.1.1 成像原理 2.1.2 色彩模型和色彩空间 2.1.3 色彩属性 2.1.4 直方图 2.1.5 色调曲线 2.1.6 线性空间与Gamma空 ...
- 《图说VR入门》——googleVR入门代码分析
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/53013843 作者:car ...
- Unity Shader 00 - 梳理 Unity Shader 的基本结构
0x00 写在前面 之前一直在阅读 The Book of Shaders 一书,为什么会开始写 Unity Shader 呢?一方面,因为该书目前尚未完结,写下此文时已阅读到该书的最新章节:另一方面 ...
随机推荐
- Qt串行化的输入和输出(使用QDataStream读写QByteArray,对QIODevice直接起作用)
参考https://lug.ustc.edu.cn/sites/qtguide/ 今天看了一个介绍Qt串行化的介绍,感觉很受益,就记录了下来. 串行化(Serialization)是计算机科学中的一个 ...
- java基础 -- 关键字final的用法
用法一(修饰变量): Final变量能被显式地初始化并且只能初始化一次.被声明为final的对象的引用不能指向不同的对象.但是final对象里的数据可以被改变.也就是说final对象的引用不能改变,但 ...
- 机器学习回顾篇(12):集成学习之Bagging与随机森林
.caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...
- 使用spring框架创建最简单的java web程序(IDEA商业版)
项目目录如下(IDEA社区版好像无法识别webapp目录?原因见https://www.cnblogs.com/bityinjd/p/9284378.html): 工具: IDEA 1.首先使用ma ...
- GNE: 4行代码实现新闻类网站通用爬虫
GNE(GeneralNewsExtractor)是一个通用新闻网站正文抽取模块,输入一篇新闻网页的 HTML, 输出正文内容.标题.作者.发布时间.正文中的图片地址和正文所在的标签源代码.GNE在提 ...
- 【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)
[题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖 ...
- 07Shell数组
Shell 数组变量 普通数组:只能使用整数作为数组索引 关联数组:可以使用字符串作为数组索引 普通数组 定义数组 方法1: 一次赋一个值 数组名[索引]=变量值 示例 # array1[0]=pea ...
- 《算法笔记》之基础C/C++进阶
这一次主要讲C++不同于C的地方:类. 1.类的定义 定义一个类,本质上是定义一个数据类型的蓝图.这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可 ...
- 查看磁盘型号和内存及raid信息
1.查看磁盘型号 工具:smartmontools #smartctl --help #smartctl --all /dev/sda -d megarid,1 (第一块磁盘的信息) #smartct ...
- ACID特性及幻读的理解
事务是关系型数据库的重要特性.它是一个包含了一条或多条SQL语句的逻辑原子单元.一个事务包含的SQL要么全部提交,要么全部回滚. Oracle 官方文档中对事务的描述如下: A transaction ...