用vulkan写个引擎 (四)PBR着色器

news/2024/10/23 5:42:19/

PBR全称(Physicallly-Based Rendering),基于物理的渲染。本文将提供一份GLSL实用型着色器。对于理论部分网络上已经有太多文章了。

仓库:https://bitbucket.org/mm_longcheng/mm-vulkan

扣扣交流群:554329899

一、着色器入参问题

对于着色器入参的不同会导致着色器实现的不同
1. 顶点着色器的顶点属性,是否有骨骼蒙皮。
2.片段着色器对于PBR需要的采样器的提供程度不同,而顶点着色器传过来的数据也有不同。

我的方案是将入参形式做一些哈希,得到一些序号组合,然后分别实现它们。

以下是顶点着色器,片段着色器,管线的取名规则
```// Primitive Attribute flag// // a0 | 0 NotNORMAL     NotTANGENT    | 1 HasNORMAL     NotTANGENT    | 2 HasNORMAL     HasTANGENT    |// a1 | 0 NotTEXCOORD0  NotTEXCOORD1  | 1 HasTEXCOORD0  NotTEXCOORD1  | 2 HasTEXCOORD0  HasTEXCOORD1  |// a2 | 0 NotCOLOR0VEC3 NotCOLOR0VEC4 | 1 HasCOLOR0VEC3 NotCOLOR0VEC4 | 2 HasCOLOR0VEC3 HasCOLOR0VEC4 |// a3 | 0 NotJOINTS0    NotJOINTS1    | 1 HasJOINTS0    NotJOINTS1    | 2 HasJOINTS0    HasJOINTS1    |//// Material Texture flag// // m0 has TextureBaseColor// m1 has TextureMetallicRoughness// m2 has TextureNormal// m3 has TextureOcclusion// m4 has TextureEmissive//// Attribute Type flag// // t0 type AttributeTEXCOORD0// t1 type AttributeTEXCOORD1// t2 type AttributeCOLOR0// t3 type AttributeJOINTS0// t4 type AttributeJOINTS1// t5 type AttributeWEIGHTS0// t6 type AttributeWEIGHTS1//// u0 = Primitive mode// d0 = Material double sided// // vertex   shader hash: a3a2a1a0// fragment shader hash: a2a1a0-m4m3m2m1m0// pipeline        hash: a3a2a1a0-m4m3m2m1m0-t6t5t4t3t2t1t0-u0d0以下是顶点着色器入参格式的哈希规则// Primitive Component Type//     NONE            0//     UNSIGNED_BYTE   1//     UNSIGNED_SHORT  2//     FLOAT           3//// POSITION   "VEC3" 5126 (FLOAT)//// NORMAL     "VEC3" 5126 (FLOAT)//// TANGENT    "VEC4" 5126 (FLOAT)//// TEXCOORD_0 "VEC2" 5126 (FLOAT)                    //                   5121 (UNSIGNED_BYTE)normalized  //                   5123 (UNSIGNED_SHORT)normalized //// COLOR_0    "VEC3" 5126 (FLOAT)                    //            "VEC4" 5121 (UNSIGNED_BYTE)normalized  //                   5123 (UNSIGNED_SHORT)normalized //// JOINTS_0   "VEC4" 5121 (UNSIGNED_BYTE)            //                   5123 (UNSIGNED_SHORT)           //// WEIGHTS_0  "VEC4" 5126 (FLOAT)                    //                   5121 (UNSIGNED_BYTE)normalized  //                   5123 (UNSIGNED_SHORT)normalized 顶点着色器 常用81种                         取名位无法线无切线 有法线无切线 有法线有切线      3  000F 0000 0001 0002无纹理       有纹理0      有纹理1           3  00F0 0000 0010 0020无颜色       有颜色0vec3  有颜色0vec4       3  0F00 0000 0100 0200无骨骼       有骨骼0      有骨骼1           3  F000 0000 1000 2000片段着色器 常用27种                         取名位无法线无切线 有法线无切线 有法线有切线      3  000F 0000 0001 0002无纹理       有纹理0      有纹理1           3  00F0 0000 0010 0020无颜色       有颜色0vec3  有颜色0vec4       3  0F00 0000 0100 0200
```以下是材质参数的哈希规则
```
void
mmVKTFMaterial_MakeLayoutHashId(const struct mmVKTFMaterial*                   p,char                                           l[2])
{int n = 0;n += (-1 != p->vIndex[mmVKTFTextureBaseColor]);n += (-1 != p->vIndex[mmVKTFTextureMetallicRoughness]);n += (-1 != p->vIndex[mmVKTFTextureNormal]);n += (-1 != p->vIndex[mmVKTFTextureOcclusion]);n += (-1 != p->vIndex[mmVKTFTextureEmissive]);// layout          hash: nsprintf(l, "%d", n);
}
```

