lovr/src/resources/shaders.c

403 lines
13 KiB
C

#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"
};