SkyShaders working

This commit is contained in:
clayjohn 2022-04-29 15:34:01 -07:00
parent 516ec892b4
commit 3bb8e6a9fe
17 changed files with 620 additions and 172 deletions

View file

@ -92,9 +92,9 @@ public:
static void make_current() {
_create_func = _create_current;
low_end = true;
}
virtual bool is_low_end() const { return true; }
uint64_t get_frame_number() const { return frame; }
double get_frame_delta_time() const { return delta; }

View file

@ -238,37 +238,81 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
dirty_sky_list = nullptr;
}
void RasterizerSceneGLES3::_draw_sky(Sky *p_sky, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_custom_fov, float p_energy, const Basis &p_sky_orientation) {
ERR_FAIL_COND(!p_sky);
void RasterizerSceneGLES3::_draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
ERR_FAIL_COND(!p_env);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
Sky *sky = sky_owner.get_or_null(p_env->sky);
ERR_FAIL_COND(!sky);
GLES3::SkyMaterialData *material_data = nullptr;
RID sky_material;
RS::EnvironmentBG background = p_env->background;
if (sky) {
ERR_FAIL_COND(!sky);
sky_material = sky->material;
if (sky_material.is_valid()) {
material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
if (!material_data || !material_data->shader_data->valid) {
material_data = nullptr;
}
}
if (!material_data) {
sky_material = sky_globals.default_material;
material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
}
} else if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
sky_material = sky_globals.fog_material;
material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
}
ERR_FAIL_COND(!material_data);
material_data->bind_uniforms();
GLES3::SkyShaderData *shader_data = material_data->shader_data;
ERR_FAIL_COND(!shader_data);
glDepthMask(GL_FALSE);
glDepthFunc(GL_LEQUAL);
glColorMask(1, 1, 1, 1);
glDisable(GL_BLEND);
//state.sky_shader.version_bind_shader(sky_globals.default_shader, SkyShaderGLES3::MODE_BACKGROUND);
//glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_instance_data_buffers[state.current_buffer]); // Canvas data updated here
//glBindBufferBase(GL_UNIFORM_BUFFER, 1, state.canvas_instance_data_buffers[state.current_buffer]); // Global data
//glBindBufferBase(GL_UNIFORM_BUFFER, 2, state.canvas_instance_data_buffers[state.current_buffer]); // Directional light data
//glBindBufferBase(GL_UNIFORM_BUFFER, 3, state.canvas_instance_data_buffers[state.current_buffer]); // Material uniforms
//glBindBufferBase(GL_UNIFORM_BUFFER, 2, p_sky.directional light data); // Directional light data
// Camera
CameraMatrix camera;
if (p_custom_fov) {
if (p_env->sky_custom_fov) {
float near_plane = p_projection.get_z_near();
float far_plane = p_projection.get_z_far();
float aspect = p_projection.get_aspect();
camera.set_perspective(p_custom_fov, aspect, near_plane, far_plane);
camera.set_perspective(p_env->sky_custom_fov, aspect, near_plane, far_plane);
} else {
camera = p_projection;
}
Basis sky_transform = p_env->sky_orientation;
sky_transform.invert();
sky_transform = p_transform.basis * sky_transform;
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::EXPOSURE, p_env->exposure, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TONEMAPPER, p_env->tone_mapper, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::WHITE, p_env->white, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
// Bind a vertex array or else OpenGL complains. We won't actually use it
glBindVertexArray(sky_globals.quad_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glDepthMask(GL_FALSE); // Leave off for transparent pass
glDepthFunc(GL_LESS);
}
Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
@ -674,12 +718,14 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
Environment *env = environment_owner.get_or_null(p_environment);
bool fb_cleared = false;
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
/* Depth Prepass */
glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
glViewport(0, 0, rb->width, rb->height);
if (!fb_cleared) {
glClearDepth(1.0f);
@ -730,7 +776,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
}
if (draw_sky) {
//_draw_sky(sky, render_data.cam_projection, render_data.cam_transform, env->sky_custom_fov, env->bg_energy, env->sky_orientation);
_draw_sky(env, render_data.cam_projection, render_data.cam_transform);
}
if (p_render_buffers.is_valid()) {
@ -1014,9 +1060,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3(RasterizerStorageGLES3 *p_storage) {
String global_defines;
global_defines += "#define MAX_GLOBAL_VARIABLES 256\n"; // TODO: this is arbitrary for now
global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_globals.max_directional_lights) + "\n";
state.sky_shader.initialize(global_defines);
sky_globals.shader_default_version = state.sky_shader.version_create();
state.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.initialize(global_defines);
sky_globals.shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_create();
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
}
{
@ -1038,12 +1084,76 @@ void sky() {
material_storage->material_set_shader(sky_globals.default_material, sky_globals.default_shader);
}
{
sky_globals.fog_shader = material_storage->shader_allocate();
material_storage->shader_initialize(sky_globals.fog_shader);
material_storage->shader_set_code(sky_globals.fog_shader, R"(
// Default clear color sky shader.
shader_type sky;
uniform vec4 clear_color;
void sky() {
COLOR = clear_color.rgb;
}
)");
sky_globals.fog_material = material_storage->material_allocate();
material_storage->material_initialize(sky_globals.fog_material);
material_storage->material_set_shader(sky_globals.fog_material, sky_globals.fog_shader);
}
{
{
//quad buffers
glGenBuffers(1, &sky_globals.quad);
glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
{
const float qv[16] = {
-1,
-1,
0,
0,
-1,
1,
0,
1,
1,
1,
1,
1,
1,
-1,
1,
0,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW);
}
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
glGenVertexArrays(1, &sky_globals.quad_array);
glBindVertexArray(sky_globals.quad_array);
glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, nullptr);
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8));
glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
}
}
RasterizerSceneGLES3::~RasterizerSceneGLES3() {
state.sky_shader.version_free(sky_globals.shader_default_version);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_free(sky_globals.shader_default_version);
storage->free(sky_globals.default_material);
storage->free(sky_globals.default_shader);
storage->free(sky_globals.fog_material);
storage->free(sky_globals.fog_shader);
}
#endif // GLES3_ENABLED