例子:

我们以加载Cesium_Man.glb为例,以下是gltf中提供的数据

以下是模型的材质和图元信息
```"materials": [{"pbrMetallicRoughness": {"baseColorTexture": {"index": 0,"texCoord": 0},"metallicFactor": 0,"baseColorFactor": [1, 1, 1, 1],"roughnessFactor": 1},"emissiveFactor": [0, 0, 0],"alphaMode": "OPAQUE","doubleSided": false,"name": "Cesium_Man-effect"}],"meshes": [{"primitives": [{"attributes": {"JOINTS_0": 1,"NORMAL": 2,"POSITION": 3,"TEXCOORD_0": 4,"WEIGHTS_0": 5},"indices": 0,"mode": 4,"material": 0}],"name": "Cesium_Man"}],
```以下是从模型加载出来的顶点属性的具体格式
```
VkVertexInputBindingDescription vibd = 
{"POSITION"binding	0	unsigned intstride	12	unsigned intinputRate	VK_VERTEX_INPUT_RATE_VERTEX (0)	VkVertexInputRate"NORMAL"binding	1	unsigned intstride	12	unsigned intinputRate	VK_VERTEX_INPUT_RATE_VERTEX (0)	VkVertexInputRate"TEXCOORD_0"binding	2	unsigned intstride	8	unsigned intinputRate	VK_VERTEX_INPUT_RATE_VERTEX (0)	VkVertexInputRate"JOINTS_0"binding	3	unsigned intstride	8	unsigned intinputRate	VK_VERTEX_INPUT_RATE_VERTEX (0)	VkVertexInputRate"WEIGHTS_0"binding	4	unsigned intstride	16	unsigned intinputRate	VK_VERTEX_INPUT_RATE_VERTEX (0)	VkVertexInputRate
}VkVertexInputAttributeDescription viad = 
{"POSITION"location	0	unsigned intbinding	0	unsigned intformat	VK_FORMAT_R32G32B32_SFLOAT (106)	VkFormatoffset	0	unsigned int"NORMAL"location	1	unsigned intbinding	1	unsigned intformat	VK_FORMAT_R32G32B32_SFLOAT (106)	VkFormatoffset	0	unsigned int"TEXCOORD_0"location	2	unsigned intbinding	2	unsigned intformat	VK_FORMAT_R32G32_SFLOAT (103)	VkFormatoffset	0	unsigned int"JOINTS_0"location	3	unsigned intbinding	3	unsigned intformat	VK_FORMAT_R16G16B16A16_UINT (95)	VkFormatoffset	0	unsigned int"WEIGHTS_0"location	4	unsigned intbinding	4	unsigned intformat	VK_FORMAT_R32G32B32A32_SFLOAT (109)	VkFormatoffset	0	unsigned int
}
```

我们得到了入参的哈希信息

它有骨骼动画 1
没有颜色入参 0
有纹理0      1
有法线无切线 1它有baseColor基础漫反射贴图                       1
没有metallicRoughnessTexture物理属性贴图          0
没有normalTexture法线贴图                        0
没有occlusionTexture遮蔽贴图                     0
没有emissiveTexture高光贴图                      0VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST            3
没有使用doubleSided双面渲染                      0Pipeline lName: mmVKTFMaterial-1
Pipeline vName: spiv/gltf/3d-1011.vert.spv
Pipeline fName: spiv/gltf/3d-011-00001.frag.spv
Pipeline xName: 3d-1011-00001-0302003-30

二、PBR着色器函数

网上关于这个的其实很多,但是并没有把它们拼合成一个可用的版本,都在罗列理论,函数比较零散。

下面是顶点着色器和片段着色器的部分,注意我们是通过一些开关来处理不同入参形式。

