1$input v_view, v_normal
2
3/*
4 * Copyright 2014-2016 Dario Manesku. All rights reserved.
5 * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
6 */
7
8#include "../common/common.sh"
9#include "uniforms.sh"
10
11SAMPLERCUBE(s_texCube, 0);
12SAMPLERCUBE(s_texCubeIrr, 1);
13
14vec3 calcFresnel(vec3 _cspec, float _dot, float _strength)
15{
16	return _cspec + (1.0 - _cspec)*pow(1.0 - _dot, 5.0) * _strength;
17}
18
19vec3 calcLambert(vec3 _cdiff, float _ndotl)
20{
21	return _cdiff*_ndotl;
22}
23
24vec3 calcBlinn(vec3 _cspec, float _ndoth, float _ndotl, float _specPwr)
25{
26	float norm = (_specPwr+8.0)*0.125;
27	float brdf = pow(_ndoth, _specPwr)*_ndotl*norm;
28	return _cspec*brdf;
29}
30
31float specPwr(float _gloss)
32{
33	return exp2(10.0*_gloss+2.0);
34}
35
36void main()
37{
38	// Light.
39	vec3 ld     = normalize(u_lightDir);
40	vec3 clight = u_lightCol;
41
42	// Input.
43	vec3 nn = normalize(v_normal);
44	vec3 vv = normalize(v_view);
45	vec3 hh = normalize(vv + ld);
46
47	float ndotv = clamp(dot(nn, vv), 0.0, 1.0);
48	float ndotl = clamp(dot(nn, ld), 0.0, 1.0);
49	float ndoth = clamp(dot(nn, hh), 0.0, 1.0);
50	float hdotv = clamp(dot(hh, vv), 0.0, 1.0);
51
52	// Material params.
53	vec3  inAlbedo       = u_rgbDiff.xyz;
54	float inReflectivity = u_reflectivity;
55	float inGloss        = u_glossiness;
56
57	// Reflection.
58	vec3 refl;
59	if (0.0 == u_metalOrSpec) // Metalness workflow.
60	{
61		refl = mix(vec3_splat(0.04), inAlbedo, inReflectivity);
62	}
63	else // Specular workflow.
64	{
65		refl = u_rgbSpec.xyz * vec3_splat(inReflectivity);
66	}
67	vec3 albedo = inAlbedo * (1.0 - inReflectivity);
68	vec3 dirFresnel = calcFresnel(refl, hdotv, inGloss);
69	vec3 envFresnel = calcFresnel(refl, ndotv, inGloss);
70
71	vec3 lambert = u_doDiffuse  * calcLambert(albedo * (1.0 - dirFresnel), ndotl);
72	vec3 blinn   = u_doSpecular * calcBlinn(dirFresnel, ndoth, ndotl, specPwr(inGloss));
73	vec3 direct  = (lambert + blinn)*clight;
74
75	// Note: Environment textures are filtered with cmft: https://github.com/dariomanesku/cmft
76	// Params used:
77	// --excludeBase true //!< First level mip is not filtered.
78	// --mipCount 7       //!< 7 mip levels are used in total, [256x256 .. 4x4]. Lower res mip maps should be avoided.
79	// --glossScale 10    //!< Spec power scale. See: specPwr().
80	// --glossBias 2      //!< Spec power bias. See: specPwr().
81	// --edgeFixup warp   //!< This must be used on DirectX9. When fileted with 'warp', fixCubeLookup() should be used.
82	float mip = 1.0 + 5.0*(1.0 - inGloss); // Use mip levels [1..6] for radiance.
83
84	mat4 mtx;
85	mtx[0] = u_mtx0;
86	mtx[1] = u_mtx1;
87	mtx[2] = u_mtx2;
88	mtx[3] = u_mtx3;
89	vec3 vr = 2.0*ndotv*nn - vv; // Same as: -reflect(vv, nn);
90	vec3 cubeR = normalize(instMul(mtx, vec4(vr, 0.0)).xyz);
91	vec3 cubeN = normalize(instMul(mtx, vec4(nn, 0.0)).xyz);
92	cubeR = fixCubeLookup(cubeR, mip, 256.0);
93
94	vec3 radiance    = toLinear(textureCubeLod(s_texCube, cubeR, mip).xyz);
95	vec3 irradiance  = toLinear(textureCube(s_texCubeIrr, cubeN).xyz);
96	vec3 envDiffuse  = albedo     * irradiance * u_doDiffuseIbl;
97	vec3 envSpecular = envFresnel * radiance   * u_doSpecularIbl;
98	vec3 indirect    = envDiffuse + envSpecular;
99
100	// Color.
101	vec3 color = direct + indirect;
102	color = color * exp2(u_exposure);
103	gl_FragColor.xyz = toFilmic(color);
104	gl_FragColor.w = 1.0;
105}
106