diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 265dfc69d4f..82ab8d6c2fa 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -3041,7 +3041,7 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Poo ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; - _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); if (p_data.size()) { uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); @@ -3202,7 +3202,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff #else index_buffer.max_index = 0xFFFFFFFF; #endif - _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); if (p_data.size()) { uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); @@ -3485,8 +3485,9 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages push_constant.push_constant_size = 0; push_constant.push_constants_vk_stage = 0; - Vector vertex_input_locations; - int fragment_outputs = 0; + uint32_t vertex_input_mask = 0; + + uint32_t fragment_outputs = 0; uint32_t stages_processed = 0; @@ -3660,6 +3661,29 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages } } + if (stage == SHADER_STAGE_VERTEX) { + + uint32_t iv_count = 0; + result = spvReflectEnumerateInputVariables(&module, &iv_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating input variables."); + + if (iv_count) { + Vector input_vars; + input_vars.resize(iv_count); + + result = spvReflectEnumerateOutputVariables(&module, &iv_count, input_vars.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining input variables."); + + for (uint32_t j = 0; j < iv_count; j++) { + if (input_vars[j]) { + vertex_input_mask |= (1 << uint32_t(input_vars[j]->location)); + } + } + } + } + if (stage == SHADER_STAGE_FRAGMENT) { uint32_t ov_count = 0; @@ -3726,7 +3750,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages Shader shader; - shader.vertex_input_locations = vertex_input_locations; + shader.vertex_input_mask = vertex_input_mask; shader.fragment_outputs = fragment_outputs; shader.push_constant = push_constant; @@ -3871,10 +3895,10 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages return shader_owner.make_rid(shader); } -Vector RenderingDeviceVulkan::shader_get_vertex_input_locations_used(RID p_shader) { +uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { const Shader *shader = shader_owner.getornull(p_shader); - ERR_FAIL_COND_V(!shader, Vector()); - return shader->vertex_input_locations; + ERR_FAIL_COND_V(!shader, 0); + return shader->vertex_input_mask; } /******************/ @@ -3929,7 +3953,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID()); TextureBuffer texture_buffer; - Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); ERR_FAIL_COND_V(err != OK, RID()); if (p_data.size()) { @@ -4488,6 +4512,49 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint return err; } +PoolVector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { + + Buffer *buffer = NULL; + if (vertex_buffer_owner.owns(p_buffer)) { + buffer = vertex_buffer_owner.getornull(p_buffer); + } else if (index_buffer_owner.owns(p_buffer)) { + buffer = index_buffer_owner.getornull(p_buffer); + } else if (texture_buffer_owner.owns(p_buffer)) { + buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; + } else { + ERR_FAIL_V_MSG(PoolVector(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving."); + } + + VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + Buffer tmp_buffer; + _buffer_allocate(&tmp_buffer, buffer->size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + VkBufferCopy region; + region.srcOffset = 0; + region.dstOffset = 0; + region.size = buffer->size; + vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, ®ion); //dst buffer is in CPU, but I wonder if src buffer needs a barrier for this.. + //flush everything so memory can be safely mapped + _flush(true, false); + + void *buffer_mem; + VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); + if (vkerr) { + ERR_FAIL_V(PoolVector()); + } + + PoolVector buffer_data; + { + + buffer_data.resize(buffer->size); + PoolVector::Write w = buffer_data.write(); + copymem(w.ptr(), buffer_mem, buffer->size); + } + + _buffer_free(&tmp_buffer); + + return buffer_data; +} + /*************************/ /**** RENDER PIPELINE ****/ /*************************/ @@ -4523,17 +4590,19 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma pipeline_vertex_input_state_create_info = vd.create_info; //validate with inputs - for (int i = 0; i < shader->vertex_input_locations.size(); i++) { - uint32_t location = shader->vertex_input_locations[i]; + for (uint32_t i = 0; i < 32; i++) { + if (!(shader->vertex_input_mask & (1 << i))) { + continue; + } bool found = false; for (int j = 0; j < vd.vertex_formats.size(); j++) { - if (vd.vertex_formats[j].location == location) { + if (vd.vertex_formats[j].location == i) { found = true; } } ERR_FAIL_COND_V_MSG(!found, RID(), - "Shader vertex input location (" + itos(location) + ") not provided in vertex input description for pipeline creation."); + "Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation."); } } else { @@ -4546,8 +4615,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0; pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = NULL; - ERR_FAIL_COND_V_MSG(shader->vertex_input_locations.size(), RID(), - "Shader contains vertex inputs (" + itos(shader->vertex_input_locations.size()) + ") but no vertex input description was provided for pipeline creation."); + ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(), + "Shader contains vertex inputs, but no vertex input description was provided for pipeline creation."); } //input assembly diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index af144a7f6bc..2cd72fbac46 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -506,7 +506,7 @@ class RenderingDeviceVulkan : public RenderingDevice { VkDescriptorSetLayout descriptor_set_layout; }; - Vector vertex_input_locations; //inputs used, this is mostly for validation + uint32_t vertex_input_mask; //inputs used, this is mostly for validation int fragment_outputs; struct PushConstant { @@ -894,7 +894,7 @@ public: /****************/ virtual RID shader_create(const Vector &p_stages); - virtual Vector shader_get_vertex_input_locations_used(RID p_shader); + virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader); /*****************/ /**** UNIFORM ****/ @@ -908,6 +908,7 @@ public: virtual bool uniform_set_is_valid(RID p_uniform_set); virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false); //works for any buffer + virtual PoolVector buffer_get_data(RID p_buffer); /*************************/ /**** RENDER PIPELINE ****/ diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 856bfe5f44e..f4749da309a 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -363,8 +363,6 @@ void EditorNode::_notification(int p_what) { Engine::get_singleton()->set_editor_hint(true); OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec"))); - get_tree()->get_root()->set_usage(Viewport::USAGE_2D_NO_SAMPLING); //reduce memory usage - get_tree()->get_root()->set_disable_3d(true); get_tree()->get_root()->set_as_audio_listener(false); get_tree()->get_root()->set_as_audio_listener_2d(false); get_tree()->set_auto_accept_quit(false); @@ -6059,7 +6057,6 @@ EditorNode::EditorNode() { scene_root = memnew(Viewport); //scene_root->set_usage(Viewport::USAGE_2D); canvas BG mode prevents usage of this as 2D - scene_root->set_disable_3d(true); VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true); scene_root->set_disable_input(true); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 69a2344bc05..ce847d02eb7 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -68,7 +68,6 @@ Vector > EditorInterface::make_mesh_previews(const Vectorviewport_create(); VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ALWAYS); - VS::get_singleton()->viewport_set_vflip(viewport, true); VS::get_singleton()->viewport_set_scenario(viewport, scenario); VS::get_singleton()->viewport_set_size(viewport, size, size); VS::get_singleton()->viewport_set_transparent_background(viewport, true); diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index bf293c3a5e4..f1e54739b35 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -984,7 +984,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref &p_me mr.push_back(a); } - p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, p_use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : 0); + p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), p_use_compression ? Mesh::ARRAY_COMPRESS_DEFAULT : 0); if (material.is_valid()) { if (p_use_mesh_material) { diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index 3239cadbe4f..7d5fd9be754 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -984,14 +984,15 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { static const Mesh::PrimitiveType primitives2[7] = { Mesh::PRIMITIVE_POINTS, Mesh::PRIMITIVE_LINES, - Mesh::PRIMITIVE_LINES, + Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted Mesh::PRIMITIVE_LINES, Mesh::PRIMITIVE_TRIANGLES, - Mesh::PRIMITIVE_TRIANGLES, - Mesh::PRIMITIVE_TRIANGLES, + Mesh::PRIMITIVE_TRIANGLE_STRIP, + Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted #ifndef _MSC_VER -#warning these will have to be decomposed into proper primitive now that lineloop/strip,etc no longer supported +#warning line loop and triangle fan are not supported and need to be converted to lines and triangles #endif + }; primitive = primitives2[mode]; diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 5e69ce4e69d..d8bbac9c490 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1322,11 +1322,10 @@ void AnimationPlayerEditor::_allocate_onion_layers() { // Each capture is a viewport with a canvas item attached that renders a full-size rect with the contents of the main viewport. onion.captures.write[i] = VS::get_singleton()->viewport_create(); - VS::get_singleton()->viewport_set_usage(onion.captures[i], VS::VIEWPORT_USAGE_2D); + VS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height); VS::get_singleton()->viewport_set_update_mode(onion.captures[i], VS::VIEWPORT_UPDATE_ALWAYS); VS::get_singleton()->viewport_set_transparent_background(onion.captures[i], !is_present); - VS::get_singleton()->viewport_set_vflip(onion.captures[i], true); VS::get_singleton()->viewport_attach_canvas(onion.captures[i], onion.capture.canvas); } diff --git a/editor/plugins/collision_polygon_editor_plugin.cpp b/editor/plugins/collision_polygon_editor_plugin.cpp index 612b21204d8..32075e82be2 100644 --- a/editor/plugins/collision_polygon_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_editor_plugin.cpp @@ -463,9 +463,7 @@ void Polygon3DEditor::_polygon_draw() { imgeom->end(); - while (m->get_surface_count()) { - m->surface_remove(0); - } + m->clear_surfaces(); if (poly.size() == 0) return; diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 2037c17b89a..6e8aef0aea5 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -370,7 +370,6 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { VS::get_singleton()->viewport_set_size(viewport, 128, 128); VS::get_singleton()->viewport_set_transparent_background(viewport, true); VS::get_singleton()->viewport_set_active(viewport, true); - VS::get_singleton()->viewport_set_vflip(viewport, true); viewport_texture = VS::get_singleton()->viewport_get_texture(viewport); camera = VS::get_singleton()->camera_create(); @@ -773,7 +772,6 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() { viewport = VS::get_singleton()->viewport_create(); VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED); - VS::get_singleton()->viewport_set_vflip(viewport, true); VS::get_singleton()->viewport_set_scenario(viewport, scenario); VS::get_singleton()->viewport_set_size(viewport, 128, 128); VS::get_singleton()->viewport_set_transparent_background(viewport, true); @@ -904,7 +902,6 @@ EditorFontPreviewPlugin::EditorFontPreviewPlugin() { viewport = VS::get_singleton()->viewport_create(); VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED); - VS::get_singleton()->viewport_set_vflip(viewport, true); VS::get_singleton()->viewport_set_size(viewport, 128, 128); VS::get_singleton()->viewport_set_active(viewport, true); viewport_texture = VS::get_singleton()->viewport_get_texture(viewport); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index c07983b6476..e0622466659 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2272,9 +2272,6 @@ void SpatialEditorViewport::_notification(int p_what) { int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa"); viewport->set_msaa(Viewport::MSAA(msaa_mode)); - bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr"); - viewport->set_hdr(hdr); - bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); info_label->set_visible(show_info); diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 9fd9fefee6e..2736bbfd3a8 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -330,7 +330,7 @@ void SpriteEditor::_convert_to_mesh_2d_node() { a[Mesh::ARRAY_TEX_UV] = computed_uv; a[Mesh::ARRAY_INDEX] = computed_indices; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); MeshInstance2D *mesh_instance = memnew(MeshInstance2D); mesh_instance->set_mesh(mesh); diff --git a/main/main.cpp b/main/main.cpp index 9aebc17a651..fff652edc83 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1795,8 +1795,6 @@ bool Main::start() { sml->get_root()->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q1_subdiv)); sml->get_root()->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q2_subdiv)); sml->get_root()->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q3_subdiv)); - Viewport::Usage usage = Viewport::Usage(int(GLOBAL_GET("rendering/quality/intended_usage/framebuffer_allocation"))); - sml->get_root()->set_usage(usage); bool snap_controls = GLOBAL_DEF("gui/common/snap_controls_to_pixels", true); sml->get_root()->set_snap_controls_to_pixels(snap_controls); @@ -1929,8 +1927,6 @@ bool Main::start() { ProgressDialog *progress_dialog = memnew(ProgressDialog); pmanager->add_child(progress_dialog); sml->get_root()->add_child(pmanager); - // Speed up rendering slightly by disabling 3D features while in the project manager. - sml->get_root()->set_usage(Viewport::USAGE_2D_NO_SAMPLING); OS::get_singleton()->set_context(OS::CONTEXT_PROJECTMAN); project_manager = true; } diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index e1e0044cea6..7b846569dc4 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -1022,8 +1022,7 @@ void GridMapEditor::_draw_grids(const Vector3 &cell_size) { Vector3 edited_floor = node->has_meta("_editor_floor_") ? node->get_meta("_editor_floor_") : Variant(); for (int i = 0; i < 3; i++) { - if (VS::get_singleton()->mesh_get_surface_count(grid[i]) > 0) - VS::get_singleton()->mesh_remove_surface(grid[i], 0); + VS::get_singleton()->mesh_clear(grid[i]); edit_floor[i] = edited_floor[i]; } diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 7f764a737a0..616ab7cf40a 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -362,8 +362,7 @@ void RayCast::_update_debug_shape() { return; Ref mesh = mi->get_mesh(); - if (mesh->get_surface_count() > 0) - mesh->surface_remove(0); + mesh->clear_surfaces(); Array a; a.resize(Mesh::ARRAY_MAX); diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp index 435bef72472..931e786455c 100644 --- a/scene/3d/soft_body.cpp +++ b/scene/3d/soft_body.cpp @@ -47,7 +47,10 @@ void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) { mesh = p_mesh; surface = p_surface; - +#ifndef _MSC_VER +#warning Softbody is not working, needs to be redone considering that these functions no longer exist +#endif +#if 0 const uint32_t surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, surface); const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface); const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface); @@ -57,6 +60,7 @@ void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) { stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets); offset_vertices = surface_offsets[VS::ARRAY_VERTEX]; offset_normal = surface_offsets[VS::ARRAY_NORMAL]; +#endif } void SoftBodyVisualServerHandler::clear() { @@ -485,14 +489,15 @@ void SoftBody::become_mesh_owner() { // Get current mesh array and create new mesh array with necessary flag for softbody Array surface_arrays = mesh->surface_get_arrays(0); Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0); + Dictionary surface_lods = mesh->surface_get_lods(0); uint32_t surface_format = mesh->surface_get_format(0); - surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL); + surface_format &= ~(Mesh::ARRAY_COMPRESS_NORMAL); surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; Ref soft_mesh; soft_mesh.instance(); - soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format); + soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format); soft_mesh->surface_set_material(0, mesh->surface_get_material(0)); set_mesh(soft_mesh); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 15d21859ea9..67a39a6b225 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -2081,12 +2081,6 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x")); root->set_msaa(Viewport::MSAA(msaa_mode)); - GLOBAL_DEF("rendering/quality/depth/hdr", true); - GLOBAL_DEF("rendering/quality/depth/hdr.mobile", false); - - bool hdr = GLOBAL_GET("rendering/quality/depth/hdr"); - root->set_hdr(hdr); - VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(), ref_atlas_size, ref_atlas_subdiv); { //load default fallback environment diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index e4343d39821..976c66ad0cf 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1330,17 +1330,6 @@ Ref Viewport::get_texture() const { return default_texture; } -void Viewport::set_vflip(bool p_enable) { - - vflip = p_enable; - VisualServer::get_singleton()->viewport_set_vflip(viewport, p_enable); -} - -bool Viewport::get_vflip() const { - - return vflip; -} - void Viewport::set_clear_mode(ClearMode p_mode) { clear_mode = p_mode; @@ -2948,26 +2937,6 @@ bool Viewport::is_input_disabled() const { return disable_input; } -void Viewport::set_disable_3d(bool p_disable) { - disable_3d = p_disable; - VS::get_singleton()->viewport_set_disable_3d(viewport, p_disable); -} - -bool Viewport::is_3d_disabled() const { - - return disable_3d; -} - -void Viewport::set_keep_3d_linear(bool p_keep_3d_linear) { - keep_3d_linear = p_keep_3d_linear; - VS::get_singleton()->viewport_set_keep_3d_linear(viewport, keep_3d_linear); -} - -bool Viewport::get_keep_3d_linear() const { - - return keep_3d_linear; -} - Variant Viewport::gui_get_drag_data() const { return gui.drag_data; } @@ -3008,30 +2977,6 @@ Viewport::MSAA Viewport::get_msaa() const { return msaa; } -void Viewport::set_hdr(bool p_hdr) { - - if (hdr == p_hdr) - return; - - hdr = p_hdr; - VS::get_singleton()->viewport_set_hdr(viewport, p_hdr); -} - -bool Viewport::get_hdr() const { - - return hdr; -} - -void Viewport::set_usage(Usage p_usage) { - - usage = p_usage; - VS::get_singleton()->viewport_set_usage(viewport, VS::ViewportUsage(p_usage)); -} - -Viewport::Usage Viewport::get_usage() const { - return usage; -} - void Viewport::set_debug_draw(DebugDraw p_debug_draw) { debug_draw = p_debug_draw; @@ -3090,10 +3035,6 @@ bool Viewport::is_handling_input_locally() const { } void Viewport::_validate_property(PropertyInfo &property) const { - - if (VisualServer::get_singleton()->is_low_end() && property.name == "hdr") { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; - } } void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) { @@ -3176,9 +3117,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size_override_stretch", "enabled"), &Viewport::set_size_override_stretch); ClassDB::bind_method(D_METHOD("is_size_override_stretch_enabled"), &Viewport::is_size_override_stretch_enabled); - ClassDB::bind_method(D_METHOD("set_vflip", "enable"), &Viewport::set_vflip); - ClassDB::bind_method(D_METHOD("get_vflip"), &Viewport::get_vflip); - ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &Viewport::set_clear_mode); ClassDB::bind_method(D_METHOD("get_clear_mode"), &Viewport::get_clear_mode); @@ -3188,12 +3126,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa); ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa); - ClassDB::bind_method(D_METHOD("set_hdr", "enable"), &Viewport::set_hdr); - ClassDB::bind_method(D_METHOD("get_hdr"), &Viewport::get_hdr); - - ClassDB::bind_method(D_METHOD("set_usage", "usage"), &Viewport::set_usage); - ClassDB::bind_method(D_METHOD("get_usage"), &Viewport::get_usage); - ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw); ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw); @@ -3236,12 +3168,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input); ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); - ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d); - ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled); - - ClassDB::bind_method(D_METHOD("set_keep_3d_linear", "keep_3d_linear"), &Viewport::set_keep_3d_linear); - ClassDB::bind_method(D_METHOD("get_keep_3d_linear"), &Viewport::get_keep_3d_linear); - ClassDB::bind_method(D_METHOD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip); ClassDB::bind_method(D_METHOD("_gui_remove_focus"), &Viewport::_gui_remove_focus); ClassDB::bind_method(D_METHOD("_post_gui_grab_click_focus"), &Viewport::_post_gui_grab_click_focus); @@ -3289,7 +3215,6 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); ADD_GROUP("Render Target", "render_target_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_target_v_flip"), "set_vflip", "get_vflip"); ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode"); ADD_GROUP("Canvas Items", "canvas_item_"); @@ -3348,11 +3273,6 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(MSAA_8X); BIND_ENUM_CONSTANT(MSAA_16X); - BIND_ENUM_CONSTANT(USAGE_2D); - BIND_ENUM_CONSTANT(USAGE_2D_NO_SAMPLING); - BIND_ENUM_CONSTANT(USAGE_3D); - BIND_ENUM_CONSTANT(USAGE_3D_NO_EFFECTS); - BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS); BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER); BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME); @@ -3406,8 +3326,6 @@ Viewport::Viewport() { size_override_size = Size2(1, 1); gen_mipmaps = false; - vflip = false; - //clear=true; update_mode = UPDATE_WHEN_VISIBLE; @@ -3433,8 +3351,6 @@ Viewport::Viewport() { unhandled_key_input_group = "_vp_unhandled_key_input" + id; disable_input = false; - disable_3d = false; - keep_3d_linear = false; //window tooltip gui.tooltip_timer = -1; @@ -3453,9 +3369,7 @@ Viewport::Viewport() { gui.last_mouse_focus = NULL; msaa = MSAA_DISABLED; - hdr = true; - usage = USAGE_3D; debug_draw = DEBUG_DRAW_DISABLED; clear_mode = CLEAR_MODE_ALWAYS; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index a70d812edaa..469665676c8 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -115,13 +115,6 @@ public: MSAA_16X, }; - enum Usage { - USAGE_2D, - USAGE_2D_NO_SAMPLING, - USAGE_3D, - USAGE_3D_NO_EFFECTS, - }; - enum RenderInfo { RENDER_INFO_OBJECTS_IN_FRAME, @@ -226,7 +219,6 @@ private: Rect2 last_vp_rect; bool transparent_bg; - bool vflip; ClearMode clear_mode; bool filter; bool gen_mipmaps; @@ -278,21 +270,15 @@ private: void _update_stretch_transform(); void _update_global_transform(); - bool disable_3d; - bool keep_3d_linear; UpdateMode update_mode; RID texture_rid; DebugDraw debug_draw; - Usage usage; - int shadow_atlas_size; ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4]; MSAA msaa; - bool hdr; - Ref default_texture; Set viewport_textures; @@ -491,9 +477,6 @@ public: void set_size_override_stretch(bool p_enable); bool is_size_override_stretch_enabled() const; - void set_vflip(bool p_enable); - bool get_vflip() const; - void set_clear_mode(ClearMode p_mode); ClearMode get_clear_mode() const; @@ -510,9 +493,6 @@ public: void set_msaa(MSAA p_msaa); MSAA get_msaa() const; - void set_hdr(bool p_hdr); - bool get_hdr() const; - Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const; Vector2 get_camera_rect_size() const; @@ -525,12 +505,6 @@ public: void set_disable_input(bool p_disable); bool is_input_disabled() const; - void set_disable_3d(bool p_disable); - bool is_3d_disabled() const; - - void set_keep_3d_linear(bool p_keep_3d_linear); - bool get_keep_3d_linear() const; - void set_attach_to_screen_rect(const Rect2 &p_rect); Rect2 get_attach_to_screen_rect() const; @@ -553,9 +527,6 @@ public: virtual String get_configuration_warning() const; - void set_usage(Usage p_usage); - Usage get_usage() const; - void set_debug_draw(DebugDraw p_debug_draw); DebugDraw get_debug_draw() const; @@ -587,7 +558,6 @@ public: VARIANT_ENUM_CAST(Viewport::UpdateMode); VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv); VARIANT_ENUM_CAST(Viewport::MSAA); -VARIANT_ENUM_CAST(Viewport::Usage); VARIANT_ENUM_CAST(Viewport::DebugDraw); VARIANT_ENUM_CAST(Viewport::ClearMode); VARIANT_ENUM_CAST(Viewport::RenderInfo); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 8955838f62f..96c609174ff 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -159,7 +159,7 @@ void Mesh::generate_debug_mesh_indices(Vector &r_points) { bool Mesh::surface_is_softbody_friendly(int p_idx) const { const uint32_t surface_format = surface_get_format(p_idx); - return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_VERTEX)) && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL))); + return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL))); } PoolVector Mesh::get_faces() const { @@ -499,7 +499,9 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); + BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES); + BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP); BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); @@ -514,18 +516,14 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_VERTEX); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_BONES); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); - BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_16_BIT_BONES); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT); @@ -626,9 +624,12 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { return true; } +#ifdef ENABLE_DEPRECATED if (!sname.begins_with("surfaces")) return false; + WARN_DEPRECATED("Mesh uses old surface format, which is deprecated (and loads slower). Consider re-importing or re-saving the scene."); + int idx = sname.get_slicec('/', 1).to_int(); String what = sname.get_slicec('/', 2); @@ -654,6 +655,12 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { uint32_t format = d["format"]; uint32_t primitive = d["primitive"]; + if (primitive > PRIMITIVE_LINE_STRIP) { + primitive--; //line loop was deprecated, so it's not supported and indices go down by one + } + if (primitive > PRIMITIVE_TRIANGLE_STRIP) { + primitive = PRIMITIVE_TRIANGLE_STRIP; //fan is no longer supported + } ERR_FAIL_COND_V(!d.has("vertex_count"), false); int vertex_count = d["vertex_count"]; @@ -701,9 +708,191 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { return true; } +#endif + return false; } +Array ArrayMesh::_get_surfaces() const { + + if (mesh.is_null()) { + return Array(); + } + + Array ret; + for (int i = 0; i < surfaces.size(); i++) { + VisualServer::SurfaceData surface = VS::get_singleton()->mesh_get_surface(mesh, i); + Dictionary data; + data["format"] = surface.format; + data["primitive"] = surface.primitive; + data["vertex_data"] = surface.vertex_data; + data["vertex_count"] = surface.vertex_count; + data["aabb"] = surface.aabb; + if (surface.index_count) { + data["index_data"] = surface.index_data; + data["index_count"] = surface.index_count; + }; + + Array lods; + for (int j = 0; j < surface.lods.size(); j++) { + lods.push_back(surface.lods[j].edge_length); + lods.push_back(surface.lods[j].index_data); + } + + if (lods.size()) { + data["lods"] = lods; + } + + Array bone_aabbs; + for (int j = 0; j < surface.bone_aabbs.size(); j++) { + bone_aabbs.push_back(surface.bone_aabbs[j]); + } + if (bone_aabbs.size()) { + data["bone_aabbs"] = bone_aabbs; + } + + Array blend_shapes; + for (int j = 0; j < surface.blend_shapes.size(); j++) { + blend_shapes.push_back(surface.blend_shapes[j]); + } + + if (surfaces[i].material.is_valid()) { + data["material"] = surfaces[i].material; + } + + if (surfaces[i].name != String()) { + data["name"] = surfaces[i].name; + } + + if (surfaces[i].is_2d) { + data["2d"] = true; + } + + ret.push_back(data); + } + return ret; +} + +void ArrayMesh::_create_if_empty() const { + if (!mesh.is_valid()) { + mesh = VS::get_singleton()->mesh_create(); + } +} + +void ArrayMesh::_set_surfaces(const Array &p_surfaces) { + + Vector surface_data; + Vector > surface_materials; + Vector surface_names; + Vector surface_2d; + + for (int i = 0; i < p_surfaces.size(); i++) { + VS::SurfaceData surface; + Dictionary d = p_surfaces[i]; + ERR_FAIL_COND(!d.has("format")); + ERR_FAIL_COND(!d.has("primitive")); + ERR_FAIL_COND(!d.has("vertex_data")); + ERR_FAIL_COND(!d.has("vertex_count")); + ERR_FAIL_COND(!d.has("aabb")); + surface.format = d["format"]; + surface.primitive = VS::PrimitiveType(int(d["primitive"])); + surface.vertex_data = d["vertex_data"]; + surface.vertex_count = d["vertex_count"]; + surface.aabb = d["aabb"]; + + if (d.has("index_data")) { + ERR_FAIL_COND(!d.has("index_count")); + surface.index_data = d["index_data"]; + surface.index_count = d["index_count"]; + } + + if (d.has("lods")) { + Array lods = d["lods"]; + ERR_FAIL_COND(lods.size() & 1); //must be even + for (int j = 0; j < lods.size(); j += 2) { + VS::SurfaceData::LOD lod; + lod.edge_length = lods[j + 0]; + lod.index_data = lods[j + 1]; + surface.lods.push_back(lod); + } + } + + if (d.has("bone_aabbs")) { + Array bone_aabbs = d["bone_aabbs"]; + for (int j = 0; j < bone_aabbs.size(); j++) { + surface.bone_aabbs.push_back(bone_aabbs[j]); + } + } + + if (d.has("blend_shapes")) { + Array blend_shapes; + for (int j = 0; j < blend_shapes.size(); j++) { + surface.blend_shapes.push_back(blend_shapes[j]); + } + } + + Ref material; + if (d.has("material")) { + material = d["material"]; + if (material.is_valid()) { + surface.material = material->get_rid(); + } + } + + String name; + if (d.has("name")) { + name = d["name"]; + } + + bool _2d = false; + if (d.has("2d")) { + _2d = d["2d"]; + } + + surface_data.push_back(surface); + surface_materials.push_back(material); + surface_names.push_back(name); + surface_2d.push_back(_2d); + } + + if (mesh.is_valid()) { + //if mesh exists, it needs to be updated + VS::get_singleton()->mesh_clear(mesh); + for (int i = 0; i < surface_data.size(); i++) { + VS::get_singleton()->mesh_add_surface(mesh, surface_data[i]); + } + } else { + // if mesh does not exist (first time this is loaded, most likely), + // we can create it with a single call, which is a lot more efficient and thread friendly + mesh = VS::get_singleton()->mesh_create_from_surfaces(surface_data); + } + + surfaces.clear(); + + aabb = AABB(); + for (int i = 0; i < surface_data.size(); i++) { + Surface s; + s.aabb = surface_data[i].aabb; + if (i == 0) { + aabb = s.aabb; + blend_shapes.resize(surface_data[i].blend_shapes.size()); + } else { + aabb.merge_with(s.aabb); + } + + s.material = surface_materials[i]; + s.is_2d = surface_2d[i]; + s.name = surface_names[i]; + + s.format = surface_data[i].format; + s.primitive = PrimitiveType(surface_data[i].primitive); + s.array_length = surface_data[i].vertex_count; + s.index_array_length = surface_data[i].index_count; + + surfaces.push_back(s); + } +} + bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const { if (_is_generated()) @@ -734,47 +923,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const { else if (what == "name") r_ret = surface_get_name(idx); return true; - } else if (!sname.begins_with("surfaces")) - return false; - - int idx = sname.get_slicec('/', 1).to_int(); - ERR_FAIL_INDEX_V(idx, surfaces.size(), false); - - Dictionary d; - - d["array_data"] = VS::get_singleton()->mesh_surface_get_array(mesh, idx); - d["vertex_count"] = VS::get_singleton()->mesh_surface_get_array_len(mesh, idx); - d["array_index_data"] = VS::get_singleton()->mesh_surface_get_index_array(mesh, idx); - d["index_count"] = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, idx); - d["primitive"] = VS::get_singleton()->mesh_surface_get_primitive_type(mesh, idx); - d["format"] = VS::get_singleton()->mesh_surface_get_format(mesh, idx); - d["aabb"] = VS::get_singleton()->mesh_surface_get_aabb(mesh, idx); - - Vector skel_aabb = VS::get_singleton()->mesh_surface_get_skeleton_aabb(mesh, idx); - Array arr; - arr.resize(skel_aabb.size()); - for (int i = 0; i < skel_aabb.size(); i++) { - arr[i] = skel_aabb[i]; } - d["skeleton_aabb"] = arr; - - Vector > blend_shape_data = VS::get_singleton()->mesh_surface_get_blend_shapes(mesh, idx); - - Array md; - for (int i = 0; i < blend_shape_data.size(); i++) { - md.push_back(blend_shape_data[i]); - } - - d["blend_shape_data"] = md; - - Ref m = surface_get_material(idx); - if (m.is_valid()) - d["material"] = m; - String n = surface_get_name(idx); - if (n != "") - d["name"] = n; - - r_ret = d; return true; } @@ -791,7 +940,6 @@ void ArrayMesh::_get_property_list(List *p_list) const { for (int i = 0; i < surfaces.size(); i++) { - p_list->push_back(PropertyInfo(Variant::DICTIONARY, "surfaces/" + itos(i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); if (surfaces[i].is_2d) { p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial", PROPERTY_USAGE_EDITOR)); @@ -814,57 +962,55 @@ void ArrayMesh::_recompute_aabb() { aabb.merge_with(surfaces[i].aabb); } } +#ifndef _MSC_VER +#warning need to add binding to add_surface using future MeshSurfaceData object +#endif +void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const PoolVector &p_array, int p_vertex_count, const PoolVector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector > &p_blend_shapes, const Vector &p_bone_aabb, const Vector &p_lods) { -void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const PoolVector &p_array, int p_vertex_count, const PoolVector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector > &p_blend_shapes, const Vector &p_bone_aabbs) { + _create_if_empty(); Surface s; s.aabb = p_aabb; s.is_2d = p_format & ARRAY_FLAG_USE_2D_VERTICES; + s.primitive = p_primitive; + s.array_length = p_vertex_count; + s.index_array_length = p_index_count; + s.format = p_format; + surfaces.push_back(s); _recompute_aabb(); - VisualServer::get_singleton()->mesh_add_surface(mesh, p_format, (VS::PrimitiveType)p_primitive, p_array, p_vertex_count, p_index_array, p_index_count, p_aabb, p_blend_shapes, p_bone_aabbs); -} + VS::SurfaceData sd; + sd.format = p_format; + sd.primitive = VS::PrimitiveType(p_primitive); + sd.aabb = p_aabb; + sd.vertex_count = p_vertex_count; + sd.vertex_data = p_array; + sd.index_count = p_index_count; + sd.index_data = p_index_array; + sd.blend_shapes = p_blend_shapes; + sd.bone_aabbs = p_bone_aabb; + sd.lods = p_lods; -void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_flags) { - - ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX); - - Surface s; - - VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_flags); - - /* make aABB? */ { - - Variant arr = p_arrays[ARRAY_VERTEX]; - PoolVector vertices = arr; - int len = vertices.size(); - ERR_FAIL_COND(len == 0); - PoolVector::Read r = vertices.read(); - const Vector3 *vtx = r.ptr(); - - // check AABB - AABB aabb; - for (int i = 0; i < len; i++) { - - if (i == 0) - aabb.position = vtx[i]; - else - aabb.expand_to(vtx[i]); - } - - s.aabb = aabb; - s.is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; - surfaces.push_back(s); - - _recompute_aabb(); - } + VisualServer::get_singleton()->mesh_add_surface(mesh, sd); clear_cache(); _change_notify(); emit_changed(); } +void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_flags) { + + ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX); + + VS::SurfaceData surface; + + Error err = VS::get_singleton()->mesh_create_surface_data_from_arrays(&surface, (VisualServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_lods, p_flags); + ERR_FAIL_COND(err != OK); + + add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shapes, surface.bone_aabbs, surface.lods); +} + Array ArrayMesh::surface_get_arrays(int p_surface) const { ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); @@ -875,6 +1021,10 @@ Array ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const { ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); return VisualServer::get_singleton()->mesh_surface_get_blend_shape_arrays(mesh, p_surface); } +Dictionary ArrayMesh::surface_get_lods(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Dictionary()); + return VisualServer::get_singleton()->mesh_surface_get_lods(mesh, p_surface); +} int ArrayMesh::get_surface_count() const { @@ -898,7 +1048,7 @@ void ArrayMesh::add_blend_shape(const StringName &p_name) { } blend_shapes.push_back(name); - VS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size()); + //VS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size()); } int ArrayMesh::get_blend_shape_count() const { @@ -927,40 +1077,28 @@ ArrayMesh::BlendShapeMode ArrayMesh::get_blend_shape_mode() const { return blend_shape_mode; } -void ArrayMesh::surface_remove(int p_idx) { - - ERR_FAIL_INDEX(p_idx, surfaces.size()); - VisualServer::get_singleton()->mesh_remove_surface(mesh, p_idx); - surfaces.remove(p_idx); - - clear_cache(); - _recompute_aabb(); - _change_notify(); - emit_changed(); -} - int ArrayMesh::surface_get_array_len(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, surfaces.size(), -1); - return VisualServer::get_singleton()->mesh_surface_get_array_len(mesh, p_idx); + return surfaces[p_idx].array_length; } int ArrayMesh::surface_get_array_index_len(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, surfaces.size(), -1); - return VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, p_idx); + return surfaces[p_idx].index_array_length; } uint32_t ArrayMesh::surface_get_format(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, surfaces.size(), 0); - return VisualServer::get_singleton()->mesh_surface_get_format(mesh, p_idx); + return surfaces[p_idx].format; } ArrayMesh::PrimitiveType ArrayMesh::surface_get_primitive_type(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, surfaces.size(), PRIMITIVE_LINES); - return (PrimitiveType)VisualServer::get_singleton()->mesh_surface_get_primitive_type(mesh, p_idx); + return surfaces[p_idx].primitive; } void ArrayMesh::surface_set_material(int p_idx, const Ref &p_material) { @@ -981,7 +1119,6 @@ int ArrayMesh::surface_find_by_name(const String &p_name) const { return i; } } - return -1; } @@ -1020,35 +1157,9 @@ Ref ArrayMesh::surface_get_material(int p_idx) const { return surfaces[p_idx].material; } -void ArrayMesh::add_surface_from_mesh_data(const Geometry::MeshData &p_mesh_data) { - - VisualServer::get_singleton()->mesh_add_surface_from_mesh_data(mesh, p_mesh_data); - AABB aabb; - for (int i = 0; i < p_mesh_data.vertices.size(); i++) { - - if (i == 0) - aabb.position = p_mesh_data.vertices[i]; - else - aabb.expand_to(p_mesh_data.vertices[i]); - } - - Surface s; - s.aabb = aabb; - if (surfaces.size() == 0) - aabb = s.aabb; - else - aabb.merge_with(s.aabb); - - clear_cache(); - - surfaces.push_back(s); - _change_notify(); - - emit_changed(); -} - RID ArrayMesh::get_rid() const { + _create_if_empty(); return mesh; } AABB ArrayMesh::get_aabb() const { @@ -1056,8 +1167,18 @@ AABB ArrayMesh::get_aabb() const { return aabb; } +void ArrayMesh::clear_surfaces() { + if (!mesh.is_valid()) { + return; + } + VS::get_singleton()->mesh_clear(mesh); + surfaces.clear(); + aabb = AABB(); +} + void ArrayMesh::set_custom_aabb(const AABB &p_custom) { + _create_if_empty(); custom_aabb = p_custom; VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb); emit_changed(); @@ -1070,6 +1191,9 @@ AABB ArrayMesh::get_custom_aabb() const { void ArrayMesh::regen_normalmaps() { + if (surfaces.size() == 0) { + return; + } Vector > surfs; for (int i = 0; i < get_surface_count(); i++) { @@ -1078,9 +1202,7 @@ void ArrayMesh::regen_normalmaps() { surfs.push_back(st); } - while (get_surface_count()) { - surface_remove(0); - } + clear_surfaces(); for (int i = 0; i < surfs.size(); i++) { @@ -1200,9 +1322,7 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe } //remove surfaces - while (get_surface_count()) { - surface_remove(0); - } + clear_surfaces(); //create surfacetools for each surface.. Vector > surfaces_tools; @@ -1286,8 +1406,8 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode); ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode); - ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); - ClassDB::bind_method(D_METHOD("surface_remove", "surf_idx"), &ArrayMesh::surface_remove); + ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); + ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces); ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region); ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len); ClassDB::bind_method(D_METHOD("surface_get_array_index_len", "surf_idx"), &ArrayMesh::surface_get_array_index_len); @@ -1309,6 +1429,10 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb); ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb); + ClassDB::bind_method(D_METHOD("_set_surfaces", "surfaces"), &ArrayMesh::_set_surfaces); + ClassDB::bind_method(D_METHOD("_get_surfaces"), &ArrayMesh::_get_surfaces); + + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces"); ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative", PROPERTY_USAGE_NOEDITOR), "set_blend_shape_mode", "get_blend_shape_mode"); ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); @@ -1350,11 +1474,14 @@ void ArrayMesh::reload_from_file() { ArrayMesh::ArrayMesh() { - mesh = VisualServer::get_singleton()->mesh_create(); + //mesh is now created on demand + //mesh = VisualServer::get_singleton()->mesh_create(); blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE; } ArrayMesh::~ArrayMesh() { - VisualServer::get_singleton()->free(mesh); + if (mesh.is_valid()) { + VisualServer::get_singleton()->free(mesh); + } } diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 6ead37a7bbb..b8f3702bbe6 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -83,28 +83,26 @@ public: ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX, ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1), - ARRAY_COMPRESS_VERTEX = 1 << (ARRAY_VERTEX + ARRAY_COMPRESS_BASE), // mandatory ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_BONES = 1 << (ARRAY_BONES + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_WEIGHTS = 1 << (ARRAY_WEIGHTS + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE), ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1, - ARRAY_FLAG_USE_16_BIT_BONES = ARRAY_COMPRESS_INDEX << 2, ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3, - ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS + ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 }; enum PrimitiveType { PRIMITIVE_POINTS = VisualServer::PRIMITIVE_POINTS, PRIMITIVE_LINES = VisualServer::PRIMITIVE_LINES, + PRIMITIVE_LINE_STRIP = VisualServer::PRIMITIVE_LINE_STRIP, PRIMITIVE_TRIANGLES = VisualServer::PRIMITIVE_TRIANGLES, + PRIMITIVE_TRIANGLE_STRIP = VisualServer::PRIMITIVE_TRIANGLE_STRIP, PRIMITIVE_MAX = VisualServer::PRIMITIVE_MAX, }; @@ -120,6 +118,7 @@ public: virtual bool surface_is_softbody_friendly(int p_idx) const; virtual Array surface_get_arrays(int p_surface) const = 0; virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0; + virtual Dictionary surface_get_lods(int p_surface) const = 0; virtual uint32_t surface_get_format(int p_idx) const = 0; virtual PrimitiveType surface_get_primitive_type(int p_idx) const = 0; virtual void surface_set_material(int p_idx, const Ref &p_material) = 0; @@ -157,20 +156,29 @@ class ArrayMesh : public Mesh { GDCLASS(ArrayMesh, Mesh); RES_BASE_EXTENSION("mesh"); + Array _get_surfaces() const; + void _set_surfaces(const Array &p_data); + private: struct Surface { + uint32_t format; + int array_length; + int index_array_length; + PrimitiveType primitive; + String name; AABB aabb; Ref material; bool is_2d; }; Vector surfaces; - RID mesh; + mutable RID mesh; AABB aabb; BlendShapeMode blend_shape_mode; Vector blend_shapes; AABB custom_aabb; + _FORCE_INLINE_ void _create_if_empty() const; void _recompute_aabb(); protected: @@ -183,11 +191,13 @@ protected: static void _bind_methods(); public: - void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), uint32_t p_flags = ARRAY_COMPRESS_DEFAULT); - void add_surface(uint32_t p_format, PrimitiveType p_primitive, const PoolVector &p_array, int p_vertex_count, const PoolVector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector > &p_blend_shapes = Vector >(), const Vector &p_bone_aabbs = Vector()); + void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = ARRAY_COMPRESS_DEFAULT); + + void add_surface(uint32_t p_format, PrimitiveType p_primitive, const PoolVector &p_array, int p_vertex_count, const PoolVector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector > &p_blend_shapes = Vector >(), const Vector &p_bone_aabbs = Vector(), const Vector &p_lods = Vector()); Array surface_get_arrays(int p_surface) const; Array surface_get_blend_shape_arrays(int p_surface) const; + Dictionary surface_get_lods(int p_surface) const; void add_blend_shape(const StringName &p_name); int get_blend_shape_count() const; @@ -202,6 +212,8 @@ public: int get_surface_count() const; void surface_remove(int p_idx); + void clear_surfaces(); + void surface_set_custom_aabb(int p_idx, const AABB &p_aabb); //only recognized by driver int surface_get_array_len(int p_idx) const; @@ -217,8 +229,6 @@ public: void surface_set_name(int p_idx, const String &p_name); String surface_get_name(int p_idx) const; - void add_surface_from_mesh_data(const Geometry::MeshData &p_mesh_data); - void set_custom_aabb(const AABB &p_custom); AABB get_custom_aabb() const; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 74df72619a0..79d030b8abf 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -57,9 +57,11 @@ void PrimitiveMesh::_update() const { } } + PoolVector indices = arr[VS::ARRAY_INDEX]; + if (flip_faces) { PoolVector normals = arr[VS::ARRAY_NORMAL]; - PoolVector indices = arr[VS::ARRAY_INDEX]; + if (normals.size() && indices.size()) { { @@ -82,6 +84,8 @@ void PrimitiveMesh::_update() const { } } + array_len = pc; + index_array_len = indices.size(); // in with the new VisualServer::get_singleton()->mesh_clear(mesh); VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)primitive_type, arr); @@ -114,7 +118,7 @@ int PrimitiveMesh::surface_get_array_len(int p_idx) const { _update(); } - return VisualServer::get_singleton()->mesh_surface_get_array_len(mesh, 0); + return array_len; } int PrimitiveMesh::surface_get_array_index_len(int p_idx) const { @@ -123,7 +127,7 @@ int PrimitiveMesh::surface_get_array_index_len(int p_idx) const { _update(); } - return VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, 0); + return index_array_len; } Array PrimitiveMesh::surface_get_arrays(int p_surface) const { @@ -135,22 +139,18 @@ Array PrimitiveMesh::surface_get_arrays(int p_surface) const { return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh, 0); } +Dictionary PrimitiveMesh::surface_get_lods(int p_surface) const { + return Dictionary(); //not really supported +} Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const { - ERR_FAIL_INDEX_V(p_surface, 1, Array()); - if (pending_request) { - _update(); - } - return Array(); + return Array(); //not really supported } uint32_t PrimitiveMesh::surface_get_format(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, 1, 0); - if (pending_request) { - _update(); - } - return VisualServer::get_singleton()->mesh_surface_get_format(mesh, 0); + return VS::ARRAY_COMPRESS_DEFAULT; } Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const { @@ -261,6 +261,9 @@ PrimitiveMesh::PrimitiveMesh() { // make sure we do an update after we've finished constructing our object pending_request = true; + + array_len = 0; + index_array_len = 0; } PrimitiveMesh::~PrimitiveMesh() { diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 47126f18622..5f17680c9e0 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -50,6 +50,9 @@ private: mutable AABB aabb; AABB custom_aabb; + mutable int array_len; + mutable int index_array_len; + Ref material; bool flip_faces; @@ -70,6 +73,7 @@ public: virtual int surface_get_array_index_len(int p_idx) const; virtual Array surface_get_arrays(int p_surface) const; virtual Array surface_get_blend_shape_arrays(int p_surface) const; + virtual Dictionary surface_get_lods(int p_surface) const; virtual uint32_t surface_get_format(int p_idx) const; virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const; virtual void surface_set_material(int p_idx, const Ref &p_material); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index f921a9695c8..a1e64302552 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -466,7 +466,7 @@ Ref SurfaceTool::commit(const Ref &p_existing, uint32_t p_ Array a = commit_to_arrays(); - mesh->add_surface_from_arrays(primitive, a, Array(), p_flags); + mesh->add_surface_from_arrays(primitive, a, Array(), Dictionary(), p_flags); if (material.is_valid()) mesh->surface_set_material(surface, material); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index c8b756fb4a5..8df43bc6958 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -100,14 +100,23 @@ public: Map instances; }; + struct InstanceCustomData { + + virtual ~InstanceCustomData() {} + }; + struct InstanceBase { VS::InstanceType base_type; RID base; + InstanceCustomData *custom_data; + RID skeleton; RID material_override; + RID instance_data; + Transform transform; int depth_layer; @@ -185,6 +194,7 @@ public: InstanceBase() : dependency_item(this) { + custom_data = nullptr; base_type = VS::INSTANCE_NONE; cast_shadows = VS::SHADOW_CASTING_SETTING_ON; receive_shadows = true; @@ -198,6 +208,9 @@ public: } virtual ~InstanceBase() { + if (custom_data) { + memdelete(custom_data); + } clear_dependencies(); } }; @@ -225,12 +238,24 @@ public: virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) = 0; - virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; + virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0; virtual void set_scene_pass(uint64_t p_pass) = 0; + virtual void set_time(double p_time) = 0; virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) = 0; + virtual void instance_create_custom_data(InstanceBase *p_instance) = 0; + virtual void instance_free_custom_data(InstanceBase *p_instance) = 0; + virtual void instance_custom_data_update_lights(InstanceBase *p_instance) = 0; + virtual void instance_custom_data_update_reflection_probes(InstanceBase *p_instance) = 0; + virtual void instance_custom_data_update_gi_probes(InstanceBase *p_instance) = 0; + virtual void instance_custom_data_update_lightmap(InstanceBase *p_instance) = 0; + virtual void instance_custom_data_update_transform(InstanceBase *p_instance) = 0; + + virtual RID render_buffers_create() = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) = 0; + virtual bool free(RID p_rid) = 0; virtual ~RasterizerScene() {} @@ -317,9 +342,9 @@ public: virtual RID mesh_create() = 0; - virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector &p_array, int p_vertex_count, const PoolVector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector > &p_blend_shapes = Vector >(), const Vector &p_bone_aabbs = Vector()) = 0; + /// Returns stride + virtual void mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_surface) = 0; - virtual void mesh_set_blend_shape_count(RID p_mesh, int p_amount) = 0; virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; virtual void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) = 0; @@ -330,26 +355,14 @@ public: virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; - virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const = 0; - virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const = 0; + virtual VS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0; - virtual PoolVector mesh_surface_get_array(RID p_mesh, int p_surface) const = 0; - virtual PoolVector mesh_surface_get_index_array(RID p_mesh, int p_surface) const = 0; - - virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const = 0; - virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const = 0; - - virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const = 0; - virtual Vector > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const = 0; - virtual Vector mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const = 0; - - virtual void mesh_remove_surface(RID p_mesh, int p_index) = 0; virtual int mesh_get_surface_count(RID p_mesh) const = 0; virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; - virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const = 0; + virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0; virtual void mesh_clear(RID p_mesh) = 0; @@ -590,13 +603,7 @@ public: /* RENDER TARGET */ enum RenderTargetFlags { - RENDER_TARGET_VFLIP, RENDER_TARGET_TRANSPARENT, - RENDER_TARGET_NO_3D_EFFECTS, - RENDER_TARGET_NO_3D, - RENDER_TARGET_NO_SAMPLING, - RENDER_TARGET_HDR, - RENDER_TARGET_KEEP_3D_LINEAR, RENDER_TARGET_DIRECT_TO_SCREEN, RENDER_TARGET_FLAG_MAX }; diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp index f0d51f514a9..130e0e15b7c 100644 --- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -342,7 +342,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vectormesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_COLOR); } //uvs @@ -370,7 +370,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vectormesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_TEX_UV); } //bones @@ -401,7 +401,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vectormesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES); } //bones @@ -432,7 +432,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vectormesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_WEIGHTS); } //check that everything is as it should be @@ -2278,7 +2278,9 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { RD::RENDER_PRIMITIVE_LINES, RD::RENDER_PRIMITIVE_POINTS, RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_LINESTRIPS, RD::RENDER_PRIMITIVE_POINTS, }; ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = { @@ -2290,6 +2292,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { SHADER_VARIANT_PRIMITIVE_POINTS, SHADER_VARIANT_ATTRIBUTES, SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES, SHADER_VARIANT_ATTRIBUTES_POINTS }, { //lit SHADER_VARIANT_QUAD_LIGHT, @@ -2299,6 +2303,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT, SHADER_VARIANT_ATTRIBUTES_LIGHT, SHADER_VARIANT_ATTRIBUTES_LIGHT, + SHADER_VARIANT_ATTRIBUTES_LIGHT, + SHADER_VARIANT_ATTRIBUTES_LIGHT, SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT }, }; @@ -2435,60 +2441,6 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { } { - { - PoolVector colors; - colors.resize(sizeof(float) * 4); - { - PoolVector::Write w = colors.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 1.0; - fptr[1] = 1.0; - fptr[2] = 1.0; - fptr[3] = 1.0; - } - polygon_buffers.default_color_buffer = RD::get_singleton()->vertex_buffer_create(colors.size(), colors); - } - - { - PoolVector uvs; - uvs.resize(sizeof(float) * 2); - { - PoolVector::Write w = uvs.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 0.0; - fptr[1] = 0.0; - } - polygon_buffers.default_uv_buffer = RD::get_singleton()->vertex_buffer_create(uvs.size(), uvs); - } - - { - PoolVector bones; - bones.resize(sizeof(uint32_t) * 4); - { - PoolVector::Write w = bones.write(); - uint32_t *iptr = (uint32_t *)w.ptr(); - iptr[0] = 0; - iptr[1] = 0; - iptr[2] = 0; - iptr[3] = 0; - } - polygon_buffers.default_bone_buffer = RD::get_singleton()->vertex_buffer_create(bones.size(), bones); - } - - { - PoolVector weights; - weights.resize(sizeof(float) * 4); - { - PoolVector::Write w = weights.write(); - float *fptr = (float *)w.ptr(); - fptr[0] = 0.0; - fptr[1] = 0.0; - fptr[2] = 0.0; - fptr[3] = 0.0; - } - polygon_buffers.default_weight_buffer = RD::get_singleton()->vertex_buffer_create(weights.size(), weights); - } - //polygon buffers polygon_buffers.last_id = 1; } @@ -2606,10 +2558,6 @@ RasterizerCanvasRD::~RasterizerCanvasRD() { { RD::get_singleton()->free(shader.quad_index_array); RD::get_singleton()->free(shader.quad_index_buffer); - RD::get_singleton()->free(polygon_buffers.default_bone_buffer); - RD::get_singleton()->free(polygon_buffers.default_weight_buffer); - RD::get_singleton()->free(polygon_buffers.default_color_buffer); - RD::get_singleton()->free(polygon_buffers.default_uv_buffer); //primitives are erase by dependency } diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h index 8c22a4b7350..eee1b194fb2 100644 --- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h @@ -116,7 +116,9 @@ class RasterizerCanvasRD : public RasterizerCanvas { PIPELINE_VARIANT_PRIMITIVE_LINES, PIPELINE_VARIANT_PRIMITIVE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, + PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP, PIPELINE_VARIANT_ATTRIBUTE_LINES, + PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_MAX }; @@ -290,10 +292,6 @@ class RasterizerCanvasRD : public RasterizerCanvas { struct { HashMap polygons; PolygonID last_id; - RID default_color_buffer; - RID default_uv_buffer; - RID default_bone_buffer; - RID default_weight_buffer; } polygon_buffers; /********************/ diff --git a/servers/visual/rasterizer_rd/effects_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp similarity index 92% rename from servers/visual/rasterizer_rd/effects_rd.cpp rename to servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp index 90881ae7fd5..765e7182797 100644 --- a/servers/visual/rasterizer_rd/effects_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp @@ -1,6 +1,6 @@ -#include "effects_rd.h" +#include "rasterizer_effects_rd.h" -RID EffectsRD::_get_uniform_set_from_texture(RID p_texture) { +RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture) { if (texture_to_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_uniform_set_cache[p_texture]; @@ -24,7 +24,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture) { return uniform_set; } -void EffectsRD::copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) { +void RasterizerEffectsRD::copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) { zeromem(&blur.push_constant, sizeof(BlurPushConstant)); @@ -45,7 +45,7 @@ void EffectsRD::copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect RD::get_singleton()->draw_list_end(); } -void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region) { +void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region) { zeromem(&blur.push_constant, sizeof(BlurPushConstant)); @@ -86,7 +86,7 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, R RD::get_singleton()->draw_list_end(); } -EffectsRD::EffectsRD() { +RasterizerEffectsRD::RasterizerEffectsRD() { // Initialize blur Vector blur_modes; @@ -138,7 +138,7 @@ EffectsRD::EffectsRD() { } } -EffectsRD::~EffectsRD() { +RasterizerEffectsRD::~RasterizerEffectsRD() { RD::get_singleton()->free(default_sampler); blur.shader.version_free(blur.shader_version); RD::get_singleton()->free(index_buffer); //array gets freed as dependency diff --git a/servers/visual/rasterizer_rd/effects_rd.h b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h similarity index 92% rename from servers/visual/rasterizer_rd/effects_rd.h rename to servers/visual/rasterizer_rd/rasterizer_effects_rd.h index ed1bc288de0..a51340b368a 100644 --- a/servers/visual/rasterizer_rd/effects_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h @@ -1,10 +1,10 @@ -#ifndef EFFECTS_RD_H -#define EFFECTS_RD_H +#ifndef RASTERIZER_EFFECTS_RD_H +#define RASTERIZER_EFFECTS_RD_H #include "render_pipeline_vertex_format_cache_rd.h" #include "shaders/blur.glsl.gen.h" -class EffectsRD { +class RasterizerEffectsRD { enum BlurMode { BLUR_MODE_GAUSSIAN_BLUR, @@ -80,8 +80,8 @@ public: void copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region); void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region); - EffectsRD(); - ~EffectsRD(); + RasterizerEffectsRD(); + ~RasterizerEffectsRD(); }; #endif // EFFECTS_RD_H diff --git a/servers/visual/rasterizer_rd/rasterizer_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_rd.cpp index 8cc090832b9..fc38b90b886 100644 --- a/servers/visual/rasterizer_rd/rasterizer_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_rd.cpp @@ -79,6 +79,7 @@ void RasterizerRD::begin_frame(double frame_step) { frame++; time += frame_step; canvas->set_time(time); + scene->set_time(time); } void RasterizerRD::end_frame(bool p_swap_buffers) { @@ -176,5 +177,5 @@ RasterizerRD::RasterizerRD() { storage = memnew(RasterizerStorageRD); canvas = memnew(RasterizerCanvasRD(storage)); - scene = memnew(RasterizerSceneForwardRD); + scene = memnew(RasterizerSceneForwardRD(storage)); } diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp index 73c99fa70db..f63ceb9dfa1 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp @@ -29,3 +29,2005 @@ /*************************************************************************/ #include "rasterizer_scene_forward_rd.h" +#include "core/project_settings.h" +#include "servers/visual/rendering_device.h" +#include "servers/visual/visual_server_raster.h" + +static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { + p_array[0] = p_mtx.basis.elements[0][0]; + p_array[1] = p_mtx.basis.elements[1][0]; + p_array[2] = p_mtx.basis.elements[2][0]; + p_array[3] = 0; + p_array[4] = p_mtx.basis.elements[0][1]; + p_array[5] = p_mtx.basis.elements[1][1]; + p_array[6] = p_mtx.basis.elements[2][1]; + p_array[7] = 0; + p_array[8] = p_mtx.basis.elements[0][2]; + p_array[9] = p_mtx.basis.elements[1][2]; + p_array[10] = p_mtx.basis.elements[2][2]; + p_array[11] = 0; + p_array[12] = p_mtx.origin.x; + p_array[13] = p_mtx.origin.y; + p_array[14] = p_mtx.origin.z; + p_array[15] = 1; +} + +static _FORCE_INLINE_ void store_transform_3x3(const Transform &p_mtx, float *p_array) { + p_array[0] = p_mtx.basis.elements[0][0]; + p_array[1] = p_mtx.basis.elements[1][0]; + p_array[2] = p_mtx.basis.elements[2][0]; + p_array[3] = 0; + p_array[4] = p_mtx.basis.elements[0][1]; + p_array[5] = p_mtx.basis.elements[1][1]; + p_array[6] = p_mtx.basis.elements[2][1]; + p_array[7] = 0; + p_array[8] = p_mtx.basis.elements[0][2]; + p_array[9] = p_mtx.basis.elements[1][2]; + p_array[10] = p_mtx.basis.elements[2][2]; + p_array[11] = 0; +} + +static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + + p_array[i * 4 + j] = p_mtx.matrix[i][j]; + } + } +} +void RasterizerSceneForwardRD::ShaderData::set_code(const String &p_code) { + //compile + + code = p_code; + valid = false; + ubo_size = 0; + uniforms.clear(); + uses_screen_texture = false; + + if (code == String()) { + return; //just invalid, but no error + } + + ShaderCompilerRD::GeneratedCode gen_code; + + int blend_mode = BLEND_MODE_MIX; + int depth_test = DEPTH_TEST_ENABLED; + int cull = CULL_BACK; + + uses_point_size = false; + uses_alpha = false; + uses_blend_alpha = false; + uses_depth_pre_pass = false; + uses_discard = false; + uses_roughness = false; + uses_normal = false; + bool wireframe = false; + + unshaded = false; + uses_vertex = false; + uses_sss = false; + uses_screen_texture = false; + uses_depth_texture = false; + uses_normal_texture = false; + uses_time = false; + writes_modelview_or_projection = false; + uses_world_coordinates = false; + + int depth_drawi = DEPTH_DRAW_OPAQUE; + + ShaderCompilerRD::IdentifierActions actions; + + actions.render_mode_values["blend_add"] = Pair(&blend_mode, BLEND_MODE_ADD); + actions.render_mode_values["blend_mix"] = Pair(&blend_mode, BLEND_MODE_MIX); + actions.render_mode_values["blend_sub"] = Pair(&blend_mode, BLEND_MODE_SUB); + actions.render_mode_values["blend_mul"] = Pair(&blend_mode, BLEND_MODE_MUL); + + actions.render_mode_values["depth_draw_never"] = Pair(&depth_drawi, DEPTH_DRAW_DISABLED); + actions.render_mode_values["depth_draw_opaque"] = Pair(&depth_drawi, DEPTH_DRAW_OPAQUE); + actions.render_mode_values["depth_draw_always"] = Pair(&depth_drawi, DEPTH_DRAW_ALWAYS); + + actions.render_mode_values["depth_test_disabled"] = Pair(&depth_test, DEPTH_TEST_DISABLED); + + actions.render_mode_values["cull_disabled"] = Pair(&cull, CULL_DISABLED); + actions.render_mode_values["cull_front"] = Pair(&cull, CULL_FRONT); + actions.render_mode_values["cull_back"] = Pair(&cull, CULL_BACK); + + actions.render_mode_flags["unshaded"] = &unshaded; + actions.render_mode_flags["wireframe"] = &wireframe; + + actions.usage_flag_pointers["ALPHA"] = &uses_alpha; + actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass; + + actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss; + + actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; + actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture; + actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture; + actions.usage_flag_pointers["DISCARD"] = &uses_discard; + actions.usage_flag_pointers["TIME"] = &uses_time; + actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; + actions.usage_flag_pointers["NORMAL"] = &uses_normal; + actions.usage_flag_pointers["NORMALMAP"] = &uses_normal; + + actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; + actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; + + actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; + actions.write_flag_pointers["VERTEX"] = &uses_vertex; + + actions.uniforms = &uniforms; + + RasterizerSceneForwardRD *scene_singleton = (RasterizerSceneForwardRD *)RasterizerSceneForwardRD::singleton; + + Error err = scene_singleton->shader.compiler.compile(VS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code); + + ERR_FAIL_COND(err != OK); + + if (version.is_null()) { + version = scene_singleton->shader.scene_shader.version_create(); + } + + depth_draw = DepthDraw(depth_drawi); + +#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 + scene_singleton->shader.scene_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines); + ERR_FAIL_COND(!scene_singleton->shader.scene_shader.version_is_valid(version)); + + ubo_size = gen_code.uniform_total_size; + ubo_offsets = gen_code.uniform_offsets; + texture_uniforms = gen_code.texture_uniforms; + + //blend modes + + RD::PipelineColorBlendState::Attachment blend_attachment; + + switch (blend_mode) { + case BLEND_MODE_MIX: { + + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + } break; + case BLEND_MODE_ADD: { + + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_SUB: { + + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + uses_blend_alpha = true; //force alpha used because of blend + + } break; + case BLEND_MODE_MUL: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + uses_blend_alpha = true; //force alpha used because of blend + } break; + } + + RD::PipelineColorBlendState blend_state_blend; + blend_state_blend.attachments.push_back(blend_attachment); + RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1); + RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2); + + //update pipelines + + RD::PipelineDepthStencilState depth_stencil_state; + + if (depth_test != DEPTH_TEST_DISABLED) { + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; + } + + bool first = true; + + for (int i = 0; i < CULL_VARIANT_MAX; i++) { + + RD::PolygonCullMode cull_mode_rd_table[3][CULL_VARIANT_MAX] = { + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT }, + { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED } + }; + + RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[cull][i]; + + for (int j = 0; j < VS::PRIMITIVE_MAX; j++) { + + RD::RenderPrimitive primitive_rd_table[VS::PRIMITIVE_MAX] = { + RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_LINESTRIPS, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, + }; + + RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; + + for (int k = 0; k < SHADER_VERSION_MAX; k++) { + + RD::PipelineRasterizationState raster_state; + raster_state.cull_mode = cull_mode_rd; + raster_state.wireframe = wireframe; + + RD::PipelineColorBlendState blend_state; + RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; + + if (uses_alpha || uses_blend_alpha) { + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_VCT_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_blend; + if (depth_draw == DEPTH_DRAW_OPAQUE) { + depth_stencil.enable_depth_write = false; //alpha does not draw depth + } + } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS)) { + if (k == SHADER_VERSION_DEPTH_PASS) { + //none, blend state contains nothing + } else { + blend_state = blend_state_opaque; //writes to normal and roughness in opaque way + } + } else { + pipelines[i][j][k].clear(); + continue; // do not use this version (will error if using it is attempted) + } + } else { + + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_VCT_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + blend_state = blend_state_opaque; + } else if (k == SHADER_VERSION_DEPTH_PASS) { + //none, leave empty + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { + blend_state = blend_state_opaque; //writes to normal and roughness in opaque way + } else { + //specular write + blend_state = blend_state_opaque_specular; + } + } + + RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k); + + if (first) { + //should be the same for all, so.. + vertex_input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader_variant); + } + pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, RD::PipelineMultisampleState(), depth_stencil, blend_state, 0); + } + } + } + + valid = true; +} + +void RasterizerSceneForwardRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { + if (!p_texture.is_valid()) { + default_texture_params.erase(p_name); + } else { + default_texture_params[p_name] = p_texture; + } +} +void RasterizerSceneForwardRD::ShaderData::get_param_list(List *p_param_list) const { + + Map order; + + for (Map::Element *E = uniforms.front(); E; E = E->next()) { + + if (E->get().texture_order >= 0) { + order[E->get().texture_order + 100000] = E->key(); + } else { + order[E->get().order] = E->key(); + } + } + + for (Map::Element *E = order.front(); E; E = E->next()) { + + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); + pi.name = E->get(); + p_param_list->push_back(pi); + } +} + +bool RasterizerSceneForwardRD::ShaderData::is_param_texture(const StringName &p_param) const { + if (!uniforms.has(p_param)) { + return false; + } + + return uniforms[p_param].texture_order >= 0; +} + +bool RasterizerSceneForwardRD::ShaderData::is_animated() const { + return false; +} +bool RasterizerSceneForwardRD::ShaderData::casts_shadows() const { + return false; +} +Variant RasterizerSceneForwardRD::ShaderData::get_default_parameter(const StringName &p_parameter) const { + if (uniforms.has(p_parameter)) { + ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; + Vector default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + } + return Variant(); +} + +RasterizerSceneForwardRD::ShaderData::ShaderData() { + valid = false; + uses_screen_texture = false; +} + +RasterizerSceneForwardRD::ShaderData::~ShaderData() { + RasterizerSceneForwardRD *scene_singleton = (RasterizerSceneForwardRD *)RasterizerSceneForwardRD::singleton; + ERR_FAIL_COND(!scene_singleton); + //pipeline variants will clear themselves if shader is gone + if (version.is_valid()) { + scene_singleton->shader.scene_shader.version_free(version); + } +} + +RasterizerStorageRD::ShaderData *RasterizerSceneForwardRD::_create_shader_func() { + ShaderData *shader_data = memnew(ShaderData); + return shader_data; +} + +void RasterizerSceneForwardRD::MaterialData::set_render_priority(int p_priority) { + priority = p_priority - VS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits +} + +void RasterizerSceneForwardRD::MaterialData::set_next_pass(RID p_pass) { + next_pass = p_pass; +} + +void RasterizerSceneForwardRD::MaterialData::update_parameters(const Map &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + + RasterizerSceneForwardRD *scene_singleton = (RasterizerSceneForwardRD *)RasterizerSceneForwardRD::singleton; + + if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { + p_uniform_dirty = true; + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + uniform_buffer = RID(); + } + + ubo_data.resize(shader_data->ubo_size); + if (ubo_data.size()) { + uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); + memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear + } + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + //check whether buffer changed + if (p_uniform_dirty && ubo_data.size()) { + + update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); + RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); + } + + uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); + + if ((uint32_t)texture_cache.size() != tex_uniform_count) { + texture_cache.resize(tex_uniform_count); + p_textures_dirty = true; + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + if (p_textures_dirty && tex_uniform_count) { + + update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw()); + } + + if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { + // This material does not require an uniform set, so don't create it. + return; + } + + if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + //no reason to update uniform set, only UBO (or nothing) was needed to update + return; + } + + Vector uniforms; + + { + + if (shader_data->ubo_size) { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(uniform_buffer); + uniforms.push_back(u); + } + + const RID *textures = texture_cache.ptrw(); + for (uint32_t i = 0; i < tex_uniform_count; i++) { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1 + i; + u.ids.push_back(textures[i]); + uniforms.push_back(u); + } + } + + uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), 3); +} +RasterizerSceneForwardRD::MaterialData::~MaterialData() { + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->free(uniform_set); + } + + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + } +} + +RasterizerStorageRD::MaterialData *RasterizerSceneForwardRD::_create_material_func(ShaderData *p_shader) { + MaterialData *material_data = memnew(MaterialData); + material_data->shader_data = p_shader; + material_data->last_frame = false; + //update will happen later anyway so do nothing. + return material_data; +} + +RasterizerSceneForwardRD::RenderBufferDataForward::~RenderBufferDataForward() { + clear(); +} + +void RasterizerSceneForwardRD::RenderBufferDataForward::clear() { + + if (color_fb.is_valid()) { + RD::get_singleton()->free(color_fb); + color_fb = RID(); + } + + if (color.is_valid()) { + RD::get_singleton()->free(color); + color = RID(); + } + + if (depth.is_valid()) { + RD::get_singleton()->free(depth); + depth = RID(); + } +} + +void RasterizerSceneForwardRD::RenderBufferDataForward::configure(RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) { + clear(); + + width = p_width; + height = p_height; + + render_target = p_render_target; + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = p_width; + tf.height = p_height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + color = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + { + RD::TextureFormat tf; + tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; + tf.width = p_width; + tf.height = p_height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } + + { + Vector fb; + fb.push_back(color); + fb.push_back(depth); + + color_fb = RD::get_singleton()->framebuffer_create(fb); + } +} + +RasterizerSceneRD::RenderBufferData *RasterizerSceneForwardRD::_create_render_buffer_data() { + return memnew(RenderBufferDataForward); +} + +bool RasterizerSceneForwardRD::free(RID p_rid) { + if (RasterizerSceneRD::free(p_rid)) { + return true; + } + return false; +} +/// INSTANCE DATA /// + +void RasterizerSceneForwardRD::instance_create_custom_data(InstanceBase *p_instance) { + InstanceGeometryData *geom_data = memnew(InstanceGeometryData); + geom_data->ubo = RD::get_singleton()->uniform_buffer_create(sizeof(InstanceGeometryData::UBO)); +} + +void RasterizerSceneForwardRD::instance_free_custom_data(InstanceBase *p_instance) { + InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; + ERR_FAIL_COND(!geom_data); + RD::get_singleton()->free(geom_data->ubo); + //uniform sets are freed as dependencies + memdelete(geom_data); + p_instance->custom_data = nullptr; +} + +void RasterizerSceneForwardRD::instance_custom_data_update_lights(InstanceBase *p_instance) { + //unused +} + +void RasterizerSceneForwardRD::instance_custom_data_update_reflection_probes(InstanceBase *p_instance) { + //unused +} +void RasterizerSceneForwardRD::instance_custom_data_update_lightmap(InstanceBase *p_instance) { + InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; + ERR_FAIL_COND(!geom_data); + + geom_data->using_lightmap_gi = p_instance->lightmap.is_valid(); + + if (geom_data->uniform_set_gi.is_valid() && RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_gi)) { + RD::get_singleton()->free(geom_data->uniform_set_gi); + } + geom_data->uniform_set_gi = RID(); +} + +void RasterizerSceneForwardRD::instance_custom_data_update_gi_probes(InstanceBase *p_instance) { + InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; + ERR_FAIL_COND(!geom_data); + + geom_data->using_vct_gi = p_instance->gi_probe_instances.size(); + + if (geom_data->uniform_set_gi.is_valid() && RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_gi)) { + RD::get_singleton()->free(geom_data->uniform_set_gi); + } + geom_data->uniform_set_gi = RID(); +} + +void RasterizerSceneForwardRD::instance_custom_data_update_transform(InstanceBase *p_instance) { + InstanceGeometryData *geom_data = (InstanceGeometryData *)p_instance->custom_data; + ERR_FAIL_COND(!geom_data); + + geom_data->ubo_dirty = true; +} + +/// RENDERING /// + +void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_screen_uniform_set, bool p_no_gi) { + + RD::DrawListID draw_list = p_draw_list; + RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; + + //global scope bindings + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_screen_uniform_set, 0); + + MaterialData *prev_material = nullptr; + // ShaderData *prev_shader = nullptr; + + RID prev_vertex_array_rd; + RID prev_index_array_rd; + + for (int i = 0; i < p_element_count; i++) { + + const RenderList::Element *e = p_elements[i]; + + MaterialData *material = e->material; + ShaderData *shader = material->shader_data; + + //find cull variant + ShaderData::CullVariant cull_variant; + + if (p_pass_mode == PASS_MODE_SHADOW && e->instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { + cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; + } else { + bool mirror = e->instance->mirror; + if (p_reverse_cull) { + mirror = !mirror; + } + cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL; + } + + //find primitive and vertex format + VS::PrimitiveType primitive; + RD::VertexFormatID vertex_format; + RID vertex_array_rd; + RID index_array_rd; + RID prev_pipeline_rd; + + switch (e->instance->base_type) { + case VS::INSTANCE_MESH: { + storage->mesh_get_arrays_primitive_and_format(e->instance->base, e->surface_index, shader->vertex_input_mask, primitive, vertex_array_rd, index_array_rd, vertex_format); + } break; + case VS::INSTANCE_MULTIMESH: { + + } break; + case VS::INSTANCE_IMMEDIATE: { + + } break; + case VS::INSTANCE_PARTICLES: { + + } break; + default: { + ERR_CONTINUE(true); //should be a bug + } + } + + if (prev_vertex_array_rd != vertex_array_rd) { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd); + prev_vertex_array_rd = vertex_array_rd; + } + if (prev_index_array_rd != index_array_rd) { + if (index_array_rd.is_valid()) { + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd); + } + prev_index_array_rd = index_array_rd; + } + + InstanceGeometryData *geom_data = (InstanceGeometryData *)e->instance->custom_data; + + ShaderVersion shader_version; + RID instance_uniform_set; + + switch (p_pass_mode) { + case PASS_MODE_COLOR: + case PASS_MODE_COLOR_TRANSPARENT: { + + if (p_no_gi) { + instance_uniform_set = geom_data->uniform_set_base; + shader_version = SHADER_VERSION_COLOR_PASS; + } else if (geom_data->using_lightmap_gi) { + instance_uniform_set = geom_data->uniform_set_gi; + shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; + } else if (geom_data->using_vct_gi) { + instance_uniform_set = geom_data->uniform_set_gi; + shader_version = SHADER_VERSION_VCT_COLOR_PASS; + } else { + instance_uniform_set = geom_data->uniform_set_base; + shader_version = SHADER_VERSION_COLOR_PASS; + } + } break; + case PASS_MODE_COLOR_SPECULAR: { + if (p_no_gi) { + instance_uniform_set = geom_data->uniform_set_base; + shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; + } else if (geom_data->using_lightmap_gi) { + instance_uniform_set = geom_data->uniform_set_gi; + shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; + } else if (geom_data->using_vct_gi) { + instance_uniform_set = geom_data->uniform_set_gi; + shader_version = SHADER_VERSION_VCT_COLOR_PASS_WITH_SEPARATE_SPECULAR; + } else { + instance_uniform_set = geom_data->uniform_set_base; + shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; + } + } break; + case PASS_MODE_SHADOW: { + shader_version = SHADER_VERSION_DEPTH_PASS; + instance_uniform_set = geom_data->uniform_set_base; + } break; + case PASS_MODE_DEPTH: { + shader_version = SHADER_VERSION_DEPTH_PASS; + instance_uniform_set = geom_data->uniform_set_base; + } break; + case PASS_MODE_DEPTH_NORMAL: { + shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL; + instance_uniform_set = geom_data->uniform_set_base; + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; + instance_uniform_set = geom_data->uniform_set_base; + } break; + } + + RenderPipelineVertexFormatCacheRD *pipeline = nullptr; + + pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; + + RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format); + + if (pipeline_rd != prev_pipeline_rd) { + // checking with prev shader does not make so much sense, as + // the pipeline may still be different. + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd); + prev_pipeline_rd = pipeline_rd; + } + + if (material != prev_material) { + //update uniform set + if (material->uniform_set.is_valid()) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, 2); + } + + prev_material = material; + } + + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, instance_uniform_set, 3); + + switch (e->instance->base_type) { + case VS::INSTANCE_MESH: { + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid()); + } break; + case VS::INSTANCE_MULTIMESH: { + + } break; + case VS::INSTANCE_IMMEDIATE: { + + } break; + case VS::INSTANCE_PARTICLES: { + + } break; + default: { + ERR_CONTINUE(true); //should be a bug + } + } + } +} + +void RasterizerSceneForwardRD::_setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog) { + Transform sky_orientation; + + //store camera into ubo + store_camera(p_cam_projection, scene_state.ubo.projection_matrix); + store_camera(p_cam_projection.inverse(), scene_state.ubo.inv_projection_matrix); + store_transform(p_cam_transform, scene_state.ubo.camera_matrix); + store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + + //time global variables + scene_state.ubo.time = time; + + RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo, true); + +#if 0 + //bg and ambient + if (p_environment.is_valid()) { + + state.ubo_data.bg_energy = env->bg_energy; + state.ubo_data.ambient_energy = env->ambient_energy; + Color linear_ambient_color = env->ambient_color.to_linear(); + state.ubo_data.ambient_light_color[0] = linear_ambient_color.r; + state.ubo_data.ambient_light_color[1] = linear_ambient_color.g; + state.ubo_data.ambient_light_color[2] = linear_ambient_color.b; + state.ubo_data.ambient_light_color[3] = linear_ambient_color.a; + + Color bg_color; + + switch (env->bg_mode) { + case VS::ENV_BG_CLEAR_COLOR: { + bg_color = storage->frame.clear_request_color.to_linear(); + } break; + case VS::ENV_BG_COLOR: { + bg_color = env->bg_color.to_linear(); + } break; + default: { + bg_color = Color(0, 0, 0, 1); + } break; + } + + state.ubo_data.bg_color[0] = bg_color.r; + state.ubo_data.bg_color[1] = bg_color.g; + state.ubo_data.bg_color[2] = bg_color.b; + state.ubo_data.bg_color[3] = bg_color.a; + + //use the inverse of our sky_orientation, we may need to skip this if we're using a reflection probe? + sky_orientation = Transform(env->sky_orientation, Vector3(0.0, 0.0, 0.0)).affine_inverse(); + + state.env_radiance_data.ambient_contribution = env->ambient_sky_contribution; + state.ubo_data.ambient_occlusion_affect_light = env->ssao_light_affect; + state.ubo_data.ambient_occlusion_affect_ssao = env->ssao_ao_channel_affect; + + //fog + + Color linear_fog = env->fog_color.to_linear(); + state.ubo_data.fog_color_enabled[0] = linear_fog.r; + state.ubo_data.fog_color_enabled[1] = linear_fog.g; + state.ubo_data.fog_color_enabled[2] = linear_fog.b; + state.ubo_data.fog_color_enabled[3] = (!p_no_fog && env->fog_enabled) ? 1.0 : 0.0; + state.ubo_data.fog_density = linear_fog.a; + + Color linear_sun = env->fog_sun_color.to_linear(); + state.ubo_data.fog_sun_color_amount[0] = linear_sun.r; + state.ubo_data.fog_sun_color_amount[1] = linear_sun.g; + state.ubo_data.fog_sun_color_amount[2] = linear_sun.b; + state.ubo_data.fog_sun_color_amount[3] = env->fog_sun_amount; + state.ubo_data.fog_depth_enabled = env->fog_depth_enabled; + state.ubo_data.fog_depth_begin = env->fog_depth_begin; + state.ubo_data.fog_depth_end = env->fog_depth_end; + state.ubo_data.fog_depth_curve = env->fog_depth_curve; + state.ubo_data.fog_transmit_enabled = env->fog_transmit_enabled; + state.ubo_data.fog_transmit_curve = env->fog_transmit_curve; + state.ubo_data.fog_height_enabled = env->fog_height_enabled; + state.ubo_data.fog_height_min = env->fog_height_min; + state.ubo_data.fog_height_max = env->fog_height_max; + state.ubo_data.fog_height_curve = env->fog_height_curve; + + } else { + state.ubo_data.bg_energy = 1.0; + state.ubo_data.ambient_energy = 1.0; + //use from clear color instead, since there is no ambient + Color linear_ambient_color = storage->frame.clear_request_color.to_linear(); + state.ubo_data.ambient_light_color[0] = linear_ambient_color.r; + state.ubo_data.ambient_light_color[1] = linear_ambient_color.g; + state.ubo_data.ambient_light_color[2] = linear_ambient_color.b; + state.ubo_data.ambient_light_color[3] = linear_ambient_color.a; + + state.ubo_data.bg_color[0] = linear_ambient_color.r; + state.ubo_data.bg_color[1] = linear_ambient_color.g; + state.ubo_data.bg_color[2] = linear_ambient_color.b; + state.ubo_data.bg_color[3] = linear_ambient_color.a; + + state.env_radiance_data.ambient_contribution = 0; + state.ubo_data.ambient_occlusion_affect_light = 0; + + state.ubo_data.fog_color_enabled[3] = 0.0; + } + + { + //directional shadow + + state.ubo_data.shadow_directional_pixel_size[0] = 1.0 / directional_shadow.size; + state.ubo_data.shadow_directional_pixel_size[1] = 1.0 / directional_shadow.size; + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + } + + glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(State::SceneDataUBO), &state.ubo_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + //fill up environment + + store_transform(sky_orientation * p_cam_transform, state.env_radiance_data.transform); + + glBindBuffer(GL_UNIFORM_BUFFER, state.env_radiance_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +#endif +} + +void RasterizerSceneForwardRD::_add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode) { + + RID m_src = p_instance->material_override.is_valid() ? p_instance->material_override : p_material; + + /*if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { + m_src = default_overdraw_material; + }*/ + + MaterialData *material = NULL; + + if (m_src.is_valid()) { + material = (MaterialData *)storage->material_get_data(m_src, RasterizerStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + material = NULL; + } + } + + if (!material) { + material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); + } + + ERR_FAIL_COND(!material); + + _add_geometry_with_material(p_instance, p_surface, material, p_pass_mode); + + while (material->next_pass.is_valid()) { + + material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) + break; + _add_geometry_with_material(p_instance, p_surface, material, p_pass_mode); + } +} + +void RasterizerSceneForwardRD::_add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, PassMode p_pass_mode) { + + bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; + bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); + bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; + bool has_alpha = has_base_alpha || has_blend_alpha; + + if (p_material->shader_data->uses_sss) { + scene_state.used_sss = true; + } + + if (p_material->shader_data->uses_screen_texture) { + scene_state.used_screen_texture = true; + } + + if (p_material->shader_data->uses_depth_texture) { + scene_state.used_depth_texture = true; + } + + if (p_material->shader_data->uses_normal_texture) { + scene_state.used_normal_texture = true; + } + + if (p_pass_mode != PASS_MODE_COLOR && p_pass_mode != PASS_MODE_COLOR_SPECULAR) { + + if (has_blend_alpha || has_read_screen_alpha || (has_base_alpha && !p_material->shader_data->uses_depth_pre_pass) || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED || p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF) { + //conditions in which no depth pass should be processed + return; + } + + if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + //shader does not use discard and does not write a vertex position, use generic material + if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) { + p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); + } else if (p_pass_mode == PASS_MODE_DEPTH_NORMAL && !p_material->shader_data->uses_normal) { + p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); + } else if (p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS && !p_material->shader_data->uses_normal && !p_material->shader_data->uses_roughness) { + p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); + } + } + + has_alpha = false; + } + + RenderList::Element *e = (has_alpha || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) ? render_list.add_alpha_element() : render_list.add_element(); + + if (!e) + return; + + e->instance = p_instance; + e->material = p_material; + e->surface_index = p_surface; + e->sort_key = 0; + + if (e->material->last_pass != render_pass) { + e->material->last_pass = render_pass; + e->material->index = scene_state.current_material_index++; + if (e->material->shader_data->last_pass != render_pass) { + e->material->shader_data->last_pass = scene_state.current_material_index++; + e->material->shader_data->index = scene_state.current_shader_index++; + } + } + + e->material_index = e->material->index; + e->shader_index = e->shader_index; + e->depth_layer = e->instance->depth_layer; + e->priority = p_material->priority; + + if (p_material->shader_data->uses_time) { + VisualServerRaster::redraw_request(); + } +} + +void RasterizerSceneForwardRD::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi) { + + scene_state.current_shader_index = 0; + scene_state.current_material_index = 0; + scene_state.used_sss = false; + scene_state.used_screen_texture = false; + scene_state.used_normal_texture = false; + scene_state.used_depth_texture = false; + + //fill list + + for (int i = 0; i < p_cull_count; i++) { + + InstanceBase *inst = p_cull_result[i]; + + InstanceGeometryData *geom_data = (InstanceGeometryData *)inst->custom_data; + + ERR_CONTINUE(!geom_data); + + if (geom_data->ubo_dirty) { + //ubo marked dirty, must be updated + InstanceGeometryData::UBO ubo; + store_transform(inst->transform, ubo.transform); + store_transform_3x3(inst->transform.basis.inverse().transposed(), ubo.normal_transform); + ubo.flags = 0; + ubo.pad[0]; + ubo.pad[1]; + ubo.pad[2]; + RD::get_singleton()->buffer_update(geom_data->ubo, 0, sizeof(InstanceGeometryData::UBO), &ubo, true); + } + + if (p_no_gi) { + if (geom_data->uniform_set_base.is_null() || !RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_base)) { + + Vector uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(geom_data->ubo); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; + u.binding = 1; + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER)); + uniforms.push_back(u); + } + + geom_data->uniform_set_base = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 3); + } + } else { + if (geom_data->uniform_set_gi.is_null() || !RD::get_singleton()->uniform_set_is_valid(geom_data->uniform_set_gi)) { + + Vector uniforms; + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(geom_data->ubo); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; + u.binding = 1; + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER)); + uniforms.push_back(u); + } + + if (geom_data->using_lightmap_gi) { + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; +#ifndef _MSC_VER +#warning Need to put actual lightmap or lightmap capture texture if exists +#endif + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + uniforms.push_back(u); + } + } else if (geom_data->using_vct_gi) { +#ifndef _MSC_VER +#warning Need to put actual vct textures here +#endif + } + + geom_data->uniform_set_gi = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 3); + } + } + + //add geometry for drawing + switch (inst->base_type) { + + case VS::INSTANCE_MESH: { + + const RID *materials = NULL; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(inst->base, surface_count); + if (!materials) { + continue; //nothing to do + } + + const RID *inst_materials = inst->materials.ptr(); + + for (uint32_t j = 0; j < surface_count; j++) { + + RID material = inst_materials[j].is_valid() ? inst_materials[j] : materials[j]; + + _add_geometry(inst, j, material, p_pass_mode); + } + + //mesh->last_pass=frame; + + } break; +#if 0 + case VS::INSTANCE_MULTIMESH: { + + RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(inst->base); + ERR_CONTINUE(!multi_mesh); + + if (multi_mesh->size == 0 || multi_mesh->visible_instances == 0) + continue; + + RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getornull(multi_mesh->mesh); + if (!mesh) + continue; //mesh not assigned + + int ssize = mesh->surfaces.size(); + + for (int j = 0; j < ssize; j++) { + + RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; + _add_geometry(s, inst, multi_mesh, -1, p_depth_pass, p_shadow_pass); + } + + } break; + case VS::INSTANCE_IMMEDIATE: { + + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + ERR_CONTINUE(!immediate); + + _add_geometry(immediate, inst, NULL, -1, p_depth_pass, p_shadow_pass); + + } break; + case VS::INSTANCE_PARTICLES: { + + RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(inst->base); + ERR_CONTINUE(!particles); + + for (int j = 0; j < particles->draw_passes.size(); j++) { + + RID pmesh = particles->draw_passes[j]; + if (!pmesh.is_valid()) + continue; + RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getornull(pmesh); + if (!mesh) + continue; //mesh not assigned + + int ssize = mesh->surfaces.size(); + + for (int k = 0; k < ssize; k++) { + + RasterizerStorageGLES3::Surface *s = mesh->surfaces[k]; + _add_geometry(s, inst, particles, -1, p_depth_pass, p_shadow_pass); + } + } + + } break; +#endif + default: { + } + } + } +} + +void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { + + RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)p_buffer_data; + + ERR_FAIL_COND(!render_buffer); //bug out for now + + //first of all, make a new render pass + render_pass++; + + //fill up ubo +#if 0 + storage->info.render.object_count += p_cull_count; + + Environment *env = environment_owner.getornull(p_environment); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); + + if (shadow_atlas && shadow_atlas->size) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / shadow_atlas->size; + scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / shadow_atlas->size; + } + + if (reflection_atlas && reflection_atlas->size) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); + } +#endif + if (p_reflection_probe.is_valid()) { + scene_state.ubo.reflection_multiplier = 0.0; + } else { + scene_state.ubo.reflection_multiplier = 1.0; + } + + //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; + + scene_state.ubo.shadow_z_offset = 0; + scene_state.ubo.shadow_z_slope_scale = 0; + + Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); + scene_state.ubo.viewport_size[0] = vp_he.x; + scene_state.ubo.viewport_size[1] = vp_he.y; + + if (render_buffer) { + scene_state.ubo.screen_pixel_size[0] = 1.0 / render_buffer->width; + scene_state.ubo.screen_pixel_size[1] = 1.0 / render_buffer->height; + } + + _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid()); +#if 0 + for (int i = 0; i < p_light_cull_count; i++) { + + ERR_BREAK(i >= RenderList::MAX_LIGHTS); + + LightInstance *li = light_instance_owner.getornull(p_light_cull_result[i]); + if (li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] > CMP_EPSILON) { + state.used_contact_shadows = true; + } + } +#endif +#if 0 + // Do depth prepass if it's explicitly enabled + bool use_depth_prepass = storage->config.use_depth_prepass; + + // If contact shadows are used then we need to do depth prepass even if it's otherwise disabled + use_depth_prepass = use_depth_prepass || state.used_contact_shadows; + + // Never do depth prepass if effects are disabled or if we render overdraws + use_depth_prepass = use_depth_prepass && storage->frame.current_rt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; + use_depth_prepass = use_depth_prepass && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; + + if (use_depth_prepass) { + //pre z pass + + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + glDrawBuffers(0, NULL); + + glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + + glColorMask(0, 0, 0, 0); + glClearDepth(1.0f); + glClear(GL_DEPTH_BUFFER_BIT); + + render_list.clear(); + _fill_render_list(p_cull_result, p_cull_count, true, false); + render_list.sort_by_key(false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, true); + _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, 0, false, false, true, false, false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH, false); + + glColorMask(1, 1, 1, 1); + + if (state.used_contact_shadows) { + + _prepare_depth_texture(); + _bind_depth_texture(); + } + + fb_cleared = true; + render_pass++; + state.used_depth_prepass = true; + } else { + state.used_depth_prepass = false; + } + + _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_shadow_atlas); + _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_reflection_atlas, env); + + bool use_mrt = false; +#endif + render_list.clear(); + _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr); +#if 0 + // + + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + + //rendering to a probe cubemap side + ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe); + GLuint current_fbo; + + if (probe) { + + ReflectionAtlas *ref_atlas = reflection_atlas_owner.getornull(probe->atlas); + ERR_FAIL_COND(!ref_atlas); + + int target_size = ref_atlas->size / ref_atlas->subdiv; + + int cubemap_index = reflection_cubemaps.size() - 1; + + for (int i = reflection_cubemaps.size() - 1; i >= 0; i--) { + //find appropriate cubemap to render to + if (reflection_cubemaps[i].size > target_size * 2) + break; + + cubemap_index = i; + } + + current_fbo = reflection_cubemaps[cubemap_index].fbo_id[p_reflection_probe_pass]; + use_mrt = false; + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false); + + glViewport(0, 0, reflection_cubemaps[cubemap_index].size, reflection_cubemaps[cubemap_index].size); + glBindFramebuffer(GL_FRAMEBUFFER, current_fbo); + + } else { + + use_mrt = env && (state.used_sss || env->ssao_enabled || env->ssr_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); //only enable MRT rendering if any of these is enabled + //effects disabled and transparency also prevent using MRTs + use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; + use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; + use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; + use_mrt = use_mrt && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS); + + glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + + if (use_mrt) { + + current_fbo = storage->frame.current_rt->buffers.fbo; + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, true); + + Vector draw_buffers; + draw_buffers.push_back(GL_COLOR_ATTACHMENT0); + draw_buffers.push_back(GL_COLOR_ATTACHMENT1); + draw_buffers.push_back(GL_COLOR_ATTACHMENT2); + if (state.used_sss) { + draw_buffers.push_back(GL_COLOR_ATTACHMENT3); + } + glDrawBuffers(draw_buffers.size(), draw_buffers.ptr()); + + Color black(0, 0, 0, 0); + glClearBufferfv(GL_COLOR, 1, black.components); // specular + glClearBufferfv(GL_COLOR, 2, black.components); // normal metal rough + if (state.used_sss) { + glClearBufferfv(GL_COLOR, 3, black.components); // normal metal rough + } + + } else { + + if (storage->frame.current_rt->buffers.active) { + current_fbo = storage->frame.current_rt->buffers.fbo; + } else { + current_fbo = storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo; + } + + glBindFramebuffer(GL_FRAMEBUFFER, current_fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false); + + Vector draw_buffers; + draw_buffers.push_back(GL_COLOR_ATTACHMENT0); + glDrawBuffers(draw_buffers.size(), draw_buffers.ptr()); + } + } + + if (!fb_cleared) { + glClearDepth(1.0f); + glClear(GL_DEPTH_BUFFER_BIT); + } + + Color clear_color(0, 0, 0, 0); + + RasterizerStorageGLES3::Sky *sky = NULL; + Ref feed; + GLuint env_radiance_tex = 0; + + if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { + clear_color = Color(0, 0, 0, 0); + storage->frame.clear_request = false; + } else if (!probe && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + clear_color = Color(0, 0, 0, 0); + storage->frame.clear_request = false; + + } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR) { + + if (storage->frame.clear_request) { + + clear_color = storage->frame.clear_request_color.to_linear(); + storage->frame.clear_request = false; + } + + } else if (env->bg_mode == VS::ENV_BG_CANVAS) { + + clear_color = env->bg_color.to_linear(); + storage->frame.clear_request = false; + } else if (env->bg_mode == VS::ENV_BG_COLOR) { + + clear_color = env->bg_color.to_linear(); + storage->frame.clear_request = false; + } else if (env->bg_mode == VS::ENV_BG_SKY) { + + storage->frame.clear_request = false; + + } else if (env->bg_mode == VS::ENV_BG_COLOR_SKY) { + + clear_color = env->bg_color.to_linear(); + storage->frame.clear_request = false; + + } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) { + feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id); + storage->frame.clear_request = false; + } else { + storage->frame.clear_request = false; + } + + if (!env || env->bg_mode != VS::ENV_BG_KEEP) { + glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular + } + + VS::EnvironmentBG bg_mode = (!env || (probe && env->bg_mode == VS::ENV_BG_CANVAS)) ? VS::ENV_BG_CLEAR_COLOR : env->bg_mode; //if no environment, or canvas while rendering a probe (invalid use case), use color. + + if (env) { + switch (bg_mode) { + case VS::ENV_BG_COLOR_SKY: + case VS::ENV_BG_SKY: + + sky = storage->sky_owner.getornull(env->sky); + + if (sky) { + env_radiance_tex = sky->radiance; + } + break; + case VS::ENV_BG_CANVAS: + //copy canvas to 3d buffer and convert it to linear + + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); + + storage->shaders.copy.bind(); + + _copy_screen(true, true); + + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); + + //restore + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + break; + case VS::ENV_BG_CAMERA_FEED: + if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) { + // copy our camera feed to our background + + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); + + if (feed->get_datatype() == CameraFeed::FEED_RGB) { + RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE); + + VS::get_singleton()->texture_bind(camera_RGBA, 0); + } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) { + RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE); + + VS::get_singleton()->texture_bind(camera_YCbCr, 0); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true); + + } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) { + RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE); + RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE); + + VS::get_singleton()->texture_bind(camera_Y, 0); + VS::get_singleton()->texture_bind(camera_CbCr, 1); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true); + }; + + storage->shaders.copy.bind(); + storage->shaders.copy.set_uniform(CopyShaderGLES3::DISPLAY_TRANSFORM, feed->get_transform()); + + _copy_screen(true, true); + + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, false); + + //restore + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + } else { + // don't have a feed, just show greenscreen :) + clear_color = Color(0.0, 1.0, 0.0, 1.0); + } + break; + default: { + } + } + } + + if (probe && probe->probe_ptr->interior) { + env_radiance_tex = 0; //for rendering probe interiors, radiance must not be used. + } + + state.texscreen_copied = false; + + glBlendEquation(GL_FUNC_ADD); + + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + } +#endif + + render_list.sort_by_key(false); + + { + //regular forward for now + Vector c; + c.push_back(Color(0, 0, 0, 1)); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(render_buffer->color_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, c); + + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(render_buffer->color_fb), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, default_render_buffer_uniform_set, render_buffer == nullptr); + RD::get_singleton()->draw_list_end(); + } + + //_render_list +#if 0 + if (state.directional_light_count == 0) { + directional_light = NULL; + _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, false, shadow_atlas != NULL); + } else { + for (int i = 0; i < state.directional_light_count; i++) { + directional_light = directional_lights[i]; + if (i > 0) { + glEnable(GL_BLEND); + } + _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0); + _render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, i > 0, shadow_atlas != NULL); + } + } + + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS, false); + + if (use_mrt) { + GLenum gldb = GL_COLOR_ATTACHMENT0; + glDrawBuffers(1, &gldb); + } + + if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || (!storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW))) { + + /* + if (use_mrt) { + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); //switch to alpha fbo for sky, only diffuse/ambient matters + */ + + if (sky && sky->panorama.is_valid()) + _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation); + } + + //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); + //glColorMask(1,1,1,1); + + //state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false); + + if (use_mrt) { + + _render_mrts(env, p_cam_projection); + } else { + // Here we have to do the blits/resolves that otherwise are done in the MRT rendering, in particular + // - prepare screen texture for any geometry that uses a shader with screen texture + // - prepare depth texture for any geometry that uses a shader with depth texture + + bool framebuffer_dirty = false; + + if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_screen_texture) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); + glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + _blur_effect_buffer(); + framebuffer_dirty = true; + } + + if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_depth_texture) { + _prepare_depth_texture(); + framebuffer_dirty = true; + } + + if (framebuffer_dirty) { + // Restore framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + } + } + + if (storage->frame.current_rt && state.used_depth_texture && storage->frame.current_rt->buffers.active) { + _bind_depth_texture(); + } + + if (storage->frame.current_rt && state.used_screen_texture && storage->frame.current_rt->buffers.active) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); + } + + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); +#endif + render_list.sort_by_reverse_depth_and_priority(true); + + { + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(render_buffer->color_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(render_buffer->color_fb), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, default_render_buffer_uniform_set, render_buffer == nullptr); + RD::get_singleton()->draw_list_end(); + } + + //_render_list +#if 0 + if (state.directional_light_count == 0) { + directional_light = NULL; + _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, false, shadow_atlas != NULL); + } else { + for (int i = 0; i < state.directional_light_count; i++) { + directional_light = directional_lights[i]; + _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0); + _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, i > 0, shadow_atlas != NULL); + } + } +#endif + if (p_reflection_probe.is_valid()) { + //rendering a probe, do no more! + return; + } + + RasterizerEffectsRD *effects = storage->get_effects(); + effects->copy(render_buffer->color, storage->render_target_get_rd_framebuffer(render_buffer->render_target), Rect2()); + +#if 0 + _post_process(env, p_cam_projection); + // Needed only for debugging + /* if (shadow_atlas && storage->frame.current_rt) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); + } + + if (storage->frame.current_rt) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, exposure_shrink[4].color); + //glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->exposure.color); + storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 16, storage->frame.current_rt->height / 16), Rect2(0, 0, 1, 1)); + } + + if (reflection_atlas && storage->frame.current_rt) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); + storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); + } + + if (directional_shadow.fbo) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); + } + + if ( env_radiance_tex) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, env_radiance_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + }*/ + //disable all stuff +#endif +} + +RasterizerSceneForwardRD *RasterizerSceneForwardRD::singleton = NULL; + +void RasterizerSceneForwardRD::set_scene_pass(uint64_t p_pass) { + scene_pass = p_pass; +} + +void RasterizerSceneForwardRD::set_time(double p_time) { + time = p_time; +} + +RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storage) { + storage = p_storage; + + /* SHADER */ + + { + String defines; + + Vector shader_versions; + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_BUFFER\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define ENABLE_WRITE_NORMAL_ROUGHNESS_BUFFER\n"); + shader_versions.push_back(""); + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); + shader_versions.push_back("\n#define USE_VOXEL_CONE_TRACING\n"); + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_VOXEL_CONE_TRACING\n"); + shader_versions.push_back("\n#define USE_LIGHTMAP\n"); + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); + shader.scene_shader.initialize(shader_versions, defines); + } + + storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_shader_funcs); + storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_material_funcs); + + { + //shader compiler + ShaderCompilerRD::DefaultIdentifierActions actions; + + actions.renames["WORLD_MATRIX"] = "world_matrix"; + actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix"; + actions.renames["INV_CAMERA_MATRIX"] = "scene_data.camera_inverse_matrix"; + actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix"; + actions.renames["PROJECTION_MATRIX"] = "projection_matrix"; + actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix"; + actions.renames["MODELVIEW_MATRIX"] = "modelview"; + actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal"; + + actions.renames["VERTEX"] = "vertex"; + actions.renames["NORMAL"] = "normal"; + actions.renames["TANGENT"] = "tangent"; + actions.renames["BINORMAL"] = "binormal"; + actions.renames["POSITION"] = "position"; + actions.renames["UV"] = "uv_interp"; + actions.renames["UV2"] = "uv2_interp"; + actions.renames["COLOR"] = "color_interp"; + actions.renames["POINT_SIZE"] = "gl_PointSize"; + actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; + + //builtins + + actions.renames["TIME"] = "scene_data.time"; + actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size"; + + actions.renames["FRAGCOORD"] = "gl_FragCoord"; + actions.renames["FRONT_FACING"] = "gl_FrontFacing"; + actions.renames["NORMALMAP"] = "normalmap"; + actions.renames["NORMALMAP_DEPTH"] = "normaldepth"; + actions.renames["ALBEDO"] = "albedo"; + actions.renames["ALPHA"] = "alpha"; + actions.renames["METALLIC"] = "metallic"; + actions.renames["SPECULAR"] = "specular"; + actions.renames["ROUGHNESS"] = "roughness"; + actions.renames["RIM"] = "rim"; + actions.renames["RIM_TINT"] = "rim_tint"; + actions.renames["CLEARCOAT"] = "clearcoat"; + actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; + actions.renames["ANISOTROPY"] = "anisotropy"; + actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; + actions.renames["SSS_STRENGTH"] = "sss_strength"; + actions.renames["TRANSMISSION"] = "transmission"; + actions.renames["AO"] = "ao"; + actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; + actions.renames["EMISSION"] = "emission"; + actions.renames["POINT_COORD"] = "gl_PointCoord"; + actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; + actions.renames["SCREEN_UV"] = "screen_uv"; + actions.renames["SCREEN_TEXTURE"] = "screen_texture"; + actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; + actions.renames["NORMAL_TEXTURE"] = "normal_buffer"; + actions.renames["DEPTH"] = "gl_FragDepth"; + actions.renames["OUTPUT_IS_SRGB"] = "true"; + + //for light + actions.renames["VIEW"] = "view"; + actions.renames["LIGHT_COLOR"] = "light_color"; + actions.renames["LIGHT"] = "light"; + actions.renames["ATTENUATION"] = "attenuation"; + actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; + actions.renames["SPECULAR_LIGHT"] = "specular_light"; + + actions.usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; + actions.usage_defines["BINORMAL"] = "@TANGENT"; + actions.usage_defines["RIM"] = "#define LIGHT_USE_RIM\n"; + actions.usage_defines["RIM_TINT"] = "@RIM"; + actions.usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n"; + actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; + actions.usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n"; + actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; + actions.usage_defines["AO"] = "#define ENABLE_AO\n"; + actions.usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; + actions.usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; + actions.usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; + actions.usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; + actions.usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; + actions.usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; + actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; + actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; + + actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; + actions.usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; + actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; + actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; + + actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + + actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; + actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; + actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; + actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; + + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + + if (!force_lambert) { + actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + + actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; + actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; + actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; + + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + + if (!force_blinn) { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + + actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; + actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; + actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; + actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; + actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; + actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; + actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; + + actions.sampler_array_name = "material_samplers"; + actions.base_texture_binding_index = 1; + actions.texture_layout_set = 2; + actions.base_uniform_string = "material."; + + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; + actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; + + shader.compiler.initialize(actions); + } + + //render list + render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)256000); + render_list.init(); + scene_pass = 0; + render_pass = 0; + + { + //default material and shader + default_shader = storage->shader_create(); + storage->shader_set_code(default_shader, "shader_type spatial;\n"); + default_material = storage->material_create(); + storage->material_set_shader(default_material, default_shader); + + MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); + default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); + } + + //default render buffer and scene state uniform set + + { + Vector uniforms; + { + RD::Uniform u; + u.binding = 1; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 2; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 3; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + uniforms.push_back(u); + } + + scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); + + { + + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 4; + u.ids.push_back(scene_state.uniform_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 5; + u.ids.resize(12); + RID *ids_ptr = u.ids.ptrw(); + ids_ptr[0] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + uniforms.push_back(u); + } + + default_render_buffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 0); + } +} + +RasterizerSceneForwardRD::~RasterizerSceneForwardRD() { +} diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h index 46a3d898b2d..e09e42b1f36 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h @@ -31,85 +31,418 @@ #ifndef RASTERIZER_SCENE_FORWARD_RD_H #define RASTERIZER_SCENE_FORWARD_RD_H -#include "servers/visual/rasterizer.h" +#include "servers/visual/rasterizer_rd/rasterizer_scene_rd.h" +#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h" +#include "servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" +#include "servers/visual/rasterizer_rd/shaders/scene_forward.glsl.gen.h" + +class RasterizerSceneForwardRD : public RasterizerSceneRD { + + /* Shader */ + + enum ShaderVersion { + SHADER_VERSION_DEPTH_PASS, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_VCT_COLOR_PASS, + SHADER_VERSION_VCT_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_MAX + }; + + struct { + SceneForwardShaderRD scene_shader; + ShaderCompilerRD compiler; + } shader; + + RasterizerStorageRD *storage; + + /* Material */ + + struct ShaderData : public RasterizerStorageRD::ShaderData { + + enum BlendMode { //used internally + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + }; + + enum DepthDraw { + DEPTH_DRAW_DISABLED, + DEPTH_DRAW_OPAQUE, + DEPTH_DRAW_ALWAYS + }; + + enum DepthTest { + DEPTH_TEST_DISABLED, + DEPTH_TEST_ENABLED + }; + + enum Cull { + CULL_DISABLED, + CULL_FRONT, + CULL_BACK + }; + + enum CullVariant { + CULL_VARIANT_NORMAL, + CULL_VARIANT_REVERSED, + CULL_VARIANT_DOUBLE_SIDED, + CULL_VARIANT_MAX + + }; + + bool valid; + RID version; + uint32_t vertex_input_mask; + RenderPipelineVertexFormatCacheRD pipelines[CULL_VARIANT_MAX][VS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; + + String path; + + Map uniforms; + Vector texture_uniforms; + + Vector ubo_offsets; + uint32_t ubo_size; + + String code; + Map default_texture_params; + + DepthDraw depth_draw; + DepthTest depth_test; + + bool uses_point_size; + bool uses_alpha; + bool uses_blend_alpha; + bool uses_depth_pre_pass; + bool uses_discard; + bool uses_roughness; + bool uses_normal; + + bool unshaded; + bool uses_vertex; + bool uses_sss; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_normal_texture; + bool uses_time; + bool writes_modelview_or_projection; + bool uses_world_coordinates; + + uint64_t last_pass = 0; + uint32_t index = 0; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void get_param_list(List *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; + ShaderData(); + virtual ~ShaderData(); + }; + + RasterizerStorageRD::ShaderData *_create_shader_func(); + static RasterizerStorageRD::ShaderData *_create_shader_funcs() { + return static_cast(singleton)->_create_shader_func(); + } + + struct MaterialData : public RasterizerStorageRD::MaterialData { + uint64_t last_frame; + ShaderData *shader_data; + RID uniform_buffer; + RID uniform_set; + Vector texture_cache; + Vector ubo_data; + uint64_t last_pass = 0; + uint32_t index = 0; + RID next_pass; + uint8_t priority; + virtual void set_render_priority(int p_priority); + virtual void set_next_pass(RID p_pass); + virtual void update_parameters(const Map &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~MaterialData(); + }; + + RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) { + return static_cast(singleton)->_create_material_func(static_cast(p_shader)); + } + + /* Instance Custom Data */ + + struct InstanceGeometryData : public InstanceCustomData { + + struct UBO { + float transform[16]; + float normal_transform[12]; + uint32_t flags; + uint32_t pad[3]; + }; + + RID ubo; + RID uniform_set_base; + RID uniform_set_gi; + + bool ubo_dirty = true; + bool using_lightmap_gi = false; + bool using_vct_gi = false; + }; + + /* Framebuffer */ + + struct RenderBufferDataForward : public RenderBufferData { + //for rendering, may be MSAAd + RID color; + RID depth; + RID color_fb; + int width, height; + + RID render_target; + + RID uniform_set_opaque; + RID uniform_set_alpha; + + void clear(); + virtual void configure(RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa); + + ~RenderBufferDataForward(); + }; + + virtual RenderBufferData *_create_render_buffer_data(); + + RID default_render_buffer_uniform_set; + /* Instance Data */ + + struct InstanceData { + struct UBO { + }; + + RID state_buffer; + RID uniform_set; + }; + + RID_Owner instance_data_owner; + + /* Scene State UBO */ + + struct SceneState { + struct UBO { + float projection_matrix[16]; + float inv_projection_matrix[16]; + + float camera_matrix[16]; + float inv_camera_matrix[16]; + + float viewport_size[2]; + float screen_pixel_size[2]; + + float shadow_z_offset; + float shadow_z_slope_scale; + + float time; + float reflection_multiplier; + }; + + UBO ubo; + + RID uniform_buffer; + + bool used_screen_texture = false; + bool used_normal_texture = false; + bool used_depth_texture = false; + bool used_sss = false; + uint32_t current_shader_index = 0; + uint32_t current_material_index = 0; + } scene_state; + + /* Render List */ + + struct RenderList { + + int max_elements; + + struct Element { + RasterizerScene::InstanceBase *instance; + MaterialData *material; + union { + struct { + //from least significant to most significant in sort, TODO: should be endian swapped on big endian + uint64_t material_index : 20; + uint64_t shader_index : 20; + uint64_t priority : 16; + uint64_t depth_layer : 8; + }; + + uint64_t sort_key; + }; + uint32_t surface_index; + }; + + Element *base_elements; + Element **elements; + + int element_count; + int alpha_element_count; + + void clear() { + + element_count = 0; + alpha_element_count = 0; + } + + //should eventually be replaced by radix + + struct SortByKey { + + _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { + return A->sort_key < B->sort_key; + } + }; + + void sort_by_key(bool p_alpha) { + + SortArray sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + struct SortByDepth { + + _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { + return A->instance->depth < B->instance->depth; + } + }; + + void sort_by_depth(bool p_alpha) { //used for shadows + + SortArray sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + struct SortByReverseDepthAndPriority { + + _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { + uint32_t layer_A = uint32_t(A->priority); + uint32_t layer_B = uint32_t(B->priority); + if (layer_A == layer_B) { + return A->instance->depth > B->instance->depth; + } else { + return layer_A < layer_B; + } + } + }; + + void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + + SortArray sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + _FORCE_INLINE_ Element *add_element() { + + if (element_count + alpha_element_count >= max_elements) + return NULL; + elements[element_count] = &base_elements[element_count]; + return elements[element_count++]; + } + + _FORCE_INLINE_ Element *add_alpha_element() { + + if (element_count + alpha_element_count >= max_elements) + return NULL; + int idx = max_elements - alpha_element_count - 1; + elements[idx] = &base_elements[idx]; + alpha_element_count++; + return elements[idx]; + } + + void init() { + + element_count = 0; + alpha_element_count = 0; + elements = memnew_arr(Element *, max_elements); + base_elements = memnew_arr(Element, max_elements); + for (int i = 0; i < max_elements; i++) + elements[i] = &base_elements[i]; // assign elements + } + + RenderList() { + + max_elements = 0; + } + + ~RenderList() { + memdelete_arr(elements); + memdelete_arr(base_elements); + } + }; + + RenderList render_list; + + static RasterizerSceneForwardRD *singleton; + uint64_t scene_pass; + uint64_t render_pass; + double time; + RID default_shader; + RID default_material; + RID default_shader_rd; + + enum PassMode { + PASS_MODE_COLOR, + PASS_MODE_COLOR_SPECULAR, + PASS_MODE_COLOR_TRANSPARENT, + PASS_MODE_SHADOW, + PASS_MODE_DEPTH, + PASS_MODE_DEPTH_NORMAL, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS, + }; + + void _setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog); + + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_screen_uniform_set, bool p_no_gi); + _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode); + _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, PassMode p_pass_mode); + + void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi); + +protected: + virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); -class RasterizerSceneForwardRD : public RasterizerScene { public: - /* SHADOW ATLAS API */ + virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {} - RID shadow_atlas_create() { return RID(); } - void shadow_atlas_set_size(RID p_atlas, int p_size) {} - void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {} - bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { return false; } + virtual void set_scene_pass(uint64_t p_pass); + virtual void set_time(double p_time); + virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {} - int get_directional_light_shadow_size(RID p_light_intance) { return 0; } - void set_directional_shadow_count(int p_count) {} + virtual void instance_create_custom_data(InstanceBase *p_instance); + virtual void instance_free_custom_data(InstanceBase *p_instance); + virtual void instance_custom_data_update_lights(InstanceBase *p_instance); + virtual void instance_custom_data_update_reflection_probes(InstanceBase *p_instance); + virtual void instance_custom_data_update_gi_probes(InstanceBase *p_instance); + virtual void instance_custom_data_update_lightmap(InstanceBase *p_instance); + virtual void instance_custom_data_update_transform(InstanceBase *p_instance); - /* ENVIRONMENT API */ + virtual bool free(RID p_rid); - RID environment_create() { return RID(); } - - void environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {} - void environment_set_sky(RID p_env, RID p_sky) {} - void environment_set_sky_custom_fov(RID p_env, float p_scale) {} - void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {} - void environment_set_bg_color(RID p_env, const Color &p_color) {} - void environment_set_bg_energy(RID p_env, float p_energy) {} - void environment_set_canvas_max_layer(RID p_env, int p_max_layer) {} - void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0) {} - - void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} - void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} - void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {} - - void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} - - void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) {} - void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {} - - void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {} - - void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} - - void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {} - void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} - void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {} - - bool is_environment(RID p_env) { return false; } - VS::EnvironmentBG environment_get_background(RID p_env) { return VS::ENV_BG_KEEP; } - int environment_get_canvas_max_layer(RID p_env) { return 0; } - - RID light_instance_create(RID p_light) { return RID(); } - void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {} - void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0) {} - void light_instance_mark_visible(RID p_light_instance) {} - - RID reflection_atlas_create() { return RID(); } - void reflection_atlas_set_size(RID p_ref_atlas, int p_size) {} - void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv) {} - - RID reflection_probe_instance_create(RID p_probe) { return RID(); } - void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {} - void reflection_probe_release_atlas_index(RID p_instance) {} - bool reflection_probe_instance_needs_redraw(RID p_instance) { return false; } - bool reflection_probe_instance_has_reflection(RID p_instance) { return false; } - bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { return false; } - bool reflection_probe_instance_postprocess_step(RID p_instance) { return true; } - - RID gi_probe_instance_create() { return RID(); } - void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) {} - void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {} - void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) {} - - void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {} - void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {} - - void set_scene_pass(uint64_t p_pass) {} - void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {} - - bool free(RID p_rid) { return true; } - - RasterizerSceneForwardRD() {} - ~RasterizerSceneForwardRD() {} + RasterizerSceneForwardRD(RasterizerStorageRD *p_storage); + ~RasterizerSceneForwardRD(); }; #endif // RASTERIZER_SCENE_FORWARD_RD_H diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp new file mode 100644 index 00000000000..26598b70a4d --- /dev/null +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -0,0 +1,41 @@ +#include "rasterizer_scene_rd.h" + +RID RasterizerSceneRD::render_buffers_create() { + RenderBuffers rb; + rb.data = _create_render_buffer_data(); + return render_buffers_owner.make_rid(rb); +} + +void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) { + + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + rb->width = p_width; + rb->height = p_height; + rb->render_target = p_render_target; + rb->msaa = p_msaa; + rb->data->configure(p_render_target, p_width, p_height, p_msaa); +} + +void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { + + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND(!rb && p_render_buffers.is_valid()); + + _render_scene(rb->data, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_environment, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass); +} + +bool RasterizerSceneRD::free(RID p_rid) { + + if (render_buffers_owner.owns(p_rid)) { + RenderBuffers *rb = render_buffers_owner.getornull(p_rid); + memdelete(rb->data); + render_buffers_owner.free(p_rid); + } else { + return false; + } + + return true; +} + +RasterizerSceneRD::RasterizerSceneRD() { +} diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h new file mode 100644 index 00000000000..2019d4e5a53 --- /dev/null +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h @@ -0,0 +1,105 @@ +#ifndef RASTERIZER_SCENE_RD_H +#define RASTERIZER_SCENE_RD_H + +#include "core/rid_owner.h" +#include "servers/visual/rasterizer.h" +class RasterizerSceneRD : public RasterizerScene { +protected: + struct RenderBufferData { + + virtual void configure(RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) = 0; + virtual ~RenderBufferData() {} + }; + virtual RenderBufferData *_create_render_buffer_data() = 0; + + virtual void _render_scene(RenderBufferData *p_buffer_data, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; + +private: + struct RenderBuffers { + + RenderBufferData *data = nullptr; + int width = 0, height = 0; + VS::ViewportMSAA msaa = VS::VIEWPORT_MSAA_DISABLED; + RID render_target; + }; + + RID_Owner render_buffers_owner; + +public: + /* SHADOW ATLAS API */ + + RID shadow_atlas_create() { return RID(); } + void shadow_atlas_set_size(RID p_atlas, int p_size) {} + void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {} + bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { return false; } + + int get_directional_light_shadow_size(RID p_light_intance) { return 0; } + void set_directional_shadow_count(int p_count) {} + + /* ENVIRONMENT API */ + + RID environment_create() { return RID(); } + + void environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {} + void environment_set_sky(RID p_env, RID p_sky) {} + void environment_set_sky_custom_fov(RID p_env, float p_scale) {} + void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {} + void environment_set_bg_color(RID p_env, const Color &p_color) {} + void environment_set_bg_energy(RID p_env, float p_energy) {} + void environment_set_canvas_max_layer(RID p_env, int p_max_layer) {} + void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0) {} + + void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} + void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} + void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {} + + void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} + + void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) {} + void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {} + + void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {} + + void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} + + void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {} + void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} + void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {} + + bool is_environment(RID p_env) { return false; } + VS::EnvironmentBG environment_get_background(RID p_env) { return VS::ENV_BG_KEEP; } + int environment_get_canvas_max_layer(RID p_env) { return 0; } + + RID light_instance_create(RID p_light) { return RID(); } + void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {} + void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0) {} + void light_instance_mark_visible(RID p_light_instance) {} + + RID reflection_atlas_create() { return RID(); } + void reflection_atlas_set_size(RID p_ref_atlas, int p_size) {} + void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv) {} + + RID reflection_probe_instance_create(RID p_probe) { return RID(); } + void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {} + void reflection_probe_release_atlas_index(RID p_instance) {} + bool reflection_probe_instance_needs_redraw(RID p_instance) { return false; } + bool reflection_probe_instance_has_reflection(RID p_instance) { return false; } + bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { return false; } + bool reflection_probe_instance_postprocess_step(RID p_instance) { return true; } + + RID gi_probe_instance_create() { return RID(); } + void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) {} + void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {} + void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) {} + + RID render_buffers_create(); + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa); + + void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + + virtual bool free(RID p_rid); + + RasterizerSceneRD(); +}; + +#endif // RASTERIZER_SCENE_RD_H diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp index 15503ec38da..5351af7c905 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -1691,6 +1691,402 @@ void RasterizerStorageRD::_update_queued_materials() { } material_update_list = NULL; } +/* MESH API */ + +RID RasterizerStorageRD::mesh_create() { + + return mesh_owner.make_rid(Mesh()); +} + +/// Returns stride +void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_surface) { + + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + + //ensure blend shape consistency + ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shapes.size() != (int)mesh->blend_shape_count); + ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size()); + + Mesh::Surface *s = memnew(Mesh::Surface); + + s->format = p_surface.format; + s->primitive = p_surface.primitive; + + s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data); + s->vertex_count = p_surface.vertex_count; + + if (p_surface.index_count) { + bool is_index_16 = p_surface.vertex_count <= 65536; + + s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false); + s->index_count = p_surface.index_count; + s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count); + if (p_surface.lods.size()) { + s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size()); + s->lod_count = p_surface.lods.size(); + + for (int i = 0; i < p_surface.lods.size(); i++) { + + uint32_t indices = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4); + s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data); + s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices); + s->lods[i].edge_length = p_surface.lods[i].edge_length; + } + } + } + + s->aabb = p_surface.aabb; + s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them. + + for (int i = 0; i < p_surface.blend_shapes.size(); i++) { + + ERR_FAIL_COND(p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()); + + RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]); + s->blend_shapes.push_back(vertex_buffer); + } + + mesh->blend_shape_count = p_surface.blend_shapes.size(); + + if (mesh->surface_count == 0) { + mesh->bone_aabbs = p_surface.bone_aabbs; + mesh->aabb = p_surface.aabb; + } else { + for (int i = 0; i < p_surface.bone_aabbs.size(); i++) { + mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]); + } + mesh->aabb.merge_with(p_surface.aabb); + } + + s->material = p_mesh; + + mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1)); + mesh->surfaces[mesh->surface_count] = s; + mesh->surface_count++; + + mesh->instance_dependency.instance_notify_changed(true, true); + + mesh->material_cache.clear(); +} + +int RasterizerStorageRD::mesh_get_blend_shape_count(RID p_mesh) const { + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, -1); + return mesh->blend_shape_count; +} + +void RasterizerStorageRD::mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_mode, 2); + + mesh->blend_shape_mode = p_mode; +} +VS::BlendShapeMode RasterizerStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, VS::BLEND_SHAPE_MODE_NORMALIZED); + return mesh->blend_shape_mode; +} + +void RasterizerStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const PoolVector &p_data) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX((uint32_t)p_surface, mesh->surface_count); + ERR_FAIL_COND(p_data.size() == 0); + uint64_t data_size = p_data.size(); + PoolVector::Read r = p_data.read(); + + RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r.ptr()); +} + +void RasterizerStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX((uint32_t)p_surface, mesh->surface_count); + mesh->surfaces[p_surface]->material = p_material; + + mesh->instance_dependency.instance_notify_changed(false, true); + mesh->material_cache.clear(); +} +RID RasterizerStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, RID()); + ERR_FAIL_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID()); + + return mesh->surfaces[p_surface]->material; +} + +VS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const { + + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, VS::SurfaceData()); + ERR_FAIL_INDEX_V((uint32_t)p_surface, mesh->surface_count, VS::SurfaceData()); + + Mesh::Surface &s = *mesh->surfaces[p_surface]; + + VS::SurfaceData sd; + sd.format = s.format; + sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); + sd.vertex_count = s.vertex_count; + sd.index_count = s.index_count; + if (sd.index_count) { + sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer); + } + sd.aabb = s.aabb; + for (uint32_t i = 0; i < s.lod_count; i++) { + VS::SurfaceData::LOD lod; + lod.edge_length = s.lods[i].edge_length; + lod.index_data = RD::get_singleton()->buffer_get_data(s.lods[i].index_buffer); + sd.lods.push_back(lod); + } + + sd.bone_aabbs = s.bone_aabbs; + + for (int i = 0; i < s.blend_shapes.size(); i++) { + PoolVector bs = RD::get_singleton()->buffer_get_data(s.blend_shapes[i]); + sd.blend_shapes.push_back(bs); + } + + return sd; +} + +int RasterizerStorageRD::mesh_get_surface_count(RID p_mesh) const { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, 0); + return mesh->surface_count; +} + +void RasterizerStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + mesh->custom_aabb = p_aabb; +} +AABB RasterizerStorageRD::mesh_get_custom_aabb(RID p_mesh) const { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, AABB()); + return mesh->custom_aabb; +} + +AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, AABB()); + + if (mesh->custom_aabb != AABB()) { + return mesh->custom_aabb; + } + + if (!p_skeleton.is_valid()) { + return mesh->aabb; + } + + return mesh->aabb; +} + +void RasterizerStorageRD::mesh_clear(RID p_mesh) { + + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + for (uint32_t i = 0; i < mesh->surface_count; i++) { + Mesh::Surface &s = *mesh->surfaces[i]; + RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions + if (s.versions) { + memfree(s.versions); //reallocs, so free with memfree. + } + + if (s.index_buffer.is_valid()) { + RD::get_singleton()->free(s.index_buffer); + } + + if (s.lod_count) { + for (uint32_t j = 0; j < s.lod_count; j++) { + RD::get_singleton()->free(s.lods[j].index_buffer); + } + memdelete_arr(s.lods); + } + + for (int32_t j = 0; j < s.blend_shapes.size(); j++) { + RD::get_singleton()->free(s.blend_shapes[j]); + } + + if (s.blend_shape_base_buffer.is_valid()) { + RD::get_singleton()->free(s.blend_shape_base_buffer); + } + + memdelete(mesh->surfaces[i]); + } + if (mesh->surfaces) { + memfree(mesh->surfaces); + } + + mesh->surfaces = nullptr; + mesh->surface_count = 0; + mesh->material_cache.clear(); + mesh->instance_dependency.instance_notify_changed(true, true); +} + +void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask) { + uint32_t version = s->version_count; + s->version_count++; + s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count); + + Mesh::Surface::Version &v = s->versions[version]; + + Vector attributes; + Vector buffers; + + uint32_t stride = 0; + + for (int i = 0; i < VS::ARRAY_WEIGHTS; i++) { + + if (!(p_input_mask & (1 << i))) { + continue; // Shader does not need this, skip it + } + + RD::VertexDescription vd; + RID buffer; + vd.location = i; + + if (!(s->format & (1 << i))) { + // Shader needs this, but it's not provided by this surface + // Create a default attribue using the default buffers + buffer = mesh_default_rd_buffers[i]; + switch (i) { + + case VS::ARRAY_VERTEX: { + + vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + + } break; + case VS::ARRAY_NORMAL: { + vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + } break; + case VS::ARRAY_TANGENT: { + + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + } break; + case VS::ARRAY_COLOR: { + + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + + } break; + case VS::ARRAY_TEX_UV: { + + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + + } break; + case VS::ARRAY_TEX_UV2: { + + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + } break; + case VS::ARRAY_BONES: { + + //assumed weights too + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + } break; + } + } else { + //Shader needs this, and it's also provided + + vd.offset = stride; + vd.stride = 1; //mark that it needs a stride set + buffer = s->vertex_buffer; + + switch (i) { + + case VS::ARRAY_VERTEX: { + + if (s->format & VS::ARRAY_FLAG_USE_2D_VERTICES) { + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + stride += sizeof(float) * 2; + } else { + vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + stride += sizeof(float) * 3; + } + + } break; + case VS::ARRAY_NORMAL: { + + if (s->format & VS::ARRAY_COMPRESS_NORMAL) { + vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM; + stride += sizeof(int8_t) * 4; + } else { + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + stride += sizeof(float) * 4; + } + + } break; + case VS::ARRAY_TANGENT: { + + if (s->format & VS::ARRAY_COMPRESS_TANGENT) { + vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM; + stride += sizeof(int8_t) * 4; + } else { + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + stride += sizeof(float) * 4; + } + + } break; + case VS::ARRAY_COLOR: { + + if (s->format & VS::ARRAY_COMPRESS_COLOR) { + vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + stride += sizeof(int8_t) * 4; + } else { + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + stride += sizeof(float) * 4; + } + + } break; + case VS::ARRAY_TEX_UV: { + + if (s->format & VS::ARRAY_COMPRESS_TEX_UV) { + vd.format = RD::DATA_FORMAT_R16G16_SFLOAT; + stride += sizeof(int16_t) * 2; + } else { + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + stride += sizeof(float) * 2; + } + + } break; + case VS::ARRAY_TEX_UV2: { + + if (s->format & VS::ARRAY_COMPRESS_TEX_UV2) { + vd.format = RD::DATA_FORMAT_R16G16_SFLOAT; + stride += sizeof(int16_t) * 2; + } else { + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + stride += sizeof(float) * 2; + } + + } break; + case VS::ARRAY_BONES: { + //assumed weights too + + //unique format, internally 16 bits, exposed as single array for 32 + + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + stride += sizeof(int32_t) * 4; + + } break; + } + } + + attributes.push_back(vd); + buffers.push_back(buffer); + } + + //update final stride + for (int i = 0; i < attributes.size(); i++) { + if (attributes[i].stride == 1) { + attributes.write[i].stride = stride; + } + } + + v.input_mask = p_input_mask; + v.vertex_format = RD::get_singleton()->vertex_format_create(attributes); + v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers); +} /* RENDER TARGET API */ @@ -2033,6 +2429,13 @@ RID RasterizerStorageRD::render_target_get_back_buffer_uniform_set(RID p_render_ return rt->backbuffer_uniform_set; } +void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { + if (mesh_owner.owns(p_base)) { + Mesh *mesh = mesh_owner.getornull(p_base); + p_instance->update_dependency(&mesh->instance_dependency); + } +} + void RasterizerStorageRD::update_dirty_resources() { _update_queued_materials(); } @@ -2081,6 +2484,11 @@ bool RasterizerStorageRD::free(RID p_rid) { material_set_shader(p_rid, RID()); //clean up shader material->instance_dependency.instance_notify_deleted(p_rid); material_owner.free(p_rid); + } else if (mesh_owner.owns(p_rid)) { + mesh_clear(p_rid); + Mesh *mesh = mesh_owner.getornull(p_rid); + mesh->instance_dependency.instance_notify_deleted(p_rid); + mesh_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { RenderTarget *rt = render_target_owner.getornull(p_rid); @@ -2100,7 +2508,7 @@ bool RasterizerStorageRD::free(RID p_rid) { return true; } -EffectsRD *RasterizerStorageRD::get_effects() { +RasterizerEffectsRD *RasterizerStorageRD::get_effects() { return &effects; } @@ -2251,6 +2659,115 @@ RasterizerStorageRD::RasterizerStorageRD() { default_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state); } } + + //default rd buffers + { + + { //vertex + PoolVector buffer; + buffer.resize(sizeof(float) * 3); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + + { //normal + PoolVector buffer; + buffer.resize(sizeof(float) * 3); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 1.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + + { //tangent + PoolVector buffer; + buffer.resize(sizeof(float) * 4); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 1.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + fptr[3] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + + { //color + PoolVector buffer; + buffer.resize(sizeof(float) * 4); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 1.0; + fptr[1] = 1.0; + fptr[2] = 1.0; + fptr[3] = 1.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + + { //tex uv 1 + PoolVector buffer; + buffer.resize(sizeof(float) * 2); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + { //tex uv 2 + PoolVector buffer; + buffer.resize(sizeof(float) * 2); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + + { //bones + PoolVector buffer; + buffer.resize(sizeof(uint32_t) * 4); + { + PoolVector::Write w = buffer.write(); + uint32_t *fptr = (uint32_t *)w.ptr(); + fptr[0] = 0; + fptr[1] = 0; + fptr[2] = 0; + fptr[3] = 0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + + { //weights + PoolVector buffer; + buffer.resize(sizeof(float) * 4); + { + PoolVector::Write w = buffer.write(); + float *fptr = (float *)w.ptr(); + fptr[0] = 0.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + fptr[3] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + } } RasterizerStorageRD::~RasterizerStorageRD() { @@ -2266,4 +2783,9 @@ RasterizerStorageRD::~RasterizerStorageRD() { RD::get_singleton()->free(default_rd_samplers[i][j]); } } + + //def buffers + for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) { + RD::get_singleton()->free(mesh_default_rd_buffers[i]); + } } diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h index db1d73e62f1..729e8b65562 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -33,7 +33,7 @@ #include "core/rid_owner.h" #include "servers/visual/rasterizer.h" -#include "servers/visual/rasterizer_rd/effects_rd.h" +#include "servers/visual/rasterizer_rd/rasterizer_effects_rd.h" #include "servers/visual/rasterizer_rd/shader_compiler_rd.h" #include "servers/visual/rendering_device.h" @@ -80,6 +80,18 @@ public: DEFAULT_RD_TEXTURE_MAX }; + enum DefaultRDBuffer { + DEFAULT_RD_BUFFER_VERTEX, + DEFAULT_RD_BUFFER_NORMAL, + DEFAULT_RD_BUFFER_TANGENT, + DEFAULT_RD_BUFFER_COLOR, + DEFAULT_RD_BUFFER_TEX_UV, + DEFAULT_RD_BUFFER_TEX_UV2, + DEFAULT_RD_BUFFER_BONES, + DEFAULT_RD_BUFFER_WEIGHTS, + DEFAULT_RD_BUFFER_MAX, + }; + private: /* TEXTURE API */ struct Texture { @@ -186,6 +198,80 @@ private: Material *material_update_list; void _material_queue_update(Material *material, bool p_uniform, bool p_texture); void _update_queued_materials(); + + /* Mesh */ + + struct Mesh { + + struct Surface { + VS::PrimitiveType primitive; + uint32_t format = 0; + + RID vertex_buffer; + uint32_t vertex_count = 0; + + // A different pipeline needs to be allocated + // depending on the inputs available in the + // material. + // There are never that many geometry/material + // combinations, so a simple array is the most + // cache-efficient structure. + + struct Version { + uint32_t input_mask; + RD::VertexFormatID vertex_format; + RID vertex_array; + }; + + SpinLock version_lock; //needed to access versions + Version *versions = nullptr; //allocated on demand + uint32_t version_count = 0; + + RID index_buffer; + RID index_array; + uint32_t index_count = 0; + + struct LOD { + float edge_length; + RID index_buffer; + RID index_array; + }; + + LOD *lods = nullptr; + uint32_t lod_count = 0; + + AABB aabb; + + Vector bone_aabbs; + + Vector blend_shapes; + RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed + + RID material; + }; + + uint32_t blend_shape_count = 0; + VS::BlendShapeMode blend_shape_mode = VS::BLEND_SHAPE_MODE_NORMALIZED; + + Surface **surfaces = nullptr; + uint32_t surface_count = 0; + + Vector bone_aabbs; + + AABB aabb; + AABB custom_aabb; + + Vector material_cache; + + RasterizerScene::InstanceDependency instance_dependency; + }; + + mutable RID_Owner mesh_owner; + + void _mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask); + + RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX]; + /* RENDER TARGET */ struct RenderTarget { @@ -231,7 +317,7 @@ private: /* EFFECTS */ - EffectsRD effects; + RasterizerEffectsRD effects; public: /* TEXTURE API */ @@ -309,26 +395,8 @@ public: /* SKY API */ - struct RDSurface { - uint32_t format; - VS::PrimitiveType primitive; - PoolVector array; - int vertex_count; - PoolVector index_array; - int index_count; - AABB aabb; - Vector > blend_shapes; - Vector bone_aabbs; - }; - - struct RDMesh { - Vector surfaces; - int blend_shape_count; - VS::BlendShapeMode blend_shape_mode; - }; RID sky_create() { return RID(); } void sky_set_texture(RID p_sky, RID p_cube_map, int p_radiance_size) {} - mutable RID_PtrOwner mesh_owner; /* SHADER API */ @@ -374,134 +442,87 @@ public: /* MESH API */ - RID mesh_create() { - RDMesh *mesh = memnew(RDMesh); - ERR_FAIL_COND_V(!mesh, RID()); - mesh->blend_shape_count = 0; - mesh->blend_shape_mode = VS::BLEND_SHAPE_MODE_NORMALIZED; - return mesh_owner.make_rid(mesh); + virtual RID mesh_create(); + + /// Return stride + virtual void mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_surface); + + virtual int mesh_get_blend_shape_count(RID p_mesh) const; + + virtual void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode); + virtual VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const; + + virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const PoolVector &p_data); + + virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material); + virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const; + + virtual VS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const; + + virtual int mesh_get_surface_count(RID p_mesh) const; + + virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb); + virtual AABB mesh_get_custom_aabb(RID p_mesh) const; + + virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()); + + virtual void mesh_clear(RID p_mesh); + + _FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, NULL); + r_surface_count = mesh->surface_count; + if (r_surface_count == 0) { + return NULL; + } + if (mesh->material_cache.empty()) { + mesh->material_cache.resize(mesh->surface_count); + for (uint32_t i = 0; i < r_surface_count; i++) { + mesh->material_cache.write[i] = mesh->surfaces[i]->material; + } + } + + return mesh->material_cache.ptr(); } - void mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector &p_array, int p_vertex_count, const PoolVector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector > &p_blend_shapes = Vector >(), const Vector &p_bone_aabbs = Vector()) { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!m); + _FORCE_INLINE_ void mesh_get_arrays_primitive_and_format(RID p_mesh, uint32_t p_surface_index, uint32_t p_input_mask, VS::PrimitiveType &r_primitive, RID &r_vertex_array_rd, RID &r_index_array_rd, RD::VertexFormatID &r_vertex_format) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + ERR_FAIL_INDEX(p_surface_index, mesh->surface_count); - m->surfaces.push_back(RDSurface()); - RDSurface *s = &m->surfaces.write[m->surfaces.size() - 1]; - s->format = p_format; - s->primitive = p_primitive; - s->array = p_array; - s->vertex_count = p_vertex_count; - s->index_array = p_index_array; - s->index_count = p_index_count; - s->aabb = p_aabb; - s->blend_shapes = p_blend_shapes; - s->bone_aabbs = p_bone_aabbs; + Mesh::Surface *s = mesh->surfaces[p_surface_index]; + + r_index_array_rd = s->index_array; + + s->version_lock.lock(); + + //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way + + for (uint32_t i = 0; i < s->version_count; i++) { + if (s->versions[i].input_mask != p_input_mask) { + continue; + } + //we have this version, hooray + r_vertex_format = s->versions[i].vertex_format; + r_vertex_array_rd = s->versions[i].vertex_array; + s->version_lock.unlock(); + return; + } + + uint32_t version = s->version_count; //gets added at the end + + _mesh_surface_generate_version_for_input_mask(s, p_input_mask); + + r_vertex_format = s->versions[version].vertex_format; + r_vertex_array_rd = s->versions[version].vertex_array; + + s->version_lock.unlock(); } - void mesh_set_blend_shape_count(RID p_mesh, int p_amount) { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!m); - m->blend_shape_count = p_amount; + _FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) { + ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID()); + return mesh_default_rd_buffers[p_buffer]; } - int mesh_get_blend_shape_count(RID p_mesh) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, 0); - return m->blend_shape_count; - } - - void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!m); - m->blend_shape_mode = p_mode; - } - VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, VS::BLEND_SHAPE_MODE_NORMALIZED); - return m->blend_shape_mode; - } - - void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const PoolVector &p_data) {} - - void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {} - RID mesh_surface_get_material(RID p_mesh, int p_surface) const { return RID(); } - - int mesh_surface_get_array_len(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, 0); - - return m->surfaces[p_surface].vertex_count; - } - int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, 0); - - return m->surfaces[p_surface].index_count; - } - - PoolVector mesh_surface_get_array(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, PoolVector()); - - return m->surfaces[p_surface].array; - } - PoolVector mesh_surface_get_index_array(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, PoolVector()); - - return m->surfaces[p_surface].index_array; - } - - uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, 0); - - return m->surfaces[p_surface].format; - } - VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, VS::PRIMITIVE_POINTS); - - return m->surfaces[p_surface].primitive; - } - - AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, AABB()); - - return m->surfaces[p_surface].aabb; - } - Vector > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, Vector >()); - - return m->surfaces[p_surface].blend_shapes; - } - Vector mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, Vector()); - - return m->surfaces[p_surface].bone_aabbs; - } - - void mesh_remove_surface(RID p_mesh, int p_index) { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!m); - ERR_FAIL_COND(p_index >= m->surfaces.size()); - - m->surfaces.remove(p_index); - } - int mesh_get_surface_count(RID p_mesh) const { - RDMesh *m = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!m, 0); - return m->surfaces.size(); - } - - void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {} - AABB mesh_get_custom_aabb(RID p_mesh) const { return AABB(); } - - AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const { return AABB(); } - void mesh_clear(RID p_mesh) {} /* MULTIMESH API */ @@ -623,7 +644,7 @@ public: float reflection_probe_get_origin_max_distance(RID p_probe) const { return 0.0; } bool reflection_probe_renders_shadows(RID p_probe) const { return false; } - void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {} + void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {} /* GI PROBE API */ @@ -752,9 +773,6 @@ public: RID render_target_get_rd_framebuffer(RID p_render_target); VS::InstanceType get_base_type(RID p_rid) const { - if (mesh_owner.owns(p_rid)) { - return VS::INSTANCE_MESH; - } return VS::INSTANCE_NONE; } @@ -777,7 +795,7 @@ public: static RasterizerStorage *base_singleton; - EffectsRD *get_effects(); + RasterizerEffectsRD *get_effects(); RasterizerStorageRD(); ~RasterizerStorageRD(); diff --git a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp index 9d4e61c733f..b2cb6a16344 100644 --- a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp +++ b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp @@ -79,6 +79,11 @@ void RenderPipelineVertexFormatCacheRD::update_shader(RID p_shader) { setup(p_shader, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags); } +void RenderPipelineVertexFormatCacheRD::clear() { + _clear(); + shader = RID(); //clear shader +} + RenderPipelineVertexFormatCacheRD::RenderPipelineVertexFormatCacheRD() { version_count = 0; versions = NULL; diff --git a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h index 05d9b8db4a7..9faa466eae4 100644 --- a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h +++ b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h @@ -63,6 +63,10 @@ public: void update_shader(RID p_shader); _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_V_MSG(shader.is_null(), RID(), + "Attempted to use an unused shader variant (shader is null),"); +#endif for (uint32_t i = 0; i < version_count; i++) { if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id) { return versions[i].pipeline; @@ -71,6 +75,7 @@ public: return _generate_version(p_vertex_format_id, p_framebuffer_format_id); } + void clear(); RenderPipelineVertexFormatCacheRD(); ~RenderPipelineVertexFormatCacheRD(); }; diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub index a8e1dafb473..65a40e981da 100644 --- a/servers/visual/rasterizer_rd/shaders/SCsub +++ b/servers/visual/rasterizer_rd/shaders/SCsub @@ -6,3 +6,5 @@ if 'RD_GLSL' in env['BUILDERS']: env.RD_GLSL('canvas.glsl'); env.RD_GLSL('canvas_occlusion.glsl'); env.RD_GLSL('blur.glsl'); + env.RD_GLSL('scene_forward.glsl'); + env.RD_GLSL('scene_forward_inc.glsl'); diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl new file mode 100644 index 00000000000..c18fead23ef --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl @@ -0,0 +1,762 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +/* INPUT ATTRIBS */ + +layout(location = 0) in vec3 vertex_attrib; +/* clang-format on */ +layout(location = 1) in vec3 normal_attrib; +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +layout(location = 2) in vec4 tangent_attrib; +#endif + +#if defined(COLOR_USED) +layout(location = 3) in vec4 color_attrib; +#endif + +#if defined(UV_USED) +layout(location = 4) in vec2 uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +layout(location = 5) in vec2 uv2_attrib; +#endif + +layout(location = 6) in uvec4 bone_attrib; // always bound, even if unused + +/* Varyings */ + +out vec3 vertex_interp; +out vec3 normal_interp; + +#if defined(COLOR_USED) +out vec4 color_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +out vec2 uv_interp; +#endif + +//uv2 may be used for lightmapping, so always pass. +#if !defined(MODE_RENDER_DEPTH) +out vec2 uv2_interp; +#endif + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +out vec3 tangent_interp; +out vec3 binormal_interp; +#endif + +#ifdef USE_MATERIAL_UNIFORMS +layout(set = 2, binding = 0, std140) uniform MaterialUniforms { +/* clang-format off */ +MATERIAL_UNIFORMS +/* clang-format on */ +} material; +#endif + + +/* clang-format off */ + +VERTEX_SHADER_GLOBALS + +/* clang-format on */ + +// FIXME: This triggers a Mesa bug that breaks rendering, so disabled for now. +// See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316 +//invariant gl_Position; + +void main() { + + vec3 vertex = vertex_attrib; + + mat4 world_matrix = instance_data.transform; + mat3 world_normal_matrix= instance_data.normal_transform; + + vec3 normal = normal_attrib; + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 tangent = tangent_attrib.xyz; + float binormalf = tangent_attrib.a; +#endif + +#if defined(COLOR_USED) + color_interp = color_attrib; +#endif + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + vec3 binormal = normalize(cross(normal, tangent) * binormalf); +#endif + +#if defined(UV_USED) + uv_interp = uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + uv2_interp = uv2_attrib; +#endif + +#ifdef USE_OVERRIDE_POSITION + vec4 position; +#endif + + vec4 instance_custom = vec4(0.0); + + mat4 projection_matrix = scene_data.projection_matrix; + +//using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) + + vertex = (world_matrix * vec4(vertex,1.0)).xyz; + + normal = world_normal_matrix * normal; + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + tangent = world_normal_matrix * tangent; + binormal = world_normal_matrix * binormal; + +#endif +#endif + + float roughness = 1.0; + + mat4 modelview = scene_data.inv_camera_matrix * instance_data.transform; + mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * instance_data.normal_transform; + + { + /* clang-format off */ + +VERTEX_SHADER_CODE + + /* clang-format on */ + } + +// using local coordinates (default) +#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) + + vertex = (modelview * vec4(vertex,1.0)).xyz; + normal = modelview_normal * normal; +#endif + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + binormal = modelview_normal * binormal; + tangent = modelview_normal * tangent; +#endif +#endif + +//using world coordinates +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) + + vertex = (scene_data.inv_camera_matrix * vec4(vertex,1.0)).xyz; + normal = mat3(scene_data.inverse_normal_matrix) * normal; + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal; + tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent; +#endif +#endif + + vertex_interp = vertex; + normal_interp = normal; + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) + tangent_interp = tangent; + binormal_interp = binormal; +#endif + +#ifdef MODE_RENDER_DEPTH + + float z_ofs = scene_data.z_offset; + z_ofs += (1.0 - abs(normal_interp.z)) * scene_data.z_slope_scale; + vertex_interp.z -= z_ofs; + +#endif //MODE_RENDER_DEPTH + +#ifdef USE_OVERRIDE_POSITION + gl_Position = position; +#else + gl_Position = projection_matrix * vec4(vertex_interp, 1.0); +#endif + +} + +/* clang-format off */ +[fragment] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + + +/* Varyings */ + +#if defined(COLOR_USED) +in vec4 color_interp; +#endif + +#if defined(UV_USED) +in vec2 uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) +in vec2 uv2_interp; +#endif + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +in vec3 tangent_interp; +in vec3 binormal_interp; +#endif + +in highp vec3 vertex_interp; +in vec3 normal_interp; + +//defines to keep compatibility with vertex + +#define world_matrix instance_data.transform; +#define world_normal_matrix instance_data.normal_transform; +#define projection_matrix scene_data.projection_matrix; + +#ifdef USE_MATERIAL_UNIFORMS +layout(set = 2, binding = 0, std140) uniform MaterialUniforms { +/* clang-format off */ +MATERIAL_UNIFORMS +/* clang-format on */ +} material; +#endif + +/* clang-format off */ + +FRAGMENT_SHADER_GLOBALS + +/* clang-format on */ + +#ifdef MODE_MULTIPLE_RENDER_TARGETS + +layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness +layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) +#else + +layout(location = 0) out vec4 frag_color; + +#endif + +// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. +// We're dividing this factor off because the overall term we'll end up looks like +// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): +// +// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) +// +// We're basically regouping this as +// +// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] +// +// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. +// +// The contents of the D and G (G1) functions (GGX) are taken from +// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). +// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). + +float G_GGX_2cos(float cos_theta_m, float alpha) { + // Schlick's approximation + // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) + // Eq. (19), although see Heitz (2014) the about the problems with his derivation. + // It nevertheless approximates GGX well with k = alpha/2. + float k = 0.5 * alpha; + return 0.5 / (cos_theta_m * (1.0 - k) + k); + + // float cos2 = cos_theta_m * cos_theta_m; + // float sin2 = (1.0 - cos2); + // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); +} + +float D_GGX(float cos_theta_m, float alpha) { + float alpha2 = alpha * alpha; + float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; + return alpha2 / (M_PI * d * d); +} + +float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float s_x = alpha_x * cos_phi; + float s_y = alpha_y * sin_phi; + return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +} + +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float r_x = cos_phi / alpha_x; + float r_y = sin_phi / alpha_y; + float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); +} + +float SchlickFresnel(float u) { + float m = 1.0 - u; + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) +} + +float GTR1(float NdotH, float a) { + if (a >= 1.0) return 1.0 / M_PI; + float a2 = a * a; + float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; + return (a2 - 1.0) / (M_PI * log(a2) * t); +} + +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); +} + +void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light, inout float alpha) { + +#if defined(USE_LIGHT_SHADER_CODE) + // light is written by the light shader + + vec3 normal = N; + vec3 albedo = diffuse_color; + vec3 light = L; + vec3 view = V; + + /* clang-format off */ + +LIGHT_SHADER_CODE + + /* clang-format on */ + +#else + float NdotL = dot(N, L); + float cNdotL = max(NdotL, 0.0); // clamped NdotL + float NdotV = dot(N, V); + float cNdotV = max(NdotV, 0.0); + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cNdotH = max(dot(N, H), 0.0); +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cLdotH = max(dot(L, H), 0.0); +#endif + + if (metallic < 1.0) { +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif + +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader + diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); + +#elif defined(DIFFUSE_OREN_NAYAR) + + { + // see http://mimosa-pudica.net/improved-oren-nayar.html + float LdotV = dot(L, V); + + float s = LdotV - NdotL * NdotV; + float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); + + float sigma2 = roughness * roughness; // TODO: this needs checking + vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); + } + +#elif defined(DIFFUSE_TOON) + + diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); + +#elif defined(DIFFUSE_BURLEY) + + { + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + /* + float energyBias = mix(roughness, 0.0, 0.5); + float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); + float fd90 = energyBias + 2.0 * VoH * VoH * roughness; + float f0 = 1.0; + float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); + float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); + + diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; + */ + } +#else + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; + +#if defined(TRANSMISSION_USED) + diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; +#endif + +#if defined(LIGHT_USE_RIM) + float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); + diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; +#endif + } + + if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely + + // D + +#if defined(SPECULAR_BLINN) + + //normalized blinn + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float intensity = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + + specular_light += light_color * intensity * specular_blob_intensity * attenuation; + +#elif defined(SPECULAR_PHONG) + + vec3 R = normalize(-reflect(L, N)); + float cRdotV = max(0.0, dot(R, V)); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + + specular_light += light_color * intensity * specular_blob_intensity * attenuation; + +#elif defined(SPECULAR_TOON) + + vec3 R = normalize(-reflect(L, N)); + float RdotV = dot(R, V); + float mid = 1.0 - roughness; + mid *= mid; + float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + diffuse_light += light_color * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection + +#elif defined(SPECULAR_DISABLED) + // none.. + +#elif defined(SPECULAR_SCHLICK_GGX) + // shlick+ggx as default + +#if defined(LIGHT_ANISOTROPY_USED) + + float alpha_ggx = roughness * roughness; + float aspect = sqrt(1.0 - anisotropy * 0.9); + float ax = alpha_ggx / aspect; + float ay = alpha_ggx * aspect; + float XdotH = dot(T, H); + float YdotH = dot(B, H); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); + float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + +#else + float alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); +#endif + // F + vec3 f0 = F0(metallic, specular, diffuse_color); + float cLdotH5 = SchlickFresnel(cLdotH); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); + + vec3 specular_brdf_NL = cNdotL * D * F * G; + + specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; +#endif + +#if defined(LIGHT_USE_CLEARCOAT) + +#if !defined(SPECULAR_SCHLICK_GGX) + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; +#endif + } + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); +#endif + +#endif //defined(USE_LIGHT_SHADER_CODE) +} + + +void main() { + + + //lay out everything, whathever is unused is optimized away anyway + vec3 vertex = vertex_interp; + vec3 view = -normalize(vertex_interp); + vec3 albedo = vec3(1.0); + vec3 transmission = vec3(0.0); + float metallic = 0.0; + float specular = 0.5; + vec3 emission = vec3(0.0); + float roughness = 1.0; + float rim = 0.0; + float rim_tint = 0.0; + float clearcoat = 0.0; + float clearcoat_gloss = 0.0; + float anisotropy = 0.0; + vec2 anisotropy_flow = vec2(1.0, 0.0); + +#if defined(ENABLE_AO) + float ao = 1.0; + float ao_light_affect = 0.0; +#endif + + float alpha = 1.0; + +#if defined(ALPHA_SCISSOR_USED) + float alpha_scissor = 0.5; +#endif + +#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 binormal = normalize(binormal_interp); + vec3 tangent = normalize(tangent_interp); +#else + vec3 binormal = vec3(0.0); + vec3 tangent = vec3(0.0); +#endif + vec3 normal = normalize(normal_interp); + +#if defined(DO_SIDE_CHECK) + if (!gl_FrontFacing) { + normal = -normal; + } +#endif + +#if defined(UV_USED) + vec2 uv = uv_interp; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + vec2 uv2 = uv2_interp; +#endif + +#if defined(COLOR_USED) + vec4 color = color_interp; +#endif + +#if defined(NORMALMAP_USED) + + vec3 normalmap = vec3(0.5); +#endif + + float normaldepth = 1.0; + +#if defined(SCREEN_UV_USED) + vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#endif + +#if defined(SSS_USED) + float sss_strength = 0.0; +#endif + +#define + { + /* clang-format off */ + +FRAGMENT_SHADER_CODE + + /* clang-format on */ + } + +#if !defined(USE_SHADOW_TO_OPACITY) + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_OPAQUE_PREPASS + + if (alpha < opaque_prepass_threshold) { + discard; + } + +#endif // USE_OPAQUE_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY + +#if defined(NORMALMAP_USED) + + normalmap.xy = normalmap.xy * 2.0 - 1.0; + normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. + + normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)); + +#endif + +#if defined(LIGHT_ANISOTROPY_USED) + + if (anisotropy > 0.01) { + //rotation matrix + mat3 rot = mat3(tangent, binormal, normal); + //make local to space + tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0)); + binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0)); + } + +#endif + +#ifdef ENABLE_CLIP_ALPHA + if (albedo.a < 0.99) { + //used for doublepass and shadowmapping + discard; + } +#endif + + /////////////////////// LIGHTING ////////////////////////////// + + //apply energy conservation + + vec3 specular_light = vec3(0.0, 0.0, 0.0); + vec3 diffuse_light = vec3(0.0, 0.0, 0.0); + vec3 ambient_light = vec3( 0.0, 0.0, 0.0); + + //radiance + + float specular_blob_intensity = 1.0; + +#if defined(SPECULAR_TOON) + specular_blob_intensity *= specular * 2.0; +#endif + + //gi probes + + //lightmap + + //lightmap capture + + //process reflections + + { + +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + + // scales the specular reflections, needs to be be computed before lighting happens, + // but after environment, GI, and reflection probes are added + // Environment brdf approximation (Lazarov 2013) + // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = roughness * c0 + c1; + float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0); + float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; +#endif + } + + //directional light + + + //process omni and spots + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_OPAQUE_PREPASS + + if (alpha < opaque_prepass_threshold) { + discard; + } + +#endif // USE_OPAQUE_PREPASS + +#endif // USE_SHADOW_TO_OPACITY + + +#ifdef MODE_RENDER_DEPTH +//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) +#else + + specular_light *= reflection_multiplier; + ambient_light *= albedo; //ambient must be multiplied by albedo at the end + +#if defined(ENABLE_AO) + ambient_light *= ao; + ao_light_affect = mix(1.0, ao, ao_light_affect); + specular_light *= ao_light_affect; + diffuse_light *= ao_light_affect; +#endif + + // base color remapping + diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point + ambient_light *= 1.0 - metallic; + + //fog + +#ifdef MODE_MULTIPLE_RENDER_TARGETS + +#ifdef USE_NO_SHADING + diffuse_buffer = vec4(albedo.rgb, 0.0); + specular_buffer = vec4(0.0); + +#else + + diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strenght); + specular_buffer = vec4(specular_light, metallic); + +#endif + +#else //MODE_MULTIPLE_RENDER_TARGETS + +#ifdef USE_NO_SHADING + frag_color = vec4(albedo, alpha); +#else + frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); + +#endif //USE_NO_SHADING + +#endif //MODE_MULTIPLE_RENDER_TARGETS + +#endif //MODE_RENDER_DEPTH +} diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl new file mode 100644 index 00000000000..189371c2c0c --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl @@ -0,0 +1,141 @@ + +#define M_PI 3.14159265359 +#define ROUGHNESS_MAX_LOD 5 + +/* Set 0 Scene data, screen and sources (changes the least) */ + +layout(set=0,location=1) uniform texture2D depth_buffer; +layout(set=0,location=2) uniform texture2D color_buffer; +layout(set=0,location=3) uniform texture2D normal_buffer; + +layout(set=0,binding=4,std140) uniform SceneData { + + mat4 projection_matrix; + mat4 inv_projection_matrix; + + mat4 camera_matrix; + mat4 inv_camera_matrix; + + vec2 viewport_size; + vec2 screen_pixel_size; + + //used for shadow mapping only + float z_offset; + float z_slope_scale; + + + float time; + float reflection_multiplier; // one normally, zero when rendering reflections + +#if 0 + vec4 ambient_light_color; + vec4 bg_color; + + vec4 fog_color_enabled; + vec4 fog_sun_color_amount; + + float ambient_energy; + float bg_energy; + +#endif + +#if 0 + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + + + float z_far; + + float subsurface_scatter_width; + float ambient_occlusion_affect_light; + float ambient_occlusion_affect_ao_channel; + float opaque_prepass_threshold; + + bool fog_depth_enabled; + float fog_depth_begin; + float fog_depth_end; + float fog_density; + float fog_depth_curve; + bool fog_transmit_enabled; + float fog_transmit_curve; + bool fog_height_enabled; + float fog_height_min; + float fog_height_max; + float fog_height_curve; +#endif +} scene_data; + +layout(set = 0, binding = 5) uniform sampler material_samplers[12]; + +#if 0 +struct DirectionalLightData { + + vec4 light_pos_inv_radius; + vec4 light_direction_attenuation; + vec4 light_color_energy; + vec4 light_params; // cone attenuation, angle, specular, shadow enabled, + vec4 light_clamp; + vec4 shadow_color_contact; + mat4 shadow_matrix1; + mat4 shadow_matrix2; + mat4 shadow_matrix3; + mat4 shadow_matrix4; + vec4 shadow_split_offsets; +}; +#endif + +/* Set 1 Skeleton Data (most objects lack it, so it changes little */ + +#if 0 +layout(set = 1 binding = 0, std140) uniform SkeletonData { + mat4 transform; + bool use_skeleton; + bool use_world_coords; + bool pad1; + bool pad2; +} skeleton; + +layout(set = 1, binding = 1) uniform textureBuffer skeleton_bones; +#endif + +/* Set 2 Custom Material Data (changess less than instance) */ + + +/* Set 3 Instance Data (Set on every draw call) */ + +layout(push_constant, binding = 0, std430) uniform DrawData { + //used in forward rendering, 16 bits indices, max 8 + uvec4 reflection_probe_indices; + uvec4 omni_light_indices; + uvec4 spot_light_indices; + uvec4 decal_indices; +} draw_data; + +layout(set = 3 binding = 0, std140) uniform InstanceData { + mat4 transform; + mat3 normal_transform; + uint flags; + uint pad0; + uint pad0; + uint pad0; +} instance_data; + +layout(set = 3, binding = 1) uniform textureBuffer multimesh_transforms; + +#ifdef USE_LIGHTMAP + +layout(set = 3, binding = 2) uniform texture2D lightmap; + +#endif + +#ifdef USE_VOXEL_CONE_TRACING + +layout(set = 3, binding = 3) uniform texture3D gi_probe[2]; + +#ifdef USE_ANISOTROPIC_VOXEL_CONE_TRACING +layout(set = 3, binding = 4) uniform texture3D gi_probe_aniso_pos[2]; +layout(set = 3, binding = 5) uniform texture3D gi_probe_aniso_neg[2]; +#endif + + +#endif diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h index 49a10a684a4..64c4f0f0c1d 100644 --- a/servers/visual/rendering_device.h +++ b/servers/visual/rendering_device.h @@ -568,7 +568,7 @@ public: }; virtual RID shader_create(const Vector &p_stages) = 0; - virtual Vector shader_get_vertex_input_locations_used(RID p_shader) = 0; + virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0; /******************/ /**** UNIFORMS ****/ @@ -613,6 +613,7 @@ public: virtual bool uniform_set_is_valid(RID p_uniform_set) = 0; virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls + virtual PoolVector buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving /*************************/ /**** RENDER PIPELINE ****/ diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 9c7c97ffe53..5cd5f0b7bb8 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -72,11 +72,13 @@ ShaderTypes::ShaderTypes() { //builtins shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4; + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4; - shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4; + shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3; shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); @@ -114,11 +116,11 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); - shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_NORMAL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT3); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); @@ -162,15 +164,17 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_draw_opaque"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_draw_always"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_draw_never"); - shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_draw_alpha_prepass"); - shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_test_disable"); + shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_prepass_alpha"); + + shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_test_disabled"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("cull_back"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("cull_front"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("cull_disabled"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("unshaded"); + shader_modes[VS::SHADER_SPATIAL].modes.push_back("wireframe"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("diffuse_lambert"); shader_modes[VS::SHADER_SPATIAL].modes.push_back("diffuse_lambert_wrap"); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 2122587304f..31683594734 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -218,11 +218,18 @@ public: /* MESH API */ + virtual RID mesh_create_from_surfaces(const Vector &p_surfaces) { + RID mesh = mesh_create(); + for (int i = 0; i < p_surfaces.size(); i++) { + mesh_add_surface(mesh, p_surfaces[i]); + } + return mesh; + } + BIND0R(RID, mesh_create) - BIND10(mesh_add_surface, RID, uint32_t, PrimitiveType, const PoolVector &, int, const PoolVector &, int, const AABB &, const Vector > &, const Vector &) + BIND2(mesh_add_surface, RID, const SurfaceData &) - BIND2(mesh_set_blend_shape_count, RID, int) BIND1RC(int, mesh_get_blend_shape_count, RID) BIND2(mesh_set_blend_shape_mode, RID, BlendShapeMode) @@ -233,20 +240,8 @@ public: BIND3(mesh_surface_set_material, RID, int, RID) BIND2RC(RID, mesh_surface_get_material, RID, int) - BIND2RC(int, mesh_surface_get_array_len, RID, int) - BIND2RC(int, mesh_surface_get_array_index_len, RID, int) + BIND2RC(SurfaceData, mesh_get_surface, RID, int) - BIND2RC(PoolVector, mesh_surface_get_array, RID, int) - BIND2RC(PoolVector, mesh_surface_get_index_array, RID, int) - - BIND2RC(uint32_t, mesh_surface_get_format, RID, int) - BIND2RC(PrimitiveType, mesh_surface_get_primitive_type, RID, int) - - BIND2RC(AABB, mesh_surface_get_aabb, RID, int) - BIND2RC(Vector >, mesh_surface_get_blend_shapes, RID, int) - BIND2RC(Vector, mesh_surface_get_skeleton_aabb, RID, int) - - BIND2(mesh_remove_surface, RID, int) BIND1RC(int, mesh_get_surface_count, RID) BIND2(mesh_set_custom_aabb, RID, const AABB &) @@ -475,8 +470,6 @@ public: BIND2(viewport_set_hide_scenario, RID, bool) BIND2(viewport_set_hide_canvas, RID, bool) BIND2(viewport_set_disable_environment, RID, bool) - BIND2(viewport_set_disable_3d, RID, bool) - BIND2(viewport_set_keep_3d_linear, RID, bool) BIND2(viewport_attach_camera, RID, RID) BIND2(viewport_set_scenario, RID, RID) @@ -491,8 +484,6 @@ public: BIND2(viewport_set_shadow_atlas_size, RID, int) BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) BIND2(viewport_set_msaa, RID, ViewportMSAA) - BIND2(viewport_set_hdr, RID, bool) - BIND2(viewport_set_usage, RID, ViewportUsage) BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo) BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 27632be2b4e..76ff6265cc5 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -360,6 +360,11 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { instance->octree_id = 0; } + if (instance->custom_data) { + VSG::scene_render->instance_free_custom_data(instance); + instance->custom_data = nullptr; + } + switch (instance->base_type) { case VS::INSTANCE_LIGHT: { @@ -489,6 +494,8 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) { //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it VSG::storage->base_update_dependency(p_base, instance); + + VSG::scene_render->instance_create_custom_data(instance); } _instance_queue_update(instance, true, true); @@ -703,6 +710,8 @@ void VisualServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap lightmap_capture->users.insert(instance); instance->lightmap = p_lightmap; } + + VSG::scene_render->instance_custom_data_update_lightmap(instance); } void VisualServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { @@ -932,6 +941,10 @@ void VisualServerScene::_update_instance(Instance *p_instance) { p_instance->transformed_aabb = new_aabb; + if (p_instance->custom_data) { + VSG::scene_render->instance_custom_data_update_transform(p_instance); + } + if (!p_instance->scenario) { return; @@ -1684,7 +1697,7 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons return animated_material_found; } -void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { +void VisualServerScene::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { // render to mono camera #ifndef _3D_DISABLED @@ -1731,11 +1744,11 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view } _prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - _render_scene(camera->transform, camera_matrix, ortho, camera->env, p_scenario, p_shadow_atlas, RID(), -1); + _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, camera->env, p_scenario, p_shadow_atlas, RID(), -1); #endif } -void VisualServerScene::render_camera(Ref &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { +void VisualServerScene::render_camera(RID p_render_buffers, Ref &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { // render for AR/VR interface Camera *camera = camera_owner.getornull(p_camera); @@ -1816,7 +1829,7 @@ void VisualServerScene::render_camera(Ref &p_interface, ARVRInter } // And render our scene... - _render_scene(cam_transform, camera_matrix, false, camera->env, p_scenario, p_shadow_atlas, RID(), -1); + _render_scene(p_render_buffers, cam_transform, camera_matrix, false, camera->env, p_scenario, p_shadow_atlas, RID(), -1); }; void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe) { @@ -1955,6 +1968,10 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } geom->lighting_dirty = false; + + if (ins->custom_data) { + VSG::scene_render->instance_custom_data_update_lights(ins); + } } if (geom->reflection_dirty) { @@ -1970,6 +1987,10 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } geom->reflection_dirty = false; + + if (ins->custom_data) { + VSG::scene_render->instance_custom_data_update_reflection_probes(ins); + } } if (geom->gi_probes_dirty) { @@ -1985,6 +2006,10 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } geom->gi_probes_dirty = false; + + if (ins->custom_data) { + VSG::scene_render->instance_custom_data_update_gi_probes(ins); + } } ins->depth = near_plane.distance_to(ins->transform.origin); @@ -2145,7 +2170,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca } } -void VisualServerScene::_render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { +void VisualServerScene::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { Scenario *scenario = scenario_owner.getornull(p_scenario); @@ -2161,10 +2186,10 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform, const Cam /* PROCESS GEOMETRY AND DRAW SCENE */ - VSG::scene_render->render_scene(p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass); + VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass); } -void VisualServerScene::render_empty_scene(RID p_scenario, RID p_shadow_atlas) { +void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { #ifndef _3D_DISABLED @@ -2175,7 +2200,7 @@ void VisualServerScene::render_empty_scene(RID p_scenario, RID p_shadow_atlas) { environment = scenario->environment; else environment = scenario->fallback_environment; - VSG::scene_render->render_scene(Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0); + VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0); #endif } @@ -2240,7 +2265,7 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int } _prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance); - _render_scene(xform, cm, false, RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step); + _render_scene(RID(), xform, cm, false, RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step); } else { //do roughness postprocess step until it believes it's done @@ -3368,6 +3393,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (!cast_shadows) { can_cast_shadows = false; } + + VSG::storage->base_update_dependency(mesh, p_instance); } } else if (p_instance->base_type == VS::INSTANCE_IMMEDIATE) { diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 4a04e3b0566..ad0c1caff38 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -478,11 +478,11 @@ public: _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe); - void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); - void render_empty_scene(RID p_scenario, RID p_shadow_atlas); + void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); - void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); - void render_camera(Ref &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, Ref &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); //probes diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index c4447bed104..0baf2032bc9 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -69,9 +69,9 @@ void VisualServerViewport::_draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_ } if (p_viewport->use_arvr && arvr_interface.is_valid()) { - VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + VSG::scene->render_camera(p_viewport->render_buffers, arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); } else { - VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + VSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); } } @@ -95,7 +95,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E } } - bool can_draw_3d = !p_viewport->disable_3d && !p_viewport->disable_3d_by_usage && VSG::scene->camera_owner.owns(p_viewport->camera); + bool can_draw_3d = !VSG::scene->camera_owner.owns(p_viewport->camera); if (p_viewport->clear_mode != VS::VIEWPORT_CLEAR_NEVER) { if (p_viewport->transparent_bg) { @@ -106,6 +106,12 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E } } + if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) { + //wants to draw 3D but there is no render buffer, create + p_viewport->render_buffers = VSG::scene_render->render_buffers_create(); + VSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa); + } + VSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor); if (!scenario_draw_canvas_bg && can_draw_3d) { @@ -218,7 +224,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) { if (!can_draw_3d) { - VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas); + VSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { _draw_3d(p_viewport, p_eye); } @@ -247,7 +253,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { if (!can_draw_3d) { - VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas); + VSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { _draw_3d(p_viewport, p_eye); } @@ -258,7 +264,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E if (scenario_draw_canvas_bg) { if (!can_draw_3d) { - VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas); + VSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { _draw_3d(p_viewport, p_eye); } @@ -427,6 +433,9 @@ void VisualServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_ viewport->size = Size2(p_width, p_height); VSG::storage->render_target_set_size(viewport->render_target, p_width, p_height); + if (viewport->render_buffers.is_valid()) { + VSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa); + } } void VisualServerViewport::viewport_set_active(RID p_viewport, bool p_active) { @@ -523,13 +532,6 @@ void VisualServerViewport::viewport_set_update_mode(RID p_viewport, VS::Viewport viewport->update_mode = p_mode; } -void VisualServerViewport::viewport_set_vflip(RID p_viewport, bool p_enable) { - - Viewport *viewport = viewport_owner.getornull(p_viewport); - ERR_FAIL_COND(!viewport); - - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_VFLIP, p_enable); -} RID VisualServerViewport::viewport_get_texture(RID p_viewport) const { @@ -561,25 +563,6 @@ void VisualServerViewport::viewport_set_disable_environment(RID p_viewport, bool viewport->disable_environment = p_disable; } -void VisualServerViewport::viewport_set_disable_3d(RID p_viewport, bool p_disable) { - - Viewport *viewport = viewport_owner.getornull(p_viewport); - ERR_FAIL_COND(!viewport); - - viewport->disable_3d = p_disable; - //VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D, p_disable); - //this should be just for disabling rendering of 3D, to actually disable it, set usage -} - -void VisualServerViewport::viewport_set_keep_3d_linear(RID p_viewport, bool p_keep_3d_linear) { - - Viewport *viewport = viewport_owner.getornull(p_viewport); - ERR_FAIL_COND(!viewport); - - viewport->keep_3d_linear = p_keep_3d_linear; - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR, p_keep_3d_linear); -} - void VisualServerViewport::viewport_attach_camera(RID p_viewport, RID p_camera) { Viewport *viewport = viewport_owner.getornull(p_viewport); @@ -678,55 +661,12 @@ void VisualServerViewport::viewport_set_msaa(RID p_viewport, VS::ViewportMSAA p_ Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); -#ifndef _MSC_VER -#warning this will no longer go in the render target, but in the 3D view -#endif - //VSG::storage->render_target_set_msaa(viewport->render_target, p_msaa); -} - -void VisualServerViewport::viewport_set_hdr(RID p_viewport, bool p_enabled) { - - Viewport *viewport = viewport_owner.getornull(p_viewport); - ERR_FAIL_COND(!viewport); - - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_HDR, p_enabled); -} - -void VisualServerViewport::viewport_set_usage(RID p_viewport, VS::ViewportUsage p_usage) { - - Viewport *viewport = viewport_owner.getornull(p_viewport); - ERR_FAIL_COND(!viewport); - - switch (p_usage) { - case VS::VIEWPORT_USAGE_2D: { - - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D, true); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS, true); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_SAMPLING, false); - - viewport->disable_3d_by_usage = true; - } break; - case VS::VIEWPORT_USAGE_2D_NO_SAMPLING: { - - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D, true); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS, true); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_SAMPLING, true); - viewport->disable_3d_by_usage = true; - } break; - case VS::VIEWPORT_USAGE_3D: { - - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D, false); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS, false); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_SAMPLING, false); - viewport->disable_3d_by_usage = false; - } break; - case VS::VIEWPORT_USAGE_3D_NO_EFFECTS: { - - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D, false); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS, true); - VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_NO_SAMPLING, false); - viewport->disable_3d_by_usage = false; - } break; + if (viewport->msaa == p_msaa) { + return; + } + viewport->msaa = p_msaa; + if (viewport->render_buffers.is_valid()) { + VSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa); } } @@ -757,6 +697,9 @@ bool VisualServerViewport::free(RID p_rid) { VSG::storage->free(viewport->render_target); VSG::scene_render->free(viewport->shadow_atlas); + if (viewport->render_buffers.is_valid()) { + VSG::scene_render->free(viewport->render_buffers); + } while (viewport->canvas_map.front()) { viewport_remove_canvas(p_rid, viewport->canvas_map.front()->key()); diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index f701e3612a2..eecbe0d1db3 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -56,6 +56,9 @@ public: VS::ViewportUpdateMode update_mode; RID render_target; RID render_target_texture; + RID render_buffers; + + VS::ViewportMSAA msaa; int viewport_to_screen; Rect2 viewport_to_screen_rect; @@ -64,7 +67,6 @@ public: bool hide_scenario; bool hide_canvas; bool disable_environment; - bool disable_3d; bool disable_3d_by_usage; bool keep_3d_linear; @@ -117,10 +119,9 @@ public: disable_environment = false; viewport_to_screen = 0; shadow_atlas_size = 0; - disable_3d = false; - disable_3d_by_usage = false; keep_3d_linear = false; debug_draw = VS::VIEWPORT_DEBUG_DRAW_DISABLED; + msaa = VS::VIEWPORT_MSAA_DISABLED; for (int i = 0; i < VS::VIEWPORT_RENDER_INFO_MAX; i++) { render_info[i] = 0; } @@ -174,8 +175,6 @@ public: void viewport_set_hide_scenario(RID p_viewport, bool p_hide); void viewport_set_hide_canvas(RID p_viewport, bool p_hide); void viewport_set_disable_environment(RID p_viewport, bool p_disable); - void viewport_set_disable_3d(RID p_viewport, bool p_disable); - void viewport_set_keep_3d_linear(RID p_viewport, bool p_keep_3d_linear); void viewport_attach_camera(RID p_viewport, RID p_camera); void viewport_set_scenario(RID p_viewport, RID p_scenario); @@ -191,8 +190,6 @@ public: void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv); void viewport_set_msaa(RID p_viewport, VS::ViewportMSAA p_msaa); - void viewport_set_hdr(RID p_viewport, bool p_enabled); - void viewport_set_usage(RID p_viewport, VS::ViewportUsage p_usage); virtual int viewport_get_render_info(RID p_viewport, VS::ViewportRenderInfo p_info); virtual void viewport_set_debug_draw(RID p_viewport, VS::ViewportDebugDraw p_draw); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index c2e7f659abc..135e4a8bd04 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -149,11 +149,14 @@ public: /* MESH API */ + virtual RID mesh_create_from_surfaces(const Vector &p_surfaces) { + return visual_server->mesh_create_from_surfaces(p_surfaces); + } + FUNCRID(mesh) - FUNC10(mesh_add_surface, RID, uint32_t, PrimitiveType, const PoolVector &, int, const PoolVector &, int, const AABB &, const Vector > &, const Vector &) + FUNC2(mesh_add_surface, RID, const SurfaceData &) - FUNC2(mesh_set_blend_shape_count, RID, int) FUNC1RC(int, mesh_get_blend_shape_count, RID) FUNC2(mesh_set_blend_shape_mode, RID, BlendShapeMode) @@ -164,20 +167,8 @@ public: FUNC3(mesh_surface_set_material, RID, int, RID) FUNC2RC(RID, mesh_surface_get_material, RID, int) - FUNC2RC(int, mesh_surface_get_array_len, RID, int) - FUNC2RC(int, mesh_surface_get_array_index_len, RID, int) + FUNC2RC(SurfaceData, mesh_get_surface, RID, int) - FUNC2RC(PoolVector, mesh_surface_get_array, RID, int) - FUNC2RC(PoolVector, mesh_surface_get_index_array, RID, int) - - FUNC2RC(uint32_t, mesh_surface_get_format, RID, int) - FUNC2RC(PrimitiveType, mesh_surface_get_primitive_type, RID, int) - - FUNC2RC(AABB, mesh_surface_get_aabb, RID, int) - FUNC2RC(Vector >, mesh_surface_get_blend_shapes, RID, int) - FUNC2RC(Vector, mesh_surface_get_skeleton_aabb, RID, int) - - FUNC2(mesh_remove_surface, RID, int) FUNC1RC(int, mesh_get_surface_count, RID) FUNC2(mesh_set_custom_aabb, RID, const AABB &) @@ -390,15 +381,12 @@ public: FUNC1(viewport_detach, RID) FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode) - FUNC2(viewport_set_vflip, RID, bool) FUNC1RC(RID, viewport_get_texture, RID) FUNC2(viewport_set_hide_scenario, RID, bool) FUNC2(viewport_set_hide_canvas, RID, bool) FUNC2(viewport_set_disable_environment, RID, bool) - FUNC2(viewport_set_disable_3d, RID, bool) - FUNC2(viewport_set_keep_3d_linear, RID, bool) FUNC2(viewport_attach_camera, RID, RID) FUNC2(viewport_set_scenario, RID, RID) @@ -413,8 +401,6 @@ public: FUNC2(viewport_set_shadow_atlas_size, RID, int) FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) FUNC2(viewport_set_msaa, RID, ViewportMSAA) - FUNC2(viewport_set_hdr, RID, bool) - FUNC2(viewport_set_usage, RID, ViewportUsage) //this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) { diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 4f14a6b27d2..60822f17466 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -360,24 +360,7 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ // setting vertices means regenerating the AABB Rect2 aabb; - if (p_format & ARRAY_COMPRESS_VERTEX) { - - for (int i = 0; i < p_vertex_array_len; i++) { - - uint16_t vector[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; - - copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(uint16_t) * 2); - - if (i == 0) { - - aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size - } else { - - aabb.expand_to(src[i]); - } - } - - } else { + { for (int i = 0; i < p_vertex_array_len; i++) { float vector[2] = { src[i].x, src[i].y }; @@ -406,24 +389,7 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ // setting vertices means regenerating the AABB AABB aabb; - if (p_format & ARRAY_COMPRESS_VERTEX) { - - for (int i = 0; i < p_vertex_array_len; i++) { - - uint16_t vector[4] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y), Math::make_half_float(src[i].z), Math::make_half_float(1.0) }; - - copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(uint16_t) * 4); - - if (i == 0) { - - aabb = AABB(src[i], SMALL_VEC3); - } else { - - aabb.expand_to(src[i]); - } - } - - } else { + { for (int i = 0; i < p_vertex_array_len; i++) { float vector[3] = { src[i].x, src[i].y, src[i].z }; @@ -624,7 +590,7 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ const real_t *src = read.ptr(); - if (p_format & ARRAY_COMPRESS_WEIGHTS) { + { for (int i = 0; i < p_vertex_array_len; i++) { @@ -635,17 +601,6 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4); } - } else { - - for (int i = 0; i < p_vertex_array_len; i++) { - - float data[VS::ARRAY_WEIGHTS_SIZE]; - for (int j = 0; j < VS::ARRAY_WEIGHTS_SIZE; j++) { - data[j] = src[i * VS::ARRAY_WEIGHTS_SIZE + j]; - } - - copymem(&vw[p_offsets[ai] + i * p_stride], data, 4 * 4); - } } } break; @@ -661,30 +616,15 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ const int *src = read.ptr(); - if (!(p_format & ARRAY_FLAG_USE_16_BIT_BONES)) { + for (int i = 0; i < p_vertex_array_len; i++) { - for (int i = 0; i < p_vertex_array_len; i++) { - - uint8_t data[VS::ARRAY_WEIGHTS_SIZE]; - for (int j = 0; j < VS::ARRAY_WEIGHTS_SIZE; j++) { - data[j] = CLAMP(src[i * VS::ARRAY_WEIGHTS_SIZE + j], 0, 255); - max_bone = MAX(data[j], max_bone); - } - - copymem(&vw[p_offsets[ai] + i * p_stride], data, 4); + uint16_t data[VS::ARRAY_WEIGHTS_SIZE]; + for (int j = 0; j < VS::ARRAY_WEIGHTS_SIZE; j++) { + data[j] = src[i * VS::ARRAY_WEIGHTS_SIZE + j]; + max_bone = MAX(data[j], max_bone); } - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - - uint16_t data[VS::ARRAY_WEIGHTS_SIZE]; - for (int j = 0; j < VS::ARRAY_WEIGHTS_SIZE; j++) { - data[j] = src[i * VS::ARRAY_WEIGHTS_SIZE + j]; - max_bone = MAX(data[j], max_bone); - } - - copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4); - } + copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4); } } break; @@ -814,9 +754,7 @@ uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format, elem_size = 3; } - if (p_format & ARRAY_COMPRESS_VERTEX) { - elem_size *= sizeof(int16_t); - } else { + { elem_size *= sizeof(float); } @@ -870,20 +808,12 @@ uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format, } break; case VS::ARRAY_WEIGHTS: { - if (p_format & ARRAY_COMPRESS_WEIGHTS) { - elem_size = sizeof(uint16_t) * 4; - } else { - elem_size = sizeof(float) * 4; - } + elem_size = sizeof(uint16_t) * 4; } break; case VS::ARRAY_BONES: { - if (p_format & ARRAY_FLAG_USE_16_BIT_BONES) { - elem_size = sizeof(uint16_t) * 4; - } else { - elem_size = sizeof(uint32_t); - } + elem_size = sizeof(uint16_t) * 4; } break; case VS::ARRAY_INDEX: { @@ -914,10 +844,10 @@ uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format, return total_elem_size; } -void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_compress_format) { +Error VisualServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) { - ERR_FAIL_INDEX(p_primitive, VS::PRIMITIVE_MAX); - ERR_FAIL_COND(p_arrays.size() != VS::ARRAY_MAX); + ERR_FAIL_INDEX_V(p_primitive, VS::PRIMITIVE_MAX, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_arrays.size() != VS::ARRAY_MAX, ERR_INVALID_PARAMETER); uint32_t format = 0; @@ -948,14 +878,14 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim } array_len = PoolVector3Array(p_arrays[i]).size(); - ERR_FAIL_COND(array_len == 0); + ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA); } else if (i == VS::ARRAY_INDEX) { index_array_len = PoolIntArray(p_arrays[i]).size(); } } - ERR_FAIL_COND((format & VS::ARRAY_FORMAT_VERTEX) == 0); // mandatory + ERR_FAIL_COND_V((format & VS::ARRAY_FORMAT_VERTEX) == 0, ERR_INVALID_PARAMETER); // mandatory if (p_blend_shapes.size()) { //validate format for morphs @@ -969,7 +899,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim bsformat |= (1 << j); } - ERR_FAIL_COND((bsformat) != (format & (VS::ARRAY_FORMAT_INDEX - 1))); + ERR_FAIL_COND_V((bsformat) != (format & (VS::ARRAY_FORMAT_INDEX - 1)), ERR_INVALID_PARAMETER); } } @@ -1001,9 +931,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim elem_size = (p_compress_format & ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3; } - if (p_compress_format & ARRAY_COMPRESS_VERTEX) { - elem_size *= sizeof(int16_t); - } else { + { elem_size *= sizeof(float); } @@ -1058,33 +986,12 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim } break; case VS::ARRAY_WEIGHTS: { - if (p_compress_format & ARRAY_COMPRESS_WEIGHTS) { - elem_size = sizeof(uint16_t) * 4; - } else { - elem_size = sizeof(float) * 4; - } + elem_size = sizeof(uint16_t) * 4; } break; case VS::ARRAY_BONES: { - PoolVector bones = p_arrays[VS::ARRAY_BONES]; - int max_bone = 0; - - { - int bc = bones.size(); - PoolVector::Read r = bones.read(); - for (int j = 0; j < bc; j++) { - max_bone = MAX(r[j], max_bone); - } - } - - if (max_bone > 255) { - p_compress_format |= ARRAY_FLAG_USE_16_BIT_BONES; - elem_size = sizeof(uint16_t) * 4; - } else { - p_compress_format &= ~ARRAY_FLAG_USE_16_BIT_BONES; - elem_size = sizeof(uint32_t); - } + elem_size = sizeof(uint16_t) * 4; } break; case VS::ARRAY_INDEX: { @@ -1105,7 +1012,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim continue; } default: { - ERR_FAIL(); + ERR_FAIL_V(ERR_BUG); } } @@ -1130,7 +1037,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim Vector bone_aabb; Error err = _surface_set_data(p_arrays, format, offsets, total_elem_size, vertex_array, array_len, index_array, index_array_len, aabb, bone_aabb); - ERR_FAIL_COND_MSG(err, "Invalid array format for surface."); + ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface."); Vector > blend_shape_data; @@ -1143,12 +1050,74 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim AABB laabb; Error err2 = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb); aabb.merge_with(laabb); - ERR_FAIL_COND_MSG(err2 != OK, "Invalid blend shape array format for surface."); + ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface."); blend_shape_data.push_back(vertex_array_shape); } + Vector lods; + if (index_array_len) { - mesh_add_surface(p_mesh, format, p_primitive, vertex_array, array_len, index_array, index_array_len, aabb, blend_shape_data, bone_aabb); + List keys; + p_lods.get_key_list(&keys); + for (List::Element *E = keys.front(); E; E = E->next()) { + float distance = E->get(); + ERR_CONTINUE(distance <= 0.0); + PoolVector indices = p_lods[E->get()]; + ERR_CONTINUE(indices.size() == 0); + uint32_t index_count = indices.size(); + ERR_CONTINUE(index_count >= (uint32_t)index_array_len); //should be smaller.. + + PoolVector::Read r = indices.read(); + + PoolVector data; + if (array_len <= 65536) { + //16 bits indices + data.resize(indices.size() * 2); + PoolVector::Write w = data.write(); + uint16_t *index_ptr = (uint16_t *)w.ptr(); + for (uint32_t i = 0; i < index_count; i++) { + index_ptr[i] = r[i]; + } + } else { + //32 bits indices + data.resize(indices.size() * 4); + PoolVector::Write w = data.write(); + uint32_t *index_ptr = (uint32_t *)w.ptr(); + for (uint32_t i = 0; i < index_count; i++) { + index_ptr[i] = r[i]; + } + } + + SurfaceData::LOD lod; + lod.edge_length = distance; + lod.index_data = data; + lods.push_back(lod); + } + } + + SurfaceData &surface_data = *r_surface_data; + surface_data.format = format; + surface_data.primitive = p_primitive; + surface_data.aabb = aabb; + surface_data.vertex_data = vertex_array; + surface_data.vertex_count = array_len; + surface_data.index_data = index_array; + surface_data.index_count = index_array_len; + surface_data.blend_shapes = blend_shape_data; + surface_data.bone_aabbs = bone_aabb; + surface_data.lods = lods; + + return OK; +} + +void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) { + + SurfaceData sd; + Error err = mesh_create_surface_data_from_arrays(&sd, p_primitive, p_arrays, p_blend_shapes, p_lods, p_compress_format); + if (err != OK) { + return; + } + mesh_add_surface(p_mesh, sd); } Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector p_vertex_data, int p_vertex_len, PoolVector p_index_data, int p_index_len) const { @@ -1176,9 +1145,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector arr_2d; arr_2d.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_VERTEX) { - - PoolVector::Write w = arr_2d.write(); - - for (int j = 0; j < p_vertex_len; j++) { - - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1])); - } - } else { + { PoolVector::Write w = arr_2d.write(); @@ -1319,16 +1269,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector arr_3d; arr_3d.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_VERTEX) { - - PoolVector::Write w = arr_3d.write(); - - for (int j = 0; j < p_vertex_len; j++) { - - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector3(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1]), Math::halfptr_to_float(&v[2])); - } - } else { + { PoolVector::Write w = arr_3d.write(); @@ -1484,7 +1425,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector arr; arr.resize(p_vertex_len * 4); - if (p_format & ARRAY_COMPRESS_WEIGHTS) { + { PoolVector::Write w = arr.write(); for (int j = 0; j < p_vertex_len; j++) { @@ -1494,16 +1435,6 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector::Write w = arr.write(); - - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = v[k]; - } - } } ret[i] = arr; @@ -1513,26 +1444,14 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector arr; arr.resize(p_vertex_len * 4); - if (p_format & ARRAY_FLAG_USE_16_BIT_BONES) { - PoolVector::Write w = arr.write(); + PoolVector::Write w = arr.write(); - for (int j = 0; j < p_vertex_len; j++) { + for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = v[k]; - } - } - } else { - - PoolVector::Write w = arr.write(); - - for (int j = 0; j < p_vertex_len; j++) { - const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = v[k]; - } + const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; + for (int k = 0; k < 4; k++) { + w[j * 4 + k] = v[k]; } } @@ -1577,28 +1496,59 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector vertex_data = mesh_surface_get_array(p_mesh, p_surface); - ERR_FAIL_COND_V(vertex_data.size() == 0, Array()); - int vertex_len = mesh_surface_get_array_len(p_mesh, p_surface); + SurfaceData sd = mesh_get_surface(p_mesh, p_surface); + return mesh_create_arrays_from_surface_data(sd); +} - PoolVector index_data = mesh_surface_get_index_array(p_mesh, p_surface); - int index_len = mesh_surface_get_array_index_len(p_mesh, p_surface); +Dictionary VisualServer::mesh_surface_get_lods(RID p_mesh, int p_surface) const { - uint32_t format = mesh_surface_get_format(p_mesh, p_surface); + SurfaceData sd = mesh_get_surface(p_mesh, p_surface); + ERR_FAIL_COND_V(sd.vertex_count == 0, Dictionary()); - return _get_array_from_surface(format, vertex_data, vertex_len, index_data, index_len); + Dictionary ret; + + for (int i = 0; i < sd.lods.size(); i++) { + PoolVector lods; + if (sd.vertex_count <= 65536) { + uint32_t lc = sd.lods[i].index_data.size() / 2; + lods.resize(lc); + PoolVector::Read r = sd.lods[i].index_data.read(); + const uint16_t *rptr = (const uint16_t *)r.ptr(); + PoolVector::Write w = lods.write(); + for (uint32_t j = 0; j < lc; j++) { + w[j] = rptr[i]; + } + } else { + uint32_t lc = sd.lods[i].index_data.size() / 4; + lods.resize(lc); + PoolVector::Read r = sd.lods[i].index_data.read(); + const uint32_t *rptr = (const uint32_t *)r.ptr(); + PoolVector::Write w = lods.write(); + for (uint32_t j = 0; j < lc; j++) { + w[j] = rptr[i]; + } + } + + ret[sd.lods[i].edge_length] = lods; + } + + return ret; } Array VisualServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const { - Vector > blend_shape_data = mesh_surface_get_blend_shapes(p_mesh, p_surface); + SurfaceData sd = mesh_get_surface(p_mesh, p_surface); + ERR_FAIL_COND_V(sd.vertex_count == 0, Array()); + + Vector > blend_shape_data = sd.blend_shapes; + if (blend_shape_data.size() > 0) { - int vertex_len = mesh_surface_get_array_len(p_mesh, p_surface); + int vertex_len = sd.vertex_count; - PoolVector index_data = mesh_surface_get_index_array(p_mesh, p_surface); - int index_len = mesh_surface_get_array_index_len(p_mesh, p_surface); + PoolVector index_data = sd.index_data; + int index_len = sd.index_count; - uint32_t format = mesh_surface_get_format(p_mesh, p_surface); + uint32_t format = sd.format; Array blend_shape_array; blend_shape_array.resize(blend_shape_data.size()); @@ -1612,6 +1562,21 @@ Array VisualServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surfac } } +Array VisualServer::mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const { + + PoolVector vertex_data = p_data.vertex_data; + + ERR_FAIL_COND_V(vertex_data.size() == 0, Array()); + int vertex_len = p_data.vertex_count; + + PoolVector index_data = p_data.index_data; + int index_len = p_data.index_count; + + uint32_t format = p_data.format; + + return _get_array_from_surface(format, vertex_data, vertex_len, index_data, index_len); +} +#if 0 Array VisualServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const { Vector vec = VS::get_singleton()->mesh_surface_get_skeleton_aabb(p_mesh, p_surface); @@ -1621,7 +1586,7 @@ Array VisualServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surfa } return arr; } - +#endif void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("force_sync"), &VisualServer::sync); @@ -1664,24 +1629,14 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &VisualServer::mesh_surface_get_format_offset); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &VisualServer::mesh_surface_get_format_stride); ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "compress_format"), &VisualServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); - ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_count", "mesh", "amount"), &VisualServer::mesh_set_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &VisualServer::mesh_get_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &VisualServer::mesh_set_blend_shape_mode); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &VisualServer::mesh_get_blend_shape_mode); ClassDB::bind_method(D_METHOD("mesh_surface_update_region", "mesh", "surface", "offset", "data"), &VisualServer::mesh_surface_update_region); ClassDB::bind_method(D_METHOD("mesh_surface_set_material", "mesh", "surface", "material"), &VisualServer::mesh_surface_set_material); ClassDB::bind_method(D_METHOD("mesh_surface_get_material", "mesh", "surface"), &VisualServer::mesh_surface_get_material); - ClassDB::bind_method(D_METHOD("mesh_surface_get_array_len", "mesh", "surface"), &VisualServer::mesh_surface_get_array_len); - ClassDB::bind_method(D_METHOD("mesh_surface_get_array_index_len", "mesh", "surface"), &VisualServer::mesh_surface_get_array_index_len); - ClassDB::bind_method(D_METHOD("mesh_surface_get_array", "mesh", "surface"), &VisualServer::mesh_surface_get_array); - ClassDB::bind_method(D_METHOD("mesh_surface_get_index_array", "mesh", "surface"), &VisualServer::mesh_surface_get_index_array); ClassDB::bind_method(D_METHOD("mesh_surface_get_arrays", "mesh", "surface"), &VisualServer::mesh_surface_get_arrays); ClassDB::bind_method(D_METHOD("mesh_surface_get_blend_shape_arrays", "mesh", "surface"), &VisualServer::mesh_surface_get_blend_shape_arrays); - ClassDB::bind_method(D_METHOD("mesh_surface_get_format", "mesh", "surface"), &VisualServer::mesh_surface_get_format); - ClassDB::bind_method(D_METHOD("mesh_surface_get_primitive_type", "mesh", "surface"), &VisualServer::mesh_surface_get_primitive_type); - ClassDB::bind_method(D_METHOD("mesh_surface_get_aabb", "mesh", "surface"), &VisualServer::mesh_surface_get_aabb); - ClassDB::bind_method(D_METHOD("mesh_surface_get_skeleton_aabb", "mesh", "surface"), &VisualServer::_mesh_surface_get_skeleton_aabb_bind); - ClassDB::bind_method(D_METHOD("mesh_remove_surface", "mesh", "index"), &VisualServer::mesh_remove_surface); ClassDB::bind_method(D_METHOD("mesh_get_surface_count", "mesh"), &VisualServer::mesh_get_surface_count); ClassDB::bind_method(D_METHOD("mesh_set_custom_aabb", "mesh", "aabb"), &VisualServer::mesh_set_custom_aabb); ClassDB::bind_method(D_METHOD("mesh_get_custom_aabb", "mesh"), &VisualServer::mesh_get_custom_aabb); @@ -1842,13 +1797,11 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_render_direct_to_screen", "viewport", "enabled"), &VisualServer::viewport_set_render_direct_to_screen); ClassDB::bind_method(D_METHOD("viewport_detach", "viewport"), &VisualServer::viewport_detach); ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &VisualServer::viewport_set_update_mode); - ClassDB::bind_method(D_METHOD("viewport_set_vflip", "viewport", "enabled"), &VisualServer::viewport_set_vflip); ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &VisualServer::viewport_set_clear_mode); ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &VisualServer::viewport_get_texture); ClassDB::bind_method(D_METHOD("viewport_set_hide_scenario", "viewport", "hidden"), &VisualServer::viewport_set_hide_scenario); ClassDB::bind_method(D_METHOD("viewport_set_hide_canvas", "viewport", "hidden"), &VisualServer::viewport_set_hide_canvas); ClassDB::bind_method(D_METHOD("viewport_set_disable_environment", "viewport", "disabled"), &VisualServer::viewport_set_disable_environment); - ClassDB::bind_method(D_METHOD("viewport_set_disable_3d", "viewport", "disabled"), &VisualServer::viewport_set_disable_3d); ClassDB::bind_method(D_METHOD("viewport_attach_camera", "viewport", "camera"), &VisualServer::viewport_attach_camera); ClassDB::bind_method(D_METHOD("viewport_set_scenario", "viewport", "scenario"), &VisualServer::viewport_set_scenario); ClassDB::bind_method(D_METHOD("viewport_attach_canvas", "viewport", "canvas"), &VisualServer::viewport_attach_canvas); @@ -1860,8 +1813,6 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &VisualServer::viewport_set_shadow_atlas_size); ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &VisualServer::viewport_set_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &VisualServer::viewport_set_msaa); - ClassDB::bind_method(D_METHOD("viewport_set_hdr", "viewport", "enabled"), &VisualServer::viewport_set_hdr); - ClassDB::bind_method(D_METHOD("viewport_set_usage", "viewport", "usage"), &VisualServer::viewport_set_usage); ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &VisualServer::viewport_get_render_info); ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &VisualServer::viewport_set_debug_draw); @@ -2068,22 +2019,21 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES); BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_VERTEX); + BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_BONES); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); - BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_16_BIT_BONES); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT); BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); + BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES); + BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP); BIND_ENUM_CONSTANT(PRIMITIVE_MAX); BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); @@ -2137,11 +2087,6 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_MSAA_EXT_2X); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_EXT_4X); - BIND_ENUM_CONSTANT(VIEWPORT_USAGE_2D); - BIND_ENUM_CONSTANT(VIEWPORT_USAGE_2D_NO_SAMPLING); - BIND_ENUM_CONSTANT(VIEWPORT_USAGE_3D); - BIND_ENUM_CONSTANT(VIEWPORT_USAGE_3D_NO_EFFECTS); - BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME); diff --git a/servers/visual_server.h b/servers/visual_server.h index 957b8fe48fb..e2c27675fbf 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -229,41 +229,68 @@ public: ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX, ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1), - ARRAY_COMPRESS_VERTEX = 1 << (ARRAY_VERTEX + ARRAY_COMPRESS_BASE), // mandatory ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_BONES = 1 << (ARRAY_BONES + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_WEIGHTS = 1 << (ARRAY_WEIGHTS + ARRAY_COMPRESS_BASE), ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE), ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1, - ARRAY_FLAG_USE_16_BIT_BONES = ARRAY_COMPRESS_INDEX << 2, ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3, - ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS + ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 }; enum PrimitiveType { PRIMITIVE_POINTS, PRIMITIVE_LINES, + PRIMITIVE_LINE_STRIP, PRIMITIVE_TRIANGLES, + PRIMITIVE_TRIANGLE_STRIP, PRIMITIVE_MAX, }; + struct SurfaceData { + + PrimitiveType primitive = PRIMITIVE_MAX; + + uint32_t format = 0; + PoolVector vertex_data; + uint32_t vertex_count = 0; + PoolVector index_data; + uint32_t index_count = 0; + + AABB aabb; + struct LOD { + float edge_length; + PoolVector index_data; + }; + Vector lods; + Vector bone_aabbs; + + Vector > blend_shapes; + + RID material; + }; + + virtual RID mesh_create_from_surfaces(const Vector &p_surfaces) = 0; virtual RID mesh_create() = 0; virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const; virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const; /// Returns stride virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const; - virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); - virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, PrimitiveType p_primitive, const PoolVector &p_array, int p_vertex_count, const PoolVector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector > &p_blend_shapes = Vector >(), const Vector &p_bone_aabbs = Vector()) = 0; + virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); + Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const; + Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const; + Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const; + Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const; + + virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); + virtual void mesh_add_surface(RID p_mesh, const SurfaceData &p_surface) = 0; - virtual void mesh_set_blend_shape_count(RID p_mesh, int p_amount) = 0; virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; enum BlendShapeMode { @@ -279,24 +306,8 @@ public: virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; - virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const = 0; - virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const = 0; + virtual SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0; - virtual PoolVector mesh_surface_get_array(RID p_mesh, int p_surface) const = 0; - virtual PoolVector mesh_surface_get_index_array(RID p_mesh, int p_surface) const = 0; - - virtual Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const; - virtual Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const; - - virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const = 0; - virtual PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const = 0; - - virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const = 0; - virtual Vector > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const = 0; - virtual Vector mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const = 0; - Array _mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const; - - virtual void mesh_remove_surface(RID p_mesh, int p_index) = 0; virtual int mesh_get_surface_count(RID p_mesh) const = 0; virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; @@ -604,7 +615,6 @@ public: }; virtual void viewport_set_update_mode(RID p_viewport, ViewportUpdateMode p_mode) = 0; - virtual void viewport_set_vflip(RID p_viewport, bool p_enable) = 0; enum ViewportClearMode { @@ -620,8 +630,6 @@ public: virtual void viewport_set_hide_scenario(RID p_viewport, bool p_hide) = 0; virtual void viewport_set_hide_canvas(RID p_viewport, bool p_hide) = 0; virtual void viewport_set_disable_environment(RID p_viewport, bool p_disable) = 0; - virtual void viewport_set_disable_3d(RID p_viewport, bool p_disable) = 0; - virtual void viewport_set_keep_3d_linear(RID p_viewport, bool p_disable) = 0; virtual void viewport_attach_camera(RID p_viewport, RID p_camera) = 0; virtual void viewport_set_scenario(RID p_viewport, RID p_scenario) = 0; @@ -648,16 +656,6 @@ public: virtual void viewport_set_msaa(RID p_viewport, ViewportMSAA p_msaa) = 0; - enum ViewportUsage { - VIEWPORT_USAGE_2D, - VIEWPORT_USAGE_2D_NO_SAMPLING, - VIEWPORT_USAGE_3D, - VIEWPORT_USAGE_3D_NO_EFFECTS, - }; - - virtual void viewport_set_hdr(RID p_viewport, bool p_enabled) = 0; - virtual void viewport_set_usage(RID p_viewport, ViewportUsage p_usage) = 0; - enum ViewportRenderInfo { VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME, @@ -1075,7 +1073,6 @@ VARIANT_ENUM_CAST(VisualServer::LightParam); VARIANT_ENUM_CAST(VisualServer::ViewportUpdateMode); VARIANT_ENUM_CAST(VisualServer::ViewportClearMode); VARIANT_ENUM_CAST(VisualServer::ViewportMSAA); -VARIANT_ENUM_CAST(VisualServer::ViewportUsage); VARIANT_ENUM_CAST(VisualServer::ViewportRenderInfo); VARIANT_ENUM_CAST(VisualServer::ViewportDebugDraw); VARIANT_ENUM_CAST(VisualServer::ScenarioDebugMode);