View file

@ -97,6 +97,10 @@ private:
RID shader_default_version;
RID default_material;
RID default_shader;
RID fog_material;
RID fog_shader;
GLuint quad = 0;
GLuint quad_array = 0;
uint32_t max_directional_lights = 4;
uint32_t roughness_layers = 8;
uint32_t ggx_samples = 128;
@ -319,7 +323,7 @@ protected:
Sky *dirty_list = nullptr;
//State to track when radiance cubemap needs updating
//SkyMaterialData *prev_material;
GLES3::SkyMaterialData *prev_material;
Vector3 prev_position = Vector3(0.0, 0.0, 0.0);
float prev_time = 0.0f;
@ -335,17 +339,12 @@ protected:
void _invalidate_sky(Sky *p_sky);
void _update_dirty_skys();
void _draw_sky(Sky *p_sky, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_custom_fov, float p_energy, const Basis &p_sky_orientation);
void _draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform);
public:
RasterizerStorageGLES3 *storage;
RasterizerCanvasGLES3 *canvas;
// References to shaders are needed in public space so they can be accessed in RasterizerStorageGLES3
struct State {
SkyShaderGLES3 sky_shader;
} state;
GeometryInstance *geometry_instance_create(RID p_base) override;
void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override;
void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override;

View file

