mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
Merge pull request #97151 from devloglogan/motion-vectors
Implement motion vectors in compatibility renderer
This commit is contained in:
commit
d9ba9ba3da
14 changed files with 871 additions and 341 deletions
|
@ -1468,9 +1468,9 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index, Ren
|
||||||
uint64_t vertex_input_mask = state.canvas_instance_batches[p_index].vertex_input_mask;
|
uint64_t vertex_input_mask = state.canvas_instance_batches[p_index].vertex_input_mask;
|
||||||
|
|
||||||
if (mesh_instance.is_valid()) {
|
if (mesh_instance.is_valid()) {
|
||||||
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, vertex_input_mask, vertex_array_gl);
|
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, vertex_input_mask, false, vertex_array_gl);
|
||||||
} else {
|
} else {
|
||||||
mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, vertex_input_mask, vertex_array_gl);
|
mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, vertex_input_mask, false, vertex_array_gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
|
index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
|
||||||
|
|
|
@ -1476,147 +1476,147 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
|
||||||
correction.set_depth_correction(p_flip_y, true, false);
|
correction.set_depth_correction(p_flip_y, true, false);
|
||||||
Projection projection = correction * p_render_data->cam_projection;
|
Projection projection = correction * p_render_data->cam_projection;
|
||||||
//store camera into ubo
|
//store camera into ubo
|
||||||
GLES3::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix);
|
GLES3::MaterialStorage::store_camera(projection, scene_state.data.projection_matrix);
|
||||||
GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
|
GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.data.inv_projection_matrix);
|
||||||
GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
|
GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.data.inv_view_matrix);
|
||||||
GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix);
|
GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.data.view_matrix);
|
||||||
GLES3::MaterialStorage::store_transform(p_render_data->main_cam_transform, scene_state.ubo.main_cam_inv_view_matrix);
|
GLES3::MaterialStorage::store_transform(p_render_data->main_cam_transform, scene_state.data.main_cam_inv_view_matrix);
|
||||||
scene_state.ubo.camera_visible_layers = p_render_data->camera_visible_layers;
|
scene_state.data.camera_visible_layers = p_render_data->camera_visible_layers;
|
||||||
|
|
||||||
if (p_render_data->view_count > 1) {
|
if (p_render_data->view_count > 1) {
|
||||||
for (uint32_t v = 0; v < p_render_data->view_count; v++) {
|
for (uint32_t v = 0; v < p_render_data->view_count; v++) {
|
||||||
projection = correction * p_render_data->view_projection[v];
|
projection = correction * p_render_data->view_projection[v];
|
||||||
GLES3::MaterialStorage::store_camera(projection, scene_state.multiview_ubo.projection_matrix_view[v]);
|
GLES3::MaterialStorage::store_camera(projection, scene_state.multiview_data.projection_matrix_view[v]);
|
||||||
GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.multiview_ubo.inv_projection_matrix_view[v]);
|
GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.multiview_data.inv_projection_matrix_view[v]);
|
||||||
|
|
||||||
scene_state.multiview_ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
|
scene_state.multiview_data.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
|
||||||
scene_state.multiview_ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
|
scene_state.multiview_data.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
|
||||||
scene_state.multiview_ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
|
scene_state.multiview_data.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
|
||||||
scene_state.multiview_ubo.eye_offset[v][3] = 0.0;
|
scene_state.multiview_data.eye_offset[v][3] = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only render the lights without shadows in the base pass.
|
// Only render the lights without shadows in the base pass.
|
||||||
scene_state.ubo.directional_light_count = p_render_data->directional_light_count - p_render_data->directional_shadow_count;
|
scene_state.data.directional_light_count = p_render_data->directional_light_count - p_render_data->directional_shadow_count;
|
||||||
|
|
||||||
scene_state.ubo.z_far = p_render_data->z_far;
|
scene_state.data.z_far = p_render_data->z_far;
|
||||||
scene_state.ubo.z_near = p_render_data->z_near;
|
scene_state.data.z_near = p_render_data->z_near;
|
||||||
|
|
||||||
scene_state.ubo.viewport_size[0] = p_screen_size.x;
|
scene_state.data.viewport_size[0] = p_screen_size.x;
|
||||||
scene_state.ubo.viewport_size[1] = p_screen_size.y;
|
scene_state.data.viewport_size[1] = p_screen_size.y;
|
||||||
|
|
||||||
Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
|
Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
|
||||||
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
|
scene_state.data.screen_pixel_size[0] = screen_pixel_size.x;
|
||||||
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
|
scene_state.data.screen_pixel_size[1] = screen_pixel_size.y;
|
||||||
|
|
||||||
scene_state.ubo.luminance_multiplier = p_render_data->luminance_multiplier;
|
scene_state.data.luminance_multiplier = p_render_data->luminance_multiplier;
|
||||||
|
|
||||||
scene_state.ubo.shadow_bias = p_shadow_bias;
|
scene_state.data.shadow_bias = p_shadow_bias;
|
||||||
scene_state.ubo.pancake_shadows = p_pancake_shadows;
|
scene_state.data.pancake_shadows = p_pancake_shadows;
|
||||||
|
|
||||||
//time global variables
|
//time global variables
|
||||||
scene_state.ubo.time = time;
|
scene_state.data.time = time;
|
||||||
|
|
||||||
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
|
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
|
||||||
scene_state.ubo.use_ambient_light = true;
|
scene_state.data.use_ambient_light = true;
|
||||||
scene_state.ubo.ambient_light_color_energy[0] = 1;
|
scene_state.data.ambient_light_color_energy[0] = 1;
|
||||||
scene_state.ubo.ambient_light_color_energy[1] = 1;
|
scene_state.data.ambient_light_color_energy[1] = 1;
|
||||||
scene_state.ubo.ambient_light_color_energy[2] = 1;
|
scene_state.data.ambient_light_color_energy[2] = 1;
|
||||||
scene_state.ubo.ambient_light_color_energy[3] = 1.0;
|
scene_state.data.ambient_light_color_energy[3] = 1.0;
|
||||||
scene_state.ubo.use_ambient_cubemap = false;
|
scene_state.data.use_ambient_cubemap = false;
|
||||||
scene_state.ubo.use_reflection_cubemap = false;
|
scene_state.data.use_reflection_cubemap = false;
|
||||||
} else if (is_environment(p_render_data->environment)) {
|
} else if (is_environment(p_render_data->environment)) {
|
||||||
RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
|
RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
|
||||||
RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
|
RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
|
||||||
|
|
||||||
float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
|
float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
|
||||||
|
|
||||||
scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
|
scene_state.data.ambient_light_color_energy[3] = bg_energy_multiplier;
|
||||||
|
|
||||||
scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
|
scene_state.data.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
|
||||||
|
|
||||||
//ambient
|
//ambient
|
||||||
if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
|
if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
|
||||||
Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
|
Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
|
||||||
color = color.srgb_to_linear();
|
color = color.srgb_to_linear();
|
||||||
|
|
||||||
scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
|
scene_state.data.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
|
||||||
scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
|
scene_state.data.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
|
||||||
scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
|
scene_state.data.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
|
||||||
scene_state.ubo.use_ambient_light = true;
|
scene_state.data.use_ambient_light = true;
|
||||||
scene_state.ubo.use_ambient_cubemap = false;
|
scene_state.data.use_ambient_cubemap = false;
|
||||||
} else {
|
} else {
|
||||||
float energy = environment_get_ambient_light_energy(p_render_data->environment);
|
float energy = environment_get_ambient_light_energy(p_render_data->environment);
|
||||||
Color color = environment_get_ambient_light(p_render_data->environment);
|
Color color = environment_get_ambient_light(p_render_data->environment);
|
||||||
color = color.srgb_to_linear();
|
color = color.srgb_to_linear();
|
||||||
scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
|
scene_state.data.ambient_light_color_energy[0] = color.r * energy;
|
||||||
scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
|
scene_state.data.ambient_light_color_energy[1] = color.g * energy;
|
||||||
scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
|
scene_state.data.ambient_light_color_energy[2] = color.b * energy;
|
||||||
|
|
||||||
Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
|
Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
|
||||||
sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
|
sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
|
||||||
GLES3::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
|
GLES3::MaterialStorage::store_transform_3x3(sky_transform, scene_state.data.radiance_inverse_xform);
|
||||||
scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
|
scene_state.data.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
|
||||||
scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
|
scene_state.data.use_ambient_light = scene_state.data.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
//specular
|
//specular
|
||||||
RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment);
|
RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment);
|
||||||
if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
|
if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
|
||||||
scene_state.ubo.use_reflection_cubemap = true;
|
scene_state.data.use_reflection_cubemap = true;
|
||||||
} else {
|
} else {
|
||||||
scene_state.ubo.use_reflection_cubemap = false;
|
scene_state.data.use_reflection_cubemap = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment);
|
scene_state.data.fog_enabled = environment_get_fog_enabled(p_render_data->environment);
|
||||||
scene_state.ubo.fog_mode = environment_get_fog_mode(p_render_data->environment);
|
scene_state.data.fog_mode = environment_get_fog_mode(p_render_data->environment);
|
||||||
scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
|
scene_state.data.fog_density = environment_get_fog_density(p_render_data->environment);
|
||||||
scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
|
scene_state.data.fog_height = environment_get_fog_height(p_render_data->environment);
|
||||||
scene_state.ubo.fog_depth_curve = environment_get_fog_depth_curve(p_render_data->environment);
|
scene_state.data.fog_depth_curve = environment_get_fog_depth_curve(p_render_data->environment);
|
||||||
scene_state.ubo.fog_depth_end = environment_get_fog_depth_end(p_render_data->environment) > 0.0 ? environment_get_fog_depth_end(p_render_data->environment) : scene_state.ubo.z_far;
|
scene_state.data.fog_depth_end = environment_get_fog_depth_end(p_render_data->environment) > 0.0 ? environment_get_fog_depth_end(p_render_data->environment) : scene_state.data.z_far;
|
||||||
scene_state.ubo.fog_depth_begin = MIN(environment_get_fog_depth_begin(p_render_data->environment), scene_state.ubo.fog_depth_end - 0.001);
|
scene_state.data.fog_depth_begin = MIN(environment_get_fog_depth_begin(p_render_data->environment), scene_state.data.fog_depth_end - 0.001);
|
||||||
scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
|
scene_state.data.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
|
||||||
scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
|
scene_state.data.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
|
||||||
|
|
||||||
Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
|
Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
|
||||||
float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
|
float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
|
||||||
|
|
||||||
scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
|
scene_state.data.fog_light_color[0] = fog_color.r * fog_energy;
|
||||||
scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
|
scene_state.data.fog_light_color[1] = fog_color.g * fog_energy;
|
||||||
scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
|
scene_state.data.fog_light_color[2] = fog_color.b * fog_energy;
|
||||||
|
|
||||||
scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
|
scene_state.data.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_render_data->camera_attributes.is_valid()) {
|
if (p_render_data->camera_attributes.is_valid()) {
|
||||||
scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
|
scene_state.data.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
|
||||||
scene_state.ubo.IBL_exposure_normalization = 1.0;
|
scene_state.data.IBL_exposure_normalization = 1.0;
|
||||||
if (is_environment(p_render_data->environment)) {
|
if (is_environment(p_render_data->environment)) {
|
||||||
RID sky_rid = environment_get_sky(p_render_data->environment);
|
RID sky_rid = environment_get_sky(p_render_data->environment);
|
||||||
if (sky_rid.is_valid()) {
|
if (sky_rid.is_valid()) {
|
||||||
float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment);
|
float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment);
|
||||||
scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky_get_baked_exposure(sky_rid));
|
scene_state.data.IBL_exposure_normalization = current_exposure / MAX(0.001, sky_get_baked_exposure(sky_rid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
|
} else if (scene_state.data.emissive_exposure_normalization > 0.0) {
|
||||||
// This branch is triggered when using render_material().
|
// This branch is triggered when using render_material().
|
||||||
// Emissive is set outside the function, so don't set it.
|
// Emissive is set outside the function, so don't set it.
|
||||||
// IBL isn't used don't set it.
|
// IBL isn't used don't set it.
|
||||||
} else {
|
} else {
|
||||||
scene_state.ubo.emissive_exposure_normalization = 1.0;
|
scene_state.data.emissive_exposure_normalization = 1.0;
|
||||||
scene_state.ubo.IBL_exposure_normalization = 1.0;
|
scene_state.data.IBL_exposure_normalization = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scene_state.ubo_buffer == 0) {
|
if (scene_state.ubo_buffer == 0) {
|
||||||
glGenBuffers(1, &scene_state.ubo_buffer);
|
glGenBuffers(1, &scene_state.ubo_buffer);
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
|
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
|
||||||
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.ubo_buffer, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW, "Scene state UBO");
|
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.ubo_buffer, sizeof(SceneState::UBO) * 2, &scene_state.data, GL_STREAM_DRAW, "Scene state UBO");
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
} else {
|
} else {
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
|
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO) * 2, &scene_state.data, GL_STREAM_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
@ -1625,10 +1625,10 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
|
||||||
if (scene_state.multiview_buffer == 0) {
|
if (scene_state.multiview_buffer == 0) {
|
||||||
glGenBuffers(1, &scene_state.multiview_buffer);
|
glGenBuffers(1, &scene_state.multiview_buffer);
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
|
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
|
||||||
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.multiview_buffer, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW, "Multiview UBO");
|
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_UNIFORM_BUFFER, scene_state.multiview_buffer, sizeof(SceneState::MultiviewUBO) * 2, &scene_state.multiview_data, GL_STREAM_DRAW, "Multiview UBO");
|
||||||
} else {
|
} else {
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
|
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO) * 2, &scene_state.multiview_data, GL_STREAM_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
@ -2382,7 +2382,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
||||||
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
|
||||||
scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
|
scene_state.data.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
|
||||||
|
|
||||||
bool flip_y = !is_reflection_probe;
|
bool flip_y = !is_reflection_probe;
|
||||||
|
|
||||||
|
@ -2493,6 +2493,46 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scene_state.reset_gl_state();
|
||||||
|
|
||||||
|
GLuint motion_vectors_fbo = rt->overridden.velocity_fbo;
|
||||||
|
if (motion_vectors_fbo != 0 && GLES3::Config::get_singleton()->max_vertex_attribs >= 22) {
|
||||||
|
RENDER_TIMESTAMP("Motion Vectors Pass");
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, motion_vectors_fbo);
|
||||||
|
|
||||||
|
Size2i motion_vectors_target_size = rt->velocity_target_size;
|
||||||
|
glViewport(0, 0, motion_vectors_target_size.x, motion_vectors_target_size.y);
|
||||||
|
|
||||||
|
if (!scene_state.is_prev_data_stored) {
|
||||||
|
scene_state.prev_data = scene_state.data;
|
||||||
|
scene_state.prev_multiview_data = scene_state.multiview_data;
|
||||||
|
scene_state.is_prev_data_stored = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_state.enable_gl_depth_test(true);
|
||||||
|
scene_state.enable_gl_depth_draw(true);
|
||||||
|
scene_state.enable_gl_blend(false);
|
||||||
|
glDepthFunc(GL_GEQUAL);
|
||||||
|
scene_state.enable_gl_scissor_test(false);
|
||||||
|
|
||||||
|
glColorMask(1, 1, 1, 1);
|
||||||
|
RasterizerGLES3::clear_depth(0.0);
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
GLuint db = GL_COLOR_ATTACHMENT0;
|
||||||
|
glDrawBuffers(1, &db);
|
||||||
|
|
||||||
|
uint64_t spec_constant = SceneShaderGLES3::DISABLE_FOG | SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL |
|
||||||
|
SceneShaderGLES3::DISABLE_LIGHTMAP | SceneShaderGLES3::DISABLE_LIGHT_OMNI |
|
||||||
|
SceneShaderGLES3::DISABLE_LIGHT_SPOT;
|
||||||
|
|
||||||
|
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant, use_wireframe);
|
||||||
|
_render_list_template<PASS_MODE_MOTION_VECTORS>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
|
||||||
|
|
||||||
|
scene_state.prev_data = scene_state.data;
|
||||||
|
scene_state.prev_multiview_data = scene_state.multiview_data;
|
||||||
|
}
|
||||||
|
|
||||||
GLuint fbo = 0;
|
GLuint fbo = 0;
|
||||||
if (is_reflection_probe && GLES3::LightStorage::get_singleton()->reflection_probe_has_atlas_index(render_data.reflection_probe)) {
|
if (is_reflection_probe && GLES3::LightStorage::get_singleton()->reflection_probe_has_atlas_index(render_data.reflection_probe)) {
|
||||||
fbo = GLES3::LightStorage::get_singleton()->reflection_probe_instance_get_framebuffer(render_data.reflection_probe, render_data.reflection_probe_pass);
|
fbo = GLES3::LightStorage::get_singleton()->reflection_probe_instance_get_framebuffer(render_data.reflection_probe, render_data.reflection_probe_pass);
|
||||||
|
@ -2504,8 +2544,6 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
glViewport(0, 0, rb->internal_size.x, rb->internal_size.y);
|
glViewport(0, 0, rb->internal_size.x, rb->internal_size.y);
|
||||||
|
|
||||||
scene_state.reset_gl_state();
|
|
||||||
|
|
||||||
// Do depth prepass if it's explicitly enabled
|
// Do depth prepass if it's explicitly enabled
|
||||||
bool use_depth_prepass = config->use_depth_prepass;
|
bool use_depth_prepass = config->use_depth_prepass;
|
||||||
|
|
||||||
|
@ -2990,6 +3028,8 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
|
|
||||||
} else if constexpr (p_pass_mode == PASS_MODE_DEPTH || p_pass_mode == PASS_MODE_SHADOW) {
|
} else if constexpr (p_pass_mode == PASS_MODE_DEPTH || p_pass_mode == PASS_MODE_SHADOW) {
|
||||||
shader_variant = SceneShaderGLES3::MODE_DEPTH;
|
shader_variant = SceneShaderGLES3::MODE_DEPTH;
|
||||||
|
} else if constexpr (p_pass_mode == PASS_MODE_MOTION_VECTORS) {
|
||||||
|
base_spec_constants |= SceneShaderGLES3::RENDER_MOTION_VECTORS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_render_data->view_count > 1) {
|
if (p_render_data->view_count > 1) {
|
||||||
|
@ -2997,8 +3037,8 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool should_request_redraw = false;
|
bool should_request_redraw = false;
|
||||||
if constexpr (p_pass_mode != PASS_MODE_DEPTH) {
|
if constexpr (p_pass_mode != PASS_MODE_DEPTH && p_pass_mode != PASS_MODE_MOTION_VECTORS) {
|
||||||
// Don't count elements during depth pre-pass to match the RD renderers.
|
// Don't count elements during depth pre-pass or motion vector pass to match the RD renderers.
|
||||||
if (p_render_data->render_info) {
|
if (p_render_data->render_info) {
|
||||||
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] += p_to_element - p_from_element;
|
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] += p_to_element - p_from_element;
|
||||||
}
|
}
|
||||||
|
@ -3059,7 +3099,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
|
|
||||||
if constexpr (p_pass_mode != PASS_MODE_SHADOW) {
|
if constexpr (p_pass_mode != PASS_MODE_SHADOW) {
|
||||||
if (shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE) {
|
if (shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE) {
|
||||||
scene_state.enable_gl_depth_draw((p_pass_mode == PASS_MODE_COLOR && !GLES3::Config::get_singleton()->use_depth_prepass) || p_pass_mode == PASS_MODE_DEPTH);
|
scene_state.enable_gl_depth_draw((p_pass_mode == PASS_MODE_COLOR && !GLES3::Config::get_singleton()->use_depth_prepass) || p_pass_mode == PASS_MODE_DEPTH || p_pass_mode == PASS_MODE_MOTION_VECTORS);
|
||||||
} else {
|
} else {
|
||||||
scene_state.enable_gl_depth_draw(shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS);
|
scene_state.enable_gl_depth_draw(shader->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS);
|
||||||
}
|
}
|
||||||
|
@ -3075,9 +3115,9 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (int32_t pass = 0; pass < MAX(1, int32_t(inst->light_passes.size() + p_render_data->directional_shadow_count)); pass++) {
|
for (int32_t pass = 0; pass < MAX(1, int32_t(inst->light_passes.size() + p_render_data->directional_shadow_count)); pass++) {
|
||||||
if constexpr (p_pass_mode == PASS_MODE_DEPTH || p_pass_mode == PASS_MODE_SHADOW) {
|
if constexpr (p_pass_mode == PASS_MODE_DEPTH || p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_MOTION_VECTORS) {
|
||||||
if (pass > 0) {
|
if (pass > 0) {
|
||||||
// Don't render shadow passes when doing depth or shadow pass.
|
// Don't render shadow passes when doing depth, shadow, or motion vector pass.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3232,9 +3272,9 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
|
|
||||||
// Skeleton and blend shapes.
|
// Skeleton and blend shapes.
|
||||||
if (surf->owner->mesh_instance.is_valid()) {
|
if (surf->owner->mesh_instance.is_valid()) {
|
||||||
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, vertex_input_mask, vertex_array_gl);
|
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, vertex_input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, vertex_array_gl);
|
||||||
} else {
|
} else {
|
||||||
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, vertex_input_mask, vertex_array_gl);
|
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, vertex_input_mask, p_pass_mode == PASS_MODE_MOTION_VECTORS, vertex_array_gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
index_array_gl = mesh_storage->mesh_surface_get_index_buffer(mesh_surface, surf->lod_index);
|
index_array_gl = mesh_storage->mesh_surface_get_index_buffer(mesh_surface, surf->lod_index);
|
||||||
|
@ -3420,7 +3460,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
}
|
}
|
||||||
|
|
||||||
float opaque_prepass_threshold = 0.0;
|
float opaque_prepass_threshold = 0.0;
|
||||||
if constexpr (p_pass_mode == PASS_MODE_DEPTH) {
|
if constexpr (p_pass_mode == PASS_MODE_DEPTH || p_pass_mode == PASS_MODE_MOTION_VECTORS) {
|
||||||
opaque_prepass_threshold = 0.99;
|
opaque_prepass_threshold = 0.99;
|
||||||
} else if constexpr (p_pass_mode == PASS_MODE_SHADOW) {
|
} else if constexpr (p_pass_mode == PASS_MODE_SHADOW) {
|
||||||
opaque_prepass_threshold = 0.1;
|
opaque_prepass_threshold = 0.1;
|
||||||
|
@ -3605,6 +3645,16 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (p_pass_mode == PASS_MODE_MOTION_VECTORS) {
|
||||||
|
if (unlikely(!inst->is_prev_transform_stored)) {
|
||||||
|
inst->prev_transform = world_transform;
|
||||||
|
inst->is_prev_transform_stored = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::PREV_WORLD_TRANSFORM, inst->prev_transform, shader->version, instance_variant, spec_constants);
|
||||||
|
inst->prev_transform = world_transform;
|
||||||
|
}
|
||||||
|
|
||||||
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, spec_constants);
|
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, spec_constants);
|
||||||
{
|
{
|
||||||
GLES3::Mesh::Surface *s = reinterpret_cast<GLES3::Mesh::Surface *>(surf->surface);
|
GLES3::Mesh::Surface *s = reinterpret_cast<GLES3::Mesh::Surface *>(surf->surface);
|
||||||
|
@ -3639,8 +3689,8 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
count = count * 2;
|
count = count * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (p_pass_mode != PASS_MODE_DEPTH) {
|
if constexpr (p_pass_mode != PASS_MODE_DEPTH && p_pass_mode != PASS_MODE_MOTION_VECTORS) {
|
||||||
// Don't count draw calls during depth pre-pass to match the RD renderers.
|
// Don't count draw calls during depth pre-pass or motion vector pass to match the RD renderers.
|
||||||
if (p_render_data->render_info) {
|
if (p_render_data->render_info) {
|
||||||
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]++;
|
p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]++;
|
||||||
}
|
}
|
||||||
|
@ -3665,32 +3715,40 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, instance_buffer);
|
bool uses_format_2d = inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
|
||||||
|
bool has_color_or_custom_data = (inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR) || (inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA);
|
||||||
|
// Current data multimesh vertex attrib data begins at index 12.
|
||||||
|
mesh_storage->multimesh_vertex_attrib_setup(instance_buffer, stride, uses_format_2d, has_color_or_custom_data, 12);
|
||||||
|
|
||||||
glEnableVertexAttribArray(12);
|
if (p_pass_mode == PASS_MODE_MOTION_VECTORS) {
|
||||||
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
|
GLuint prev_instance_buffer = 0;
|
||||||
glVertexAttribDivisor(12, 1);
|
if (inst->flags_cache & INSTANCE_DATA_FLAG_PARTICLES) {
|
||||||
glEnableVertexAttribArray(13);
|
prev_instance_buffer = particles_storage->particles_get_prev_gl_buffer(inst->data->base);
|
||||||
glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4));
|
} else {
|
||||||
glVertexAttribDivisor(13, 1);
|
prev_instance_buffer = mesh_storage->multimesh_get_prev_gl_buffer(inst->data->base);
|
||||||
if (!(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D)) {
|
}
|
||||||
glEnableVertexAttribArray(14);
|
|
||||||
glVertexAttribPointer(14, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 8));
|
|
||||||
glVertexAttribDivisor(14, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR) || (inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA)) {
|
if (prev_instance_buffer == 0) {
|
||||||
uint32_t color_custom_offset = inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D ? 8 : 12;
|
break;
|
||||||
glEnableVertexAttribArray(15);
|
}
|
||||||
glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_custom_offset * sizeof(float)));
|
|
||||||
glVertexAttribDivisor(15, 1);
|
GLuint secondary_instance_buffer = 0;
|
||||||
} else {
|
if (inst->flags_cache & INSTANCE_DATA_FLAG_PARTICLES) {
|
||||||
// Set all default instance color and custom data values to 1.0 or 0.0 using a compressed format.
|
if (particles_storage->particles_get_last_change(inst->data->base) == RSG::rasterizer->get_frame_number()) {
|
||||||
uint16_t zero = Math::make_half_float(0.0f);
|
secondary_instance_buffer = prev_instance_buffer;
|
||||||
uint16_t one = Math::make_half_float(1.0f);
|
} else {
|
||||||
GLuint default_color = (uint32_t(one) << 16) | one;
|
secondary_instance_buffer = instance_buffer;
|
||||||
GLuint default_custom = (uint32_t(zero) << 16) | zero;
|
}
|
||||||
glVertexAttribI4ui(15, default_color, default_color, default_custom, default_custom);
|
} else {
|
||||||
|
if (mesh_storage->multimesh_get_last_change(inst->data->base) == RSG::rasterizer->get_frame_number()) {
|
||||||
|
secondary_instance_buffer = prev_instance_buffer;
|
||||||
|
} else {
|
||||||
|
secondary_instance_buffer = instance_buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous data multimesh vertex attrib data begins at index 18.
|
||||||
|
mesh_storage->multimesh_vertex_attrib_setup(secondary_instance_buffer, stride, uses_format_2d, has_color_or_custom_data, 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_wireframe) {
|
if (use_wireframe) {
|
||||||
|
@ -3814,7 +3872,7 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance *
|
||||||
RenderDataGLES3 render_data;
|
RenderDataGLES3 render_data;
|
||||||
render_data.instances = &p_instances;
|
render_data.instances = &p_instances;
|
||||||
|
|
||||||
scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
|
scene_state.data.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
|
||||||
|
|
||||||
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false);
|
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ enum PassMode {
|
||||||
PASS_MODE_SHADOW,
|
PASS_MODE_SHADOW,
|
||||||
PASS_MODE_DEPTH,
|
PASS_MODE_DEPTH,
|
||||||
PASS_MODE_MATERIAL,
|
PASS_MODE_MATERIAL,
|
||||||
|
PASS_MODE_MOTION_VECTORS,
|
||||||
};
|
};
|
||||||
|
|
||||||
// These should share as much as possible with SkyUniform Location
|
// These should share as much as possible with SkyUniform Location
|
||||||
|
@ -301,6 +302,10 @@ private:
|
||||||
//used during rendering
|
//used during rendering
|
||||||
bool store_transform_cache = true;
|
bool store_transform_cache = true;
|
||||||
|
|
||||||
|
// Used for generating motion vectors.
|
||||||
|
Transform3D prev_transform;
|
||||||
|
bool is_prev_transform_stored = false;
|
||||||
|
|
||||||
int32_t instance_count = 0;
|
int32_t instance_count = 0;
|
||||||
|
|
||||||
bool can_sdfgi = false;
|
bool can_sdfgi = false;
|
||||||
|
@ -454,12 +459,16 @@ private:
|
||||||
};
|
};
|
||||||
static_assert(sizeof(TonemapUBO) % 16 == 0, "Tonemap UBO size must be a multiple of 16 bytes");
|
static_assert(sizeof(TonemapUBO) % 16 == 0, "Tonemap UBO size must be a multiple of 16 bytes");
|
||||||
|
|
||||||
UBO ubo;
|
UBO data;
|
||||||
|
UBO prev_data;
|
||||||
GLuint ubo_buffer = 0;
|
GLuint ubo_buffer = 0;
|
||||||
MultiviewUBO multiview_ubo;
|
MultiviewUBO multiview_data;
|
||||||
|
MultiviewUBO prev_multiview_data;
|
||||||
GLuint multiview_buffer = 0;
|
GLuint multiview_buffer = 0;
|
||||||
GLuint tonemap_buffer = 0;
|
GLuint tonemap_buffer = 0;
|
||||||
|
|
||||||
|
bool is_prev_data_stored = false;
|
||||||
|
|
||||||
bool used_depth_prepass = false;
|
bool used_depth_prepass = false;
|
||||||
|
|
||||||
GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
|
GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
|
||||||
|
|
|
@ -37,6 +37,7 @@ ADDITIVE_SPOT = false
|
||||||
RENDER_MATERIAL = false
|
RENDER_MATERIAL = false
|
||||||
SECOND_REFLECTION_PROBE = false
|
SECOND_REFLECTION_PROBE = false
|
||||||
LIGHTMAP_BICUBIC_FILTER = false
|
LIGHTMAP_BICUBIC_FILTER = false
|
||||||
|
RENDER_MOTION_VECTORS = false
|
||||||
|
|
||||||
|
|
||||||
#[vertex]
|
#[vertex]
|
||||||
|
@ -155,13 +156,24 @@ layout(location = 14) in highp vec4 instance_xform2;
|
||||||
layout(location = 15) in highp uvec4 instance_color_custom_data; // Color packed into xy, Custom data into zw.
|
layout(location = 15) in highp uvec4 instance_color_custom_data; // Color packed into xy, Custom data into zw.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(RENDER_MOTION_VECTORS)
|
||||||
|
layout(location = 16) in highp vec4 prev_vertex_attrib;
|
||||||
|
layout(location = 17) in highp vec4 prev_normal_attrib;
|
||||||
|
#ifdef USE_INSTANCING
|
||||||
|
layout(location = 18) in highp vec4 prev_instance_xform0;
|
||||||
|
layout(location = 19) in highp vec4 prev_instance_xform1;
|
||||||
|
layout(location = 20) in highp vec4 prev_instance_xform2;
|
||||||
|
layout(location = 21) in highp uvec4 prev_instance_color_custom_data;
|
||||||
|
#endif // USE_INSTANCING
|
||||||
|
#endif // RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
#define FLAGS_NON_UNIFORM_SCALE (1 << 4)
|
#define FLAGS_NON_UNIFORM_SCALE (1 << 4)
|
||||||
|
|
||||||
layout(std140) uniform GlobalShaderUniformData { //ubo:1
|
layout(std140) uniform GlobalShaderUniformData { //ubo:1
|
||||||
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
|
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std140) uniform SceneData { // ubo:2
|
struct SceneData {
|
||||||
highp mat4 projection_matrix;
|
highp mat4 projection_matrix;
|
||||||
highp mat4 inv_projection_matrix;
|
highp mat4 inv_projection_matrix;
|
||||||
highp mat4 inv_view_matrix;
|
highp mat4 inv_view_matrix;
|
||||||
|
@ -209,9 +221,15 @@ layout(std140) uniform SceneData { // ubo:2
|
||||||
float luminance_multiplier;
|
float luminance_multiplier;
|
||||||
uint camera_visible_layers;
|
uint camera_visible_layers;
|
||||||
bool pancake_shadows;
|
bool pancake_shadows;
|
||||||
}
|
};
|
||||||
scene_data;
|
|
||||||
|
|
||||||
|
layout(std140) uniform SceneDataBlock { // ubo:2
|
||||||
|
SceneData data;
|
||||||
|
SceneData prev_data;
|
||||||
|
}
|
||||||
|
scene_data_block;
|
||||||
|
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
#ifdef USE_ADDITIVE_LIGHTING
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
|
|
||||||
#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
||||||
|
@ -426,14 +444,20 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, float
|
||||||
#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
|
#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) && defined(USE_VERTEX_LIGHTING)
|
||||||
|
|
||||||
#endif // USE_VERTEX_LIGHTING
|
#endif // USE_VERTEX_LIGHTING
|
||||||
|
#endif // RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
layout(std140) uniform MultiviewData { // ubo:8
|
struct MultiviewData {
|
||||||
highp mat4 projection_matrix_view[MAX_VIEWS];
|
highp mat4 projection_matrix_view[MAX_VIEWS];
|
||||||
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
|
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
|
||||||
highp vec4 eye_offset[MAX_VIEWS];
|
highp vec4 eye_offset[MAX_VIEWS];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140) uniform MultiviewDataBlock { // ubo:8
|
||||||
|
MultiviewData data;
|
||||||
|
MultiviewData prev_data;
|
||||||
}
|
}
|
||||||
multiview_data;
|
multiview_data_block;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform highp mat4 world_transform;
|
uniform highp mat4 world_transform;
|
||||||
|
@ -442,6 +466,10 @@ uniform highp vec3 compressed_aabb_size;
|
||||||
uniform highp vec4 uv_scale;
|
uniform highp vec4 uv_scale;
|
||||||
uniform highp uint instance_offset;
|
uniform highp uint instance_offset;
|
||||||
|
|
||||||
|
#if defined(RENDER_MOTION_VECTORS)
|
||||||
|
uniform highp mat4 prev_world_transform;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform highp uint model_flags;
|
uniform highp uint model_flags;
|
||||||
|
|
||||||
#ifdef RENDER_MATERIAL
|
#ifdef RENDER_MATERIAL
|
||||||
|
@ -472,6 +500,7 @@ out vec3 tangent_interp;
|
||||||
out vec3 binormal_interp;
|
out vec3 binormal_interp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
#ifdef USE_ADDITIVE_LIGHTING
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
out highp vec4 shadow_coord;
|
out highp vec4 shadow_coord;
|
||||||
|
|
||||||
|
@ -482,8 +511,9 @@ out highp vec4 shadow_coord2;
|
||||||
#ifdef LIGHT_USE_PSSM4
|
#ifdef LIGHT_USE_PSSM4
|
||||||
out highp vec4 shadow_coord3;
|
out highp vec4 shadow_coord3;
|
||||||
out highp vec4 shadow_coord4;
|
out highp vec4 shadow_coord4;
|
||||||
#endif //LIGHT_USE_PSSM4
|
#endif // LIGHT_USE_PSSM4
|
||||||
#endif
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
|
#endif // RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
#ifdef MATERIAL_UNIFORMS_USED
|
#ifdef MATERIAL_UNIFORMS_USED
|
||||||
|
|
||||||
|
@ -499,27 +529,60 @@ layout(std140) uniform MaterialUniforms { // ubo:3
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
|
#if defined(RENDER_MOTION_VECTORS)
|
||||||
|
out highp vec4 clip_position;
|
||||||
|
out highp vec4 prev_clip_position;
|
||||||
|
#endif
|
||||||
|
|
||||||
#GLOBALS
|
#GLOBALS
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
invariant gl_Position;
|
invariant gl_Position;
|
||||||
|
|
||||||
void main() {
|
void vertex_shader(vec4 vertex_angle_attrib_input,
|
||||||
highp vec3 vertex = vertex_angle_attrib.xyz * compressed_aabb_size + compressed_aabb_position;
|
vec3 compressed_aabb_size_input,
|
||||||
|
vec3 compressed_aabb_position_input,
|
||||||
highp mat4 model_matrix = world_transform;
|
mat4 world_transform_input,
|
||||||
|
uint model_flags_input,
|
||||||
|
SceneData scene_data_input,
|
||||||
#ifdef USE_INSTANCING
|
#ifdef USE_INSTANCING
|
||||||
highp mat4 m = mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0));
|
vec4 instance_xform0_input, vec4 instance_xform1_input, vec4 instance_xform2_input,
|
||||||
|
uvec4 instance_color_custom_data_input,
|
||||||
|
#endif
|
||||||
|
#ifdef NORMAL_USED
|
||||||
|
vec4 axis_tangent_attrib_input,
|
||||||
|
#endif
|
||||||
|
#if defined(COLOR_USED)
|
||||||
|
vec4 color_attrib_input,
|
||||||
|
#endif
|
||||||
|
#if defined(UV_USED)
|
||||||
|
vec2 uv_attrib_input,
|
||||||
|
#endif
|
||||||
|
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
|
||||||
|
vec2 uv2_attrib_input,
|
||||||
|
#endif
|
||||||
|
#ifdef USE_MULTIVIEW
|
||||||
|
mat4 projection_matrix,
|
||||||
|
mat4 inv_projection_matrix,
|
||||||
|
vec3 eye_offset,
|
||||||
|
#endif
|
||||||
|
vec4 uv_scale_input,
|
||||||
|
out vec4 clip_position_output) {
|
||||||
|
highp vec3 vertex = vertex_angle_attrib_input.xyz * compressed_aabb_size_input + compressed_aabb_position_input;
|
||||||
|
|
||||||
|
highp mat4 model_matrix = world_transform_input;
|
||||||
|
#ifdef USE_INSTANCING
|
||||||
|
highp mat4 m = mat4(instance_xform0_input, instance_xform1_input, instance_xform2_input, vec4(0.0, 0.0, 0.0, 1.0));
|
||||||
model_matrix = model_matrix * transpose(m);
|
model_matrix = model_matrix * transpose(m);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NORMAL_USED
|
#ifdef NORMAL_USED
|
||||||
vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0);
|
vec3 normal = oct_to_vec3(axis_tangent_attrib_input.xy * 2.0 - 1.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
highp mat3 model_normal_matrix;
|
highp mat3 model_normal_matrix;
|
||||||
|
|
||||||
if (bool(model_flags & uint(FLAGS_NON_UNIFORM_SCALE))) {
|
if (bool(model_flags_input & uint(FLAGS_NON_UNIFORM_SCALE))) {
|
||||||
model_normal_matrix = transpose(inverse(mat3(model_matrix)));
|
model_normal_matrix = transpose(inverse(mat3(model_matrix)));
|
||||||
} else {
|
} else {
|
||||||
model_normal_matrix = mat3(model_matrix);
|
model_normal_matrix = mat3(model_matrix);
|
||||||
|
@ -538,7 +601,7 @@ void main() {
|
||||||
binormal = normalize(cross(normal, tangent) * binormal_sign);
|
binormal = normalize(cross(normal, tangent) * binormal_sign);
|
||||||
} else {
|
} else {
|
||||||
// Compressed format.
|
// Compressed format.
|
||||||
float angle = vertex_angle_attrib.w;
|
float angle = vertex_angle_attrib_input.w;
|
||||||
binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller.
|
binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller.
|
||||||
angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably.
|
angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably.
|
||||||
vec3 axis = normal;
|
vec3 axis = normal;
|
||||||
|
@ -548,29 +611,29 @@ void main() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(COLOR_USED)
|
#if defined(COLOR_USED)
|
||||||
color_interp = color_attrib;
|
color_interp = color_attrib_input;
|
||||||
#ifdef USE_INSTANCING
|
#ifdef USE_INSTANCING
|
||||||
vec4 instance_color;
|
vec4 instance_color;
|
||||||
instance_color.xy = unpackHalf2x16(instance_color_custom_data.x);
|
instance_color.xy = unpackHalf2x16(instance_color_custom_data_input.x);
|
||||||
instance_color.zw = unpackHalf2x16(instance_color_custom_data.y);
|
instance_color.zw = unpackHalf2x16(instance_color_custom_data_input.y);
|
||||||
color_interp *= instance_color;
|
color_interp *= instance_color;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(UV_USED)
|
#if defined(UV_USED)
|
||||||
uv_interp = uv_attrib;
|
uv_interp = uv_attrib_input;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
|
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
|
||||||
uv2_interp = uv2_attrib;
|
uv2_interp = uv2_attrib_input;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (uv_scale != vec4(0.0)) { // Compression enabled
|
if (uv_scale_input != vec4(0.0)) { // Compression enabled
|
||||||
#ifdef UV_USED
|
#ifdef UV_USED
|
||||||
uv_interp = (uv_interp - 0.5) * uv_scale.xy;
|
uv_interp = (uv_interp - 0.5) * uv_scale_input.xy;
|
||||||
#endif
|
#endif
|
||||||
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
|
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
|
||||||
uv2_interp = (uv2_interp - 0.5) * uv_scale.zw;
|
uv2_interp = (uv2_interp - 0.5) * uv_scale_input.zw;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,20 +641,15 @@ void main() {
|
||||||
highp vec4 position;
|
highp vec4 position;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifndef USE_MULTIVIEW
|
||||||
mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
|
mat4 projection_matrix = scene_data_input.projection_matrix;
|
||||||
mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
|
mat4 inv_projection_matrix = scene_data_input.inv_projection_matrix;
|
||||||
vec3 eye_offset = multiview_data.eye_offset[ViewIndex].xyz;
|
#endif //!USE_MULTIVIEW
|
||||||
#else
|
|
||||||
mat4 projection_matrix = scene_data.projection_matrix;
|
|
||||||
mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
|
|
||||||
vec3 eye_offset = vec3(0.0, 0.0, 0.0);
|
|
||||||
#endif //USE_MULTIVIEW
|
|
||||||
|
|
||||||
#ifdef USE_INSTANCING
|
#ifdef USE_INSTANCING
|
||||||
vec4 instance_custom;
|
vec4 instance_custom;
|
||||||
instance_custom.xy = unpackHalf2x16(instance_color_custom_data.z);
|
instance_custom.xy = unpackHalf2x16(instance_color_custom_data_input.z);
|
||||||
instance_custom.zw = unpackHalf2x16(instance_color_custom_data.w);
|
instance_custom.zw = unpackHalf2x16(instance_color_custom_data_input.w);
|
||||||
#else
|
#else
|
||||||
vec4 instance_custom = vec4(0.0);
|
vec4 instance_custom = vec4(0.0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -619,8 +677,8 @@ void main() {
|
||||||
|
|
||||||
float roughness = 1.0;
|
float roughness = 1.0;
|
||||||
|
|
||||||
highp mat4 modelview = scene_data.view_matrix * model_matrix;
|
highp mat4 modelview = scene_data_input.view_matrix * model_matrix;
|
||||||
highp mat3 modelview_normal = mat3(scene_data.view_matrix) * model_normal_matrix;
|
highp mat3 modelview_normal = mat3(scene_data_input.view_matrix) * model_normal_matrix;
|
||||||
|
|
||||||
float point_size = 1.0;
|
float point_size = 1.0;
|
||||||
|
|
||||||
|
@ -648,14 +706,14 @@ void main() {
|
||||||
// Using world coordinates
|
// Using world coordinates
|
||||||
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
|
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
|
||||||
|
|
||||||
vertex = (scene_data.view_matrix * vec4(vertex, 1.0)).xyz;
|
vertex = (scene_data_input.view_matrix * vec4(vertex, 1.0)).xyz;
|
||||||
#ifdef NORMAL_USED
|
#ifdef NORMAL_USED
|
||||||
normal = (scene_data.view_matrix * vec4(normal, 0.0)).xyz;
|
normal = (scene_data_input.view_matrix * vec4(normal, 0.0)).xyz;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
|
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
|
||||||
binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz;
|
binormal = (scene_data_input.view_matrix * vec4(binormal, 0.0)).xyz;
|
||||||
tangent = (scene_data.view_matrix * vec4(tangent, 0.0)).xyz;
|
tangent = (scene_data_input.view_matrix * vec4(tangent, 0.0)).xyz;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -672,6 +730,7 @@ void main() {
|
||||||
binormal_interp = normalize(binormal);
|
binormal_interp = normalize(binormal);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
// Calculate shadows.
|
// Calculate shadows.
|
||||||
#ifdef USE_ADDITIVE_LIGHTING
|
#ifdef USE_ADDITIVE_LIGHTING
|
||||||
#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
#if defined(ADDITIVE_OMNI) || defined(ADDITIVE_SPOT)
|
||||||
|
@ -711,15 +770,16 @@ void main() {
|
||||||
#endif // USE_ADDITIVE_LIGHTING
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
|
|
||||||
#if defined(RENDER_SHADOWS) && !defined(RENDER_SHADOWS_LINEAR)
|
#if defined(RENDER_SHADOWS) && !defined(RENDER_SHADOWS_LINEAR)
|
||||||
// This is an optimized version of normalize(vertex_interp) * scene_data.shadow_bias / length(vertex_interp).
|
// This is an optimized version of normalize(vertex_interp) * scene_data_input.shadow_bias / length(vertex_interp).
|
||||||
float light_length_sq = dot(vertex_interp, vertex_interp);
|
float light_length_sq = dot(vertex_interp, vertex_interp);
|
||||||
vertex_interp += vertex_interp * scene_data.shadow_bias / light_length_sq;
|
vertex_interp += vertex_interp * scene_data_input.shadow_bias / light_length_sq;
|
||||||
#endif
|
#endif
|
||||||
|
#endif // RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
#if defined(OVERRIDE_POSITION)
|
#if defined(OVERRIDE_POSITION)
|
||||||
gl_Position = position;
|
clip_position_output = position;
|
||||||
#else
|
#else
|
||||||
gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
|
clip_position_output = projection_matrix * vec4(vertex_interp, 1.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(RENDER_SHADOWS) && !defined(RENDER_SHADOWS_LINEAR)
|
#if !defined(RENDER_SHADOWS) && !defined(RENDER_SHADOWS_LINEAR)
|
||||||
|
@ -730,17 +790,18 @@ void main() {
|
||||||
|
|
||||||
#ifdef RENDER_MATERIAL
|
#ifdef RENDER_MATERIAL
|
||||||
vec2 uv_dest_attrib;
|
vec2 uv_dest_attrib;
|
||||||
if (uv_scale != vec4(0.0)) {
|
if (uv_scale_input != vec4(0.0)) {
|
||||||
uv_dest_attrib = (uv2_attrib.xy - 0.5) * uv_scale.zw;
|
uv_dest_attrib = (uv2_attrib_input.xy - 0.5) * uv_scale_input.zw;
|
||||||
} else {
|
} else {
|
||||||
uv_dest_attrib = uv2_attrib.xy;
|
uv_dest_attrib = uv2_attrib_input.xy;
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_Position.xy = (uv_dest_attrib + uv_offset) * 2.0 - 1.0;
|
clip_position_output.xy = (uv_dest_attrib + uv_offset) * 2.0 - 1.0;
|
||||||
gl_Position.z = 0.00001;
|
clip_position_output.z = 0.00001;
|
||||||
gl_Position.w = 1.0;
|
clip_position_output.w = 1.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
#ifdef USE_VERTEX_LIGHTING
|
#ifdef USE_VERTEX_LIGHTING
|
||||||
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
|
@ -752,7 +813,7 @@ void main() {
|
||||||
specular_light_interp = vec3(0.0);
|
specular_light_interp = vec3(0.0);
|
||||||
#ifdef BASE_PASS
|
#ifdef BASE_PASS
|
||||||
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
||||||
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
|
for (uint i = uint(0); i < scene_data_input.directional_light_count; i++) {
|
||||||
#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
|
#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
|
||||||
if (directional_lights[i].bake_mode == LIGHT_BAKE_STATIC) {
|
if (directional_lights[i].bake_mode == LIGHT_BAKE_STATIC) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -803,7 +864,97 @@ void main() {
|
||||||
#endif // USE_ADDITIVE_LIGHTING
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
|
||||||
#endif // USE_VERTEX_LIGHTING
|
#endif // USE_VERTEX_LIGHTING
|
||||||
|
#endif // RENDER_MOTION_VECTORS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
#if defined(RENDER_MOTION_VECTORS)
|
||||||
|
|
||||||
|
#ifdef USE_INSTANCING
|
||||||
|
// Check for inactive particle instances.
|
||||||
|
highp vec4 input_instance_xform0;
|
||||||
|
highp vec4 input_instance_xform1;
|
||||||
|
highp vec4 input_instance_xform2;
|
||||||
|
highp uvec4 input_instance_color_custom_data;
|
||||||
|
if (prev_instance_xform0.xyz == vec3(0.0, 0.0, 0.0)) {
|
||||||
|
input_instance_xform0 = instance_xform0;
|
||||||
|
input_instance_xform1 = instance_xform1;
|
||||||
|
input_instance_xform2 = instance_xform2;
|
||||||
|
input_instance_color_custom_data = instance_color_custom_data;
|
||||||
|
} else {
|
||||||
|
input_instance_xform0 = prev_instance_xform0;
|
||||||
|
input_instance_xform1 = prev_instance_xform1;
|
||||||
|
input_instance_xform2 = prev_instance_xform2;
|
||||||
|
input_instance_color_custom_data = prev_instance_color_custom_data;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vertex_shader(prev_vertex_attrib,
|
||||||
|
compressed_aabb_size,
|
||||||
|
compressed_aabb_position,
|
||||||
|
prev_world_transform,
|
||||||
|
model_flags,
|
||||||
|
scene_data_block.prev_data,
|
||||||
|
#ifdef USE_INSTANCING
|
||||||
|
input_instance_xform0, input_instance_xform1, input_instance_xform2,
|
||||||
|
input_instance_color_custom_data,
|
||||||
|
#endif
|
||||||
|
#ifdef NORMAL_USED
|
||||||
|
prev_normal_attrib,
|
||||||
|
#endif
|
||||||
|
#if defined(COLOR_USED)
|
||||||
|
color_attrib,
|
||||||
|
#endif
|
||||||
|
#if defined(UV_USED)
|
||||||
|
uv_attrib,
|
||||||
|
#endif
|
||||||
|
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
|
||||||
|
uv2_attrib,
|
||||||
|
#endif
|
||||||
|
#ifdef USE_MULTIVIEW
|
||||||
|
multiview_data_block.prev_data.projection_matrix_view[ViewIndex],
|
||||||
|
multiview_data_block.prev_data.inv_projection_matrix_view[ViewIndex],
|
||||||
|
multiview_data_block.prev_data.eye_offset[ViewIndex].xyz,
|
||||||
|
#endif
|
||||||
|
uv_scale,
|
||||||
|
prev_clip_position);
|
||||||
|
#else
|
||||||
|
vec4 clip_position;
|
||||||
|
#endif // defined(RENDER_MOTION_VECTORS)
|
||||||
|
|
||||||
|
vertex_shader(vertex_angle_attrib,
|
||||||
|
compressed_aabb_size,
|
||||||
|
compressed_aabb_position,
|
||||||
|
world_transform,
|
||||||
|
model_flags,
|
||||||
|
scene_data_block.data,
|
||||||
|
#ifdef USE_INSTANCING
|
||||||
|
instance_xform0, instance_xform1, instance_xform2,
|
||||||
|
instance_color_custom_data,
|
||||||
|
#endif
|
||||||
|
#ifdef NORMAL_USED
|
||||||
|
axis_tangent_attrib,
|
||||||
|
#endif
|
||||||
|
#if defined(COLOR_USED)
|
||||||
|
color_attrib,
|
||||||
|
#endif
|
||||||
|
#if defined(UV_USED)
|
||||||
|
uv_attrib,
|
||||||
|
#endif
|
||||||
|
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
|
||||||
|
uv2_attrib,
|
||||||
|
#endif
|
||||||
|
#ifdef USE_MULTIVIEW
|
||||||
|
multiview_data_block.data.projection_matrix_view[ViewIndex],
|
||||||
|
multiview_data_block.data.inv_projection_matrix_view[ViewIndex],
|
||||||
|
multiview_data_block.data.eye_offset[ViewIndex].xyz,
|
||||||
|
#endif
|
||||||
|
uv_scale,
|
||||||
|
clip_position);
|
||||||
|
|
||||||
|
gl_Position = clip_position;
|
||||||
|
}
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
#[fragment]
|
#[fragment]
|
||||||
|
|
||||||
|
@ -859,6 +1010,12 @@ void main() {
|
||||||
|
|
||||||
/* Varyings */
|
/* Varyings */
|
||||||
|
|
||||||
|
#if defined(RENDER_MOTION_VECTORS)
|
||||||
|
in highp vec4 clip_position;
|
||||||
|
in highp vec4 prev_clip_position;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
#if defined(COLOR_USED)
|
#if defined(COLOR_USED)
|
||||||
in vec4 color_interp;
|
in vec4 color_interp;
|
||||||
#endif
|
#endif
|
||||||
|
@ -958,7 +1115,7 @@ layout(std140) uniform MaterialUniforms { // ubo:3
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
layout(std140) uniform SceneData { // ubo:2
|
struct SceneData {
|
||||||
highp mat4 projection_matrix;
|
highp mat4 projection_matrix;
|
||||||
highp mat4 inv_projection_matrix;
|
highp mat4 inv_projection_matrix;
|
||||||
highp mat4 inv_view_matrix;
|
highp mat4 inv_view_matrix;
|
||||||
|
@ -1006,16 +1163,26 @@ layout(std140) uniform SceneData { // ubo:2
|
||||||
float luminance_multiplier;
|
float luminance_multiplier;
|
||||||
uint camera_visible_layers;
|
uint camera_visible_layers;
|
||||||
bool pancake_shadows;
|
bool pancake_shadows;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140) uniform SceneDataBlock { // ubo:2
|
||||||
|
SceneData data;
|
||||||
|
SceneData prev_data;
|
||||||
}
|
}
|
||||||
scene_data;
|
scene_data_block;
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
layout(std140) uniform MultiviewData { // ubo:8
|
struct MultiviewData {
|
||||||
highp mat4 projection_matrix_view[MAX_VIEWS];
|
highp mat4 projection_matrix_view[MAX_VIEWS];
|
||||||
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
|
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
|
||||||
highp vec4 eye_offset[MAX_VIEWS];
|
highp vec4 eye_offset[MAX_VIEWS];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140) uniform MultiviewDataBlock { // ubo:8
|
||||||
|
MultiviewData data;
|
||||||
|
MultiviewData prev_data;
|
||||||
}
|
}
|
||||||
multiview_data;
|
multiview_data_block;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform highp mat4 world_transform;
|
uniform highp mat4 world_transform;
|
||||||
|
@ -1249,6 +1416,7 @@ ivec2 multiview_uv(ivec2 uv) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform mediump float opaque_prepass_threshold;
|
uniform mediump float opaque_prepass_threshold;
|
||||||
|
#endif // !RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
#if defined(RENDER_MATERIAL)
|
#if defined(RENDER_MATERIAL)
|
||||||
layout(location = 0) out vec4 albedo_output_buffer;
|
layout(location = 0) out vec4 albedo_output_buffer;
|
||||||
|
@ -1257,8 +1425,13 @@ layout(location = 2) out vec4 orm_output_buffer;
|
||||||
layout(location = 3) out vec4 emission_output_buffer;
|
layout(location = 3) out vec4 emission_output_buffer;
|
||||||
|
|
||||||
#else // !RENDER_MATERIAL
|
#else // !RENDER_MATERIAL
|
||||||
|
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
// Normal color rendering.
|
// Normal color rendering.
|
||||||
layout(location = 0) out vec4 frag_color;
|
layout(location = 0) out vec4 frag_color;
|
||||||
|
#else
|
||||||
|
layout(location = 0) out vec4 motion_vectors;
|
||||||
|
#endif // !RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
#endif // !RENDER_MATERIAL
|
#endif // !RENDER_MATERIAL
|
||||||
|
|
||||||
|
@ -1268,6 +1441,7 @@ layout(location = 0) out vec4 frag_color;
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
vec3 F0(float metallic, float specular, vec3 albedo) {
|
vec3 F0(float metallic, float specular, vec3 albedo) {
|
||||||
float dielectric = 0.16 * specular * specular;
|
float dielectric = 0.16 * specular * specular;
|
||||||
// use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
|
// use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
|
||||||
|
@ -1330,8 +1504,8 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di
|
||||||
// light is written by the light shader
|
// light is written by the light shader
|
||||||
|
|
||||||
highp mat4 model_matrix = world_transform;
|
highp mat4 model_matrix = world_transform;
|
||||||
mat4 projection_matrix = scene_data.projection_matrix;
|
mat4 projection_matrix = scene_data_block.data.projection_matrix;
|
||||||
mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
|
mat4 inv_projection_matrix = scene_data_block.data.inv_projection_matrix;
|
||||||
|
|
||||||
vec3 normal = N;
|
vec3 normal = N;
|
||||||
vec3 light = L;
|
vec3 light = L;
|
||||||
|
@ -1579,32 +1753,32 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
|
||||||
#endif // !USE_VERTEX_LIGHTING
|
#endif // !USE_VERTEX_LIGHTING
|
||||||
|
|
||||||
vec4 fog_process(vec3 vertex) {
|
vec4 fog_process(vec3 vertex) {
|
||||||
vec3 fog_color = scene_data.fog_light_color;
|
vec3 fog_color = scene_data_block.data.fog_light_color;
|
||||||
|
|
||||||
#ifdef USE_RADIANCE_MAP
|
#ifdef USE_RADIANCE_MAP
|
||||||
/*
|
/*
|
||||||
if (scene_data.fog_aerial_perspective > 0.0) {
|
if (scene_data_block.data.fog_aerial_perspective > 0.0) {
|
||||||
vec3 sky_fog_color = vec3(0.0);
|
vec3 sky_fog_color = vec3(0.0);
|
||||||
vec3 cube_view = scene_data.radiance_inverse_xform * vertex;
|
vec3 cube_view = scene_data_block.data.radiance_inverse_xform * vertex;
|
||||||
// mip_level always reads from the second mipmap and higher so the fog is always slightly blurred
|
// mip_level always reads from the second mipmap and higher so the fog is always slightly blurred
|
||||||
float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near));
|
float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data_block.data.z_near) / (scene_data_block.data.z_far - scene_data_block.data.z_near));
|
||||||
|
|
||||||
sky_fog_color = textureLod(radiance_map, cube_view, mip_level * RADIANCE_MAX_LOD).rgb;
|
sky_fog_color = textureLod(radiance_map, cube_view, mip_level * RADIANCE_MAX_LOD).rgb;
|
||||||
|
|
||||||
fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective);
|
fog_color = mix(fog_color, sky_fog_color, scene_data_block.data.fog_aerial_perspective);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
||||||
if (scene_data.fog_sun_scatter > 0.001) {
|
if (scene_data_block.data.fog_sun_scatter > 0.001) {
|
||||||
vec4 sun_scatter = vec4(0.0);
|
vec4 sun_scatter = vec4(0.0);
|
||||||
float sun_total = 0.0;
|
float sun_total = 0.0;
|
||||||
vec3 view = normalize(vertex);
|
vec3 view = normalize(vertex);
|
||||||
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
|
for (uint i = uint(0); i < scene_data_block.data.directional_light_count; i++) {
|
||||||
vec3 light_color = directional_lights[i].color * directional_lights[i].energy;
|
vec3 light_color = directional_lights[i].color * directional_lights[i].energy;
|
||||||
float light_amount = pow(max(dot(view, directional_lights[i].direction), 0.0), 8.0);
|
float light_amount = pow(max(dot(view, directional_lights[i].direction), 0.0), 8.0);
|
||||||
fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
|
fog_color += light_color * light_amount * scene_data_block.data.fog_sun_scatter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // !DISABLE_LIGHT_DIRECTIONAL
|
#endif // !DISABLE_LIGHT_DIRECTIONAL
|
||||||
|
@ -1612,18 +1786,18 @@ vec4 fog_process(vec3 vertex) {
|
||||||
float fog_amount = 0.0;
|
float fog_amount = 0.0;
|
||||||
|
|
||||||
#ifdef USE_DEPTH_FOG
|
#ifdef USE_DEPTH_FOG
|
||||||
float fog_z = smoothstep(scene_data.fog_depth_begin, scene_data.fog_depth_end, length(vertex));
|
float fog_z = smoothstep(scene_data_block.data.fog_depth_begin, scene_data_block.data.fog_depth_end, length(vertex));
|
||||||
fog_amount = pow(fog_z, scene_data.fog_depth_curve) * scene_data.fog_density;
|
fog_amount = pow(fog_z, scene_data_block.data.fog_depth_curve) * scene_data_block.data.fog_density;
|
||||||
#else
|
#else
|
||||||
fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
|
fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data_block.data.fog_density));
|
||||||
#endif // USE_DEPTH_FOG
|
#endif // USE_DEPTH_FOG
|
||||||
|
|
||||||
if (abs(scene_data.fog_height_density) >= 0.0001) {
|
if (abs(scene_data_block.data.fog_height_density) >= 0.0001) {
|
||||||
float y = (scene_data.inv_view_matrix * vec4(vertex, 1.0)).y;
|
float y = (scene_data_block.data.inv_view_matrix * vec4(vertex, 1.0)).y;
|
||||||
|
|
||||||
float y_dist = y - scene_data.fog_height;
|
float y_dist = y - scene_data_block.data.fog_height;
|
||||||
|
|
||||||
float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density));
|
float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data_block.data.fog_height_density));
|
||||||
|
|
||||||
fog_amount = max(vfog_amount, fog_amount);
|
fog_amount = max(vfog_amount, fog_amount);
|
||||||
}
|
}
|
||||||
|
@ -1781,20 +1955,22 @@ vec4 textureArray_bicubic(sampler2DArray tex, vec3 uv, vec2 texture_size) {
|
||||||
(g1(fuv.y) * (g0x * texture(tex, vec3(p2, uv.z)) + g1x * texture(tex, vec3(p3, uv.z))));
|
(g1(fuv.y) * (g0x * texture(tex, vec3(p2, uv.z)) + g1x * texture(tex, vec3(p3, uv.z))));
|
||||||
}
|
}
|
||||||
#endif //LIGHTMAP_BICUBIC_FILTER
|
#endif //LIGHTMAP_BICUBIC_FILTER
|
||||||
|
#endif // RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
#ifndef RENDER_MOTION_VECTORS
|
||||||
//lay out everything, whatever is unused is optimized away anyway
|
//lay out everything, whatever is unused is optimized away anyway
|
||||||
vec3 vertex = vertex_interp;
|
vec3 vertex = vertex_interp;
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
vec3 eye_offset = multiview_data.eye_offset[ViewIndex].xyz;
|
vec3 eye_offset = multiview_data_block.data.eye_offset[ViewIndex].xyz;
|
||||||
vec3 view = -normalize(vertex_interp - eye_offset);
|
vec3 view = -normalize(vertex_interp - eye_offset);
|
||||||
mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
|
mat4 projection_matrix = multiview_data_block.data.projection_matrix_view[ViewIndex];
|
||||||
mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
|
mat4 inv_projection_matrix = multiview_data_block.data.inv_projection_matrix_view[ViewIndex];
|
||||||
#else
|
#else
|
||||||
vec3 eye_offset = vec3(0.0, 0.0, 0.0);
|
vec3 eye_offset = vec3(0.0, 0.0, 0.0);
|
||||||
vec3 view = -normalize(vertex_interp);
|
vec3 view = -normalize(vertex_interp);
|
||||||
mat4 projection_matrix = scene_data.projection_matrix;
|
mat4 projection_matrix = scene_data_block.data.projection_matrix;
|
||||||
mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
|
mat4 inv_projection_matrix = scene_data_block.data.inv_projection_matrix;
|
||||||
#endif
|
#endif
|
||||||
highp mat4 model_matrix = world_transform;
|
highp mat4 model_matrix = world_transform;
|
||||||
vec3 albedo = vec3(1.0);
|
vec3 albedo = vec3(1.0);
|
||||||
|
@ -1870,7 +2046,7 @@ void main() {
|
||||||
|
|
||||||
float normal_map_depth = 1.0;
|
float normal_map_depth = 1.0;
|
||||||
|
|
||||||
vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size;
|
vec2 screen_uv = gl_FragCoord.xy * scene_data_block.data.screen_pixel_size;
|
||||||
|
|
||||||
float sss_strength = 0.0;
|
float sss_strength = 0.0;
|
||||||
|
|
||||||
|
@ -1976,7 +2152,7 @@ void main() {
|
||||||
// fog must be processed as early as possible and then packed.
|
// fog must be processed as early as possible and then packed.
|
||||||
// to maximize VGPR usage
|
// to maximize VGPR usage
|
||||||
|
|
||||||
if (scene_data.fog_enabled) {
|
if (scene_data_block.data.fog_enabled) {
|
||||||
fog = fog_process(vertex);
|
fog = fog_process(vertex);
|
||||||
}
|
}
|
||||||
#endif // !DISABLE_FOG
|
#endif // !DISABLE_FOG
|
||||||
|
@ -2005,7 +2181,7 @@ void main() {
|
||||||
vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);
|
vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);
|
||||||
|
|
||||||
#ifdef USE_RADIANCE_MAP
|
#ifdef USE_RADIANCE_MAP
|
||||||
if (scene_data.use_reflection_cubemap) {
|
if (scene_data_block.data.use_reflection_cubemap) {
|
||||||
#ifdef LIGHT_ANISOTROPY_USED
|
#ifdef LIGHT_ANISOTROPY_USED
|
||||||
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
|
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
|
||||||
vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
|
vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
|
||||||
|
@ -2018,11 +2194,11 @@ void main() {
|
||||||
#endif
|
#endif
|
||||||
ref_vec = mix(ref_vec, normal, roughness * roughness);
|
ref_vec = mix(ref_vec, normal, roughness * roughness);
|
||||||
float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
|
float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
|
||||||
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
|
ref_vec = scene_data_block.data.radiance_inverse_xform * ref_vec;
|
||||||
specular_light = textureLod(radiance_map, ref_vec, sqrt(roughness) * RADIANCE_MAX_LOD).rgb;
|
specular_light = textureLod(radiance_map, ref_vec, sqrt(roughness) * RADIANCE_MAX_LOD).rgb;
|
||||||
specular_light = srgb_to_linear(specular_light);
|
specular_light = srgb_to_linear(specular_light);
|
||||||
specular_light *= horizon * horizon;
|
specular_light *= horizon * horizon;
|
||||||
specular_light *= scene_data.ambient_light_color_energy.a;
|
specular_light *= scene_data_block.data.ambient_light_color_energy.a;
|
||||||
}
|
}
|
||||||
#endif // USE_RADIANCE_MAP
|
#endif // USE_RADIANCE_MAP
|
||||||
|
|
||||||
|
@ -2058,21 +2234,21 @@ void main() {
|
||||||
|
|
||||||
#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE)
|
#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE)
|
||||||
//lightmap overrides everything
|
//lightmap overrides everything
|
||||||
if (scene_data.use_ambient_light) {
|
if (scene_data_block.data.use_ambient_light) {
|
||||||
ambient_light = scene_data.ambient_light_color_energy.rgb;
|
ambient_light = scene_data_block.data.ambient_light_color_energy.rgb;
|
||||||
|
|
||||||
#ifdef USE_RADIANCE_MAP
|
#ifdef USE_RADIANCE_MAP
|
||||||
if (scene_data.use_ambient_cubemap) {
|
if (scene_data_block.data.use_ambient_cubemap) {
|
||||||
vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
|
vec3 ambient_dir = scene_data_block.data.radiance_inverse_xform * normal;
|
||||||
vec3 cubemap_ambient = textureLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).rgb;
|
vec3 cubemap_ambient = textureLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).rgb;
|
||||||
cubemap_ambient = srgb_to_linear(cubemap_ambient);
|
cubemap_ambient = srgb_to_linear(cubemap_ambient);
|
||||||
ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
|
ambient_light = mix(ambient_light, cubemap_ambient * scene_data_block.data.ambient_light_color_energy.a, scene_data_block.data.ambient_color_sky_mix);
|
||||||
}
|
}
|
||||||
#endif // USE_RADIANCE_MAP
|
#endif // USE_RADIANCE_MAP
|
||||||
|
|
||||||
#ifndef DISABLE_REFLECTION_PROBE
|
#ifndef DISABLE_REFLECTION_PROBE
|
||||||
if (ambient_accum.a > 0.0) {
|
if (ambient_accum.a > 0.0) {
|
||||||
ambient_light = mix(ambient_light, (ambient_accum.rgb / ambient_accum.a) * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
|
ambient_light = mix(ambient_light, (ambient_accum.rgb / ambient_accum.a) * scene_data_block.data.ambient_light_color_energy.a, scene_data_block.data.ambient_color_sky_mix);
|
||||||
}
|
}
|
||||||
#endif // DISABLE_REFLECTION_PROBE
|
#endif // DISABLE_REFLECTION_PROBE
|
||||||
}
|
}
|
||||||
|
@ -2086,7 +2262,7 @@ void main() {
|
||||||
#ifdef USE_LIGHTMAP_CAPTURE
|
#ifdef USE_LIGHTMAP_CAPTURE
|
||||||
{
|
{
|
||||||
// The world normal.
|
// The world normal.
|
||||||
vec3 wnormal = mat3(scene_data.inv_view_matrix) * normal;
|
vec3 wnormal = mat3(scene_data_block.data.inv_view_matrix) * normal;
|
||||||
|
|
||||||
// The SH coefficients used for evaluating diffuse data from SH probes.
|
// The SH coefficients used for evaluating diffuse data from SH probes.
|
||||||
const float c0 = 0.886227; // l0 sqrt(1.0/(4.0*PI)) * PI
|
const float c0 = 0.886227; // l0 sqrt(1.0/(4.0*PI)) * PI
|
||||||
|
@ -2104,7 +2280,7 @@ void main() {
|
||||||
c3 * lightmap_captures[6].rgb * (3.0 * wnormal.z * wnormal.z - 1.0) +
|
c3 * lightmap_captures[6].rgb * (3.0 * wnormal.z * wnormal.z - 1.0) +
|
||||||
c2 * lightmap_captures[7].rgb * wnormal.x * wnormal.z +
|
c2 * lightmap_captures[7].rgb * wnormal.x * wnormal.z +
|
||||||
c4 * lightmap_captures[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y)) *
|
c4 * lightmap_captures[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y)) *
|
||||||
scene_data.IBL_exposure_normalization;
|
scene_data_block.data.IBL_exposure_normalization;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef USE_LIGHTMAP
|
#ifdef USE_LIGHTMAP
|
||||||
|
@ -2192,7 +2368,7 @@ void main() {
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
#ifndef DISABLE_LIGHT_DIRECTIONAL
|
||||||
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
|
for (uint i = uint(0); i < scene_data_block.data.directional_light_count; i++) {
|
||||||
#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
|
#if defined(USE_LIGHTMAP) && !defined(DISABLE_LIGHTMAP)
|
||||||
if (directional_lights[i].bake_mode == LIGHT_BAKE_STATIC) {
|
if (directional_lights[i].bake_mode == LIGHT_BAKE_STATIC) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -2299,7 +2475,7 @@ void main() {
|
||||||
#ifdef MODE_RENDER_DEPTH
|
#ifdef MODE_RENDER_DEPTH
|
||||||
#ifdef RENDER_SHADOWS_LINEAR
|
#ifdef RENDER_SHADOWS_LINEAR
|
||||||
// Linearize the depth buffer if rendering cubemap shadows.
|
// Linearize the depth buffer if rendering cubemap shadows.
|
||||||
gl_FragDepth = (scene_data.z_far - (length(vertex) + scene_data.shadow_bias)) / scene_data.z_far;
|
gl_FragDepth = (scene_data_block.data.z_far - (length(vertex) + scene_data_block.data.shadow_bias)) / scene_data_block.data.z_far;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
|
// Nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
|
||||||
|
@ -2618,7 +2794,7 @@ void main() {
|
||||||
|
|
||||||
frag_color.rgb += additive_light_color;
|
frag_color.rgb += additive_light_color;
|
||||||
#endif // USE_ADDITIVE_LIGHTING
|
#endif // USE_ADDITIVE_LIGHTING
|
||||||
frag_color.rgb *= scene_data.luminance_multiplier;
|
frag_color.rgb *= scene_data_block.data.luminance_multiplier;
|
||||||
|
|
||||||
#endif // !RENDER_MATERIAL
|
#endif // !RENDER_MATERIAL
|
||||||
#endif // !MODE_RENDER_DEPTH
|
#endif // !MODE_RENDER_DEPTH
|
||||||
|
@ -2626,4 +2802,14 @@ void main() {
|
||||||
#ifdef PREMUL_ALPHA_USED
|
#ifdef PREMUL_ALPHA_USED
|
||||||
frag_color.rgb *= premul_alpha;
|
frag_color.rgb *= premul_alpha;
|
||||||
#endif // PREMUL_ALPHA_USED
|
#endif // PREMUL_ALPHA_USED
|
||||||
|
#endif // !RENDER_MOTION_VECTORS
|
||||||
|
|
||||||
|
#if defined(RENDER_MOTION_VECTORS)
|
||||||
|
// These motion vectors are in NDC space (as opposed to screen space) to fit the OpenXR XR_FB_space_warp specification.
|
||||||
|
// https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_FB_space_warp
|
||||||
|
|
||||||
|
vec3 ndc = clip_position.xyz / clip_position.w;
|
||||||
|
vec3 prev_ndc = prev_clip_position.xyz / prev_clip_position.w;
|
||||||
|
motion_vectors = vec4(ndc - prev_ndc, 0.0);
|
||||||
|
#endif // RENDER_MOTION_VECTORS
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ Config::Config() {
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
||||||
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
|
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
|
||||||
|
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);
|
||||||
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
|
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
|
||||||
GLint max_vertex_output;
|
GLint max_vertex_output;
|
||||||
glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &max_vertex_output);
|
glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &max_vertex_output);
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
GLint max_texture_image_units = 0;
|
GLint max_texture_image_units = 0;
|
||||||
GLint max_texture_size = 0;
|
GLint max_texture_size = 0;
|
||||||
GLint max_viewport_size[2] = { 0, 0 };
|
GLint max_viewport_size[2] = { 0, 0 };
|
||||||
|
GLint max_vertex_attribs = 0;
|
||||||
GLint64 max_uniform_buffer_size = 0;
|
GLint64 max_uniform_buffer_size = 0;
|
||||||
uint32_t max_shader_varyings = 0;
|
uint32_t max_shader_varyings = 0;
|
||||||
|
|
||||||
|
@ -113,7 +114,13 @@ public:
|
||||||
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC eglFramebufferTexture2DMultisampleEXT = nullptr;
|
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC eglFramebufferTexture2DMultisampleEXT = nullptr;
|
||||||
PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC eglFramebufferTextureMultisampleMultiviewOVR = nullptr;
|
PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC eglFramebufferTextureMultisampleMultiviewOVR = nullptr;
|
||||||
PFNEGLIMAGETARGETTEXTURE2DOESPROC eglEGLImageTargetTexture2DOES = nullptr;
|
PFNEGLIMAGETARGETTEXTURE2DOESPROC eglEGLImageTargetTexture2DOES = nullptr;
|
||||||
#endif
|
|
||||||
|
#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
|
||||||
|
#define glTexStorage3DMultisample GLES3::Config::get_singleton()->eglTexStorage3DMultisample
|
||||||
|
#define glFramebufferTexture2DMultisampleEXT GLES3::Config::get_singleton()->eglFramebufferTexture2DMultisampleEXT
|
||||||
|
#define glFramebufferTextureMultisampleMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultisampleMultiviewOVR
|
||||||
|
#define glEGLImageTargetTexture2DOES GLES3::Config::get_singleton()->eglEGLImageTargetTexture2DOES
|
||||||
|
#endif // ANDROID_ENABLED
|
||||||
|
|
||||||
static Config *get_singleton() { return singleton; }
|
static Config *get_singleton() { return singleton; }
|
||||||
|
|
||||||
|
|
|
@ -1244,13 +1244,13 @@ MaterialStorage::MaterialStorage() {
|
||||||
|
|
||||||
actions.renames["MODEL_MATRIX"] = "model_matrix";
|
actions.renames["MODEL_MATRIX"] = "model_matrix";
|
||||||
actions.renames["MODEL_NORMAL_MATRIX"] = "model_normal_matrix";
|
actions.renames["MODEL_NORMAL_MATRIX"] = "model_normal_matrix";
|
||||||
actions.renames["VIEW_MATRIX"] = "scene_data.view_matrix";
|
actions.renames["VIEW_MATRIX"] = "scene_data_block.data.view_matrix";
|
||||||
actions.renames["INV_VIEW_MATRIX"] = "scene_data.inv_view_matrix";
|
actions.renames["INV_VIEW_MATRIX"] = "scene_data_block.data.inv_view_matrix";
|
||||||
actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
|
actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
|
||||||
actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
|
actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
|
||||||
actions.renames["MODELVIEW_MATRIX"] = "modelview";
|
actions.renames["MODELVIEW_MATRIX"] = "modelview";
|
||||||
actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
|
actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
|
||||||
actions.renames["MAIN_CAM_INV_VIEW_MATRIX"] = "scene_data.main_cam_inv_view_matrix";
|
actions.renames["MAIN_CAM_INV_VIEW_MATRIX"] = "scene_data_block.data.main_cam_inv_view_matrix";
|
||||||
|
|
||||||
actions.renames["VERTEX"] = "vertex";
|
actions.renames["VERTEX"] = "vertex";
|
||||||
actions.renames["NORMAL"] = "normal";
|
actions.renames["NORMAL"] = "normal";
|
||||||
|
@ -1272,15 +1272,15 @@ MaterialStorage::MaterialStorage() {
|
||||||
|
|
||||||
//builtins
|
//builtins
|
||||||
|
|
||||||
actions.renames["TIME"] = "scene_data.time";
|
actions.renames["TIME"] = "scene_data_block.data.time";
|
||||||
actions.renames["EXPOSURE"] = "(1.0 / scene_data.emissive_exposure_normalization)";
|
actions.renames["EXPOSURE"] = "(1.0 / scene_data_block.data.emissive_exposure_normalization)";
|
||||||
actions.renames["PI"] = String::num(Math::PI);
|
actions.renames["PI"] = String::num(Math::PI);
|
||||||
actions.renames["TAU"] = String::num(Math::TAU);
|
actions.renames["TAU"] = String::num(Math::TAU);
|
||||||
actions.renames["E"] = String::num(Math::E);
|
actions.renames["E"] = String::num(Math::E);
|
||||||
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
|
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
|
||||||
actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
|
actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
|
||||||
actions.renames["IN_SHADOW_PASS"] = "IN_SHADOW_PASS";
|
actions.renames["IN_SHADOW_PASS"] = "IN_SHADOW_PASS";
|
||||||
actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
|
actions.renames["VIEWPORT_SIZE"] = "scene_data_block.data.viewport_size";
|
||||||
|
|
||||||
actions.renames["FRAGCOORD"] = "gl_FragCoord";
|
actions.renames["FRAGCOORD"] = "gl_FragCoord";
|
||||||
actions.renames["FRONT_FACING"] = "gl_FrontFacing";
|
actions.renames["FRONT_FACING"] = "gl_FrontFacing";
|
||||||
|
@ -1323,10 +1323,10 @@ MaterialStorage::MaterialStorage() {
|
||||||
actions.renames["LIGHT_VERTEX"] = "light_vertex";
|
actions.renames["LIGHT_VERTEX"] = "light_vertex";
|
||||||
|
|
||||||
actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
|
actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
|
||||||
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
|
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data_block.data.inv_view_matrix[3].xyz";
|
||||||
actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.inv_view_matrix[2].xyz";
|
actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data_block.data.inv_view_matrix[2].xyz";
|
||||||
actions.renames["CAMERA_VISIBLE_LAYERS"] = "scene_data.camera_visible_layers";
|
actions.renames["CAMERA_VISIBLE_LAYERS"] = "scene_data_block.data.camera_visible_layers";
|
||||||
actions.renames["NODE_POSITION_VIEW"] = "(scene_data.view_matrix * model_matrix)[3].xyz";
|
actions.renames["NODE_POSITION_VIEW"] = "(scene_data_block.data.view_matrix * model_matrix)[3].xyz";
|
||||||
|
|
||||||
actions.renames["VIEW_INDEX"] = "ViewIndex";
|
actions.renames["VIEW_INDEX"] = "ViewIndex";
|
||||||
actions.renames["VIEW_MONO_LEFT"] = "uint(0)";
|
actions.renames["VIEW_MONO_LEFT"] = "uint(0)";
|
||||||
|
|
|
@ -872,7 +872,7 @@ void MeshStorage::mesh_clear(RID p_mesh) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis) {
|
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_uses_motion_vectors, MeshInstance::Surface *mis, int p_current_vertex_buffer, int p_prev_vertex_buffer) {
|
||||||
Mesh::Surface::Attrib attribs[RS::ARRAY_MAX];
|
Mesh::Surface::Attrib attribs[RS::ARRAY_MAX];
|
||||||
|
|
||||||
int position_stride = 0; // Vertex position only.
|
int position_stride = 0; // Vertex position only.
|
||||||
|
@ -1024,7 +1024,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
|
||||||
if (i <= RS::ARRAY_TANGENT) {
|
if (i <= RS::ARRAY_TANGENT) {
|
||||||
attribs[i].stride = (i == RS::ARRAY_VERTEX) ? position_stride : normal_tangent_stride;
|
attribs[i].stride = (i == RS::ARRAY_VERTEX) ? position_stride : normal_tangent_stride;
|
||||||
if (mis) {
|
if (mis) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mis->vertex_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, mis->vertex_buffers[p_current_vertex_buffer]);
|
||||||
} else {
|
} else {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
|
||||||
}
|
}
|
||||||
|
@ -1044,12 +1044,28 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
|
||||||
glEnableVertexAttribArray(i);
|
glEnableVertexAttribArray(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_uses_motion_vectors) {
|
||||||
|
for (int i = 0; i < RS::ARRAY_TANGENT; i++) {
|
||||||
|
if (mis) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, mis->vertex_buffers[mis->prev_vertex_buffer]);
|
||||||
|
} else {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
glVertexAttribPointer(i + 16, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset));
|
||||||
|
glEnableVertexAttribArray(i + 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Do not bind index here as we want to switch between index buffers for LOD
|
// Do not bind index here as we want to switch between index buffers for LOD
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
v.input_mask = p_input_mask;
|
v.input_mask = p_input_mask;
|
||||||
|
v.uses_motion_vectors = p_uses_motion_vectors;
|
||||||
|
v.current_vertex_buffer = p_current_vertex_buffer;
|
||||||
|
v.prev_vertex_buffer = p_prev_vertex_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::mesh_surface_remove(RID p_mesh, int p_surface) {
|
void MeshStorage::mesh_surface_remove(RID p_mesh, int p_surface) {
|
||||||
|
@ -1189,16 +1205,17 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
|
||||||
|
|
||||||
int buffer_size = s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count;
|
int buffer_size = s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count;
|
||||||
|
|
||||||
// Buffer to be used for rendering. Final output of skeleton and blend shapes.
|
// First buffer to be used for rendering. Final output of skeleton and blend shapes.
|
||||||
glGenBuffers(1, &s.vertex_buffer);
|
// If motion vectors are enabled, a second buffer will be created on demand, and they'll be swapped every frame.
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer);
|
glGenBuffers(1, &s.vertex_buffers[0]);
|
||||||
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffer, buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer");
|
glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffers[0]);
|
||||||
|
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[0], buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer");
|
||||||
if (mesh->blend_shape_count > 0) {
|
if (mesh->blend_shape_count > 0) {
|
||||||
// Ping-Pong buffers for processing blendshapes.
|
// Ping-Pong buffers for processing blendshapes.
|
||||||
glGenBuffers(2, s.vertex_buffers);
|
glGenBuffers(2, s.blend_shape_vertex_buffers);
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
for (uint32_t i = 0; i < 2; i++) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffers[i]);
|
glBindBuffer(GL_ARRAY_BUFFER, s.blend_shape_vertex_buffers[i]);
|
||||||
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[i], buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]");
|
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.blend_shape_vertex_buffers[i], buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
|
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
|
||||||
|
@ -1226,9 +1243,11 @@ void MeshStorage::_mesh_instance_remove_surface(MeshInstance *mi, int p_surface)
|
||||||
surface.vertex_buffers[1] = 0;
|
surface.vertex_buffers[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface.vertex_buffer != 0) {
|
for (int i = 0; i < 2; i++) {
|
||||||
GLES3::Utilities::get_singleton()->buffer_free_data(surface.vertex_buffer);
|
if (surface.vertex_buffers[i] != 0) {
|
||||||
surface.vertex_buffer = 0;
|
GLES3::Utilities::get_singleton()->buffer_free_data(surface.vertex_buffers[i]);
|
||||||
|
surface.vertex_buffers[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mi->surfaces.remove_at(p_surface);
|
mi->surfaces.remove_at(p_surface);
|
||||||
|
@ -1268,7 +1287,7 @@ void MeshStorage::mesh_instance_set_canvas_item_transform(RID p_mesh_instance, c
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::_blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface) {
|
void MeshStorage::_blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface) {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, p_mi->surfaces[p_surface].vertex_buffers[0]);
|
glBindBuffer(GL_ARRAY_BUFFER, p_mi->surfaces[p_surface].blend_shape_vertex_buffers[0]);
|
||||||
|
|
||||||
if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_VERTEX))) {
|
if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_VERTEX))) {
|
||||||
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
|
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
|
||||||
|
@ -1310,7 +1329,7 @@ void MeshStorage::_compute_skeleton(MeshInstance *p_mi, Skeleton *p_sk, uint32_t
|
||||||
glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_UNSIGNED_SHORT, GL_TRUE, skin_stride, CAST_INT_TO_UCHAR_PTR(4 * sizeof(uint16_t)));
|
glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_UNSIGNED_SHORT, GL_TRUE, skin_stride, CAST_INT_TO_UCHAR_PTR(4 * sizeof(uint16_t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, p_mi->surfaces[p_surface].vertex_buffer);
|
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, p_mi->surfaces[p_surface].vertex_buffers[p_mi->surfaces[p_surface].current_vertex_buffer]);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, p_sk->transforms_texture);
|
glBindTexture(GL_TEXTURE_2D, p_sk->transforms_texture);
|
||||||
|
|
||||||
|
@ -1337,6 +1356,36 @@ void MeshStorage::update_mesh_instances() {
|
||||||
while (dirty_mesh_instance_arrays.first()) {
|
while (dirty_mesh_instance_arrays.first()) {
|
||||||
MeshInstance *mi = dirty_mesh_instance_arrays.first()->self();
|
MeshInstance *mi = dirty_mesh_instance_arrays.first()->self();
|
||||||
|
|
||||||
|
bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0;
|
||||||
|
int frame = RSG::rasterizer->get_frame_number();
|
||||||
|
if (uses_motion_vectors) {
|
||||||
|
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
|
||||||
|
mi->surfaces[i].prev_vertex_buffer = mi->surfaces[i].current_vertex_buffer;
|
||||||
|
|
||||||
|
if (frame - mi->surfaces[i].last_change == 1) {
|
||||||
|
// Previous buffer's data can only be one frame old to be able to use motion vectors.
|
||||||
|
uint32_t new_buffer_index = mi->surfaces[i].current_vertex_buffer ^ 1;
|
||||||
|
|
||||||
|
if (mi->surfaces[i].vertex_buffers[new_buffer_index] == 0) {
|
||||||
|
// Create the new vertex buffer on demand where the result for the current frame will be stored.
|
||||||
|
GLuint new_vertex_buffer = 0;
|
||||||
|
GLES3::Mesh::Surface *surface = mi->mesh->surfaces[i];
|
||||||
|
int buffer_size = mi->surfaces[i].vertex_stride_cache * surface->vertex_count;
|
||||||
|
glGenBuffers(1, &new_vertex_buffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, new_vertex_buffer);
|
||||||
|
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_vertex_buffer, buffer_size, nullptr, (surface->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Secondary mesh vertex buffer");
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
mi->surfaces[i].vertex_buffers[new_buffer_index] = new_vertex_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
mi->surfaces[i].current_vertex_buffer = new_buffer_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
mi->surfaces[i].last_change = frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
|
Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
|
||||||
|
|
||||||
// Precompute base weight if using blend shapes.
|
// Precompute base weight if using blend shapes.
|
||||||
|
@ -1348,7 +1397,7 @@ void MeshStorage::update_mesh_instances() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
|
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
|
||||||
if (mi->surfaces[i].vertex_buffer == 0) {
|
if (mi->surfaces[i].vertex_buffers[mi->surfaces[i].current_vertex_buffer] == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1383,9 +1432,9 @@ void MeshStorage::update_mesh_instances() {
|
||||||
GLuint vertex_array_gl = 0;
|
GLuint vertex_array_gl = 0;
|
||||||
uint64_t mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_VERTEX;
|
uint64_t mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_VERTEX;
|
||||||
uint64_t format = mi->mesh->surfaces[i]->format & mask; // Format should only have vertex, normal, tangent (as necessary).
|
uint64_t format = mi->mesh->surfaces[i]->format & mask; // Format should only have vertex, normal, tangent (as necessary).
|
||||||
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl);
|
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, false, vertex_array_gl);
|
||||||
glBindVertexArray(vertex_array_gl);
|
glBindVertexArray(vertex_array_gl);
|
||||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[0]);
|
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].blend_shape_vertex_buffers[0]);
|
||||||
glBeginTransformFeedback(GL_POINTS);
|
glBeginTransformFeedback(GL_POINTS);
|
||||||
glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
|
glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
|
||||||
glEndTransformFeedback();
|
glEndTransformFeedback();
|
||||||
|
@ -1407,15 +1456,17 @@ void MeshStorage::update_mesh_instances() {
|
||||||
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_WEIGHT, weight, skeleton_shader.shader_version, variant, specialization);
|
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_WEIGHT, weight, skeleton_shader.shader_version, variant, specialization);
|
||||||
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization);
|
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization);
|
||||||
|
|
||||||
|
// Ensure the skeleton shader outputs to the correct (current) VBO.
|
||||||
|
|
||||||
glBindVertexArray(mi->mesh->surfaces[i]->blend_shapes[bs].vertex_array);
|
glBindVertexArray(mi->mesh->surfaces[i]->blend_shapes[bs].vertex_array);
|
||||||
_blend_shape_bind_mesh_instance_buffer(mi, i);
|
_blend_shape_bind_mesh_instance_buffer(mi, i);
|
||||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[1]);
|
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].blend_shape_vertex_buffers[1]);
|
||||||
|
|
||||||
glBeginTransformFeedback(GL_POINTS);
|
glBeginTransformFeedback(GL_POINTS);
|
||||||
glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
|
glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
|
||||||
glEndTransformFeedback();
|
glEndTransformFeedback();
|
||||||
|
|
||||||
SWAP(mi->surfaces[i].vertex_buffers[0], mi->surfaces[i].vertex_buffers[1]);
|
SWAP(mi->surfaces[i].blend_shape_vertex_buffers[0], mi->surfaces[i].blend_shape_vertex_buffers[1]);
|
||||||
}
|
}
|
||||||
uint32_t bs = mi->mesh->blend_shape_count - 1;
|
uint32_t bs = mi->mesh->blend_shape_count - 1;
|
||||||
|
|
||||||
|
@ -1451,7 +1502,7 @@ void MeshStorage::update_mesh_instances() {
|
||||||
can_use_skeleton = false;
|
can_use_skeleton = false;
|
||||||
} else {
|
} else {
|
||||||
// Do last blendshape by itself and prepare vertex data for use by the renderer.
|
// Do last blendshape by itself and prepare vertex data for use by the renderer.
|
||||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffer);
|
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[mi->surfaces[i].current_vertex_buffer]);
|
||||||
|
|
||||||
glBeginTransformFeedback(GL_POINTS);
|
glBeginTransformFeedback(GL_POINTS);
|
||||||
glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
|
glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
|
||||||
|
@ -1497,7 +1548,7 @@ void MeshStorage::update_mesh_instances() {
|
||||||
GLuint vertex_array_gl = 0;
|
GLuint vertex_array_gl = 0;
|
||||||
uint64_t mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_VERTEX;
|
uint64_t mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_VERTEX;
|
||||||
uint64_t format = mi->mesh->surfaces[i]->format & mask; // Format should only have vertex, normal, tangent (as necessary).
|
uint64_t format = mi->mesh->surfaces[i]->format & mask; // Format should only have vertex, normal, tangent (as necessary).
|
||||||
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl);
|
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, false, vertex_array_gl);
|
||||||
glBindVertexArray(vertex_array_gl);
|
glBindVertexArray(vertex_array_gl);
|
||||||
_compute_skeleton(mi, sk, i);
|
_compute_skeleton(mi, sk, i);
|
||||||
}
|
}
|
||||||
|
@ -1541,9 +1592,11 @@ void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multimesh->buffer) {
|
for (int i = 0; i < 2; i++) {
|
||||||
GLES3::Utilities::get_singleton()->buffer_free_data(multimesh->buffer);
|
if (multimesh->buffer[i] != 0) {
|
||||||
multimesh->buffer = 0;
|
GLES3::Utilities::get_singleton()->buffer_free_data(multimesh->buffer[i]);
|
||||||
|
multimesh->buffer[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multimesh->data_cache_dirty_regions) {
|
if (multimesh->data_cache_dirty_regions) {
|
||||||
|
@ -1571,9 +1624,9 @@ void MeshStorage::_multimesh_allocate_data(RID p_multimesh, int p_instances, RS:
|
||||||
multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
|
multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
|
||||||
|
|
||||||
if (multimesh->instances) {
|
if (multimesh->instances) {
|
||||||
glGenBuffers(1, &multimesh->buffer);
|
glGenBuffers(1, &multimesh->buffer[0]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer[0]);
|
||||||
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW, "MultiMesh buffer");
|
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, multimesh->buffer[0], multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW, "MultiMesh buffer");
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1604,7 +1657,7 @@ void MeshStorage::_multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
|
||||||
} else if (multimesh->instances) {
|
} else if (multimesh->instances) {
|
||||||
// Need to re-create AABB. Unfortunately, calling this has a penalty.
|
// Need to re-create AABB. Unfortunately, calling this has a penalty.
|
||||||
if (multimesh->buffer_set) {
|
if (multimesh->buffer_set) {
|
||||||
Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float));
|
Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer[multimesh->current_buffer], multimesh->instances * multimesh->stride_cache * sizeof(float));
|
||||||
const uint8_t *r = buffer.ptr();
|
const uint8_t *r = buffer.ptr();
|
||||||
const float *data = (const float *)r;
|
const float *data = (const float *)r;
|
||||||
_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
|
_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
|
||||||
|
@ -1628,7 +1681,7 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
|
||||||
float *w = multimesh->data_cache.ptrw();
|
float *w = multimesh->data_cache.ptrw();
|
||||||
|
|
||||||
if (multimesh->buffer_set) {
|
if (multimesh->buffer_set) {
|
||||||
Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float));
|
Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer[multimesh->current_buffer], multimesh->instances * multimesh->stride_cache * sizeof(float));
|
||||||
|
|
||||||
{
|
{
|
||||||
const uint8_t *r = buffer.ptr();
|
const uint8_t *r = buffer.ptr();
|
||||||
|
@ -1971,6 +2024,10 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
|
||||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||||
ERR_FAIL_NULL(multimesh);
|
ERR_FAIL_NULL(multimesh);
|
||||||
|
|
||||||
|
// Assign data to previous buffer if motion vectors are used, that data will be made current in _update_dirty_multimeshes().
|
||||||
|
bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0;
|
||||||
|
int buffer_index = uses_motion_vectors ? multimesh->prev_buffer : multimesh->current_buffer;
|
||||||
|
|
||||||
if (multimesh->uses_colors || multimesh->uses_custom_data) {
|
if (multimesh->uses_colors || multimesh->uses_custom_data) {
|
||||||
// Color and custom need to be packed so copy buffer to data_cache and pack.
|
// Color and custom need to be packed so copy buffer to data_cache and pack.
|
||||||
|
|
||||||
|
@ -2016,7 +2073,7 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
|
||||||
|
|
||||||
multimesh->data_cache.resize(multimesh->instances * (int)multimesh->stride_cache);
|
multimesh->data_cache.resize(multimesh->instances * (int)multimesh->stride_cache);
|
||||||
const float *r = multimesh->data_cache.ptr();
|
const float *r = multimesh->data_cache.ptr();
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer[buffer_index]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, multimesh->data_cache.size() * sizeof(float), r, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, multimesh->data_cache.size() * sizeof(float), r, GL_STATIC_DRAW);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
@ -2029,7 +2086,7 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
|
||||||
// Only Transform is being used, so we can upload directly.
|
// Only Transform is being used, so we can upload directly.
|
||||||
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
|
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
|
||||||
const float *r = p_buffer.ptr();
|
const float *r = p_buffer.ptr();
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer[buffer_index]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, p_buffer.size() * sizeof(float), r, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, p_buffer.size() * sizeof(float), r, GL_STATIC_DRAW);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
@ -2068,14 +2125,14 @@ Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
|
||||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||||
ERR_FAIL_NULL_V(multimesh, Vector<float>());
|
ERR_FAIL_NULL_V(multimesh, Vector<float>());
|
||||||
Vector<float> ret;
|
Vector<float> ret;
|
||||||
if (multimesh->buffer == 0 || multimesh->instances == 0) {
|
if (multimesh->buffer[multimesh->current_buffer] == 0 || multimesh->instances == 0) {
|
||||||
return Vector<float>();
|
return Vector<float>();
|
||||||
} else if (multimesh->data_cache.size()) {
|
} else if (multimesh->data_cache.size()) {
|
||||||
ret = multimesh->data_cache;
|
ret = multimesh->data_cache;
|
||||||
} else {
|
} else {
|
||||||
// Buffer not cached, so fetch from GPU memory. This can be a stalling operation, avoid whenever possible.
|
// Buffer not cached, so fetch from GPU memory. This can be a stalling operation, avoid whenever possible.
|
||||||
|
|
||||||
Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float));
|
Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer[multimesh->current_buffer], multimesh->instances * multimesh->stride_cache * sizeof(float));
|
||||||
ret.resize(multimesh->instances * multimesh->stride_cache);
|
ret.resize(multimesh->instances * multimesh->stride_cache);
|
||||||
{
|
{
|
||||||
float *w = ret.ptrw();
|
float *w = ret.ptrw();
|
||||||
|
@ -2175,53 +2232,27 @@ void MeshStorage::_update_dirty_multimeshes() {
|
||||||
while (multimesh_dirty_list) {
|
while (multimesh_dirty_list) {
|
||||||
MultiMesh *multimesh = multimesh_dirty_list;
|
MultiMesh *multimesh = multimesh_dirty_list;
|
||||||
|
|
||||||
if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists
|
bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0;
|
||||||
const float *data = multimesh->data_cache.ptr();
|
if (uses_motion_vectors) {
|
||||||
|
multimesh->prev_buffer = multimesh->current_buffer;
|
||||||
|
uint32_t new_buffer_index = multimesh->current_buffer ^ 1;
|
||||||
|
|
||||||
uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
|
// Generate secondary buffer if it doesn't exist.
|
||||||
|
if (multimesh->buffer[new_buffer_index] == 0 && multimesh->instances) {
|
||||||
if (multimesh->data_cache_used_dirty_regions) {
|
GLuint new_buffer = 0;
|
||||||
uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, (int)MULTIMESH_DIRTY_REGION_SIZE);
|
glGenBuffers(1, &new_buffer);
|
||||||
uint32_t visible_region_count = visible_instances == 0 ? 0 : Math::division_round_up(visible_instances, (uint32_t)MULTIMESH_DIRTY_REGION_SIZE);
|
glBindBuffer(GL_ARRAY_BUFFER, new_buffer);
|
||||||
|
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, new_buffer, multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW, "MultiMesh secondary buffer");
|
||||||
GLint region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
multimesh->buffer[new_buffer_index] = new_buffer;
|
||||||
if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
|
|
||||||
// If there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
|
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
} else {
|
|
||||||
// Not that many regions? update them all
|
|
||||||
// TODO: profile the performance cost on low end
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
|
|
||||||
for (uint32_t i = 0; i < visible_region_count; i++) {
|
|
||||||
if (multimesh->data_cache_dirty_regions[i]) {
|
|
||||||
GLint offset = i * region_size;
|
|
||||||
GLint size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
|
|
||||||
uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
|
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, offset, MIN(region_size, size - offset), &data[region_start_index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
|
|
||||||
multimesh->data_cache_dirty_regions[i] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
multimesh->data_cache_used_dirty_regions = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multimesh->aabb_dirty && multimesh->mesh.is_valid()) {
|
multimesh->current_buffer = new_buffer_index;
|
||||||
multimesh->aabb_dirty = false;
|
multimesh->last_change = RSG::rasterizer->get_frame_number();
|
||||||
if (multimesh->custom_aabb == AABB()) {
|
|
||||||
_multimesh_re_create_aabb(multimesh, data, visible_instances);
|
|
||||||
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_update_dirty_multimesh(multimesh, uses_motion_vectors);
|
||||||
|
|
||||||
multimesh_dirty_list = multimesh->dirty_list;
|
multimesh_dirty_list = multimesh->dirty_list;
|
||||||
|
|
||||||
multimesh->dirty_list = nullptr;
|
multimesh->dirty_list = nullptr;
|
||||||
|
@ -2231,6 +2262,86 @@ void MeshStorage::_update_dirty_multimeshes() {
|
||||||
multimesh_dirty_list = nullptr;
|
multimesh_dirty_list = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshStorage::_update_dirty_multimesh(MultiMesh *p_multimesh, bool p_uses_motion_vectors) {
|
||||||
|
if (p_multimesh->data_cache.size()) { // May have been cleared, so only process if it exists.
|
||||||
|
const float *data = p_multimesh->data_cache.ptr();
|
||||||
|
|
||||||
|
uint32_t visible_instances = p_multimesh->visible_instances >= 0 ? p_multimesh->visible_instances : p_multimesh->instances;
|
||||||
|
|
||||||
|
if (p_multimesh->data_cache_used_dirty_regions) {
|
||||||
|
uint32_t data_cache_dirty_region_count = Math::division_round_up(p_multimesh->instances, (int)MULTIMESH_DIRTY_REGION_SIZE);
|
||||||
|
uint32_t visible_region_count = visible_instances == 0 ? 0 : Math::division_round_up(visible_instances, (uint32_t)MULTIMESH_DIRTY_REGION_SIZE);
|
||||||
|
|
||||||
|
GLint region_size = p_multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
|
||||||
|
|
||||||
|
if (p_multimesh->data_cache_used_dirty_regions > 32 || p_multimesh->data_cache_used_dirty_regions > visible_region_count / 2 || p_uses_motion_vectors) {
|
||||||
|
// If there are too many dirty regions, the dirty regions represent the majority of visible regions, or motion vectors are used:
|
||||||
|
// Just copy all, else transfer cost piles up too much.
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, p_multimesh->buffer[p_multimesh->current_buffer]);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, MIN(visible_region_count * region_size, p_multimesh->instances * p_multimesh->stride_cache * sizeof(float)), data);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
} else {
|
||||||
|
// Not that many regions? Update them all.
|
||||||
|
// TODO: profile the performance cost on low end
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, p_multimesh->buffer[p_multimesh->current_buffer]);
|
||||||
|
for (uint32_t i = 0; i < visible_region_count; i++) {
|
||||||
|
if (p_multimesh->data_cache_dirty_regions[i]) {
|
||||||
|
GLint offset = i * region_size;
|
||||||
|
GLint size = p_multimesh->stride_cache * (uint32_t)p_multimesh->instances * (uint32_t)sizeof(float);
|
||||||
|
uint32_t region_start_index = p_multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, offset, MIN(region_size, size - offset), &data[region_start_index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
|
||||||
|
p_multimesh->data_cache_dirty_regions[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_multimesh->data_cache_used_dirty_regions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_multimesh->aabb_dirty && p_multimesh->mesh.is_valid()) {
|
||||||
|
p_multimesh->aabb_dirty = false;
|
||||||
|
if (p_multimesh->custom_aabb == AABB()) {
|
||||||
|
_multimesh_re_create_aabb(p_multimesh, data, visible_instances);
|
||||||
|
p_multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLES3::MeshStorage::multimesh_vertex_attrib_setup(GLuint p_instance_buffer, uint32_t p_stride, bool p_uses_format_2d, bool p_has_color_or_custom_data, int p_attrib_base_index) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, p_instance_buffer);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(p_attrib_base_index + 0);
|
||||||
|
glVertexAttribPointer(p_attrib_base_index + 0, 4, GL_FLOAT, GL_FALSE, p_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
|
||||||
|
glVertexAttribDivisor(p_attrib_base_index + 0, 1);
|
||||||
|
glEnableVertexAttribArray(p_attrib_base_index + 1);
|
||||||
|
glVertexAttribPointer(p_attrib_base_index + 1, 4, GL_FLOAT, GL_FALSE, p_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4));
|
||||||
|
glVertexAttribDivisor(p_attrib_base_index + 1, 1);
|
||||||
|
if (!p_uses_format_2d) {
|
||||||
|
glEnableVertexAttribArray(p_attrib_base_index + 2);
|
||||||
|
glVertexAttribPointer(p_attrib_base_index + 2, 4, GL_FLOAT, GL_FALSE, p_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 8));
|
||||||
|
glVertexAttribDivisor(p_attrib_base_index + 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_has_color_or_custom_data) {
|
||||||
|
uint32_t color_custom_offset = p_uses_format_2d ? 8 : 12;
|
||||||
|
glEnableVertexAttribArray(p_attrib_base_index + 3);
|
||||||
|
glVertexAttribIPointer(p_attrib_base_index + 3, 4, GL_UNSIGNED_INT, p_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_custom_offset * sizeof(float)));
|
||||||
|
glVertexAttribDivisor(p_attrib_base_index + 3, 1);
|
||||||
|
} else {
|
||||||
|
// Set all default instance color and custom data values to 1.0 or 0.0 using a compressed format.
|
||||||
|
uint16_t zero = Math::make_half_float(0.0f);
|
||||||
|
uint16_t one = Math::make_half_float(1.0f);
|
||||||
|
GLuint default_color = (uint32_t(one) << 16) | one;
|
||||||
|
GLuint default_custom = (uint32_t(zero) << 16) | zero;
|
||||||
|
glVertexAttribI4ui(p_attrib_base_index + 3, default_color, default_color, default_custom, default_custom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* SKELETON API */
|
/* SKELETON API */
|
||||||
|
|
||||||
RID MeshStorage::skeleton_allocate() {
|
RID MeshStorage::skeleton_allocate() {
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "core/templates/rid_owner.h"
|
#include "core/templates/rid_owner.h"
|
||||||
#include "core/templates/self_list.h"
|
#include "core/templates/self_list.h"
|
||||||
#include "drivers/gles3/shaders/skeleton.glsl.gen.h"
|
#include "drivers/gles3/shaders/skeleton.glsl.gen.h"
|
||||||
|
#include "servers/rendering/rendering_server_globals.h"
|
||||||
#include "servers/rendering/storage/mesh_storage.h"
|
#include "servers/rendering/storage/mesh_storage.h"
|
||||||
#include "servers/rendering/storage/utilities.h"
|
#include "servers/rendering/storage/utilities.h"
|
||||||
|
|
||||||
|
@ -70,6 +71,9 @@ struct Mesh {
|
||||||
// Cache vertex arrays so they can be created
|
// Cache vertex arrays so they can be created
|
||||||
struct Version {
|
struct Version {
|
||||||
uint32_t input_mask = 0;
|
uint32_t input_mask = 0;
|
||||||
|
bool uses_motion_vectors = false;
|
||||||
|
uint32_t current_vertex_buffer = 0;
|
||||||
|
uint32_t prev_vertex_buffer = 0;
|
||||||
GLuint vertex_array = 0;
|
GLuint vertex_array = 0;
|
||||||
|
|
||||||
Attrib attribs[RS::ARRAY_MAX];
|
Attrib attribs[RS::ARRAY_MAX];
|
||||||
|
@ -152,9 +156,9 @@ struct MeshInstance {
|
||||||
Mesh *mesh = nullptr;
|
Mesh *mesh = nullptr;
|
||||||
RID skeleton;
|
RID skeleton;
|
||||||
struct Surface {
|
struct Surface {
|
||||||
GLuint vertex_buffers[2] = { 0, 0 };
|
GLuint blend_shape_vertex_buffers[2] = { 0, 0 };
|
||||||
GLuint vertex_arrays[2] = { 0, 0 };
|
GLuint vertex_arrays[2] = { 0, 0 };
|
||||||
GLuint vertex_buffer = 0;
|
GLuint vertex_buffers[2] = { 0, 0 };
|
||||||
int vertex_stride_cache = 0;
|
int vertex_stride_cache = 0;
|
||||||
int vertex_size_cache = 0;
|
int vertex_size_cache = 0;
|
||||||
int vertex_normal_offset_cache = 0;
|
int vertex_normal_offset_cache = 0;
|
||||||
|
@ -163,6 +167,11 @@ struct MeshInstance {
|
||||||
|
|
||||||
Mesh::Surface::Version *versions = nullptr; //allocated on demand
|
Mesh::Surface::Version *versions = nullptr; //allocated on demand
|
||||||
uint32_t version_count = 0;
|
uint32_t version_count = 0;
|
||||||
|
|
||||||
|
bool uses_motion_vectors = false;
|
||||||
|
int current_vertex_buffer = 0;
|
||||||
|
int prev_vertex_buffer = 0;
|
||||||
|
uint64_t last_change = 0;
|
||||||
};
|
};
|
||||||
LocalVector<Surface> surfaces;
|
LocalVector<Surface> surfaces;
|
||||||
LocalVector<float> blend_weights;
|
LocalVector<float> blend_weights;
|
||||||
|
@ -199,7 +208,10 @@ struct MultiMesh {
|
||||||
bool *data_cache_dirty_regions = nullptr;
|
bool *data_cache_dirty_regions = nullptr;
|
||||||
uint32_t data_cache_used_dirty_regions = 0;
|
uint32_t data_cache_used_dirty_regions = 0;
|
||||||
|
|
||||||
GLuint buffer = 0;
|
GLuint buffer[2] = { 0, 0 };
|
||||||
|
int current_buffer = 0;
|
||||||
|
int prev_buffer = 0;
|
||||||
|
uint64_t last_change = 0;
|
||||||
|
|
||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
MultiMesh *dirty_list = nullptr;
|
MultiMesh *dirty_list = nullptr;
|
||||||
|
@ -239,7 +251,7 @@ private:
|
||||||
|
|
||||||
mutable RID_Owner<Mesh, true> mesh_owner;
|
mutable RID_Owner<Mesh, true> mesh_owner;
|
||||||
|
|
||||||
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis = nullptr);
|
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_uses_motion_vectors, MeshInstance::Surface *mis = nullptr, int p_current_vertex_buffer = 0, int p_prev_vertex_buffer = 0);
|
||||||
void _mesh_surface_clear(Mesh *mesh, int p_surface);
|
void _mesh_surface_clear(Mesh *mesh, int p_surface);
|
||||||
|
|
||||||
/* Mesh Instance API */
|
/* Mesh Instance API */
|
||||||
|
@ -418,7 +430,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this to cache Vertex Array Objects so they are only generated once
|
// Use this to cache Vertex Array Objects so they are only generated once
|
||||||
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, GLuint &r_vertex_array_gl) {
|
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, bool p_uses_motion_vectors, GLuint &r_vertex_array_gl) {
|
||||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||||
|
|
||||||
s->version_lock.lock();
|
s->version_lock.lock();
|
||||||
|
@ -426,7 +438,7 @@ public:
|
||||||
// There will never be more than 3 or 4 versions, so iterating is the fastest way.
|
// There will never be more than 3 or 4 versions, so iterating is the fastest way.
|
||||||
|
|
||||||
for (uint32_t i = 0; i < s->version_count; i++) {
|
for (uint32_t i = 0; i < s->version_count; i++) {
|
||||||
if (s->versions[i].input_mask != p_input_mask) {
|
if (s->versions[i].input_mask != p_input_mask || s->versions[i].uses_motion_vectors != p_uses_motion_vectors) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// We have this version, hooray.
|
// We have this version, hooray.
|
||||||
|
@ -439,7 +451,7 @@ public:
|
||||||
s->version_count++;
|
s->version_count++;
|
||||||
s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
|
s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
|
||||||
|
|
||||||
_mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
|
_mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask, p_uses_motion_vectors);
|
||||||
|
|
||||||
r_vertex_array_gl = s->versions[version].vertex_array;
|
r_vertex_array_gl = s->versions[version].vertex_array;
|
||||||
|
|
||||||
|
@ -461,7 +473,7 @@ public:
|
||||||
|
|
||||||
// TODO: considering hashing versions with multimesh buffer RID.
|
// TODO: considering hashing versions with multimesh buffer RID.
|
||||||
// Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance.
|
// Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance.
|
||||||
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint64_t p_input_mask, GLuint &r_vertex_array_gl) {
|
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint64_t p_input_mask, bool p_uses_motion_vectors, GLuint &r_vertex_array_gl) {
|
||||||
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
||||||
ERR_FAIL_NULL(mi);
|
ERR_FAIL_NULL(mi);
|
||||||
Mesh *mesh = mi->mesh;
|
Mesh *mesh = mi->mesh;
|
||||||
|
@ -470,14 +482,24 @@ public:
|
||||||
MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
|
MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
|
||||||
Mesh::Surface *s = mesh->surfaces[p_surface_index];
|
Mesh::Surface *s = mesh->surfaces[p_surface_index];
|
||||||
|
|
||||||
|
uint32_t current_buffer = mis->current_vertex_buffer;
|
||||||
|
|
||||||
|
// Using the previous buffer is only allowed if the surface was updated this frame and motion vectors are required.
|
||||||
|
uint32_t previous_buffer = p_uses_motion_vectors && (RSG::rasterizer->get_frame_number() == mis->last_change) ? mis->prev_vertex_buffer : current_buffer;
|
||||||
|
|
||||||
s->version_lock.lock();
|
s->version_lock.lock();
|
||||||
|
|
||||||
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
|
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mis->version_count; i++) {
|
for (uint32_t i = 0; i < mis->version_count; i++) {
|
||||||
if (mis->versions[i].input_mask != p_input_mask) {
|
if (mis->versions[i].input_mask != p_input_mask || mis->versions[i].uses_motion_vectors != p_uses_motion_vectors) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mis->versions[i].current_vertex_buffer != current_buffer || mis->versions[i].prev_vertex_buffer != previous_buffer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//we have this version, hooray
|
//we have this version, hooray
|
||||||
r_vertex_array_gl = mis->versions[i].vertex_array;
|
r_vertex_array_gl = mis->versions[i].vertex_array;
|
||||||
s->version_lock.unlock();
|
s->version_lock.unlock();
|
||||||
|
@ -488,7 +510,7 @@ public:
|
||||||
mis->version_count++;
|
mis->version_count++;
|
||||||
mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
|
mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
|
||||||
|
|
||||||
_mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
|
_mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, p_uses_motion_vectors, mis, current_buffer, previous_buffer);
|
||||||
|
|
||||||
r_vertex_array_gl = mis->versions[version].vertex_array;
|
r_vertex_array_gl = mis->versions[version].vertex_array;
|
||||||
|
|
||||||
|
@ -532,6 +554,9 @@ public:
|
||||||
virtual MultiMeshInterpolator *_multimesh_get_interpolator(RID p_multimesh) const override;
|
virtual MultiMeshInterpolator *_multimesh_get_interpolator(RID p_multimesh) const override;
|
||||||
|
|
||||||
void _update_dirty_multimeshes();
|
void _update_dirty_multimeshes();
|
||||||
|
void _update_dirty_multimesh(MultiMesh *p_multimesh, bool p_uses_motion_vectors);
|
||||||
|
|
||||||
|
void multimesh_vertex_attrib_setup(GLuint p_instance_buffer, uint32_t p_stride, bool p_uses_format_2d, bool p_has_color_or_custom_data, int p_attrib_base_index);
|
||||||
|
|
||||||
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
|
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
|
||||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||||
|
@ -563,7 +588,17 @@ public:
|
||||||
_FORCE_INLINE_ GLuint multimesh_get_gl_buffer(RID p_multimesh) const {
|
_FORCE_INLINE_ GLuint multimesh_get_gl_buffer(RID p_multimesh) const {
|
||||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||||
ERR_FAIL_NULL_V(multimesh, 0);
|
ERR_FAIL_NULL_V(multimesh, 0);
|
||||||
return multimesh->buffer;
|
return multimesh->buffer[multimesh->current_buffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint multimesh_get_prev_gl_buffer(RID p_multimesh) const {
|
||||||
|
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||||
|
return multimesh->buffer[multimesh->prev_buffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint64_t multimesh_get_last_change(RID p_multimesh) const {
|
||||||
|
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||||
|
return multimesh->last_change;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ uint32_t multimesh_get_stride(RID p_multimesh) const {
|
_FORCE_INLINE_ uint32_t multimesh_get_stride(RID p_multimesh) const {
|
||||||
|
|
|
@ -1169,6 +1169,7 @@ void ParticlesStorage::update_particles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SWAP(particles->front_instance_buffer, particles->back_instance_buffer);
|
SWAP(particles->front_instance_buffer, particles->back_instance_buffer);
|
||||||
|
particles->last_change = RSG::rasterizer->get_frame_number();
|
||||||
|
|
||||||
// At the end of update, the back_buffer contains the most up-to-date-information to read from.
|
// At the end of update, the back_buffer contains the most up-to-date-information to read from.
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,8 @@ private:
|
||||||
GLuint back_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
|
GLuint back_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
|
||||||
GLuint back_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
|
GLuint back_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
|
||||||
|
|
||||||
|
uint64_t last_change = 0;
|
||||||
|
|
||||||
uint32_t instance_buffer_size_cache = 0;
|
uint32_t instance_buffer_size_cache = 0;
|
||||||
uint32_t instance_buffer_stride_cache = 0;
|
uint32_t instance_buffer_stride_cache = 0;
|
||||||
uint32_t num_attrib_arrays_cache = 0;
|
uint32_t num_attrib_arrays_cache = 0;
|
||||||
|
@ -397,6 +399,20 @@ public:
|
||||||
return particles->back_instance_buffer;
|
return particles->back_instance_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ GLuint particles_get_prev_gl_buffer(RID p_particles) {
|
||||||
|
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||||
|
ERR_FAIL_NULL_V(particles, 0);
|
||||||
|
|
||||||
|
return particles->front_instance_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint64_t particles_get_last_change(RID p_particles) {
|
||||||
|
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||||
|
ERR_FAIL_NULL_V(particles, 0);
|
||||||
|
|
||||||
|
return particles->last_change;
|
||||||
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
|
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
|
||||||
Particles *particles = particles_owner.get_or_null(p_particles);
|
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||||
ERR_FAIL_NULL_V(particles, false);
|
ERR_FAIL_NULL_V(particles, false);
|
||||||
|
|
|
@ -35,13 +35,6 @@
|
||||||
#include "texture_storage.h"
|
#include "texture_storage.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef ANDROID_ENABLED
|
|
||||||
#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
|
|
||||||
#define glTexStorage3DMultisample GLES3::Config::get_singleton()->eglTexStorage3DMultisample
|
|
||||||
#define glFramebufferTexture2DMultisampleEXT GLES3::Config::get_singleton()->eglFramebufferTexture2DMultisampleEXT
|
|
||||||
#define glFramebufferTextureMultisampleMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultisampleMultiviewOVR
|
|
||||||
#endif // ANDROID_ENABLED
|
|
||||||
|
|
||||||
// Will only be defined if GLES 3.2 headers are included
|
// Will only be defined if GLES 3.2 headers are included
|
||||||
#ifndef GL_TEXTURE_2D_MULTISAMPLE_ARRAY
|
#ifndef GL_TEXTURE_2D_MULTISAMPLE_ARRAY
|
||||||
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
|
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
|
||||||
|
|
|
@ -37,10 +37,6 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef ANDROID_ENABLED
|
|
||||||
#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace GLES3;
|
using namespace GLES3;
|
||||||
|
|
||||||
TextureStorage *TextureStorage::singleton = nullptr;
|
TextureStorage *TextureStorage::singleton = nullptr;
|
||||||
|
@ -2265,7 +2261,7 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const {
|
||||||
|
|
||||||
GLuint TextureStorage::system_fbo = 0;
|
GLuint TextureStorage::system_fbo = 0;
|
||||||
|
|
||||||
void TextureStorage::_update_render_target(RenderTarget *rt) {
|
void TextureStorage::_update_render_target_color(RenderTarget *rt) {
|
||||||
// do not allocate a render target with no size
|
// do not allocate a render target with no size
|
||||||
if (rt->size.x <= 0 || rt->size.y <= 0) {
|
if (rt->size.x <= 0 || rt->size.y <= 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -2437,6 +2433,60 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureStorage::_update_render_target_velocity(RenderTarget *rt) {
|
||||||
|
GLuint new_velocity_fbo;
|
||||||
|
glGenFramebuffers(1, &new_velocity_fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, new_velocity_fbo);
|
||||||
|
|
||||||
|
uint32_t view_count = rt->view_count;
|
||||||
|
GLuint texture_target = view_count > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
|
||||||
|
|
||||||
|
GLuint velocity_texture_id = texture_get_texid(rt->overridden.velocity);
|
||||||
|
glBindTexture(texture_target, velocity_texture_id);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
#ifndef IOS_ENABLED
|
||||||
|
if (view_count > 1) {
|
||||||
|
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, velocity_texture_id, 0, 0, view_count);
|
||||||
|
} else {
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, velocity_texture_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint velocity_depth_texture_id = texture_get_texid(rt->overridden.velocity_depth);
|
||||||
|
glBindTexture(texture_target, velocity_depth_texture_id);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
#ifndef IOS_ENABLED
|
||||||
|
if (view_count > 1) {
|
||||||
|
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, velocity_depth_texture_id, 0, 0, view_count);
|
||||||
|
} else {
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, velocity_depth_texture_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
glDeleteFramebuffers(1, &new_velocity_fbo);
|
||||||
|
WARN_PRINT(vformat("Could not create motion vector render target, status: %s.", GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status)));
|
||||||
|
} else {
|
||||||
|
rt->overridden.velocity_fbo = new_velocity_fbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(texture_target, 0);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
|
void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
|
||||||
ERR_FAIL_COND_MSG(rt->backbuffer_fbo != 0, "Cannot allocate RenderTarget backbuffer: already initialized.");
|
ERR_FAIL_COND_MSG(rt->backbuffer_fbo != 0, "Cannot allocate RenderTarget backbuffer: already initialized.");
|
||||||
ERR_FAIL_COND(rt->direct_to_screen);
|
ERR_FAIL_COND(rt->direct_to_screen);
|
||||||
|
@ -2578,6 +2628,12 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (KeyValue<uint32_t, GLuint> &E : rt->overridden.velocity_fbo_cache) {
|
||||||
|
glDeleteFramebuffers(1, &E.value);
|
||||||
|
}
|
||||||
|
rt->overridden.velocity_fbo_cache.clear();
|
||||||
|
rt->overridden.velocity_fbo = 0;
|
||||||
|
|
||||||
// Dispose of the cached fbo's and the allocated textures
|
// Dispose of the cached fbo's and the allocated textures
|
||||||
for (KeyValue<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry> &E : rt->overridden.fbo_cache) {
|
for (KeyValue<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry> &E : rt->overridden.fbo_cache) {
|
||||||
glDeleteTextures(E.value.allocated_textures.size(), E.value.allocated_textures.ptr());
|
glDeleteTextures(E.value.allocated_textures.size(), E.value.allocated_textures.ptr());
|
||||||
|
@ -2630,7 +2686,6 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
|
||||||
}
|
}
|
||||||
rt->depth = 0;
|
rt->depth = 0;
|
||||||
|
|
||||||
rt->overridden.velocity = RID();
|
|
||||||
rt->overridden.is_overridden = false;
|
rt->overridden.is_overridden = false;
|
||||||
|
|
||||||
if (rt->backbuffer_fbo != 0) {
|
if (rt->backbuffer_fbo != 0) {
|
||||||
|
@ -2659,7 +2714,7 @@ RID TextureStorage::render_target_create() {
|
||||||
t.is_render_target = true;
|
t.is_render_target = true;
|
||||||
|
|
||||||
render_target.texture = texture_owner.make_rid(t);
|
render_target.texture = texture_owner.make_rid(t);
|
||||||
_update_render_target(&render_target);
|
_update_render_target_color(&render_target);
|
||||||
return render_target_owner.make_rid(render_target);
|
return render_target_owner.make_rid(render_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2708,7 +2763,7 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
|
||||||
rt->size = Size2i(p_width, p_height);
|
rt->size = Size2i(p_width, p_height);
|
||||||
rt->view_count = p_view_count;
|
rt->view_count = p_view_count;
|
||||||
|
|
||||||
_update_render_target(rt);
|
_update_render_target_color(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: convert to Size2i internally
|
// TODO: convert to Size2i internally
|
||||||
|
@ -2727,9 +2782,10 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
|
||||||
// Remember what our current color output is.
|
// Remember what our current color output is.
|
||||||
RID was_color_texture = render_target_get_texture(p_render_target);
|
RID was_color_texture = render_target_get_texture(p_render_target);
|
||||||
|
|
||||||
rt->overridden.velocity = p_velocity_texture;
|
bool create_new_color_fbo = true;
|
||||||
|
bool create_new_velocity_fbo = true;
|
||||||
|
|
||||||
if (rt->overridden.color == p_color_texture && rt->overridden.depth == p_depth_texture) {
|
if (rt->overridden.color == p_color_texture && rt->overridden.depth == p_depth_texture && rt->overridden.velocity == p_velocity_texture && rt->overridden.velocity_depth == p_velocity_depth_texture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2740,8 +2796,8 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
|
||||||
}
|
}
|
||||||
|
|
||||||
_clear_render_target(rt);
|
_clear_render_target(rt);
|
||||||
_update_render_target(rt);
|
_update_render_target_color(rt);
|
||||||
return;
|
create_new_color_fbo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rt->overridden.is_overridden) {
|
if (!rt->overridden.is_overridden) {
|
||||||
|
@ -2751,6 +2807,8 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
|
||||||
rt->overridden.color = p_color_texture;
|
rt->overridden.color = p_color_texture;
|
||||||
rt->overridden.depth = p_depth_texture;
|
rt->overridden.depth = p_depth_texture;
|
||||||
rt->overridden.depth_has_stencil = p_depth_texture.is_null();
|
rt->overridden.depth_has_stencil = p_depth_texture.is_null();
|
||||||
|
rt->overridden.velocity = p_velocity_texture;
|
||||||
|
rt->overridden.velocity_depth = p_velocity_depth_texture;
|
||||||
rt->overridden.is_overridden = true;
|
rt->overridden.is_overridden = true;
|
||||||
|
|
||||||
// Update to our new color output.
|
// Update to our new color output.
|
||||||
|
@ -2771,25 +2829,51 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
|
||||||
rt->depth_has_stencil = cache->get().depth_has_stencil;
|
rt->depth_has_stencil = cache->get().depth_has_stencil;
|
||||||
rt->size = cache->get().size;
|
rt->size = cache->get().size;
|
||||||
rt->texture = p_color_texture;
|
rt->texture = p_color_texture;
|
||||||
return;
|
create_new_color_fbo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_update_render_target(rt);
|
uint32_t velocity_hash_key = hash_murmur3_one_64(p_velocity_texture.get_id());
|
||||||
|
velocity_hash_key = hash_murmur3_one_64(p_velocity_depth_texture.get_id(), velocity_hash_key);
|
||||||
|
velocity_hash_key = hash_fmix32(velocity_hash_key);
|
||||||
|
|
||||||
RenderTarget::RTOverridden::FBOCacheEntry new_entry;
|
RBMap<uint32_t, GLuint>::Element *fbo = rt->overridden.velocity_fbo_cache.find(velocity_hash_key);
|
||||||
new_entry.fbo = rt->fbo;
|
if (fbo != nullptr) {
|
||||||
new_entry.color = rt->color;
|
rt->overridden.velocity_fbo = fbo->get();
|
||||||
new_entry.depth = rt->depth;
|
create_new_velocity_fbo = false;
|
||||||
new_entry.depth_has_stencil = rt->depth_has_stencil;
|
|
||||||
new_entry.size = rt->size;
|
|
||||||
// Keep track of any textures we had to allocate because they weren't overridden.
|
|
||||||
if (p_color_texture.is_null()) {
|
|
||||||
new_entry.allocated_textures.push_back(rt->color);
|
|
||||||
}
|
}
|
||||||
if (p_depth_texture.is_null()) {
|
|
||||||
new_entry.allocated_textures.push_back(rt->depth);
|
if (p_velocity_texture.is_null()) {
|
||||||
|
for (KeyValue<uint32_t, GLuint> &E : rt->overridden.velocity_fbo_cache) {
|
||||||
|
glDeleteFramebuffers(1, &E.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt->overridden.velocity_fbo_cache.clear();
|
||||||
|
rt->overridden.velocity_fbo = 0;
|
||||||
|
create_new_velocity_fbo = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_new_color_fbo) {
|
||||||
|
_update_render_target_color(rt);
|
||||||
|
|
||||||
|
RenderTarget::RTOverridden::FBOCacheEntry new_entry;
|
||||||
|
new_entry.fbo = rt->fbo;
|
||||||
|
new_entry.color = rt->color;
|
||||||
|
new_entry.depth = rt->depth;
|
||||||
|
new_entry.size = rt->size;
|
||||||
|
// Keep track of any textures we had to allocate because they weren't overridden.
|
||||||
|
if (p_color_texture.is_null()) {
|
||||||
|
new_entry.allocated_textures.push_back(rt->color);
|
||||||
|
}
|
||||||
|
if (p_depth_texture.is_null()) {
|
||||||
|
new_entry.allocated_textures.push_back(rt->depth);
|
||||||
|
}
|
||||||
|
rt->overridden.fbo_cache.insert(hash_key, new_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_new_velocity_fbo) {
|
||||||
|
_update_render_target_velocity(rt);
|
||||||
|
rt->overridden.velocity_fbo_cache.insert(velocity_hash_key, rt->overridden.velocity_fbo);
|
||||||
}
|
}
|
||||||
rt->overridden.fbo_cache.insert(hash_key, new_entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
|
RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
|
||||||
|
@ -2813,6 +2897,13 @@ RID TextureStorage::render_target_get_override_velocity(RID p_render_target) con
|
||||||
return rt->overridden.velocity;
|
return rt->overridden.velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RID TextureStorage::render_target_get_override_velocity_depth(RID p_render_target) const {
|
||||||
|
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||||
|
ERR_FAIL_NULL_V(rt, RID());
|
||||||
|
|
||||||
|
return rt->overridden.velocity_depth;
|
||||||
|
}
|
||||||
|
|
||||||
void TextureStorage::render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) {
|
void TextureStorage::render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) {
|
||||||
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||||
ERR_FAIL_NULL(rt);
|
ERR_FAIL_NULL(rt);
|
||||||
|
@ -2838,6 +2929,20 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) {
|
||||||
return rt->texture;
|
return rt->texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureStorage::render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) {
|
||||||
|
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||||
|
ERR_FAIL_NULL(rt);
|
||||||
|
|
||||||
|
rt->velocity_target_size = p_target_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size2i TextureStorage::render_target_get_velocity_target_size(RID p_render_target) const {
|
||||||
|
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||||
|
ERR_FAIL_NULL_V(rt, Size2i(0, 0));
|
||||||
|
|
||||||
|
return rt->velocity_target_size;
|
||||||
|
}
|
||||||
|
|
||||||
void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) {
|
void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) {
|
||||||
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
|
||||||
ERR_FAIL_NULL(rt);
|
ERR_FAIL_NULL(rt);
|
||||||
|
@ -2846,7 +2951,7 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_t
|
||||||
|
|
||||||
if (rt->overridden.color.is_null()) {
|
if (rt->overridden.color.is_null()) {
|
||||||
_clear_render_target(rt);
|
_clear_render_target(rt);
|
||||||
_update_render_target(rt);
|
_update_render_target_color(rt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2872,8 +2977,9 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo
|
||||||
rt->overridden.color = RID();
|
rt->overridden.color = RID();
|
||||||
rt->overridden.depth = RID();
|
rt->overridden.depth = RID();
|
||||||
rt->overridden.velocity = RID();
|
rt->overridden.velocity = RID();
|
||||||
|
rt->overridden.velocity_depth = RID();
|
||||||
}
|
}
|
||||||
_update_render_target(rt);
|
_update_render_target_color(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const {
|
bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const {
|
||||||
|
@ -2909,7 +3015,7 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
|
||||||
|
|
||||||
_clear_render_target(rt);
|
_clear_render_target(rt);
|
||||||
rt->msaa = p_msaa;
|
rt->msaa = p_msaa;
|
||||||
_update_render_target(rt);
|
_update_render_target_color(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const {
|
RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const {
|
||||||
|
@ -2929,7 +3035,7 @@ void TextureStorage::render_target_set_use_hdr(RID p_render_target, bool p_use_h
|
||||||
|
|
||||||
_clear_render_target(rt);
|
_clear_render_target(rt);
|
||||||
rt->hdr = p_use_hdr_2d;
|
rt->hdr = p_use_hdr_2d;
|
||||||
_update_render_target(rt);
|
_update_render_target_color(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureStorage::render_target_is_using_hdr(RID p_render_target) const {
|
bool TextureStorage::render_target_is_using_hdr(RID p_render_target) const {
|
||||||
|
|
|
@ -359,6 +359,8 @@ struct RenderTarget {
|
||||||
GLuint backbuffer_depth = 0;
|
GLuint backbuffer_depth = 0;
|
||||||
bool depth_has_stencil = true;
|
bool depth_has_stencil = true;
|
||||||
|
|
||||||
|
Size2i velocity_target_size;
|
||||||
|
|
||||||
bool hdr = false; // For Compatibility this effects both 2D and 3D rendering!
|
bool hdr = false; // For Compatibility this effects both 2D and 3D rendering!
|
||||||
GLuint color_internal_format = GL_RGBA8;
|
GLuint color_internal_format = GL_RGBA8;
|
||||||
GLuint color_format = GL_RGBA;
|
GLuint color_format = GL_RGBA;
|
||||||
|
@ -390,6 +392,7 @@ struct RenderTarget {
|
||||||
RID color;
|
RID color;
|
||||||
RID depth;
|
RID depth;
|
||||||
RID velocity;
|
RID velocity;
|
||||||
|
RID velocity_depth;
|
||||||
|
|
||||||
struct FBOCacheEntry {
|
struct FBOCacheEntry {
|
||||||
GLuint fbo;
|
GLuint fbo;
|
||||||
|
@ -400,6 +403,9 @@ struct RenderTarget {
|
||||||
bool depth_has_stencil;
|
bool depth_has_stencil;
|
||||||
};
|
};
|
||||||
RBMap<uint32_t, FBOCacheEntry> fbo_cache;
|
RBMap<uint32_t, FBOCacheEntry> fbo_cache;
|
||||||
|
|
||||||
|
GLuint velocity_fbo = 0;
|
||||||
|
RBMap<uint32_t, GLuint> velocity_fbo_cache;
|
||||||
} overridden;
|
} overridden;
|
||||||
|
|
||||||
RID texture;
|
RID texture;
|
||||||
|
@ -464,7 +470,8 @@ private:
|
||||||
mutable RID_Owner<RenderTarget> render_target_owner;
|
mutable RID_Owner<RenderTarget> render_target_owner;
|
||||||
|
|
||||||
void _clear_render_target(RenderTarget *rt);
|
void _clear_render_target(RenderTarget *rt);
|
||||||
void _update_render_target(RenderTarget *rt);
|
void _update_render_target_color(RenderTarget *rt);
|
||||||
|
void _update_render_target_velocity(RenderTarget *rt);
|
||||||
void _create_render_target_backbuffer(RenderTarget *rt);
|
void _create_render_target_backbuffer(RenderTarget *rt);
|
||||||
void _render_target_allocate_sdf(RenderTarget *rt);
|
void _render_target_allocate_sdf(RenderTarget *rt);
|
||||||
void _render_target_clear_sdf(RenderTarget *rt);
|
void _render_target_clear_sdf(RenderTarget *rt);
|
||||||
|
@ -707,15 +714,15 @@ public:
|
||||||
virtual RID render_target_get_override_color(RID p_render_target) const override;
|
virtual RID render_target_get_override_color(RID p_render_target) const override;
|
||||||
virtual RID render_target_get_override_depth(RID p_render_target) const override;
|
virtual RID render_target_get_override_depth(RID p_render_target) const override;
|
||||||
virtual RID render_target_get_override_velocity(RID p_render_target) const override;
|
virtual RID render_target_get_override_velocity(RID p_render_target) const override;
|
||||||
virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); }
|
virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override;
|
||||||
|
|
||||||
virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) override;
|
virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) override;
|
||||||
virtual Rect2i render_target_get_render_region(RID p_render_target) const override;
|
virtual Rect2i render_target_get_render_region(RID p_render_target) const override;
|
||||||
|
|
||||||
virtual RID render_target_get_texture(RID p_render_target) override;
|
virtual RID render_target_get_texture(RID p_render_target) override;
|
||||||
|
|
||||||
virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}
|
virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override;
|
||||||
virtual Size2i render_target_get_velocity_target_size(RID p_render_target) const override { return Size2i(); }
|
virtual Size2i render_target_get_velocity_target_size(RID p_render_target) const override;
|
||||||
|
|
||||||
void bind_framebuffer(GLuint framebuffer) {
|
void bind_framebuffer(GLuint framebuffer) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue