#include "resources/shaders.h" const char* lovrShaderVertexPrefix = "" "#define VERTEX VERTEX \n" "#define MAX_BONES 48 \n" "#define MAX_DRAWS 256 \n" "#define lovrView lovrViews[lovrViewID] \n" "#define lovrProjection lovrProjections[lovrViewID] \n" "#define lovrModel lovrModels[lovrDrawID] \n" "#define lovrTransform (lovrView * lovrModel) \n" "#ifdef FLAG_uniformScale \n" "#define lovrNormalMatrix mat3(lovrModel) \n" "#else \n" "#define lovrNormalMatrix mat3(transpose(inverse(lovrModel))) \n" "#endif \n" "#define lovrPoseMatrix (" "lovrPose[lovrBones[0]] * lovrBoneWeights[0] +" "lovrPose[lovrBones[1]] * lovrBoneWeights[1] +" "lovrPose[lovrBones[2]] * lovrBoneWeights[2] +" "lovrPose[lovrBones[3]] * lovrBoneWeights[3]" ") \n" "#ifdef FLAG_animated \n" "#define lovrVertex (lovrPoseMatrix * vec4(lovrPosition, 1.)) \n" "#else \n" "#define lovrVertex vec4(lovrPosition, 1.) \n" "#endif \n" "precision highp float; \n" "precision highp int; \n" "in vec3 lovrPosition; \n" "in vec3 lovrNormal; \n" "in vec2 lovrTexCoord; \n" "in vec4 lovrVertexColor; \n" "in vec4 lovrTangent; \n" "in uvec4 lovrBones; \n" "in vec4 lovrBoneWeights; \n" "in uint lovrDrawID; \n" "out vec2 texCoord; \n" "out vec4 vertexColor; \n" "out vec4 lovrGraphicsColor; \n" "layout(std140) uniform lovrModelBlock { mat4 lovrModels[MAX_DRAWS]; }; \n" "layout(std140) uniform lovrColorBlock { vec4 lovrColors[MAX_DRAWS]; }; \n" "layout(std140) uniform lovrFrameBlock { mat4 lovrViews[2]; mat4 lovrProjections[2]; }; \n" "uniform mat3 lovrMaterialTransform; \n" "uniform float lovrPointSize; \n" "uniform mat4 lovrPose[MAX_BONES]; \n" "uniform lowp int lovrViewportCount; \n" "#if defined MULTIVIEW \n" "layout(num_views = 2) in; \n" "#define lovrViewID (int(gl_ViewID_OVR)) \n" "#define lovrInstanceID gl_InstanceID \n" "#elif defined INSTANCED_STEREO \n" "#define lovrViewID gl_ViewportIndex \n" "#define lovrInstanceID (gl_InstanceID / lovrViewportCount) \n" "#else \n" "uniform lowp int lovrViewID; \n" "#define lovrInstanceID gl_InstanceID \n" "#endif \n" "#line 0 \n"; const char* lovrShaderVertexSuffix = "" "void main() { \n" " texCoord = (lovrMaterialTransform * vec3(lovrTexCoord, 1.)).xy; \n" " vertexColor = lovrVertexColor; \n" " lovrGraphicsColor = lovrColors[lovrDrawID]; \n" "#if defined INSTANCED_STEREO \n" " gl_ViewportIndex = gl_InstanceID % lovrViewportCount; \n" "#endif \n" " gl_PointSize = lovrPointSize; \n" " gl_Position = position(lovrProjection, lovrTransform, lovrVertex); \n" "}"; const char* lovrShaderFragmentPrefix = "" "#define PIXEL PIXEL \n" "#define FRAGMENT FRAGMENT \n" "#define lovrTexCoord texCoord \n" "#define lovrVertexColor vertexColor \n" "#ifdef FLAG_highp \n" "precision highp float; \n" "precision highp int; \n" "#else \n" "precision mediump float; \n" "precision mediump int; \n" "#endif \n" "in vec2 texCoord; \n" "in vec4 vertexColor; \n" "in vec4 lovrGraphicsColor; \n" "out vec4 lovrCanvas[gl_MaxDrawBuffers]; \n" "uniform float lovrMetalness; \n" "uniform float lovrRoughness; \n" "uniform float lovrAlphaCutoff; \n" "uniform vec4 lovrDiffuseColor; \n" "uniform vec4 lovrEmissiveColor; \n" "uniform sampler2D lovrDiffuseTexture; \n" "uniform sampler2D lovrEmissiveTexture; \n" "uniform sampler2D lovrMetalnessTexture; \n" "uniform sampler2D lovrRoughnessTexture; \n" "uniform sampler2D lovrOcclusionTexture; \n" "uniform sampler2D lovrNormalTexture; \n" "uniform lowp int lovrViewportCount; \n" "#if defined MULTIVIEW \n" "#define lovrViewID gl_ViewID_OVR \n" "#elif defined INSTANCED_STEREO \n" "#define lovrViewID gl_ViewportIndex \n" "#else \n" "uniform lowp int lovrViewID; \n" "#endif \n" "#ifdef MULTIVIEW \n" "#define sampler2DMultiview sampler2DArray \n" "vec4 textureMultiview(sampler2DMultiview t, vec2 uv) { \n" " return texture(t, vec3(uv, lovrViewID)); \n" "} \n" "#else \n" "#define sampler2DMultiview sampler2D \n" "vec4 textureMultiview(sampler2DMultiview t, vec2 uv) { \n" " uv = clamp(uv, 0., 1.) * vec2(.5, 1.) + vec2(lovrViewID) * vec2(.5, 0.); \n" " return texture(t, uv); \n" "} \n" "#endif \n" "#line 0 \n"; const char* lovrShaderFragmentSuffix = "" "void main() { \n" "#if defined(MULTICANVAS) || defined(FLAG_multicanvas) \n" " colors(lovrGraphicsColor, lovrDiffuseTexture, texCoord); \n" "#else \n" " lovrCanvas[0] = color(lovrGraphicsColor, lovrDiffuseTexture, lovrTexCoord); \n" "#ifdef FLAG_alphaCutoff \n" " if (lovrCanvas[0].a < lovrAlphaCutoff) { \n" " discard; \n" " } \n" "#endif \n" #if defined(LOVR_WEBGL) " lovrCanvas[0].rgb = pow(lovrCanvas[0].rgb, vec3(.4545)); \n" #endif "#endif \n" "}"; #ifdef LOVR_GLES const char* lovrShaderComputePrefix = "" "#version 310 es \n" "#line 0 \n"; #else const char* lovrShaderComputePrefix = "" "#version 330 \n" "#extension GL_ARB_compute_shader : enable \n" "#extension GL_ARB_shader_storage_buffer_object : enable \n" "#extension GL_ARB_shader_image_load_store : enable \n" "#line 0 \n"; #endif const char* lovrShaderComputeSuffix = "" "void main() { \n" " compute(); \n" "}"; const char* lovrUnlitVertexShader = "" "vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n" " return lovrProjection * lovrTransform * lovrVertex; \n" "}"; const char* lovrUnlitFragmentShader = "" "vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n" " return lovrGraphicsColor * lovrVertexColor * lovrDiffuseColor * texture(lovrDiffuseTexture, lovrTexCoord); \n" "}"; const char* lovrStandardVertexShader = "" "out vec3 vVertexPositionWorld; \n" "out vec3 vCameraPositionWorld; \n" "#ifdef FLAG_normalMap \n" "out mat3 vTangentMatrix; \n" "#else \n" "out vec3 vNormal; \n" "#endif \n" "vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n" " vVertexPositionWorld = vec3(lovrModel * lovrVertex); \n" " vCameraPositionWorld = -lovrView[3].xyz * mat3(lovrView); \n" "#ifdef FLAG_normalMap \n" " vec3 normal = normalize(lovrNormalMatrix * lovrNormal); \n" " vec3 tangent = normalize(lovrNormalMatrix * lovrTangent.xyz); \n" " vec3 bitangent = cross(normal, tangent) * lovrTangent.w; \n" " vTangentMatrix = mat3(tangent, bitangent, normal); \n" "#else \n" " vNormal = normalize(lovrNormalMatrix * lovrNormal); \n" "#endif \n" " return lovrProjection * lovrTransform * lovrVertex; \n" "}"; const char* lovrStandardFragmentShader = "" "#define PI 3.14159265358979 \n" "#if defined(GL_ES) && !defined(FLAG_highp) \n" "#define EPS 1e-4 \n" "#else \n" "#define EPS 1e-8 \n" "#endif \n" "in vec3 vVertexPositionWorld; \n" "in vec3 vCameraPositionWorld; \n" "#ifdef FLAG_normalMap \n" "in mat3 vTangentMatrix; \n" "#else \n" "in vec3 vNormal; \n" "#endif \n" "uniform vec3 lovrLightDirection; \n" "uniform vec4 lovrLightColor; \n" "uniform samplerCube lovrEnvironmentMap; \n" "uniform vec3 lovrSphericalHarmonics[9]; \n" "uniform float lovrExposure; \n" "float D_GGX(float NoH, float roughness); \n" "float G_SmithGGXCorrelated(float NoV, float NoL, float roughness); \n" "vec3 F_Schlick(vec3 F0, float VoH); \n" "vec3 E_SphericalHarmonics(vec3 sh[9], vec3 n); \n" "vec2 prefilteredBRDF(float NoV, float roughness); \n" "vec3 tonemap_ACES(vec3 color); \n" "vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n" " vec3 result = vec3(0.); \n" // Parameters " vec3 baseColor = texture(lovrDiffuseTexture, lovrTexCoord).rgb * lovrDiffuseColor.rgb; \n" " float metalness = texture(lovrMetalnessTexture, lovrTexCoord).b * lovrMetalness; \n" " float roughness = max(texture(lovrRoughnessTexture, lovrTexCoord).g * lovrRoughness, .05); \n" "#ifdef FLAG_normalMap \n" " vec3 N = normalize(vTangentMatrix * (texture(lovrNormalTexture, lovrTexCoord).rgb * 2. - 1.)); \n" "#else \n" " vec3 N = normalize(vNormal); \n" "#endif \n" " vec3 V = normalize(vCameraPositionWorld - vVertexPositionWorld); \n" " vec3 L = normalize(-lovrLightDirection); \n" " vec3 H = normalize(V + L); \n" " vec3 R = normalize(reflect(-V, N)); \n" " float NoV = abs(dot(N, V)) + EPS; \n" " float NoL = clamp(dot(N, L), 0., 1.); \n" " float NoH = clamp(dot(N, H), 0., 1.); \n" " float VoH = clamp(dot(V, H), 0., 1.); \n" // Direct lighting " vec3 F0 = mix(vec3(.04), baseColor, metalness); \n" " float D = D_GGX(NoH, roughness); \n" " float G = G_SmithGGXCorrelated(NoV, NoL, roughness); \n" " vec3 F = F_Schlick(F0, VoH); \n" " vec3 specularDirect = vec3(D * G * F); \n" " vec3 diffuseDirect = (vec3(1.) - F) * (1. - metalness) * baseColor; \n" " result += (diffuseDirect / PI + specularDirect) * NoL * lovrLightColor.rgb * lovrLightColor.a; \n" // Indirect lighting "#ifdef FLAG_indirectLighting \n" " vec2 lookup = prefilteredBRDF(NoV, roughness); \n" " float mipmapCount = log2(float(textureSize(lovrEnvironmentMap, 0).x)); \n" " vec3 specularIndirect = (F0 * lookup.r + lookup.g) * textureLod(lovrEnvironmentMap, R, roughness * mipmapCount).rgb; \n" " vec3 diffuseIndirect = diffuseDirect * E_SphericalHarmonics(lovrSphericalHarmonics, N); \n" "#ifdef FLAG_occlusion \n" // Occlusion only affects indirect diffuse light " diffuseIndirect *= texture(lovrOcclusionTexture, lovrTexCoord).r; \n" "#endif \n" " result += diffuseIndirect + specularIndirect; \n" "#endif \n" // Emissive "#ifdef FLAG_emissive \n" // Currently emissive texture and color have to be used together " result += texture(lovrEmissiveTexture, lovrTexCoord).rgb * lovrEmissiveColor.rgb; \n" "#endif \n" // Tonemap "#ifndef FLAG_skipTonemap \n" " result = tonemap_ACES(result * lovrExposure); \n" "#endif \n" " return lovrGraphicsColor * vec4(result, 1.); \n" "}" // Helpers "float D_GGX(float NoH, float roughness) { \n" " float alpha = roughness * roughness; \n" " float alpha2 = alpha * alpha; \n" " float denom = (NoH * NoH) * (alpha2 - 1.) + 1.; \n" " return alpha2 / max(PI * denom * denom, EPS); \n" "} \n" "float G_SmithGGXCorrelated(float NoV, float NoL, float roughness) { \n" " float alpha = roughness * roughness; \n" " float alpha2 = alpha * alpha; \n" " float GGXV = NoL * sqrt(alpha2 + (1. - alpha2) * (NoV * NoV)); \n" " float GGXL = NoV * sqrt(alpha2 + (1. - alpha2) * (NoL * NoL)); \n" " return .5 / max(GGXV + GGXL, EPS); \n" "} \n" "vec3 F_Schlick(vec3 F0, float VoH) { \n" " return F0 + (vec3(1.) - F0) * pow(1. - VoH, 5.); \n" "} \n" "vec3 E_SphericalHarmonics(vec3 sh[9], vec3 n) { \n" " n = -n; \n" " return max(" "sh[0] + " "sh[1] * n.y + " "sh[2] * n.z + " "sh[3] * n.x + " "sh[4] * n.y * n.x + " "sh[5] * n.y * n.z + " "sh[6] * (3. * n.z * n.z - 1.) + " "sh[7] * n.z * n.x + " "sh[8] * (n.x * n.x - n.y * n.y)" ", 0.); \n" "} \n" // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile "vec2 prefilteredBRDF(float NoV, float roughness) { \n" " vec4 c0 = vec4(-1., -.0275, -.572, .022); \n" " vec4 c1 = vec4(1., .0425, 1.04, -.04); \n" " vec4 r = roughness * c0 + c1; \n" " float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; \n" " return vec2(-1.04, 1.04) * a004 + r.zw; \n" "} \n" "vec3 tonemap_ACES(vec3 x) { \n" " float a = 2.51; \n" " float b = 0.03; \n" " float c = 2.43; \n" " float d = 0.59; \n" " float e = 0.14; \n" " return (x * (a * x + b)) / (x * (c * x + d) + e); \n" "}"; const char* lovrCubeVertexShader = "" "out vec3 texturePosition[2]; \n" "vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n" " texturePosition[lovrViewID] = inverse(mat3(lovrTransform)) * (inverse(lovrProjection) * lovrVertex).xyz; \n" " return lovrVertex; \n" "}"; const char* lovrCubeFragmentShader = "" "in vec3 texturePosition[2]; \n" "uniform samplerCube lovrSkyboxTexture; \n" "vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n" " return lovrGraphicsColor * texture(lovrSkyboxTexture, texturePosition[lovrViewID] * vec3(-1, 1, 1)); \n" "}"; const char* lovrPanoFragmentShader = "" "in vec3 texturePosition[2]; \n" "#define PI 3.141592653589 \n" "vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n" " vec3 direction = texturePosition[lovrViewID]; \n" " float theta = acos(-direction.y / length(direction)); \n" " float phi = atan(direction.x, -direction.z); \n" " vec2 cubeUv = vec2(.5 + phi / (2. * PI), theta / PI); \n" " return lovrGraphicsColor * texture(lovrDiffuseTexture, cubeUv); \n" "}"; const char* lovrFontFragmentShader = "" "uniform vec2 lovrSdfRange; \n" "float screenPxRange() { \n" " vec2 screenTexSize = vec2(1.) / fwidth(lovrTexCoord); \n" " return max(.5 * dot(lovrSdfRange, screenTexSize), 1.); \n" "} \n" "float median(float r, float g, float b) { \n" " return max(min(r, g), min(max(r, g), b)); \n" "} \n" "vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n" " vec3 msd = texture(lovrDiffuseTexture, lovrTexCoord).rgb; \n" " float sd = median(msd.r, msd.g, msd.b); \n" " float screenPxDistance = screenPxRange() * (sd - .5); \n" " float alpha = clamp(screenPxDistance + .5, 0., 1.); \n" " if (alpha <= 0.0) discard; \n" " return vec4(lovrGraphicsColor.rgb, lovrGraphicsColor.a * alpha); \n" "}"; const char* lovrFillVertexShader = "" "vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n" " return lovrVertex; \n" "}"; const char* lovrShaderScalarUniforms[] = { "lovrMetalness", "lovrRoughness", "lovrAlphaCutoff" }; const char* lovrShaderColorUniforms[] = { "lovrDiffuseColor", "lovrEmissiveColor" }; const char* lovrShaderTextureUniforms[] = { "lovrDiffuseTexture", "lovrEmissiveTexture", "lovrMetalnessTexture", "lovrRoughnessTexture", "lovrOcclusionTexture", "lovrNormalTexture" }; const char* lovrShaderAttributeNames[] = { "lovrPosition", "lovrNormal", "lovrTexCoord", "lovrVertexColor", "lovrTangent", "lovrBones", "lovrBoneWeights" };