@ -342,25 +342,13 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder,
*/
RS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
return RS::INSTANCE_NONE;
/*
if (mesh_owner.owns(p_rid)) {
if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
return RS::INSTANCE_MESH;
} else if (light_owner.owns(p_rid)) {
return RS::INSTANCE_LIGHT;
} else if (multimesh_owner.owns(p_rid)) {
return RS::INSTANCE_MULTIMESH;
} else if (immediate_owner.owns(p_rid)) {
return RS::INSTANCE_IMMEDIATE;
} else if (reflection_probe_owner.owns(p_rid)) {
return RS::INSTANCE_REFLECTION_PROBE;
} else if (lightmap_capture_data_owner.owns(p_rid)) {
return RS::INSTANCE_LIGHTMAP_CAPTURE;
} else {
return RS::INSTANCE_NONE;
}
*/
if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
return RS::INSTANCE_MULTIMESH;
}
return RS::INSTANCE_NONE;
}
bool RasterizerStorageGLES3::free(RID p_rid) {
@ -379,80 +367,19 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
} else if (GLES3::MaterialStorage::get_singleton()->owns_material(p_rid)) {
GLES3::MaterialStorage::get_singleton()->material_free(p_rid);
return true;
} else if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
GLES3::MeshStorage::get_singleton()->mesh_free(p_rid);
return true;
} else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
GLES3::MeshStorage::get_singleton()->multimesh_free(p_rid);
return true;
} else if (GLES3::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) {
GLES3::MeshStorage::get_singleton()->mesh_instance_free(p_rid);
return true;
} else {
return false;
}
/*
} else if (skeleton_owner.owns(p_rid)) {
Skeleton *s = skeleton_owner.get_or_null(p_rid);
if (s->update_list.in_list()) {
skeleton_update_list.remove(&s->update_list);
}
for (Set<InstanceBaseDependency *>::Element *E = s->instances.front(); E; E = E->next()) {
E->get()->skeleton = RID();
}
skeleton_allocate(p_rid, 0, false);
if (s->tex_id) {
glDeleteTextures(1, &s->tex_id);
}
skeleton_owner.free(p_rid);
memdelete(s);
return true;
} else if (mesh_owner.owns(p_rid)) {
Mesh *mesh = mesh_owner.get_or_null(p_rid);
mesh->instance_remove_deps();
mesh_clear(p_rid);
while (mesh->multimeshes.first()) {
MultiMesh *multimesh = mesh->multimeshes.first()->self();
multimesh->mesh = RID();
multimesh->dirty_aabb = true;
mesh->multimeshes.remove(mesh->multimeshes.first());
if (!multimesh->update_list.in_list()) {
multimesh_update_list.add(&multimesh->update_list);
}
}
mesh_owner.free(p_rid);
memdelete(mesh);
return true;
} else if (multimesh_owner.owns(p_rid)) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
multimesh->instance_remove_deps();
if (multimesh->mesh.is_valid()) {
Mesh *mesh = mesh_owner.get_or_null(multimesh->mesh);
if (mesh) {
mesh->multimeshes.remove(&multimesh->mesh_list);
}
}
multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_3D, RS::MULTIMESH_COLOR_NONE);
_update_dirty_multimeshes();
multimesh_owner.free(p_rid);
memdelete(multimesh);
return true;
} else if (immediate_owner.owns(p_rid)) {
Immediate *im = immediate_owner.get_or_null(p_rid);
im->instance_remove_deps();
immediate_owner.free(p_rid);
memdelete(im);
return true;
} else if (light_owner.owns(p_rid)) {
Light *light = light_owner.get_or_null(p_rid);
light->instance_remove_deps();

View file

@ -20,6 +20,15 @@ layout(location = 4) in vec2 uv_attrib;
layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
layout(std140) uniform MaterialUniforms{ //ubo:4
#MATERIAL_UNIFORMS
};
#endif
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
@ -38,15 +47,6 @@ out vec2 pixel_size_interp;
#endif
#ifdef MATERIAL_UNIFORMS_USED
layout(std140) uniform MaterialUniforms{
//ubo:4
#MATERIAL_UNIFORMS
};
#endif
#GLOBALS
void main() {

View file

@ -26,9 +26,9 @@ out vec2 uv_interp;
void main() {
// One big triangle to cover the whole screen
vec2 base_arr[3] = vec2[](vec2(-1.0, -2.0), vec2(-1.0, 2.0), vec2(2.0, 2.0));
vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0));
uv_interp = base_arr[gl_VertexID];
gl_Position = vec4(uv_interp, 1.0, 1.0);
gl_Position = vec4(uv_interp, 0.0, 1.0);
}
/* clang-format off */
@ -50,6 +50,8 @@ precision mediump int;
#endif
#endif
#include "tonemap_inc.glsl"
in vec2 uv_interp;
/* clang-format on */
@ -63,12 +65,7 @@ uniform sampler2D half_res; //texunit:-2
uniform sampler2D quarter_res; //texunit:-3
#endif
layout(std140) uniform CanvasData { //ubo:0
mat3 orientation;
vec4 projection;
vec4 position_multiplier;
float time;
float luminance_multiplier;
layout(std140) uniform SceneData { //ubo:0
float pad1;
float pad2;
};
@ -88,15 +85,16 @@ layout(std140) uniform DirectionalLights { //ubo:2
}
directional_lights;
/* clang-format off */
#ifdef MATERIAL_UNIFORMS_USED
layout(std140) uniform MaterialUniforms{
//ubo:3
layout(std140) uniform MaterialUniforms{ //ubo:3
#MATERIAL_UNIFORMS
} material;
};
#endif
/* clang-format on */
#GLOBALS
#ifdef USE_CUBEMAP_PASS
@ -117,6 +115,12 @@ layout(std140) uniform MaterialUniforms{
#define AT_QUARTER_RES_PASS false
#endif
// mat4 is a waste of space, but we don't have an easy way to set a mat3 uniform for now
uniform mat4 orientation;
uniform vec4 projection;
uniform vec3 position;
uniform float time;
layout(location = 0) out vec4 frag_color;
void main() {
@ -128,7 +132,7 @@ void main() {
cube_normal.z = -cube_normal.z;
cube_normal = normalize(cube_normal);
vec2 uv = uv_interp * 0.5 + 0.5;
vec2 uv = gl_FragCoord.xy; // uv_interp * 0.5 + 0.5;
vec2 panorama_coords = vec2(atan(cube_normal.x, cube_normal.z), acos(cube_normal.y));
@ -148,17 +152,17 @@ void main() {
vec3 inverted_cube_normal = cube_normal;
inverted_cube_normal.z *= -1.0;
#ifdef USES_HALF_RES_COLOR
half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * luminance_multiplier;
half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
#endif
#ifdef USES_QUARTER_RES_COLOR
quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * luminance_multiplier;
quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
#endif
#else
#ifdef USES_HALF_RES_COLOR
half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * luminance_multiplier;
half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
#endif
#ifdef USES_QUARTER_RES_COLOR
quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * luminance_multiplier;
quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
#endif
#endif
@ -168,12 +172,19 @@ void main() {
}
frag_color.rgb = color * position_multiplier.w / luminance_multiplier;
frag_color.a = alpha;
// Tonemap before writing as we are writing to an sRGB framebuffer
color *= exposure;
color = apply_tonemapping(color, white);
color = linear_to_srgb(color);
// Blending is disabled for Sky, so alpha doesn't blend
// alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
frag_color.a = 0.0;
}
#ifdef USE_BCS
color = apply_bcs(color, bcs);
#endif
#ifdef USE_COLOR_CORRECTION
color = apply_color_correction(color, color_correction);
#endif
frag_color.rgb = color;
frag_color.a = alpha;
}

View file

@ -0,0 +1,117 @@
#ifdef USE_BCS
uniform vec3 bcs;
#endif
#ifdef USE_COLOR_CORRECTION
#ifdef USE_1D_LUT
uniform sampler2D source_color_correction; //texunit:-1
#else
uniform sampler3D source_color_correction; //texunit:-1
#endif
#endif
// These could be grouped into some form of SceneData UBO along with time, will have to test performance though
uniform int tonemapper;
uniform float exposure;
uniform float white;
vec3 apply_bcs(vec3 color, vec3 bcs) {
color = mix(vec3(0.0), color, bcs.x);
color = mix(vec3(0.5), color, bcs.y);
color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z);
return color;
}
#ifdef USE_COLOR_CORRECTION
#ifdef USE_1D_LUT
vec3 apply_color_correction(vec3 color) {
color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r;
color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g;
color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b;
return color;
}
#else
vec3 apply_color_correction(vec3 color) {
return textureLod(source_color_correction, color, 0.0).rgb;
}
#endif
#endif
vec3 tonemap_filmic(vec3 color, float p_white) {
// exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers
// also useful to scale the input to the range that the tonemapper is designed for (some require very high input values)
// has no effect on the curve's general shape or visual properties
const float exposure_bias = 2.0f;
const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance
const float B = 0.30f * exposure_bias;
const float C = 0.10f;
const float D = 0.20f;
const float E = 0.01f;
const float F = 0.30f;
vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
float p_white_tonemapped = ((p_white * (A * p_white + C * B) + D * E) / (p_white * (A * p_white + B) + D * F)) - E / F;
return color_tonemapped / p_white_tonemapped;
}
// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
// (MIT License).
vec3 tonemap_aces(vec3 color, float p_white) {
const float exposure_bias = 1.8f;
const float A = 0.0245786f;
const float B = 0.000090537f;
const float C = 0.983729f;
const float D = 0.432951f;
const float E = 0.238081f;
// Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
const mat3 rgb_to_rrt = mat3(
vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));
const mat3 odt_to_rgb = mat3(
vec3(1.60475f, -0.53108f, -0.07367f),
vec3(-0.10208f, 1.10813f, -0.00605f),
vec3(-0.00327f, -0.07276f, 1.07602f));
color *= rgb_to_rrt;
vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
color_tonemapped *= odt_to_rgb;
p_white *= exposure_bias;
float p_white_tonemapped = (p_white * (p_white + A) - B) / (p_white * (C * p_white + D) + E);
return color_tonemapped / p_white_tonemapped;
}
vec3 tonemap_reinhard(vec3 color, float p_white) {
return (p_white * color + color) / (color * p_white + p_white);
}
vec3 linear_to_srgb(vec3 color) {
//if going to srgb, clamp from 0 to 1.
color = clamp(color, vec3(0.0), vec3(1.0));
const vec3 a = vec3(0.055f);
return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}
#define TONEMAPPER_LINEAR 0
#define TONEMAPPER_REINHARD 1
#define TONEMAPPER_FILMIC 2
#define TONEMAPPER_ACES 3
vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always outputs clamped [0;1] color
// Ensure color values passed to tonemappers are positive.
// They can be negative in the case of negative lights, which leads to undesired behavior.
if (tonemapper == TONEMAPPER_LINEAR) {
return color;
} else if (tonemapper == TONEMAPPER_REINHARD) {
return tonemap_reinhard(max(vec3(0.0f), color), p_white);
} else if (tonemapper == TONEMAPPER_FILMIC) {
return tonemap_filmic(max(vec3(0.0f), color), p_white);
} else { // TONEMAPPER_ACES
return tonemap_aces(max(vec3(0.0f), color), p_white);
}
}

