shaderlib wip
parent
d835b83aec
commit
4e346fdd9d
|
@ -37,6 +37,7 @@ int main() {
|
||||||
texture_t t2 = texture("matcaps/material3", 0);
|
texture_t t2 = texture("matcaps/material3", 0);
|
||||||
// load model
|
// load model
|
||||||
model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
|
model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
|
||||||
|
model_t m5 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
|
||||||
model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
|
model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
|
||||||
model_t m3 = model("damagedhelmet.gltf", MODEL_NO_ANIMATIONS|MODEL_PBR);
|
model_t m3 = model("damagedhelmet.gltf", MODEL_NO_ANIMATIONS|MODEL_PBR);
|
||||||
// model_t m3 = model("Scutum_low.fbx", MODEL_NO_ANIMATIONS|MODEL_PBR);
|
// model_t m3 = model("Scutum_low.fbx", MODEL_NO_ANIMATIONS|MODEL_PBR);
|
||||||
|
@ -72,7 +73,7 @@ int main() {
|
||||||
|
|
||||||
// spawn object3 (video)
|
// spawn object3 (video)
|
||||||
object_t* obj3 = scene_spawn();
|
object_t* obj3 = scene_spawn();
|
||||||
object_model(obj3, m1);
|
object_model(obj3, m5);
|
||||||
object_diffuse(obj3, video_textures(v)[0]);
|
object_diffuse(obj3, video_textures(v)[0]);
|
||||||
object_scale(obj3, vec3(3,3,3));
|
object_scale(obj3, vec3(3,3,3));
|
||||||
object_move(obj3, vec3(-10+5*1,0,-10));
|
object_move(obj3, vec3(-10+5*1,0,-10));
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
#ifdef SHADING_PBR
|
||||||
|
uniform vec2 resolution; /// set:640,480 // debug options below use this (USE_MAP_DEBUGGING, USE_AMBIENT_DEBUGGING)
|
||||||
|
|
||||||
|
#define USE_BRUTEFORCE_IRRADIANCE false // Samples irradiance from tex_skysphere when enabled.
|
||||||
|
#define USE_WRAPAROUND_SPECULAR true // Makes silhouettes more reflective to avoid black pixels.
|
||||||
|
#define USE_SPECULAR_AO_ATTENUATION true // Dampens IBL specular ambient with AO if enabled.
|
||||||
|
#define USE_NORMAL_VARIATION_TO_ROUGHNESS true // Increases roughness if normal map has variation and was minified.
|
||||||
|
#define USE_MAP_DEBUGGING false // Shows all ColorMaps as horizontal bars
|
||||||
|
#define USE_AMBIENT_DEBUGGING false // Splits the screen in two and shows image-based specular (left), full shading (middle), diffuse shading (right).
|
||||||
|
#define BOOST_LIGHTING 2.00f // Multiplies analytic light's color with this constant because otherwise they look really pathetic.
|
||||||
|
#define BOOST_SPECULAR 1.50f
|
||||||
|
#define BOOST_NOISE 2.50f
|
||||||
|
|
||||||
|
struct ColorMap
|
||||||
|
{
|
||||||
|
bool has_tex;
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform ColorMap map_albedo; uniform sampler2D map_albedo_tex;
|
||||||
|
uniform ColorMap map_diffuse; uniform sampler2D map_diffuse_tex;
|
||||||
|
uniform ColorMap map_specular; uniform sampler2D map_specular_tex; // not used
|
||||||
|
uniform ColorMap map_normals; uniform sampler2D map_normals_tex;
|
||||||
|
uniform ColorMap map_roughness; uniform sampler2D map_roughness_tex;
|
||||||
|
uniform ColorMap map_metallic; uniform sampler2D map_metallic_tex;
|
||||||
|
uniform ColorMap map_ao; uniform sampler2D map_ao_tex;
|
||||||
|
uniform ColorMap map_ambient; uniform sampler2D map_ambient_tex;
|
||||||
|
uniform ColorMap map_emissive; uniform sampler2D map_emissive_tex;
|
||||||
|
|
||||||
|
#define sample_colormap(ColorMap_, uv_) \
|
||||||
|
(ColorMap_.has_tex ? texture( ColorMap_##_tex, uv_ ) : ColorMap_.color)
|
||||||
|
|
||||||
|
uniform float skysphere_rotation; /// set:0
|
||||||
|
uniform float skysphere_mip_count;
|
||||||
|
uniform float exposure; /// set:1
|
||||||
|
uniform uint frame_count;
|
||||||
|
uniform float specular_shininess;
|
||||||
|
|
||||||
|
uniform sampler2D tex_skysphere;
|
||||||
|
uniform sampler2D tex_skyenv;
|
||||||
|
uniform sampler2D tex_brdf_lut;
|
||||||
|
|
||||||
|
uniform bool has_tex_skysphere;
|
||||||
|
uniform bool has_tex_skyenv;
|
||||||
|
|
||||||
|
const float PI = 3.1415926536;
|
||||||
|
|
||||||
|
// MurMurHash 3 finalizer. Implementation is in public domain.
|
||||||
|
uint hash( uint h )
|
||||||
|
{
|
||||||
|
h ^= h >> 16;
|
||||||
|
h *= 0x85ebca6bU;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 0xc2b2ae35U;
|
||||||
|
h ^= h >> 16;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random function using the idea of StackOverflow user "Spatial" https://stackoverflow.com/a/17479300
|
||||||
|
// Creates random 23 bits and puts them into the fraction bits of an 32-bit float.
|
||||||
|
float random( uvec3 h )
|
||||||
|
{
|
||||||
|
uint m = hash(h.x ^ hash( h.y ) ^ hash( h.z ));
|
||||||
|
return uintBitsToFloat( ( m & 0x007FFFFFu ) | 0x3f800000u ) - 1.;
|
||||||
|
}
|
||||||
|
|
||||||
|
float random( vec3 v )
|
||||||
|
{
|
||||||
|
return random(floatBitsToUint( v ));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fresnel_schlick( vec3 H, vec3 V, vec3 F0 )
|
||||||
|
{
|
||||||
|
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
||||||
|
return F0 + ( vec3( 1.0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Fresnel term that dampens rough specular reflections.
|
||||||
|
// https://seblagarde.wordpress.com/2011/08/17/hello-world/
|
||||||
|
vec3 fresnel_schlick_roughness( vec3 H, vec3 V, vec3 F0, float roughness )
|
||||||
|
{
|
||||||
|
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
||||||
|
return F0 + ( max( vec3( 1.0 - roughness ), F0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
float distribution_ggx( vec3 N, vec3 H, float roughness )
|
||||||
|
{
|
||||||
|
float a = roughness * roughness;
|
||||||
|
float a2 = a * a;
|
||||||
|
float NdotH = max( 0., dot( N, H ) );
|
||||||
|
float factor = NdotH * NdotH * ( a2 - 1. ) + 1.;
|
||||||
|
|
||||||
|
return a2 / ( PI * factor * factor );
|
||||||
|
}
|
||||||
|
|
||||||
|
float geometry_schlick_ggx( vec3 N, vec3 V, float k )
|
||||||
|
{
|
||||||
|
float NdotV = max( 0., dot( N, V ) );
|
||||||
|
return NdotV / (NdotV * ( 1. - k ) + k );
|
||||||
|
}
|
||||||
|
|
||||||
|
float geometry_smith( vec3 N, vec3 V, vec3 L, float roughness )
|
||||||
|
{
|
||||||
|
#if 1 // original
|
||||||
|
float r = roughness + 1.;
|
||||||
|
float k = (r * r) / 8.;
|
||||||
|
#elif 0 // vries
|
||||||
|
float a = roughness;
|
||||||
|
float k = (a * a) / 2.0;
|
||||||
|
#elif 0 // vries improved?
|
||||||
|
float a = roughness * roughness;
|
||||||
|
float k = a / 2.0;
|
||||||
|
#endif
|
||||||
|
return geometry_schlick_ggx( N, V, k ) * geometry_schlick_ggx( N, L, k );
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 sphere_to_polar( vec3 normal ) {
|
||||||
|
normal = normalize( normal );
|
||||||
|
return vec2( 1-atan( normal.z, normal.x ) / PI + 0.5 , acos( normal.y ) / PI );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our vertically GL_CLAMPed textures seem to blend towards black when sampling the half-pixel edge.
|
||||||
|
// Not sure if it has a border, or this if is a driver bug, but can repro on multiple nvidia cards.
|
||||||
|
// Knowing the texture height we can limit sampling to the centers of the top and bottom pixel rows.
|
||||||
|
vec2 sphere_to_polar_clamp_y( vec3 normal, float texture_height )
|
||||||
|
{
|
||||||
|
normal = normalize( normal );
|
||||||
|
return vec2( ( atan( normal.z, normal.x ) + skysphere_rotation ) / PI / 2.0 + 0.5, clamp(acos( normal.y ) / PI, 0.5 / texture_height, 1.0 - 0.5 / texture_height) );
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 sample_sky( vec3 normal )
|
||||||
|
{
|
||||||
|
vec2 polar = sphere_to_polar( normal );
|
||||||
|
return texture( tex_skysphere, polar ).rgb * exposure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes samples around the hemisphere, converts them to radiances via weighting and
|
||||||
|
// returns a normalized sum.
|
||||||
|
vec3 sample_irradiance_slow( vec3 normal, vec3 vertex_tangent )
|
||||||
|
{
|
||||||
|
float delta = 0.10;
|
||||||
|
|
||||||
|
vec3 up = abs( normal.y ) < 0.999 ? vec3( 0., 1., 0. ) : vec3( 0., 0., 1. );
|
||||||
|
vec3 tangent_x = normalize( cross( up, normal ) );
|
||||||
|
vec3 tangent_y = cross( normal, tangent_x );
|
||||||
|
|
||||||
|
int numIrradianceSamples = 0;
|
||||||
|
|
||||||
|
vec3 irradiance = vec3(0.);
|
||||||
|
|
||||||
|
for ( float phi = 0.; phi < 2. * PI ; phi += delta )
|
||||||
|
{
|
||||||
|
for ( float theta = 0.; theta < 0.5 * PI; theta += delta )
|
||||||
|
{
|
||||||
|
vec3 tangent_space = vec3(
|
||||||
|
sin( theta ) * cos( phi ),
|
||||||
|
sin( theta ) * sin( phi ),
|
||||||
|
cos( theta ) );
|
||||||
|
|
||||||
|
vec3 world_space = tangent_space.x * tangent_x + tangent_space.y + tangent_y + tangent_space.z * normal;
|
||||||
|
|
||||||
|
vec3 color = sample_sky( world_space );
|
||||||
|
irradiance += color * cos( theta ) * sin( theta );
|
||||||
|
numIrradianceSamples++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irradiance = PI * irradiance / float( numIrradianceSamples );
|
||||||
|
return irradiance;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 sample_irradiance_fast( vec3 normal, vec3 vertex_tangent )
|
||||||
|
{
|
||||||
|
// Sample the irradiance map if it exists, otherwise fall back to blurred reflection map.
|
||||||
|
if ( has_tex_skyenv )
|
||||||
|
{
|
||||||
|
vec2 polar = sphere_to_polar( normal );
|
||||||
|
return textureLod( tex_skyenv, polar, 0.0 ).rgb * exposure;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec2 polar = sphere_to_polar( normal );
|
||||||
|
return textureLod( tex_skysphere, polar, 0.80 * skysphere_mip_count ).rgb * exposure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec3 specular_ibl( vec3 V, vec3 N, float roughness, vec3 fresnel )
|
||||||
|
{
|
||||||
|
// What we'd like to do here is take a LOT of skybox samples around the reflection
|
||||||
|
// vector R according to the BRDF lobe.
|
||||||
|
//
|
||||||
|
// Unfortunately it's not possible in real time so we use the following UE4 style approximations:
|
||||||
|
// 1. Integrate incoming light and BRDF separately ("split sum approximation")
|
||||||
|
// 2. Assume V = R = N so that we can just blur the skybox and sample that.
|
||||||
|
// 3. Bake the BRDF integral into a lookup texture so that it can be computed in constant time.
|
||||||
|
//
|
||||||
|
// Here we also simplify approximation #2 by using bilinear mipmaps with a magic formula instead
|
||||||
|
// of properly convolving it with a GGX lobe.
|
||||||
|
//
|
||||||
|
// For details, see Brian Karis, "Real Shading in Unreal Engine 4", 2013.
|
||||||
|
|
||||||
|
vec3 R = 2. * dot( V, N ) * N - V;
|
||||||
|
|
||||||
|
vec2 polar = sphere_to_polar( R );
|
||||||
|
|
||||||
|
// Map roughness from range [0, 1] into a mip LOD [0, skysphere_mip_count].
|
||||||
|
// The magic numbers were chosen empirically.
|
||||||
|
|
||||||
|
float mip = 0.9 * skysphere_mip_count * pow(roughness, 0.25 * BOOST_SPECULAR);
|
||||||
|
|
||||||
|
vec3 prefiltered = textureLod( tex_skysphere, polar, mip ).rgb * exposure;
|
||||||
|
|
||||||
|
float NdotV = dot( N, V );
|
||||||
|
|
||||||
|
// dot( N, V ) seems to produce negative values so we can try to stretch it a bit behind the silhouette
|
||||||
|
// to avoid black pixels.
|
||||||
|
if (USE_WRAPAROUND_SPECULAR)
|
||||||
|
{
|
||||||
|
NdotV = NdotV * 0.9 + 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NdotV = min(0.99, max(0.01, NdotV));
|
||||||
|
|
||||||
|
// A precomputed lookup table contains a scale and a bias term for specular intensity (called "fresnel" here).
|
||||||
|
// See equation (8) in Karis' course notes mentioned above.
|
||||||
|
vec2 envBRDF = texture( tex_brdf_lut, vec2(NdotV, 1.0-roughness) ).xy; // (NdotV,1-roughtness) for green top-left (NdotV,roughness) for green bottom-left
|
||||||
|
vec3 specular = prefiltered * (fresnel * envBRDF.x + vec3(envBRDF.y));
|
||||||
|
|
||||||
|
return specular;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,43 @@
|
||||||
|
uniform mat4 model, view;
|
||||||
|
uniform sampler2D u_texture2d;
|
||||||
|
uniform vec3 u_coefficients_sh[9];
|
||||||
|
uniform bool u_textured; /// set:1
|
||||||
|
uniform bool u_lit; /// set:0
|
||||||
|
uniform bool u_matcaps; /// set:0
|
||||||
|
uniform vec4 u_diffuse; /// set:1,1,1,1
|
||||||
|
|
||||||
|
// lightmapping
|
||||||
|
uniform sampler2D u_lightmap;
|
||||||
|
uniform bool u_texlit;
|
||||||
|
uniform bool u_texmod; /// set:1
|
||||||
|
uniform float u_litboost; /// set:1
|
||||||
|
|
||||||
|
in vec3 v_position;
|
||||||
|
in vec3 v_position_ws;
|
||||||
|
#ifdef RIM
|
||||||
|
uniform mat4 M; // RIM
|
||||||
|
uniform vec3 u_rimcolor; /// set:0.05,0.05,0.05
|
||||||
|
uniform vec3 u_rimrange; /// set:0.11,0.98,0.5
|
||||||
|
uniform vec3 u_rimpivot; /// set:0,0,0
|
||||||
|
uniform bool u_rimambient; /// set:1
|
||||||
|
#endif
|
||||||
|
in vec3 v_normal, v_normal_ws;
|
||||||
|
in vec2 v_texcoord, v_texcoord2;
|
||||||
|
in vec4 v_color;
|
||||||
|
in vec3 v_tangent;
|
||||||
|
in vec3 v_binormal;
|
||||||
|
in vec3 v_to_camera;
|
||||||
|
in vec3 v_vertcolor;
|
||||||
|
out vec4 fragcolor;
|
||||||
|
|
||||||
|
|
||||||
|
#include "shadowmap.glsl"
|
||||||
|
in vec4 vpeye;
|
||||||
|
in vec4 vneye;
|
||||||
|
in vec4 sc;
|
||||||
|
vec4 shadowing() {
|
||||||
|
return shadowmap(vpeye, vneye, v_texcoord, sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
uniform vec3 u_cam_pos;
|
||||||
|
uniform vec3 u_cam_dir;
|
|
@ -0,0 +1,148 @@
|
||||||
|
#ifndef MAX_BONES
|
||||||
|
#define MAX_BONES 110
|
||||||
|
#endif
|
||||||
|
uniform mat3x4 vsBoneMatrix[MAX_BONES];
|
||||||
|
uniform bool SKINNED; /// set:0
|
||||||
|
uniform mat4 M; // RIM
|
||||||
|
uniform mat4 VP;
|
||||||
|
uniform mat4 P;
|
||||||
|
uniform vec3 u_cam_dir;
|
||||||
|
uniform int u_billboard;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Fetch blend channels from all attached blend deformers.
|
||||||
|
for (size_t di = 0; di < mesh->blend_deformers.count; di++) {
|
||||||
|
ufbx_blend_deformer *deformer = mesh->blend_deformers.data[di];
|
||||||
|
for (size_t ci = 0; ci < deformer->channels.count; ci++) {
|
||||||
|
ufbx_blend_channel *chan = deformer->channels.data[ci];
|
||||||
|
if (chan->keyframes.count == 0) continue;
|
||||||
|
if (num_blend_shapes < MAX_BLEND_SHAPES) {
|
||||||
|
blend_channels[num_blend_shapes] = chan;
|
||||||
|
vmesh->blend_channel_indices[num_blend_shapes] = (int32_t)chan->typed_id;
|
||||||
|
num_blend_shapes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_blend_shapes > 0) {
|
||||||
|
vmesh->blend_shape_image = pack_blend_channels_to_image(mesh, blend_channels, num_blend_shapes);
|
||||||
|
vmesh->num_blend_shapes = num_blend_shapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ubo.f_num_blend_shapes = (float)mesh->num_blend_shapes;
|
||||||
|
for (size_t i = 0; i < mesh->num_blend_shapes; i++) {
|
||||||
|
ubo.blend_weights[i] = view->scene.blend_channels[mesh->blend_channel_indices[i]].weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sg_image blend_shapes = mesh->num_blend_shapes > 0 ? mesh->blend_shape_image : view->empty_blend_shape_image;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// for blendshapes
|
||||||
|
#ifndef MAX_BLENDSHAPES
|
||||||
|
#define MAX_BLENDSHAPES 16
|
||||||
|
#endif
|
||||||
|
uniform vec4 blend_weights[MAX_BLENDSHAPES]; // @todo: implement me
|
||||||
|
uniform float f_num_blend_shapes; // @todo: implement me
|
||||||
|
uniform MEDIUMP sampler2DArray blend_shapes; // @todo: implement me
|
||||||
|
|
||||||
|
in vec3 att_position; // @todo: reorder ass2iqe to emit p3 n3 u2 t3 b3 c4B i4 w4 instead
|
||||||
|
in vec2 att_texcoord;
|
||||||
|
in vec3 att_normal;
|
||||||
|
in vec4 att_tangent; // vec3 + bi sign
|
||||||
|
in mat4 att_instanced_matrix; // for instanced rendering
|
||||||
|
in vec4 att_indexes; // @fixme: gles might use ivec4 instead?
|
||||||
|
in vec4 att_weights; // @todo: downgrade from float to byte
|
||||||
|
in float att_vertexindex; // for blendshapes
|
||||||
|
in vec4 att_color;
|
||||||
|
in vec3 att_bitangent; // @todo: remove? also, ass2iqe might output this
|
||||||
|
in vec2 att_texcoord2;
|
||||||
|
out vec4 v_color;
|
||||||
|
out vec3 v_position, v_position_ws;
|
||||||
|
out vec3 v_normal, v_normal_ws;
|
||||||
|
out vec2 v_texcoord, v_texcoord2;
|
||||||
|
out vec3 v_tangent;
|
||||||
|
out vec3 v_binormal;
|
||||||
|
out vec3 v_viewpos;
|
||||||
|
out vec3 v_to_camera;
|
||||||
|
out vec3 v_vertcolor;
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
uniform mat4 model, view, inv_view;
|
||||||
|
uniform mat4 cameraToShadowProjector;
|
||||||
|
out vec4 vneye;
|
||||||
|
out vec4 vpeye;
|
||||||
|
out vec4 sc;
|
||||||
|
void do_shadow() {
|
||||||
|
vneye = view * model * vec4(att_normal, 0.0f);
|
||||||
|
vpeye = view * model * vec4(att_position, 1.0);
|
||||||
|
sc = cameraToShadowProjector * model * vec4(att_position, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// blendshapes
|
||||||
|
vec3 evaluate_blend_shape(int vertex_index) {
|
||||||
|
ivec2 coord = ivec2(vertex_index & (2048 - 1), vertex_index >> 11);
|
||||||
|
int num_blend_shapes = int(f_num_blend_shapes);
|
||||||
|
vec3 offset = vec3(0.0);
|
||||||
|
for (int i = 0; i < num_blend_shapes; i++) {
|
||||||
|
vec4 packedw = blend_weights[i >> 2];
|
||||||
|
float weight = packedw[i & 3];
|
||||||
|
offset += weight * texelFetch(blend_shapes, ivec3(coord, i), 0).xyz;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 get_object_pos() {
|
||||||
|
vec3 objPos;
|
||||||
|
if(!SKINNED) {
|
||||||
|
objPos = att_position;
|
||||||
|
v_normal = att_normal;
|
||||||
|
} else {
|
||||||
|
mat3x4 m = vsBoneMatrix[int(att_indexes.x)] * att_weights.x;
|
||||||
|
m += vsBoneMatrix[int(att_indexes.y)] * att_weights.y;
|
||||||
|
m += vsBoneMatrix[int(att_indexes.z)] * att_weights.z;
|
||||||
|
m += vsBoneMatrix[int(att_indexes.w)] * att_weights.w;
|
||||||
|
objPos = vec4(att_position, 1.0) * m;
|
||||||
|
|
||||||
|
// blendshapes
|
||||||
|
// objPos += evaluate_blend_shape(int(att_vertexindex));
|
||||||
|
|
||||||
|
v_normal = vec4(att_normal, 0.0) * m;
|
||||||
|
//@todo: tangents
|
||||||
|
}
|
||||||
|
|
||||||
|
return objPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_billboards(mat4 modelView, mat4 l_model) {
|
||||||
|
if(u_billboard > 0) {
|
||||||
|
vec3 cameraPosition = -transpose(mat3(view)) * view[3].xyz;
|
||||||
|
vec3 lookDir = normalize(cameraPosition - v_position_ws);
|
||||||
|
|
||||||
|
vec3 up = vec3(modelView[0][1], modelView[1][1], modelView[2][1]);
|
||||||
|
vec3 right = normalize(cross(up, lookDir));
|
||||||
|
up = cross(lookDir, right);
|
||||||
|
|
||||||
|
vec3 scale;
|
||||||
|
scale.x = length(vec3(l_model[0]));
|
||||||
|
scale.y = length(vec3(l_model[1]));
|
||||||
|
scale.z = length(vec3(l_model[2]));
|
||||||
|
// scale.x *= sign(l_model[0][0]);
|
||||||
|
// scale.y *= sign(l_model[1][1]);
|
||||||
|
// scale.z *= sign(l_model[2][2]);
|
||||||
|
|
||||||
|
mat4 billboardRotation = mat4(
|
||||||
|
vec4(right * scale.x, 0.0),
|
||||||
|
vec4(-up * scale.y, 0.0),
|
||||||
|
vec4(-lookDir * scale.z, 0.0),
|
||||||
|
vec4(0.0, 0.0, 0.0, 1.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
if((u_billboard & 0x4) != 0) l_model[0] = billboardRotation[0];
|
||||||
|
if((u_billboard & 0x2) != 0) l_model[1] = billboardRotation[1];
|
||||||
|
if((u_billboard & 0x1) != 0) l_model[2] = billboardRotation[2];
|
||||||
|
modelView = view * l_model;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,300 +1,7 @@
|
||||||
//version 400
|
#include "model_fs.glsl"
|
||||||
|
|
||||||
uniform mat4 model, view;
|
|
||||||
uniform sampler2D u_texture2d;
|
|
||||||
uniform vec3 u_coefficients_sh[9];
|
|
||||||
uniform bool u_textured; /// set:1
|
|
||||||
uniform bool u_lit; /// set:0
|
|
||||||
uniform bool u_matcaps; /// set:0
|
|
||||||
uniform vec4 u_diffuse; /// set:1,1,1,1
|
|
||||||
|
|
||||||
// lightmapping
|
|
||||||
uniform sampler2D u_lightmap;
|
|
||||||
uniform bool u_texlit;
|
|
||||||
uniform bool u_texmod; /// set:1
|
|
||||||
uniform float u_litboost; /// set:1
|
|
||||||
|
|
||||||
in vec3 v_position;
|
|
||||||
in vec3 v_position_ws;
|
|
||||||
#ifdef RIM
|
|
||||||
uniform mat4 M; // RIM
|
|
||||||
uniform vec3 u_rimcolor; /// set:0.05,0.05,0.05
|
|
||||||
uniform vec3 u_rimrange; /// set:0.11,0.98,0.5
|
|
||||||
uniform vec3 u_rimpivot; /// set:0,0,0
|
|
||||||
uniform bool u_rimambient; /// set:1
|
|
||||||
#endif
|
|
||||||
in vec3 v_normal, v_normal_ws;
|
|
||||||
in vec2 v_texcoord, v_texcoord2;
|
|
||||||
in vec4 v_color;
|
|
||||||
in vec3 v_tangent;
|
|
||||||
in vec3 v_binormal;
|
|
||||||
in vec3 v_to_camera;
|
|
||||||
in vec3 v_vertcolor;
|
|
||||||
out vec4 fragcolor;
|
|
||||||
|
|
||||||
|
|
||||||
{{include-shadowmap}}
|
|
||||||
in vec4 vpeye;
|
|
||||||
in vec4 vneye;
|
|
||||||
in vec4 sc;
|
|
||||||
vec4 shadowing() {
|
|
||||||
return shadowmap(vpeye, vneye, v_texcoord, sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
uniform vec3 u_cam_pos;
|
|
||||||
uniform vec3 u_cam_dir;
|
|
||||||
|
|
||||||
#include "light.glsl"
|
#include "light.glsl"
|
||||||
|
#include "brdf.glsl"
|
||||||
#ifdef SHADING_PBR
|
#include "sh_lighting.glsl"
|
||||||
uniform vec2 resolution; /// set:640,480 // debug options below use this (USE_MAP_DEBUGGING, USE_AMBIENT_DEBUGGING)
|
|
||||||
|
|
||||||
#define USE_BRUTEFORCE_IRRADIANCE false // Samples irradiance from tex_skysphere when enabled.
|
|
||||||
#define USE_WRAPAROUND_SPECULAR true // Makes silhouettes more reflective to avoid black pixels.
|
|
||||||
#define USE_SPECULAR_AO_ATTENUATION true // Dampens IBL specular ambient with AO if enabled.
|
|
||||||
#define USE_NORMAL_VARIATION_TO_ROUGHNESS true // Increases roughness if normal map has variation and was minified.
|
|
||||||
#define USE_MAP_DEBUGGING false // Shows all ColorMaps as horizontal bars
|
|
||||||
#define USE_AMBIENT_DEBUGGING false // Splits the screen in two and shows image-based specular (left), full shading (middle), diffuse shading (right).
|
|
||||||
#define BOOST_LIGHTING 2.00f // Multiplies analytic light's color with this constant because otherwise they look really pathetic.
|
|
||||||
#define BOOST_SPECULAR 1.50f
|
|
||||||
#define BOOST_NOISE 2.50f
|
|
||||||
|
|
||||||
struct ColorMap
|
|
||||||
{
|
|
||||||
bool has_tex;
|
|
||||||
vec4 color;
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform ColorMap map_albedo; uniform sampler2D map_albedo_tex;
|
|
||||||
uniform ColorMap map_diffuse; uniform sampler2D map_diffuse_tex;
|
|
||||||
uniform ColorMap map_specular; uniform sampler2D map_specular_tex; // not used
|
|
||||||
uniform ColorMap map_normals; uniform sampler2D map_normals_tex;
|
|
||||||
uniform ColorMap map_roughness; uniform sampler2D map_roughness_tex;
|
|
||||||
uniform ColorMap map_metallic; uniform sampler2D map_metallic_tex;
|
|
||||||
uniform ColorMap map_ao; uniform sampler2D map_ao_tex;
|
|
||||||
uniform ColorMap map_ambient; uniform sampler2D map_ambient_tex;
|
|
||||||
uniform ColorMap map_emissive; uniform sampler2D map_emissive_tex;
|
|
||||||
|
|
||||||
#define sample_colormap(ColorMap_, uv_) \
|
|
||||||
(ColorMap_.has_tex ? texture( ColorMap_##_tex, uv_ ) : ColorMap_.color)
|
|
||||||
|
|
||||||
uniform float skysphere_rotation; /// set:0
|
|
||||||
uniform float skysphere_mip_count;
|
|
||||||
uniform float exposure; /// set:1
|
|
||||||
uniform uint frame_count;
|
|
||||||
uniform float specular_shininess;
|
|
||||||
|
|
||||||
uniform sampler2D tex_skysphere;
|
|
||||||
uniform sampler2D tex_skyenv;
|
|
||||||
uniform sampler2D tex_brdf_lut;
|
|
||||||
|
|
||||||
uniform bool has_tex_skysphere;
|
|
||||||
uniform bool has_tex_skyenv;
|
|
||||||
|
|
||||||
const float PI = 3.1415926536;
|
|
||||||
|
|
||||||
// MurMurHash 3 finalizer. Implementation is in public domain.
|
|
||||||
uint hash( uint h )
|
|
||||||
{
|
|
||||||
h ^= h >> 16;
|
|
||||||
h *= 0x85ebca6bU;
|
|
||||||
h ^= h >> 13;
|
|
||||||
h *= 0xc2b2ae35U;
|
|
||||||
h ^= h >> 16;
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Random function using the idea of StackOverflow user "Spatial" https://stackoverflow.com/a/17479300
|
|
||||||
// Creates random 23 bits and puts them into the fraction bits of an 32-bit float.
|
|
||||||
float random( uvec3 h )
|
|
||||||
{
|
|
||||||
uint m = hash(h.x ^ hash( h.y ) ^ hash( h.z ));
|
|
||||||
return uintBitsToFloat( ( m & 0x007FFFFFu ) | 0x3f800000u ) - 1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
float random( vec3 v )
|
|
||||||
{
|
|
||||||
return random(floatBitsToUint( v ));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 fresnel_schlick( vec3 H, vec3 V, vec3 F0 )
|
|
||||||
{
|
|
||||||
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
|
||||||
return F0 + ( vec3( 1.0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Fresnel term that dampens rough specular reflections.
|
|
||||||
// https://seblagarde.wordpress.com/2011/08/17/hello-world/
|
|
||||||
vec3 fresnel_schlick_roughness( vec3 H, vec3 V, vec3 F0, float roughness )
|
|
||||||
{
|
|
||||||
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
|
||||||
return F0 + ( max( vec3( 1.0 - roughness ), F0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
float distribution_ggx( vec3 N, vec3 H, float roughness )
|
|
||||||
{
|
|
||||||
float a = roughness * roughness;
|
|
||||||
float a2 = a * a;
|
|
||||||
float NdotH = max( 0., dot( N, H ) );
|
|
||||||
float factor = NdotH * NdotH * ( a2 - 1. ) + 1.;
|
|
||||||
|
|
||||||
return a2 / ( PI * factor * factor );
|
|
||||||
}
|
|
||||||
|
|
||||||
float geometry_schlick_ggx( vec3 N, vec3 V, float k )
|
|
||||||
{
|
|
||||||
float NdotV = max( 0., dot( N, V ) );
|
|
||||||
return NdotV / (NdotV * ( 1. - k ) + k );
|
|
||||||
}
|
|
||||||
|
|
||||||
float geometry_smith( vec3 N, vec3 V, vec3 L, float roughness )
|
|
||||||
{
|
|
||||||
#if 1 // original
|
|
||||||
float r = roughness + 1.;
|
|
||||||
float k = (r * r) / 8.;
|
|
||||||
#elif 0 // vries
|
|
||||||
float a = roughness;
|
|
||||||
float k = (a * a) / 2.0;
|
|
||||||
#elif 0 // vries improved?
|
|
||||||
float a = roughness * roughness;
|
|
||||||
float k = a / 2.0;
|
|
||||||
#endif
|
|
||||||
return geometry_schlick_ggx( N, V, k ) * geometry_schlick_ggx( N, L, k );
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 sphere_to_polar( vec3 normal ) {
|
|
||||||
normal = normalize( normal );
|
|
||||||
return vec2( 1-atan( normal.z, normal.x ) / PI + 0.5 , acos( normal.y ) / PI );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our vertically GL_CLAMPed textures seem to blend towards black when sampling the half-pixel edge.
|
|
||||||
// Not sure if it has a border, or this if is a driver bug, but can repro on multiple nvidia cards.
|
|
||||||
// Knowing the texture height we can limit sampling to the centers of the top and bottom pixel rows.
|
|
||||||
vec2 sphere_to_polar_clamp_y( vec3 normal, float texture_height )
|
|
||||||
{
|
|
||||||
normal = normalize( normal );
|
|
||||||
return vec2( ( atan( normal.z, normal.x ) + skysphere_rotation ) / PI / 2.0 + 0.5, clamp(acos( normal.y ) / PI, 0.5 / texture_height, 1.0 - 0.5 / texture_height) );
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 sample_sky( vec3 normal )
|
|
||||||
{
|
|
||||||
vec2 polar = sphere_to_polar( normal );
|
|
||||||
return texture( tex_skysphere, polar ).rgb * exposure;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes samples around the hemisphere, converts them to radiances via weighting and
|
|
||||||
// returns a normalized sum.
|
|
||||||
vec3 sample_irradiance_slow( vec3 normal, vec3 vertex_tangent )
|
|
||||||
{
|
|
||||||
float delta = 0.10;
|
|
||||||
|
|
||||||
vec3 up = abs( normal.y ) < 0.999 ? vec3( 0., 1., 0. ) : vec3( 0., 0., 1. );
|
|
||||||
vec3 tangent_x = normalize( cross( up, normal ) );
|
|
||||||
vec3 tangent_y = cross( normal, tangent_x );
|
|
||||||
|
|
||||||
int numIrradianceSamples = 0;
|
|
||||||
|
|
||||||
vec3 irradiance = vec3(0.);
|
|
||||||
|
|
||||||
for ( float phi = 0.; phi < 2. * PI ; phi += delta )
|
|
||||||
{
|
|
||||||
for ( float theta = 0.; theta < 0.5 * PI; theta += delta )
|
|
||||||
{
|
|
||||||
vec3 tangent_space = vec3(
|
|
||||||
sin( theta ) * cos( phi ),
|
|
||||||
sin( theta ) * sin( phi ),
|
|
||||||
cos( theta ) );
|
|
||||||
|
|
||||||
vec3 world_space = tangent_space.x * tangent_x + tangent_space.y + tangent_y + tangent_space.z * normal;
|
|
||||||
|
|
||||||
vec3 color = sample_sky( world_space );
|
|
||||||
irradiance += color * cos( theta ) * sin( theta );
|
|
||||||
numIrradianceSamples++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
irradiance = PI * irradiance / float( numIrradianceSamples );
|
|
||||||
return irradiance;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 sample_irradiance_fast( vec3 normal, vec3 vertex_tangent )
|
|
||||||
{
|
|
||||||
// Sample the irradiance map if it exists, otherwise fall back to blurred reflection map.
|
|
||||||
if ( has_tex_skyenv )
|
|
||||||
{
|
|
||||||
vec2 polar = sphere_to_polar( normal );
|
|
||||||
return textureLod( tex_skyenv, polar, 0.0 ).rgb * exposure;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vec2 polar = sphere_to_polar( normal );
|
|
||||||
return textureLod( tex_skysphere, polar, 0.80 * skysphere_mip_count ).rgb * exposure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vec3 specular_ibl( vec3 V, vec3 N, float roughness, vec3 fresnel )
|
|
||||||
{
|
|
||||||
// What we'd like to do here is take a LOT of skybox samples around the reflection
|
|
||||||
// vector R according to the BRDF lobe.
|
|
||||||
//
|
|
||||||
// Unfortunately it's not possible in real time so we use the following UE4 style approximations:
|
|
||||||
// 1. Integrate incoming light and BRDF separately ("split sum approximation")
|
|
||||||
// 2. Assume V = R = N so that we can just blur the skybox and sample that.
|
|
||||||
// 3. Bake the BRDF integral into a lookup texture so that it can be computed in constant time.
|
|
||||||
//
|
|
||||||
// Here we also simplify approximation #2 by using bilinear mipmaps with a magic formula instead
|
|
||||||
// of properly convolving it with a GGX lobe.
|
|
||||||
//
|
|
||||||
// For details, see Brian Karis, "Real Shading in Unreal Engine 4", 2013.
|
|
||||||
|
|
||||||
vec3 R = 2. * dot( V, N ) * N - V;
|
|
||||||
|
|
||||||
vec2 polar = sphere_to_polar( R );
|
|
||||||
|
|
||||||
// Map roughness from range [0, 1] into a mip LOD [0, skysphere_mip_count].
|
|
||||||
// The magic numbers were chosen empirically.
|
|
||||||
|
|
||||||
float mip = 0.9 * skysphere_mip_count * pow(roughness, 0.25 * BOOST_SPECULAR);
|
|
||||||
|
|
||||||
vec3 prefiltered = textureLod( tex_skysphere, polar, mip ).rgb * exposure;
|
|
||||||
|
|
||||||
float NdotV = dot( N, V );
|
|
||||||
|
|
||||||
// dot( N, V ) seems to produce negative values so we can try to stretch it a bit behind the silhouette
|
|
||||||
// to avoid black pixels.
|
|
||||||
if (USE_WRAPAROUND_SPECULAR)
|
|
||||||
{
|
|
||||||
NdotV = NdotV * 0.9 + 0.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
NdotV = min(0.99, max(0.01, NdotV));
|
|
||||||
|
|
||||||
// A precomputed lookup table contains a scale and a bias term for specular intensity (called "fresnel" here).
|
|
||||||
// See equation (8) in Karis' course notes mentioned above.
|
|
||||||
vec2 envBRDF = texture( tex_brdf_lut, vec2(NdotV, 1.0-roughness) ).xy; // (NdotV,1-roughtness) for green top-left (NdotV,roughness) for green bottom-left
|
|
||||||
vec3 specular = prefiltered * (fresnel * envBRDF.x + vec3(envBRDF.y));
|
|
||||||
|
|
||||||
return specular;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vec3 sh_lighting(vec3 n) {
|
|
||||||
vec3 SHLightResult[9];
|
|
||||||
SHLightResult[0] = 0.282095f * u_coefficients_sh[0];
|
|
||||||
SHLightResult[1] = -0.488603f * u_coefficients_sh[1] * n.y;
|
|
||||||
SHLightResult[2] = 0.488603f * u_coefficients_sh[2] * n.z;
|
|
||||||
SHLightResult[3] = -0.488603f * u_coefficients_sh[3] * n.x;
|
|
||||||
SHLightResult[4] = 1.092548f * u_coefficients_sh[4] * n.x * n.y;
|
|
||||||
SHLightResult[5] = -1.092548f * u_coefficients_sh[5] * n.y * n.z;
|
|
||||||
SHLightResult[6] = 0.315392f * u_coefficients_sh[6] * (3.0f * n.z * n.z - 1.0f);
|
|
||||||
SHLightResult[7] = -1.092548f * u_coefficients_sh[7] * n.x * n.z;
|
|
||||||
SHLightResult[8] = 0.546274f * u_coefficients_sh[8] * (n.x * n.x - n.y * n.y);
|
|
||||||
vec3 result = vec3(0.0);
|
|
||||||
for (int i = 0; i < 9; ++i)
|
|
||||||
result += SHLightResult[i];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LIGHTMAP_BAKING
|
#ifdef LIGHTMAP_BAKING
|
||||||
void main() {
|
void main() {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
vec3 sh_lighting(vec3 n) {
|
||||||
|
vec3 SHLightResult[9];
|
||||||
|
SHLightResult[0] = 0.282095f * u_coefficients_sh[0];
|
||||||
|
SHLightResult[1] = -0.488603f * u_coefficients_sh[1] * n.y;
|
||||||
|
SHLightResult[2] = 0.488603f * u_coefficients_sh[2] * n.z;
|
||||||
|
SHLightResult[3] = -0.488603f * u_coefficients_sh[3] * n.x;
|
||||||
|
SHLightResult[4] = 1.092548f * u_coefficients_sh[4] * n.x * n.y;
|
||||||
|
SHLightResult[5] = -1.092548f * u_coefficients_sh[5] * n.y * n.z;
|
||||||
|
SHLightResult[6] = 0.315392f * u_coefficients_sh[6] * (3.0f * n.z * n.z - 1.0f);
|
||||||
|
SHLightResult[7] = -1.092548f * u_coefficients_sh[7] * n.x * n.z;
|
||||||
|
SHLightResult[8] = 0.546274f * u_coefficients_sh[8] * (n.x * n.x - n.y * n.y);
|
||||||
|
vec3 result = vec3(0.0);
|
||||||
|
for (int i = 0; i < 9; ++i)
|
||||||
|
result += SHLightResult[i];
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
// uniform mat4 view = mat4(1.0);
|
||||||
|
uniform vec3 lightPos; /// set:1,1,1
|
||||||
|
uniform float doTexture; /// set:1
|
||||||
|
#ifdef VSMCUBE
|
||||||
|
uniform samplerCube shadowMap; // VSMCUBE
|
||||||
|
#else
|
||||||
|
uniform sampler2D shadowMap; // !VSMCUBE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct light {
|
||||||
|
vec3 position; // world-space
|
||||||
|
vec4 diffuse;
|
||||||
|
vec4 specular;
|
||||||
|
float constantAttenuation, linearAttenuation, quadraticAttenuation;
|
||||||
|
};
|
||||||
|
|
||||||
|
light light0 = light(
|
||||||
|
vec3(1,1,1), // lightPos
|
||||||
|
vec4(1,1,1,1), // diffuse
|
||||||
|
vec4(1,1,1,1), // specular
|
||||||
|
1.0, 0.0, 0.0 // attenuation (const, linear, quad)
|
||||||
|
);
|
||||||
|
|
||||||
|
// From http://fabiensanglard.net/shadowmappingVSM/index.php
|
||||||
|
#ifdef VSMCUBE
|
||||||
|
float chebyshevUpperBound(float distance, vec3 dir) {
|
||||||
|
distance = distance/20 ;
|
||||||
|
vec2 moments = texture(shadowMap, dir).rg;
|
||||||
|
#else
|
||||||
|
float chebyshevUpperBound(float distance, vec4 scPostW) {
|
||||||
|
vec2 moments = texture(shadowMap,scPostW.xy).rg;
|
||||||
|
#endif
|
||||||
|
// Surface is fully lit. as the current fragment is before the light occluder
|
||||||
|
if (distance <= moments.x)
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
|
// The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check
|
||||||
|
// How likely this pixel is to be lit (p_max)
|
||||||
|
float variance = moments.y - (moments.x*moments.x);
|
||||||
|
//variance = max(variance, 0.000002);
|
||||||
|
variance = max(variance, 0.00002);
|
||||||
|
|
||||||
|
float d = distance - moments.x;
|
||||||
|
float p_max = variance / (variance + d*d);
|
||||||
|
|
||||||
|
return p_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec4 shadowmap(in vec4 vpeye, in vec4 vneye, in vec2 uv, in vec4 sc) {
|
||||||
|
#ifndef VSMCUBE
|
||||||
|
return vec4(1.);
|
||||||
|
#else
|
||||||
|
vec3 fragment = vec3(vpeye);
|
||||||
|
vec3 normal = vec3(normalize(vneye));
|
||||||
|
vec3 viewDir = normalize(-fragment);
|
||||||
|
|
||||||
|
// Lighting
|
||||||
|
// Convert to eye-space
|
||||||
|
vec3 light = vec3(view * vec4(light0.position, 1.0));
|
||||||
|
|
||||||
|
#ifdef VSMCUBE
|
||||||
|
// Vectors
|
||||||
|
vec3 fragmentToLight = light - fragment;
|
||||||
|
vec3 fragmentToLightDir = normalize(fragmentToLight);
|
||||||
|
|
||||||
|
// Shadows
|
||||||
|
vec4 fragmentToLight_world = inverse(view) * vec4(fragmentToLightDir, 0.0);
|
||||||
|
float shadowFactor = chebyshevUpperBound(length(fragmentToLight), -fragmentToLight_world.xyz);
|
||||||
|
#else
|
||||||
|
// Shadows
|
||||||
|
vec4 scPostW = sc / sc.w;
|
||||||
|
scPostW = scPostW * 0.5 + 0.5;
|
||||||
|
|
||||||
|
float shadowFactor = 1.0; // Not in shadow
|
||||||
|
|
||||||
|
bool outsideShadowMap = sc.w <= 0.0f || (scPostW.x < 0 || scPostW.y < 0) || (scPostW.x >= 1 || scPostW.y >= 1);
|
||||||
|
if (!outsideShadowMap) {
|
||||||
|
shadowFactor = chebyshevUpperBound(scPostW.z, scPostW);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec4 diffColor = vec4(1,1,1,1);
|
||||||
|
#ifdef VSMCUBE
|
||||||
|
if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, -fragmentToLight_world.xyz).r), 1.0);
|
||||||
|
#else
|
||||||
|
if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, vec2(uv.x, 1.0 - uv.y)).r), 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
vec3 positionToLight = light - fragment;
|
||||||
|
vec3 lightDir = normalize(positionToLight);
|
||||||
|
|
||||||
|
// Angle between fragment-normal and incoming light
|
||||||
|
float cosAngIncidence = dot(lightDir, normal);
|
||||||
|
cosAngIncidence = clamp(cosAngIncidence, 0, 1);
|
||||||
|
|
||||||
|
float attenuation = 1.0f;
|
||||||
|
attenuation = 1.0 / (light0.constantAttenuation + light0.linearAttenuation * length(positionToLight) + light0.quadraticAttenuation * pow(length(positionToLight),2));
|
||||||
|
|
||||||
|
vec4 diffuse = diffColor * light0.diffuse * cosAngIncidence * attenuation;
|
||||||
|
|
||||||
|
vec4 total_lighting;
|
||||||
|
total_lighting += vec4(0.1, 0.1, 0.1, 1.0) * diffColor; // Ambient
|
||||||
|
total_lighting += diffuse * shadowFactor; // Diffuse
|
||||||
|
#else
|
||||||
|
vec4 total_lighting = diffColor;
|
||||||
|
#endif
|
||||||
|
return vec4(clamp(vec3(total_lighting), 0., 1.), 1.0);
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -1,124 +1,11 @@
|
||||||
#ifndef MAX_BONES
|
#include "model_vs.glsl"
|
||||||
#define MAX_BONES 110
|
|
||||||
#endif
|
|
||||||
uniform mat3x4 vsBoneMatrix[MAX_BONES];
|
|
||||||
uniform bool SKINNED; /// set:0
|
|
||||||
uniform mat4 M; // RIM
|
|
||||||
uniform mat4 VP;
|
|
||||||
uniform mat4 P;
|
|
||||||
uniform vec3 u_cam_dir;
|
|
||||||
uniform int u_billboard;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Fetch blend channels from all attached blend deformers.
|
|
||||||
for (size_t di = 0; di < mesh->blend_deformers.count; di++) {
|
|
||||||
ufbx_blend_deformer *deformer = mesh->blend_deformers.data[di];
|
|
||||||
for (size_t ci = 0; ci < deformer->channels.count; ci++) {
|
|
||||||
ufbx_blend_channel *chan = deformer->channels.data[ci];
|
|
||||||
if (chan->keyframes.count == 0) continue;
|
|
||||||
if (num_blend_shapes < MAX_BLEND_SHAPES) {
|
|
||||||
blend_channels[num_blend_shapes] = chan;
|
|
||||||
vmesh->blend_channel_indices[num_blend_shapes] = (int32_t)chan->typed_id;
|
|
||||||
num_blend_shapes++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (num_blend_shapes > 0) {
|
|
||||||
vmesh->blend_shape_image = pack_blend_channels_to_image(mesh, blend_channels, num_blend_shapes);
|
|
||||||
vmesh->num_blend_shapes = num_blend_shapes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ubo.f_num_blend_shapes = (float)mesh->num_blend_shapes;
|
|
||||||
for (size_t i = 0; i < mesh->num_blend_shapes; i++) {
|
|
||||||
ubo.blend_weights[i] = view->scene.blend_channels[mesh->blend_channel_indices[i]].weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sg_image blend_shapes = mesh->num_blend_shapes > 0 ? mesh->blend_shape_image : view->empty_blend_shape_image;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// for blendshapes
|
|
||||||
#ifndef MAX_BLENDSHAPES
|
|
||||||
#define MAX_BLENDSHAPES 16
|
|
||||||
#endif
|
|
||||||
uniform vec4 blend_weights[MAX_BLENDSHAPES]; // @todo: implement me
|
|
||||||
uniform float f_num_blend_shapes; // @todo: implement me
|
|
||||||
uniform MEDIUMP sampler2DArray blend_shapes; // @todo: implement me
|
|
||||||
|
|
||||||
in vec3 att_position; // @todo: reorder ass2iqe to emit p3 n3 u2 t3 b3 c4B i4 w4 instead
|
|
||||||
in vec2 att_texcoord;
|
|
||||||
in vec3 att_normal;
|
|
||||||
in vec4 att_tangent; // vec3 + bi sign
|
|
||||||
in mat4 att_instanced_matrix; // for instanced rendering
|
|
||||||
in vec4 att_indexes; // @fixme: gles might use ivec4 instead?
|
|
||||||
in vec4 att_weights; // @todo: downgrade from float to byte
|
|
||||||
in float att_vertexindex; // for blendshapes
|
|
||||||
in vec4 att_color;
|
|
||||||
in vec3 att_bitangent; // @todo: remove? also, ass2iqe might output this
|
|
||||||
in vec2 att_texcoord2;
|
|
||||||
out vec4 v_color;
|
|
||||||
out vec3 v_position, v_position_ws;
|
|
||||||
out vec3 v_normal, v_normal_ws;
|
|
||||||
out vec2 v_texcoord, v_texcoord2;
|
|
||||||
out vec3 v_tangent;
|
|
||||||
out vec3 v_binormal;
|
|
||||||
out vec3 v_viewpos;
|
|
||||||
out vec3 v_to_camera;
|
|
||||||
out vec3 v_vertcolor;
|
|
||||||
|
|
||||||
// lights
|
// lights
|
||||||
#include "light.glsl"
|
#include "light.glsl"
|
||||||
|
|
||||||
// shadow
|
|
||||||
uniform mat4 model, view, inv_view;
|
|
||||||
uniform mat4 cameraToShadowProjector;
|
|
||||||
out vec4 vneye;
|
|
||||||
out vec4 vpeye;
|
|
||||||
out vec4 sc;
|
|
||||||
void do_shadow() {
|
|
||||||
vneye = view * model * vec4(att_normal, 0.0f);
|
|
||||||
vpeye = view * model * vec4(att_position, 1.0);
|
|
||||||
sc = cameraToShadowProjector * model * vec4(att_position, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// blendshapes
|
|
||||||
vec3 evaluate_blend_shape(int vertex_index) {
|
|
||||||
ivec2 coord = ivec2(vertex_index & (2048 - 1), vertex_index >> 11);
|
|
||||||
int num_blend_shapes = int(f_num_blend_shapes);
|
|
||||||
vec3 offset = vec3(0.0);
|
|
||||||
for (int i = 0; i < num_blend_shapes; i++) {
|
|
||||||
vec4 packedw = blend_weights[i >> 2];
|
|
||||||
float weight = packedw[i & 3];
|
|
||||||
offset += weight * texelFetch(blend_shapes, ivec3(coord, i), 0).xyz;
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 objPos;
|
vec3 objPos = get_object_pos();
|
||||||
if(!SKINNED) {
|
|
||||||
objPos = att_position;
|
|
||||||
v_normal = att_normal;
|
|
||||||
} else {
|
|
||||||
mat3x4 m = vsBoneMatrix[int(att_indexes.x)] * att_weights.x;
|
|
||||||
m += vsBoneMatrix[int(att_indexes.y)] * att_weights.y;
|
|
||||||
m += vsBoneMatrix[int(att_indexes.z)] * att_weights.z;
|
|
||||||
m += vsBoneMatrix[int(att_indexes.w)] * att_weights.w;
|
|
||||||
objPos = vec4(att_position, 1.0) * m;
|
|
||||||
|
|
||||||
// blendshapes
|
|
||||||
// objPos += evaluate_blend_shape(int(att_vertexindex));
|
|
||||||
|
|
||||||
v_normal = vec4(att_normal, 0.0) * m;
|
|
||||||
//@todo: tangents
|
|
||||||
}
|
|
||||||
|
|
||||||
// vec3 tangent = att_tangent.xyz;
|
|
||||||
// vec3 bitangent = cross(att_normal, att_tangent.xyz) * att_tangent.w;
|
|
||||||
v_normal_ws = normalize(vec3(att_instanced_matrix * vec4(v_normal, 0.))); // normal to world/model space
|
v_normal_ws = normalize(vec3(att_instanced_matrix * vec4(v_normal, 0.))); // normal to world/model space
|
||||||
v_normal = normalize(v_normal);
|
v_normal = normalize(v_normal);
|
||||||
v_position = att_position;
|
v_position = att_position;
|
||||||
|
@ -129,36 +16,11 @@ void main() {
|
||||||
mat4 l_model = att_instanced_matrix;
|
mat4 l_model = att_instanced_matrix;
|
||||||
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
||||||
|
|
||||||
if(u_billboard > 0) {
|
setup_billboards(modelView, l_model);
|
||||||
vec3 cameraPosition = -transpose(mat3(view)) * view[3].xyz;
|
|
||||||
vec3 lookDir = normalize(cameraPosition - v_position_ws);
|
|
||||||
|
|
||||||
vec3 up = vec3(modelView[0][1], modelView[1][1], modelView[2][1]);
|
|
||||||
vec3 right = normalize(cross(up, lookDir));
|
|
||||||
up = cross(lookDir, right);
|
|
||||||
|
|
||||||
vec3 scale;
|
|
||||||
scale.x = length(vec3(l_model[0]));
|
|
||||||
scale.y = length(vec3(l_model[1]));
|
|
||||||
scale.z = length(vec3(l_model[2]));
|
|
||||||
// scale.x *= sign(l_model[0][0]);
|
|
||||||
// scale.y *= sign(l_model[1][1]);
|
|
||||||
// scale.z *= sign(l_model[2][2]);
|
|
||||||
|
|
||||||
mat4 billboardRotation = mat4(
|
|
||||||
vec4(right * scale.x, 0.0),
|
|
||||||
vec4(-up * scale.y, 0.0),
|
|
||||||
vec4(-lookDir * scale.z, 0.0),
|
|
||||||
vec4(0.0, 0.0, 0.0, 1.0)
|
|
||||||
);
|
|
||||||
|
|
||||||
if((u_billboard & 0x4) != 0) l_model[0] = billboardRotation[0];
|
|
||||||
if((u_billboard & 0x2) != 0) l_model[1] = billboardRotation[1];
|
|
||||||
if((u_billboard & 0x1) != 0) l_model[2] = billboardRotation[2];
|
|
||||||
modelView = view * l_model;
|
|
||||||
}
|
|
||||||
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
||||||
v_tangent = normalize(mat3(att_instanced_matrix) * att_tangent.xyz);
|
v_tangent = normalize(mat3(att_instanced_matrix) * att_tangent.xyz);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// compute tangent T and bitangent B
|
// compute tangent T and bitangent B
|
||||||
vec3 Q1 = dFdx(att_position);
|
vec3 Q1 = dFdx(att_position);
|
||||||
|
@ -172,7 +34,9 @@ void main() {
|
||||||
#else
|
#else
|
||||||
vec3 binormal = cross(att_normal, att_tangent.xyz) * att_tangent.w;
|
vec3 binormal = cross(att_normal, att_tangent.xyz) * att_tangent.w;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
v_binormal = normalize(mat3(att_instanced_matrix) * binormal);
|
v_binormal = normalize(mat3(att_instanced_matrix) * binormal);
|
||||||
|
|
||||||
vec4 finalPos = modelView * vec4( objPos, 1.0 );
|
vec4 finalPos = modelView * vec4( objPos, 1.0 );
|
||||||
vec3 to_camera = normalize( -finalPos.xyz );
|
vec3 to_camera = normalize( -finalPos.xyz );
|
||||||
v_to_camera = mat3( inv_view ) * to_camera;
|
v_to_camera = mat3( inv_view ) * to_camera;
|
||||||
|
|
Loading…
Reference in New Issue