顶点着色器 3d-1011.vert
```
#version 450#extension GL_GOOGLE_include_directive : enable#include "vs-UBOScene.glsl"
#include "vs-PushConstants.glsl"
#include "vs-UBOSkin.glsl"layout (location = 0) in vec3  a_position;
layout (location = 1) in vec3  a_normal;
layout (location = 2) in vec2  a_texcoord[1];
layout (location = 3) in uvec4 a_joints_0;
layout (location = 4) in vec4  a_weights_0;layout (location = 0) out vec3 v_position;
layout (location = 1) out vec3 v_normal;
layout (location = 2) out vec2 v_texcoord[1];out gl_PerVertex
{vec4 gl_Position;
};void main()
{// world space.mat4 skinMat = mat4( 0.0 );skinMat += a_weights_0.x * uboSkin.joints[a_joints_0.x];skinMat += a_weights_0.y * uboSkin.joints[a_joints_0.y];skinMat += a_weights_0.z * uboSkin.joints[a_joints_0.z];skinMat += a_weights_0.w * uboSkin.joints[a_joints_0.w];mat4 modelMat = constants.model * skinMat;mat3 normalMat = transpose(inverse(mat3(modelMat)));v_position = vec3(modelMat * vec4(a_position, 1.0));v_normal = normalize(normalMat * a_normal);v_texcoord[0] = a_texcoord[0];gl_Position = uboScene.projection * uboScene.view * vec4(v_position, 1.0);
}
```片段着色器 3d-011-00001.frag
```
#version 450#extension GL_GOOGLE_include_directive : enable// Interface protocol macro definition.
#define HAS_VaryingNormal
// #define HAS_VaryingTBN
// #define HAS_VaryingColor
#define HAS_VaryingTexcoord// Material texture macro definition.
#define HAS_TextureBaseColor
// #define HAS_TextureMetallicRoughness
// #define HAS_TextureNormal
// #define HAS_TextureOcclusion
// #define HAS_TextureEmissive// Vertex input Protocol.
layout (location = 0) in vec3 v_position;
layout (location = 1) in vec3 v_normal;
layout (location = 2) in vec2 v_texcoord[1];// Material sampler Protocol.
layout (set = 1, binding = 1) uniform sampler2D baseColorTexture;#include "fs-Main.glsl"
```

下面是include的实际部分

