diff options
Diffstat (limited to 'servers/visual')
| -rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp | 9 | ||||
| -rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_scene_rd.h | 7 | ||||
| -rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_storage_rd.h | 2 | ||||
| -rw-r--r-- | servers/visual/rasterizer_rd/shader_rd.cpp | 121 | ||||
| -rw-r--r-- | servers/visual/rasterizer_rd/shader_rd.h | 13 | ||||
| -rw-r--r-- | servers/visual/rasterizer_rd/shaders/SCsub | 1 | ||||
| -rw-r--r-- | servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl | 241 | ||||
| -rw-r--r-- | servers/visual/rendering_device.h | 20 |
8 files changed, 407 insertions, 7 deletions
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index 7bb615eda9..888568e21a 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -1469,6 +1469,15 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { sky_ggx_samples_realtime = GLOBAL_GET("rendering/quality/reflections/ggx_samples_realtime"); sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); // sky_use_cubemap_array = false; + + { + String defines = ""; + Vector<String> versions; + versions.push_back(""); + giprobe_lighting_shader.initialize(versions, defines); + giprobe_lighting_shader_version = giprobe_lighting_shader.version_create(); + giprobe_lighting_shader_version_shader = giprobe_lighting_shader.version_get_shader(giprobe_lighting_shader_version, 0); + } } RasterizerSceneRD::~RasterizerSceneRD() { diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h index a1897cabe1..97e1d08d90 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h @@ -4,6 +4,7 @@ #include "core/rid_owner.h" #include "servers/visual/rasterizer.h" #include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h" +#include "servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl.gen.h" #include "servers/visual/rendering_device.h" class RasterizerSceneRD : public RasterizerScene { @@ -108,6 +109,12 @@ private: mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; + /* GIPROBE INSTANCE */ + + GiprobeLightingShaderRD giprobe_lighting_shader; + RID giprobe_lighting_shader_version; + RID giprobe_lighting_shader_version_shader; + /* SHADOW ATLAS */ struct ShadowAtlas { diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h index 397e3c1b95..6cdc21c2f0 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -778,6 +778,8 @@ public: _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND_V(!skeleton, RID()); + ERR_FAIL_COND_V(skeleton->size == 0, RID()); if (skeleton->use_2d) { return RID(); } diff --git a/servers/visual/rasterizer_rd/shader_rd.cpp b/servers/visual/rasterizer_rd/shader_rd.cpp index 58596f6a72..98e0c99c2e 100644 --- a/servers/visual/rasterizer_rd/shader_rd.cpp +++ b/servers/visual/rasterizer_rd/shader_rd.cpp @@ -33,11 +33,11 @@ #include "rasterizer_rd.h" #include "servers/visual/rendering_device.h" -void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name) { +void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) { name = p_name; //split vertex and shader code (thank you, shader compiler programmers from you know what company). - { + if (p_vertex_code) { String defines_tag = "\nVERSION_DEFINES"; String globals_tag = "\nVERTEX_SHADER_GLOBALS"; String material_tag = "\nMATERIAL_UNIFORMS"; @@ -79,7 +79,7 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con } } - { + if (p_fragment_code) { String defines_tag = "\nVERSION_DEFINES"; String globals_tag = "\nFRAGMENT_SHADER_GLOBALS"; String material_tag = "\nMATERIAL_UNIFORMS"; @@ -135,6 +135,50 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con } } } + + if (p_compute_code) { + is_compute = true; + + String defines_tag = "\nVERSION_DEFINES"; + String globals_tag = "\nCOMPUTE_SHADER_GLOBALS"; + String material_tag = "\nMATERIAL_UNIFORMS"; + String code_tag = "\nCOMPUTE_SHADER_CODE"; + String code = p_compute_code; + + int cpos = code.find(defines_tag); + if (cpos != -1) { + compute_codev = code.substr(0, cpos).ascii(); + code = code.substr(cpos + defines_tag.length(), code.length()); + } + + cpos = code.find(material_tag); + + if (cpos == -1) { + compute_code0 = code.ascii(); + } else { + compute_code0 = code.substr(0, cpos).ascii(); + code = code.substr(cpos + material_tag.length(), code.length()); + + cpos = code.find(globals_tag); + + if (cpos == -1) { + compute_code1 = code.ascii(); + } else { + + compute_code1 = code.substr(0, cpos).ascii(); + String code2 = code.substr(cpos + globals_tag.length(), code.length()); + + cpos = code2.find(code_tag); + if (cpos == -1) { + compute_code2 = code2.ascii(); + } else { + + compute_code2 = code2.substr(0, cpos).ascii(); + compute_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); + } + } + } + } } RID ShaderRD::version_create() { @@ -171,7 +215,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { RD::ShaderStage current_stage = RD::SHADER_STAGE_VERTEX; bool build_ok = true; - { + if (!is_compute) { //vertex stage StringBuilder builder; @@ -211,7 +255,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { } } - if (build_ok) { + if (!is_compute && build_ok) { //fragment stage current_stage = RD::SHADER_STAGE_FRAGMENT; @@ -256,9 +300,50 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { } } + if (is_compute) { + //compute stage + current_stage = RD::SHADER_STAGE_COMPUTE; + + StringBuilder builder; + + builder.append(compute_codev.get_data()); // version info (if exists) + builder.append("\n"); //make sure defines begin at newline + builder.append(general_defines.get_data()); + builder.append(variant_defines[p_variant].get_data()); + + for (int j = 0; j < p_version->custom_defines.size(); j++) { + builder.append(p_version->custom_defines[j].get_data()); + } + + builder.append(compute_code0.get_data()); //first part of compute + + builder.append(p_version->uniforms.get_data()); //uniforms (same for compute and fragment) + + builder.append(compute_code1.get_data()); //second part of compute + + builder.append(p_version->compute_globals.get_data()); // compute globals + + builder.append(compute_code2.get_data()); //third part of compute + + builder.append(p_version->compute_code.get_data()); // code + + builder.append(compute_code3.get_data()); //fourth of compute + + current_source = builder.as_string(); + RD::ShaderStageData stage; + stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error); + if (stage.spir_v.size() == 0) { + build_ok = false; + } else { + + stage.shader_stage = RD::SHADER_STAGE_COMPUTE; + stages.push_back(stage); + } + } + if (!build_ok) { variant_set_mutex.lock(); //properly print the errors - ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment") + " shader, variant #" + itos(p_variant) + " (" + variant_defines[p_variant].get_data() + ")."); + ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_COMPUTE ? "Compute " : (current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment")) + " shader, variant #" + itos(p_variant) + " (" + variant_defines[p_variant].get_data() + ")."); ERR_PRINT(error); #ifdef DEBUG_ENABLED @@ -319,6 +404,8 @@ void ShaderRD::_compile_version(Version *p_version) { void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines) { + ERR_FAIL_COND(is_compute); + Version *version = version_owner.getornull(p_version); ERR_FAIL_COND(!version); version->vertex_globals = p_vertex_globals.utf8(); @@ -340,6 +427,28 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S } } +void ShaderRD::version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines) { + + ERR_FAIL_COND(!is_compute); + + Version *version = version_owner.getornull(p_version); + ERR_FAIL_COND(!version); + version->compute_globals = p_compute_globals.utf8(); + version->compute_code = p_compute_code.utf8(); + version->uniforms = p_uniforms.utf8(); + + version->custom_defines.clear(); + for (int i = 0; i < p_custom_defines.size(); i++) { + version->custom_defines.push_back(p_custom_defines[i].utf8()); + } + + version->dirty = true; + if (version->initialize_needed) { + _compile_version(version); + version->initialize_needed = false; + } +} + bool ShaderRD::version_is_valid(RID p_version) { Version *version = version_owner.getornull(p_version); ERR_FAIL_COND_V(!version, false); diff --git a/servers/visual/rasterizer_rd/shader_rd.h b/servers/visual/rasterizer_rd/shader_rd.h index 81169343d6..4d1e9576ce 100644 --- a/servers/visual/rasterizer_rd/shader_rd.h +++ b/servers/visual/rasterizer_rd/shader_rd.h @@ -55,6 +55,8 @@ class ShaderRD { CharString uniforms; CharString vertex_globals; CharString vertex_code; + CharString compute_globals; + CharString compute_code; CharString fragment_light; CharString fragment_globals; CharString fragment_code; @@ -89,16 +91,25 @@ class ShaderRD { CharString vertex_code2; CharString vertex_code3; + bool is_compute = false; + + CharString compute_codev; //for version and extensions + CharString compute_code0; + CharString compute_code1; + CharString compute_code2; + CharString compute_code3; + const char *name; protected: ShaderRD() {} - void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name); + void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name); public: RID version_create(); void version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines); + void version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines); _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub index b1fa9cd3f4..660523e29f 100644 --- a/servers/visual/rasterizer_rd/shaders/SCsub +++ b/servers/visual/rasterizer_rd/shaders/SCsub @@ -11,4 +11,5 @@ if 'RD_GLSL' in env['BUILDERS']: env.RD_GLSL('sky.glsl'); env.RD_GLSL('tonemap.glsl'); env.RD_GLSL('copy.glsl'); + env.RD_GLSL('giprobe_lighting.glsl'); diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl b/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl new file mode 100644 index 0000000000..cec25f86f9 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/giprobe_lighting.glsl @@ -0,0 +1,241 @@ +[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +#define NO_CHILDREN 0xFFFFFFFF +#define GREY_VEC vec3(0.33333,0.33333,0.33333) + +struct CellPosition { + uint children[8]; +}; + + +layout(set=0,binding=1,std140) buffer CellPositions { + CellPosition data[]; +} cell_positions; + +struct CellMaterial { + uint position; // xyz 10 bits + uint albedo; //rgb albedo + uint emission; //rgb normalized with e as multiplier + uint normal; //RGB normal encoded +}; + +layout(set=0,binding=2,std140) buffer CellMaterials { + CellMaterial data[]; +} cell_materials; + +#define LIGHT_TYPE_DIRECTIONAL 0 +#define LIGHT_TYPE_OMNI 1 +#define LIGHT_TYPE_SPOT 2 + +struct Light { + + uint type; + float energy; + float radius; + float attenuation; + + vec3 color; + float spot_angle_radians; + + float advance; + float max_length; + uint pad0; + uint pad2; + + vec3 position; + float spot_attenuation; + + + vec3 direction; + bool visible; + + vec4 clip_planes[3]; +}; + +layout(set=0,binding=3,std140) buffer Lights { + Light data[]; +} lights; + + +layout(set=0,binding=4,std140) uniform Params { + vec3 limits; + float max_length; + uint size; + uint stack_size; + uint light_count; + float emission_scale; +} params; + + +layout (rgba8,set=0,binding=5) uniform restrict writeonly image3D color_tex; + + +uint raymarch(float distance,float distance_adv,vec3 from,vec3 direction) { + + uint result = NO_CHILDREN; + + while (distance > -distance_adv) { //use this to avoid precision errors + + uint cell = 0; + + ivec3 pos = ivec3(from); + ivec3 ofs = ivec3(0); + ivec3 half_size = ivec3(params.size) / 2; + if (any(lessThan(pos,ivec3(0))) || any(greaterThanEqual(pos,ivec3(params.size)))) { + return NO_CHILDREN; //outside range + } + + for (int i = 0; i < params.stack_size - 1; i++) { + + bvec3 greater = greaterThanEqual(pos,ofs+half_size); + + ofs += mix(ivec3(0),half_size,greater); + + uint child = 0; //wonder if this can be done faster + if (greater.x) { + child|=1; + } + if (greater.y) { + child|=2; + } + if (greater.z) { + child|=4; + } + + cell = cell_positions.data[cell].children[child]; + if (cell == NO_CHILDREN) + break; + + half_size >>= ivec3(1); + } + + if ( cell != NO_CHILDREN) { + return cell; //found cell! + } + + from += direction * distance_adv; + distance -= distance_adv; + } + + return NO_CHILDREN; +} + +bool compute_light_vector(uint light,uint cell, vec3 pos,out float attenuation, out vec3 light_pos) { + + if (lights.data[light].type==LIGHT_TYPE_DIRECTIONAL) { + + light_pos = pos - lights.data[light].direction * params.max_length; + attenuation = 1.0; + + } else { + + light_pos = lights.data[light].position; + float distance = length(pos - light_pos); + if (distance >= lights.data[light].radius) { + return false; + } + + attenuation = pow( distance / lights.data[light].radius + 0.0001, lights.data[light].attenuation ); + + + if (lights.data[light].type==LIGHT_TYPE_SPOT) { + + vec3 rel = normalize(pos - light_pos); + float angle = acos(dot(rel,lights.data[light].direction)); + if (angle > lights.data[light].spot_angle_radians) { + return false; + } + + float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1); + attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation); + } + } + + return true; +} + +void main() { + + uint cell_index = gl_GlobalInvocationID.x; + + uvec3 posu = uvec3(cell_materials.data[cell_index].position&0x3FF,(cell_materials.data[cell_index].position>>10)&0x3FF,cell_materials.data[cell_index].position>>20); + vec3 pos = vec3(posu); + + vec3 emission = vec3(ivec3(cell_materials.data[cell_index].emission&0x3FF,(cell_materials.data[cell_index].emission>>10)&0x7FF,cell_materials.data[cell_index].emission>>21)) * params.emission_scale; + vec4 albedo = unpackUnorm4x8(cell_materials.data[cell_index].albedo); + vec4 normal = unpackSnorm4x8(cell_materials.data[cell_index].normal); //w >0.5 means, all directions + +#ifdef MODE_ANISOTROPIC + vec3 accum[6]=vec3[](vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0)); + const vec3 accum_dirs[6]=vec3[](vec3(1.0,0.0,0.0),vec3(-1.0,0.0,0.0),vec3(0.0,1.0,0.0),vec3(0.0,-1.0,0.0),vec3(0.0,0.0,1.0),vec3(0.0,0.0,-1.0)); +#else + vec3 accum = vec3(0); +#endif + + for(uint i=0;i<params.light_count;i++) { + + float attenuation; + vec3 light_pos; + + if (!compute_light_vector(i,cell_index,pos,attenuation,light_pos)) { + continue; + } + + float distance_adv = lights.data[i].advance; + + vec3 light_dir = pos - light_pos; + float distance = length(light_dir); + + light_dir=normalize(light_dir); + + distance += distance_adv - mod(distance, distance_adv); //make it reach the center of the box always + + vec3 from = pos - light_dir * distance; //approximate + + if (normal.w < 0.5 && dot(normal.xyz,light_dir)>=0) { + continue; //not facing the light + } + + uint result = raymarch(distance,distance_adv,from,lights.data[i].direction); + + if (result != cell_index) { + continue; //was occluded + } + + vec3 light = lights.data[i].color * albedo.rgb * attenuation; + +#ifdef MODE_ANISOTROPIC + for(uint j=0;j<6;j++) { + accum[j]+=max(0.0,dot(accum_dir,-light_dir))*light+emission; + } +#else + if (normal.w < 0.5) { + accum+=max(0.0,dot(normal.xyz,-light_dir))*light+emission; + } else { + //all directions + accum+=light+emission; + } +#endif + + } + +#ifdef MODE_ANISOTROPIC + + vec3 accum_total = accum[0]+accum[1]+accum[2]+accum[3]+accum[4]+accum[5]; + float accum_total_energy = max(dot(accum_total,GREY_VEC),0.00001); + vec3 iso_positive = vec3(dot(aniso[0],GREY_VEC),dot(aniso[2],GREY_VEC),dot(aniso[4],GREY_VEC))/vec3(accum_total_energy); + vec3 iso_negative = vec3(dot(aniso[1],GREY_VEC),dot(aniso[3],GREY_VEC),dot(aniso[5],GREY_VEC))/vec3(accum_total_energy); + + //store in 3D textures, total color, and isotropic magnitudes +#else + //store in 3D texture pos, accum + imageStore(color_tex,ivec3(posu),vec4(accum,albedo.a)); +#endif + +} diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h index 859a9e798c..d0afb3f13b 100644 --- a/servers/visual/rendering_device.h +++ b/servers/visual/rendering_device.h @@ -882,6 +882,13 @@ public: virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0) = 0; virtual bool render_pipeline_is_valid(RID p_pipeline) = 0; + /**************************/ + /**** COMPUTE PIPELINE ****/ + /**************************/ + + virtual RID compute_pipeline_create(RID p_shader) = 0; + virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0; + /****************/ /**** SCREEN ****/ /****************/ @@ -930,6 +937,19 @@ public: virtual void draw_list_end() = 0; + /***********************/ + /**** COMPUTE LISTS ****/ + /***********************/ + + typedef int64_t ComputeListID; + + virtual ComputeListID compute_list_begin() = 0; + virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) = 0; + virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0; + virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) = 0; + virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0; + virtual void compute_list_end() = 0; + /***************/ /**** FREE! ****/ /***************/ |