View file

@ -1278,13 +1278,13 @@ MaterialStorage::MaterialStorage() {
shader_data_request_func[RS::SHADER_SPATIAL] = nullptr;
shader_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_shader_func;
shader_data_request_func[RS::SHADER_PARTICLES] = nullptr;
shader_data_request_func[RS::SHADER_SKY] = nullptr;
shader_data_request_func[RS::SHADER_SKY] = _create_sky_shader_func;
shader_data_request_func[RS::SHADER_FOG] = nullptr;
material_data_request_func[RS::SHADER_SPATIAL] = nullptr;
material_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_material_func;
material_data_request_func[RS::SHADER_PARTICLES] = nullptr;
material_data_request_func[RS::SHADER_SKY] = nullptr;
material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func;
material_data_request_func[RS::SHADER_FOG] = nullptr;
static_assert(sizeof(GlobalVariables::Value) == 16);
@ -1365,7 +1365,7 @@ MaterialStorage::MaterialStorage() {
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
actions.base_texture_binding_index = 1;
actions.base_texture_binding_index = 0;
actions.base_uniform_string = "";
actions.global_buffer_array_variable = "";
@ -1626,10 +1626,10 @@ ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["COLOR"] = "color";
actions.renames["ALPHA"] = "alpha";
actions.renames["EYEDIR"] = "cube_normal";
actions.renames["POSITION"] = "params.position_multiplier.xyz";
actions.renames["POSITION"] = "position";
actions.renames["SKY_COORDS"] = "panorama_coords";
actions.renames["SCREEN_UV"] = "uv";
actions.renames["TIME"] = "params.time";
actions.renames["TIME"] = "time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
@ -1660,15 +1660,12 @@ ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = 1;
actions.base_uniform_string = "material.";
actions.base_varying_index = 10;
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
@ -2739,7 +2736,8 @@ void MaterialStorage::material_update_dependency(RID p_material, RendererStorage
}
}
// Canvas Shader Data
/* Canvas Shader Data */
void CanvasShaderData::set_code(const String &p_code) {
// compile the shader
@ -2982,4 +2980,227 @@ GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) {
return material_data;
}
////////////////////////////////////////////////////////////////////////////////
// SKY SHADER
void SkyShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
if (code.is_empty()) {
return; //just invalid, but no error
}
ShaderCompiler::GeneratedCode gen_code;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["sky"] = ShaderCompiler::STAGE_FRAGMENT;
uses_time = false;
uses_half_res = false;
uses_quarter_res = false;
uses_position = false;
uses_light = false;
actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
actions.usage_flag_pointers["TIME"] = &uses_time;
actions.usage_flag_pointers["POSITION"] = &uses_position;
actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
actions.uniforms = &uniforms;
Error err = MaterialStorage::get_singleton()->shaders.compiler_sky.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = MaterialStorage::get_singleton()->shaders.sky_shader.version_create();
}
#if 0
print_line("**compiling shader:");
print_line("**defines:\n");
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
// print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
// print_line("\n**vertex_code:\n" + gen_code.vertex);
print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
print_line("\n**fragment_code:\n" + gen_code.fragment);
print_line("\n**light_code:\n" + gen_code.light);
#endif
Vector<StringName> texture_uniform_names;
for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
}
MaterialStorage::get_singleton()->shaders.sky_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.sky_shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
valid = true;
}
void SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
if (!p_texture.is_valid()) {
if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
default_texture_params[p_name].erase(p_index);
if (default_texture_params[p_name].is_empty()) {
default_texture_params.erase(p_name);
}
}
} else {
if (!default_texture_params.has(p_name)) {
default_texture_params[p_name] = Map<int, RID>();
}
default_texture_params[p_name][p_index] = p_texture;
}
}
void SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
Map<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
if (E.value.texture_order >= 0) {
order[E.value.texture_order + 100000] = E.key;
} else {
order[E.value.order] = E.key;
}
}
for (const KeyValue<int, StringName> &E : order) {
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);
}
}
void SkyShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererMaterialStorage::InstanceShaderParam p;
p.info = ShaderLanguage::uniform_to_property_info(E.value);
p.info.name = E.key; //supply name
p.index = E.value.instance_index;
p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
bool SkyShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
return uniforms[p_param].texture_order >= 0;
}
bool SkyShaderData::is_animated() const {
return false;
}
bool SkyShaderData::casts_shadows() const {
return false;
}
Variant SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
RS::ShaderNativeSourceCode SkyShaderData::get_native_source_code() const {
return MaterialStorage::get_singleton()->shaders.sky_shader.version_get_native_source_code(version);
}
SkyShaderData::SkyShaderData() {
valid = false;
}
SkyShaderData::~SkyShaderData() {
if (version.is_valid()) {
MaterialStorage::get_singleton()->shaders.sky_shader.version_free(version);
}
}
GLES3::ShaderData *GLES3::_create_sky_shader_func() {
SkyShaderData *shader_data = memnew(SkyShaderData);
return shader_data;
}
////////////////////////////////////////////////////////////////////////////////
// Sky material
void SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
}
SkyMaterialData::~SkyMaterialData() {
}
GLES3::MaterialData *GLES3::_create_sky_material_func(ShaderData *p_shader) {
SkyMaterialData *material_data = memnew(SkyMaterialData);
material_data->shader_data = static_cast<SkyShaderData *>(p_shader);
//update will happen later anyway so do nothing.
return material_data;
}
void SkyMaterialData::bind_uniforms() {
// Bind Material Uniforms
glBindBufferBase(GL_UNIFORM_BUFFER, 3, uniform_buffer);
RID *textures = texture_cache.ptrw();
ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
for (int ti = 0; ti < texture_cache.size(); ti++) {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
glActiveTexture(GL_TEXTURE0 + ti);
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
// Set sampler state here as the same texture can be used in multiple places with different flags
// Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
texture->gl_set_filter(filter);
texture->gl_set_repeat(repeat);
}
}
#endif // !GLES3_ENABLED