vs-UBOScene.glsl
```
layout (set = 0, binding = 0, std140) uniform UBOScene
{mat4 projection;mat4 view;
} uboScene;
```vs-PushConstants.glsl
```
layout (push_constant, std140) uniform PushConstants
{mat4 normal;mat4 model;
} constants;
```vs-UBOSkin.glsl
```
layout (set = 2, binding = 0, std430) readonly buffer UBOSkin 
{mat4 joints[];
} uboSkin;
```fs-Main.glsl
```
#include "fs-Constant.glsl"
#include "fs-PerturbNormal.glsl"
#include "fs-SRGB.glsl"
#include "fs-Lights.glsl"
#include "fs-UBOScene.glsl"
#include "fs-UBOMaterial.glsl"
#include "fs-BRDF.glsl"
#include "fs-ToneMap.glsl"
#include "fs-AlphaMode.glsl"layout (location = 0) out vec4 outColor;void main()
{// view vector// world space.vec3 V = normalize(uboScene.camera - v_position);// normal vectorvec3 N = GetNormal();vec4 baseColor = GetBaseColor();baseColor = AlphaModeColor(baseColor);#ifndef HAS_TextureMetallicRoughnessfloat metallic = uboMaterial.metallicFactor;float roughness = uboMaterial.roughnessFactor;
#elsevec2 value = GetMetallicRoughness();float metallic = value.x;float roughness = value.y;
#endif//HAS_TextureMetallicRoughness    vec3 color = vec3(0.0);vec3 ambient = uboScene.ambient;vec3 ambientColor = baseColor.rgb * ambient;const vec3 black = vec3(0.0);vec3 diffuseColor = mix(baseColor.rgb, black, metallic);const float f90 = 1.0;vec3 f0 = mix(vec3(0.04), baseColor.rgb, metallic);int i;for (i = 0;i < uboScene.lightCount;++i){UBOLight light = uboLights.lights[i];vec3 L = GetPointToLight(light, v_position);vec3 intensity = GetLighIntensity(light, L);vec3 material  = BRDF_Material(L, V, N, diffuseColor, f0, f90, roughness);color += material * intensity;}color += ambientColor;/*vec3 lightColor   = uboScene.lightColor;float distance    = length(L);float attenuation = 1.0 / (distance * distance);vec3 radiance     = lightColor * attenuation;vec3 material     = BRDF_Material(L, V, N, diffuseColor, f0, f90, roughness);color = material * radiance + ambientColor;*/#ifdef HAS_TextureOcclusioncolor = GetOcclusionColor(color);
#endif//HAS_TextureOcclusion#ifdef HAS_TextureEmissivecolor += GetEmissiveColor();
#endif//HAS_TextureEmissive// Tone mappingoutColor = vec4(toneMap(color), baseColor.a);
}
```fs-Constant.glsl
```
#define MM_E                  2.71828182845904523536028747135266250   /* e           */
#define MM_LOG2E              1.44269504088896340735992468100189214   /* log2(e)     */
#define MM_LOG10E             0.434294481903251827651128918916605082  /* log10(e)    */
#define MM_LN2                0.693147180559945309417232121458176568  /* loge(2)     */
#define MM_LN10               2.30258509299404568401799145468436421   /* loge(10)    */
#define MM_PI                 3.14159265358979323846264338327950288   /* pi          */
#define MM_PI_DIV_2           1.57079632679489661923132169163975144   /* pi/2        */
#define MM_PI_DIV_4           0.785398163397448309615660845819875721  /* pi/4        */
#define MM_1_DIV_PI           0.318309886183790671537767526745028724  /* 1/pi        */
#define MM_2_DIV_PI           0.636619772367581343075535053490057448  /* 2/pi        */
#define MM_2_DIV_SQRTPI       1.12837916709551257389615890312154517   /* 2/sqrt(pi)  */
#define MM_SQRT2              1.41421356237309504880168872420969808   /* sqrt(2)     */
#define MM_1_DIV_SQRT2        0.707106781186547524400844362104849039  /* 1/sqrt(2)   */#define MM_EPSILON   1e-6#define saturate( a ) clamp( a, 0.0, 1.0 )#define pow2( a ) (a * a)const float MM_GAMMA = 2.2;
const float MM_1_DIV_GAMMA = 1.0 / MM_GAMMA;// enum mmGLTFAlphaMode_t
const int mmGLTFAlphaModeOpaque  = 0;// "OPAQUE"
const int mmGLTFAlphaModeMask    = 1;// "MASK"
const int mmGLTFAlphaModeBlend   = 2;// "BLEND"
```fs-PerturbNormal.glsl
```
// Bump Mapping.
// Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
// http://api.unrealengine.com/attachments/Engine/Rendering/LightingAndShadows/BumpMappingWithoutTangentSpace/mm_sfgrad_bump.pdf
vec3 PerturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection) 
{// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988vec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );vec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );vec3 vN = surf_norm;        // normalizedvec3 R1 = cross( vSigmaY, vN );vec3 R2 = cross( vN, vSigmaX );float fDet = dot( vSigmaX, R1 ) * faceDirection;vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );return normalize( abs( fDet ) * surf_norm - vGrad );
}// Normal Mapping Without Precomputed Tangents
// http://www.thetenthplanet.de/archives/1180
vec3 PerturbNormal2Arb(vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection, vec2 vUv) 
{// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );vec2 st0 = dFdx( vUv.st );vec2 st1 = dFdy( vUv.st );vec3 N = surf_norm; // normalizedvec3 q1perp = cross( q1, N );vec3 q0perp = cross( N, q0 );vec3 T = q1perp * st0.x + q0perp * st1.x;vec3 B = q1perp * st0.y + q0perp * st1.y;float det = max( dot( T, T ), dot( B, B ) );float scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );return normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );
}
```fs-SRGB.glsl
```
// linear to sRGB approximation
// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
vec3 linearTosRGB(vec3 color)
{return pow(color, vec3(MM_1_DIV_GAMMA));
}// sRGB to linear approximation
// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
vec3 sRGBToLinear(vec3 srgbIn)
{return vec3(pow(srgbIn.xyz, vec3(MM_GAMMA)));
}vec4 sRGBToLinear(vec4 srgbIn)
{return vec4(sRGBToLinear(srgbIn.xyz), srgbIn.w);
}
```fs-Lights.glsl
```
// KHR_lights_punctual extension.
// see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
struct UBOLight
{vec3 direction;vec3 position;vec3 color;float range;float intensity;float innerConeCos;float outerConeCos;int type;
};const int mmGLTFLightTypeInvalid      = 0; //  Invalid
const int mmGLTFLightTypeDirectional  = 1; // "directional"
const int mmGLTFLightTypePoint        = 2; // "point"
const int mmGLTFLightTypeSpot         = 3; // "spot"// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#range-property
float GetRangeAttenuation(const in float range, const in float distance)
{if (range <= 0.0){// negative range means unlimitedreturn 1.0 / pow(distance, 2.0);}else{return max(min(1.0 - pow(distance / range, 4.0), 1.0), 0.0) / pow(distance, 2.0);}
}// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#inner-and-outer-cone-angles
float GetSpotAttenuation(const in vec3  pointToLight, const in vec3  spotDirection, const in float outerConeCos, const in float innerConeCos)
{float actualCos = dot(normalize(spotDirection), normalize(-pointToLight));if (actualCos > outerConeCos){if (actualCos < innerConeCos){return smoothstep(outerConeCos, innerConeCos, actualCos);}else{return 1.0;}}else{return 0.0;}
}vec3 GetLighIntensity(const in UBOLight light, const in vec3 pointToLight)
{float rangeAttenuation = 1.0;float spotAttenuation = 1.0;if (light.type != mmGLTFLightTypeDirectional){rangeAttenuation = GetRangeAttenuation(light.range, length(pointToLight));}if (light.type == mmGLTFLightTypeSpot){spotAttenuation = GetSpotAttenuation(pointToLight, light.direction, light.outerConeCos, light.innerConeCos);}return rangeAttenuation * spotAttenuation * light.intensity * light.color;
}vec3 GetPointToLight(const in UBOLight light, const in vec3 position)
{if (light.type != mmGLTFLightTypeDirectional){return light.position - position;}else{return -light.direction;}
}
```fs-UBOScene.glsl
```
layout (set = 0, binding = 1, std140) uniform UBOScene
{vec3 camera;vec3 ambient;float exposure;int lightCount;
} uboScene;layout (set = 0, binding = 2, std430) readonly buffer UBOLights 
{UBOLight lights[];
} uboLights;
```fs-UBOMaterial.glsl
```
struct UBOTextureInfo
{int index;int texCoord;
};layout (set = 1, binding = 0, std140) uniform UBOMaterial 
{UBOTextureInfo baseColorTexture;UBOTextureInfo metallicRoughnessTexture;UBOTextureInfo normalTexture;UBOTextureInfo occlusionTexture;UBOTextureInfo emissiveTexture;vec4 baseColorFactor;vec3 emissiveFactor;float metallicFactor;float roughnessFactor;float scale;float strength;float alphaCutoff;int alphaMode;int doubleSided;
} uboMaterial;// BaseColor
#ifndef HAS_VaryingColor#ifndef HAS_TextureBaseColorvec4 GetBaseColor()
{return uboMaterial.baseColorFactor;
}#else#ifndef HAS_VaryingTexcoord
vec4 GetBaseColor()
{return uboMaterial.baseColorFactor;
}
#else
vec4 GetBaseColor()
{vec4 color;UBOTextureInfo t = uboMaterial.baseColorTexture;if (-1 == t.index){color = uboMaterial.baseColorFactor;}else{color = texture(baseColorTexture, v_texcoord[t.texCoord]);color = uboMaterial.baseColorFactor * sRGBToLinear(color);}return color;
}
#endif//HAS_VaryingTexcoord#endif//HAS_TextureBaseColor#else#ifndef HAS_TextureBaseColorvec4 GetBaseColor()
{return uboMaterial.baseColorFactor * v_color_0;
}#else#ifndef HAS_VaryingTexcoord
vec4 GetBaseColor()
{return uboMaterial.baseColorFactor * v_color_0;
}
#else
vec4 GetBaseColor()
{vec4 color;UBOTextureInfo t = uboMaterial.baseColorTexture;if (-1 == t.index){color = uboMaterial.baseColorFactor;}else{color = texture(baseColorTexture, v_texcoord[t.texCoord]);color = uboMaterial.baseColorFactor * sRGBToLinear(color);}return color * v_color_0;
}
#endif//HAS_VaryingTexcoord#endif//HAS_TextureBaseColor#endif//HAS_VaryingColor// Normal
#ifndef HAS_TextureNormal#ifndef HAS_VaryingNormal#ifndef HAS_VaryingTBN
// 0 NotNORMAL     NotTANGENT  NotTextureNormal
vec3 GetNormal()
{// Use flat normalreturn normalize(cross(dFdx(v_position), dFdy(v_position)));
}
#else// x NotNORMAL     HasTANGENT  NotTextureNormal
vec3 GetNormal()
{// Use TBN normalreturn normalize(v_tbn[2]);
}#endif//HAS_VaryingTBN#else#ifndef HAS_VaryingTBN
// 1 HasNORMAL     NotTANGENT  NotTextureNormal
vec3 GetNormal()
{// Use varying normalreturn normalize(v_normal);
}
#else
// 2 HasNORMAL     HasTANGENT  NotTextureNormal
vec3 GetNormal()
{// Use TBN normalreturn normalize(v_tbn[2]);
}
#endif//HAS_VaryingTBN#endif//HAS_VaryingNormal#else#ifndef HAS_VaryingNormal#ifndef HAS_VaryingTBN
// 0 NotNORMAL     NotTANGENT  HasTextureNormal
vec3 GetNormal()
{vec3 normal;UBOTextureInfo t = uboMaterial.normalTexture;if (-1 == t.index){// Use flat normalnormal = normalize(cross(dFdx(v_position), dFdy(v_position)));}else{vec2 vUv = v_texcoord[t.texCoord];normal = texture(normalTexture, vUv).rgb;normal = normalize(normal * 2.0f - 1.0f);}return normal;
}
#else
// x NotNORMAL     HasTANGENT  HasTextureNormal
vec3 GetNormal()
{vec3 normal;UBOTextureInfo t = uboMaterial.normalTexture;if (-1 == t.index){// Use TBN normalnormal = normalize(v_tbn[2]);}else{vec2 vUv = v_texcoord[t.texCoord];normal = texture(normalTexture, vUv).rgb;normal = normalize(normal * 2.0f - 1.0f);normal = normalize(v_tbn * normal);}return normal;
}#endif//HAS_VaryingTBN#else#ifndef HAS_VaryingTBN
// 1 HasNORMAL     NotTANGENT  HasTextureNormal
vec3 GetNormal()
{vec3 normal;UBOTextureInfo t = uboMaterial.normalTexture;if (-1 == t.index){// Use varying normalnormal = normalize(v_normal);}else{// face direction.float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;vec2 vUv = v_texcoord[t.texCoord];normal = texture(normalTexture, vUv).rgb;normal = normalize(normal * 2.0f - 1.0f);normal = PerturbNormal2Arb(-uboScene.camera, v_normal, normal, faceDirection, vUv);}return normal;
}
#else
// 2 HasNORMAL     HasTANGENT  HasTextureNormal
vec3 GetNormal()
{vec3 normal;UBOTextureInfo t = uboMaterial.normalTexture;if (-1 == t.index){// Use varying normalnormal = normalize(v_normal);}else{normal = texture(normalTexture, v_texcoord[t.texCoord]).rgb;normal = normalize(normal * 2.0f - 1.0f);normal = normalize(v_tbn * normal);}return normal;
}
#endif//HAS_VaryingTBN#endif//HAS_VaryingNormal#endif//HAS_TextureNormal// Metallic Roughness
#ifndef HAS_TextureMetallicRoughness
vec2 GetMetallicRoughness()
{vec2 value;value.x = uboMaterial.metallicFactor;value.y = uboMaterial.roughnessFactor;return value;
}
#else
vec2 GetMetallicRoughness()
{vec2 value;UBOTextureInfo t = uboMaterial.metallicRoughnessTexture;if (-1 == t.index){value.x = uboMaterial.metallicFactor;value.y = uboMaterial.roughnessFactor;}else{value = texture(metallicRoughnessTexture, v_texcoord[t.texCoord]).bg;}return value;
}
#endif//HAS_TextureMetallicRoughness// Occlusion
#ifndef HAS_TextureOcclusion
vec3 GetOcclusionColor(vec3 color)
{return color;
}
#else
vec3 GetOcclusionColor(vec3 color)
{float occlusion;UBOTextureInfo t = uboMaterial.occlusionTexture;if (-1 == t.index){occlusion = 1.0;}else{occlusion = texture(occlusionTexture, v_texcoord[t.texCoord]).r;color = mix(color, color * occlusion, uboMaterial.strength);}return color;
}
#endif//HAS_TextureOcclusion// Emissive
#ifndef HAS_TextureEmissive
vec3 GetEmissiveColor()
{return vec3(0.0);
}
#else
vec3 GetEmissiveColor()
{vec3 color;UBOTextureInfo t = uboMaterial.emissiveTexture;if (-1 == t.index){color = vec3(0.0);}else{color = texture(emissiveTexture, v_texcoord[t.texCoord]).rgb;color = uboMaterial.emissiveFactor * sRGBToLinear(color);}return color;
}
#endif//HAS_TextureEmissive
```fs-BRDF.glsl
```
// Fresnel Schlick approximation translates
vec3 F_Schlick(const in vec3  f0, const in float f90, const in float dotVH) 
{// Rf(l,h) = F0 + (1 - F0) * (1 - (l dot h))^5// F0 = Ff(h,h) = Cspecfloat fresnel = pow(1.0 - dotVH, 5.0);return f0 + (f90 - f0) * fresnel;
}// Fresnel Schlick approximation translates
vec3 F_SchlickEpic( const in vec3  f0, const in float f90, const in float dotVH) 
{// Original approximation by Christophe Schlick '94// float fresnel = pow( 1.0 - dotVH, 5.0 );//// Optimized variant (presented by Epic at SIGGRAPH '13)// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdffloat fresnel = exp2((-5.55473 * dotVH - 6.98316) * dotVH);return f0 + (f90 - f0) * fresnel;
}// Geometric Shadowing function
// Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV) 
{float a2 = pow2( alpha );float gv = dotNL * sqrt(a2 + (1.0 - a2) * pow2(dotNV));float gl = dotNV * sqrt(a2 + (1.0 - a2) * pow2(dotNL));return 0.5 / max(gv + gl, MM_EPSILON);
}
// Geometric Shadowing function
float G_GGX( const in float alpha, const in float dotNL, const in float dotNV) 
{float a2 = pow2( alpha );float GGXV = 2 * dotNV / (dotNV + sqrt(a2 + (1.0 - a2) * (dotNV * dotNV)));float GGXL = 2 * dotNL / (dotNL + sqrt(a2 + (1.0 - a2) * (dotNL * dotNL)));return GGXV * GGXL;
}// Microfacet Models for Refraction through Rough Surfaces - equation (33)
// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// alpha is "roughness squared" in Disney’s reparameterization
float D_GGX( const in float alpha, const in float dotNH ) 
{float a2 = pow2(alpha);// avoid alpha = 0 with dotNH = 1float denom = pow2(dotNH) * (a2 - 1.0) + 1.0;return MM_1_DIV_PI * a2 / pow2(denom);
}vec3 BRDF_Diffuse(const in vec3  diffuseColor)
{return MM_1_DIV_PI * diffuseColor;
}vec3 BRDF_Specular(const in float dotNH, const in float dotNL, const in float dotNV, const in float alpha)
{if (dotNL > 0.0 && dotNV > 0.0){// Geometric Shadowing functionfloat G = G_GGX(alpha, dotNL, dotNV);// Normal Distribution functionfloat D = D_GGX(alpha, dotNH);// Visibility functionfloat V = G / (4.0 * dotNL * dotNV);return vec3(V * D);}else{return vec3(0.0);}
}vec3 BRDF_Material(const in vec3  L, const in vec3  V, const in vec3  N,const in vec3  diffuseColor,const in vec3  f0,const in float f90,const in float roughness)
{vec3 H = normalize (V + L);float dotNV = clamp(dot(N, V), 0.0, 1.0);float dotNL = clamp(dot(N, L), 0.0, 1.0);float dotNH = clamp(dot(N, H), 0.0, 1.0);float dotVH = clamp(dot(V, H), 0.0, 1.0);float alpha = roughness * roughness;vec3        F = F_Schlick(f0, f90, dotVH);vec3  diffuse = BRDF_Diffuse(diffuseColor);vec3 specular = BRDF_Specular(dotNH, dotNL, dotNV, alpha);vec3 material = (1 - F) * diffuse + F * specular;return dotNL * material;
}
```fs-ToneMap.glsl
```
// ACES tone map (faster approximation)
// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 toneMapACES_Narkowicz(vec3 color)
{const float A = 2.51;const float B = 0.03;const float C = 2.43;const float D = 0.59;const float E = 0.14;return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
}vec3 toneMap(vec3 color)
{color *= uboScene.exposure;color = toneMapACES_Narkowicz(color);return linearTosRGB(color);
}
```fs-AlphaMode.glsl
```
vec4 AlphaModeColor(vec4 baseColor)
{switch(uboMaterial.alphaMode){case mmGLTFAlphaModeOpaque:{baseColor.a = 1.0;}break;case mmGLTFAlphaModeMask:{// Late discard to avoid samplig artifacts. // See https://github.com/KhronosGroup/glTF-Sample-Viewer/issues/267if (baseColor.a < uboMaterial.alphaCutoff){discard;}baseColor.a = 1.0;}break;case mmGLTFAlphaModeBlend:default:break;}return baseColor;
}
```

