MetaCoreEngineV2/rpcore/shader/includes/common_functions.inc.glsl
2026-01-13 17:06:06 +08:00

321 lines
11 KiB
GLSL

/**
*
* RenderPipeline
*
* Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#pragma once
#define saturate(v) clamp(v, 0, 1)
#define M_PI 3.1415926535897932384626433
#define HALF_PI 1.5707963267948966192313216
#define TWO_PI 6.2831853071795864769252867
#define FOUR_PI 12.566370614359172953850573
#define ONE_BY_PI 0.3183098861837906715377675
#define SQRT_TWO 1.4142135623730950488016887
#define AIR_IOR 1.000277
// Fixes the cubemap direction
vec3 fix_cubemap_coord(vec3 coord) {
// return normalize(coord.xzy * vec3(1,-1,1));
return normalize(coord.yxz * vec3(-1, 1, 1));
}
// Converts a texture coodinate and face index to a direction vector
vec3 get_cubemap_coordinate(int face_index, vec2 coord) {
vec3 baseDir = vec3(0);
if (face_index == 0) baseDir = vec3(1.0, -coord.y, -coord.x);
else if (face_index == 1) baseDir = vec3(-1.0, -coord.y, coord.x);
else if (face_index == 2) baseDir = vec3(coord.x, 1.0, coord.y);
else if (face_index == 3) baseDir = vec3(coord.x, -1.0, -coord.y);
else if (face_index == 4) baseDir = vec3(coord.x, -coord.y, 1.0);
else if (face_index == 5) baseDir = vec3(-coord.x, -coord.y, -1.0);
return normalize(baseDir);
}
// Computes the skydome texcoord based on the pixels view direction
vec2 get_skydome_coord(vec3 view_dir) {
float angle = (atan(view_dir.x, view_dir.y) + M_PI) / (2.0 * M_PI);
return vec2(angle, view_dir.z);
}
// Converts a coordinate like "gl_FragCoord" to a cubemap direction, with a given
// cubemap size. Assumes the render target has a size of (6 * cubemap_size, cubemap_size).
// clamped_coord will contain a coordinate from (0 .. cubemap_size), this can be
// used for further processing or writing the result.
// face will contain the selected cubemap face.
vec3 texcoord_to_cubemap(int cubemap_size, ivec2 coord, out ivec2 clamped_coord, out int face) {
face = coord.x / cubemap_size;
clamped_coord = coord % cubemap_size;
vec2 local_coord = saturate((clamped_coord + 0.5) / float(cubemap_size)) * 2.0 - 1.0;
return get_cubemap_coordinate(face, local_coord);
}
// Version of texcoord_to_cubemap without the out parameters
vec3 texcoord_to_cubemap(int cubemap_size, ivec2 coord) {
ivec2 clamped_coord; int face;
return texcoord_to_cubemap(cubemap_size, coord, clamped_coord, face);
}
// Rotate a vector by a given sinus and cosinus of an angle
vec2 rotate(vec2 vector, float cos_alpha, float sin_alpha) {
return vec2(
vector.x * cos_alpha - vector.y * sin_alpha,
vector.x * sin_alpha + vector.y * cos_alpha
);
}
// Rotate a vector by an angle
vec2 rotate(vec2 vector, float angle) {
float cos_alpha = cos(angle);
float sin_alpha = sin(angle);
return rotate(vector, cos_alpha, sin_alpha);
}
// Returns a coordinate which can be used for bilateral upscaling
ivec2 get_bilateral_coord(ivec2 coord) {
return (coord + 1) / 2 - 1;
}
// Checks if a 2D-coordinate exceeds the [0, 1] range
bool out_of_screen(vec2 tcoord) {
return tcoord.x < 0.0 || tcoord.y < 0.0 || tcoord.x > 1.0 || tcoord.y > 1.0;
}
// Checks if a 3D-coordinate exceeds the [0, 1] range
bool out_of_unit_box(vec3 coord) {
return coord.x < 0.0 || coord.y < 0.0 || coord.z < 0.0 ||
coord.x > 1.0 || coord.y > 1.0 || coord.z > 1.0;
}
// Finds a tangent and bitangent vector based on a given normal
void find_arbitrary_tangent(vec3 normal, out vec3 tangent, out vec3 bitangent) {
vec3 v0 = abs(normal.z) < (0.99) ? vec3(0, 0, 1) : vec3(0, 1, 0);
tangent = normalize(cross(v0, normal));
bitangent = normalize(cross(tangent, normal));
}
// Transforms a given vector to tangent space
vec3 tangent_to_world(vec3 normal, vec3 vector)
{
vec3 tangent, binormal;
find_arbitrary_tangent(normal, tangent, binormal);
return vector.x * tangent + vector.y * binormal + vector.z * normal;
}
// Returns the number of mipmaps of a cubemap
int get_mipmap_count(samplerCube cubemap) {
int cubemap_size = textureSize(cubemap, 0).x;
return int(1 + floor(log2(cubemap_size)));
}
// Returns the number of mipmaps of a 2D Texture
int get_mipmap_count(sampler2D tex) {
int tex_size = textureSize(tex, 0).x;
return int(1 + floor(log2(tex_size)));
}
// Returns the number of mipmaps of a cubemap arry
int get_mipmap_count(samplerCubeArray cubemap) {
int cubemap_size = textureSize(cubemap, 0).x;
return int(1 + floor(log2(cubemap_size)));
}
// Converts a normalized spherical coordinate (r = 1) to cartesian coordinates
vec3 spherical_to_vector(float theta, float phi) {
float sin_theta = sin(theta);
return normalize(vec3(
sin_theta * cos(phi),
sin_theta * sin(phi),
cos(theta)
));
}
// Converts a cartesian coordinate to spherical coordinates
void vector_to_spherical(vec3 v, out float theta, out float phi, out float radius) {
radius = sqrt(dot(v, v));
phi = acos(v.z / radius);
theta = atan(v.y, v.x) + M_PI;
}
// Convertsa normalized vector to spherical coordinates
void vector_to_spherical(vec3 v, out float theta, out float phi) {
phi = acos(v.z);
theta = atan(v.y, v.x) + M_PI;
}
// Converts a given sun azimuth and altitude to a direction vector
vec3 sun_azimuth_to_angle(float azimuth, float altitude) {
float theta = (90 - altitude) / 180.0 * M_PI;
float phi = azimuth / 180.0 * M_PI;
return spherical_to_vector(theta, phi);
}
// Blends a given color soft with the base color
// From: https://github.com/mattdesl/glsl-blend-soft-light/blob/master/index.glsl
vec3 blend_soft_light(vec3 base, vec3 blend) {
return mix(
sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend),
2.0 * base * blend + base * base * (1.0 - 2.0 * blend),
step(base, vec3(0.5))
);
}
// Normalizes v without taking the w component into account
vec4 normalize_without_w(vec4 v) {
return v / length(v.xyz);
}
// Unpacks a normal from 0 .. 1 range to the -1 .. 1 range
vec3 unpack_texture_normal(vec3 n) {
return fma(n, vec3(2.0), vec3(-1.0));
}
// Converts a value from linear to logarithmic distribution, using a given factor
float make_logarithmic(float x, float factor) {
// return (exp(factor * x)-1) / (exp(factor)-1);
return log(factor * x + 1.0 + 1e-6) / log(1.0 + factor);
}
// Makes a 3 component vector logarithmic
vec3 make_logarithmic(vec3 v, float factor) {
return log(factor * v + 1.0 + 1e-6) / log(1.0 + factor);
}
// Unpacks an integer from a float, packed by the GPUCommandQueue.
int gpu_cq_unpack_int_from_float(float v) {
#if GPU_CMD_INT_AS_FLOAT
return floatBitsToInt(v);
#else
return int(v);
#endif
}
// Computes the diffuse antialiasing factor
// From: http://blog.selfshadow.com/sandbox/diffuse_aa.html
float get_diffuse_aa(float w, float NxL) {
float x = sqrt(1.0 - w);
float x0 = 0.373837 * NxL;
float x1 = 0.66874 * x;
float n = x0 + x1;
return w * ((abs(x0) <= x1) ? n * n / x : saturate(NxL));
}
// Blends a material
float blend_material(float material_factor, float detailmap, float add_factor, float pow_factor) {
material_factor = max(0, material_factor);
return saturate(
mix(pow(max(0, detailmap + add_factor), pow_factor), 1.0, material_factor) *
material_factor);
}
// Blends a specular IOR to make sure it never drops below 1.0
float blend_ior(float material_specular, float sampled_specular) {
return 1.0 + max(0, material_specular - 1.0) * 2.0 * sampled_specular;
}
// We need to define them as macros instead of functions, since gl_FragCoord is
// not available in compute shaders
// Regular texcoord
#define get_texcoord() (gl_FragCoord.xy / SCREEN_SIZE)
// Texcoord for half-res targets sampling full-res targets
#define get_half_texcoord() vec2((ivec2(gl_FragCoord.xy) * 2 + 0.5) / SCREEN_SIZE)
// Texcoord for half-res targets sampling half-res targets
#define get_half_native_texcoord() ((vec2(gl_FragCoord.xy) + 0.5) / ivec2(SCREEN_SIZE / 2))
// Converts degree (0 .. 360) to radians (0 .. 2 PI)
float degree_to_radians(float degree) {
return degree / 180.0 * M_PI;
}
// Converts radians (0 .. 2 PI) to degree (0 .. 360)
float radians_to_degree(float radians) {
return radians / M_PI * 180.0;
}
// Simulates a near filter on a fullscreen texture
vec2 truncate_coordinate(vec2 tcoord) {
return (ivec2(tcoord * SCREEN_SIZE) + 0.5) / SCREEN_SIZE;
}
// Returns the squared length of v
float length_squared(vec2 v) { return dot(v, v); }
float length_squared(vec3 v) { return dot(v, v); }
float length_squared(vec4 v) { return dot(v, v); }
// Squared distance between a and b
float distance_squared(vec3 a, vec3 b) { return length_squared(a - b); }
float distance_squared(vec4 a, vec4 b) { return length_squared(a - b); }
float distance_squared(vec2 a, vec2 b) { return length_squared(a - b); }
// Returns x * x
float square(float x) { return x * x; }
vec2 square(vec2 x) { return x * x; }
vec3 square(vec3 x) { return x * x; }
vec4 square(vec4 x) { return x * x; }
// Minimum and maximum for multiple components
// XXX: There are hardware instructions (at least on AMD) for it:
// https://www.opengl.org/registry/specs/AMD/shader_trinary_minmax.txt
#define min3(a, b, c) min(a, min(b, c))
#define max3(a, b, c) max(a, max(b, c))
#define min4(a, b, c, d) min(a, min(b, min(c, d)))
#define max4(a, b, c, d) max(a, max(b, max(c, d)))
#define min5(a, b, c, d, e) min(a, min(b, min(c, min(d, e))))
#define max5(a, b, c, d, e) max(a, max(b, max(c, max(d, e))))
// Convenience function which ensures v dot n is > 0
vec3 face_forward(vec3 v, vec3 n) {
return dot(v, n) < 0 ? -v : v;
}
// Creates a rotation mat, rotation should be 0 .. 2 * pi
mat2 make_rotation_mat(float rotation) {
float r_sin = sin(rotation);
float r_cos = cos(rotation);
return mat2(r_cos, -r_sin, r_sin, r_cos);
}
// Convenience functions for the scattering plugin - probably don't belong here
#define get_sun_vector() sun_azimuth_to_angle(TimeOfDay.scattering.sun_azimuth, TimeOfDay.scattering.sun_altitude)
#define get_sun_color() (TimeOfDay.scattering.sun_color * TimeOfDay.scattering.sun_intensity)
#define get_sun_color_scale(_v) saturate(square((_v.z) / 0.15))
#if !HAVE_PLUGIN(color_correction)
#undef get_sun_color
#define get_sun_color() (TimeOfDay.scattering.sun_color * TimeOfDay.scattering.sun_intensity)
#endif