View file

@ -200,6 +200,55 @@ struct CanvasMaterialData : public MaterialData {
MaterialData *_create_canvas_material_func(ShaderData *p_shader);
/* Sky Materials */
struct SkyShaderData : public ShaderData {
bool valid;
RID version;
Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size;
String path;
String code;
Map<StringName, Map<int, RID>> default_texture_params;
bool uses_time;
bool uses_position;
bool uses_half_res;
bool uses_quarter_res;
bool uses_light;
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
SkyShaderData();
virtual ~SkyShaderData();
};
ShaderData *_create_sky_shader_func();
struct SkyMaterialData : public MaterialData {
SkyShaderData *shader_data = nullptr;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual void bind_uniforms();
virtual ~SkyMaterialData();
};
MaterialData *_create_sky_material_func(ShaderData *p_shader);
/* Global variable structs */
struct GlobalVariables {
enum {

View file

@ -388,6 +388,9 @@ public:
/* MESH INSTANCE API */
MeshInstance *get_mesh_instance(RID p_rid) { return mesh_instance_owner.get_or_null(p_rid); };
bool owns_mesh_instance(RID p_rid) { return mesh_instance_owner.owns(p_rid); };
virtual RID mesh_instance_create(RID p_base) override;
virtual void mesh_instance_free(RID p_rid) override;
virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
@ -431,6 +434,9 @@ public:
/* MULTIMESH API */
MultiMesh *get_multimesh(RID p_rid) { return multimesh_owner.get_or_null(p_rid); };
bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); };
virtual RID multimesh_allocate() override;
virtual void multimesh_initialize(RID p_rid) override;
virtual void multimesh_free(RID p_rid) override;
@ -483,6 +489,9 @@ public:
/* SKELETON API */
Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
bool owns_skeleton(RID p_rid) { return skeleton_owner.owns(p_rid); };
virtual RID skeleton_allocate() override;
virtual void skeleton_initialize(RID p_rid) override;
virtual void skeleton_free(RID p_rid) override;

View file

@ -95,9 +95,9 @@ public:
static void make_current() {
_create_func = _create_current;
low_end = true;
}
bool is_low_end() const override { return true; }
uint64_t get_frame_number() const override { return frame; }
double get_frame_delta_time() const override { return delta; }

View file

@ -35,6 +35,7 @@
#include "core/string/print_string.h"
RendererCompositor *(*RendererCompositor::_create_func)() = nullptr;
bool RendererCompositor::low_end = false;
RendererCompositor *RendererCompositor::create() {
return _create_func();

View file

@ -71,6 +71,7 @@ private:
protected:
static RendererCompositor *(*_create_func)();
bool back_end = false;
static bool low_end;
public:
static RendererCompositor *create();
@ -97,7 +98,7 @@ public:
virtual uint64_t get_frame_number() const = 0;
virtual double get_frame_delta_time() const = 0;
_FORCE_INLINE_ virtual bool is_low_end() const { return back_end; };
static bool is_low_end() { return low_end; };
virtual bool is_xr_enabled() const;
RendererCompositor();

View file

@ -131,6 +131,7 @@ public:
static void make_current() {
_create_func = _create_current;
low_end = false;
}
static RendererCompositorRD *singleton;

View file

@ -321,11 +321,7 @@ void RenderingServerDefault::set_debug_generate_wireframes(bool p_generate) {
}
bool RenderingServerDefault::is_low_end() const {
// FIXME: Commented out when rebasing vulkan branch on master,
// causes a crash, it seems rasterizer is not initialized yet the
// first time it's called.
//return RSG::rasterizer->is_low_end();
return false;
return RendererCompositor::is_low_end();
}
void RenderingServerDefault::_thread_exit() {

View file

@ -113,7 +113,9 @@ public:
_changes_changed();
#else
_FORCE_INLINE_ static void redraw_request() { changes++; }
_FORCE_INLINE_ static void redraw_request() {
changes++;
}
#endif
#define WRITE_ACTION redraw_request();

View file

@ -48,8 +48,8 @@ static String _mktab(int p_level) {
static String _typestr(SL::DataType p_type) {
String type = ShaderLanguage::get_datatype_name(p_type);
if (ShaderLanguage::is_sampler_type(p_type)) {
type = type.replace("sampler", "texture"); //we use textures instead of samplers
if (!RS::get_singleton()->is_low_end() && ShaderLanguage::is_sampler_type(p_type)) {
type = type.replace("sampler", "texture"); //we use textures instead of samplers in Vulkan GLSL
}
return type;
}
@ -538,7 +538,11 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
continue; // Instances are indexed directly, don't need index uniforms.
}
if (SL::is_sampler_type(uniform.type)) {
ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") uniform ";
// Texture layouts are different for OpenGL GLSL and Vulkan GLSL
if (!RS::get_singleton()->is_low_end()) {
ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") ";
}
ucode += "uniform ";
}
bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
@ -1125,8 +1129,8 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
code += ", ";
}
String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
if (is_texture_func && i == 1) {
//need to map from texture to sampler in order to sample
if (!RS::get_singleton()->is_low_end() && is_texture_func && i == 1) {
//need to map from texture to sampler in order to sample when using Vulkan GLSL
StringName texture_uniform;
bool correct_texture_uniform = false;