三、PBR原理

这里主要说一下BRDF的部分

根据gltf官方文档,实现pbr的混色流程

 注意,这里得到的material并不是最终颜色,我们需要将结果乘以dotNL。

下面是pbr的实现理论 glTF-2.0-and-PBR-GTC_May17.pdf

仅截图BRDF的部分

 

下面是对部分函数实现不同版本的探讨

Fresnel Schlick 有两个版本,我使用的原始版本,这两个函数从渲染结果来看并没有太大不同

// Fresnel Schlick approximation translates
vec3 F_Schlick(const in vec3  f0, const in float f90, const in float dotVH) 
{// Rf(l,h) = F0 + (1 - F0) * (1 - (l dot h))^5// F0 = Ff(h,h) = Cspecfloat fresnel = pow(1.0 - dotVH, 5.0);return f0 + (f90 - f0) * fresnel;
}// Fresnel Schlick approximation translates
vec3 F_SchlickEpic( const in vec3  f0, const in float f90, const in float dotVH) 
{// Original approximation by Christophe Schlick '94// float fresnel = pow( 1.0 - dotVH, 5.0 );//// Optimized variant (presented by Epic at SIGGRAPH '13)// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdffloat fresnel = exp2((-5.55473 * dotVH - 6.98316) * dotVH);return f0 + (f90 - f0) * fresnel;
}

 Geometric Shadowing function 也有两个版本,第一个版本是从three.js获取的,第二个是根据官方给的pdf实现的。从渲染结果来看,我使用了原始版本。第一个版本在模型边缘处会产生一些高亮瑕疵,可能是我使用方式不太对。

// Geometric Shadowing function
// Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV) 
{float a2 = pow2( alpha );float gv = dotNL * sqrt(a2 + (1.0 - a2) * pow2(dotNV));float gl = dotNV * sqrt(a2 + (1.0 - a2) * pow2(dotNL));return 0.5 / max(gv + gl, MM_EPSILON);
}
// Geometric Shadowing function
float G_GGX( const in float alpha, const in float dotNL, const in float dotNV) 
{float a2 = pow2( alpha );float GGXV = 2 * dotNV / (dotNV + sqrt(a2 + (1.0 - a2) * (dotNV * dotNV)));float GGXL = 2 * dotNL / (dotNL + sqrt(a2 + (1.0 - a2) * (dotNL * dotNL)));return GGXV * GGXL;
}

 


http://www.ppmy.cn/news/653708.html

相关文章

Vulkan开发实战详解 学习笔记 - 构建一个球体对象

构建一个球体对象 BallData.h #ifndef VULKANEXBASE_BALLDATA_H #define VULKANEXBASE_BALLDATA_H//防止重复引用 class BallData { public:static float* vdata;//顶点数据数组首地址指针static int dataByteCount;//顶点数据所占总字节数static int vCount;//顶点数量stat…

安装oracle10g32,Windows7旗舰版32位安装oracle10g方法

Windows7旗舰版32位安装oracle10g方法 首先要下载支持Vista版本的Oracle 10g 下载完成后解压出来&#xff1a; http://www.doczj.com/doc/816ed069b84ae45c3b358c7a.html/otn/nt/oracle10g/10203/10203_vista_w2k8_x86_production_d b.zip安装的第一步就是要修改安装文件目录中…

oracle11g32位安装流程_Oracle11g R2 安装图解(win7 32位)

1.首先去网址&#xff1a;http://www.oracle.com/technetwork/cn/database/enterprise-edition/downloads/112010-win32soft-098630-zhs.html 下载安装包&#xff0c;解压的时候一定要放在一起解压 2、找到解压的database文件夹中的Setup.exe直接双击安装。 3、安装环境检测 4.…

oracle11g32位安装流程_Oracle 11g下载

多多为大家免费提供Oracle 11g下载&#xff0c;包含64位/32位官方版本&#xff0c;并附详细的Oracle 11g安装图解教程&#xff0c;同时希望能帮助到刚接触到Oracle数据库的朋友。安装过程稍需一段时间&#xff0c;具体时间决取于你的电脑配置&#xff0c;请大家稍安勿躁。 Orac…

D3D计算着色器入门

1.对计算着色器的理解&#xff1a; 计算着色器跟他的名字一样&#xff0c;就是进行计算的着色器。但是它的用途不仅局限于图形的运算&#xff0c;也可以进行通用的运算。计算着色器的计算能力非常强&#xff0c;这就使得在gpu进行通用运算后再传输回cpu&#xff0c;比直接在cpu…

G16、G24、G32、G36、G60

请输入置换次数N&#xff1a;51 请输入置换m&#xff1a;1,3,16,21,36,45,51,2,4,5,6,7,8,9,10,11,12,13,14,15,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,37 ,38,39,40,41,42,43,44,46,47,48,49,50 置换m^-1&#xff1a;1,8,2,9,10,11,12,13,14,15,16,17,18,19,…

ssm+jsp计算机毕业设计毕业论文管理系统的设计与实现m7g32(程序+LW+源码+远程部署)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行环境配置&#xff1a; Python3.7.7DjangoMysql5.7pip listHBuilderX&#xff08;Vscode也行&#xff09;VuePychram社区版。 项目技术&#xff1a; Django Vue PythonMysql 等等组成&#xff0c;…

[附源码]JSP+ssm计算机毕业设计大学生助学贷款管理系统46g32【源码、数据库、LW、部署】

项目运行 项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1…