From 4428115916144b45c4697cd65d9c8c093631bec6 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 19 Oct 2016 11:14:41 -0300 Subject: Everything returning to normal in 3D, still a long way to go -implemented the scene part of visual server and rasterizer, objects without lighting and material are rendererd only --- servers/visual/visual_server_scene.cpp | 1517 ++++++++++++++++++++++++++++++++ 1 file changed, 1517 insertions(+) create mode 100644 servers/visual/visual_server_scene.cpp (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp new file mode 100644 index 000000000..a3b1d76fb --- /dev/null +++ b/servers/visual/visual_server_scene.cpp @@ -0,0 +1,1517 @@ +#include "visual_server_scene.h" +#include "visual_server_global.h" + +/* CAMERA API */ + + +RID VisualServerScene::camera_create() { + + Camera * camera = memnew( Camera ); + return camera_owner.make_rid( camera ); + +} + +void VisualServerScene::camera_set_perspective(RID p_camera,float p_fovy_degrees, float p_z_near, float p_z_far) { + + Camera *camera = camera_owner.get( p_camera ); + ERR_FAIL_COND(!camera); + camera->type=Camera::PERSPECTIVE; + camera->fov=p_fovy_degrees; + camera->znear=p_z_near; + camera->zfar=p_z_far; + +} + +void VisualServerScene::camera_set_orthogonal(RID p_camera,float p_size, float p_z_near, float p_z_far) { + + Camera *camera = camera_owner.get( p_camera ); + ERR_FAIL_COND(!camera); + camera->type=Camera::ORTHOGONAL; + camera->size=p_size; + camera->znear=p_z_near; + camera->zfar=p_z_far; +} + +void VisualServerScene::camera_set_transform(RID p_camera,const Transform& p_transform) { + + Camera *camera = camera_owner.get( p_camera ); + ERR_FAIL_COND(!camera); + camera->transform=p_transform.orthonormalized(); + + +} + +void VisualServerScene::camera_set_cull_mask(RID p_camera,uint32_t p_layers) { + + + Camera *camera = camera_owner.get( p_camera ); + ERR_FAIL_COND(!camera); + + camera->visible_layers=p_layers; + +} + +void VisualServerScene::camera_set_environment(RID p_camera,RID p_env) { + + Camera *camera = camera_owner.get( p_camera ); + ERR_FAIL_COND(!camera); + camera->env=p_env; + +} + + +void VisualServerScene::camera_set_use_vertical_aspect(RID p_camera,bool p_enable) { + + Camera *camera = camera_owner.get( p_camera ); + ERR_FAIL_COND(!camera); + camera->vaspect=p_enable; + +} + + + +/* ENVIRONMENT API */ + +RID VisualServerScene::environment_create(){ + + return RID(); +} + +void VisualServerScene::environment_set_background(RID p_env,VS::EnvironmentBG p_bg){ + +} +void VisualServerScene::environment_set_skybox(RID p_env,RID p_skybox,float p_energy){ + +} +void VisualServerScene::environment_set_bg_color(RID p_env,const Color& p_color){ + +} +void VisualServerScene::environment_set_canvas_max_layer(RID p_env,int p_max_layer){ + +} +void VisualServerScene::environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy){ + +} + +void VisualServerScene::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode){ + +} +void VisualServerScene::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){ + +} + +void VisualServerScene::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){ + +} +void VisualServerScene::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){ + +} +void VisualServerScene::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){ + +} +void VisualServerScene::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){ + +} +void VisualServerScene::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){ + +} + + +/* SCENARIO API */ + + + +void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int) { + +// VisualServerScene *self = (VisualServerScene*)p_self; + Instance *A = p_A; + Instance *B = p_B; + + //instance indices are designed so greater always contains lesser + if (A->base_type > B->base_type) { + SWAP(A,B); //lesser always first + } + + if (B->base_type==VS::INSTANCE_LIGHT && (1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceLightData * light = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + + InstanceLightData::PairInfo pinfo; + pinfo.geometry=A; + pinfo.L = geom->lighting.push_back(B); + + List::Element *E = light->geometries.push_back(pinfo); + + light->shadow_sirty=true; + geom->lighting_dirty=true; + + return E; //this element should make freeing faster + } + +#if 0 + if (A->base_type==INSTANCE_PORTAL) { + + ERR_FAIL_COND_V( B->base_type!=INSTANCE_PORTAL,NULL ); + + A->portal_info->candidate_set.insert(B); + B->portal_info->candidate_set.insert(A); + + self->_portal_attempt_connect(A); + //attempt to conncet portal A (will go through B anyway) + //this is a little hackish, but works fine in practice + + } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) { + + if (B->base_type==INSTANCE_BAKED_LIGHT) { + SWAP(A,B); + } + + ERR_FAIL_COND_V(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER,NULL); + B->baked_light_sampler_info->baked_lights.insert(A); + + } else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) { + + if (B->base_type==INSTANCE_ROOM) + SWAP(A,B); + + ERR_FAIL_COND_V(! ((1<base_type)&INSTANCE_GEOMETRY_MASK ),NULL); + + B->auto_rooms.insert(A); + A->room_info->owned_autoroom_geometry.insert(B); + + self->_instance_validate_autorooms(B); + + + } else { + + if (B->base_type==INSTANCE_LIGHT) { + + SWAP(A,B); + } else if (A->base_type!=INSTANCE_LIGHT) { + return NULL; + } + + + A->light_info->affected.insert(B); + B->lights.insert(A); + B->light_cache_dirty=true; + + + } +#endif + + return NULL; + +} +void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int,void* udata) { + +// VisualServerScene *self = (VisualServerScene*)p_self; + Instance *A = p_A; + Instance *B = p_B; + + //instance indices are designed so greater always contains lesser + if (A->base_type > B->base_type) { + SWAP(A,B); //lesser always first + } + + + + if (B->base_type==VS::INSTANCE_LIGHT && (1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceLightData * light = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + List::Element *E = reinterpret_cast::Element*>(udata); + + geom->lighting.erase(E->get().L); + light->geometries.erase(E); + + light->shadow_sirty=true; + geom->lighting_dirty=true; + + + } +#if 0 + if (A->base_type==INSTANCE_PORTAL) { + + ERR_FAIL_COND( B->base_type!=INSTANCE_PORTAL ); + + + A->portal_info->candidate_set.erase(B); + B->portal_info->candidate_set.erase(A); + + //after disconnecting them, see if they can connect again + self->_portal_attempt_connect(A); + self->_portal_attempt_connect(B); + + } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) { + + if (B->base_type==INSTANCE_BAKED_LIGHT) { + SWAP(A,B); + } + + ERR_FAIL_COND(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER); + B->baked_light_sampler_info->baked_lights.erase(A); + + } else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) { + + if (B->base_type==INSTANCE_ROOM) + SWAP(A,B); + + ERR_FAIL_COND(! ((1<base_type)&INSTANCE_GEOMETRY_MASK )); + + B->auto_rooms.erase(A); + B->valid_auto_rooms.erase(A); + A->room_info->owned_autoroom_geometry.erase(B); + + }else { + + + + if (B->base_type==INSTANCE_LIGHT) { + + SWAP(A,B); + } else if (A->base_type!=INSTANCE_LIGHT) { + return; + } + + + A->light_info->affected.erase(B); + B->lights.erase(A); + B->light_cache_dirty=true; + + } +#endif +} + +RID VisualServerScene::scenario_create() { + + Scenario *scenario = memnew( Scenario ); + ERR_FAIL_COND_V(!scenario,RID()); + RID scenario_rid = scenario_owner.make_rid( scenario ); + scenario->self=scenario_rid; + + scenario->octree.set_pair_callback(_instance_pair,this); + scenario->octree.set_unpair_callback(_instance_unpair,this); + + return scenario_rid; +} + +void VisualServerScene::scenario_set_debug(RID p_scenario,VS::ScenarioDebugMode p_debug_mode) { + + Scenario *scenario = scenario_owner.get(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->debug=p_debug_mode; +} + +void VisualServerScene::scenario_set_environment(RID p_scenario, RID p_environment) { + + Scenario *scenario = scenario_owner.get(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->environment=p_environment; + +} + +void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_environment) { + + + Scenario *scenario = scenario_owner.get(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->fallback_environment=p_environment; + + +} + + + +/* INSTANCING API */ + +void VisualServerScene::_instance_queue_update(Instance *p_instance,bool p_update_aabb,bool p_update_materials) { + + if (p_update_aabb) + p_instance->update_aabb=true; + if (p_update_materials) + p_instance->update_materials=true; + + if (p_instance->update_item.in_list()) + return; + + _instance_update_list.add(&p_instance->update_item); + + +} + +// from can be mesh, light, area and portal so far. +RID VisualServerScene::instance_create(){ + + Instance *instance = memnew( Instance ); + ERR_FAIL_COND_V(!instance,RID()); + + RID instance_rid = instance_owner.make_rid(instance); + instance->self=instance_rid; + + + return instance_rid; + + +} + +void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ + + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + Scenario *scenario = instance->scenario; + + if (instance->base_type!=VS::INSTANCE_NONE) { + //free anything related to that base + + VSG::storage->instance_remove_dependency(instance->base,instance); + + if (scenario && instance->octree_id) { + scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away + instance->octree_id=0; + } + + switch(instance->base_type) { + case VS::INSTANCE_LIGHT: { + + InstanceLightData *light = static_cast(instance->base_data); + + if (instance->scenario && light->D) { + instance->scenario->directional_lights.erase( light->D ); + light->D=NULL; + } + VSG::scene_render->free(light->instance); + + } + } + + if (instance->base_data) { + memdelete( instance->base_data ); + instance->base_data=NULL; + } + + instance->morph_values.clear(); + instance->materials.clear(); + +#if 0 + if (instance->light_info) { + + if (instance->scenario && instance->light_info->D) + instance->scenario->directional_lights.erase( instance->light_info->D ); + rasterizer->free(instance->light_info->instance); + memdelete(instance->light_info); + instance->light_info=NULL; + } + + + + if ( instance->room ) { + + instance_set_room(p_instance,RID()); + /* + if((1<base_type)&INSTANCE_GEOMETRY_MASK) + instance->room->room_info->owned_geometry_instances.erase(instance->RE); + else if (instance->base_type==INSTANCE_PORTAL) { + print_line("freeing portal, is it there? "+itos(instance->room->room_info->owned_portal_instances.(instance->RE))); + instance->room->room_info->owned_portal_instances.erase(instance->RE); + } else if (instance->base_type==INSTANCE_ROOM) + instance->room->room_info->owned_room_instances.erase(instance->RE); + else if (instance->base_type==INSTANCE_LIGHT) + instance->room->room_info->owned_light_instances.erase(instance->RE); + + instance->RE=NULL;*/ + } + + + + + + + if (instance->portal_info) { + + _portal_disconnect(instance,true); + memdelete(instance->portal_info); + instance->portal_info=NULL; + + } + + if (instance->baked_light_info) { + + while(instance->baked_light_info->owned_instances.size()) { + + Instance *owned=instance->baked_light_info->owned_instances.front()->get(); + owned->baked_light=NULL; + owned->data.baked_light=NULL; + owned->data.baked_light_octree_xform=NULL; + owned->BLE=NULL; + instance->baked_light_info->owned_instances.pop_front(); + } + + memdelete(instance->baked_light_info); + instance->baked_light_info=NULL; + + } + + if (instance->scenario && instance->octree_id) { + instance->scenario->octree.erase( instance->octree_id ); + instance->octree_id=0; + } + + + if (instance->room_info) { + + for(List::Element *E=instance->room_info->owned_geometry_instances.front();E;E=E->next()) { + + Instance *owned = E->get(); + owned->room=NULL; + owned->RE=NULL; + } + for(List::Element *E=instance->room_info->owned_portal_instances.front();E;E=E->next()) { + + _portal_disconnect(E->get(),true); + Instance *owned = E->get(); + owned->room=NULL; + owned->RE=NULL; + } + + for(List::Element *E=instance->room_info->owned_room_instances.front();E;E=E->next()) { + + Instance *owned = E->get(); + owned->room=NULL; + owned->RE=NULL; + } + + if (instance->room_info->disconnected_child_portals.size()) { + ERR_PRINT("BUG: Disconnected portals remain!"); + } + memdelete(instance->room_info); + instance->room_info=NULL; + + } + + if (instance->particles_info) { + + rasterizer->free( instance->particles_info->instance ); + memdelete(instance->particles_info); + instance->particles_info=NULL; + + } + + if (instance->baked_light_sampler_info) { + + while (instance->baked_light_sampler_info->owned_instances.size()) { + + instance_geometry_set_baked_light_sampler(instance->baked_light_sampler_info->owned_instances.front()->get()->self,RID()); + } + + if (instance->baked_light_sampler_info->sampled_light.is_valid()) { + rasterizer->free(instance->baked_light_sampler_info->sampled_light); + } + memdelete( instance->baked_light_sampler_info ); + instance->baked_light_sampler_info=NULL; + } +#endif + + } + + + instance->base_type=VS::INSTANCE_NONE; + instance->base=RID(); + + + if (p_base.is_valid()) { + + instance->base_type=VSG::storage->get_base_type(p_base); + ERR_FAIL_COND(instance->base_type==VS::INSTANCE_NONE); + + switch(instance->base_type) { + case VS::INSTANCE_LIGHT: { + + InstanceLightData *light = memnew( InstanceLightData ); + + if (scenario && VSG::storage->light_get_type(p_base)==VS::LIGHT_DIRECTIONAL) { + light->D = scenario->directional_lights.push_back(instance); + } + + light->instance = VSG::scene_render->light_instance_create(p_base); + + instance->base_data=light; + } + case VS::INSTANCE_MESH: { + + InstanceGeometryData *geom = memnew( InstanceGeometryData ); + instance->base_data=geom; + } + + } + + VSG::storage->instance_add_dependency(p_base,instance); + + instance->base=p_base; + + if (scenario) + _instance_queue_update(instance,true,true); + + +#if 0 + if (rasterizer->is_mesh(p_base)) { + instance->base_type=INSTANCE_MESH; + instance->data.morph_values.resize( rasterizer->mesh_get_morph_target_count(p_base)); + instance->data.materials.resize( rasterizer->mesh_get_surface_count(p_base)); + } else if (rasterizer->is_multimesh(p_base)) { + instance->base_type=INSTANCE_MULTIMESH; + } else if (rasterizer->is_immediate(p_base)) { + instance->base_type=INSTANCE_IMMEDIATE; + } else if (rasterizer->is_particles(p_base)) { + instance->base_type=INSTANCE_PARTICLES; + instance->particles_info=memnew( Instance::ParticlesInfo ); + instance->particles_info->instance = rasterizer->particles_instance_create( p_base ); + } else if (rasterizer->is_light(p_base)) { + + instance->base_type=INSTANCE_LIGHT; + instance->light_info = memnew( Instance::LightInfo ); + instance->light_info->instance = rasterizer->light_instance_create(p_base); + if (instance->scenario && rasterizer->light_get_type(p_base)==LIGHT_DIRECTIONAL) { + + instance->light_info->D = instance->scenario->directional_lights.push_back(instance->self); + } + + } else if (room_owner.owns(p_base)) { + instance->base_type=INSTANCE_ROOM; + instance->room_info = memnew( Instance::RoomInfo ); + instance->room_info->room=room_owner.get(p_base); + } else if (portal_owner.owns(p_base)) { + + instance->base_type=INSTANCE_PORTAL; + instance->portal_info = memnew(Instance::PortalInfo); + instance->portal_info->portal=portal_owner.get(p_base); + } else if (baked_light_owner.owns(p_base)) { + + instance->base_type=INSTANCE_BAKED_LIGHT; + instance->baked_light_info=memnew(Instance::BakedLightInfo); + instance->baked_light_info->baked_light=baked_light_owner.get(p_base); + + //instance->portal_info = memnew(Instance::PortalInfo); + //instance->portal_info->portal=portal_owner.get(p_base); + } else if (baked_light_sampler_owner.owns(p_base)) { + + + instance->base_type=INSTANCE_BAKED_LIGHT_SAMPLER; + instance->baked_light_sampler_info=memnew( Instance::BakedLightSamplerInfo); + instance->baked_light_sampler_info->sampler=baked_light_sampler_owner.get(p_base); + + //instance->portal_info = memnew(Instance::PortalInfo); + //instance->portal_info->portal=portal_owner.get(p_base); + + } else { + ERR_EXPLAIN("Invalid base RID for instance!") + ERR_FAIL(); + } + + instance_dependency_map[ p_base ].insert( instance->self ); +#endif + + + } +} +void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){ + + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + if (instance->scenario) { + + instance->scenario->instances.remove( &instance->scenario_item ); + + if (instance->octree_id) { + instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away + instance->octree_id=0; + } + + + switch(instance->base_type) { + + case VS::INSTANCE_LIGHT: { + + + InstanceLightData *light = static_cast(instance->base_data); + + if (light->D) { + instance->scenario->directional_lights.erase( light->D ); + light->D=NULL; + } + } + } + + instance->scenario=NULL; + } + + + if (p_scenario.is_valid()) { + + Scenario *scenario = scenario_owner.get( p_scenario ); + ERR_FAIL_COND(!scenario); + + instance->scenario=scenario; + + scenario->instances.add( &instance->scenario_item ); + + + switch(instance->base_type) { + + case VS::INSTANCE_LIGHT: { + + + InstanceLightData *light = static_cast(instance->base_data); + + if (VSG::storage->light_get_type(instance->base)==VS::LIGHT_DIRECTIONAL) { + light->D = scenario->directional_lights.push_back(instance); + } + } + } + + _instance_queue_update(instance,true,true); + } +} +void VisualServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask){ + + + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + instance->layer_mask=p_mask; +} +void VisualServerScene::instance_set_transform(RID p_instance, const Transform& p_transform){ + + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + if (instance->transform==p_transform) + return; //must be checked to avoid worst evil + + instance->transform=p_transform; + _instance_queue_update(instance,true); +} +void VisualServerScene::instance_attach_object_instance_ID(RID p_instance,ObjectID p_ID){ + + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + instance->object_ID=p_ID; + +} +void VisualServerScene::instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight){ + +} +void VisualServerScene::instance_set_surface_material(RID p_instance,int p_surface, RID p_material){ + + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + _update_dirty_instance(instance); + + ERR_FAIL_INDEX(p_surface,instance->materials.size()); + + instance->materials[p_surface]=p_material; + +} + +void VisualServerScene::instance_attach_skeleton(RID p_instance,RID p_skeleton){ + + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + instance->skeleton=p_skeleton; + + _instance_queue_update(instance,true); +} + +void VisualServerScene::instance_set_exterior( RID p_instance, bool p_enabled ){ + +} +void VisualServerScene::instance_set_room( RID p_instance, RID p_room ){ + +} + +void VisualServerScene::instance_set_extra_visibility_margin( RID p_instance, real_t p_margin ){ + +} + +// don't use these in a game! +Vector VisualServerScene::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{ + + return Vector(); +} + +Vector VisualServerScene::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{ + + return Vector(); +} +Vector VisualServerScene::instances_cull_convex(const Vector& p_convex, RID p_scenario) const { + + return Vector(); +} + + +void VisualServerScene::instance_geometry_set_flag(RID p_instance,VS::InstanceFlags p_flags,bool p_enabled){ + +} +void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) { + +} +void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material){ + +} + + +void VisualServerScene::instance_geometry_set_draw_range(RID p_instance,float p_min,float p_max,float p_min_margin,float p_max_margin){ + +} +void VisualServerScene::instance_geometry_set_as_instance_lod(RID p_instance,RID p_as_lod_of_instance){ + +} + + +void VisualServerScene::_update_instance(Instance *p_instance) { + + p_instance->version++; + + if (p_instance->base_type == VS::INSTANCE_LIGHT) { + + InstanceLightData *light = static_cast(p_instance->base_data); + + VSG::scene_render->light_instance_set_transform( light->instance, p_instance->transform ); + + } + + + if (p_instance->aabb.has_no_surface()) + return; + +#if 0 + if (p_instance->base_type == VS::INSTANCE_PARTICLES) { + + rasterizer->particles_instance_set_transform( p_instance->particles_info->instance, p_instance->data.transform ); + } + +#endif + if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceGeometryData *geom = static_cast(p_instance->base_data); + //make sure lights are updated + + for (List::Element *E=geom->lighting.front();E;E=E->next()) { + InstanceLightData *light = static_cast(E->get()->base_data); + light->shadow_sirty=true; + } + + } +#if 0 + else if (p_instance->base_type == INSTANCE_ROOM) { + + p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse(); + } else if (p_instance->base_type == INSTANCE_BAKED_LIGHT) { + + Transform scale; + scale.basis.scale(p_instance->baked_light_info->baked_light->octree_aabb.size); + scale.origin=p_instance->baked_light_info->baked_light->octree_aabb.pos; + //print_line("scale: "+scale); + p_instance->baked_light_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse(); + } + + +#endif + + p_instance->mirror = p_instance->transform.basis.determinant() < 0.0; + + AABB new_aabb; +#if 0 + if (p_instance->base_type==INSTANCE_PORTAL) { + + //portals need to be transformed in a special way, so they don't become too wide if they have scale.. + Transform portal_xform = p_instance->data.transform; + portal_xform.basis.set_axis(2,portal_xform.basis.get_axis(2).normalized()); + + p_instance->portal_info->plane_cache=Plane( p_instance->data.transform.origin, portal_xform.basis.get_axis(2)); + int point_count=p_instance->portal_info->portal->shape.size(); + p_instance->portal_info->transformed_point_cache.resize(point_count); + + AABB portal_aabb; + + for(int i=0;iportal_info->portal->shape[i]; + Vector3 point = portal_xform.xform(Vector3(src.x,src.y,0)); + p_instance->portal_info->transformed_point_cache[i]=point; + if (i==0) + portal_aabb.pos=point; + else + portal_aabb.expand_to(point); + } + + portal_aabb.grow_by(p_instance->portal_info->portal->connect_range); + + new_aabb = portal_aabb; + + } else { +#endif + new_aabb = p_instance->transform.xform(p_instance->aabb); +#if 0 + } +#endif + + + p_instance->transformed_aabb=new_aabb; + + if (!p_instance->scenario) { + + return; + } + + + + if (p_instance->octree_id==0) { + + uint32_t base_type = 1<base_type; + uint32_t pairable_mask=0; + bool pairable=false; + + if (p_instance->base_type == VS::INSTANCE_LIGHT) { + + pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK:0; + pairable=true; + } +#if 0 + + if (p_instance->base_type == VS::INSTANCE_PORTAL) { + + pairable_mask=(1<base_type == VS::INSTANCE_BAKED_LIGHT_SAMPLER) { + + pairable_mask=(1<room && (1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + base_type|=VS::INSTANCE_ROOMLESS_MASK; + } + + if (p_instance->base_type == VS::INSTANCE_ROOM) { + + pairable_mask=INSTANCE_ROOMLESS_MASK; + pairable=true; + } +#endif + + // not inside octree + p_instance->octree_id = p_instance->scenario->octree.create(p_instance,new_aabb,0,pairable,base_type,pairable_mask); + + } else { + + // if (new_aabb==p_instance->data.transformed_aabb) + // return; + + p_instance->scenario->octree.move(p_instance->octree_id,new_aabb); + } +#if 0 + if (p_instance->base_type==INSTANCE_PORTAL) { + + _portal_attempt_connect(p_instance); + } + + if (!p_instance->room && (1<base_type)&INSTANCE_GEOMETRY_MASK) { + + _instance_validate_autorooms(p_instance); + } + + if (p_instance->base_type == INSTANCE_ROOM) { + + for(Set::Element *E=p_instance->room_info->owned_autoroom_geometry.front();E;E=E->next()) + _instance_validate_autorooms(E->get()); + } +#endif + +} + +void VisualServerScene::_update_instance_aabb(Instance *p_instance) { + + AABB new_aabb; + + ERR_FAIL_COND(p_instance->base_type!=VS::INSTANCE_NONE && !p_instance->base.is_valid()); + + switch(p_instance->base_type) { + case VisualServer::INSTANCE_NONE: { + + // do nothing + } break; + case VisualServer::INSTANCE_MESH: { + + new_aabb = VSG::storage->mesh_get_aabb(p_instance->base,p_instance->skeleton); + + } break; +#if 0 + case VisualServer::INSTANCE_MULTIMESH: { + + new_aabb = rasterizer->multimesh_get_aabb(p_instance->base); + + } break; + case VisualServer::INSTANCE_IMMEDIATE: { + + new_aabb = rasterizer->immediate_get_aabb(p_instance->base); + + + } break; + case VisualServer::INSTANCE_PARTICLES: { + + new_aabb = rasterizer->particles_get_aabb(p_instance->base); + + + } break; +#endif + case VisualServer::INSTANCE_LIGHT: { + + new_aabb = VSG::storage->light_get_aabb(p_instance->base); + + } break; +#if 0 + case VisualServer::INSTANCE_ROOM: { + + Room *room = room_owner.get( p_instance->base ); + ERR_FAIL_COND(!room); + new_aabb=room->bounds.get_aabb(); + + } break; + case VisualServer::INSTANCE_PORTAL: { + + Portal *portal = portal_owner.get( p_instance->base ); + ERR_FAIL_COND(!portal); + for (int i=0;ishape.size();i++) { + + Vector3 point( portal->shape[i].x, portal->shape[i].y, 0 ); + if (i==0) { + + new_aabb.pos=point; + new_aabb.size.z=0.01; // make it not flat for octree + } else { + + new_aabb.expand_to(point); + } + } + + } break; + case VisualServer::INSTANCE_BAKED_LIGHT: { + + BakedLight *baked_light = baked_light_owner.get( p_instance->base ); + ERR_FAIL_COND(!baked_light); + new_aabb=baked_light->octree_aabb; + + } break; + case VisualServer::INSTANCE_BAKED_LIGHT_SAMPLER: { + + BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get( p_instance->base ); + ERR_FAIL_COND(!baked_light_sampler); + float radius = baked_light_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS]; + + new_aabb=AABB(Vector3(-radius,-radius,-radius),Vector3(radius*2,radius*2,radius*2)); + + } break; +#endif + default: {} + } + + if (p_instance->extra_margin) + new_aabb.grow_by(p_instance->extra_margin); + + p_instance->aabb=new_aabb; + +} + + + +void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size) { + + + + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + render_pass++; + uint32_t camera_layer_mask=camera->visible_layers; + + + /* STEP 1 - SETUP CAMERA */ + CameraMatrix camera_matrix; + bool ortho=false; + + switch(camera->type) { + case Camera::ORTHOGONAL: { + + camera_matrix.set_orthogonal( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect + + ); + ortho=true; + } break; + case Camera::PERSPECTIVE: { + + camera_matrix.set_perspective( + camera->fov, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect + + ); + ortho=false; + + } break; + } + + +// rasterizer->set_camera(camera->transform, camera_matrix,ortho); + + Vector planes = camera_matrix.get_projection_planes(camera->transform); + + Plane near_plane(camera->transform.origin,-camera->transform.basis.get_axis(2).normalized()); + + /* STEP 2 - CULL */ + int cull_count = scenario->octree.cull_convex(planes,instance_cull_result,MAX_INSTANCE_CULL); + light_cull_count=0; +// light_samplers_culled=0; + +/* print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0)); + print_line("OTO: "+itos(p_scenario->octree.get_octant_count())); +// print_line("OTE: "+itos(p_scenario->octree.get_elem_count())); + print_line("OTP: "+itos(p_scenario->octree.get_pair_count())); +*/ + + /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */ + + + // compute portals +#if 0 + exterior_visited=false; + exterior_portal_cull_count=0; + + if (room_cull_enabled) { + for(int i=0;ilast_render_pass=render_pass; + + if (ins->base_type!=INSTANCE_PORTAL) + continue; + + if (ins->room) + continue; + + ERR_CONTINUE(exterior_portal_cull_count>=MAX_EXTERIOR_PORTALS); + exterior_portal_cull_result[exterior_portal_cull_count++]=ins; + + } + + room_cull_count = p_scenario->octree.cull_point(camera->transform.origin,room_cull_result,MAX_ROOM_CULL,NULL,(1< current_rooms; + Set portal_rooms; + //add to set + for(int i=0;ibase_type==INSTANCE_ROOM) { + current_rooms.insert(room_cull_result[i]); + } + if (room_cull_result[i]->base_type==INSTANCE_PORTAL) { + //assume inside that room if also inside the portal.. + if (room_cull_result[i]->room) { + portal_rooms.insert(room_cull_result[i]->room); + } + + SWAP(room_cull_result[i],room_cull_result[room_cull_count-1]); + room_cull_count--; + i--; + } + } + + //remove from set if it has a parent room or BSP doesn't contain + for(int i=0;iroom_info->affine_inverse.xform( camera->transform.origin ); + + if (!portal_rooms.has(r) && !r->room_info->room->bounds.point_is_inside(room_local_point)) { + + current_rooms.erase(r); + continue; + } + + //check parent + while (r->room) {// has parent room + + current_rooms.erase(r); + r=r->room; + } + + } + + if (current_rooms.size()) { + //camera is inside a room + // go through rooms + for(Set::Element *E=current_rooms.front();E;E=E->next()) { + _cull_room(camera,E->get()); + } + + } else { + //start from exterior + _cull_room(camera,NULL); + + } + } + +#endif + /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */ + + for(int i=0;ilayer_mask)==0) { + + //failure + } else if (ins->base_type==VS::INSTANCE_LIGHT && ins->visible) { + + if (light_cull_count(ins->base_data); + + if (!light->geometries.empty()) { + //do not add this light if no geometry is affected by it.. + light_cull_result[light_cull_count]=ins; + light_instance_cull_result[light_cull_count]=light->instance; + + light_cull_count++; + } + +// rasterizer->light_instance_set_active_hint(ins->light_info->instance); + } + + } else if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + + keep=true; +#if 0 + bool discarded=false; + + if (ins->draw_range_end>0) { + + float d = cull_range.nearp.distance_to(ins->data.transform.origin); + if (d<0) + d=0; + discarded=(ddraw_range_begin || d>=ins->draw_range_end); + + + } + + if (!discarded) { + + // test if this geometry should be visible + + if (room_cull_enabled) { + + + if (ins->visible_in_all_rooms) { + keep=true; + } else if (ins->room) { + + if (ins->room->room_info->last_visited_pass==render_pass) + keep=true; + } else if (ins->auto_rooms.size()) { + + + for(Set::Element *E=ins->auto_rooms.front();E;E=E->next()) { + + if (E->get()->room_info->last_visited_pass==render_pass) { + keep=true; + break; + } + } + } else if(exterior_visited) + keep=true; + } else { + + keep=true; + } + + + } + + + if (keep) { + // update cull range + float min,max; + ins->transformed_aabb.project_range_in_plane(cull_range.nearp,min,max); + + if (mincull_range.max) + cull_range.max=max; + + if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) { + if (light_samplers_culledsampled_light; + ins->sampled_light->baked_light_sampler_info->last_pass=render_pass; + } + } + } +#endif + + + InstanceGeometryData * geom = static_cast(ins->base_data); + + if (geom->lighting_dirty) { + int l=0; + //only called when lights AABB enter/exit this geometry + ins->light_instances.resize(geom->lighting.size()); + + for (List::Element *E=geom->lighting.front();E;E=E->next()) { + + InstanceLightData * light = static_cast(E->get()->base_data); + + ins->light_instances[l++]=light->instance; + } + + geom->lighting_dirty=false; + } + + } + + if (!keep) { + // remove, no reason to keep + cull_count--; + SWAP( instance_cull_result[i], instance_cull_result[ cull_count ] ); + i--; + ins->last_render_pass=0; // make invalid + } else { + + ins->last_render_pass=render_pass; + } + } + + /* STEP 5 - PROCESS LIGHTS */ + + RID *directional_light_ptr=&light_instance_cull_result[light_cull_count]; + int directional_light_count=0; + + // directional lights + { + for (List::Element *E=scenario->directional_lights.front();E;E=E->next()) { + + if (light_cull_count+directional_light_count>=MAX_LIGHTS_CULLED) { + break; + } + + if (!E->get()->visible) + continue; + + InstanceLightData * light = static_cast(E->get()->base_data); + + + //check shadow.. + + +/* if (light && light->light_info->enabled && rasterizer->light_has_shadow(light->base_rid)) { + //rasterizer->light_instance_set_active_hint(light->light_info->instance); + _light_instance_update_shadow(light,p_scenario,camera,cull_range); + } +*/ + + //add to list + + + directional_light_ptr[directional_light_count++]=light->instance; + + } + } + +#if 0 + { //this should eventually change to + //assign shadows by distance to camera + SortArray sorter; + sorter.sort(light_cull_result,light_cull_count); + for (int i=0;ilight_has_shadow(ins->base_rid) || !shadows_enabled) + continue; + + /* for far shadows? + if (ins->version == ins->light_info->last_version && rasterizer->light_instance_has_far_shadow(ins->light_info->instance)) + continue; // didn't change + */ + + _light_instance_update_shadow(ins,p_scenario,camera,cull_range); + ins->light_info->last_version=ins->version; + } + } +#endif + /* ENVIRONMENT */ + + RID environment; + if (camera->env.is_valid()) //camera has more environment priority + environment=camera->env; + else if (scenario->environment.is_valid()) + environment=scenario->environment; + else + environment=scenario->fallback_environment; + +#if 0 + /* STEP 6 - SAMPLE BAKED LIGHT */ + + bool islinear =false; + if (environment.is_valid()) { + islinear = rasterizer->environment_is_fx_enabled(environment,VS::ENV_FX_SRGB); + } + + for(int i=0;itransform,light_sampler_cull_result[i],islinear); + } +#endif + /* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/ + +#if 0 + // add lights + + { + List::Element *E=p_scenario->directional_lights.front(); + + + for(;E;E=E->next()) { + Instance *light = E->get().is_valid()?instance_owner.get(E->get()):NULL; + + ERR_CONTINUE(!light); + if (!light->light_info->enabled) + continue; + + rasterizer->add_light(light->light_info->instance); + light->light_info->last_add_pass=render_pass; + } + + for (int i=0;iadd_light(ins->light_info->instance); + ins->light_info->last_add_pass=render_pass; + } + } + // add geometry +#endif + + + VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count,directional_light_ptr,directional_light_count,environment); + +} + + + +void VisualServerScene::_update_dirty_instance(Instance *p_instance) { + + + if (p_instance->update_aabb) + _update_instance_aabb(p_instance); + + if (p_instance->update_materials) { + if (p_instance->base_type==VS::INSTANCE_MESH) { + p_instance->materials.resize(VSG::storage->mesh_get_surface_count(p_instance->base)); + } + } + + _update_instance(p_instance); + + p_instance->update_aabb=false; + p_instance->update_materials=false; + + _instance_update_list.remove( &p_instance->update_item ); +} + + +void VisualServerScene::update_dirty_instances() { + + while(_instance_update_list.first()) { + + _update_dirty_instance( _instance_update_list.first()->self() ); + } +} + +bool VisualServerScene::free(RID p_rid) { + + if (camera_owner.owns(p_rid)) { + + Camera *camera = camera_owner.get( p_rid ); + + camera_owner.free(p_rid); + memdelete(camera); + + } else if (scenario_owner.owns(p_rid)) { + + Scenario *scenario = scenario_owner.get( p_rid ); + + while(scenario->instances.first()) { + instance_set_scenario(scenario->instances.first()->self()->self,RID()); + } + + scenario_owner.free(p_rid); + memdelete(scenario); + + } else if (instance_owner.owns(p_rid)) { + // delete the instance + + update_dirty_instances(); + + Instance *instance = instance_owner.get(p_rid); + + instance_set_room(p_rid,RID()); + instance_set_scenario(p_rid,RID()); + instance_set_base(p_rid,RID()); + + if (instance->skeleton.is_valid()) + instance_attach_skeleton(p_rid,RID()); + + instance_owner.free(p_rid); + memdelete(instance); + } else { + return false; + } + + + return true; +} + +VisualServerScene *VisualServerScene::singleton=NULL; + +VisualServerScene::VisualServerScene() { + + + render_pass=1; + singleton=this; + +} -- cgit v1.2.3-70-g09d2 From cb34b70df13ad9f7942b0c363edc71cfd417bb21 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 21 Oct 2016 07:27:13 -0300 Subject: More scene work, can display a skybox --- drivers/gles3/rasterizer_canvas_gles3.cpp | 1 - drivers/gles3/rasterizer_scene_gles3.cpp | 225 ++++++++++++++++++++++++++++- drivers/gles3/rasterizer_scene_gles3.h | 66 ++++++++- drivers/gles3/rasterizer_storage_gles3.cpp | 137 ++++++++++++++++++ drivers/gles3/rasterizer_storage_gles3.h | 8 + drivers/gles3/shaders/SCsub | 1 + drivers/gles3/shaders/copy.glsl | 17 ++- drivers/gles3/shaders/cubemap_filter.glsl | 143 ++++++++++++++++++ scene/resources/environment.cpp | 175 +++++++++++++++++++++- scene/resources/environment.h | 54 ++++++- servers/visual/rasterizer.h | 21 +++ servers/visual/visual_server_raster.h | 12 +- servers/visual/visual_server_scene.cpp | 48 ------ servers/visual/visual_server_scene.h | 19 --- servers/visual_server.h | 16 +- 15 files changed, 860 insertions(+), 83 deletions(-) create mode 100644 drivers/gles3/shaders/cubemap_filter.glsl (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 237b3ec3f..b2228a6cf 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -117,7 +117,6 @@ void RasterizerCanvasGLES3::canvas_begin(){ glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a ); glClear(GL_COLOR_BUFFER_BIT); storage->frame.clear_request=false; - print_line("canvas clear?"); } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 121620594..4ce2bd2f3 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1,5 +1,10 @@ #include "rasterizer_scene_gles3.h" #include "globals.h" + + + + + static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) { p_array[ 0]=p_mtx.elements[0][0]; @@ -52,6 +57,121 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix& p_mtx, float* p_arra + +/* ENVIRONMENT API */ + +RID RasterizerSceneGLES3::environment_create(){ + + + Environment *env = memnew( Environment ); + + return environment_owner.make_rid(env); +} + +void RasterizerSceneGLES3::environment_set_background(RID p_env,VS::EnvironmentBG p_bg){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + env->bg_mode=p_bg; +} + +void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox, int p_radiance_size, int p_irradiance_size){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + if (env->skybox_color.is_valid()) { + env->skybox_color=RID(); + } + if (env->skybox_radiance.is_valid()) { + storage->free(env->skybox_radiance); + env->skybox_radiance=RID(); + } + if (env->skybox_irradiance.is_valid()) { + storage->free(env->skybox_irradiance); + env->skybox_irradiance=RID(); + } + + if (p_skybox.is_valid()) { + + env->skybox_color=p_skybox; + // env->skybox_radiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_RADIANCE,p_radiance_size); + //env->skybox_irradiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_IRRADIANCE,p_irradiance_size); + } + +} + +void RasterizerSceneGLES3::environment_set_skybox_scale(RID p_env,float p_scale) { + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->skybox_scale=p_scale; + +} + +void RasterizerSceneGLES3::environment_set_bg_color(RID p_env,const Color& p_color){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->bg_color=p_color; + +} +void RasterizerSceneGLES3::environment_set_bg_energy(RID p_env,float p_energy) { + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->energy=p_energy; + +} + +void RasterizerSceneGLES3::environment_set_canvas_max_layer(RID p_env,int p_max_layer){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->canvas_max_layer=p_max_layer; + +} +void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color& p_color, float p_energy, float p_skybox_energy){ + + Environment *env=environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->ambient_color=p_color; + env->ambient_anergy=p_energy; + env->skybox_ambient=p_skybox_energy; + +} + +void RasterizerSceneGLES3::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode){ + +} +void RasterizerSceneGLES3::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){ + +} + +void RasterizerSceneGLES3::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){ + +} +void RasterizerSceneGLES3::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){ + +} +void RasterizerSceneGLES3::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){ + +} +void RasterizerSceneGLES3::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){ + +} +void RasterizerSceneGLES3::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){ + +} + + + + RID RasterizerSceneGLES3::light_instance_create(RID p_light) { @@ -493,6 +613,70 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g #endif } +void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { + + RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox); + + ERR_FAIL_COND(!tex); + glActiveTexture(GL_TEXTURE0); + glBindTexture(tex->target,tex->tex_id); + + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glColorMask(1,1,1,1); + + float flip_sign = p_vflip?-1:1; + + Vector3 vertices[8]={ + Vector3(-1,-1*flip_sign,0.1), + Vector3( 0, 1, 0), + Vector3( 1,-1*flip_sign,0.1), + Vector3( 1, 1, 0), + Vector3( 1, 1*flip_sign,0.1), + Vector3( 1, 0, 0), + Vector3(-1, 1*flip_sign,0.1), + Vector3( 0, 0, 0), + + }; + + + + //skybox uv vectors + float vw,vh,zn; + p_projection.get_viewport_size(vw,vh); + zn=p_projection.get_z_near(); + + float scale=p_scale; + + for(int i=0;i<4;i++) { + + Vector3 uv=vertices[i*2+1]; + uv.x=(uv.x*2.0-1.0)*vw*scale; + uv.y=-(uv.y*2.0-1.0)*vh*scale; + uv.z=-zn; + vertices[i*2+1] = p_transform.basis.xform(uv).normalized(); + vertices[i*2+1].z = -vertices[i*2+1].z; + } + + glBindBuffer(GL_ARRAY_BUFFER,state.skybox_verts); + glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(Vector3)*8,vertices); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + glBindVertexArray(state.skybox_array); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_CUBEMAP,true); + storage->shaders.copy.bind(); + + glDrawArrays(GL_TRIANGLE_FAN,0,4); + + glBindVertexArray(0); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_CUBEMAP,false); + +} + void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){ @@ -561,7 +745,9 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); - if (true) { + Environment *env = environment_owner.getornull(p_environment); + + if (!env || env->bg_mode==VS::ENV_BG_CLEAR_COLOR) { if (storage->frame.clear_request) { @@ -570,6 +756,16 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM storage->frame.clear_request=false; } + } else if (env->bg_mode==VS::ENV_BG_COLOR) { + + + glClearColor( env->bg_color.r, env->bg_color.g, env->bg_color.b, env->bg_color.a ); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + storage->frame.clear_request=false; + } else { + glClear(GL_DEPTH_BUFFER_BIT); + storage->frame.clear_request=false; + } state.current_depth_test=true; @@ -616,6 +812,12 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,false,false); + + if (env && env->bg_mode==VS::ENV_BG_SKYBOX) { + + _draw_skybox(env->skybox_color,p_cam_projection,p_cam_transform,storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP],env->skybox_scale); + } + //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); //glColorMask(1,1,1,1); @@ -793,6 +995,27 @@ void RasterizerSceneGLES3::initialize() { if (render_list.max_elements<1024) render_list.max_elements=1024; + + + { + //quad buffers + + glGenBuffers(1,&state.skybox_verts); + glBindBuffer(GL_ARRAY_BUFFER,state.skybox_verts); + glBufferData(GL_ARRAY_BUFFER,sizeof(Vector3)*8,NULL,GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + + glGenVertexArrays(1,&state.skybox_array); + glBindVertexArray(state.skybox_array); + glBindBuffer(GL_ARRAY_BUFFER,state.skybox_verts); + glVertexAttribPointer(VS::ARRAY_VERTEX,3,GL_FLOAT,GL_FALSE,sizeof(Vector3)*2,0); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_TEX_UV,3,GL_FLOAT,GL_FALSE,sizeof(Vector3)*2,((uint8_t*)NULL)+sizeof(Vector3)); + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + } render_list.init(); } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 6fba777fc..53088deb0 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -16,8 +16,6 @@ public: RasterizerStorageGLES3 *storage; - - struct State { bool current_depth_test; @@ -40,10 +38,70 @@ public: GLuint scene_ubo; - + GLuint skybox_verts; + GLuint skybox_array; } state; + + + + /* ENVIRONMENT API */ + + struct Environment : public RID_Data { + + VS::EnvironmentBG bg_mode; + + RID skybox_color; + RID skybox_radiance; + RID skybox_irradiance; + float skybox_scale; + + Color bg_color; + float energy; + float skybox_ambient; + + Color ambient_color; + float ambient_anergy; + float ambient_skybox_energy; + + int canvas_max_layer; + + + Environment() { + bg_mode=VS::ENV_BG_CLEAR_COLOR; + skybox_scale=1.0; + energy=1.0; + skybox_ambient=0; + ambient_anergy=1.0; + ambient_skybox_energy=0.0; + canvas_max_layer=0; + } + }; + + RID_Owner environment_owner; + + virtual RID environment_create(); + + virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size); + virtual void environment_set_skybox_scale(RID p_env,float p_scale); + virtual void environment_set_bg_color(RID p_env,const Color& p_color); + virtual void environment_set_bg_energy(RID p_env,float p_energy); + virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer); + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0); + + virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode); + virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture); + + virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper); + virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness); + virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast); + virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation); + virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp); + + /* RENDER LIST */ + struct RenderList { enum { @@ -166,6 +224,8 @@ public: _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material); + void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); + virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment); virtual bool free(RID p_rid); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index f633ef21c..94ad2afab 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -995,6 +995,104 @@ void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable config.shrink_textures_x2=p_enable; } +RID RasterizerStorageGLES3::texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution) const { + + Texture * texture = texture_owner.get(p_source); + ERR_FAIL_COND_V(!texture,RID()); + ERR_FAIL_COND_V(!(texture->flags&VS::TEXTURE_FLAG_CUBEMAP),RID()); + + bool use_float=true; + + if (p_resolution<0) { + p_resolution=texture->width; + } + + + glBindVertexArray(0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); +#ifdef GLEW_ENABLED + glDisable(GL_POINT_SPRITE); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + glDisable(GL_BLEND); + + + glActiveTexture(GL_TEXTURE1); + glBindTexture(texture->target, texture->tex_id); + + glActiveTexture(GL_TEXTURE0); + GLuint new_cubemap; + glGenTextures(1, &new_cubemap); + + + GLuint tmp_fb; + + glGenFramebuffers(1, &tmp_fb); + glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); + + + int w = texture->width; + int h = texture->height; + + int lod=0; + + shaders.cubemap_filter.bind(); + + int mipmaps=6; + + int mm_level=mipmaps; + + while(mm_level) { + + for(int i=0;i<6;i++) { + glTexImage2D(_cube_side_enum[i], lod, use_float?GL_RGBA16F:GL_RGB10_A2, w, h, 0, GL_RGBA, use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV, NULL); + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_BASE_LEVEL, lod); + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_MAX_LEVEL, lod); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], new_cubemap, 0); + + glViewport(0,0,w,h); + glBindVertexArray(resources.quadie_array); + + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::FACE_ID,i); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,lod/float(mipmaps)); + + + glDrawArrays(GL_TRIANGLE_FAN,0,4); + glBindVertexArray(0); +#ifdef DEBUG_ENABLED + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); +#endif + } + + + + if (w>1) + w>>=1; + if (h>1) + h>>=1; + + lod++; + mm_level--; + + } + + + for(int i=0;i<6;i++) { + //restore ranges + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(_cube_side_enum[i], GL_TEXTURE_MAX_LEVEL, lod); + + } + + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + glDeleteFramebuffers(1, &tmp_fb); + + + return RID(); +} /* SHADER API */ @@ -3649,6 +3747,45 @@ void RasterizerStorageGLES3::initialize() { #else config.use_rgba_2d_shadows=true; #endif + + + //generic quadie for copying + + { + //quad buffers + + glGenBuffers(1,&resources.quadie); + glBindBuffer(GL_ARRAY_BUFFER,resources.quadie); + { + const float qv[16]={ + -1,-1, + 0, 0, + -1, 1, + 0, 1, + 1, 1, + 1, 1, + 1,-1, + 1, 0, + }; + + glBufferData(GL_ARRAY_BUFFER,sizeof(float)*16,qv,GL_STATIC_DRAW); + } + + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + + + glGenVertexArrays(1,&resources.quadie_array); + glBindVertexArray(resources.quadie_array); + glBindBuffer(GL_ARRAY_BUFFER,resources.quadie); + glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,((uint8_t*)NULL)+8); + glEnableVertexAttribArray(1); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + } + + shaders.cubemap_filter.init(); } void RasterizerStorageGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 950d65b9d..c3022b3ac 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -6,6 +6,7 @@ #include "shader_gles3.h" #include "shaders/copy.glsl.h" #include "shaders/canvas.glsl.h" +#include "shaders/cubemap_filter.glsl.h" #include "self_list.h" #include "shader_compiler_gles3.h" @@ -60,6 +61,8 @@ public: ShaderCompilerGLES3 compiler; + CubemapFilterShaderGLES3 cubemap_filter; + ShaderCompilerGLES3::IdentifierActions actions_canvas; ShaderCompilerGLES3::IdentifierActions actions_scene; } shaders; @@ -70,6 +73,9 @@ public: GLuint black_tex; GLuint normal_tex; + GLuint quadie; + GLuint quadie_array; + } resources; struct Info { @@ -178,6 +184,8 @@ public: virtual void texture_debug_usage(List *r_info); + virtual RID texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution=-1) const; + /* SHADER API */ diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index 0fa0e3b73..afffe1031 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -5,4 +5,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'): env.GLES3_GLSL('canvas.glsl'); env.GLES3_GLSL('canvas_shadow.glsl'); env.GLES3_GLSL('scene.glsl'); + env.GLES3_GLSL('cubemap_filter.glsl'); diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index aba280186..eb58d6643 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -33,20 +33,31 @@ void main() { #ifdef USE_CUBEMAP in vec3 cube_interp; -uniform samplerCube source_cube; +uniform samplerCube source_cube; //texunit:0 #else in vec2 uv_interp; -uniform sampler2D source; +uniform sampler2D source; //texunit:0 #endif + +uniform float stuff; + in vec2 uv2_interp; -layout(location = 0) vec4 frag_color; //color:0 +layout(location = 0) out vec4 frag_color; void main() { //vec4 color = color_interp; +#ifdef USE_CUBEMAP + vec4 color = texture( source_cube, normalize(cube_interp) ); + +#else + vec4 color = texture( source, uv_interp ); +#endif + + frag_color = color; } diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl new file mode 100644 index 000000000..f450f3411 --- /dev/null +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -0,0 +1,143 @@ +[vertex] + + +layout(location=0) in highp vec2 vertex; + +layout(location=1) in highp vec2 uv; + +out highp vec2 uv_interp; + +void main() { + + uv_interp=uv; + gl_Position=vec4(vertex,0,1); +} + +[fragment] + + +uniform samplerCube source_cube; //texunit:1 +uniform int face_id; +uniform float roughness; +in highp vec2 uv_interp; + + +layout(location = 0) vec4 frag_color; + + +vec3 texelCoordToVec(vec2 uv, int faceID) +{ + mat3 faceUvVectors[6]; + + // -x + faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z + faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face + + // +x + faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z + faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face + + // -y + faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z + faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face + + // +y + faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z + faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face + + // -z + faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x + faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face + + // +z + faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face + + // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. + vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; + return normalize(result); +} + +vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) +{ + float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] + + // Compute distribution direction + float Phi = 2.0 * M_PI * Xi.x; + float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + float SinTheta = sqrt(1.0 - CosTheta * CosTheta); + + // Convert to spherical direction + vec3 H; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 TangentX = normalize(cross(UpVector, N)); + vec3 TangentY = cross(N, TangentX); + + // Tangent to world space + return TangentX * H.x + TangentY * H.y + N * H.z; +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float GGX(float NdotV, float a) +{ + float k = a / 2.0; + return NdotV / (NdotV * (1.0 - k) + k); +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float G_Smith(float a, float nDotV, float nDotL) +{ + return GGX(nDotL, a * a) * GGX(nDotV, a * a); +} + +float radicalInverse_VdC(uint bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N) { + return vec2(float(i)/float(N), radicalInverse_VdC(i)); +} + +#define SAMPLE_COUNT 1024 + +void main() { + + vec2 uv = (uv_interp * 2.0) - 1.0; + vec3 N = texelCoordToVec(uv, face_id); + + //vec4 color = color_interp; + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + + for(int sampleNum = 0; sampleNum < SAMPLE_COUNT; sampleNum++) { + vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT); + vec2 xi = texture2DLod(Texture0, vec2(float(sampleNum) / float(SAMPLE_COUNT), 0.5), 0.0).xy; + + vec3 H = ImportanceSampleGGX( xi, roughness, N ); + vec3 V = N; + vec3 L = normalize(2.0 * dot( V, H ) * H - V); + + float ndotl = max(0.0, dot(N, L)); + vec3 s = textureCubeLod(u_skyCube, H, 0.0).rgb * ndotl; + + sum += vec4(s, 1.0); + } + sum /= sum.w; + + frag_color = vec4(sum.rgb, 1.0); +} + diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 6fecdef59..85d16da91 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -28,20 +28,193 @@ /*************************************************************************/ #include "environment.h" #include "texture.h" - +#include "globals.h" +#include "servers/visual_server.h" RID Environment::get_rid() const { return environment; } + +void Environment::set_background(BGMode p_bg) { + + bg_mode=p_bg; + VS::get_singleton()->environment_set_background(environment,VS::EnvironmentBG(p_bg)); + _change_notify(); +} + +void Environment::set_skybox(const Ref& p_skybox){ + + bg_skybox=p_skybox; + + RID sb_rid; + if (bg_skybox.is_valid()) + sb_rid=bg_skybox->get_rid(); + print_line("skybox valid: "+itos(sb_rid.is_valid())); + + VS::get_singleton()->environment_set_skybox(environment,sb_rid,Globals::get_singleton()->get("rendering/skybox/radiance_cube_resolution"),Globals::get_singleton()->get("rendering/skybox/iradiance_cube_resolution")); +} + +void Environment::set_skybox_scale(float p_scale) { + + bg_skybox_scale=p_scale; + VS::get_singleton()->environment_set_skybox_scale(environment,p_scale); +} + +void Environment::set_bg_color(const Color& p_color){ + + bg_color=p_color; + VS::get_singleton()->environment_set_bg_color(environment,p_color); +} +void Environment::set_bg_energy(float p_energy){ + + bg_energy=p_energy; + VS::get_singleton()->environment_set_bg_energy(environment,p_energy); +} +void Environment::set_canvas_max_layer(int p_max_layer){ + + bg_canvas_max_layer=p_max_layer; + VS::get_singleton()->environment_set_canvas_max_layer(environment,p_max_layer); +} +void Environment::set_ambient_light_color(const Color& p_color){ + + ambient_color=p_color; + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); +} +void Environment::set_ambient_light_energy(float p_energy){ + + ambient_energy=p_energy; + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); +} +void Environment::set_ambient_light_skybox_energy(float p_energy){ + + ambient_skybox_energy=p_energy; + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); +} + +Environment::BGMode Environment::get_background() const{ + + return bg_mode; +} +Ref Environment::get_skybox() const{ + + return bg_skybox; +} + +float Environment::get_skybox_scale() const { + + return bg_skybox_scale; +} + +Color Environment::get_bg_color() const{ + + return bg_color; +} +float Environment::get_bg_energy() const{ + + return bg_energy; +} +int Environment::get_canvas_max_layer() const{ + + return bg_canvas_max_layer; +} +Color Environment::get_ambient_light_color() const{ + + return ambient_color; +} +float Environment::get_ambient_light_energy() const{ + + return ambient_energy; +} +float Environment::get_ambient_light_skybox_energy() const{ + + return ambient_skybox_energy; +} + + + +void Environment::_validate_property(PropertyInfo& property) const { + + if (property.name=="background/skybox" || property.name=="ambient_light/skybox_energy") { + if (bg_mode!=BG_SKYBOX) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + if (property.name=="background/color") { + if (bg_mode!=BG_COLOR) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + if (property.name=="background/canvas_max_layer") { + if (bg_mode!=BG_CANVAS) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + +} + void Environment::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_background","mode"),&Environment::set_background); + ObjectTypeDB::bind_method(_MD("set_skybox","skybox:CubeMap"),&Environment::set_skybox); + ObjectTypeDB::bind_method(_MD("set_skybox_scale","scale"),&Environment::set_skybox_scale); + ObjectTypeDB::bind_method(_MD("set_bg_color","color"),&Environment::set_bg_color); + ObjectTypeDB::bind_method(_MD("set_bg_energy","energy"),&Environment::set_bg_energy); + ObjectTypeDB::bind_method(_MD("set_canvas_max_layer","layer"),&Environment::set_canvas_max_layer); + ObjectTypeDB::bind_method(_MD("set_ambient_light_color","color"),&Environment::set_ambient_light_color); + ObjectTypeDB::bind_method(_MD("set_ambient_light_energy","energy"),&Environment::set_ambient_light_energy); + ObjectTypeDB::bind_method(_MD("set_ambient_light_skybox_energy","energy"),&Environment::set_ambient_light_skybox_energy); + + + ObjectTypeDB::bind_method(_MD("get_background"),&Environment::get_background); + ObjectTypeDB::bind_method(_MD("get_skybox:CubeMap"),&Environment::get_skybox); + ObjectTypeDB::bind_method(_MD("get_skybox_scale"),&Environment::get_skybox_scale); + ObjectTypeDB::bind_method(_MD("get_bg_color"),&Environment::get_bg_color); + ObjectTypeDB::bind_method(_MD("get_bg_energy"),&Environment::get_bg_energy); + ObjectTypeDB::bind_method(_MD("get_canvas_max_layer"),&Environment::get_canvas_max_layer); + ObjectTypeDB::bind_method(_MD("get_ambient_light_color"),&Environment::get_ambient_light_color); + ObjectTypeDB::bind_method(_MD("get_ambient_light_energy"),&Environment::get_ambient_light_energy); + ObjectTypeDB::bind_method(_MD("get_ambient_light_skybox_energy"),&Environment::get_ambient_light_skybox_energy); + + + ADD_PROPERTY(PropertyInfo(Variant::INT,"background/mode",PROPERTY_HINT_ENUM,"Clear Color,Custom Color,Skybox,Canvas,Keep"),_SCS("set_background"),_SCS("get_background") ); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"background/skybox",PROPERTY_HINT_RESOURCE_TYPE,"CubeMap"),_SCS("set_skybox"),_SCS("get_skybox") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/skybox_scale",PROPERTY_HINT_RANGE,"0,32,0.01"),_SCS("set_skybox_scale"),_SCS("get_skybox_scale") ); + ADD_PROPERTY(PropertyInfo(Variant::COLOR,"background/color"),_SCS("set_bg_color"),_SCS("get_bg_color") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_bg_energy"),_SCS("get_bg_energy") ); + ADD_PROPERTY(PropertyInfo(Variant::INT,"background/canvas_max_layer",PROPERTY_HINT_RANGE,"-1000,1000,1"),_SCS("set_canvas_max_layer"),_SCS("get_canvas_max_layer") ); + ADD_PROPERTY(PropertyInfo(Variant::COLOR,"ambient_light/color"),_SCS("set_ambient_light_color"),_SCS("get_ambient_light_color") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_ambient_light_energy"),_SCS("get_ambient_light_energy") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/skybox_energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_ambient_light_skybox_energy"),_SCS("get_ambient_light_skybox_energy") ); + + GLOBAL_DEF("rendering/skybox/irradiance_cube_resolution",256); + GLOBAL_DEF("rendering/skybox/radiance_cube_resolution",64); + + BIND_CONSTANT(BG_KEEP); + BIND_CONSTANT(BG_CLEAR_COLOR); + BIND_CONSTANT(BG_COLOR); + BIND_CONSTANT(BG_SKYBOX); + BIND_CONSTANT(BG_CANVAS); + BIND_CONSTANT(BG_MAX); + BIND_CONSTANT(GLOW_BLEND_MODE_ADDITIVE); + BIND_CONSTANT(GLOW_BLEND_MODE_SCREEN); + BIND_CONSTANT(GLOW_BLEND_MODE_SOFTLIGHT); + BIND_CONSTANT(GLOW_BLEND_MODE_DISABLED); } Environment::Environment() { + bg_mode=BG_CLEAR_COLOR; + bg_energy=1.0; + bg_canvas_max_layer=0; + ambient_energy=1.0; + ambient_skybox_energy=0; + + environment = VS::get_singleton()->environment_create(); } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index f8ea0cb36..0435ffc6c 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -31,28 +31,80 @@ #include "resource.h" #include "servers/visual_server.h" +#include "scene/resources/texture.h" class Environment : public Resource { OBJ_TYPE(Environment,Resource); public: + enum BGMode { -private: + BG_CLEAR_COLOR, + BG_COLOR, + BG_SKYBOX, + BG_CANVAS, + BG_KEEP, + BG_MAX + }; + enum GlowBlendMode { + GLOW_BLEND_MODE_ADDITIVE, + GLOW_BLEND_MODE_SCREEN, + GLOW_BLEND_MODE_SOFTLIGHT, + GLOW_BLEND_MODE_DISABLED, + }; +private: RID environment; + BGMode bg_mode; + Ref bg_skybox; + float bg_skybox_scale; + Color bg_color; + float bg_energy; + int bg_canvas_max_layer; + Color ambient_color; + float ambient_energy; + float ambient_skybox_energy; + protected: static void _bind_methods(); + virtual void _validate_property(PropertyInfo& property) const; + public: + + void set_background(BGMode p_bg); + void set_skybox(const Ref& p_skybox); + void set_skybox_scale(float p_scale); + void set_bg_color(const Color& p_color); + void set_bg_energy(float p_energy); + void set_canvas_max_layer(int p_max_layer); + void set_ambient_light_color(const Color& p_color); + void set_ambient_light_energy(float p_energy); + void set_ambient_light_skybox_energy(float p_energy); + + BGMode get_background() const; + Ref get_skybox() const; + float get_skybox_scale() const; + Color get_bg_color() const; + float get_bg_energy() const; + int get_canvas_max_layer() const; + Color get_ambient_light_color() const; + float get_ambient_light_energy() const; + float get_ambient_light_skybox_energy() const; + + virtual RID get_rid() const; Environment(); ~Environment(); }; +VARIANT_ENUM_CAST(Environment::BGMode) +VARIANT_ENUM_CAST(Environment::GlowBlendMode) + #endif // ENVIRONMENT_H diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index d3f27687c..81cdcf6a2 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -39,6 +39,26 @@ class RasterizerScene { public: + /* ENVIRONMENT API */ + + virtual RID environment_create()=0; + + virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size)=0; + virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; + virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; + virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; + virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer)=0; + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0)=0; + + virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode)=0; + virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture)=0; + + virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper)=0; + virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness)=0; + virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast)=0; + virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation)=0; + virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp)=0; struct InstanceBase : RID_Data { @@ -126,6 +146,7 @@ public: virtual void texture_debug_usage(List *r_info)=0; + virtual RID texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution=-1) const=0; /* SHADER API */ diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 62d45f820..a2502e89f 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -620,6 +620,7 @@ public: BIND1RC(uint32_t,texture_get_width,RID) BIND1RC(uint32_t,texture_get_height,RID) BIND3(texture_set_size_override,RID,int,int) + BIND3RC(RID,texture_create_pbr_cubemap,RID,PBRCubeMapMode,int) @@ -848,15 +849,17 @@ public: #undef BINDBASE //from now on, calls forwarded to this singleton -#define BINDBASE VSG::scene +#define BINDBASE VSG::scene_render BIND0R(RID,environment_create) BIND2(environment_set_background,RID ,EnvironmentBG ) - BIND3(environment_set_skybox,RID,RID ,float ) + BIND4(environment_set_skybox,RID,RID ,int,int ) + BIND2(environment_set_skybox_scale,RID,float) BIND2(environment_set_bg_color,RID,const Color& ) + BIND2(environment_set_bg_energy,RID,float ) BIND2(environment_set_canvas_max_layer,RID,int ) - BIND3(environment_set_ambient_light,RID,const Color& ,float ) + BIND4(environment_set_ambient_light,RID,const Color& ,float,float ) BIND7(environment_set_glow,RID,bool ,int ,float ,float ,float ,EnvironmentGlowBlendMode ) BIND5(environment_set_fog,RID,bool ,float ,float ,RID ) @@ -871,6 +874,9 @@ public: /* SCENARIO API */ +#undef BINDBASE +#define BINDBASE VSG::scene + BIND0R(RID,scenario_create) BIND2(scenario_set_debug,RID,ScenarioDebugMode ) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index a3b1d76fb..8fdf3d160 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -69,54 +69,6 @@ void VisualServerScene::camera_set_use_vertical_aspect(RID p_camera,bool p_enabl } - -/* ENVIRONMENT API */ - -RID VisualServerScene::environment_create(){ - - return RID(); -} - -void VisualServerScene::environment_set_background(RID p_env,VS::EnvironmentBG p_bg){ - -} -void VisualServerScene::environment_set_skybox(RID p_env,RID p_skybox,float p_energy){ - -} -void VisualServerScene::environment_set_bg_color(RID p_env,const Color& p_color){ - -} -void VisualServerScene::environment_set_canvas_max_layer(RID p_env,int p_max_layer){ - -} -void VisualServerScene::environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy){ - -} - -void VisualServerScene::environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode){ - -} -void VisualServerScene::environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture){ - -} - -void VisualServerScene::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){ - -} -void VisualServerScene::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){ - -} -void VisualServerScene::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){ - -} -void VisualServerScene::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){ - -} -void VisualServerScene::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){ - -} - - /* SCENARIO API */ diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index ceec4af59..515d52db7 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -139,25 +139,6 @@ public: }; */ - /* ENVIRONMENT API */ - - virtual RID environment_create(); - - virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); - virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0); - virtual void environment_set_bg_color(RID p_env,const Color& p_color); - virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer); - virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0); - - virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode); - virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture); - - virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper); - virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness); - virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast); - virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation); - virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp); - /* SCENARIO API */ diff --git a/servers/visual_server.h b/servers/visual_server.h index eb20355ef..11828c7d2 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -125,6 +125,13 @@ public: virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable)=0; + enum PBRCubeMapMode { + PBR_CUBEMAP_RADIANCE, + PBR_CUBEMAP_IRRADIANCE, + }; + + virtual RID texture_create_pbr_cubemap(RID p_source,PBRCubeMapMode p_mode,int p_resolution=-1) const=0; + struct TextureInfo { RID texture; Size2 size; @@ -478,18 +485,21 @@ public: enum EnvironmentBG { - ENV_BG_KEEP, + ENV_BG_CLEAR_COLOR, ENV_BG_COLOR, ENV_BG_SKYBOX, ENV_BG_CANVAS, + ENV_BG_KEEP, ENV_BG_MAX }; virtual void environment_set_background(RID p_env,EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,float p_energy=1.0)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size)=0; + virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; + virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer)=0; - virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0)=0; + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0)=0; //set default SSAO options //set default SSR options -- cgit v1.2.3-70-g09d2 From 53d8f2b1ec1d86b189800b7fe156c464fdf9e380 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 27 Oct 2016 11:50:26 -0300 Subject: PBR more or less working, still working on bringing gizmos back --- doc/base/classes.xml | 4 +- drivers/gles3/rasterizer_scene_gles3.cpp | 709 +++++++++++++++++-- drivers/gles3/rasterizer_scene_gles3.h | 138 +++- drivers/gles3/rasterizer_storage_gles3.cpp | 226 ++++-- drivers/gles3/rasterizer_storage_gles3.h | 26 +- drivers/gles3/shader_compiler_gles3.cpp | 81 ++- drivers/gles3/shader_gles3.cpp | 1 + drivers/gles3/shader_gles3.h | 1 + drivers/gles3/shaders/cubemap_filter.glsl | 59 +- drivers/gles3/shaders/scene.glsl | 282 ++++++-- modules/gridmap/grid_map.cpp | 4 +- platform/iphone/rasterizer_iphone.cpp | 16 +- platform/iphone/rasterizer_iphone.h | 20 +- scene/3d/light.cpp | 156 ++++- scene/3d/light.h | 41 +- scene/3d/particles.cpp | 10 +- scene/main/scene_main_loop.cpp | 52 +- scene/main/scene_main_loop.h | 12 + scene/main/viewport.cpp | 2 +- scene/register_scene_types.cpp | 11 +- scene/resources/environment.cpp | 27 +- scene/resources/environment.h | 6 +- scene/resources/material.cpp | 754 ++++++++++++++++++++- scene/resources/material.h | 291 +++++++- servers/visual/rasterizer.cpp | 98 +-- servers/visual/rasterizer.h | 60 +- servers/visual/shader_language.cpp | 42 +- servers/visual/shader_types.cpp | 16 +- servers/visual/visual_server_raster.cpp | 20 +- servers/visual/visual_server_raster.h | 4 +- servers/visual/visual_server_scene.cpp | 63 +- servers/visual_server.cpp | 7 - servers/visual_server.h | 19 +- tools/editor/io_plugins/editor_import_collada.cpp | 26 +- .../io_plugins/editor_scene_import_plugin.cpp | 30 +- .../io_plugins/editor_scene_importer_fbxconv.cpp | 24 +- tools/editor/plugins/baked_light_baker.cpp | 10 +- .../plugins/collision_polygon_editor_plugin.cpp | 20 +- .../plugins/collision_polygon_editor_plugin.h | 4 +- tools/editor/plugins/path_editor_plugin.cpp | 12 +- tools/editor/plugins/path_editor_plugin.h | 4 +- tools/editor/plugins/spatial_editor_plugin.cpp | 56 +- tools/editor/plugins/spatial_editor_plugin.h | 8 +- tools/editor/spatial_editor_gizmos.cpp | 98 +-- tools/editor/spatial_editor_gizmos.h | 56 +- 45 files changed, 3020 insertions(+), 586 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 9453cdc77..df1d0262a 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -13434,12 +13434,12 @@ - + Simple Material with a fixed parameter set. - FixedMaterial is a simple type of material [Resource], which contains a fixed amount of parameters. It is the only type of material supported in fixed-pipeline devices and APIs. It is also an often a better alternative to [ShaderMaterial] for most simple use cases. + FixedSpatialMaterial is a simple type of material [Resource], which contains a fixed amount of parameters. It is the only type of material supported in fixed-pipeline devices and APIs. It is also an often a better alternative to [ShaderMaterial] for most simple use cases. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 4ce2bd2f3..aadf9e633 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -75,7 +75,7 @@ void RasterizerSceneGLES3::environment_set_background(RID p_env,VS::EnvironmentB env->bg_mode=p_bg; } -void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox, int p_radiance_size, int p_irradiance_size){ +void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox, int p_radiance_size){ Environment *env=environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -87,15 +87,12 @@ void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox, int p storage->free(env->skybox_radiance); env->skybox_radiance=RID(); } - if (env->skybox_irradiance.is_valid()) { - storage->free(env->skybox_irradiance); - env->skybox_irradiance=RID(); - } + if (p_skybox.is_valid()) { env->skybox_color=p_skybox; - // env->skybox_radiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_RADIANCE,p_radiance_size); + env->skybox_radiance=storage->texture_create_radiance_cubemap(p_skybox,p_radiance_size); //env->skybox_irradiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_IRRADIANCE,p_irradiance_size); } @@ -123,7 +120,7 @@ void RasterizerSceneGLES3::environment_set_bg_energy(RID p_env,float p_energy) { Environment *env=environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - env->energy=p_energy; + env->bg_energy=p_energy; } @@ -135,14 +132,14 @@ void RasterizerSceneGLES3::environment_set_canvas_max_layer(RID p_env,int p_max_ env->canvas_max_layer=p_max_layer; } -void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color& p_color, float p_energy, float p_skybox_energy){ +void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color& p_color, float p_energy, float p_skybox_contribution){ Environment *env=environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->ambient_color=p_color; - env->ambient_anergy=p_energy; - env->skybox_ambient=p_skybox_energy; + env->ambient_energy=p_energy; + env->ambient_skybox_contribution=p_skybox_contribution; } @@ -174,13 +171,28 @@ void RasterizerSceneGLES3::environment_set_color_correction(RID p_env,bool p_ena RID RasterizerSceneGLES3::light_instance_create(RID p_light) { + LightInstance *light_instance = memnew( LightInstance ); + + light_instance->light=p_light; + light_instance->light_ptr=storage->light_owner.getornull(p_light); + + glGenBuffers(1, &light_instance->light_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, light_instance->light_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInstance::LightDataUBO), NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + - return RID(); + ERR_FAIL_COND_V(!light_instance->light_ptr,RID()); + + return light_instance_owner.make_rid(light_instance); } void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,const Transform& p_transform){ + LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND(!light_instance); + light_instance->transform=p_transform; } @@ -247,11 +259,13 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_m //material parameters + state.scene_shader.set_custom_shader(p_material->shader->custom_code_id); bool rebind = state.scene_shader.bind(); if (p_material->ubo_id) { + glBindBufferBase(GL_UNIFORM_BUFFER,1,p_material->ubo_id); } @@ -267,6 +281,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_m RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull( textures[i] ); if (!t) { //check hints + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); continue; } @@ -328,7 +343,14 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } -void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,bool p_reverse_cull,bool p_alpha_pass) { +void RasterizerSceneGLES3::_setup_light(LightInstance *p_light) { + + + glBindBufferBase(GL_UNIFORM_BUFFER,3,p_light->light_ubo); //bind light uniform +} + + +void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass) { if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { //p_reverse_cull=!p_reverse_cull; @@ -337,8 +359,22 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glFrontFace(GL_CW); } + bool shadow=false; + glBindBufferBase(GL_UNIFORM_BUFFER,0,state.scene_ubo); //bind globals ubo + + glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1); + glBindTexture(GL_TEXTURE_2D,state.brdf_texture); + + if (p_base_env) { + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); + glBindTexture(p_base_env->target,p_base_env->tex_id); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true); + } + + state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false); state.current_blend_mode=-1; @@ -349,6 +385,11 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e RasterizerStorageGLES3::Geometry* prev_geometry=NULL; VS::InstanceType prev_base_type = VS::INSTANCE_MAX; + int prev_light_type=-1; + int prev_light_index=-1; + int prev_blend=-1; + int current_blend_mode=-1; + for (int i=0;isort_key>>RenderList::SORT_KEY_LIGHT_TYPE_SHIFT)&0xF; + int light_index=(e->sort_key>>RenderList::SORT_KEY_LIGHT_INDEX_SHIFT)&0xFFFF; + + bool additive=false; + + if (!shadow) { +#if 0 + if (texscreen_used && !texscreen_copied && material->shader_cache && material->shader_cache->valid && material->shader_cache->has_texscreen) { + texscreen_copied=true; + _copy_to_texscreen(); + + //force reset state + prev_material=NULL; + prev_light=0x777E; + prev_geometry_cmp=NULL; + prev_light_type=0xEF; + prev_skeleton =NULL; + prev_sort_flags=0xFF; + prev_morph_values=NULL; + prev_receive_shadows_state=-1; + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + + } +#endif + if (light_type!=prev_light_type /* || receive_shadows_state!=prev_receive_shadows_state*/) { + + if (material->shader->spatial.unshaded/* || current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); + + //state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); + } else { + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,light_type!=0xF); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,light_type==VS::LIGHT_DIRECTIONAL); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,light_type==VS::LIGHT_OMNI); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,light_type==VS::LIGHT_SPOT); + /* + if (receive_shadows_state==1) { + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,(light_type&0x8)); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,(light_type&0x10)); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,(light_type&0x20)); + } + else { + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + } + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); + */ + } + + rebind=true; + } + + + if (!*e->additive_ptr) { + + additive=false; + *e->additive_ptr=true; + } else { + additive=true; + } + + bool desired_blend=false; + int desired_blend_mode=RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX; + + if (additive) { + desired_blend=true; + desired_blend_mode=RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD; + } else { + desired_blend=p_alpha_pass; + desired_blend_mode=material->shader->spatial.blend_mode; + } + + if (prev_blend!=desired_blend) { + + if (desired_blend) { + glEnable(GL_BLEND); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glColorMask(1,1,1,0); + } + } else { + glDisable(GL_BLEND); + glColorMask(1,1,1,1); + } + + prev_blend=desired_blend; + } + + if (desired_blend && desired_blend_mode!=current_blend_mode) { + + + switch(desired_blend_mode) { + + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + } break; + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD: { + + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(p_alpha_pass?GL_SRC_ALPHA:GL_ONE,GL_ONE); + + } break; + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_SUB: { + + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + } break; + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + } break; + + } + + current_blend_mode=desired_blend_mode; + } + } + + if (light_index!=prev_light_index) { + if (light_index!=0xFFFF) { //not unshaded + _setup_light(light_instances[light_index]); + } + } + if (material!=prev_material || rebind) { rebind = _setup_material(material,p_alpha_pass); @@ -396,6 +582,7 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g RasterizerStorageGLES3::Material *m=NULL; RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override :(p_material>=0?p_instance->materials[p_material]:p_geometry->material); + /* #ifdef DEBUG_ENABLED if (current_debug==VS::SCENARIO_DEBUG_OVERDRAW) { @@ -404,8 +591,10 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g #endif */ + if (m_src.is_valid()) { m=storage->material_owner.getornull( m_src ); + if (!m->shader) { m=NULL; } @@ -419,9 +608,10 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g - //bool has_base_alpha=(m->shader_cache && m->shader_cache->has_alpha); - //bool has_blend_alpha=m->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX || m->flags[VS::MATERIAL_FLAG_ONTOP]; - bool has_alpha = false; //has_base_alpha || has_blend_alpha; + bool has_base_alpha=(m->shader->spatial.uses_alpha); + bool has_blend_alpha=m->shader->spatial.blend_mode!=RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX || m->shader->spatial.ontop; + bool has_alpha = has_base_alpha || has_blend_alpha; + bool shadow = false; #if 0 if (shadow) { @@ -488,12 +678,13 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g e->additive_ptr=&e->additive; e->sort_key=0; + if (e->geometry->last_pass!=render_pass) { e->geometry->last_pass=render_pass; e->geometry->index=current_geometry_index++; } - e->sort_key|=uint64_t(e->instance->base_type)<sort_key|=uint64_t(e->geometry->index)<sort_key|=uint64_t(e->instance->base_type)<material->last_pass!=render_pass) { @@ -502,7 +693,6 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g } e->sort_key|=uint64_t(e->material->index)<sort_key|=uint64_t(e->instance->depth_layer)<geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) @@ -510,42 +700,45 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g bool mirror = e->instance->mirror; -// if (m->flags[VS::MATERIAL_FLAG_INVERT_FACES]) -// e->mirror=!e->mirror; + if (m->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) { + mirror=!mirror; + } if (mirror) { e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG; } //e->light_type=0xFF; // no lights! - e->sort_key|=uint64_t(0xF)<sort_key|=uint64_t(0xFFFF)<depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA) { + + if (!shadow && !has_blend_alpha && has_alpha && m->shader->spatial.depth_draw_mode==RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { //if nothing exists, add this element as opaque too - RenderList::Element *oe = opaque_render_list.add_element(); + RenderList::Element *oe = render_list.add_element(); if (!oe) return; - memcpy(oe,e,sizeof(RenderList::Element)); + copymem(oe,e,sizeof(RenderList::Element)); oe->additive_ptr=&oe->additive; } -*/ -#if 0 - if (shadow || m->flags[VS::MATERIAL_FLAG_UNSHADED] || current_debug==VS::SCENARIO_DEBUG_SHADELESS) { - e->light_type=0x7F; //unshaded is zero + + + if (shadow || m->shader->spatial.unshaded /*|| current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) { + + e->sort_key=RenderList::SORT_KEY_LIGHT_INDEX_UNSHADED; + e->sort_key|=uint64_t(0xF)<sort_key|=uint64_t(0xFFFF)<sort_key; - uint8_t light_type = VS::LIGHT_DIRECTIONAL; + for(int i=0;ibase->shadow_enabled) { light_type|=0x8; if (directional_lights[i]->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) @@ -554,22 +747,24 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g light_type|=0x30; } +*/ RenderList::Element *ec; if (duplicate) { - - ec = render_list->add_element(); - memcpy(ec,e,sizeof(RenderList::Element)); + ec = render_list.add_element(); + copymem(ec,e,sizeof(RenderList::Element)); } else { ec=e; duplicate=true; } - ec->light_type=light_type; - ec->light=sort_key; ec->additive_ptr=&e->additive; + ec->sort_key|=uint64_t(directional_light_instances[i]->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; + ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; + + lighted=true; } @@ -580,37 +775,45 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g for(int i=0;ilast_pass!=scene_pass) //lit by light not in visible scene + LightInstance *li=light_instance_owner.getptr( liptr[i] ); + + if (!li || li->last_pass!=render_pass) //lit by light not in visible scene continue; - uint8_t light_type=li->base->type|0x40; //penalty to ensure directionals always go first - if (li->base->shadow_enabled) { - light_type|=0x8; - } - uint16_t sort_key =li->sort_key; + + +// if (li->base->shadow_enabled) { +// light_type|=0x8; +// } RenderList::Element *ec; if (duplicate) { - ec = render_list->add_element(); - memcpy(ec,e,sizeof(RenderList::Element)); + ec = render_list.add_element(); + copymem(ec,e,sizeof(RenderList::Element)); } else { duplicate=true; ec=e; } - ec->light_type=light_type; - ec->light=sort_key; ec->additive_ptr=&e->additive; + ec->sort_key|=uint64_t(li->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; + ec->sort_key|=uint64_t(li->light_ptr->type) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; + + lighted=true; } + if (!lighted) { + e->sort_key|=uint64_t(0xE)<sort_key|=uint64_t(0xFFFF)<frame.time[i]; } + //bg and ambient + if (env) { + state.ubo_data.bg_energy=env->bg_energy; + state.ubo_data.ambient_energy=env->ambient_energy; + Color linear_ambient_color = env->ambient_color.to_linear(); + state.ubo_data.ambient_light_color[0]=linear_ambient_color.r; + state.ubo_data.ambient_light_color[1]=linear_ambient_color.g; + state.ubo_data.ambient_light_color[2]=linear_ambient_color.b; + state.ubo_data.ambient_light_color[3]=linear_ambient_color.a; + + Color bg_color; + + switch(env->bg_mode) { + case VS::ENV_BG_CLEAR_COLOR: { + bg_color=storage->frame.clear_request_color.to_linear(); + } break; + case VS::ENV_BG_COLOR: { + bg_color=env->bg_color.to_linear(); + } break; + default: { + bg_color=Color(0,0,0,1); + } break; + } + + state.ubo_data.bg_color[0]=bg_color.r; + state.ubo_data.bg_color[1]=bg_color.g; + state.ubo_data.bg_color[2]=bg_color.b; + state.ubo_data.bg_color[3]=bg_color.a; + + state.env_radiance_data.ambient_contribution=env->ambient_skybox_contribution; + } else { + state.ubo_data.bg_energy=1.0; + state.ubo_data.ambient_energy=1.0; + //use from clear color instead, since there is no ambient + Color linear_ambient_color = storage->frame.clear_request_color.to_linear(); + state.ubo_data.ambient_light_color[0]=linear_ambient_color.r; + state.ubo_data.ambient_light_color[1]=linear_ambient_color.g; + state.ubo_data.ambient_light_color[2]=linear_ambient_color.b; + state.ubo_data.ambient_light_color[3]=linear_ambient_color.a; + + state.ubo_data.bg_color[0]=linear_ambient_color.r; + state.ubo_data.bg_color[1]=linear_ambient_color.g; + state.ubo_data.bg_color[2]=linear_ambient_color.b; + state.ubo_data.bg_color[3]=linear_ambient_color.a; + + state.env_radiance_data.ambient_contribution=0; + + } glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(State::SceneDataUBO), &state.ubo_data); glBindBuffer(GL_UNIFORM_BUFFER, 0); + //fill up environment + + store_transform(p_cam_transform,state.env_radiance_data.transform); + + + glBindBuffer(GL_UNIFORM_BUFFER, state.env_radiance_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + +} + +void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform) { + + directional_light_instance_count=0; + light_instance_count=0; + + for(int i=0;i=RenderList::MAX_LIGHTS ); + + LightInstance *li = light_instance_owner.getptr(p_light_cull_result[i]); + + switch(li->light_ptr->type) { + + case VS::LIGHT_DIRECTIONAL: { + + ERR_FAIL_COND( directional_light_instance_count >= RenderList::MAX_LIGHTS); + directional_light_instances[directional_light_instance_count++]=li; + + li->light_ubo_data.light_color_energy[0]=li->light_ptr->color.r; + li->light_ubo_data.light_color_energy[1]=li->light_ptr->color.g; + li->light_ubo_data.light_color_energy[2]=li->light_ptr->color.b; + li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + + //omni, keep at 0 + li->light_ubo_data.light_pos_inv_radius[0]=0.0; + li->light_ubo_data.light_pos_inv_radius[1]=0.0; + li->light_ubo_data.light_pos_inv_radius[2]=0.0; + li->light_ubo_data.light_pos_inv_radius[3]=0.0; + + Vector3 direction = p_camera_inverse_transform.basis.xform(li->transform.basis.xform(Vector3(0,0,-1))).normalized(); + li->light_ubo_data.light_direction_attenuation[0]=direction.x; + li->light_ubo_data.light_direction_attenuation[1]=direction.y; + li->light_ubo_data.light_direction_attenuation[2]=direction.z; + li->light_ubo_data.light_direction_attenuation[3]=1.0; + + li->light_ubo_data.light_params[0]=0; + li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + li->light_ubo_data.light_params[2]=0; + li->light_ubo_data.light_params[3]=0; - render_list.clear(); + +#if 0 + if (li->light_ptr->shadow_enabled) { + CameraMatrix bias; + bias.set_light_bias(); + + int passes=light_instance_get_shadow_passes(p_light_instance); + + for(int i=0;icustom_transform[i]).inverse(); + li->shadow_projection[i] = bias * li->custom_projection[i] * modelview; + } + lights_use_shadow=true; + } +#endif + } break; + case VS::LIGHT_OMNI: { + + li->light_ubo_data.light_color_energy[0]=li->light_ptr->color.r; + li->light_ubo_data.light_color_energy[1]=li->light_ptr->color.g; + li->light_ubo_data.light_color_energy[2]=li->light_ptr->color.b; + li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + + Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); + + //directional, keep at 0 + li->light_ubo_data.light_pos_inv_radius[0]=pos.x; + li->light_ubo_data.light_pos_inv_radius[1]=pos.y; + li->light_ubo_data.light_pos_inv_radius[2]=pos.z; + li->light_ubo_data.light_pos_inv_radius[3]=1.0/MAX(0.001,li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); + + li->light_ubo_data.light_direction_attenuation[0]=0; + li->light_ubo_data.light_direction_attenuation[1]=0; + li->light_ubo_data.light_direction_attenuation[2]=0; + li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + + li->light_ubo_data.light_params[0]=0; + li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + li->light_ubo_data.light_params[2]=0; + li->light_ubo_data.light_params[3]=0; + +#if 0 + if (li->light_ptr->shadow_enabled) { + li->shadow_projection[0] = Transform(camera_transform_inverse * li->transform).inverse(); + lights_use_shadow=true; + } +#endif + } break; + case VS::LIGHT_SPOT: { + + li->light_ubo_data.light_color_energy[0]=li->light_ptr->color.r; + li->light_ubo_data.light_color_energy[1]=li->light_ptr->color.g; + li->light_ubo_data.light_color_energy[2]=li->light_ptr->color.b; + li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + + Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); + + //directional, keep at 0 + li->light_ubo_data.light_pos_inv_radius[0]=pos.x; + li->light_ubo_data.light_pos_inv_radius[1]=pos.y; + li->light_ubo_data.light_pos_inv_radius[2]=pos.z; + li->light_ubo_data.light_pos_inv_radius[3]=1.0/MAX(0.001,li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); + + Vector3 direction = p_camera_inverse_transform.basis.xform(li->transform.basis.xform(Vector3(0,0,-1))).normalized(); + li->light_ubo_data.light_direction_attenuation[0]=direction.x; + li->light_ubo_data.light_direction_attenuation[1]=direction.y; + li->light_ubo_data.light_direction_attenuation[2]=direction.z; + li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + + li->light_ubo_data.light_params[0]=li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; + li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + li->light_ubo_data.light_params[2]=0; + li->light_ubo_data.light_params[3]=0; + +#if 0 + if (li->light_ptr->shadow_enabled) { + CameraMatrix bias; + bias.set_light_bias(); + Transform modelview=Transform(camera_transform_inverse * li->transform).inverse(); + li->shadow_projection[0] = bias * li->projection * modelview; + lights_use_shadow=true; + } +#endif + } break; + + } + + + /* make light hash */ + + // actually, not really a hash, but helps to sort the lights + // and avoid recompiling redudant shader versions + + + li->last_pass=render_pass; + li->light_index=i; + + //update UBO for forward rendering, blit to texture for clustered + + glBindBuffer(GL_UNIFORM_BUFFER, li->light_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightInstance::LightDataUBO), &li->light_ubo_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + light_instances[i]=li; + } + +} + +void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){ + + //first of all, make a new render pass render_pass++; + + //fill up ubo + + Environment *env = environment_owner.getornull(p_environment); + + _setup_environment(env,p_cam_projection,p_cam_transform); + + _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse()); + + render_list.clear(); + current_material_index=0; //fill list @@ -744,8 +1169,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM glClearDepth(1.0); glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); - - Environment *env = environment_owner.getornull(p_environment); + RasterizerStorageGLES3::Texture* env_radiance_tex; if (!env || env->bg_mode==VS::ENV_BG_CLEAR_COLOR) { @@ -756,12 +1180,21 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM storage->frame.clear_request=false; } + } else if (env->bg_mode==VS::ENV_BG_COLOR) { glClearColor( env->bg_color.r, env->bg_color.g, env->bg_color.b, env->bg_color.a ); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); storage->frame.clear_request=false; + } else if (env->bg_mode==VS::ENV_BG_SKYBOX) { + + if (env->skybox_radiance.is_valid()) { + env_radiance_tex = storage->texture_owner.getornull(env->skybox_radiance); + } + glClear(GL_DEPTH_BUFFER_BIT); + storage->frame.clear_request=false; + } else { glClear(GL_DEPTH_BUFFER_BIT); storage->frame.clear_request=false; @@ -810,7 +1243,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM // } - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,false,false); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false); if (env && env->bg_mode==VS::ENV_BG_SKYBOX) { @@ -824,6 +1257,17 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM // state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false); glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); + + render_list.sort_by_depth(true); + + _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false); + + #if 0 if (use_fb) { @@ -972,7 +1416,143 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM bool RasterizerSceneGLES3::free(RID p_rid) { - return false; + if (light_instance_owner.owns(p_rid)) { + + LightInstance *light_instance = light_instance_owner.getptr(p_rid); + glDeleteBuffers(1,&light_instance->light_ubo); + light_instance_owner.free(p_rid); + memdelete(light_instance); + + + } else { + return false; + } + + + return true; + +} + +// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html +static _FORCE_INLINE_ float radicalInverse_VdC(uint32_t bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10f; // / 0x100000000 +} + +static _FORCE_INLINE_ Vector2 Hammersley(uint32_t i, uint32_t N) { + return Vector2(float(i) / float(N), radicalInverse_VdC(i)); +} + +static _FORCE_INLINE_ Vector3 ImportanceSampleGGX(Vector2 Xi, float Roughness, Vector3 N) { + float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] + + // Compute distribution direction + float Phi = 2.0f * M_PI * Xi.x; + float CosTheta = Math::sqrt((1.0f - Xi.y) / (1.0f + (a*a - 1.0f) * Xi.y)); + float SinTheta = Math::sqrt((float)Math::abs(1.0f - CosTheta * CosTheta)); + + // Convert to spherical direction + Vector3 H; + H.x = SinTheta * Math::cos(Phi); + H.y = SinTheta * Math::sin(Phi); + H.z = CosTheta; + + Vector3 UpVector = Math::abs(N.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(1.0, 0.0, 0.0); + Vector3 TangentX = UpVector.cross(N); + TangentX.normalize(); + Vector3 TangentY = N.cross(TangentX); + + // Tangent to world space + return TangentX * H.x + TangentY * H.y + N * H.z; +} + +static _FORCE_INLINE_ float GGX(float NdotV, float a) { + float k = a / 2.0; + return NdotV / (NdotV * (1.0 - k) + k); +} + +// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html +float _FORCE_INLINE_ G_Smith(float a, float nDotV, float nDotL) +{ + return GGX(nDotL, a * a) * GGX(nDotV, a * a); +} + +void RasterizerSceneGLES3::_generate_brdf() { + + int brdf_size=GLOBAL_DEF("rendering/gles3/brdf_texture_size",64); + + + + DVector brdf; + brdf.resize(brdf_size*brdf_size*2); + + DVector::Write w = brdf.write(); + + + for(int i=0;i 0.0 ) { + float G = G_Smith( Roughness, NoV, NoL ); + float G_Vis = G * VoH / (NoH * NoV); + float Fc = pow(1.0 - VoH, 5.0); + + A += (1.0 - Fc) * G_Vis; + B += Fc * G_Vis; + } + } + + A/=512.0; + B/=512.0; + + int tofs = ((brdf_size-j-1)*brdf_size+i)*2; + w[tofs+0]=CLAMP(A*255,0,255); + w[tofs+1]=CLAMP(B*255,0,255); + } + } + + + //set up brdf texture + + + glGenTextures(1, &state.brdf_texture); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,state.brdf_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, brdf_size, brdf_size, 0, GL_RG, GL_UNSIGNED_BYTE,w.ptr()); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D,0); } @@ -989,6 +1569,12 @@ void RasterizerSceneGLES3::initialize() { glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.scene_ubo, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); + glGenBuffers(1, &state.env_radiance_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.env_radiance_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_ubo, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + render_list.max_elements=GLOBAL_DEF("rendering/gles3/max_renderable_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS); if (render_list.max_elements>1000000) render_list.max_elements=1000000; @@ -1017,6 +1603,7 @@ void RasterizerSceneGLES3::initialize() { glBindBuffer(GL_ARRAY_BUFFER,0); //unbind } render_list.init(); + _generate_brdf(); } void RasterizerSceneGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 53088deb0..4b1b77f13 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -32,12 +32,28 @@ public: float camera_inverse_matrix[16]; float camera_matrix[16]; float time[4]; - float ambient_light[4]; + float ambient_light_color[4]; + float bg_color[4]; + float ambient_energy; + float bg_energy; } ubo_data; GLuint scene_ubo; + struct EnvironmentRadianceUBO { + + float transform[16]; + float box_min[4]; //unused for now + float box_max[4]; + float ambient_contribution; + + } env_radiance_data; + + GLuint env_radiance_ubo; + + GLuint brdf_texture; + GLuint skybox_verts; GLuint skybox_array; @@ -54,16 +70,15 @@ public: RID skybox_color; RID skybox_radiance; - RID skybox_irradiance; float skybox_scale; Color bg_color; - float energy; + float bg_energy; float skybox_ambient; Color ambient_color; - float ambient_anergy; - float ambient_skybox_energy; + float ambient_energy; + float ambient_skybox_contribution; int canvas_max_layer; @@ -71,10 +86,10 @@ public: Environment() { bg_mode=VS::ENV_BG_CLEAR_COLOR; skybox_scale=1.0; - energy=1.0; + bg_energy=1.0; skybox_ambient=0; - ambient_anergy=1.0; - ambient_skybox_energy=0.0; + ambient_energy=1.0; + ambient_skybox_contribution=0.0; canvas_max_layer=0; } }; @@ -84,12 +99,12 @@ public: virtual RID environment_create(); virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size); + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size); virtual void environment_set_skybox_scale(RID p_env,float p_scale); virtual void environment_set_bg_color(RID p_env,const Color& p_color); virtual void environment_set_bg_energy(RID p_env,float p_energy); virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer); - virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0); + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_contribution=0.0); virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode); virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture); @@ -100,19 +115,81 @@ public: virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation); virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp); + + /* LIGHT INSTANCE */ + + struct LightInstance : public RID_Data { + + struct SplitInfo { + + CameraMatrix camera; + Transform transform; + float near; + float far; + }; + + struct LightDataUBO { + + float light_pos_inv_radius[4]; + float light_direction_attenuation[4]; + float light_color_energy[4]; + float light_params[4]; //cone attenuation, specular, shadow darkening, + float shadow_split_offsets[4]; + float shadow_matrix1[16]; + float shadow_matrix2[16]; + float shadow_matrix3[16]; + float shadow_matrix4[16]; + + } light_ubo_data; + + + SplitInfo split_info[4]; + + RID light; + RasterizerStorageGLES3::Light *light_ptr; + + CameraMatrix shadow_matrix[4]; + + Transform transform; + + Vector3 light_vector; + Vector3 spot_vector; + float linear_att; + + GLuint light_ubo; + + uint64_t shadow_pass; + uint64_t last_pass; + uint16_t light_index; + + Vector2 dp; + + CameraMatrix shadow_projection[4]; + + + LightInstance() { } + + }; + + mutable RID_Owner light_instance_owner; + + virtual RID light_instance_create(RID p_light); + virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform); + /* RENDER LIST */ struct RenderList { enum { DEFAULT_MAX_ELEMENTS=65536, - MAX_LIGHTS=4, SORT_FLAG_SKELETON=1, SORT_FLAG_INSTANCING=2, - + MAX_DIRECTIONAL_LIGHTS=16, + MAX_LIGHTS=4096, SORT_KEY_DEPTH_LAYER_SHIFT=58, SORT_KEY_LIGHT_TYPE_SHIFT=54, //type is most important SORT_KEY_LIGHT_INDEX_SHIFT=38, //type is most important + SORT_KEY_LIGHT_INDEX_UNSHADED=uint64_t(0xF) << SORT_KEY_LIGHT_TYPE_SHIFT, //type is most important SORT_KEY_MATERIAL_INDEX_SHIFT=22, SORT_KEY_GEOMETRY_INDEX_SHIFT=6, SORT_KEY_GEOMETRY_TYPE_SHIFT=2, @@ -161,7 +238,24 @@ public: SortArray sorter; if (p_alpha) { - sorter.sort(&elements[max_elements-alpha_element_count-1],alpha_element_count); + sorter.sort(&elements[max_elements-alpha_element_count],alpha_element_count); + } else { + sorter.sort(elements,element_count); + } + } + + struct SortByDepth { + + _FORCE_INLINE_ bool operator()(const Element* A, const Element* B ) const { + return A->instance->depth > B->instance->depth; + } + }; + + void sort_by_depth(bool p_alpha) { + + SortArray sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements-alpha_element_count],alpha_element_count); } else { sorter.sort(elements,element_count); } @@ -197,6 +291,7 @@ public: } + RenderList() { max_elements=DEFAULT_MAX_ELEMENTS; @@ -210,26 +305,35 @@ public: + LightInstance *directional_light_instances[RenderList::MAX_DIRECTIONAL_LIGHTS]; + int directional_light_instance_count; + + LightInstance *light_instances[RenderList::MAX_LIGHTS]; + int light_instance_count; + RenderList render_list; _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e); _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); + _FORCE_INLINE_ void _setup_light(LightInstance *p_light); + void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass); - void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, bool p_reverse_cull, bool p_alpha_pass); - - virtual RID light_instance_create(RID p_light); - virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform); _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material); void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); + void _setup_environment(Environment *env,CameraMatrix& p_cam_projection, const Transform& p_cam_transform); + void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform); + virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment); virtual bool free(RID p_rid); + void _generate_brdf(); + void initialize(); void finalize(); RasterizerSceneGLES3(); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 94ad2afab..1141a605c 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -587,6 +587,7 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture,int p_width, int p_h texture->height=p_height; texture->format=p_format; texture->flags=p_flags; + texture->stored_cube_sides=0; texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; _get_gl_image_and_format(Image(),texture->format,texture->flags,format,internal_format,type,compressed,srgb); @@ -759,8 +760,9 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture,const Image& p_image //printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem); + texture->stored_cube_sides|=(1<flags&VS::TEXTURE_FLAG_MIPMAPS && mipmaps==1 && !texture->ignore_mipmaps) { + if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && mipmaps==1 && !texture->ignore_mipmaps && (!(texture->flags&VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides==(1<<6)-1)) { //generate mipmaps if they were requested and the image does not contain them glGenerateMipmap(texture->target); } @@ -995,7 +997,7 @@ void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable config.shrink_textures_x2=p_enable; } -RID RasterizerStorageGLES3::texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution) const { +RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_resolution) const { Texture * texture = texture_owner.get(p_source); ERR_FAIL_COND_V(!texture,RID()); @@ -1019,12 +1021,13 @@ RID RasterizerStorageGLES3::texture_create_pbr_cubemap(RID p_source,VS::PBRCubeM glDisable(GL_BLEND); - glActiveTexture(GL_TEXTURE1); + glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); - glActiveTexture(GL_TEXTURE0); + glActiveTexture(GL_TEXTURE1); GLuint new_cubemap; glGenTextures(1, &new_cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, new_cubemap); GLuint tmp_fb; @@ -1033,8 +1036,7 @@ RID RasterizerStorageGLES3::texture_create_pbr_cubemap(RID p_source,VS::PBRCubeM glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - int w = texture->width; - int h = texture->height; + int size = p_resolution; int lod=0; @@ -1044,19 +1046,42 @@ RID RasterizerStorageGLES3::texture_create_pbr_cubemap(RID p_source,VS::PBRCubeM int mm_level=mipmaps; + GLenum internal_format = use_float?GL_RGBA16F:GL_RGB10_A2; + GLenum format = GL_RGBA; + GLenum type = use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV; + + + while(mm_level) { + + for(int i=0;i<6;i++) { + glTexImage2D(_cube_side_enum[i], lod, internal_format, size, size, 0, format, type, NULL); + } + + lod++; + mm_level--; + + if (size>1) + size>>=1; + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, lod-1); + + lod=0; + mm_level=mipmaps; + + size = p_resolution; + while(mm_level) { for(int i=0;i<6;i++) { - glTexImage2D(_cube_side_enum[i], lod, use_float?GL_RGBA16F:GL_RGB10_A2, w, h, 0, GL_RGBA, use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV, NULL); - glTexParameteri(_cube_side_enum[i], GL_TEXTURE_BASE_LEVEL, lod); - glTexParameteri(_cube_side_enum[i], GL_TEXTURE_MAX_LEVEL, lod); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], new_cubemap, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], new_cubemap, lod); - glViewport(0,0,w,h); + glViewport(0,0,size,size); glBindVertexArray(resources.quadie_array); shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::FACE_ID,i); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,lod/float(mipmaps)); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,lod/float(mipmaps-1)); glDrawArrays(GL_TRIANGLE_FAN,0,4); @@ -1069,29 +1094,51 @@ RID RasterizerStorageGLES3::texture_create_pbr_cubemap(RID p_source,VS::PBRCubeM - if (w>1) - w>>=1; - if (h>1) - h>>=1; - + if (size>1) + size>>=1; lod++; mm_level--; } - for(int i=0;i<6;i++) { - //restore ranges - glTexParameteri(_cube_side_enum[i], GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(_cube_side_enum[i], GL_TEXTURE_MAX_LEVEL, lod); + //restore ranges + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, lod-1); - } + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); glDeleteFramebuffers(1, &tmp_fb); - - return RID(); + Texture * ctex = memnew( Texture ); + + ctex->flags=VS::TEXTURE_FLAG_CUBEMAP|VS::TEXTURE_FLAG_MIPMAPS|VS::TEXTURE_FLAG_FILTER; + ctex->width=p_resolution; + ctex->height=p_resolution; + ctex->alloc_width=p_resolution; + ctex->alloc_height=p_resolution; + ctex->format=use_float?Image::FORMAT_RGBAH:Image::FORMAT_RGBA8; + ctex->target=GL_TEXTURE_CUBE_MAP; + ctex->gl_format_cache=format; + ctex->gl_internal_format_cache=internal_format; + ctex->gl_type_cache=type; + ctex->data_size=0; + ctex->compressed=false; + ctex->srgb=false; + ctex->total_data_size=0; + ctex->ignore_mipmaps=false; + ctex->mipmaps=mipmaps; + ctex->active=true; + ctex->tex_id=new_cubemap; + ctex->stored_cube_sides=(1<<6)-1; + ctex->render_target=NULL; + + return texture_owner.make_rid(ctex); } @@ -1137,9 +1184,9 @@ void RasterizerStorageGLES3::shader_set_mode(RID p_shader,VS::ShaderMode p_mode) shader->mode=p_mode; ShaderGLES3* shaders[VS::SHADER_MAX]={ - &canvas->state.canvas_shader, &scene->state.scene_shader, &canvas->state.canvas_shader, + &canvas->state.canvas_shader, }; @@ -1231,10 +1278,14 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { shaders.actions_scene.render_mode_values["cull_back"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_BACK); shaders.actions_scene.render_mode_values["cull_disable"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED); - shaders.actions_canvas.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded; - shaders.actions_canvas.render_mode_flags["ontop"]=&p_shader->spatial.ontop; + shaders.actions_scene.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded; + shaders.actions_scene.render_mode_flags["ontop"]=&p_shader->spatial.ontop; + + shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha; + + actions=&shaders.actions_scene; + actions->uniforms=&p_shader->uniforms; - shaders.actions_canvas.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha; } @@ -1243,6 +1294,7 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { Error err = shaders.compiler.compile(p_shader->mode,p_shader->code,actions,p_shader->path,gen_code); + ERR_FAIL_COND(err!=OK); p_shader->shader->set_custom_shader_code(p_shader->custom_code_id,gen_code.vertex,gen_code.vertex_global,gen_code.fragment,gen_code.light,gen_code.fragment_global,gen_code.uniforms,gen_code.texture_uniforms,gen_code.defines); @@ -1633,29 +1685,29 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy gui[0]=v.r; gui[1]=v.g; - gui[3]=v.b; - gui[4]=v.a; + gui[2]=v.b; + gui[3]=v.a; } else if (value.get_type()==Variant::RECT2) { Rect2 v=value; gui[0]=v.pos.x; gui[1]=v.pos.y; - gui[3]=v.size.x; - gui[4]=v.size.y; + gui[2]=v.size.x; + gui[3]=v.size.y; } else if (value.get_type()==Variant::QUAT) { Quat v=value; gui[0]=v.x; gui[1]=v.y; - gui[3]=v.z; - gui[4]=v.w; + gui[2]=v.z; + gui[3]=v.w; } else { Plane v=value; gui[0]=v.normal.x; gui[1]=v.normal.y; - gui[3]=v.normal.x; - gui[4]=v.d; + gui[2]=v.normal.x; + gui[3]=v.d; } } break; @@ -2307,8 +2359,6 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P if (p_format&VS::ARRAY_FORMAT_INDEX) { index_array_size=attribs[VS::ARRAY_INDEX].stride*p_index_count; - - print_line("index count: "+itos(p_index_count)+" stride: "+itos(attribs[VS::ARRAY_INDEX].stride) ); } @@ -2882,55 +2932,134 @@ Matrix32 RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton,i RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ - return RID(); + Light *light = memnew( Light ); + light->type=p_type; + + light->param[VS::LIGHT_PARAM_ENERGY]=1.0; + light->param[VS::LIGHT_PARAM_SPECULAR]=1.0; + light->param[VS::LIGHT_PARAM_RANGE]=1.0; + light->param[VS::LIGHT_PARAM_SPOT_ANGLE]=45; + light->param[VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE]=0; + light->param[VS::LIGHT_PARAM_SHADOW_DARKNESS]=0; + light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET]=0.1; + light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET]=0.3; + light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET]=0.6; + light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET]=1.0; + light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]=0.1; + light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]=0.1; + + + light->color=Color(1,1,1,1); + light->shadow=false; + light->negative=false; + light->cull_mask=0xFFFFFFFF; + light->directional_shadow_mode=VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; + + return light_owner.make_rid(light); } void RasterizerStorageGLES3::light_set_color(RID p_light,const Color& p_color){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + light->color=p_color; } void RasterizerStorageGLES3::light_set_param(RID p_light,VS::LightParam p_param,float p_value){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + ERR_FAIL_INDEX(p_param,VS::LIGHT_PARAM_MAX); + if (p_param==VS::LIGHT_PARAM_RANGE || p_param==VS::LIGHT_PARAM_SPOT_ANGLE) { + light->instance_change_notify(); + } + light->param[p_param]=p_value; } void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + light->shadow=p_enabled; } void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + } void RasterizerStorageGLES3::light_set_attenuation_texure(RID p_light,RID p_texture){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + } void RasterizerStorageGLES3::light_set_negative(RID p_light,bool p_enable){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + light->negative=p_enable; } void RasterizerStorageGLES3::light_set_cull_mask(RID p_light,uint32_t p_mask){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + light->cull_mask=p_mask; } void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); } void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode){ + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); } VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const { + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL); + return VS::LIGHT_DIRECTIONAL; } AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,AABB()); + + switch( light->type ) { + + case VS::LIGHT_SPOT: { + + float len=light->param[VS::LIGHT_PARAM_RANGE]; + float size=Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE]))*len; + return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) ); + } break; + case VS::LIGHT_OMNI: { + + float r = light->param[VS::LIGHT_PARAM_RANGE]; + return AABB( -Vector3(r,r,r), Vector3(r,r,r)*2 ); + } break; + case VS::LIGHT_DIRECTIONAL: { + + return AABB(); + } break; + default: {} + } + + ERR_FAIL_V( AABB() ); return AABB(); } @@ -3028,6 +3157,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: inst = mesh_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_LIGHT: { + inst = light_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; default: { ERR_FAIL(); } @@ -3046,6 +3179,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_LIGHT: { + inst = light_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; default: { ERR_FAIL(); } @@ -3542,6 +3679,9 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return VS::INSTANCE_MESH; } + if (light_owner.owns(p_rid)) { + return VS::INSTANCE_LIGHT; + } return VS::INSTANCE_NONE; } @@ -3617,6 +3757,14 @@ bool RasterizerStorageGLES3::free(RID p_rid){ mesh_owner.free(p_rid); memdelete(mesh); + } else if (light_owner.owns(p_rid)) { + + // delete the texture + Light *light = light_owner.get(p_rid); + + light_owner.free(p_rid); + memdelete(light); + } else if (canvas_occluder_owner.owns(p_rid)) { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index c3022b3ac..f052aa801 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -135,10 +135,13 @@ public: bool active; GLuint tex_id; + uint16_t stored_cube_sides; + RenderTarget *render_target; Texture() { + stored_cube_sides=0; ignore_mipmaps=false; render_target=NULL; flags=width=height=0; @@ -184,7 +187,7 @@ public: virtual void texture_debug_usage(List *r_info); - virtual RID texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution=-1) const; + virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const; /* SHADER API */ @@ -351,13 +354,6 @@ public: struct Instantiable : public RID_Data { - enum Type { - GEOMETRY_INVALID, - GEOMETRY_SURFACE, - GEOMETRY_IMMEDIATE, - GEOMETRY_MULTISURFACE, - }; - SelfList::List instance_list; _FORCE_INLINE_ void instance_change_notify() { @@ -582,6 +578,20 @@ public: /* Light API */ + + struct Light : Instantiable { + + VS::LightType type; + float param[VS::LIGHT_PARAM_MAX]; + Color color; + bool shadow; + bool negative; + uint32_t cull_mask; + VS::LightDirectionalShadowMode directional_shadow_mode; + }; + + mutable RID_Owner light_owner; + virtual RID light_create(VS::LightType p_type); virtual void light_set_color(RID p_light,const Color& p_color); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 49707400c..da8f6689d 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -48,7 +48,7 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_SAMPLERCUBE: return 16; } - + ERR_FAIL_V(0); } @@ -195,7 +195,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener for(Map::Element *E=pnode->uniforms.front();E;E=E->next()) { - String ucode="uniform "; + String ucode; + + if (SL::is_sampler_type(E->get().type)) { + ucode="uniform "; + } + ucode+=_prestr(E->get().precission); ucode+=_typestr(E->get().type); ucode+=" "+_mkid(E->key()); @@ -228,7 +233,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener for(int i=0;i0) - r_gen_code.uniform_offsets[i]=uniform_sizes[i]-1; + r_gen_code.uniform_offsets[i]=uniform_sizes[i-1]; else r_gen_code.uniform_offsets[i]=0; } @@ -320,7 +325,11 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::VariableNode *vnode=(SL::VariableNode*)p_node; if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) { - r_gen_code.defines.push_back(p_default_actions.usage_defines[vnode->name].utf8()); + String define = p_default_actions.usage_defines[vnode->name]; + if (define.begins_with("@")) { + define = p_default_actions.usage_defines[define.substr(1,define.length())]; + } + r_gen_code.defines.push_back(define.utf8()); used_name_defines.insert(vnode->name); } @@ -451,6 +460,14 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String& p_code, Error err = parser.compile(p_code,ShaderTypes::get_singleton()->get_functions(p_mode),ShaderTypes::get_singleton()->get_modes(p_mode)); if (err!=OK) { +#if 1 + + Vector shader = p_code.split("\n"); + for(int i=0;i func_list; ShaderLanguage::get_builtin_funcs(&func_list); diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index ebdf60cf4..052c91524 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -751,6 +751,7 @@ void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id, const String& p_ver ERR_FAIL_COND(!custom_code_map.has(p_code_id)); CustomCode *cc=&custom_code_map[p_code_id]; + cc->vertex=p_vertex; cc->vertex_globals=p_vertex_globals; cc->fragment=p_fragment; diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index 176a2282f..4c7f682df 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -29,6 +29,7 @@ #ifndef SHADER_GLES3_H #define SHADER_GLES3_H +#include #include "platform_config.h" #ifndef GLES3_INCLUDE_H diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index f450f3411..d3d4cbd43 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -16,19 +16,26 @@ void main() { [fragment] -uniform samplerCube source_cube; //texunit:1 +precision highp float; +precision highp int; + + +uniform samplerCube source_cube; //texunit:0 uniform int face_id; uniform float roughness; in highp vec2 uv_interp; -layout(location = 0) vec4 frag_color; +layout(location = 0) out vec4 frag_color; + + +#define M_PI 3.14159265359 vec3 texelCoordToVec(vec2 uv, int faceID) { mat3 faceUvVectors[6]; - +/* // -x faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y @@ -58,6 +65,37 @@ vec3 texelCoordToVec(vec2 uv, int faceID) faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face +*/ + + // -x + faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z + faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face + + // +x + faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z + faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face + + // -y + faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z + faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face + + // +y + faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z + faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face + + // -z + faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x + faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face + + // +z + faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x + faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y + faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; @@ -113,7 +151,7 @@ vec2 Hammersley(uint i, uint N) { return vec2(float(i)/float(N), radicalInverse_VdC(i)); } -#define SAMPLE_COUNT 1024 +#define SAMPLE_COUNT 1024u void main() { @@ -123,20 +161,21 @@ void main() { //vec4 color = color_interp; vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); - for(int sampleNum = 0; sampleNum < SAMPLE_COUNT; sampleNum++) { + for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) { vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT); - vec2 xi = texture2DLod(Texture0, vec2(float(sampleNum) / float(SAMPLE_COUNT), 0.5), 0.0).xy; vec3 H = ImportanceSampleGGX( xi, roughness, N ); vec3 V = N; vec3 L = normalize(2.0 * dot( V, H ) * H - V); - float ndotl = max(0.0, dot(N, L)); - vec3 s = textureCubeLod(u_skyCube, H, 0.0).rgb * ndotl; + float ndotl = clamp(dot(N, L),0.0,1.0); - sum += vec4(s, 1.0); + if (ndotl>0.0) { + sum.rgb += textureLod(source_cube, H, 0.0).rgb *ndotl; + sum.a += ndotl; + } } - sum /= sum.w; + sum /= sum.a; frag_color = vec4(sum.rgb, 1.0); } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 4183e828f..3f9425260 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1,7 +1,7 @@ [vertex] - +#define ENABLE_UV_INTERP /* from VisualServer: @@ -52,14 +52,47 @@ layout(std140) uniform SceneData { //ubo:0 highp mat4 camera_matrix; highp vec4 time; - highp vec4 ambient_light; + highp vec4 ambient_light_color; + highp vec4 bg_color; + float ambient_energy; + float bg_energy; }; uniform highp mat4 world_transform; +#ifdef USE_FORWARD_LIGHTING + +layout(std140) uniform LightData { //ubo:3 + + highp vec4 light_pos_inv_radius; + mediump vec4 light_direction_attenuation; + mediump vec4 light_color_energy; + mediump vec4 light_params; //cone attenuation, specular, shadow darkening, + mediump vec4 shadow_split_offsets; + highp mat4 shadow_matrix1; + highp mat4 shadow_matrix2; + highp mat4 shadow_matrix3; + highp mat4 shadow_matrix4; +}; + +#ifdef USE_FORWARD_1_SHADOW_MAP +out mediump vec4 forward_shadow_pos1; +#endif + +#ifdef USE_FORWARD_2_SHADOW_MAP +out mediump vec4 forward_shadow_pos2; +#endif + +#ifdef USE_FORWARD_4_SHADOW_MAP +out mediump vec4 forward_shadow_pos3; +out mediump vec4 forward_shadow_pos4; +#endif + +#endif + /* Varyings */ -out vec3 vertex_interp; +out highp vec3 vertex_interp; out vec3 normal_interp; #if defined(ENABLE_COLOR_INTERP) @@ -74,13 +107,6 @@ out vec2 uv_interp; out vec2 uv2_interp; #endif -#if defined(ENABLE_VAR1_INTERP) -out vec4 var1_interp; -#endif - -#if defined(ENABLE_VAR2_INTERP) -out vec4 var2_interp; -#endif #if defined(ENABLE_TANGENT_INTERP) out vec3 tangent_interp; @@ -118,13 +144,13 @@ MATERIAL_UNIFORMS void main() { - highp vec4 vertex_in = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0); + highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0); highp mat4 modelview = camera_inverse_matrix * world_transform; - vec3 normal_in = normal_attrib; - normal_in*=normal_mult; + vec3 normal = normal_attrib * normal_mult; + #if defined(ENABLE_TANGENT_INTERP) - vec3 tangent_in = tangent_attrib.xyz; - tangent_in*=normal_mult; + vec3 tangent = tangent_attrib.xyz; + tangent*=normal_mult; float binormalf = tangent_attrib.a; #endif @@ -137,23 +163,31 @@ void main() { m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.z*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.z; m+=mat4(texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+0.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+1.0)*skeltex_pixel_size,0.0)),texture2D(skeleton_matrices,vec2((bone_indices.w*3.0+2.0)*skeltex_pixel_size,0.0)),vec4(0.0,0.0,0.0,1.0))*bone_weights.w; - vertex_in = vertex_in * m; - normal_in = (vec4(normal_in,0.0) * m).xyz; + vertex = vertex_in * m; + normal = (vec4(normal,0.0) * m).xyz; #if defined(ENABLE_TANGENT_INTERP) - tangent_in = (vec4(tangent_in,0.0) * m).xyz; + tangent = (vec4(tangent,0.0) * m).xyz; #endif } #endif - vertex_interp = (modelview * vertex_in).xyz; - normal_interp = normalize((modelview * vec4(normal_in,0.0)).xyz); +#if !defined(SKIP_TRANSFORM_USED) + + vertex = modelview * vertex; + normal = normalize((modelview * vec4(normal,0.0)).xyz); +#endif #if defined(ENABLE_TANGENT_INTERP) - tangent_interp=normalize((modelview * vec4(tangent_in,0.0)).xyz); - binormal_interp = normalize( cross(normal_interp,tangent_interp) * binormalf ); +# if !defined(SKIP_TRANSFORM_USED) + + tangent=normalize((modelview * vec4(tangent,0.0)).xyz); +# endif + vec3 binormal = normalize( cross(normal,tangent) * binormalf ); #endif + + #if defined(ENABLE_COLOR_INTERP) color_interp = color_attrib; #endif @@ -161,13 +195,17 @@ void main() { #if defined(ENABLE_UV_INTERP) uv_interp = uv_attrib; #endif + #if defined(ENABLE_UV2_INTERP) uv2_interp = uv2_attrib; #endif +{ VERTEX_SHADER_CODE +} + #ifdef USE_SHADOW_PASS @@ -177,26 +215,32 @@ VERTEX_SHADER_CODE #endif -#ifdef USE_FOG + vertex_interp = vertex.xyz; + normal_interp = normal; - fog_interp.a = pow( clamp( (length(vertex_interp)-fog_params.x)/(fog_params.y-fog_params.x), 0.0, 1.0 ), fog_params.z ); - fog_interp.rgb = mix( fog_color_begin, fog_color_end, fog_interp.a ); +#if defined(ENABLE_TANGENT_INTERP) + tangent_interp = tangent; + binormal_interp = binormal; #endif -#ifndef VERTEX_SHADER_WRITE_POSITION -//vertex shader might write a position +#if !defined(SKIP_TRANSFORM_USED) gl_Position = projection_matrix * vec4(vertex_interp,1.0); +#else + gl_Position = vertex; #endif - - } [fragment] + +#define M_PI 3.14159265359 + + +#define ENABLE_UV_INTERP //hack to use uv if no uv present so it works with lightmap @@ -219,17 +263,27 @@ in vec3 tangent_interp; in vec3 binormal_interp; #endif -#if defined(ENABLE_VAR1_INTERP) -in vec4 var1_interp; -#endif +in highp vec3 vertex_interp; +in vec3 normal_interp; -#if defined(ENABLE_VAR2_INTERP) -in vec4 var2_interp; -#endif -in vec3 vertex_interp; -in vec3 normal_interp; +/* PBR CHANNELS */ + +#ifdef USE_RADIANCE_CUBEMAP + +uniform sampler2D brdf_texture; //texunit:-1 +uniform samplerCube radiance_cube; //texunit:-2 + +layout(std140) uniform Radiance { //ubo:2 + + mat4 radiance_inverse_xform; + vec3 radiance_box_min; + vec3 radiance_box_max; + float radiance_ambient_contribution; + +}; +#endif /* Material Uniforms */ @@ -255,18 +309,97 @@ layout(std140) uniform SceneData { highp mat4 camera_matrix; highp vec4 time; - highp vec4 ambient_light; + highp vec4 ambient_light_color; + highp vec4 bg_color; + float ambient_energy; + float bg_energy; }; + +#ifdef USE_FORWARD_LIGHTING + +layout(std140) uniform LightData { + + highp vec4 light_pos_inv_radius; + mediump vec4 light_direction_attenuation; + mediump vec4 light_color_energy; + mediump vec4 light_params; //cone attenuation, specular, shadow darkening, + mediump vec4 shadow_split_offsets; + highp mat4 shadow_matrix1; + highp mat4 shadow_matrix2; + highp mat4 shadow_matrix3; + highp mat4 shadow_matrix4; +}; + +#ifdef USE_FORWARD_1_SHADOW_MAP +in mediump vec4 forward_shadow_pos1; +#endif + +#ifdef USE_FORWARD_2_SHADOW_MAP +in mediump vec4 forward_shadow_pos2; +#endif + +#ifdef USE_FORWARD_4_SHADOW_MAP +in mediump vec4 forward_shadow_pos3; +in mediump vec4 forward_shadow_pos4; +#endif + +#endif + layout(location=0) out vec4 frag_color; + +// GGX Specular +// Source: http://www.filmicworlds.com/images/ggx-opt/optimized-ggx.hlsl +float G1V(float dotNV, float k) +{ + return 1.0 / (dotNV * (1.0 - k) + k); +} + +float specularGGX(vec3 N, vec3 V, vec3 L, float roughness, float F0) +{ + float alpha = roughness * roughness; + + vec3 H = normalize(V + L); + + float dotNL = max(dot(N,L), 0.0 ); + float dotNV = max(dot(N,V), 0.0 ); + float dotNH = max(dot(N,H), 0.0 ); + float dotLH = max(dot(L,H), 0.0 ); + + // D + float alphaSqr = alpha * alpha; + float pi = M_PI; + float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0; + float D = alphaSqr / (pi * denom * denom); + + // F + float dotLH5 = pow(1.0 - dotLH, 5.0); + float F = F0 + (1.0 - F0) * (dotLH5); + + // V + float k = alpha / 2.0f; + float vis = G1V(dotNL, k) * G1V(dotNV, k); + + return dotNL * D * F * vis; +} + +void light_compute(vec3 normal, vec3 light_vec,vec3 eye_vec,vec3 diffuse_color, vec3 specular_color, float roughness, float attenuation, inout vec3 diffuse, inout vec3 specular) { + + diffuse += max(0.0,dot(normal,light_vec)) * diffuse_color * attenuation; + //specular += specular_ggx( roughness, max(0.0,dot(normal,eye_vec)) ) * specular_color * attenuation; + float s = roughness > 0.0 ? specularGGX(normal,eye_vec,light_vec,roughness,1.0) : 0.0; + specular += s * specular_color * attenuation; +} + + void main() { //lay out everything, whathever is unused is optimized away anyway vec3 vertex = vertex_interp; - vec3 albedo = vec3(0.9,0.9,0.9); - vec3 metal = vec3(0.0,0.0,0.0); - float rough = 0.0; + vec3 albedo = vec3(0.8,0.8,0.8); + vec3 specular = vec3(0.2,0.2,0.2); + float roughness = 1.0; float alpha = 1.0; #ifdef METERIAL_DOUBLESIDED @@ -334,6 +467,66 @@ FRAGMENT_SHADER_CODE } #endif +/////////////////////// LIGHTING ////////////////////////////// + + vec3 specular_light = vec3(0.0,0.0,0.0); + vec3 ambient_light = ambient_light_color.rgb; + vec3 diffuse_light = vec3(0.0,0.0,0.0); + + vec3 eye_vec = -normalize( vertex_interp ); + +#ifdef USE_RADIANCE_CUBEMAP + + { + + float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); + vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; + + float lod = roughness * 5.0; + vec3 r = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); + r=normalize((radiance_inverse_xform * vec4(r,0.0)).xyz); + vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); + + specular_light=mix(albedo,radiance,specular); + + } + + { + + vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); + vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz; + + ambient_light=mix(ambient_light,env_ambient,radiance_ambient_contribution); + } + + +#else + + ambient_light=albedo; +#endif + + +#ifdef USE_FORWARD_LIGHTING + +#ifdef USE_FORWARD_DIRECTIONAL + + light_compute(normal,light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,1.0,diffuse_light,specular_light); +#endif + +#ifdef USE_FORWARD_OMNI + + vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex; + float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w; + float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w ); + light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light); + +#endif + +#ifdef USE_FORWARD_SPOT + +#endif + +#endif #if defined(USE_LIGHT_SHADER_CODE) @@ -345,7 +538,14 @@ LIGHT_SHADER_CODE } #endif +#ifdef SHADELESS + frag_color=vec4(albedo,alpha); +#else + frag_color=vec4(ambient_light+diffuse_light+specular_light,alpha); + +#endif + } diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 6e73244b5..57027bd9b 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -960,9 +960,9 @@ void GridMap::_octant_bake(const OctantKey &p_key, const Ref& p_tm st->add_to_format(VS::ARRAY_FORMAT_COLOR); if (m.is_valid()) { - Ref fm = m; + Ref fm = m; if (fm.is_valid()) - fm->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); + fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true); } } } diff --git a/platform/iphone/rasterizer_iphone.cpp b/platform/iphone/rasterizer_iphone.cpp index 5478569a4..874056f76 100644 --- a/platform/iphone/rasterizer_iphone.cpp +++ b/platform/iphone/rasterizer_iphone.cpp @@ -486,7 +486,7 @@ RID RasterizerIPhone::material_create() { return material_owner.make_rid( memnew( Material ) ); } -void RasterizerIPhone::fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value) { +void RasterizerIPhone::fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant& p_value) { Material *m=material_owner.get( p_material ); ERR_FAIL_COND(!m); @@ -494,7 +494,7 @@ void RasterizerIPhone::fixed_material_set_parameter(RID p_material, VS::FixedMat m->parameters[p_parameter] = p_value; } -Variant RasterizerIPhone::fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const { +Variant RasterizerIPhone::fixed_material_get_parameter(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const { Material *m=material_owner.get( p_material ); ERR_FAIL_COND_V(!m, Variant()); @@ -503,7 +503,7 @@ Variant RasterizerIPhone::fixed_material_get_parameter(RID p_material,VS::FixedM return m->parameters[p_parameter]; } -void RasterizerIPhone::fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture) { +void RasterizerIPhone::fixed_material_set_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter, RID p_texture) { Material *m=material_owner.get( p_material ); ERR_FAIL_COND(!m); @@ -511,7 +511,7 @@ void RasterizerIPhone::fixed_material_set_texture(RID p_material,VS::FixedMateri m->textures[p_parameter] = p_texture; } -RID RasterizerIPhone::fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const { +RID RasterizerIPhone::fixed_material_get_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const { Material *m=material_owner.get( p_material ); ERR_FAIL_COND_V(!m, RID()); @@ -535,7 +535,7 @@ VS::MaterialBlendMode RasterizerIPhone::fixed_material_get_detail_blend_mode(RID return m->detail_blend_mode; } -void RasterizerIPhone::fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode) { +void RasterizerIPhone::fixed_material_set_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode) { Material *m=material_owner.get( p_material ); ERR_FAIL_COND(!m); @@ -543,7 +543,7 @@ void RasterizerIPhone::fixed_material_set_texcoord_mode(RID p_material,VS::Fixed m->texcoord_mode[p_parameter] = p_mode; } -VS::FixedMaterialTexCoordMode RasterizerIPhone::fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const { +VS::FixedSpatialMaterialTexCoordMode RasterizerIPhone::fixed_material_get_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const { Material *m=material_owner.get( p_material ); ERR_FAIL_COND_V(!m, VS::FIXED_MATERIAL_TEXCOORD_TEXGEN); @@ -552,7 +552,7 @@ VS::FixedMaterialTexCoordMode RasterizerIPhone::fixed_material_get_texcoord_mode return m->texcoord_mode[p_parameter]; // for now } -void RasterizerIPhone::fixed_material_set_texgen_mode(RID p_material,VS::FixedMaterialTexGenMode p_mode) { +void RasterizerIPhone::fixed_material_set_texgen_mode(RID p_material,VS::FixedSpatialMaterialTexGenMode p_mode) { Material *m=material_owner.get( p_material ); ERR_FAIL_COND(!m); @@ -560,7 +560,7 @@ void RasterizerIPhone::fixed_material_set_texgen_mode(RID p_material,VS::FixedMa m->texgen_mode = p_mode; }; -VS::FixedMaterialTexGenMode RasterizerIPhone::fixed_material_get_texgen_mode(RID p_material) const { +VS::FixedSpatialMaterialTexGenMode RasterizerIPhone::fixed_material_get_texgen_mode(RID p_material) const { Material *m=material_owner.get( p_material ); ERR_FAIL_COND_V(!m, VS::FIXED_MATERIAL_TEXGEN_SPHERE); diff --git a/platform/iphone/rasterizer_iphone.h b/platform/iphone/rasterizer_iphone.h index fcbb339ab..bb9bddfe2 100644 --- a/platform/iphone/rasterizer_iphone.h +++ b/platform/iphone/rasterizer_iphone.h @@ -100,11 +100,11 @@ class RasterizerIPhone : public Rasterizer { RID textures[VisualServer::FIXED_MATERIAL_PARAM_MAX]; Transform uv_transform; - VS::FixedMaterialTexCoordMode texcoord_mode[VisualServer::FIXED_MATERIAL_PARAM_MAX]; + VS::FixedSpatialMaterialTexCoordMode texcoord_mode[VisualServer::FIXED_MATERIAL_PARAM_MAX]; VS::MaterialBlendMode detail_blend_mode; - VS::FixedMaterialTexGenMode texgen_mode; + VS::FixedSpatialMaterialTexGenMode texgen_mode; Material() { @@ -624,20 +624,20 @@ public: virtual RID material_create(); - virtual void fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value); - virtual Variant fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const; + virtual void fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant& p_value); + virtual Variant fixed_material_get_parameter(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const; - virtual void fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture); - virtual RID fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const; + virtual void fixed_material_set_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter, RID p_texture); + virtual RID fixed_material_get_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const; virtual void fixed_material_set_detail_blend_mode(RID p_material,VS::MaterialBlendMode p_mode); virtual VS::MaterialBlendMode fixed_material_get_detail_blend_mode(RID p_material) const; - virtual void fixed_material_set_texgen_mode(RID p_material,VS::FixedMaterialTexGenMode p_mode); - virtual VS::FixedMaterialTexGenMode fixed_material_get_texgen_mode(RID p_material) const; + virtual void fixed_material_set_texgen_mode(RID p_material,VS::FixedSpatialMaterialTexGenMode p_mode); + virtual VS::FixedSpatialMaterialTexGenMode fixed_material_get_texgen_mode(RID p_material) const; - virtual void fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode); - virtual VS::FixedMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const; + virtual void fixed_material_set_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode); + virtual VS::FixedSpatialMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const; virtual void fixed_material_set_uv_transform(RID p_material,const Transform& p_transform); virtual Transform fixed_material_get_uv_transform(RID p_material) const; diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index d98f10002..88ba7b373 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -39,24 +39,88 @@ bool Light::_can_gizmo_scale() const { } +void Light::set_param(Param p_param, float p_value) { + + ERR_FAIL_INDEX(p_param,PARAM_MAX); + param[p_param]=p_value; + + VS::get_singleton()->light_set_param(light,VS::LightParam(p_param),p_value); + + if (p_param==PARAM_SPOT_ANGLE || p_param==PARAM_RANGE) { + update_gizmo();; + } + + +} + +float Light::get_param(Param p_param) const{ + + ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0); + return param[p_param]; + +} + +void Light::set_shadow(bool p_enable){ + + shadow=p_enable; + VS::get_singleton()->light_set_shadow(light,p_enable); + +} +bool Light::has_shadow() const{ + + return shadow; +} + +void Light::set_negative(bool p_enable){ + + negative=p_enable; + VS::get_singleton()->light_set_negative(light,p_enable); +} +bool Light::is_negative() const{ + + return negative; +} + +void Light::set_cull_mask(uint32_t p_cull_mask){ + + cull_mask=p_cull_mask; + VS::get_singleton()->light_set_cull_mask(light,p_cull_mask); + +} +uint32_t Light::get_cull_mask() const{ + + return cull_mask; +} + +void Light::set_color(const Color& p_color){ + + color=p_color; + VS::get_singleton()->light_set_color(light,p_color); +} +Color Light::get_color() const{ + + return color; +} + + AABB Light::get_aabb() const { -#if 0 + if (type==VisualServer::LIGHT_DIRECTIONAL) { return AABB( Vector3(-1,-1,-1), Vector3(2, 2, 2 ) ); } else if (type==VisualServer::LIGHT_OMNI) { - return AABB( Vector3(-1,-1,-1) * vars[PARAM_RADIUS], Vector3(2, 2, 2 ) * vars[PARAM_RADIUS]); + return AABB( Vector3(-1,-1,-1) * param[PARAM_RANGE], Vector3(2, 2, 2 ) * param[PARAM_RANGE]); } else if (type==VisualServer::LIGHT_SPOT) { - float len=vars[PARAM_RADIUS]; - float size=Math::tan(Math::deg2rad(vars[PARAM_SPOT_ANGLE]))*len; + float len=param[PARAM_RANGE]; + float size=Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE]))*len; return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) ); } -#endif + return AABB(); } @@ -118,10 +182,51 @@ void Light::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_editor_only"), &Light::is_editor_only ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only")); - - - + ObjectTypeDB::bind_method(_MD("set_param","param","value"), &Light::set_param ); + ObjectTypeDB::bind_method(_MD("get_param","param"), &Light::get_param ); + + ObjectTypeDB::bind_method(_MD("set_shadow","enabled"), &Light::set_shadow ); + ObjectTypeDB::bind_method(_MD("has_shadow"), &Light::has_shadow ); + + ObjectTypeDB::bind_method(_MD("set_negative","enabled"), &Light::set_negative ); + ObjectTypeDB::bind_method(_MD("is_negative"), &Light::is_negative ); + + ObjectTypeDB::bind_method(_MD("set_cull_mask","cull_mask"), &Light::set_cull_mask ); + ObjectTypeDB::bind_method(_MD("get_cull_mask"), &Light::get_cull_mask ); + + ObjectTypeDB::bind_method(_MD("set_color","color"), &Light::set_color ); + ObjectTypeDB::bind_method(_MD("get_color"), &Light::get_color ); + + ADD_PROPERTY( PropertyInfo( Variant::COLOR, "light/color"), _SCS("set_color"), _SCS("get_color")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/energy"), _SCS("set_param"), _SCS("get_param"), PARAM_ENERGY); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "light/negative"), _SCS("set_negative"), _SCS("is_negative")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/specular"), _SCS("set_param"), _SCS("get_param"), PARAM_SPECULAR); + ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask"), _SCS("set_cull_mask"), _SCS("get_cull_mask")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkness"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_DARKNESS); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/normal_bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_NORMAL_BIAS); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias_split_scale"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS_SPLIT_SCALE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/max_distance"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE); + + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editor/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only")); + + BIND_CONSTANT( PARAM_ENERGY ); + BIND_CONSTANT( PARAM_SPECULAR ); + BIND_CONSTANT( PARAM_RANGE ); + BIND_CONSTANT( PARAM_ATTENUATION ); + BIND_CONSTANT( PARAM_SPOT_ANGLE ); + BIND_CONSTANT( PARAM_SPOT_ATTENUATION ); + BIND_CONSTANT( PARAM_SHADOW_MAX_DISTANCE ); + BIND_CONSTANT( PARAM_SHADOW_DARKNESS ); + BIND_CONSTANT( PARAM_SHADOW_SPLIT_1_OFFSET ); + BIND_CONSTANT( PARAM_SHADOW_SPLIT_2_OFFSET ); + BIND_CONSTANT( PARAM_SHADOW_SPLIT_3_OFFSET ); + BIND_CONSTANT( PARAM_SHADOW_SPLIT_4_OFFSET ); + BIND_CONSTANT( PARAM_SHADOW_NORMAL_BIAS ); + BIND_CONSTANT( PARAM_SHADOW_BIAS ); + BIND_CONSTANT( PARAM_SHADOW_BIAS_SPLIT_SCALE ); + BIND_CONSTANT( PARAM_MAX ); } @@ -131,9 +236,29 @@ Light::Light(VisualServer::LightType p_type) { type=p_type; light=VisualServer::get_singleton()->light_create(p_type); - + VS::get_singleton()->instance_set_base(get_instance(),light); editor_only=false; + set_color(Color(1,1,1,1)); + set_shadow(false); + set_negative(false); + set_cull_mask(0xFFFFFFFF); + + set_param(PARAM_ENERGY,1); + set_param(PARAM_SPECULAR,1); + set_param(PARAM_RANGE,5); + set_param(PARAM_ATTENUATION,1); + set_param(PARAM_SPOT_ANGLE,45); + set_param(PARAM_SPOT_ATTENUATION,1); + set_param(PARAM_SHADOW_MAX_DISTANCE,0); + set_param(PARAM_SHADOW_DARKNESS,0); + set_param(PARAM_SHADOW_SPLIT_1_OFFSET,0.1); + set_param(PARAM_SHADOW_SPLIT_2_OFFSET,0.2); + set_param(PARAM_SHADOW_SPLIT_3_OFFSET,0.5); + set_param(PARAM_SHADOW_SPLIT_4_OFFSET,1.0); + set_param(PARAM_SHADOW_NORMAL_BIAS,0.1); + set_param(PARAM_SHADOW_BIAS,0.1); + set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE,0.1); } @@ -147,6 +272,8 @@ Light::Light() { Light::~Light() { + VS::get_singleton()->instance_set_base(get_instance(),RID()); + if (light.is_valid()) VisualServer::get_singleton()->free(light); } @@ -156,6 +283,10 @@ Light::~Light() { void DirectionalLight::_bind_methods() { + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_4"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_4_OFFSET); } @@ -169,11 +300,16 @@ DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL ) void OmniLight::_bind_methods() { + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); } void SpotLight::_bind_methods() { + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION); + } diff --git a/scene/3d/light.h b/scene/3d/light.h index 3c31d90d4..7da2d8e7c 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -44,10 +44,32 @@ class Light : public VisualInstance { public: - + enum Param { + PARAM_ENERGY, + PARAM_SPECULAR, + PARAM_RANGE, + PARAM_ATTENUATION, + PARAM_SPOT_ANGLE, + PARAM_SPOT_ATTENUATION, + PARAM_SHADOW_MAX_DISTANCE, + PARAM_SHADOW_DARKNESS, + PARAM_SHADOW_SPLIT_1_OFFSET, + PARAM_SHADOW_SPLIT_2_OFFSET, + PARAM_SHADOW_SPLIT_3_OFFSET, + PARAM_SHADOW_SPLIT_4_OFFSET, + PARAM_SHADOW_NORMAL_BIAS, + PARAM_SHADOW_BIAS, + PARAM_SHADOW_BIAS_SPLIT_SCALE, + PARAM_MAX + }; private: + Color color; + float param[PARAM_MAX]; + bool shadow; + bool negative; + uint32_t cull_mask; VS::LightType type; bool editor_only; void _update_visibility(); @@ -71,6 +93,22 @@ public: void set_editor_only(bool p_editor_only); bool is_editor_only() const; + void set_param(Param p_param, float p_value); + float get_param(Param p_param) const; + + void set_shadow(bool p_enable); + bool has_shadow() const; + + void set_negative(bool p_enable); + bool is_negative() const; + + void set_cull_mask(uint32_t p_cull_mask); + uint32_t get_cull_mask() const; + + void set_color(const Color& p_color); + Color get_color() const; + + virtual AABB get_aabb() const; virtual DVector get_faces(uint32_t p_usage_flags) const; @@ -79,6 +117,7 @@ public: }; +VARIANT_ENUM_CAST(Light::Param); class DirectionalLight : public Light { diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 994e32985..1e18ba2c7 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -319,10 +319,10 @@ RES Particles::_get_gizmo_geometry() const { Ref surface_tool( memnew( SurfaceTool )); - Ref mat( memnew( FixedMaterial )); + Ref mat( memnew( FixedSpatialMaterial )); - mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.2) ); - mat->set_parameter( FixedMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) ); + mat->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.2) ); + mat->set_parameter( FixedSpatialMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) ); mat->set_blend_mode( Material::BLEND_MODE_ADD ); mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); // mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); @@ -382,9 +382,9 @@ RES Particles::_get_gizmo_geometry() const { Ref mesh = surface_tool->commit(); - Ref mat_aabb( memnew( FixedMaterial )); + Ref mat_aabb( memnew( FixedSpatialMaterial )); - mat_aabb->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.9,0.7) ); + mat_aabb->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.9,0.7) ); mat_aabb->set_line_width(3); mat_aabb->set_flag( Material::FLAG_UNSHADED, true ); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index c1552a416..cfc675337 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -490,6 +490,8 @@ void SceneTree::input_event( const InputEvent& p_event ) { } + _call_idle_callbacks(); + } void SceneTree::init() { @@ -528,6 +530,7 @@ bool SceneTree::iteration(float p_time) { root_lock--; _flush_delete_queue(); + _call_idle_callbacks(); return _quit; } @@ -590,6 +593,8 @@ bool SceneTree::idle(float p_time){ E=N; } + _call_idle_callbacks(); + return _quit; } @@ -745,12 +750,12 @@ Ref SceneTree::get_debug_navigation_material() { if (navigation_material.is_valid()) return navigation_material; - Ref line_material = Ref( memnew( FixedMaterial )); + Ref line_material = Ref( memnew( FixedSpatialMaterial )); /* line_material->set_flag(Material::FLAG_UNSHADED, true); line_material->set_line_width(3.0); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_navigation_color());*/ + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_color());*/ navigation_material=line_material; @@ -763,12 +768,12 @@ Ref SceneTree::get_debug_navigation_disabled_material(){ if (navigation_disabled_material.is_valid()) return navigation_disabled_material; - Ref line_material = Ref( memnew( FixedMaterial )); + Ref line_material = Ref( memnew( FixedSpatialMaterial )); /* line_material->set_flag(Material::FLAG_UNSHADED, true); line_material->set_line_width(3.0); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color());*/ + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color());*/ navigation_disabled_material=line_material; @@ -781,12 +786,12 @@ Ref SceneTree::get_debug_collision_material() { return collision_material; - Ref line_material = Ref( memnew( FixedMaterial )); + Ref line_material = Ref( memnew( FixedSpatialMaterial )); /*line_material->set_flag(Material::FLAG_UNSHADED, true); line_material->set_line_width(3.0); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_collisions_color());*/ + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_collisions_color());*/ collision_material=line_material; @@ -800,11 +805,11 @@ Ref SceneTree::get_debug_contact_mesh() { debug_contact_mesh = Ref( memnew( Mesh ) ); - Ref mat = memnew( FixedMaterial ); + Ref mat = memnew( FixedSpatialMaterial ); /*mat->set_flag(Material::FLAG_UNSHADED,true); mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); - mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color());*/ + mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); + mat->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color());*/ Vector3 diamond[6]={ Vector3(-1, 0, 0), @@ -2259,6 +2264,23 @@ void SceneTree::_bind_methods() { SceneTree *SceneTree::singleton=NULL; + +SceneTree::IdleCallback SceneTree::idle_callbacks[SceneTree::MAX_IDLE_CALLBACKS]; +int SceneTree::idle_callback_count=0; + +void SceneTree::_call_idle_callbacks() { + + for(int i=0;i=MAX_IDLE_CALLBACKS); + idle_callbacks[idle_callback_count++]=p_callback; +} + + SceneTree::SceneTree() { singleton=this; diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 1c0f88862..4860f4a9b 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -74,6 +74,8 @@ class SceneTree : public MainLoop { public: + typedef void (*IdleCallback)(); + enum StretchMode { STRETCH_MODE_DISABLED, @@ -303,6 +305,15 @@ friend class Viewport; static void _live_edit_reparent_node_funcs(void* self,const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos) { reinterpret_cast(self)->_live_edit_reparent_node_func(p_at,p_new_place,p_new_name,p_at_pos); } #endif + + enum { + MAX_IDLE_CALLBACKS=256 + }; + + static IdleCallback idle_callbacks[MAX_IDLE_CALLBACKS]; + static int idle_callback_count; + void _call_idle_callbacks(); + protected: @@ -430,6 +441,7 @@ public: void set_refuse_new_network_connections(bool p_refuse); bool is_refusing_new_network_connections() const; + static void add_idle_callback(IdleCallback p_callback); SceneTree(); ~SceneTree(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index e93a16371..35f72c5ce 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2513,7 +2513,7 @@ Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const { Vector2 Viewport::get_camera_rect_size() const { - return last_vp_rect.size; + return size; } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index ad845555a..e2f5b5679 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -544,14 +544,16 @@ void register_scene_types() { #ifndef _3D_DISABLED ObjectTypeDB::register_type(); ObjectTypeDB::register_virtual_type(); - ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + SceneTree::add_idle_callback(FixedSpatialMaterial::flush_changes); + FixedSpatialMaterial::init_shaders(); // ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); // ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::add_compatibility_type("Shader","MaterialShader"); - ObjectTypeDB::add_compatibility_type("ParticleSystemMaterial","FixedMaterial"); - ObjectTypeDB::add_compatibility_type("UnshadedMaterial","FixedMaterial"); + ObjectTypeDB::add_compatibility_type("ParticleSystemMaterial","FixedSpatialMaterial"); + ObjectTypeDB::add_compatibility_type("UnshadedMaterial","FixedSpatialMaterial"); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); @@ -655,6 +657,7 @@ void unregister_scene_types() { memdelete( resource_loader_wav ); memdelete( resource_loader_dynamic_font ); + #ifdef TOOLS_ENABLED @@ -669,5 +672,7 @@ void unregister_scene_types() { if (resource_loader_text) { memdelete(resource_loader_text); } + + FixedSpatialMaterial::finish_shaders(); SceneStringNames::free(); } diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 85d16da91..3897c86d5 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -53,7 +53,7 @@ void Environment::set_skybox(const Ref& p_skybox){ sb_rid=bg_skybox->get_rid(); print_line("skybox valid: "+itos(sb_rid.is_valid())); - VS::get_singleton()->environment_set_skybox(environment,sb_rid,Globals::get_singleton()->get("rendering/skybox/radiance_cube_resolution"),Globals::get_singleton()->get("rendering/skybox/iradiance_cube_resolution")); + VS::get_singleton()->environment_set_skybox(environment,sb_rid,Globals::get_singleton()->get("rendering/skybox/radiance_cube_resolution")); } void Environment::set_skybox_scale(float p_scale) { @@ -80,17 +80,17 @@ void Environment::set_canvas_max_layer(int p_max_layer){ void Environment::set_ambient_light_color(const Color& p_color){ ambient_color=p_color; - VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_contribution); } void Environment::set_ambient_light_energy(float p_energy){ ambient_energy=p_energy; - VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_contribution); } -void Environment::set_ambient_light_skybox_energy(float p_energy){ +void Environment::set_ambient_light_skybox_contribution(float p_energy){ - ambient_skybox_energy=p_energy; - VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_energy); + ambient_skybox_contribution=p_energy; + VS::get_singleton()->environment_set_ambient_light(environment,ambient_color,ambient_energy,ambient_skybox_contribution); } Environment::BGMode Environment::get_background() const{ @@ -127,16 +127,16 @@ float Environment::get_ambient_light_energy() const{ return ambient_energy; } -float Environment::get_ambient_light_skybox_energy() const{ +float Environment::get_ambient_light_skybox_contribution() const{ - return ambient_skybox_energy; + return ambient_skybox_contribution; } void Environment::_validate_property(PropertyInfo& property) const { - if (property.name=="background/skybox" || property.name=="ambient_light/skybox_energy") { + if (property.name=="background/skybox" || property.name=="background/skybox_scale" || property.name=="ambient_light/skybox_contribution") { if (bg_mode!=BG_SKYBOX) { property.usage=PROPERTY_USAGE_NOEDITOR; } @@ -166,7 +166,7 @@ void Environment::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_canvas_max_layer","layer"),&Environment::set_canvas_max_layer); ObjectTypeDB::bind_method(_MD("set_ambient_light_color","color"),&Environment::set_ambient_light_color); ObjectTypeDB::bind_method(_MD("set_ambient_light_energy","energy"),&Environment::set_ambient_light_energy); - ObjectTypeDB::bind_method(_MD("set_ambient_light_skybox_energy","energy"),&Environment::set_ambient_light_skybox_energy); + ObjectTypeDB::bind_method(_MD("set_ambient_light_skybox_contribution","energy"),&Environment::set_ambient_light_skybox_contribution); ObjectTypeDB::bind_method(_MD("get_background"),&Environment::get_background); @@ -177,7 +177,7 @@ void Environment::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_canvas_max_layer"),&Environment::get_canvas_max_layer); ObjectTypeDB::bind_method(_MD("get_ambient_light_color"),&Environment::get_ambient_light_color); ObjectTypeDB::bind_method(_MD("get_ambient_light_energy"),&Environment::get_ambient_light_energy); - ObjectTypeDB::bind_method(_MD("get_ambient_light_skybox_energy"),&Environment::get_ambient_light_skybox_energy); + ObjectTypeDB::bind_method(_MD("get_ambient_light_skybox_contribution"),&Environment::get_ambient_light_skybox_contribution); ADD_PROPERTY(PropertyInfo(Variant::INT,"background/mode",PROPERTY_HINT_ENUM,"Clear Color,Custom Color,Skybox,Canvas,Keep"),_SCS("set_background"),_SCS("get_background") ); @@ -188,7 +188,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT,"background/canvas_max_layer",PROPERTY_HINT_RANGE,"-1000,1000,1"),_SCS("set_canvas_max_layer"),_SCS("get_canvas_max_layer") ); ADD_PROPERTY(PropertyInfo(Variant::COLOR,"ambient_light/color"),_SCS("set_ambient_light_color"),_SCS("get_ambient_light_color") ); ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_ambient_light_energy"),_SCS("get_ambient_light_energy") ); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/skybox_energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_ambient_light_skybox_energy"),_SCS("get_ambient_light_skybox_energy") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/skybox_contribution",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_ambient_light_skybox_contribution"),_SCS("get_ambient_light_skybox_contribution") ); GLOBAL_DEF("rendering/skybox/irradiance_cube_resolution",256); GLOBAL_DEF("rendering/skybox/radiance_cube_resolution",64); @@ -209,10 +209,11 @@ void Environment::_bind_methods() { Environment::Environment() { bg_mode=BG_CLEAR_COLOR; + bg_skybox_scale=1.0; bg_energy=1.0; bg_canvas_max_layer=0; ambient_energy=1.0; - ambient_skybox_energy=0; + ambient_skybox_contribution=0; environment = VS::get_singleton()->environment_create(); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 0435ffc6c..6478f6420 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -66,7 +66,7 @@ private: int bg_canvas_max_layer; Color ambient_color; float ambient_energy; - float ambient_skybox_energy; + float ambient_skybox_contribution; protected: @@ -84,7 +84,7 @@ public: void set_canvas_max_layer(int p_max_layer); void set_ambient_light_color(const Color& p_color); void set_ambient_light_energy(float p_energy); - void set_ambient_light_skybox_energy(float p_energy); + void set_ambient_light_skybox_contribution(float p_energy); BGMode get_background() const; Ref get_skybox() const; @@ -94,7 +94,7 @@ public: int get_canvas_max_layer() const; Color get_ambient_light_color() const; float get_ambient_light_energy() const; - float get_ambient_light_skybox_energy() const; + float get_ambient_light_skybox_contribution() const; virtual RID get_rid() const; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 3ebe5b780..e3df1461c 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -45,14 +45,762 @@ Material::~Material() { } -FixedMaterial::FixedMaterial() { +///////////////////////////////// + +Mutex *FixedSpatialMaterial::material_mutex=NULL; +SelfList::List FixedSpatialMaterial::dirty_materials; +Map FixedSpatialMaterial::shader_map; +FixedSpatialMaterial::ShaderNames* FixedSpatialMaterial::shader_names=NULL; + +void FixedSpatialMaterial::init_shaders() { + +#ifndef NO_THREADS + material_mutex = Mutex::create(); +#endif + + shader_names = memnew( ShaderNames ); + shader_names->albedo="albedo"; + shader_names->specular="specular"; + shader_names->roughness="roughness"; + shader_names->emission="emission"; + shader_names->normal_scale="normal_scale"; + shader_names->sheen="sheen"; + shader_names->sheen_color="sheen_color"; + shader_names->clearcoat="clearcoat"; + shader_names->clearcoat_gloss="clearcoat_gloss"; + shader_names->anisotropy="anisotropy"; + shader_names->height_scale="height_scale"; + shader_names->subsurface_scattering="subsurface_scattering"; + shader_names->refraction="refraction"; + shader_names->refraction_roughness="refraction_roughness"; + + shader_names->texture_names[TEXTURE_ALBEDO]="texture_albedo"; + shader_names->texture_names[TEXTURE_SPECULAR]="texture_specular"; + shader_names->texture_names[TEXTURE_EMISSION]="texture_emission"; + shader_names->texture_names[TEXTURE_NORMAL]="texture_normal"; + shader_names->texture_names[TEXTURE_SHEEN]="texture_sheen"; + shader_names->texture_names[TEXTURE_CLEARCOAT]="texture_clearcoat"; + shader_names->texture_names[TEXTURE_ANISOTROPY]="texture_anisotropy"; + shader_names->texture_names[TEXTURE_AMBIENT_OCCLUSION]="texture_ambient_occlusion"; + shader_names->texture_names[TEXTURE_HEIGHT]="texture_height"; + shader_names->texture_names[TEXTURE_SUBSURFACE_SCATTERING]="texture_subsurface_scattering"; + shader_names->texture_names[TEXTURE_REFRACTION]="texture_refraction"; + shader_names->texture_names[TEXTURE_REFRACTION_ROUGHNESS]="texture_refraction_roughness"; + shader_names->texture_names[TEXTURE_DETAIL_MASK]="texture_detail_mask"; + shader_names->texture_names[TEXTURE_DETAIL_ALBEDO]="texture_detail_albedo"; + shader_names->texture_names[TEXTURE_DETAIL_NORMAL]="texture_detail_normal"; } -FixedMaterial::~FixedMaterial() { +void FixedSpatialMaterial::finish_shaders(){ + +#ifndef NO_THREADS + memdelete( material_mutex ); +#endif + memdelete( shader_names ); } -///////////////////////////////// + + +void FixedSpatialMaterial::_update_shader() { + + dirty_materials.remove( &element ); + + MaterialKey mk = _compute_key(); + if (mk.key==current_key.key) + return; //no update required in the end + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users==0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + } + + current_key=mk; + + if (shader_map.has(mk)) { + + VS::get_singleton()->material_set_shader(_get_material(),shader_map[mk].shader); + shader_map[mk].users++; + return; + } + + //must create a shader! + + String code="render_mode "; + switch(blend_mode) { + case BLEND_MODE_MIX: code+="blend_mix"; break; + case BLEND_MODE_ADD: code+="blend_add"; break; + case BLEND_MODE_SUB: code+="blend_sub"; break; + case BLEND_MODE_MUL: code+="blend_mul"; break; + } + + switch(depth_draw_mode) { + case DEPTH_DRAW_OPAQUE_ONLY: code+=",depth_draw_opaque"; break; + case DEPTH_DRAW_ALWAYS: code+=",depth_draw_always"; break; + case DEPTH_DRAW_DISABLED: code+=",depth_draw_never"; break; + case DEPTH_DRAW_ALPHA_OPAQUE_PREPASS: code+=",depth_draw_alpha_prepass"; break; + } + + switch(cull_mode) { + case CULL_BACK: code+=",cull_back"; break; + case CULL_FRONT: code+=",cull_front"; break; + case CULL_DISABLED: code+=",cull_disable"; break; + + } + + if (flags[FLAG_UNSHADED]) { + code+=",unshaded"; + } + if (flags[FLAG_ONTOP]) { + code+=",ontop"; + } + + code+=";\n"; + + + code+="uniform vec4 albedo : hint_color;\n"; + code+="uniform sampler2D albedo_texture : hint_albedo;\n"; + code+="uniform vec4 specular : hint_color;\n"; + code+="uniform float roughness : hint_range(0,1);\n"; + code+="uniform sampler2D specular_texture : hint_white;\n"; + code+="\n\n"; + + code+="\n\n"; + code+="void fragment() {\n"; + code+="\tvec4 albedo_tex = texture(albedo_texture,UV);\n"; + + if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) { + code+="\talbedo_tex *= COLOR;\n"; + } + + code+="\tALBEDO = albedo.rgb * albedo_tex.rgb;\n"; + if (features[FEATURE_TRANSPARENT]) { + code+="\tALPHA = albedo.a * albedo_tex.a;\n"; + } + code+="\tvec4 specular_tex = texture(specular_texture,UV);\n"; + code+="\tSPECULAR = specular.rgb * specular_tex.rgb;\n"; + code+="\tROUGHNESS = specular.a * roughness;\n"; + code+="}\n"; + + ShaderData shader_data; + shader_data.shader = VS::get_singleton()->shader_create(VS::SHADER_SPATIAL); + shader_data.users=1; + + VS::get_singleton()->shader_set_code( shader_data.shader, code ); + + shader_map[mk]=shader_data; + + VS::get_singleton()->material_set_shader(_get_material(),shader_data.shader); + +} + +void FixedSpatialMaterial::flush_changes() { + + if (material_mutex) + material_mutex->lock(); + + while (dirty_materials.first()) { + + dirty_materials.first()->self()->_update_shader(); + } + + if (material_mutex) + material_mutex->unlock(); +} + +void FixedSpatialMaterial::_queue_shader_change() { + + if (material_mutex) + material_mutex->lock(); + + if (!element.in_list()) { + dirty_materials.add(&element); + } + + if (material_mutex) + material_mutex->unlock(); + + +} + +bool FixedSpatialMaterial::_is_shader_dirty() const { + + bool dirty=false; + + if (material_mutex) + material_mutex->lock(); + + dirty=element.in_list(); + + if (material_mutex) + material_mutex->unlock(); + + return dirty; +} +void FixedSpatialMaterial::set_albedo(const Color& p_albedo) { + + albedo=p_albedo; + + VS::get_singleton()->material_set_param(_get_material(),shader_names->albedo,p_albedo); +} + +Color FixedSpatialMaterial::get_albedo() const{ + + return albedo; +} + +void FixedSpatialMaterial::set_specular(const Color& p_specular){ + + specular=p_specular; + VS::get_singleton()->material_set_param(_get_material(),shader_names->specular,p_specular); + +} +Color FixedSpatialMaterial::get_specular() const{ + + return specular; +} + +void FixedSpatialMaterial::set_roughness(float p_roughness){ + + roughness=p_roughness; + VS::get_singleton()->material_set_param(_get_material(),shader_names->roughness,p_roughness); + +} +float FixedSpatialMaterial::get_roughness() const{ + + return roughness; +} + +void FixedSpatialMaterial::set_emission(const Color& p_emission){ + + emission=p_emission; + VS::get_singleton()->material_set_param(_get_material(),shader_names->emission,p_emission); + +} +Color FixedSpatialMaterial::get_emission() const{ + + return emission; +} + +void FixedSpatialMaterial::set_normal_scale(float p_normal_scale){ + + normal_scale=p_normal_scale; + VS::get_singleton()->material_set_param(_get_material(),shader_names->normal_scale,p_normal_scale); + +} +float FixedSpatialMaterial::get_normal_scale() const{ + + return normal_scale; +} + +void FixedSpatialMaterial::set_sheen(float p_sheen){ + + sheen=p_sheen; + VS::get_singleton()->material_set_param(_get_material(),shader_names->sheen,p_sheen); + + +} +float FixedSpatialMaterial::get_sheen() const{ + + return sheen; +} + +void FixedSpatialMaterial::set_sheen_color(const Color& p_sheen_color){ + + sheen_color=p_sheen_color; + VS::get_singleton()->material_set_param(_get_material(),shader_names->sheen_color,p_sheen_color); + +} +Color FixedSpatialMaterial::get_sheen_color() const{ + + return sheen_color; +} + +void FixedSpatialMaterial::set_clearcoat(float p_clearcoat){ + + clearcoat=p_clearcoat; + VS::get_singleton()->material_set_param(_get_material(),shader_names->clearcoat,p_clearcoat); + +} + +float FixedSpatialMaterial::get_clearcoat() const{ + + return clearcoat; +} + +void FixedSpatialMaterial::set_clearcoat_gloss(float p_clearcoat_gloss){ + + clearcoat_gloss=p_clearcoat_gloss; + VS::get_singleton()->material_set_param(_get_material(),shader_names->clearcoat_gloss,p_clearcoat_gloss); + + +} + +float FixedSpatialMaterial::get_clearcoat_gloss() const{ + + return clearcoat_gloss; +} + +void FixedSpatialMaterial::set_anisotropy(float p_anisotropy){ + + anisotropy=p_anisotropy; + VS::get_singleton()->material_set_param(_get_material(),shader_names->anisotropy,p_anisotropy); + +} +float FixedSpatialMaterial::get_anisotropy() const{ + + return anisotropy; +} + +void FixedSpatialMaterial::set_height_scale(float p_height_scale){ + + height_scale=p_height_scale; + VS::get_singleton()->material_set_param(_get_material(),shader_names->height_scale,p_height_scale); + + +} + +float FixedSpatialMaterial::get_height_scale() const{ + + return height_scale; +} + +void FixedSpatialMaterial::set_subsurface_scattering(float p_subsurface_scattering){ + + subsurface_scattering=p_subsurface_scattering; + VS::get_singleton()->material_set_param(_get_material(),shader_names->subsurface_scattering,subsurface_scattering); + + +} + +float FixedSpatialMaterial::get_subsurface_scattering() const{ + + return subsurface_scattering; +} + +void FixedSpatialMaterial::set_refraction(float p_refraction){ + + refraction=p_refraction; + VS::get_singleton()->material_set_param(_get_material(),shader_names->refraction,refraction); + +} + +float FixedSpatialMaterial::get_refraction() const { + + return refraction; +} + +void FixedSpatialMaterial::set_refraction_roughness(float p_refraction_roughness) { + + refraction_roughness=p_refraction_roughness; + VS::get_singleton()->material_set_param(_get_material(),shader_names->refraction_roughness,refraction_roughness); + + +} +float FixedSpatialMaterial::get_refraction_roughness() const { + + return refraction_roughness; +} + +void FixedSpatialMaterial::set_detail_uv(DetailUV p_detail_uv) { + + if (detail_uv==p_detail_uv) + return; + + detail_uv=p_detail_uv; + _queue_shader_change(); +} +FixedSpatialMaterial::DetailUV FixedSpatialMaterial::get_detail_uv() const { + + return detail_uv; +} + +void FixedSpatialMaterial::set_blend_mode(BlendMode p_mode) { + + if (blend_mode==p_mode) + return; + + blend_mode=p_mode; + _queue_shader_change(); +} +FixedSpatialMaterial::BlendMode FixedSpatialMaterial::get_blend_mode() const { + + return blend_mode; +} + +void FixedSpatialMaterial::set_detail_blend_mode(BlendMode p_mode) { + + detail_blend_mode=p_mode; + _queue_shader_change(); +} +FixedSpatialMaterial::BlendMode FixedSpatialMaterial::get_detail_blend_mode() const { + + return detail_blend_mode; +} + +void FixedSpatialMaterial::set_depth_draw_mode(DepthDrawMode p_mode) { + + if (depth_draw_mode==p_mode) + return; + + depth_draw_mode=p_mode; + _queue_shader_change(); +} +FixedSpatialMaterial::DepthDrawMode FixedSpatialMaterial::get_depth_draw_mode() const { + + return depth_draw_mode; +} + +void FixedSpatialMaterial::set_cull_mode(CullMode p_mode) { + + if (cull_mode==p_mode) + return; + + cull_mode=p_mode; + _queue_shader_change(); +} +FixedSpatialMaterial::CullMode FixedSpatialMaterial::get_cull_mode() const { + + return cull_mode; +} + +void FixedSpatialMaterial::set_diffuse_mode(DiffuseMode p_mode) { + + if (diffuse_mode==p_mode) + return; + + diffuse_mode=p_mode; + _queue_shader_change(); +} +FixedSpatialMaterial::DiffuseMode FixedSpatialMaterial::get_diffuse_mode() const { + + return diffuse_mode; +} + +void FixedSpatialMaterial::set_flag(Flags p_flag,bool p_enabled) { + + ERR_FAIL_INDEX(p_flag,FLAG_MAX); + + if (flags[p_flag]==p_enabled) + return; + + flags[p_flag]=p_enabled; + _queue_shader_change(); +} + +bool FixedSpatialMaterial::get_flag(Flags p_flag) const { + + ERR_FAIL_INDEX_V(p_flag,FLAG_MAX,false); + return flags[p_flag]; +} + +void FixedSpatialMaterial::set_feature(Feature p_feature,bool p_enabled) { + + ERR_FAIL_INDEX(p_feature,FEATURE_MAX); + if (features[p_feature]==p_enabled) + return; + + features[p_feature]=p_enabled; + _change_notify(); + _queue_shader_change(); + + +} + +bool FixedSpatialMaterial::get_feature(Feature p_feature) const { + + ERR_FAIL_INDEX_V(p_feature,FEATURE_MAX,false); + return features[p_feature]; +} + + + +void FixedSpatialMaterial::set_texture(TextureParam p_param, const Ref &p_texture) { + + ERR_FAIL_INDEX(p_param,TEXTURE_MAX); + textures[p_param]=p_texture; + VS::get_singleton()->material_set_param(_get_material(),shader_names->texture_names[p_param],p_texture); +} + +Ref FixedSpatialMaterial::get_texture(TextureParam p_param) const { + + ERR_FAIL_INDEX_V(p_param,TEXTURE_MAX,Ref()); + return textures[p_param]; +} + + +void FixedSpatialMaterial::_validate_feature(const String& text, Feature feature,PropertyInfo& property) const { + if (property.name.begins_with(text) && property.name!=text+"/enabled" && !features[feature]) { + property.usage=0; + } +} + +void FixedSpatialMaterial::_validate_property(PropertyInfo& property) const { + _validate_feature("normal",FEATURE_NORMAL_MAPPING,property); + _validate_feature("sheen",FEATURE_SHEEN,property); + _validate_feature("clearcoat",FEATURE_CLEARCOAT,property); + _validate_feature("anisotropy",FEATURE_ANISOTROPY,property); + _validate_feature("ao",FEATURE_AMBIENT_OCCLUSION,property); + _validate_feature("height",FEATURE_HEIGHT_MAPPING,property); + _validate_feature("subsurf_scatter",FEATURE_SUBSURACE_SCATTERING,property); + _validate_feature("refraction",FEATURE_REFRACTION,property); + _validate_feature("detail",FEATURE_DETAIL,property); + +} + +void FixedSpatialMaterial::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_albedo","albedo"),&FixedSpatialMaterial::set_albedo); + ObjectTypeDB::bind_method(_MD("get_albedo"),&FixedSpatialMaterial::get_albedo); + + ObjectTypeDB::bind_method(_MD("set_specular","specular"),&FixedSpatialMaterial::set_specular); + ObjectTypeDB::bind_method(_MD("get_specular"),&FixedSpatialMaterial::get_specular); + + ObjectTypeDB::bind_method(_MD("set_roughness","roughness"),&FixedSpatialMaterial::set_roughness); + ObjectTypeDB::bind_method(_MD("get_roughness"),&FixedSpatialMaterial::get_roughness); + + ObjectTypeDB::bind_method(_MD("set_emission","emission"),&FixedSpatialMaterial::set_emission); + ObjectTypeDB::bind_method(_MD("get_emission"),&FixedSpatialMaterial::get_emission); + + ObjectTypeDB::bind_method(_MD("set_normal_scale","normal_scale"),&FixedSpatialMaterial::set_normal_scale); + ObjectTypeDB::bind_method(_MD("get_normal_scale"),&FixedSpatialMaterial::get_normal_scale); + + ObjectTypeDB::bind_method(_MD("set_sheen","sheen"),&FixedSpatialMaterial::set_sheen); + ObjectTypeDB::bind_method(_MD("get_sheen"),&FixedSpatialMaterial::get_sheen); + + ObjectTypeDB::bind_method(_MD("set_sheen_color","sheen_color"),&FixedSpatialMaterial::set_sheen_color); + ObjectTypeDB::bind_method(_MD("get_sheen_color"),&FixedSpatialMaterial::get_sheen_color); + + ObjectTypeDB::bind_method(_MD("set_clearcoat","clearcoat"),&FixedSpatialMaterial::set_clearcoat); + ObjectTypeDB::bind_method(_MD("get_clearcoat"),&FixedSpatialMaterial::get_clearcoat); + + ObjectTypeDB::bind_method(_MD("set_clearcoat_gloss","clearcoat_gloss"),&FixedSpatialMaterial::set_clearcoat_gloss); + ObjectTypeDB::bind_method(_MD("get_clearcoat_gloss"),&FixedSpatialMaterial::get_clearcoat_gloss); + + ObjectTypeDB::bind_method(_MD("set_anisotropy","anisotropy"),&FixedSpatialMaterial::set_anisotropy); + ObjectTypeDB::bind_method(_MD("get_anisotropy"),&FixedSpatialMaterial::get_anisotropy); + + ObjectTypeDB::bind_method(_MD("set_height_scale","height_scale"),&FixedSpatialMaterial::set_height_scale); + ObjectTypeDB::bind_method(_MD("get_height_scale"),&FixedSpatialMaterial::get_height_scale); + + ObjectTypeDB::bind_method(_MD("set_subsurface_scattering","subsurface_scattering"),&FixedSpatialMaterial::set_subsurface_scattering); + ObjectTypeDB::bind_method(_MD("get_subsurface_scattering"),&FixedSpatialMaterial::get_subsurface_scattering); + + ObjectTypeDB::bind_method(_MD("set_refraction","refraction"),&FixedSpatialMaterial::set_refraction); + ObjectTypeDB::bind_method(_MD("get_refraction"),&FixedSpatialMaterial::get_refraction); + + ObjectTypeDB::bind_method(_MD("set_refraction_roughness","refraction_roughness"),&FixedSpatialMaterial::set_refraction_roughness); + ObjectTypeDB::bind_method(_MD("get_refraction_roughness"),&FixedSpatialMaterial::get_refraction_roughness); + + ObjectTypeDB::bind_method(_MD("set_detail_uv","detail_uv"),&FixedSpatialMaterial::set_detail_uv); + ObjectTypeDB::bind_method(_MD("get_detail_uv"),&FixedSpatialMaterial::get_detail_uv); + + ObjectTypeDB::bind_method(_MD("set_blend_mode","blend_mode"),&FixedSpatialMaterial::set_blend_mode); + ObjectTypeDB::bind_method(_MD("get_blend_mode"),&FixedSpatialMaterial::get_blend_mode); + + ObjectTypeDB::bind_method(_MD("set_depth_draw_mode","depth_draw_mode"),&FixedSpatialMaterial::set_depth_draw_mode); + ObjectTypeDB::bind_method(_MD("get_depth_draw_mode"),&FixedSpatialMaterial::get_depth_draw_mode); + + ObjectTypeDB::bind_method(_MD("set_cull_mode","cull_mode"),&FixedSpatialMaterial::set_cull_mode); + ObjectTypeDB::bind_method(_MD("get_cull_mode"),&FixedSpatialMaterial::get_cull_mode); + + ObjectTypeDB::bind_method(_MD("set_diffuse_mode","diffuse_mode"),&FixedSpatialMaterial::set_diffuse_mode); + ObjectTypeDB::bind_method(_MD("get_diffuse_mode"),&FixedSpatialMaterial::get_diffuse_mode); + + ObjectTypeDB::bind_method(_MD("set_flag","flag","enable"),&FixedSpatialMaterial::set_flag); + ObjectTypeDB::bind_method(_MD("get_flag"),&FixedSpatialMaterial::get_flag); + + ObjectTypeDB::bind_method(_MD("set_feature","feature","enable"),&FixedSpatialMaterial::set_feature); + ObjectTypeDB::bind_method(_MD("get_feature","feature"),&FixedSpatialMaterial::get_feature); + + ObjectTypeDB::bind_method(_MD("set_texture","param:Texture","texture"),&FixedSpatialMaterial::set_texture); + ObjectTypeDB::bind_method(_MD("get_texture:Texture","param:Texture"),&FixedSpatialMaterial::get_texture); + + ObjectTypeDB::bind_method(_MD("set_detail_blend_mode","detail_blend_mode"),&FixedSpatialMaterial::set_detail_blend_mode); + ObjectTypeDB::bind_method(_MD("get_detail_blend_mode"),&FixedSpatialMaterial::get_detail_blend_mode); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/transparent"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_TRANSPARENT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/unshaded"),_SCS("set_flag"),_SCS("get_flag"),FLAG_UNSHADED); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/on_top"),_SCS("set_flag"),_SCS("get_flag"),FLAG_ONTOP); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/vcol_albedo"),_SCS("set_flag"),_SCS("get_flag"),FLAG_ALBEDO_FROM_VERTEX_COLOR); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"params/diffuse_mode",PROPERTY_HINT_ENUM,"Labert,Lambert Wrap,Oren Nayar,Burley"),_SCS("set_diffuse_mode"),_SCS("get_diffuse_mode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"params/blend_mode",PROPERTY_HINT_ENUM,"Mix,Add,Sub,Mul"),_SCS("set_blend_mode"),_SCS("get_blend_mode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"params/cull_mode",PROPERTY_HINT_ENUM,"Back,Front,Disabled"),_SCS("set_cull_mode"),_SCS("get_cull_mode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"params/depth_draw_mode",PROPERTY_HINT_ENUM,"Opaque Only,Always,Never,Opaque Pre-Pass"),_SCS("set_depth_draw_mode"),_SCS("get_depth_draw_mode")); + + ADD_PROPERTY(PropertyInfo(Variant::COLOR,"albedo/color"),_SCS("set_albedo"),_SCS("get_albedo")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"albedo/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_ALBEDO); + + ADD_PROPERTY(PropertyInfo(Variant::COLOR,"specular/color"),_SCS("set_specular"),_SCS("get_specular")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"specular/roughness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_roughness"),_SCS("get_roughness")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"specular/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_SPECULAR); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"normal/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_NORMAL_MAPPING); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"normal/scale",PROPERTY_HINT_RANGE,"-16,16,0.01"),_SCS("set_normal_scale"),_SCS("get_normal_scale")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"normal/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_NORMAL); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"sheen/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_SHEEN); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"sheen/amount",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_sheen"),_SCS("get_sheen")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"sheen/color"),_SCS("set_sheen_color"),_SCS("get_sheen_color")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"sheen/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_SHEEN); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"clearcoat/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_CLEARCOAT); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"clearcoat/amount",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_clearcoat"),_SCS("get_clearcoat")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"clearcoat/gloss"),_SCS("set_clearcoat_gloss"),_SCS("get_clearcoat_gloss")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"clearcoat/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_CLEARCOAT); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"anisotropy/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_ANISOTROPY); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"anisotropy/amount",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_anisotropy"),_SCS("get_anisotropy")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"anisotropy/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_ANISOTROPY); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"ao/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_AMBIENT_OCCLUSION); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"ao/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_AMBIENT_OCCLUSION); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"height/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_HEIGHT_MAPPING); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"height/scale",PROPERTY_HINT_RANGE,"-16,16,0.01"),_SCS("set_height_scale"),_SCS("get_height_scale")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"height/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_HEIGHT); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"subsurf_scatter/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_SUBSURACE_SCATTERING); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"subsurf_scatter/amount",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_subsurface_scattering"),_SCS("get_subsurface_scattering")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"subsurf_scatter/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_SUBSURFACE_SCATTERING); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"refraction/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_REFRACTION); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"refraction/displacement",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_refraction"),_SCS("get_refraction")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"refraction/roughness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_refraction_roughness"),_SCS("get_refraction_roughness")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"refraction/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_REFRACTION); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"detail/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_DETAIL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"detail/mask",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_DETAIL_MASK); + ADD_PROPERTY(PropertyInfo(Variant::INT,"detail/blend_mode",PROPERTY_HINT_ENUM,"Mix,Add,Sub,Mul"),_SCS("set_detail_blend_mode"),_SCS("get_detail_blend_mode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"detail/uv_layer",PROPERTY_HINT_ENUM,"UV1,UV2"),_SCS("set_detail_uv"),_SCS("get_detail_uv")); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"detail/albedo",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_DETAIL_ALBEDO); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"detail/normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_DETAIL_NORMAL); + + BIND_CONSTANT( TEXTURE_ALBEDO ); + BIND_CONSTANT( TEXTURE_SPECULAR ); + BIND_CONSTANT( TEXTURE_EMISSION ); + BIND_CONSTANT( TEXTURE_NORMAL ); + BIND_CONSTANT( TEXTURE_SHEEN ); + BIND_CONSTANT( TEXTURE_CLEARCOAT ); + BIND_CONSTANT( TEXTURE_ANISOTROPY ); + BIND_CONSTANT( TEXTURE_AMBIENT_OCCLUSION ); + BIND_CONSTANT( TEXTURE_HEIGHT ); + BIND_CONSTANT( TEXTURE_SUBSURFACE_SCATTERING ); + BIND_CONSTANT( TEXTURE_REFRACTION ); + BIND_CONSTANT( TEXTURE_REFRACTION_ROUGHNESS ); + BIND_CONSTANT( TEXTURE_DETAIL_MASK ); + BIND_CONSTANT( TEXTURE_DETAIL_ALBEDO ); + BIND_CONSTANT( TEXTURE_DETAIL_NORMAL ); + BIND_CONSTANT( TEXTURE_MAX ); + + + BIND_CONSTANT( DETAIL_UV_1 ); + BIND_CONSTANT( DETAIL_UV_2 ); + + BIND_CONSTANT( FEATURE_TRANSPARENT ); + BIND_CONSTANT( FEATURE_EMISSION ); + BIND_CONSTANT( FEATURE_NORMAL_MAPPING ); + BIND_CONSTANT( FEATURE_SHEEN ); + BIND_CONSTANT( FEATURE_CLEARCOAT ); + BIND_CONSTANT( FEATURE_ANISOTROPY ); + BIND_CONSTANT( FEATURE_AMBIENT_OCCLUSION ); + BIND_CONSTANT( FEATURE_HEIGHT_MAPPING ); + BIND_CONSTANT( FEATURE_SUBSURACE_SCATTERING ); + BIND_CONSTANT( FEATURE_REFRACTION ); + BIND_CONSTANT( FEATURE_DETAIL ); + BIND_CONSTANT( FEATURE_MAX ); + + BIND_CONSTANT( BLEND_MODE_MIX ); + BIND_CONSTANT( BLEND_MODE_ADD ); + BIND_CONSTANT( BLEND_MODE_SUB ); + BIND_CONSTANT( BLEND_MODE_MUL ); + + BIND_CONSTANT( DEPTH_DRAW_OPAQUE_ONLY ); + BIND_CONSTANT( DEPTH_DRAW_ALWAYS ); + BIND_CONSTANT( DEPTH_DRAW_DISABLED ); + BIND_CONSTANT( DEPTH_DRAW_ALPHA_OPAQUE_PREPASS ); + + + BIND_CONSTANT( CULL_BACK ); + BIND_CONSTANT( CULL_FRONT ); + BIND_CONSTANT( CULL_DISABLED ); + + BIND_CONSTANT( FLAG_UNSHADED ); + BIND_CONSTANT( FLAG_ONTOP ); + BIND_CONSTANT( FLAG_ALBEDO_FROM_VERTEX_COLOR ); + BIND_CONSTANT( FLAG_MAX ); + + BIND_CONSTANT( DIFFUSE_LAMBERT ); + BIND_CONSTANT( DIFFUSE_LAMBERT_WRAP ); + BIND_CONSTANT( DIFFUSE_OREN_NAYAR ); + BIND_CONSTANT( DIFFUSE_BURLEY ); +} + + +FixedSpatialMaterial::FixedSpatialMaterial() : element(this) { + + //initialize to right values + set_albedo(Color(0.7,0.7,0.7,1.0)); + set_specular(Color(0.1,0.1,0.1)); + set_roughness(0.0); + set_emission(Color(0,0,0)); + set_normal_scale(1); + set_sheen(0); + set_sheen_color(Color(1,1,1,1)); + set_clearcoat(0); + set_clearcoat_gloss(0.5); + set_anisotropy(0); + set_height_scale(1); + set_subsurface_scattering(0); + set_refraction(0); + set_refraction_roughness(0); + + detail_uv=DETAIL_UV_1; + blend_mode=BLEND_MODE_MIX; + detail_blend_mode=BLEND_MODE_MIX; + depth_draw_mode=DEPTH_DRAW_OPAQUE_ONLY; + cull_mode=CULL_BACK; + for(int i=0;ilock(); + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users==0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + + VS::get_singleton()->material_set_shader(_get_material(),RID()); + } + + + if (material_mutex) + material_mutex->unlock(); + +} diff --git a/scene/resources/material.h b/scene/resources/material.h index 1acc03164..0f0bf4802 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -34,7 +34,7 @@ #include "scene/resources/shader.h" #include "resource.h" #include "servers/visual/shader_language.h" - +#include "self_list.h" /** @author Juan Linietsky */ @@ -57,17 +57,298 @@ public: }; -class FixedMaterial : public Material { +class FixedSpatialMaterial : public Material { - OBJ_TYPE(FixedMaterial,Resource); + OBJ_TYPE(FixedSpatialMaterial,Material) public: - FixedMaterial(); - virtual ~FixedMaterial(); + enum TextureParam { + TEXTURE_ALBEDO, + TEXTURE_SPECULAR, + TEXTURE_EMISSION, + TEXTURE_NORMAL, + TEXTURE_SHEEN, + TEXTURE_CLEARCOAT, + TEXTURE_ANISOTROPY, + TEXTURE_AMBIENT_OCCLUSION, + TEXTURE_HEIGHT, + TEXTURE_SUBSURFACE_SCATTERING, + TEXTURE_REFRACTION, + TEXTURE_REFRACTION_ROUGHNESS, + TEXTURE_DETAIL_MASK, + TEXTURE_DETAIL_ALBEDO, + TEXTURE_DETAIL_NORMAL, + TEXTURE_MAX + + + }; + + + enum DetailUV { + DETAIL_UV_1, + DETAIL_UV_2 + }; + + enum Feature { + FEATURE_TRANSPARENT, + FEATURE_EMISSION, + FEATURE_NORMAL_MAPPING, + FEATURE_SHEEN, + FEATURE_CLEARCOAT, + FEATURE_ANISOTROPY, + FEATURE_AMBIENT_OCCLUSION, + FEATURE_HEIGHT_MAPPING, + FEATURE_SUBSURACE_SCATTERING, + FEATURE_REFRACTION, + FEATURE_DETAIL, + FEATURE_MAX + }; + + + enum BlendMode { + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + }; + + enum DepthDrawMode { + DEPTH_DRAW_OPAQUE_ONLY, + DEPTH_DRAW_ALWAYS, + DEPTH_DRAW_DISABLED, + DEPTH_DRAW_ALPHA_OPAQUE_PREPASS + + }; + + enum CullMode { + CULL_BACK, + CULL_FRONT, + CULL_DISABLED + }; + + enum Flags { + FLAG_UNSHADED, + FLAG_ONTOP, + FLAG_ALBEDO_FROM_VERTEX_COLOR, + FLAG_MAX + }; + + enum DiffuseMode { + DIFFUSE_LAMBERT, + DIFFUSE_LAMBERT_WRAP, + DIFFUSE_OREN_NAYAR, + DIFFUSE_BURLEY, + }; + +private: + union MaterialKey { + + struct { + uint32_t feature_mask : 16; + uint32_t detail_uv : 1; + uint32_t blend_mode : 2; + uint32_t depth_draw_mode : 2; + uint32_t cull_mode : 2; + uint32_t flags : 3; + uint32_t detail_blend_mode : 2; + uint32_t diffuse_mode : 2; + uint32_t invalid_key : 1; + }; + + uint32_t key; + + bool operator<(const MaterialKey& p_key) const { + return key < p_key.key; + } + + }; + + struct ShaderData { + RID shader; + int users; + }; + + static Map shader_map; + + MaterialKey current_key; + + _FORCE_INLINE_ MaterialKey _compute_key() const { + + MaterialKey mk; + mk.key=0; + for(int i=0;i::List dirty_materials; + static ShaderNames* shader_names; + + SelfList element; + + void _update_shader(); + _FORCE_INLINE_ void _queue_shader_change(); + _FORCE_INLINE_ bool _is_shader_dirty() const; + + Color albedo; + Color specular; + float roughness; + Color emission; + float normal_scale; + float sheen; + Color sheen_color; + float clearcoat; + float clearcoat_gloss; + float anisotropy; + float height_scale; + float subsurface_scattering; + float refraction; + float refraction_roughness; + + DetailUV detail_uv; + + BlendMode blend_mode; + BlendMode detail_blend_mode; + DepthDrawMode depth_draw_mode; + CullMode cull_mode; + bool flags[FLAG_MAX]; + DiffuseMode diffuse_mode; + + bool features[FEATURE_MAX]; + + Ref textures[TEXTURE_MAX]; + + _FORCE_INLINE_ void _validate_feature(const String& text, Feature feature,PropertyInfo& property) const; + +protected: + + static void _bind_methods(); + void _validate_property(PropertyInfo& property) const; + +public: + + + void set_albedo(const Color& p_albedo); + Color get_albedo() const; + + void set_specular(const Color& p_specular); + Color get_specular() const; + + void set_roughness(float p_roughness); + float get_roughness() const; + + void set_emission(const Color& p_emission); + Color get_emission() const; + + void set_normal_scale(float p_normal_scale); + float get_normal_scale() const; + + void set_sheen(float p_sheen); + float get_sheen() const; + + void set_sheen_color(const Color& p_sheen_color); + Color get_sheen_color() const; + + void set_clearcoat(float p_clearcoat); + float get_clearcoat() const; + + void set_clearcoat_gloss(float p_clearcoat_gloss); + float get_clearcoat_gloss() const; + + void set_anisotropy(float p_anisotropy); + float get_anisotropy() const; + + void set_height_scale(float p_height_scale); + float get_height_scale() const; + + void set_subsurface_scattering(float p_subsurface_scattering); + float get_subsurface_scattering() const; + + void set_refraction(float p_refraction); + float get_refraction() const; + + void set_refraction_roughness(float p_refraction_roughness); + float get_refraction_roughness() const; + + void set_detail_uv(DetailUV p_detail_uv); + DetailUV get_detail_uv() const; + + void set_blend_mode(BlendMode p_mode); + BlendMode get_blend_mode() const; + + void set_detail_blend_mode(BlendMode p_mode); + BlendMode get_detail_blend_mode() const; + + void set_depth_draw_mode(DepthDrawMode p_mode); + DepthDrawMode get_depth_draw_mode() const; + + void set_cull_mode(CullMode p_mode); + CullMode get_cull_mode() const; + + void set_diffuse_mode(DiffuseMode p_mode); + DiffuseMode get_diffuse_mode() const; + + void set_flag(Flags p_flag,bool p_enabled); + bool get_flag(Flags p_flag) const; + + void set_texture(TextureParam p_param,const Ref& p_texture); + Ref get_texture(TextureParam p_param) const; + + void set_feature(Feature p_feature,bool p_enabled); + bool get_feature(Feature p_feature) const; + + static void init_shaders(); + static void finish_shaders(); + static void flush_changes(); + + FixedSpatialMaterial(); + virtual ~FixedSpatialMaterial(); }; +VARIANT_ENUM_CAST( FixedSpatialMaterial::TextureParam ) +VARIANT_ENUM_CAST( FixedSpatialMaterial::DetailUV ) +VARIANT_ENUM_CAST( FixedSpatialMaterial::Feature ) +VARIANT_ENUM_CAST( FixedSpatialMaterial::BlendMode ) +VARIANT_ENUM_CAST( FixedSpatialMaterial::DepthDrawMode ) +VARIANT_ENUM_CAST( FixedSpatialMaterial::CullMode ) +VARIANT_ENUM_CAST( FixedSpatialMaterial::Flags ) +VARIANT_ENUM_CAST( FixedSpatialMaterial::DiffuseMode ) ////////////////////// diff --git a/servers/visual/rasterizer.cpp b/servers/visual/rasterizer.cpp index 2952098a3..2c62f22a6 100644 --- a/servers/visual/rasterizer.cpp +++ b/servers/visual/rasterizer.cpp @@ -55,10 +55,10 @@ RID Rasterizer::create_default_material() { /* Fixed MAterial SHADER API */ -RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) { +RID Rasterizer::_create_shader(const FixedSpatialMaterialShaderKey& p_key) { ERR_FAIL_COND_V(!p_key.valid,RID()); - Map::Element *E=fixed_material_shaders.find(p_key); + Map::Element *E=fixed_material_shaders.find(p_key); if (E) { E->get().refcount++; @@ -67,7 +67,7 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) { uint64_t t = OS::get_singleton()->get_ticks_usec(); - FixedMaterialShader fms; + FixedSpatialMaterialShader fms; fms.refcount=1; fms.shader=shader_create(); @@ -313,12 +313,12 @@ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) { return fms.shader; } -void Rasterizer::_free_shader(const FixedMaterialShaderKey& p_key) { +void Rasterizer::_free_shader(const FixedSpatialMaterialShaderKey& p_key) { if (p_key.valid==0) return; //not a valid key - Map::Element *E=fixed_material_shaders.find(p_key); + Map::Element *E=fixed_material_shaders.find(p_key); ERR_FAIL_COND(!E); E->get().refcount--; @@ -330,12 +330,12 @@ void Rasterizer::_free_shader(const FixedMaterialShaderKey& p_key) { } -void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags p_flag, bool p_enabled) { +void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag, bool p_enabled) { - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); - FixedMaterial &fm=*E->get(); + FixedSpatialMaterial &fm=*E->get(); switch(p_flag) { @@ -351,11 +351,11 @@ void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags } -bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags p_flag) const{ +bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag) const{ - const Map::Element *E = fixed_materials.find(p_material); + const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,false); - const FixedMaterial &fm=*E->get(); + const FixedSpatialMaterial &fm=*E->get(); switch(p_flag) { case VS::FIXED_MATERIAL_FLAG_USE_ALPHA: return fm.use_alpha;; break; @@ -374,8 +374,8 @@ bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags RID Rasterizer::fixed_material_create() { RID mat = material_create(); - fixed_materials[mat]=memnew( FixedMaterial() ); - FixedMaterial &fm=*fixed_materials[mat]; + fixed_materials[mat]=memnew( FixedSpatialMaterial() ); + FixedSpatialMaterial &fm=*fixed_materials[mat]; fm.self=mat; fm.get_key(); material_set_flag(mat,VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB,true); @@ -391,11 +391,11 @@ RID Rasterizer::fixed_material_create() { -void Rasterizer::fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value){ +void Rasterizer::fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant& p_value){ - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); - FixedMaterial &fm=*E->get(); + FixedSpatialMaterial &fm=*E->get(); RID material=E->key(); ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX); @@ -418,24 +418,24 @@ void Rasterizer::fixed_material_set_parameter(RID p_material, VS::FixedMaterialP } -Variant Rasterizer::fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const{ +Variant Rasterizer::fixed_material_get_parameter(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const{ - const Map::Element *E = fixed_materials.find(p_material); + const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,Variant()); - const FixedMaterial &fm=*E->get(); + const FixedSpatialMaterial &fm=*E->get(); ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,Variant()); return fm.param[p_parameter]; } -void Rasterizer::fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture){ +void Rasterizer::fixed_material_set_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter, RID p_texture){ - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); if (!E) { print_line("Not found: "+itos(p_material.get_id())); } ERR_FAIL_COND(!E); - FixedMaterial &fm=*E->get(); + FixedSpatialMaterial &fm=*E->get(); ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX); @@ -450,22 +450,22 @@ void Rasterizer::fixed_material_set_texture(RID p_material,VS::FixedMaterialPara } -RID Rasterizer::fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const{ +RID Rasterizer::fixed_material_get_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const{ - const Map::Element *E = fixed_materials.find(p_material); + const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,RID()); - const FixedMaterial &fm=*E->get(); + const FixedSpatialMaterial &fm=*E->get(); ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,RID()); return fm.texture[p_parameter]; } -void Rasterizer::fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode) { +void Rasterizer::fixed_material_set_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode) { - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); - FixedMaterial &fm=*E->get(); + FixedSpatialMaterial &fm=*E->get(); ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX); fm.get_key(); @@ -477,11 +477,11 @@ void Rasterizer::fixed_material_set_texcoord_mode(RID p_material,VS::FixedMateri } -VS::FixedMaterialTexCoordMode Rasterizer::fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const { +VS::FixedSpatialMaterialTexCoordMode Rasterizer::fixed_material_get_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const { - const Map::Element *E = fixed_materials.find(p_material); + const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,VS::FIXED_MATERIAL_TEXCOORD_UV); - const FixedMaterial &fm=*E->get(); + const FixedSpatialMaterial &fm=*E->get(); ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,VS::FIXED_MATERIAL_TEXCOORD_UV); return fm.texture_tc[p_parameter]; @@ -489,9 +489,9 @@ VS::FixedMaterialTexCoordMode Rasterizer::fixed_material_get_texcoord_mode(RID p void Rasterizer::fixed_material_set_uv_transform(RID p_material,const Transform& p_transform) { - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); - FixedMaterial &fm=*E->get(); + FixedSpatialMaterial &fm=*E->get(); RID material=E->key(); VS::get_singleton()->material_set_param(material,_fixed_material_uv_xform_name,p_transform); @@ -504,18 +504,18 @@ void Rasterizer::fixed_material_set_uv_transform(RID p_material,const Transform& Transform Rasterizer::fixed_material_get_uv_transform(RID p_material) const { - const Map::Element *E = fixed_materials.find(p_material); + const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,Transform()); - const FixedMaterial &fm=*E->get(); + const FixedSpatialMaterial &fm=*E->get(); return fm.uv_xform; } -void Rasterizer::fixed_material_set_light_shader(RID p_material,VS::FixedMaterialLightShader p_shader) { +void Rasterizer::fixed_material_set_light_shader(RID p_material,VS::FixedSpatialMaterialLightShader p_shader) { - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); - FixedMaterial &fm=*E->get(); + FixedSpatialMaterial &fm=*E->get(); fm.light_shader=p_shader; @@ -524,20 +524,20 @@ void Rasterizer::fixed_material_set_light_shader(RID p_material,VS::FixedMateria } -VS::FixedMaterialLightShader Rasterizer::fixed_material_get_light_shader(RID p_material) const { +VS::FixedSpatialMaterialLightShader Rasterizer::fixed_material_get_light_shader(RID p_material) const { - const Map::Element *E = fixed_materials.find(p_material); + const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,VS::FIXED_MATERIAL_LIGHT_SHADER_LAMBERT); - const FixedMaterial &fm=*E->get(); + const FixedSpatialMaterial &fm=*E->get(); return fm.light_shader; } void Rasterizer::fixed_material_set_point_size(RID p_material,float p_size) { - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); - FixedMaterial &fm=*E->get(); + FixedSpatialMaterial &fm=*E->get(); RID material=E->key(); VS::get_singleton()->material_set_param(material,_fixed_material_point_size_name,p_size); @@ -549,9 +549,9 @@ void Rasterizer::fixed_material_set_point_size(RID p_material,float p_size) { float Rasterizer::fixed_material_get_point_size(RID p_material) const{ - const Map::Element *E = fixed_materials.find(p_material); + const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,1.0); - const FixedMaterial &fm=*E->get(); + const FixedSpatialMaterial &fm=*E->get(); return fm.point_size; @@ -562,9 +562,9 @@ void Rasterizer::_update_fixed_materials() { while(fixed_material_dirty_list.first()) { - FixedMaterial &fm=*fixed_material_dirty_list.first()->self(); + FixedSpatialMaterial &fm=*fixed_material_dirty_list.first()->self(); - FixedMaterialShaderKey new_key = fm.get_key(); + FixedSpatialMaterialShaderKey new_key = fm.get_key(); if (new_key.key!=fm.current_key.key) { _free_shader(fm.current_key); @@ -594,7 +594,7 @@ void Rasterizer::_update_fixed_materials() { void Rasterizer::_free_fixed_material(const RID& p_material) { - Map::Element *E = fixed_materials.find(p_material); + Map::Element *E = fixed_materials.find(p_material); if (E) { @@ -637,7 +637,7 @@ Rasterizer::Rasterizer() { draw_viewport_func=NULL; - ERR_FAIL_COND( sizeof(FixedMaterialShaderKey)!=4); + ERR_FAIL_COND( sizeof(FixedSpatialMaterialShaderKey)!=4); } diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 81cdcf6a2..78757c799 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -44,12 +44,12 @@ public: virtual RID environment_create()=0; virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size)=0; virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer)=0; - virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0)=0; + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_contribution=0.0)=0; virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode)=0; virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture)=0; @@ -90,6 +90,8 @@ public: bool billboard_y :8; bool receive_shadows : 8; + float depth; //used for sorting + SelfList dependency_item; virtual void base_removed()=0; @@ -146,7 +148,7 @@ public: virtual void texture_debug_usage(List *r_info)=0; - virtual RID texture_create_pbr_cubemap(RID p_source,VS::PBRCubeMapMode p_mode,int p_resolution=-1) const=0; + virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const=0; /* SHADER API */ @@ -798,7 +800,7 @@ protected: /* Fixed Material Shader API */ - union FixedMaterialShaderKey { + union FixedSpatialMaterialShaderKey { struct { uint16_t texcoord_mask; @@ -814,21 +816,21 @@ protected: uint32_t key; - _FORCE_INLINE_ bool operator<(const FixedMaterialShaderKey& p_key) const { return key fixed_material_shaders; + Map fixed_material_shaders; - RID _create_shader(const FixedMaterialShaderKey& p_key); - void _free_shader(const FixedMaterialShaderKey& p_key); + RID _create_shader(const FixedSpatialMaterialShaderKey& p_key); + void _free_shader(const FixedSpatialMaterialShaderKey& p_key); - struct FixedMaterial { + struct FixedSpatialMaterial { RID self; @@ -839,19 +841,19 @@ protected: bool use_xy_normalmap; float point_size; Transform uv_xform; - VS::FixedMaterialLightShader light_shader; + VS::FixedSpatialMaterialLightShader light_shader; RID texture[VS::FIXED_MATERIAL_PARAM_MAX]; Variant param[VS::FIXED_MATERIAL_PARAM_MAX]; - VS::FixedMaterialTexCoordMode texture_tc[VS::FIXED_MATERIAL_PARAM_MAX]; + VS::FixedSpatialMaterialTexCoordMode texture_tc[VS::FIXED_MATERIAL_PARAM_MAX]; - SelfList dirty_list; + SelfList dirty_list; - FixedMaterialShaderKey current_key; + FixedSpatialMaterialShaderKey current_key; - _FORCE_INLINE_ FixedMaterialShaderKey get_key() const { + _FORCE_INLINE_ FixedSpatialMaterialShaderKey get_key() const { - FixedMaterialShaderKey k; + FixedSpatialMaterialShaderKey k; k.key=0; k.use_alpha=use_alpha; k.use_color_array=use_color_array; @@ -872,7 +874,7 @@ protected: } - FixedMaterial() : dirty_list(this) { + FixedSpatialMaterial() : dirty_list(this) { use_alpha=false; use_color_array=false; @@ -904,9 +906,9 @@ protected: StringName _fixed_material_uv_xform_name; StringName _fixed_material_point_size_name; - Map fixed_materials; + Map fixed_materials; - SelfList::List fixed_material_dirty_list; + SelfList::List fixed_material_dirty_list; protected: void _update_fixed_materials(); @@ -993,23 +995,23 @@ public: virtual RID fixed_material_create(); - virtual void fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags p_flag, bool p_enabled); - virtual bool fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags p_flag) const; + virtual void fixed_material_set_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag, bool p_enabled); + virtual bool fixed_material_get_flag(RID p_material, VS::FixedSpatialMaterialFlags p_flag) const; - virtual void fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value); - virtual Variant fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const; + virtual void fixed_material_set_parameter(RID p_material, VS::FixedSpatialMaterialParam p_parameter, const Variant& p_value); + virtual Variant fixed_material_get_parameter(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const; - virtual void fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture); - virtual RID fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const; + virtual void fixed_material_set_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter, RID p_texture); + virtual RID fixed_material_get_texture(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const; - virtual void fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode); - virtual VS::FixedMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const; + virtual void fixed_material_set_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter, VS::FixedSpatialMaterialTexCoordMode p_mode); + virtual VS::FixedSpatialMaterialTexCoordMode fixed_material_get_texcoord_mode(RID p_material,VS::FixedSpatialMaterialParam p_parameter) const; virtual void fixed_material_set_uv_transform(RID p_material,const Transform& p_transform); virtual Transform fixed_material_get_uv_transform(RID p_material) const; - virtual void fixed_material_set_light_shader(RID p_material,VS::FixedMaterialLightShader p_shader); - virtual VS::FixedMaterialLightShader fixed_material_get_light_shader(RID p_material) const; + virtual void fixed_material_set_light_shader(RID p_material,VS::FixedSpatialMaterialLightShader p_shader); + virtual VS::FixedSpatialMaterialLightShader fixed_material_get_light_shader(RID p_material) const; virtual void fixed_material_set_point_size(RID p_material,float p_size); virtual float fixed_material_get_point_size(RID p_material) const; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 065bb4d31..357546e59 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -260,11 +260,11 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[]={ {TK_UNIFORM,"uniform"}, {TK_VARYING,"varying"}, {TK_RENDER_MODE,"render_mode"}, - {TK_HINT_WHITE_TEXTURE,"white"}, - {TK_HINT_BLACK_TEXTURE,"black"}, - {TK_HINT_NORMAL_TEXTURE,"normal"}, - {TK_HINT_ALBEDO_TEXTURE,"albedo"}, - {TK_HINT_COLOR,"color"}, + {TK_HINT_WHITE_TEXTURE,"hint_white"}, + {TK_HINT_BLACK_TEXTURE,"hint_black"}, + {TK_HINT_NORMAL_TEXTURE,"hint_normal"}, + {TK_HINT_ALBEDO_TEXTURE,"hint_albedo"}, + {TK_HINT_COLOR,"hint_color"}, {TK_HINT_RANGE,"hint_range"}, {TK_ERROR,NULL} @@ -604,7 +604,7 @@ String ShaderLanguage::token_debug(const String& p_code) { Token tk = _get_token(); while(tk.type!=TK_EOF && tk.type!=TK_ERROR) { - print_line(get_token_text(tk)); + output+=itos(tk_line)+": "+get_token_text(tk)+"\n"; tk = _get_token(); } @@ -2232,9 +2232,7 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const Node *expr=NULL; TkPos prepos = _get_tkpos(); Token tk = _get_token(); - TkPos pos = _get_tkpos(); - - print_line("in expr: "+get_token_text(tk)); + TkPos pos = _get_tkpos(); if (tk.type==TK_PARENTHESIS_OPEN) { @@ -2301,8 +2299,6 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const } else if (is_token_nonvoid_datatype(tk.type)) { //basic type constructor - print_line("parse constructor"); - OperatorNode *func = alloc_node(); func->op=OP_CONSTRUCT; @@ -3193,17 +3189,17 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Maprender_modes.find(tk.text)!=-1) { - _set_error("Duplicate render mode: '"+String(tk.text)+"'"); + if (shader->render_modes.find(mode)!=-1) { + _set_error("Duplicate render mode: '"+String(mode)+"'"); return ERR_PARSE_ERROR; } - shader->render_modes.push_back(tk.text); + shader->render_modes.push_back(mode); tk = _get_token(); if (tk.type==TK_COMMA) { @@ -3262,7 +3258,7 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Mapuniforms.size(); + if (is_sampler_type(type)) { uniform.texture_order=texture_uniforms++; uniform.order=-1; @@ -3331,7 +3327,7 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map >::Element *E=p_functions.front();E;E=E->next()) { r_options->push_back(E->key()); @@ -3635,7 +3629,6 @@ Error ShaderLanguage::complete(const String& p_code,const Map< StringName, Map matches; @@ -3709,7 +3702,6 @@ Error ShaderLanguage::complete(const String& p_code,const Map< StringName, Mapfunctions.size();i++) { if (!shader->functions[i].callable) continue; diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 767d11bc8..8c54ef11f 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -136,16 +136,16 @@ ShaderTypes::ShaderTypes() shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["POINT_COORD"]=ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["TIME"]=ShaderLanguage::TYPE_FLOAT; - shader_modes[VS::SHADER_SPATIAL].modes.insert("skip_transform"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("skip_transform"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mix"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_add"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_sub"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mul"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_premul_alpha"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("blend_mix"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("blend_add"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("blend_sub"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("blend_mul"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("blend_premul_alpha"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("light_only"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("unshaded"); + shader_modes[VS::SHADER_CANVAS_ITEM].modes.insert("light_only"); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 70abfe236..bbad460f4 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -405,33 +405,33 @@ RID VisualServerRaster::fixed_material_create() { return rasterizer->fixed_material_create(); } -void VisualServerRaster::fixed_material_set_flag(RID p_material, FixedMaterialFlags p_flag, bool p_enabled) { +void VisualServerRaster::fixed_material_set_flag(RID p_material, FixedSpatialMaterialFlags p_flag, bool p_enabled) { rasterizer->fixed_material_set_flag(p_material,p_flag,p_enabled); } -bool VisualServerRaster::fixed_material_get_flag(RID p_material, FixedMaterialFlags p_flag) const { +bool VisualServerRaster::fixed_material_get_flag(RID p_material, FixedSpatialMaterialFlags p_flag) const { return rasterizer->fixed_material_get_flag(p_material,p_flag); } -void VisualServerRaster::fixed_material_set_param(RID p_material, FixedMaterialParam p_parameter, const Variant& p_value) { +void VisualServerRaster::fixed_material_set_param(RID p_material, FixedSpatialMaterialParam p_parameter, const Variant& p_value) { VS_CHANGED; rasterizer->fixed_material_set_parameter(p_material,p_parameter,p_value); } -Variant VisualServerRaster::fixed_material_get_param(RID p_material,FixedMaterialParam p_parameter) const { +Variant VisualServerRaster::fixed_material_get_param(RID p_material,FixedSpatialMaterialParam p_parameter) const { return rasterizer->fixed_material_get_parameter(p_material,p_parameter); } -void VisualServerRaster::fixed_material_set_texture(RID p_material,FixedMaterialParam p_parameter, RID p_texture) { +void VisualServerRaster::fixed_material_set_texture(RID p_material,FixedSpatialMaterialParam p_parameter, RID p_texture) { VS_CHANGED; rasterizer->fixed_material_set_texture(p_material,p_parameter,p_texture); } -RID VisualServerRaster::fixed_material_get_texture(RID p_material,FixedMaterialParam p_parameter) const { +RID VisualServerRaster::fixed_material_get_texture(RID p_material,FixedSpatialMaterialParam p_parameter) const { return rasterizer->fixed_material_get_texture(p_material,p_parameter); } @@ -439,12 +439,12 @@ RID VisualServerRaster::fixed_material_get_texture(RID p_material,FixedMaterialP -void VisualServerRaster::fixed_material_set_texcoord_mode(RID p_material,FixedMaterialParam p_parameter, FixedMaterialTexCoordMode p_mode) { +void VisualServerRaster::fixed_material_set_texcoord_mode(RID p_material,FixedSpatialMaterialParam p_parameter, FixedSpatialMaterialTexCoordMode p_mode) { VS_CHANGED; rasterizer->fixed_material_set_texcoord_mode(p_material,p_parameter,p_mode); } -VS::FixedMaterialTexCoordMode VisualServerRaster::fixed_material_get_texcoord_mode(RID p_material,FixedMaterialParam p_parameter) const { +VS::FixedSpatialMaterialTexCoordMode VisualServerRaster::fixed_material_get_texcoord_mode(RID p_material,FixedSpatialMaterialParam p_parameter) const { return rasterizer->fixed_material_get_texcoord_mode(p_material,p_parameter); } @@ -471,14 +471,14 @@ Transform VisualServerRaster::fixed_material_get_uv_transform(RID p_material) co return rasterizer->fixed_material_get_uv_transform(p_material); } -void VisualServerRaster::fixed_material_set_light_shader(RID p_material,FixedMaterialLightShader p_shader) { +void VisualServerRaster::fixed_material_set_light_shader(RID p_material,FixedSpatialMaterialLightShader p_shader) { VS_CHANGED; rasterizer->fixed_material_set_light_shader(p_material,p_shader); } -VisualServerRaster::FixedMaterialLightShader VisualServerRaster::fixed_material_get_light_shader(RID p_material) const{ +VisualServerRaster::FixedSpatialMaterialLightShader VisualServerRaster::fixed_material_get_light_shader(RID p_material) const{ return rasterizer->fixed_material_get_light_shader(p_material); } diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index a2502e89f..655ce410b 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -620,7 +620,7 @@ public: BIND1RC(uint32_t,texture_get_width,RID) BIND1RC(uint32_t,texture_get_height,RID) BIND3(texture_set_size_override,RID,int,int) - BIND3RC(RID,texture_create_pbr_cubemap,RID,PBRCubeMapMode,int) + BIND2RC(RID,texture_create_radiance_cubemap,RID,int) @@ -854,7 +854,7 @@ public: BIND0R(RID,environment_create) BIND2(environment_set_background,RID ,EnvironmentBG ) - BIND4(environment_set_skybox,RID,RID ,int,int ) + BIND3(environment_set_skybox,RID,RID ,int ) BIND2(environment_set_skybox_scale,RID,float) BIND2(environment_set_bg_color,RID,const Color& ) BIND2(environment_set_bg_energy,RID,float ) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 8fdf3d160..2f0f8f263 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -337,8 +337,7 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ light->D=NULL; } VSG::scene_render->free(light->instance); - - } + } break; } if (instance->base_data) { @@ -492,12 +491,12 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ light->instance = VSG::scene_render->light_instance_create(p_base); instance->base_data=light; - } + } break; case VS::INSTANCE_MESH: { InstanceGeometryData *geom = memnew( InstanceGeometryData ); instance->base_data=geom; - } + } break; } @@ -596,7 +595,7 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){ instance->scenario->directional_lights.erase( light->D ); light->D=NULL; } - } + } break; } instance->scenario=NULL; @@ -623,7 +622,7 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){ if (VSG::storage->light_get_type(instance->base)==VS::LIGHT_DIRECTIONAL) { light->D = scenario->directional_lights.push_back(instance); } - } + } break; } _instance_queue_update(instance,true,true); @@ -711,12 +710,59 @@ Vector VisualServerScene::instances_cull_convex(const Vector& p void VisualServerScene::instance_geometry_set_flag(RID p_instance,VS::InstanceFlags p_flags,bool p_enabled){ + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + switch(p_flags) { + + case VS::INSTANCE_FLAG_VISIBLE: { + + instance->visible=p_enabled; + + } break; + case VS::INSTANCE_FLAG_BILLBOARD: { + + instance->billboard=p_enabled; + + } break; + case VS::INSTANCE_FLAG_BILLBOARD_FIX_Y: { + + instance->billboard_y=p_enabled; + + } break; + case VS::INSTANCE_FLAG_CAST_SHADOW: { + /*if (p_enabled == true) { + instance->cast_shadows = SHADOW_CASTING_SETTING_ON; + } + else { + instance->cast_shadows = SHADOW_CASTING_SETTING_OFF; + }*/ + + } break; + case VS::INSTANCE_FLAG_DEPH_SCALE: { + + instance->depth_scale=p_enabled; + + } break; + case VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS: { + + instance->visible_in_all_rooms=p_enabled; + + } break; + + } } void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) { } void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material){ + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + instance->material_override=p_material; + + } @@ -1151,7 +1197,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp //failure } else if (ins->base_type==VS::INSTANCE_LIGHT && ins->visible) { - if (light_cull_countvisible && light_cull_count(ins->base_data); @@ -1253,6 +1300,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp geom->lighting_dirty=false; } + ins->depth = near_plane.distance_to(ins->transform.origin); + } if (!keep) { diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 97825c172..95636d2bc 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1036,30 +1036,23 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi } } - print_line("type "+itos(i)+" size: "+itos(elem_size)+" offset "+itos(total_elem_size)); offsets[i]=total_elem_size; total_elem_size+=elem_size; } - print_line("total elemn size: "+itos(total_elem_size)); - uint32_t mask = (1< vertex_array; vertex_array.resize(array_size); int index_array_size = offsets[VS::ARRAY_INDEX]*index_array_len; - print_line("index array size: "+itos(index_array_size)); - DVector index_array; index_array.resize(index_array_size); diff --git a/servers/visual_server.h b/servers/visual_server.h index 11828c7d2..bbe6c2c68 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -125,12 +125,7 @@ public: virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable)=0; - enum PBRCubeMapMode { - PBR_CUBEMAP_RADIANCE, - PBR_CUBEMAP_IRRADIANCE, - }; - - virtual RID texture_create_pbr_cubemap(RID p_source,PBRCubeMapMode p_mode,int p_resolution=-1) const=0; + virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const=0; struct TextureInfo { RID texture; @@ -349,7 +344,9 @@ public: LIGHT_PARAM_ENERGY, LIGHT_PARAM_SPECULAR, LIGHT_PARAM_RANGE, + LIGHT_PARAM_ATTENUATION, LIGHT_PARAM_SPOT_ANGLE, + LIGHT_PARAM_SPOT_ATTENUATION, LIGHT_PARAM_SHADOW_MAX_DISTANCE, LIGHT_PARAM_SHADOW_DARKNESS, LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET, @@ -357,10 +354,8 @@ public: LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET, LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET, LIGHT_PARAM_SHADOW_NORMAL_BIAS, - LIGHT_PARAM_SHADOW_BIAS_1, - LIGHT_PARAM_SHADOW_BIAS_2, - LIGHT_PARAM_SHADOW_BIAS_3, - LIGHT_PARAM_SHADOW_BIAS_4, + LIGHT_PARAM_SHADOW_BIAS, + LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE, LIGHT_PARAM_MAX }; @@ -494,12 +489,12 @@ public: }; virtual void environment_set_background(RID p_env,EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size,int p_irradiance_size)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size)=0; virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; virtual void environment_set_canvas_max_layer(RID p_env,int p_max_layer)=0; - virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_energy=0.0)=0; + virtual void environment_set_ambient_light(RID p_env,const Color& p_color,float p_energy=1.0,float p_skybox_contribution=0.0)=0; //set default SSAO options //set default SSR options diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index 6b1873d49..e8207c957 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -377,7 +377,7 @@ Error ColladaImport::_create_material(const String& p_target) { ERR_FAIL_COND_V(!collada.state.effect_map.has(src_mat.instance_effect),ERR_INVALID_PARAMETER); Collada::Effect &effect=collada.state.effect_map[src_mat.instance_effect]; - Ref material= memnew( FixedMaterial ); + Ref material= memnew( FixedSpatialMaterial ); if (src_mat.name!="") material->set_name(src_mat.name); @@ -394,14 +394,14 @@ Error ColladaImport::_create_material(const String& p_target) { Ref texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { -// material->set_texture(FixedMaterial::PARAM_DIFFUSE,texture); -// material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,1)); +// material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,texture); +// material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1)); } else { missing_textures.push_back(texfile.get_file()); } } } else { -// material->set_parameter(FixedMaterial::PARAM_DIFFUSE,effect.diffuse.color); +// material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,effect.diffuse.color); } // SPECULAR @@ -414,15 +414,15 @@ Error ColladaImport::_create_material(const String& p_target) { Ref texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { -// material->set_texture(FixedMaterial::PARAM_SPECULAR,texture); -// material->set_parameter(FixedMaterial::PARAM_SPECULAR,Color(1,1,1,1)); +// material->set_texture(FixedSpatialMaterial::PARAM_SPECULAR,texture); +// material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1)); } else { missing_textures.push_back(texfile.get_file()); } } } else { -// material->set_parameter(FixedMaterial::PARAM_SPECULAR,effect.specular.color); +// material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,effect.specular.color); } // EMISSION @@ -435,15 +435,15 @@ Error ColladaImport::_create_material(const String& p_target) { Ref texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { -// material->set_texture(FixedMaterial::PARAM_EMISSION,texture); -// material->set_parameter(FixedMaterial::PARAM_EMISSION,Color(1,1,1,1)); +// material->set_texture(FixedSpatialMaterial::PARAM_EMISSION,texture); +// material->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,Color(1,1,1,1)); }else { // missing_textures.push_back(texfile.get_file()); } } } else { -// material->set_parameter(FixedMaterial::PARAM_EMISSION,effect.emission.color); +// material->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,effect.emission.color); } // NORMAL @@ -456,7 +456,7 @@ Error ColladaImport::_create_material(const String& p_target) { Ref texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { - // material->set_texture(FixedMaterial::PARAM_NORMAL,texture); + // material->set_texture(FixedSpatialMaterial::PARAM_NORMAL,texture); }else { // missing_textures.push_back(texfile.get_file()); } @@ -465,7 +465,7 @@ Error ColladaImport::_create_material(const String& p_target) { } -// material->set_parameter(FixedMaterial::PARAM_SPECULAR_EXP,effect.shininess); +// material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR_EXP,effect.shininess); // material->set_flag(Material::FLAG_DOUBLE_SIDED,effect.double_sided); // material->set_flag(Material::FLAG_UNSHADED,effect.unshaded); @@ -1042,7 +1042,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref& p_mesh,con { - Ref material; + Ref material; //find material Mesh::PrimitiveType primitive=Mesh::PRIMITIVE_TRIANGLES; diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp index 9d68807c4..41b245eb7 100644 --- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp @@ -1392,7 +1392,7 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Map::Element *E=pl.front();E;E=E->next()) { if (E->get().type==Variant::OBJECT || E->get().type==Variant::ARRAY || E->get().type==Variant::DICTIONARY) { - if (E->get().type==Variant::OBJECT && res->cast_to() && (E->get().name=="textures/diffuse" || E->get().name=="textures/detail" || E->get().name=="textures/emission")) { + if (E->get().type==Variant::OBJECT && res->cast_to() && (E->get().name=="textures/diffuse" || E->get().name=="textures/detail" || E->get().name=="textures/emission")) { Ref tex =res->get(E->get().name); if (tex.is_valid()) { @@ -1400,14 +1400,14 @@ void EditorSceneImportPlugin::_find_resources(const Variant& p_var, Mapget().type==Variant::OBJECT && res->cast_to() && (E->get().name=="textures/normal")) { + } else if (E->get().type==Variant::OBJECT && res->cast_to() && (E->get().name=="textures/normal")) { Ref tex =res->get(E->get().name); if (tex.is_valid()) { image_map.insert(tex,TEXTURE_ROLE_NORMALMAP); //if (p_flags&SCENE_FLAG_CONVERT_NORMALMAPS_TO_XY) - // res->cast_to()->set_fixed_flag(FixedMaterial::FLAG_USE_XY_NORMALMAP,true); + // res->cast_to()->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_XY_NORMALMAP,true); }// @@ -1514,12 +1514,12 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map Ref m = mi->get_mesh(); for(int i=0;iget_surface_count();i++) { - Ref fm = m->surface_get_material(i); + Ref fm = m->surface_get_material(i); if (fm.is_valid()) { // fm->set_flag(Material::FLAG_UNSHADED,true); // fm->set_flag(Material::FLAG_DOUBLE_SIDED,true); // fm->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - // fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); + // fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); } } } @@ -1537,18 +1537,18 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map for(int i=0;iget_surface_count();i++) { - Ref mat = m->surface_get_material(i); + Ref mat = m->surface_get_material(i); if (!mat.is_valid()) continue; if (p_flags&SCENE_FLAG_DETECT_ALPHA && _teststr(mat->get_name(),"alpha")) { - // mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); + // mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); // mat->set_name(_fixstr(mat->get_name(),"alpha")); } if (p_flags&SCENE_FLAG_DETECT_VCOLOR && _teststr(mat->get_name(),"vcol")) { - //mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); + //mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true); //mat->set_name(_fixstr(mat->get_name(),"vcol")); } @@ -1623,12 +1623,12 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map Ref m = mi->get_mesh(); for(int i=0;iget_surface_count();i++) { - Ref fm = m->surface_get_material(i); + Ref fm = m->surface_get_material(i); if (fm.is_valid()) { // fm->set_flag(Material::FLAG_UNSHADED,true); // fm->set_flag(Material::FLAG_DOUBLE_SIDED,true); // fm->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - // fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); + // fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); } } } @@ -1671,12 +1671,12 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map Ref m = mi->get_mesh(); for(int i=0;iget_surface_count();i++) { - Ref fm = m->surface_get_material(i); + Ref fm = m->surface_get_material(i); if (fm.is_valid()) { fm->set_flag(Material::FLAG_UNSHADED,true); fm->set_flag(Material::FLAG_DOUBLE_SIDED,true); fm->set_hint(Material::HINT_NO_DEPTH_DRAW,true); - fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); + fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); } } }*/ @@ -2044,16 +2044,16 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map for(int i=0;iget_surface_count();i++) { - Ref fm = mesh->surface_get_material(i); + Ref fm = mesh->surface_get_material(i); if (fm.is_valid()) { String name = fm->get_name(); /* if (_teststr(name,"alpha")) { - fm->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); + fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); name=_fixstr(name,"alpha"); } if (_teststr(name,"vcol")) { - fm->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); + fm->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true); name=_fixstr(name,"vcol"); }*/ fm->set_name(name); diff --git a/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp b/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp index f11718236..a954db829 100644 --- a/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp +++ b/tools/editor/io_plugins/editor_scene_importer_fbxconv.cpp @@ -482,29 +482,29 @@ void EditorSceneImporterFBXConv::_parse_materials(State& state) { ERR_CONTINUE(!material.has("id")); String id = _id(material["id"]); - Ref mat = memnew( FixedMaterial ); + Ref mat = memnew( FixedSpatialMaterial ); if (material.has("diffuse")) { - mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,_get_color(material["diffuse"])); + mat->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,_get_color(material["diffuse"])); } if (material.has("specular")) { - mat->set_parameter(FixedMaterial::PARAM_SPECULAR,_get_color(material["specular"])); + mat->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,_get_color(material["specular"])); } if (material.has("emissive")) { - mat->set_parameter(FixedMaterial::PARAM_EMISSION,_get_color(material["emissive"])); + mat->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,_get_color(material["emissive"])); } if (material.has("shininess")) { float exp = material["shininess"]; - mat->set_parameter(FixedMaterial::PARAM_SPECULAR_EXP,exp); + mat->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR_EXP,exp); } if (material.has("opacity")) { - Color c = mat->get_parameter(FixedMaterial::PARAM_DIFFUSE); + Color c = mat->get_parameter(FixedSpatialMaterial::PARAM_DIFFUSE); c.a=material["opacity"]; - mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,c); + mat->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,c); } @@ -536,15 +536,15 @@ void EditorSceneImporterFBXConv::_parse_materials(State& state) { String type=texture["type"]; if (type=="DIFFUSE") - mat->set_texture(FixedMaterial::PARAM_DIFFUSE,tex); + mat->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,tex); else if (type=="SPECULAR") - mat->set_texture(FixedMaterial::PARAM_SPECULAR,tex); + mat->set_texture(FixedSpatialMaterial::PARAM_SPECULAR,tex); else if (type=="SHININESS") - mat->set_texture(FixedMaterial::PARAM_SPECULAR_EXP,tex); + mat->set_texture(FixedSpatialMaterial::PARAM_SPECULAR_EXP,tex); else if (type=="NORMAL") - mat->set_texture(FixedMaterial::PARAM_NORMAL,tex); + mat->set_texture(FixedSpatialMaterial::PARAM_NORMAL,tex); else if (type=="EMISSIVE") - mat->set_texture(FixedMaterial::PARAM_EMISSION,tex); + mat->set_texture(FixedSpatialMaterial::PARAM_EMISSION,tex); } } diff --git a/tools/editor/plugins/baked_light_baker.cpp b/tools/editor/plugins/baked_light_baker.cpp index 5cdae6aff..f31c8adf8 100644 --- a/tools/editor/plugins/baked_light_baker.cpp +++ b/tools/editor/plugins/baked_light_baker.cpp @@ -143,18 +143,18 @@ void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& p_m MeshMaterial mm; - Ref fm = mat; + Ref fm = mat; if (fm.is_valid()) { //fixed route - mm.diffuse.color=fm->get_parameter(FixedMaterial::PARAM_DIFFUSE); + mm.diffuse.color=fm->get_parameter(FixedSpatialMaterial::PARAM_DIFFUSE); if (linear_color) mm.diffuse.color=mm.diffuse.color.to_linear(); - mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_DIFFUSE)); - mm.specular.color=fm->get_parameter(FixedMaterial::PARAM_SPECULAR); + mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedSpatialMaterial::PARAM_DIFFUSE)); + mm.specular.color=fm->get_parameter(FixedSpatialMaterial::PARAM_SPECULAR); if (linear_color) mm.specular.color=mm.specular.color.to_linear(); - mm.specular.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_SPECULAR)); + mm.specular.tex=_get_mat_tex(fm->get_texture(FixedSpatialMaterial::PARAM_SPECULAR)); } else { mm.diffuse.color=Color(1,1,1,1); diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_editor_plugin.cpp index ccec7eaed..472ada116 100644 --- a/tools/editor/plugins/collision_polygon_editor_plugin.cpp +++ b/tools/editor/plugins/collision_polygon_editor_plugin.cpp @@ -570,25 +570,25 @@ CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) { imgeom->set_transform(Transform(Matrix3(),Vector3(0,0,0.00001))); - line_material = Ref( memnew( FixedMaterial )); + line_material = Ref( memnew( FixedSpatialMaterial )); line_material->set_flag(Material::FLAG_UNSHADED, true); line_material->set_line_width(3.0); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1)); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1)); - handle_material = Ref( memnew( FixedMaterial )); + handle_material = Ref( memnew( FixedSpatialMaterial )); handle_material->set_flag(Material::FLAG_UNSHADED, true); - handle_material->set_fixed_flag(FixedMaterial::FLAG_USE_POINT_SIZE, true); - handle_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1)); - handle_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - handle_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false); + handle_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_POINT_SIZE, true); + handle_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1)); + handle_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + handle_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, false); Ref handle=editor->get_gui_base()->get_icon("Editor3DHandle","EditorIcons"); handle_material->set_point_size(handle->get_width()); - handle_material->set_texture(FixedMaterial::PARAM_DIFFUSE,handle); + handle_material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,handle); pointsm = memnew( MeshInstance ); imgeom->add_child(pointsm); diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.h b/tools/editor/plugins/collision_polygon_editor_plugin.h index 4c1f45eca..ed371e81b 100644 --- a/tools/editor/plugins/collision_polygon_editor_plugin.h +++ b/tools/editor/plugins/collision_polygon_editor_plugin.h @@ -62,8 +62,8 @@ class CollisionPolygonEditor : public HBoxContainer { ToolButton *button_edit; - Ref line_material; - Ref handle_material; + Ref line_material; + Ref handle_material; EditorNode *editor; Panel *panel; diff --git a/tools/editor/plugins/path_editor_plugin.cpp b/tools/editor/plugins/path_editor_plugin.cpp index aa7071298..c56d526de 100644 --- a/tools/editor/plugins/path_editor_plugin.cpp +++ b/tools/editor/plugins/path_editor_plugin.cpp @@ -523,16 +523,16 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { editor=p_node; singleton=this; - path_material = Ref( memnew( FixedMaterial )); - path_material->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.8) ); - path_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); + path_material = Ref( memnew( FixedSpatialMaterial )); + path_material->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.8) ); + path_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); path_material->set_line_width(3); path_material->set_flag(Material::FLAG_DOUBLE_SIDED,true); path_material->set_flag(Material::FLAG_UNSHADED,true); - path_thin_material = Ref( memnew( FixedMaterial )); - path_thin_material->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.4) ); - path_thin_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); + path_thin_material = Ref( memnew( FixedSpatialMaterial )); + path_thin_material->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.4) ); + path_thin_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); path_thin_material->set_line_width(1); path_thin_material->set_flag(Material::FLAG_DOUBLE_SIDED,true); path_thin_material->set_flag(Material::FLAG_UNSHADED,true); diff --git a/tools/editor/plugins/path_editor_plugin.h b/tools/editor/plugins/path_editor_plugin.h index ee2196b47..ab9474f38 100644 --- a/tools/editor/plugins/path_editor_plugin.h +++ b/tools/editor/plugins/path_editor_plugin.h @@ -79,8 +79,8 @@ public: Path *get_edited_path() { return path; } static PathEditorPlugin* singleton; - Ref path_material; - Ref path_thin_material; + Ref path_material; + Ref path_thin_material; virtual bool forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event); // virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); } diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 38a7706ac..7a24ab418 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -2548,11 +2548,11 @@ void SpatialEditor::_generate_selection_box() { } - Ref mat = memnew( FixedMaterial ); - /*mat->set_flag(Material::FLAG_UNSHADED,true); - mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1)); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);*/ + Ref mat = memnew( FixedSpatialMaterial ); + mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + mat->set_albedo(Color(1,1,1)); + mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true); + mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); st->set_material(mat); selection_box = st->commit(); } @@ -3139,11 +3139,11 @@ void SpatialEditor::_init_indicators() { { - indicator_mat = VisualServer::get_singleton()->material_create(); - /*VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true ); - VisualServer::get_singleton()->material_set_flag( indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false ); - VisualServer::get_singleton()->fixed_material_set_flag(indicator_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true); - VisualServer::get_singleton()->fixed_material_set_flag(indicator_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);*/ + indicator_mat.instance();; + indicator_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP,true); + indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); + indicator_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true); DVector grid_colors[3]; DVector grid_points[3]; @@ -3186,7 +3186,7 @@ void SpatialEditor::_init_indicators() { d[VisualServer::ARRAY_VERTEX]=grid_points[i]; d[VisualServer::ARRAY_COLOR]=grid_colors[i]; VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[i],VisualServer::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat); + VisualServer::get_singleton()->mesh_surface_set_material(grid[i],0,indicator_mat->get_rid()); grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i],get_tree()->get_root()->get_world()->get_scenario()); grid_visible[i]=false; @@ -3205,7 +3205,7 @@ void SpatialEditor::_init_indicators() { d[VisualServer::ARRAY_COLOR]=origin_colors; VisualServer::get_singleton()->mesh_add_surface_from_arrays(origin,VisualServer::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(origin,0,indicator_mat); + VisualServer::get_singleton()->mesh_surface_set_material(origin,0,indicator_mat->get_rid()); // origin = VisualServer::get_singleton()->poly_create(); @@ -3236,17 +3236,15 @@ void SpatialEditor::_init_indicators() { cursor_points.push_back(Vector3(0,-cs,0)); cursor_points.push_back(Vector3(0,0,+cs)); cursor_points.push_back(Vector3(0,0,-cs)); - cursor_material=VisualServer::get_singleton()->material_create(); - /*VisualServer::get_singleton()->fixed_material_set_param(cursor_material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0,1,1)); - VisualServer::get_singleton()->material_set_flag( cursor_material, VisualServer::MATERIAL_FLAG_UNSHADED, true ); - VisualServer::get_singleton()->fixed_material_set_flag(cursor_material, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true); - VisualServer::get_singleton()->fixed_material_set_flag(cursor_material, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);*/ + cursor_material.instance(); + cursor_material->set_albedo(Color(0,1,1)); + cursor_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); Array d; d.resize(VS::ARRAY_MAX); d[VS::ARRAY_VERTEX]=cursor_points; VisualServer::get_singleton()->mesh_add_surface_from_arrays(cursor_mesh,VS::PRIMITIVE_LINES,d); - VisualServer::get_singleton()->mesh_surface_set_material(cursor_mesh,0,cursor_material); + VisualServer::get_singleton()->mesh_surface_set_material(cursor_mesh,0,cursor_material->get_rid()); cursor_instance = VisualServer::get_singleton()->instance_create2(cursor_mesh,get_tree()->get_root()->get_world()->get_scenario()); VS::get_singleton()->instance_set_layer_mask(cursor_instance,1<get("3d_editor/manipulator_gizmo_opacity"); - gizmo_hl = Ref( memnew( FixedMaterial ) ); - /* gizmo_hl->set_flag(Material::FLAG_UNSHADED, true); - gizmo_hl->set_flag(Material::FLAG_ONTOP, true); - gizmo_hl->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - gizmo_hl->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,gizmo_alph+0.2f));*/ + gizmo_hl = Ref( memnew( FixedSpatialMaterial ) ); + gizmo_hl->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + gizmo_hl->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true); + gizmo_hl->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + gizmo_hl->set_albedo(Color(1,1,1,gizmo_alph+0.2f)); for(int i=0;i<3;i++) { @@ -3276,14 +3274,14 @@ void SpatialEditor::_init_indicators() { rotate_gizmo[i]=Ref( memnew( Mesh ) ); - Ref mat = memnew( FixedMaterial ); - /* mat->set_flag(Material::FLAG_UNSHADED, true); - mat->set_flag(Material::FLAG_ONTOP, true); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); + Ref mat = memnew( FixedSpatialMaterial ); + mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP, true); + mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); Color col; col[i]=1.0; col.a= gizmo_alph; - mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,col);*/ + mat->set_albedo(col); gizmo_color[i]=mat; @@ -3429,8 +3427,6 @@ void SpatialEditor::_finish_indicators() { VisualServer::get_singleton()->free(cursor_instance); VisualServer::get_singleton()->free(cursor_mesh); - VisualServer::get_singleton()->free(indicator_mat); - VisualServer::get_singleton()->free(cursor_material); } void SpatialEditor::_instance_scene() { diff --git a/tools/editor/plugins/spatial_editor_plugin.h b/tools/editor/plugins/spatial_editor_plugin.h index 4751cf707..8c8a80bc3 100644 --- a/tools/editor/plugins/spatial_editor_plugin.h +++ b/tools/editor/plugins/spatial_editor_plugin.h @@ -331,8 +331,8 @@ private: bool grid_enabled; Ref move_gizmo[3], rotate_gizmo[3]; - Ref gizmo_color[3]; - Ref gizmo_hl; + Ref gizmo_color[3]; + Ref gizmo_hl; int over_gizmo_handle; @@ -344,8 +344,8 @@ private: RID indicators_instance; RID cursor_mesh; RID cursor_instance; - RID indicator_mat; - RID cursor_material; + Ref indicator_mat; + Ref cursor_material; /* struct Selected { diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index 716b03b7b..bc76f6c20 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -2976,25 +2976,25 @@ Ref SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { } -Ref SpatialEditorGizmos::create_line_material(const Color& p_base_color) { +Ref SpatialEditorGizmos::create_line_material(const Color& p_base_color) { - Ref line_material = Ref( memnew( FixedMaterial )); + Ref line_material = Ref( memnew( FixedSpatialMaterial )); line_material->set_flag(Material::FLAG_UNSHADED, true); line_material->set_line_width(3.0); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,p_base_color); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,p_base_color); return line_material; } -Ref SpatialEditorGizmos::create_solid_material(const Color& p_base_color) { +Ref SpatialEditorGizmos::create_solid_material(const Color& p_base_color) { - Ref line_material = Ref( memnew( FixedMaterial )); + Ref line_material = Ref( memnew( FixedSpatialMaterial )); line_material->set_flag(Material::FLAG_UNSHADED, true); - line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,p_base_color); + line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,p_base_color); return line_material; @@ -3004,50 +3004,50 @@ SpatialEditorGizmos::SpatialEditorGizmos() { singleton=this; - handle_material = Ref( memnew( FixedMaterial )); + handle_material = Ref( memnew( FixedSpatialMaterial )); handle_material->set_flag(Material::FLAG_UNSHADED, true); - handle_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.8)); + handle_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.8)); - handle2_material = Ref( memnew( FixedMaterial )); + handle2_material = Ref( memnew( FixedSpatialMaterial )); handle2_material->set_flag(Material::FLAG_UNSHADED, true); - handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_POINT_SIZE, true); + handle2_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_POINT_SIZE, true); handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle","EditorIcons"); handle2_material->set_point_size(handle_t->get_width()); - handle2_material->set_texture(FixedMaterial::PARAM_DIFFUSE,handle_t); - handle2_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1)); - handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); + handle2_material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,handle_t); + handle2_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1)); + handle2_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + handle2_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); light_material = create_line_material(Color(1,1,0.2)); - light_material_omni_icon = Ref( memnew( FixedMaterial )); + light_material_omni_icon = Ref( memnew( FixedSpatialMaterial )); light_material_omni_icon->set_flag(Material::FLAG_UNSHADED, true); light_material_omni_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); light_material_omni_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - light_material_omni_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - light_material_omni_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - light_material_omni_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoLight","EditorIcons")); + light_material_omni_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + light_material_omni_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); + light_material_omni_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoLight","EditorIcons")); - light_material_directional_icon = Ref( memnew( FixedMaterial )); + light_material_directional_icon = Ref( memnew( FixedSpatialMaterial )); light_material_directional_icon->set_flag(Material::FLAG_UNSHADED, true); light_material_directional_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); light_material_directional_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - light_material_directional_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - light_material_directional_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - light_material_directional_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight","EditorIcons")); + light_material_directional_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + light_material_directional_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); + light_material_directional_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight","EditorIcons")); camera_material = create_line_material(Color(1.0,0.5,1.0)); navmesh_edge_material = create_line_material(Color(0.1,0.8,1.0)); navmesh_solid_material = create_solid_material(Color(0.1,0.8,1.0,0.4)); - navmesh_edge_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false); + navmesh_edge_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, false); navmesh_solid_material->set_flag(Material::FLAG_DOUBLE_SIDED,true); navmesh_edge_material_disabled = create_line_material(Color(1.0,0.8,0.1)); navmesh_solid_material_disabled = create_solid_material(Color(1.0,0.8,0.1,0.4)); - navmesh_edge_material_disabled->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false); + navmesh_edge_material_disabled->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, false); navmesh_solid_material_disabled->set_flag(Material::FLAG_DOUBLE_SIDED,true); skeleton_material = create_line_material(Color(0.6,1.0,0.3)); @@ -3077,10 +3077,10 @@ SpatialEditorGizmos::SpatialEditorGizmos() { cursor_colors.push_back(Color(0.5,0.5,1,0.7)); cursor_colors.push_back(Color(0.5,0.5,1,0.7)); - Ref mat = memnew( FixedMaterial ); + Ref mat = memnew( FixedSpatialMaterial ); mat->set_flag(Material::FLAG_UNSHADED,true); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); + mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true); + mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); mat->set_line_width(3); Array d; d.resize(VS::ARRAY_MAX); @@ -3100,10 +3100,10 @@ SpatialEditorGizmos::SpatialEditorGizmos() { cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - Ref mat = memnew(FixedMaterial); + Ref mat = memnew(FixedSpatialMaterial); mat->set_flag(Material::FLAG_UNSHADED, true); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); - mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); + mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); mat->set_line_width(3); Array d; d.resize(VS::ARRAY_MAX); @@ -3114,13 +3114,13 @@ SpatialEditorGizmos::SpatialEditorGizmos() { } - sample_player_icon = Ref( memnew( FixedMaterial )); + sample_player_icon = Ref( memnew( FixedSpatialMaterial )); sample_player_icon->set_flag(Material::FLAG_UNSHADED, true); sample_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); sample_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - sample_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - sample_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - sample_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer","EditorIcons")); + sample_player_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + sample_player_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); + sample_player_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer","EditorIcons")); room_material = create_line_material(Color(1.0,0.6,0.9)); portal_material = create_line_material(Color(1.0,0.8,0.6)); @@ -3129,29 +3129,29 @@ SpatialEditorGizmos::SpatialEditorGizmos() { visibility_notifier_material = create_line_material(Color(1.0,0.5,1.0)); joint_material = create_line_material(Color(0.6,0.8,1.0)); - stream_player_icon = Ref( memnew( FixedMaterial )); + stream_player_icon = Ref( memnew( FixedSpatialMaterial )); stream_player_icon->set_flag(Material::FLAG_UNSHADED, true); stream_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); stream_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - stream_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - stream_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - stream_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer","EditorIcons")); + stream_player_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + stream_player_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); + stream_player_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer","EditorIcons")); - visibility_notifier_icon = Ref( memnew( FixedMaterial )); + visibility_notifier_icon = Ref( memnew( FixedSpatialMaterial )); visibility_notifier_icon->set_flag(Material::FLAG_UNSHADED, true); visibility_notifier_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); visibility_notifier_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - visibility_notifier_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - visibility_notifier_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - visibility_notifier_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons")); + visibility_notifier_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + visibility_notifier_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); + visibility_notifier_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons")); - listener_icon = Ref(memnew(FixedMaterial)); + listener_icon = Ref(memnew(FixedSpatialMaterial)); listener_icon->set_flag(Material::FLAG_UNSHADED, true); listener_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); listener_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - listener_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); - listener_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9)); - listener_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons")); + listener_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + listener_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9)); + listener_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons")); { diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h index a7a6af4b1..64c6a6e82 100644 --- a/tools/editor/spatial_editor_gizmos.h +++ b/tools/editor/spatial_editor_gizmos.h @@ -464,34 +464,34 @@ public: class SpatialEditorGizmos { public: - Ref create_line_material(const Color& p_base_color); - Ref create_solid_material(const Color& p_base_color); - Ref handle2_material; - Ref handle_material; - Ref light_material; - Ref light_material_omni_icon; - Ref light_material_directional_icon; - Ref camera_material; - Ref skeleton_material; - Ref room_material; - Ref portal_material; - Ref raycast_material; - Ref visibility_notifier_material; - Ref car_wheel_material; - Ref joint_material; - - Ref navmesh_edge_material; - Ref navmesh_solid_material; - Ref navmesh_edge_material_disabled; - Ref navmesh_solid_material_disabled; - - Ref listener_icon; - - Ref sample_player_icon; - Ref stream_player_icon; - Ref visibility_notifier_icon; - - Ref shape_material; + Ref create_line_material(const Color& p_base_color); + Ref create_solid_material(const Color& p_base_color); + Ref handle2_material; + Ref handle_material; + Ref light_material; + Ref light_material_omni_icon; + Ref light_material_directional_icon; + Ref camera_material; + Ref skeleton_material; + Ref room_material; + Ref portal_material; + Ref raycast_material; + Ref visibility_notifier_material; + Ref car_wheel_material; + Ref joint_material; + + Ref navmesh_edge_material; + Ref navmesh_solid_material; + Ref navmesh_edge_material_disabled; + Ref navmesh_solid_material_disabled; + + Ref listener_icon; + + Ref sample_player_icon; + Ref stream_player_icon; + Ref visibility_notifier_icon; + + Ref shape_material; Ref handle_t; Ref pos3d_mesh; -- cgit v1.2.3-70-g09d2 From d6567010bf1c65abcbe09b959cde63664778d923 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 29 Oct 2016 20:48:09 -0300 Subject: -Many many fixes -Gizmos work again --- drivers/gles3/rasterizer_canvas_gles3.cpp | 23 +- drivers/gles3/rasterizer_gles3.cpp | 6 +- drivers/gles3/rasterizer_scene_gles3.cpp | 310 ++++++++++++++++++++----- drivers/gles3/rasterizer_scene_gles3.h | 17 +- drivers/gles3/rasterizer_storage_gles3.cpp | 214 +++++++++-------- drivers/gles3/rasterizer_storage_gles3.h | 40 ++-- drivers/gles3/shader_compiler_gles3.cpp | 88 +++++-- drivers/gles3/shader_compiler_gles3.h | 2 + drivers/gles3/shaders/copy.glsl | 27 ++- drivers/gles3/shaders/cubemap_filter.glsl | 2 +- drivers/gles3/shaders/scene.glsl | 70 ++++-- methods.py | 1 + scene/3d/visual_instance.h | 1 + scene/resources/environment.cpp | 224 ++++++++++++++++++ scene/resources/environment.h | 69 ++++++ scene/resources/material.cpp | 69 +++++- scene/resources/material.h | 16 +- servers/visual/rasterizer.h | 9 +- servers/visual/visual_server_raster.h | 11 +- servers/visual/visual_server_scene.cpp | 76 +++++- servers/visual/visual_server_scene.h | 2 +- servers/visual_server.h | 13 +- tools/editor/editor_node.cpp | 2 +- tools/editor/plugins/spatial_editor_plugin.cpp | 9 +- tools/editor/plugins/spatial_editor_plugin.h | 2 +- tools/editor/spatial_editor_gizmos.cpp | 173 +++++++------- tools/editor/spatial_editor_gizmos.h | 3 +- 27 files changed, 1135 insertions(+), 344 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index b2228a6cf..c10c5fee6 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -914,6 +914,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const } + if (shader_ptr && shader_ptr!=shader_cache) { state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); @@ -925,6 +926,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const int tc = material_ptr->textures.size(); RID* textures = material_ptr->textures.ptr(); + ShaderLanguage::ShaderNode::Uniform::Hint* texture_hints = shader_ptr->texture_hints.ptr(); for(int i=0;itexture_owner.getornull( textures[i] ); if (!t) { + + switch(texture_hints[i]) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { + glBindTexture(GL_TEXTURE_2D,storage->resources.black_tex); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { + glBindTexture(GL_TEXTURE_2D,storage->resources.normal_tex); + } break; + default: { + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + } break; + } + //check hints - glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + continue; } + if (storage->config.srgb_decode_supported && t->using_srgb) { + //no srgb in 2D + glTexParameteri(t->target,_TEXTURE_SRGB_DECODE_EXT,_SKIP_DECODE_EXT); + t->using_srgb=false; + } + glBindTexture(t->target,t->tex_id); } diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 83c40edc1..e838020c4 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -253,10 +253,8 @@ void RasterizerGLES3::make_current() { void RasterizerGLES3::register_config() { - GLOBAL_DEF("rendering/gles3/framebuffer_format",RasterizerStorageGLES3::FBO_FORMAT_FLOAT); - Globals::get_singleton()->set_custom_property_info("rendering/gles3/framebuffer_format",PropertyInfo(Variant::INT,"",PROPERTY_HINT_ENUM,"16 Bits,32 Bits,Half Float")); - GLOBAL_DEF("rendering/gles3/lighting_technique",1); - Globals::get_singleton()->set_custom_property_info("rendering/gles3/lighting_technique",PropertyInfo(Variant::INT,"",PROPERTY_HINT_ENUM,"Forward,Deferred")); + GLOBAL_DEF("rendering/gles3/render_architecture",0); + Globals::get_singleton()->set_custom_property_info("rendering/gles3/render_architecture",PropertyInfo(Variant::INT,"",PROPERTY_HINT_ENUM,"Desktop,Mobile")); GLOBAL_DEF("rendering/gles3/use_nearest_mipmap_filter",false); GLOBAL_DEF("rendering/gles3/anisotropic_filter_level",4.0); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index aadf9e633..f7baf1a30 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -150,27 +150,19 @@ void RasterizerSceneGLES3::environment_set_fog(RID p_env,bool p_enable,float p_b } -void RasterizerSceneGLES3::environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper){ +void RasterizerSceneGLES3::environment_set_tonemap(RID p_env, bool p_enable, float p_exposure, float p_white, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale, VS::EnvironmentToneMapper p_tone_mapper){ } -void RasterizerSceneGLES3::environment_set_brightness(RID p_env,bool p_enable,float p_brightness){ -} -void RasterizerSceneGLES3::environment_set_contrast(RID p_env,bool p_enable,float p_contrast){ +void RasterizerSceneGLES3::environment_set_adjustment(RID p_env,bool p_enable,float p_brightness,float p_contrast,float p_saturation,RID p_ramp) { -} -void RasterizerSceneGLES3::environment_set_saturation(RID p_env,bool p_enable,float p_saturation){ } -void RasterizerSceneGLES3::environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp){ - -} - - RID RasterizerSceneGLES3::light_instance_create(RID p_light) { + print_line("hello light"); LightInstance *light_instance = memnew( LightInstance ); light_instance->light=p_light; @@ -204,6 +196,29 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_m glEnable(GL_CULL_FACE); } + if (state.current_line_width!=p_material->line_width) { + glLineWidth(p_material->line_width); + state.current_line_width=p_material->line_width; + } + + if (state.current_depth_draw!=p_material->shader->spatial.depth_draw_mode) { + switch(p_material->shader->spatial.depth_draw_mode) { + case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: + case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_OPAQUE: { + + glDepthMask(!p_alpha_pass); + } break; + case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALWAYS: { + glDepthMask(GL_TRUE); + } break; + case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER: { + glDepthMask(GL_FALSE); + } break; + } + + state.current_depth_draw=p_material->shader->spatial.depth_draw_mode; + } + //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); /* @@ -216,7 +231,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_m //if (p_material->line_width) // glLineWidth(p_material->line_width); - +#if 0 //blend mode if (state.current_blend_mode!=p_material->shader->spatial.blend_mode) { @@ -256,7 +271,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_m state.current_blend_mode=p_material->shader->spatial.blend_mode; } - +#endif //material parameters @@ -273,6 +288,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_m int tc = p_material->textures.size(); RID* textures = p_material->textures.ptr(); + ShaderLanguage::ShaderNode::Uniform::Hint* texture_hints = p_material->shader->texture_hints.ptr(); for(int i=0;itexture_owner.getornull( textures[i] ); if (!t) { //check hints + switch(texture_hints[i]) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { + glBindTexture(GL_TEXTURE_2D,storage->resources.black_tex); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { + glBindTexture(GL_TEXTURE_2D,storage->resources.normal_tex); + } break; + default: { + glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); + } break; + } glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex); continue; } + if (storage->config.srgb_decode_supported) { + //if SRGB decode extension is present, simply switch the texture to whathever is needed + bool must_srgb=false; + + if (t->srgb && texture_hints[i]==ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO) { + must_srgb=true; + } + + if (t->using_srgb!=must_srgb) { + if (must_srgb) { + glTexParameteri(t->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); +#ifdef TOOLS_ENABLED + if (!(t->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { + t->flags|=VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; + //notify that texture must be set to linear beforehand, so it works in other platforms when exported + } +#endif + + } else { + glTexParameteri(t->target,_TEXTURE_SRGB_DECODE_EXT,_SKIP_DECODE_EXT); + } + t->using_srgb=must_srgb; + } + } + + glBindTexture(t->target,t->tex_id); } @@ -348,7 +401,60 @@ void RasterizerSceneGLES3::_setup_light(LightInstance *p_light) { glBindBufferBase(GL_UNIFORM_BUFFER,3,p_light->light_ubo); //bind light uniform } +void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection) { + + if (p_instance->billboard || p_instance->billboard_y || p_instance->depth_scale) { + + Transform xf=p_instance->transform; + if (p_instance->depth_scale) { + + if (p_projection.matrix[3][3]) { + //orthogonal matrix, try to do about the same + //with viewport size + //real_t w = Math::abs( 1.0/(2.0*(p_projection.matrix[0][0])) ); + real_t h = Math::abs( 1.0/(2.0*p_projection.matrix[1][1]) ); + float sc = (h*2.0); //consistent with Y-fov + xf.basis.scale( Vector3(sc,sc,sc)); + } else { + //just scale by depth + real_t sc = Plane(p_view_transform.origin,-p_view_transform.get_basis().get_axis(2)).distance_to(xf.origin); + xf.basis.scale( Vector3(sc,sc,sc)); + } + } + + if (p_instance->billboard) { + + Vector3 scale = xf.basis.get_scale(); + + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { + xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), -p_view_transform.get_basis().get_axis(1)); + } else { + xf.set_look_at(xf.origin, xf.origin + p_view_transform.get_basis().get_axis(2), p_view_transform.get_basis().get_axis(1)); + } + + xf.basis.scale(scale); + } + + if (p_instance->billboard_y) { + + Vector3 scale = xf.basis.get_scale(); + Vector3 look_at = p_view_transform.get_origin(); + look_at.y = 0.0; + Vector3 look_at_norm = look_at.normalized(); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { + xf.set_look_at(xf.origin,xf.origin + look_at_norm, Vector3(0.0, -1.0, 0.0)); + } else { + xf.set_look_at(xf.origin,xf.origin + look_at_norm, Vector3(0.0, 1.0, 0.0)); + } + xf.basis.scale(scale); + } + state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, xf); + + } else { + state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, p_instance->transform); + } +} void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass) { @@ -372,12 +478,18 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); glBindTexture(p_base_env->target,p_base_env->tex_id); state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true); + } else { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + } + state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false); state.current_blend_mode=-1; + state.current_line_width=-1; + state.current_depth_draw=-1; glDisable(GL_BLEND); @@ -390,6 +502,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e int prev_blend=-1; int current_blend_mode=-1; + bool prev_additive=false; + for (int i=0;imirror,p_reverse_cull); state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror?-1.0:1.0); - state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform); + + _setup_transform(e->instance,p_view_transform,p_projection); // _render(e->geometry, material, skeleton,e->owner,e->instance->transform); @@ -567,6 +687,10 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e prev_material=material; prev_base_type=e->instance->base_type; prev_geometry=e->geometry; + prev_additive=additive; + prev_light_type=light_type; + prev_light_index=light_index; + } //print_line("shaderchanges: "+itos(p_alpha_pass)+": "+itos(_rinfo.shader_change_count)); @@ -824,6 +948,19 @@ void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection, glActiveTexture(GL_TEXTURE0); glBindTexture(tex->target,tex->tex_id); + + if (storage->config.srgb_decode_supported && tex->srgb && !tex->using_srgb) { + + glTexParameteri(tex->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + tex->using_srgb=true; +#ifdef TOOLS_ENABLED + if (!(tex->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { + tex->flags|=VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; + //notify that texture must be set to linear beforehand, so it works in other platforms when exported + } +#endif + } + glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); @@ -876,6 +1013,7 @@ void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection, glDrawArrays(GL_TRIANGLE_FAN,0,4); glBindVertexArray(0); + glColorMask(1,1,1,1); storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_CUBEMAP,false); @@ -977,9 +1115,10 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu ERR_FAIL_COND( directional_light_instance_count >= RenderList::MAX_LIGHTS); directional_light_instances[directional_light_instance_count++]=li; - li->light_ubo_data.light_color_energy[0]=li->light_ptr->color.r; - li->light_ubo_data.light_color_energy[1]=li->light_ptr->color.g; - li->light_ubo_data.light_color_energy[2]=li->light_ptr->color.b; + Color linear_col = li->light_ptr->color.to_linear(); + li->light_ubo_data.light_color_energy[0]=linear_col.r; + li->light_ubo_data.light_color_energy[1]=linear_col.g; + li->light_ubo_data.light_color_energy[2]=linear_col.b; li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; //omni, keep at 0 @@ -1018,9 +1157,10 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu } break; case VS::LIGHT_OMNI: { - li->light_ubo_data.light_color_energy[0]=li->light_ptr->color.r; - li->light_ubo_data.light_color_energy[1]=li->light_ptr->color.g; - li->light_ubo_data.light_color_energy[2]=li->light_ptr->color.b; + Color linear_col = li->light_ptr->color.to_linear(); + li->light_ubo_data.light_color_energy[0]=linear_col.r; + li->light_ubo_data.light_color_energy[1]=linear_col.g; + li->light_ubo_data.light_color_energy[2]=linear_col.b; li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); @@ -1050,9 +1190,10 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu } break; case VS::LIGHT_SPOT: { - li->light_ubo_data.light_color_energy[0]=li->light_ptr->color.r; - li->light_ubo_data.light_color_energy[1]=li->light_ptr->color.g; - li->light_ubo_data.light_color_energy[2]=li->light_ptr->color.b; + Color linear_col = li->light_ptr->color.to_linear(); + li->light_ubo_data.light_color_energy[0]=linear_col.r; + li->light_ubo_data.light_color_energy[1]=linear_col.g; + li->light_ubo_data.light_color_energy[2]=linear_col.b; li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); @@ -1108,6 +1249,51 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu } +void RasterizerSceneGLES3::_copy_screen() { + + glBindVertexArray(storage->resources.quadie_array); + glDrawArrays(GL_TRIANGLE_FAN,0,4); + glBindVertexArray(0); + +} + +void RasterizerSceneGLES3::_copy_to_front_buffer(Environment *env) { + + //copy to front buffer + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1,1,1,1); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,true); + + if (!env) { + //no environment, simply convert from linear to srgb + storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB,true); + } else { + storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB,true); + + } + + storage->shaders.copy.bind(); + + _copy_screen(); + + + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB,false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,false); + + +} + void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){ //first of all, make a new render pass @@ -1125,6 +1311,8 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM current_material_index=0; + bool use_mrt=false; + //fill list for(int i=0;iframe.current_rt->buffers.fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,true); + + Color black(0,0,0,0); + glClearBufferfv(GL_COLOR,1,black.components); // specular + glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough + + } else { + + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); + + } + + glClearDepth(1.0); - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); + glClear(GL_DEPTH_BUFFER_BIT); - RasterizerStorageGLES3::Texture* env_radiance_tex; + Color clear_color(0,0,0,0); if (!env || env->bg_mode==VS::ENV_BG_CLEAR_COLOR) { if (storage->frame.clear_request) { - glClearColor( storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a ); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + clear_color = storage->frame.clear_request_color.to_linear(); storage->frame.clear_request=false; } } else if (env->bg_mode==VS::ENV_BG_COLOR) { - - glClearColor( env->bg_color.r, env->bg_color.g, env->bg_color.b, env->bg_color.a ); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + clear_color = env->bg_color.to_linear(); storage->frame.clear_request=false; } else if (env->bg_mode==VS::ENV_BG_SKYBOX) { if (env->skybox_radiance.is_valid()) { env_radiance_tex = storage->texture_owner.getornull(env->skybox_radiance); } - glClear(GL_DEPTH_BUFFER_BIT); storage->frame.clear_request=false; } else { - glClear(GL_DEPTH_BUFFER_BIT); storage->frame.clear_request=false; - } - state.current_depth_test=true; - state.current_depth_mask=true; + glClearBufferfv(GL_COLOR,0,clear_color.components); // specular + + state.texscreen_copied=false; glBlendEquation(GL_FUNC_ADD); @@ -1214,43 +1417,33 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM } glDisable(GL_BLEND); - //current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; - render_list.sort_by_key(false); - //_render_list_forward(&opaque_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting); -/* - if (draw_tex_background) { - - //most 3D vendors recommend drawing a texture bg or skybox here, - //after opaque geometry has been drawn - //so the zbuffer can get rid of most pixels - _draw_tex_bg(); - } -*/ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } -// glDisable(GL_BLEND); -// current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; -// state.scene_shader.set_conditional(SceneShaderGLES3::USE_GLOW,false); -// if (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) { -// glColorMask(1,1,1,0); //don't touch alpha -// } - - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); + if (env && env->bg_mode==VS::ENV_BG_SKYBOX) { + if (use_mrt) { + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); //switch to alpha fbo for skybox, only diffuse/ambient matters + } + _draw_skybox(env->skybox_color,p_cam_projection,p_cam_transform,storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP],env->skybox_scale); } + + + + //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); //glColorMask(1,1,1,1); @@ -1261,12 +1454,14 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); render_list.sort_by_depth(true); - _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false); + _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true); + + _copy_to_front_buffer(env); #if 0 if (use_fb) { @@ -1418,6 +1613,7 @@ bool RasterizerSceneGLES3::free(RID p_rid) { if (light_instance_owner.owns(p_rid)) { + print_line("bye light"); LightInstance *light_instance = light_instance_owner.getptr(p_rid); glDeleteBuffers(1,&light_instance->light_ubo); light_instance_owner.free(p_rid); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 4b1b77f13..5457b5cde 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -18,10 +18,11 @@ public: struct State { - bool current_depth_test; - bool current_depth_mask; + bool texscreen_copied; int current_blend_mode; + float current_line_width; + int current_depth_draw; SceneShaderGLES3 scene_shader; @@ -57,6 +58,8 @@ public: GLuint skybox_verts; GLuint skybox_array; + + } state; @@ -109,11 +112,8 @@ public: virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode); virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture); - virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper); - virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness); - virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast); - virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation); - virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp); + virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,float p_auto_exp_scale,VS::EnvironmentToneMapper p_tone_mapper); + virtual void environment_set_adjustment(RID p_env,bool p_enable,float p_brightness,float p_contrast,float p_saturation,RID p_ramp); /* LIGHT INSTANCE */ @@ -314,6 +314,7 @@ public: RenderList render_list; _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass); + _FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e); _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); _FORCE_INLINE_ void _setup_light(LightInstance *p_light); @@ -327,6 +328,8 @@ public: void _setup_environment(Environment *env,CameraMatrix& p_cam_projection, const Transform& p_cam_transform); void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform); + void _copy_screen(); + void _copy_to_front_buffer(Environment *env); virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 1141a605c..a678c460f 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -57,9 +57,6 @@ #define _EXT_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE -#define _TEXTURE_SRGB_DECODE_EXT 0x8A48 -#define _DECODE_EXT 0x8A49 -#define _SKIP_DECODE_EXT 0x8A4A #define _GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE @@ -679,8 +676,10 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture,const Image& p_image if (texture->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) { glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + texture->using_srgb=true; } else { glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_SKIP_DECODE_EXT); + texture->using_srgb=false; } } @@ -892,8 +891,10 @@ void RasterizerStorageGLES3::texture_set_flags(RID p_texture,uint32_t p_flags) { if (texture->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) { glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + texture->using_srgb=true; } else { glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_SKIP_DECODE_EXT); + texture->using_srgb=false; } } @@ -1024,6 +1025,19 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_r glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); + if (config.srgb_decode_supported && texture->srgb && !texture->using_srgb) { + + glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + texture->using_srgb=true; +#ifdef TOOLS_ENABLED + if (!(texture->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { + texture->flags|=VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; + //notify that texture must be set to linear beforehand, so it works in other platforms when exported + } +#endif + } + + glActiveTexture(GL_TEXTURE1); GLuint new_cubemap; glGenTextures(1, &new_cubemap); @@ -1302,6 +1316,7 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { p_shader->ubo_size=gen_code.uniform_total_size; p_shader->ubo_offsets=gen_code.uniform_offsets; p_shader->texture_count=gen_code.texture_uniforms.size(); + p_shader->texture_hints=gen_code.texture_hints; //all materials using this shader will have to be invalidated, unfortunately @@ -1510,7 +1525,17 @@ Variant RasterizerStorageGLES3::material_get_param(RID p_material, const StringN return Variant(); } -_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant& value, uint8_t *data) { +void RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_width) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND(!material); + + material->line_width=p_width; + + +} + +_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant& value, uint8_t *data,bool p_linear_color) { switch(type) { case ShaderLanguage::TYPE_BOOL: { @@ -1683,6 +1708,10 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy if (value.get_type()==Variant::COLOR) { Color v=value; + if (p_linear_color) { + v=v.to_linear(); + } + gui[0]=v.r; gui[1]=v.g; gui[2]=v.b; @@ -2019,7 +2048,7 @@ void RasterizerStorageGLES3::_update_material(Material* material) { if (V) { //user provided - _fill_std140_variant_ubo_value(E->get().type,V->get(),data); + _fill_std140_variant_ubo_value(E->get().type,V->get(),data,material->shader->mode==VS::SHADER_SPATIAL); } else if (E->get().default_value.size()){ //default value _fill_std140_ubo_value(E->get().type,E->get().default_value,data); @@ -2641,9 +2670,7 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ Surface *surface = mesh->surfaces[p_surface]; - ERR_FAIL_COND(surface->index_array_len==0); - - glDeleteBuffers(1,&surface->array_id); + glDeleteBuffers(1,&surface->vertex_id); if (surface->index_id) { glDeleteBuffers(1,&surface->index_id); } @@ -3211,14 +3238,14 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { rt->back.fbo=0; } - if (rt->deferred.fbo) { - glDeleteFramebuffers(1,&rt->deferred.fbo); - glDeleteFramebuffers(1,&rt->deferred.fbo_color); - glDeleteTextures(1,&rt->deferred.albedo_ao); - glDeleteTextures(1,&rt->deferred.normal_special); - glDeleteTextures(1,&rt->deferred.metal_rough_motion); - rt->deferred.fbo=0; - rt->deferred.fbo_color=0; + if (rt->buffers.fbo) { + glDeleteFramebuffers(1,&rt->buffers.fbo); + glDeleteFramebuffers(1,&rt->buffers.alpha_fbo); + glDeleteTextures(1,&rt->buffers.diffuse); + glDeleteTextures(1,&rt->buffers.specular); + glDeleteTextures(1,&rt->buffers.normal_sr); + rt->buffers.fbo=0; + rt->buffers.alpha_fbo=0; } if (rt->depth) { @@ -3239,26 +3266,6 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ if (rt->width<=0 || rt->height<=0) return; - glActiveTexture(GL_TEXTURE0); - - glGenFramebuffers(1, &rt->front.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->front.fbo); - - - glGenRenderbuffers(1, &rt->depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->depth ); - if (config.fbo_format==FBO_FORMAT_16_BITS) { - glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT16, rt->width, rt->height); - } else { - glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH24_STENCIL8, rt->width, rt->height); - } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - glBindRenderbuffer(GL_RENDERBUFFER, 0 ); - - - glGenTextures(1, &rt->front.color); - glBindTexture(GL_TEXTURE_2D, rt->front.color); - GLuint color_internal_format; GLuint color_format; @@ -3266,21 +3273,8 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ Image::Format image_format; - if (config.fbo_format==FBO_FORMAT_16_BITS) { - if (rt->flags[RENDER_TARGET_TRANSPARENT]) { - color_internal_format=GL_RGB5_A1; - color_format=GL_RGBA; - color_type=GL_UNSIGNED_SHORT_5_5_5_1; - image_format=Image::FORMAT_RGBA5551; - } else { - color_internal_format=GL_RGB565; - color_format=GL_RGB; - color_type=GL_UNSIGNED_SHORT_5_6_5; - image_format=Image::FORMAT_RGB565; - } - - } else if (config.fbo_format==FBO_FORMAT_32_BITS || (config.fbo_format==FBO_FORMAT_FLOAT && rt->flags[RENDER_TARGET_NO_3D])) { + if (config.render_arch==RENDER_ARCH_MOBILE || rt->flags[RENDER_TARGET_NO_3D]) { if (rt->flags[RENDER_TARGET_TRANSPARENT]) { color_internal_format=GL_RGBA8; @@ -3293,53 +3287,75 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ color_type=GL_UNSIGNED_INT_2_10_10_10_REV; image_format=Image::FORMAT_RGBA8;//todo } - } else if (config.fbo_format==FBO_FORMAT_FLOAT) { - + } else { color_internal_format=GL_RGBA16F; color_format=GL_RGBA; color_type=GL_HALF_FLOAT; image_format=Image::FORMAT_RGBAH; } - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); + { + /* FRONT FBO */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->front.color, 0); + glActiveTexture(GL_TEXTURE0); + + glGenFramebuffers(1, &rt->front.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->front.fbo); + + + glGenRenderbuffers(1, &rt->depth); + glBindRenderbuffer(GL_RENDERBUFFER, rt->depth ); + + + glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH24_STENCIL8, rt->width, rt->height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + glBindRenderbuffer(GL_RENDERBUFFER, 0 ); + + + glGenTextures(1, &rt->front.color); + glBindTexture(GL_TEXTURE_2D, rt->front.color); + + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->front.color, 0); - { GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE ); - } - Texture *tex = texture_owner.get(rt->texture); - tex->format=image_format; - tex->gl_format_cache=color_format; - tex->gl_type_cache=color_type; - tex->gl_internal_format_cache=color_internal_format; - tex->tex_id=rt->front.color; - tex->width=rt->width; - tex->alloc_width=rt->width; - tex->height=rt->height; - tex->alloc_height=rt->height; + Texture *tex = texture_owner.get(rt->texture); + tex->format=image_format; + tex->gl_format_cache=color_format; + tex->gl_type_cache=color_type; + tex->gl_internal_format_cache=color_internal_format; + tex->tex_id=rt->front.color; + tex->width=rt->width; + tex->alloc_width=rt->width; + tex->height=rt->height; + tex->alloc_height=rt->height; + + texture_set_flags(rt->texture,tex->flags); + + } - texture_set_flags(rt->texture,tex->flags); + + /* BACK FBO */ if (!rt->flags[RENDER_TARGET_NO_SAMPLING]) { glGenFramebuffers(1, &rt->back.fbo); glBindFramebuffer(GL_FRAMEBUFFER, rt->back.fbo); - + glBindRenderbuffer(GL_RENDERBUFFER, rt->depth ); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); glGenTextures(1, &rt->back.color); glBindTexture(GL_TEXTURE_2D, rt->back.color); - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -3357,43 +3373,42 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ } } + if (config.render_arch==RENDER_ARCH_DESKTOP && !rt->flags[RENDER_TARGET_NO_3D]) { - if (config.fbo_deferred && !rt->flags[RENDER_TARGET_NO_3D]) { - //regular fbo - glGenFramebuffers(1, &rt->deferred.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->deferred.fbo); + glGenFramebuffers(1, &rt->buffers.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->buffers.fbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - glGenTextures(1, &rt->deferred.albedo_ao); - glBindTexture(GL_TEXTURE_2D, rt->deferred.albedo_ao); + glGenTextures(1, &rt->buffers.diffuse); + glBindTexture(GL_TEXTURE_2D, rt->buffers.diffuse); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->deferred.albedo_ao, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->buffers.diffuse, 0); - glGenTextures(1, &rt->deferred.metal_rough_motion); - glBindTexture(GL_TEXTURE_2D, rt->deferred.metal_rough_motion); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glGenTextures(1, &rt->buffers.specular); + glBindTexture(GL_TEXTURE_2D, rt->buffers.specular); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rt->width, rt->height, 0, GL_RGBA, GL_HALF_FLOAT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt->deferred.metal_rough_motion, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt->buffers.specular, 0); - glGenTextures(1, &rt->deferred.normal_special); - glBindTexture(GL_TEXTURE_2D, rt->deferred.normal_special); + glGenTextures(1, &rt->buffers.normal_sr); + glBindTexture(GL_TEXTURE_2D, rt->buffers.normal_sr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->deferred.normal_special, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->buffers.normal_sr, 0); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -3402,19 +3417,15 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ if (status != GL_FRAMEBUFFER_COMPLETE) { _render_target_clear(rt); ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE ); - } + } - //regular fbo with color attachment (needed for emission or objects rendered as forward) - glGenFramebuffers(1, &rt->deferred.fbo_color); - glBindFramebuffer(GL_FRAMEBUFFER, rt->deferred.fbo_color); + //alpha fbo + glGenFramebuffers(1, &rt->buffers.alpha_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->buffers.alpha_fbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->deferred.albedo_ao, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt->deferred.metal_rough_motion, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->deferred.normal_special, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, rt->front.color, 0); - + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->buffers.diffuse, 0); status = glCheckFramebufferStatus(GL_FRAMEBUFFER); glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); @@ -3423,6 +3434,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ _render_target_clear(rt); ERR_FAIL_COND( status != GL_FRAMEBUFFER_COMPLETE ); } + } @@ -3797,8 +3809,8 @@ bool RasterizerStorageGLES3::free(RID p_rid){ void RasterizerStorageGLES3::initialize() { - config.fbo_format=FBOFormat(int(Globals::get_singleton()->get("rendering/gles3/framebuffer_format"))); - config.fbo_deferred=int(Globals::get_singleton()->get("rendering/gles3/lighting_technique")); + config.render_arch=RENDER_ARCH_DESKTOP; + //config.fbo_deferred=int(Globals::get_singleton()->get("rendering/gles3/lighting_technique")); config.system_fbo=0; @@ -3925,10 +3937,10 @@ void RasterizerStorageGLES3::initialize() { glGenVertexArrays(1,&resources.quadie_array); glBindVertexArray(resources.quadie_array); glBindBuffer(GL_ARRAY_BUFFER,resources.quadie); - glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,0); + glVertexAttribPointer(VS::ARRAY_VERTEX,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,0); glEnableVertexAttribArray(0); - glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,((uint8_t*)NULL)+8); - glEnableVertexAttribArray(1); + glVertexAttribPointer(VS::ARRAY_TEX_UV,2,GL_FLOAT,GL_FALSE,sizeof(float)*4,((uint8_t*)NULL)+8); + glEnableVertexAttribArray(4); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER,0); //unbind } diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index f052aa801..b12c2d93b 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -13,6 +13,9 @@ class RasterizerCanvasGLES3; class RasterizerSceneGLES3; +#define _TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define _DECODE_EXT 0x8A49 +#define _SKIP_DECODE_EXT 0x8A4A class RasterizerStorageGLES3 : public RasterizerStorage { public: @@ -20,16 +23,15 @@ public: RasterizerCanvasGLES3 *canvas; RasterizerSceneGLES3 *scene; - enum FBOFormat { - FBO_FORMAT_16_BITS, - FBO_FORMAT_32_BITS, - FBO_FORMAT_FLOAT, + enum RenderArchitecture { + RENDER_ARCH_MOBILE, + RENDER_ARCH_DESKTOP, }; struct Config { - FBOFormat fbo_format; - bool fbo_deferred; + RenderArchitecture render_arch; + GLuint system_fbo; //on some devices, such as apple, screen is rendered to yet another fbo. bool shrink_textures_x2; @@ -135,12 +137,15 @@ public: bool active; GLuint tex_id; + bool using_srgb; + uint16_t stored_cube_sides; RenderTarget *render_target; Texture() { + using_srgb=false; stored_cube_sides=0; ignore_mipmaps=false; render_target=NULL; @@ -218,6 +223,8 @@ public: Map default_textures; + Vector texture_hints; + bool valid; String path; @@ -319,12 +326,14 @@ public: SelfList list; SelfList dirty_list; Vector textures; + float line_width; uint32_t index; uint64_t last_pass; Material() : list(this), dirty_list(this) { shader=NULL; + line_width=1.0; ubo_id=0; ubo_size=0; last_pass=0; @@ -346,6 +355,8 @@ public: virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value); virtual Variant material_get_param(RID p_material, const StringName& p_param) const; + virtual void material_set_line_width(RID p_material, float p_width); + void _update_material(Material* material); void update_dirty_materials(); @@ -655,14 +666,13 @@ public: GLuint depth; - struct Deferred { + struct Buffers { GLuint fbo; - GLuint fbo_color; - - GLuint albedo_ao; - GLuint metal_rough_motion; - GLuint normal_special; - } deferred; + GLuint alpha_fbo; //single buffer, just diffuse (for alpha pass) + GLuint specular; + GLuint diffuse; + GLuint normal_sr; + } buffers; int width,height; @@ -679,8 +689,8 @@ public: depth=0; front.fbo=0; back.fbo=0; - deferred.fbo=0; - deferred.fbo_color=0; + buffers.fbo=0; + buffers.alpha_fbo=0; used_in_frame=false; flags[RENDER_TARGET_VFLIP]=false; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index da8f6689d..0dff53bfb 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -75,25 +75,81 @@ static String _mkid(const String& p_id) { return "m_"+p_id; } +static String f2sp0(float p_float) { + + if (int(p_float)==p_float) + return itos(p_float)+".0"; + else + return rtoss(p_float); +} + static String get_constant_text(SL::DataType p_type, const Vector& p_values) { switch(p_type) { case SL::TYPE_BOOL: return p_values[0].boolean?"true":"false"; - case SL::TYPE_BVEC2: return String()+"bvec2("+(p_values[0].boolean?"true":"false")+(p_values[1].boolean?"true":"false")+")"; - case SL::TYPE_BVEC3: return String()+"bvec3("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+")"; - case SL::TYPE_BVEC4: return String()+"bvec4("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+","+(p_values[3].boolean?"true":"false")+")"; - case SL::TYPE_INT: return rtos(p_values[0].sint); - case SL::TYPE_IVEC2: return String()+"ivec2("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+")"; - case SL::TYPE_IVEC3: return String()+"ivec3("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+")"; - case SL::TYPE_IVEC4: return String()+"ivec4("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+","+rtos(p_values[3].sint)+")"; - case SL::TYPE_UINT: return rtos(p_values[0].real); - case SL::TYPE_UVEC2: return String()+"uvec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")"; - case SL::TYPE_UVEC3: return String()+"uvec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")"; - case SL::TYPE_UVEC4: return String()+"uvec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")"; - case SL::TYPE_FLOAT: return rtos(p_values[0].real); - case SL::TYPE_VEC2: return String()+"vec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")"; - case SL::TYPE_VEC3: return String()+"vec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")"; - case SL::TYPE_VEC4: return String()+"vec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")"; + case SL::TYPE_BVEC2: + case SL::TYPE_BVEC3: + case SL::TYPE_BVEC4: { + + + String text="bvec"+itos(p_type-SL::TYPE_BOOL+1)+"("; + for(int i=0;i0) + text+=","; + + text+=p_values[i].boolean?"true":"false"; + } + text+=")"; + return text; + } + + case SL::TYPE_INT: return itos(p_values[0].sint); + case SL::TYPE_IVEC2: + case SL::TYPE_IVEC3: + case SL::TYPE_IVEC4: { + + String text="ivec"+itos(p_type-SL::TYPE_INT+1)+"("; + for(int i=0;i0) + text+=","; + + text+=itos(p_values[i].sint); + } + text+=")"; + return text; + + } break; + case SL::TYPE_UINT: return itos(p_values[0].uint)+"u"; + case SL::TYPE_UVEC2: + case SL::TYPE_UVEC3: + case SL::TYPE_UVEC4: { + + String text="uvec"+itos(p_type-SL::TYPE_UINT+1)+"("; + for(int i=0;i0) + text+=","; + + text+=itos(p_values[i].uint)+"u"; + } + text+=")"; + return text; + } break; + case SL::TYPE_FLOAT: return f2sp0(p_values[0].real)+"f"; + case SL::TYPE_VEC2: + case SL::TYPE_VEC3: + case SL::TYPE_VEC4: { + + String text="vec"+itos(p_type-SL::TYPE_FLOAT+1)+"("; + for(int i=0;i0) + text+=","; + + text+=f2sp0(p_values[i].real); + } + text+=")"; + return text; + + } break; default: ERR_FAIL_V(String()); } } @@ -189,6 +245,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } r_gen_code.texture_uniforms.resize(max_texture_uniforms); + r_gen_code.texture_hints.resize(max_texture_uniforms); Vector uniform_sizes; uniform_sizes.resize(max_uniforms); @@ -209,6 +266,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener r_gen_code.vertex_global+=ucode; r_gen_code.fragment_global+=ucode; r_gen_code.texture_uniforms[E->get().texture_order]=_mkid(E->key()); + r_gen_code.texture_hints[E->get().texture_order]=E->get().hint; } else { if (r_gen_code.uniforms.empty()) { diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index ad51b9992..dcea82d77 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -21,6 +21,8 @@ public: Vector defines; Vector texture_uniforms; + Vector texture_hints; + Vector uniform_offsets; uint32_t uniform_total_size; String uniforms; diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index eb58d6643..79982ecf2 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -5,9 +5,9 @@ layout(location=0) in highp vec4 vertex_attrib; #ifdef USE_CUBEMAP layout(location=4) in vec3 cube_in; #else -layout(location=4) in vec2 uv_in; // attrib:4 +layout(location=4) in vec2 uv_in; #endif -layout(location=5) in vec2 uv2_in; // attrib:5 +layout(location=5) in vec2 uv2_in; #ifdef USE_CUBEMAP out vec3 cube_interp; @@ -40,6 +40,15 @@ uniform sampler2D source; //texunit:0 #endif +float sRGB_gamma_correct(float c){ + float a = 0.055; + if(c < 0.0031308) + return 12.92*c; + else + return (1.0+a)*pow(c, 1.0/2.4) - a; +} + + uniform float stuff; in vec2 uv2_interp; @@ -57,6 +66,20 @@ void main() { vec4 color = texture( source, uv_interp ); #endif +#ifdef LINEAR_TO_SRGB + //regular Linear -> SRGB conversion + vec3 a = vec3(0.055); + color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308))); +#endif + +#ifdef DEBUG_GRADIENT + color.rg=uv_interp; + color.b=0.0; +#endif + +#ifdef DISABLE_ALPHA + color.a=1.0; +#endif frag_color = color; } diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index d3d4cbd43..998a59833 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -3,7 +3,7 @@ layout(location=0) in highp vec2 vertex; -layout(location=1) in highp vec2 uv; +layout(location=4) in highp vec2 uv; out highp vec2 uv_interp; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 3f9425260..60ac015a1 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -269,11 +269,16 @@ in vec3 normal_interp; /* PBR CHANNELS */ +//used on forward mainly +uniform bool no_ambient_light; + + #ifdef USE_RADIANCE_CUBEMAP uniform sampler2D brdf_texture; //texunit:-1 uniform samplerCube radiance_cube; //texunit:-2 + layout(std140) uniform Radiance { //ubo:2 mat4 radiance_inverse_xform; @@ -346,8 +351,18 @@ in mediump vec4 forward_shadow_pos4; #endif +#ifdef USE_MULTIPLE_RENDER_TARGETS + +layout(location=0) out vec4 diffuse_buffer; +layout(location=1) out vec4 specular_buffer; +layout(location=2) out vec4 normal_mr_buffer; + +#else + layout(location=0) out vec4 frag_color; +#endif + // GGX Specular // Source: http://www.filmicworlds.com/images/ggx-opt/optimized-ggx.hlsl @@ -470,39 +485,46 @@ FRAGMENT_SHADER_CODE /////////////////////// LIGHTING ////////////////////////////// vec3 specular_light = vec3(0.0,0.0,0.0); - vec3 ambient_light = ambient_light_color.rgb; + vec3 ambient_light; vec3 diffuse_light = vec3(0.0,0.0,0.0); vec3 eye_vec = -normalize( vertex_interp ); #ifdef USE_RADIANCE_CUBEMAP - { + if (no_ambient_light) { + ambient_light=vec3(0.0,0.0,0.0); + } else { + { - float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); - vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; + float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); + vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; - float lod = roughness * 5.0; - vec3 r = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); - r=normalize((radiance_inverse_xform * vec4(r,0.0)).xyz); - vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); + float lod = roughness * 5.0; + vec3 r = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); + r=normalize((radiance_inverse_xform * vec4(r,0.0)).xyz); + vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); - specular_light=mix(albedo,radiance,specular); + specular_light=mix(albedo,radiance,specular); - } + } - { + { - vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); - vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz; + vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); + vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz; - ambient_light=mix(ambient_light,env_ambient,radiance_ambient_contribution); + ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution); + } } - #else - ambient_light=albedo; + if (no_ambient_light){ + ambient_light=vec3(0.0,0.0,0.0); + } else { + ambient_light=ambient_light_color.rgb; + } #endif @@ -538,11 +560,25 @@ LIGHT_SHADER_CODE } #endif -#ifdef SHADELESS +#ifdef USE_MULTIPLE_RENDER_TARGETS + + //approximate ambient scale for SSAO, since we will lack full ambient + float max_ambient=max(ambient_light.r,max(ambient_light.g,ambient_light.b)); + float max_diffuse=max(diffuse_light.r,max(diffuse_light.g,diffuse_light.b)); + float total_ambient = max_ambient+max_diffuse; + float ambient_scale = (total_ambient>0.0) ? max_ambient/total_ambient : 0.0; + diffuse_buffer=vec4(diffuse_light+ambient_light,ambient_scale); + specular_buffer=vec4(specular_light,0.0); + normal_mr_buffer=vec4(normal.x,normal.y,max(specular.r,max(specular.g,specular.b)),roughness); + +#else + +#ifdef SHADELESS frag_color=vec4(albedo,alpha); #else frag_color=vec4(ambient_light+diffuse_light+specular_light,alpha); +#endif #endif diff --git a/methods.py b/methods.py index 7ad42a559..f6bae4a64 100755 --- a/methods.py +++ b/methods.py @@ -233,6 +233,7 @@ def build_glsl_header( filename ): fd.write("\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n"); fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; ERR_FAIL_COND( get_active()!=this );\n\n "); + fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, bool p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value?1:0); }\n\n"); fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n"); fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n"); fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index eb0587815..b168bcbfe 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -97,6 +97,7 @@ public: FLAG_MAX=VS::INSTANCE_FLAG_MAX, }; + enum ShadowCastingSetting { SHADOW_CASTING_SETTING_OFF=VS::SHADOW_CASTING_SETTING_OFF, SHADOW_CASTING_SETTING_ON = VS::SHADOW_CASTING_SETTING_ON, diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 3897c86d5..47f4370cc 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -134,6 +134,151 @@ float Environment::get_ambient_light_skybox_contribution() const{ +void Environment::set_tonemapper(ToneMapper p_tone_mapper) { + + tone_mapper=p_tone_mapper; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); +} + +Environment::ToneMapper Environment::get_tonemapper() const{ + + return tone_mapper; +} + +void Environment::set_tonemap_exposure(float p_exposure){ + + tonemap_exposure=p_exposure; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); +} + +float Environment::get_tonemap_exposure() const{ + + return get_tonemap_auto_exposure(); +} + +void Environment::set_tonemap_white(float p_white){ + + tonemap_white=p_white; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); + +} +float Environment::get_tonemap_white() const { + + return tonemap_white; +} + +void Environment::set_tonemap_auto_exposure(bool p_enabled) { + + tonemap_auto_exposure=p_enabled; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); + +} +bool Environment::get_tonemap_auto_exposure() const { + + return tonemap_auto_exposure; +} + +void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) { + + tonemap_auto_exposure_max=p_auto_exposure_max; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); + +} +float Environment::get_tonemap_auto_exposure_max() const { + + return tonemap_auto_exposure_max; +} + +void Environment::set_tonemap_auto_exposure_min(float p_auto_exposure_min) { + + tonemap_auto_exposure_min=p_auto_exposure_min; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); + +} +float Environment::get_tonemap_auto_exposure_min() const { + + return tonemap_auto_exposure_min; +} + +void Environment::set_tonemap_auto_exposure_speed(float p_auto_exposure_speed) { + + tonemap_auto_exposure_speed=p_auto_exposure_speed; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); + +} +float Environment::get_tonemap_auto_exposure_speed() const { + + return tonemap_auto_exposure_speed; +} + +void Environment::set_tonemap_auto_exposure_scale(float p_auto_exposure_scale) { + + tonemap_auto_exposure_scale=p_auto_exposure_scale; + VS::get_singleton()->environment_set_tonemap(environment,tonemap_auto_exposure,tonemap_exposure,tonemap_white,tonemap_auto_exposure_min,tonemap_auto_exposure_max,tonemap_auto_exposure_speed,tonemap_auto_exposure_scale,VS::EnvironmentToneMapper(tone_mapper)); + +} +float Environment::get_tonemap_auto_exposure_scale() const { + + return tonemap_auto_exposure_scale; +} + +void Environment::set_adjustment_enable(bool p_enable) { + + adjustment_enabled=p_enable; + VS::get_singleton()->environment_set_adjustment(environment,adjustment_enabled,adjustment_brightness,adjustment_contrast,adjustment_saturation,adjustment_color_correction.is_valid()?adjustment_color_correction->get_rid():RID()); +} + +bool Environment::is_adjustment_enabled() const { + + return adjustment_enabled; +} + + +void Environment::set_adjustment_brightness(float p_brightness) { + + adjustment_brightness=p_brightness; + VS::get_singleton()->environment_set_adjustment(environment,adjustment_enabled,adjustment_brightness,adjustment_contrast,adjustment_saturation,adjustment_color_correction.is_valid()?adjustment_color_correction->get_rid():RID()); + +} +float Environment::get_adjustment_brightness() const { + + return adjustment_brightness; +} + +void Environment::set_adjustment_contrast(float p_contrast) { + + adjustment_contrast=p_contrast; + VS::get_singleton()->environment_set_adjustment(environment,adjustment_enabled,adjustment_brightness,adjustment_contrast,adjustment_saturation,adjustment_color_correction.is_valid()?adjustment_color_correction->get_rid():RID()); + +} +float Environment::get_adjustment_contrast() const { + + return adjustment_contrast; +} + +void Environment::set_adjustment_saturation(float p_saturation) { + + adjustment_saturation=p_saturation; + VS::get_singleton()->environment_set_adjustment(environment,adjustment_enabled,adjustment_brightness,adjustment_contrast,adjustment_saturation,adjustment_color_correction.is_valid()?adjustment_color_correction->get_rid():RID()); + +} +float Environment::get_adjustment_saturation() const { + + return adjustment_saturation; +} + +void Environment::set_adjustment_color_correction(const Ref& p_ramp) { + + adjustment_color_correction=p_ramp; + VS::get_singleton()->environment_set_adjustment(environment,adjustment_enabled,adjustment_brightness,adjustment_contrast,adjustment_saturation,adjustment_color_correction.is_valid()?adjustment_color_correction->get_rid():RID()); + +} +Ref Environment::get_adjustment_color_correction() const { + + return adjustment_color_correction; +} + + void Environment::_validate_property(PropertyInfo& property) const { if (property.name=="background/skybox" || property.name=="background/skybox_scale" || property.name=="ambient_light/skybox_contribution") { @@ -190,6 +335,61 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_ambient_light_energy"),_SCS("get_ambient_light_energy") ); ADD_PROPERTY(PropertyInfo(Variant::REAL,"ambient_light/skybox_contribution",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_ambient_light_skybox_contribution"),_SCS("get_ambient_light_skybox_contribution") ); + ObjectTypeDB::bind_method(_MD("set_tonemapper","mode"),&Environment::set_tonemapper); + ObjectTypeDB::bind_method(_MD("get_tonemapper"),&Environment::get_tonemapper); + + ObjectTypeDB::bind_method(_MD("set_tonemap_exposure","exposure"),&Environment::set_tonemap_exposure); + ObjectTypeDB::bind_method(_MD("get_tonemap_exposure"),&Environment::get_tonemap_exposure); + + ObjectTypeDB::bind_method(_MD("set_tonemap_white","white"),&Environment::set_tonemap_white); + ObjectTypeDB::bind_method(_MD("get_tonemap_white"),&Environment::get_tonemap_white); + + ObjectTypeDB::bind_method(_MD("set_tonemap_auto_exposure","auto_exposure"),&Environment::set_tonemap_auto_exposure); + ObjectTypeDB::bind_method(_MD("get_tonemap_auto_exposure"),&Environment::get_tonemap_auto_exposure); + + ObjectTypeDB::bind_method(_MD("set_tonemap_auto_exposure_max","exposure_max"),&Environment::set_tonemap_auto_exposure_max); + ObjectTypeDB::bind_method(_MD("get_tonemap_auto_exposure_max"),&Environment::get_tonemap_auto_exposure_max); + + ObjectTypeDB::bind_method(_MD("set_tonemap_auto_exposure_min","exposure_min"),&Environment::set_tonemap_auto_exposure_min); + ObjectTypeDB::bind_method(_MD("get_tonemap_auto_exposure_min"),&Environment::get_tonemap_auto_exposure_min); + + ObjectTypeDB::bind_method(_MD("set_tonemap_auto_exposure_speed","exposure_speed"),&Environment::set_tonemap_auto_exposure_speed); + ObjectTypeDB::bind_method(_MD("get_tonemap_auto_exposure_speed"),&Environment::get_tonemap_auto_exposure_speed); + + ObjectTypeDB::bind_method(_MD("set_tonemap_auto_exposure_scale","exposure_scale"),&Environment::set_tonemap_auto_exposure_scale); + ObjectTypeDB::bind_method(_MD("get_tonemap_auto_exposure_scale"),&Environment::get_tonemap_auto_exposure_scale); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"tonemap/mode",PROPERTY_HINT_ENUM,"Linear,Log,Reindhart,Filmic,Aces"),_SCS("set_tonemapper"),_SCS("get_tonemapper") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"tonemap/exposure",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_tonemap_exposure"),_SCS("get_tonemap_exposure") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"tonemap/white",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_tonemap_white"),_SCS("get_tonemap_white") ); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"auto_exposure/enable"),_SCS("set_tonemap_auto_exposure"),_SCS("get_tonemap_auto_exposure") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"auto_exposure/scale",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_tonemap_auto_exposure_scale"),_SCS("get_tonemap_auto_exposure_scale") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"auto_exposure/min_luma",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_tonemap_auto_exposure_min"),_SCS("get_tonemap_auto_exposure_min") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"auto_exposure/max_luma",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_tonemap_auto_exposure_max"),_SCS("get_tonemap_auto_exposure_max") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"auto_exposure/speed",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_tonemap_auto_exposure_speed"),_SCS("get_tonemap_auto_exposure_speed") ); + + ObjectTypeDB::bind_method(_MD("set_adjustment_enable","enabled"),&Environment::set_adjustment_enable); + ObjectTypeDB::bind_method(_MD("is_adjustment_enabled"),&Environment::is_adjustment_enabled); + + ObjectTypeDB::bind_method(_MD("set_adjustment_brightness","brightness"),&Environment::set_adjustment_brightness); + ObjectTypeDB::bind_method(_MD("get_adjustment_brightness"),&Environment::get_adjustment_brightness); + + ObjectTypeDB::bind_method(_MD("set_adjustment_contrast","contrast"),&Environment::set_adjustment_contrast); + ObjectTypeDB::bind_method(_MD("get_adjustment_contrast"),&Environment::get_adjustment_contrast); + + ObjectTypeDB::bind_method(_MD("set_adjustment_saturation","saturation"),&Environment::set_adjustment_saturation); + ObjectTypeDB::bind_method(_MD("get_adjustment_saturation"),&Environment::get_adjustment_saturation); + + ObjectTypeDB::bind_method(_MD("set_adjustment_color_correction","color_correction"),&Environment::set_adjustment_color_correction); + ObjectTypeDB::bind_method(_MD("get_adjustment_color_correction"),&Environment::get_adjustment_color_correction); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"adjustment/enabled"),_SCS("set_adjustment_enable"),_SCS("is_adjustment_enabled") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"adjustment/brightness",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("set_adjustment_brightness"),_SCS("get_adjustment_brightness") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"adjustment/contrast",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("set_adjustment_contrast"),_SCS("get_adjustment_contrast") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"adjustment/saturation",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("set_adjustment_saturation"),_SCS("get_adjustment_saturation") ); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"adjustment/color_correction",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_adjustment_color_correction"),_SCS("get_adjustment_color_correction") ); + + GLOBAL_DEF("rendering/skybox/irradiance_cube_resolution",256); GLOBAL_DEF("rendering/skybox/radiance_cube_resolution",64); @@ -203,6 +403,12 @@ void Environment::_bind_methods() { BIND_CONSTANT(GLOW_BLEND_MODE_SCREEN); BIND_CONSTANT(GLOW_BLEND_MODE_SOFTLIGHT); BIND_CONSTANT(GLOW_BLEND_MODE_DISABLED); + BIND_CONSTANT(TONE_MAPPER_LINEAR); + BIND_CONSTANT(TONE_MAPPER_LOG); + BIND_CONSTANT(TONE_MAPPER_REINHARDT); + BIND_CONSTANT(TONE_MAPPER_FILMIC); + BIND_CONSTANT(TONE_MAPPER_ACES_FILMIC); + } @@ -216,6 +422,24 @@ Environment::Environment() { ambient_skybox_contribution=0; + tone_mapper=TONE_MAPPER_LINEAR; + tonemap_exposure=1.0; + tonemap_white=1.0; + tonemap_auto_exposure=false; + tonemap_auto_exposure_max=8; + tonemap_auto_exposure_min=0.4; + tonemap_auto_exposure_speed=0.5; + tonemap_auto_exposure_scale=0.4; + + set_tonemapper(tone_mapper); //update + + adjustment_enabled=false; + adjustment_contrast=1.0; + adjustment_saturation=1.0; + adjustment_brightness=1.0; + + set_adjustment_enable(adjustment_enabled); //update + environment = VS::get_singleton()->environment_create(); } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 6478f6420..394b67dad 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -55,6 +55,16 @@ public: GLOW_BLEND_MODE_DISABLED, }; + enum ToneMapper { + TONE_MAPPER_LINEAR, + TONE_MAPPER_LOG, + TONE_MAPPER_REINHARDT, + TONE_MAPPER_FILMIC, + TONE_MAPPER_ACES_FILMIC + }; + + + private: RID environment; @@ -68,6 +78,21 @@ private: float ambient_energy; float ambient_skybox_contribution; + ToneMapper tone_mapper; + float tonemap_exposure; + float tonemap_white; + bool tonemap_auto_exposure; + float tonemap_auto_exposure_max; + float tonemap_auto_exposure_min; + float tonemap_auto_exposure_speed; + float tonemap_auto_exposure_scale; + + bool adjustment_enabled; + float adjustment_contrast; + float adjustment_saturation; + float adjustment_brightness; + Ref adjustment_color_correction; + protected: static void _bind_methods(); @@ -97,14 +122,58 @@ public: float get_ambient_light_skybox_contribution() const; + void set_tonemapper(ToneMapper p_tone_mapper); + ToneMapper get_tonemapper() const; + + void set_tonemap_exposure(float p_exposure); + float get_tonemap_exposure() const; + + void set_tonemap_white(float p_white); + float get_tonemap_white() const; + + void set_tonemap_auto_exposure(bool p_enabled); + bool get_tonemap_auto_exposure() const; + + void set_tonemap_auto_exposure_max(float p_auto_exposure_max); + float get_tonemap_auto_exposure_max() const; + + void set_tonemap_auto_exposure_min(float p_auto_exposure_min); + float get_tonemap_auto_exposure_min() const; + + void set_tonemap_auto_exposure_speed(float p_auto_exposure_speed); + float get_tonemap_auto_exposure_speed() const; + + void set_tonemap_auto_exposure_scale(float p_auto_exposure_scale); + float get_tonemap_auto_exposure_scale() const; + + void set_adjustment_enable(bool p_enable); + bool is_adjustment_enabled() const; + + void set_adjustment_brightness(float p_brightness); + float get_adjustment_brightness() const; + + void set_adjustment_contrast(float p_contrast); + float get_adjustment_contrast() const; + + void set_adjustment_saturation(float p_saturation); + float get_adjustment_saturation() const; + + void set_adjustment_color_correction(const Ref& p_ramp); + Ref get_adjustment_color_correction() const; + + virtual RID get_rid() const; Environment(); ~Environment(); }; + + + VARIANT_ENUM_CAST(Environment::BGMode) VARIANT_ENUM_CAST(Environment::GlowBlendMode) +VARIANT_ENUM_CAST(Environment::ToneMapper) #endif // ENVIRONMENT_H diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index e3df1461c..3c7b0fbe6 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -74,6 +74,7 @@ void FixedSpatialMaterial::init_shaders() { shader_names->subsurface_scattering="subsurface_scattering"; shader_names->refraction="refraction"; shader_names->refraction_roughness="refraction_roughness"; + shader_names->point_size="point_size"; shader_names->texture_names[TEXTURE_ALBEDO]="texture_albedo"; shader_names->texture_names[TEXTURE_SPECULAR]="texture_specular"; @@ -166,15 +167,33 @@ void FixedSpatialMaterial::_update_shader() { code+="uniform vec4 albedo : hint_color;\n"; - code+="uniform sampler2D albedo_texture : hint_albedo;\n"; + code+="uniform sampler2D texture_albedo : hint_albedo;\n"; code+="uniform vec4 specular : hint_color;\n"; code+="uniform float roughness : hint_range(0,1);\n"; - code+="uniform sampler2D specular_texture : hint_white;\n"; + code+="uniform float point_size : hint_range(0,128);\n"; + code+="uniform sampler2D texture_specular : hint_white;\n"; code+="\n\n"; + code+="void vertex() {\n"; + + if (flags[FLAG_SRGB_VERTEX_COLOR]) { + + code+="\tCOLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );\n"; + } + if (flags[FLAG_USE_POINT_SIZE]) { + + code+="\tPOINT_SIZE=point_size;\n"; + } + + code+="}\n"; code+="\n\n"; code+="void fragment() {\n"; - code+="\tvec4 albedo_tex = texture(albedo_texture,UV);\n"; + + if (flags[FLAG_USE_POINT_SIZE]) { + code+="\tvec4 albedo_tex = texture(texture_albedo,POINT_COORD);\n"; + } else { + code+="\tvec4 albedo_tex = texture(texture_albedo,UV);\n"; + } if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) { code+="\talbedo_tex *= COLOR;\n"; @@ -184,7 +203,7 @@ void FixedSpatialMaterial::_update_shader() { if (features[FEATURE_TRANSPARENT]) { code+="\tALPHA = albedo.a * albedo_tex.a;\n"; } - code+="\tvec4 specular_tex = texture(specular_texture,UV);\n"; + code+="\tvec4 specular_tex = texture(texture_specular,UV);\n"; code+="\tSPECULAR = specular.rgb * specular_tex.rgb;\n"; code+="\tROUGHNESS = specular.a * roughness;\n"; code+="}\n"; @@ -526,7 +545,8 @@ void FixedSpatialMaterial::set_texture(TextureParam p_param, const Ref ERR_FAIL_INDEX(p_param,TEXTURE_MAX); textures[p_param]=p_texture; - VS::get_singleton()->material_set_param(_get_material(),shader_names->texture_names[p_param],p_texture); + RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + VS::get_singleton()->material_set_param(_get_material(),shader_names->texture_names[p_param],rid); } Ref FixedSpatialMaterial::get_texture(TextureParam p_param) const { @@ -540,6 +560,7 @@ void FixedSpatialMaterial::_validate_feature(const String& text, Feature feature if (property.name.begins_with(text) && property.name!=text+"/enabled" && !features[feature]) { property.usage=0; } + } void FixedSpatialMaterial::_validate_property(PropertyInfo& property) const { @@ -555,6 +576,28 @@ void FixedSpatialMaterial::_validate_property(PropertyInfo& property) const { } +void FixedSpatialMaterial::set_line_width(float p_line_width) { + + line_width=p_line_width; + VS::get_singleton()->material_set_line_width(_get_material(),line_width); +} + +float FixedSpatialMaterial::get_line_width() const { + + return line_width; +} + +void FixedSpatialMaterial::set_point_size(float p_point_size) { + + point_size=p_point_size; + VS::get_singleton()->material_set_param(_get_material(),shader_names->point_size,p_point_size); +} + +float FixedSpatialMaterial::get_point_size() const { + + return point_size; +} + void FixedSpatialMaterial::_bind_methods() { @@ -600,6 +643,12 @@ void FixedSpatialMaterial::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_refraction_roughness","refraction_roughness"),&FixedSpatialMaterial::set_refraction_roughness); ObjectTypeDB::bind_method(_MD("get_refraction_roughness"),&FixedSpatialMaterial::get_refraction_roughness); + ObjectTypeDB::bind_method(_MD("set_line_width","line_width"),&FixedSpatialMaterial::set_line_width); + ObjectTypeDB::bind_method(_MD("get_line_width"),&FixedSpatialMaterial::get_line_width); + + ObjectTypeDB::bind_method(_MD("set_point_size","point_size"),&FixedSpatialMaterial::set_point_size); + ObjectTypeDB::bind_method(_MD("get_point_size"),&FixedSpatialMaterial::get_point_size); + ObjectTypeDB::bind_method(_MD("set_detail_uv","detail_uv"),&FixedSpatialMaterial::set_detail_uv); ObjectTypeDB::bind_method(_MD("get_detail_uv"),&FixedSpatialMaterial::get_detail_uv); @@ -630,12 +679,16 @@ void FixedSpatialMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/transparent"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_TRANSPARENT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/unshaded"),_SCS("set_flag"),_SCS("get_flag"),FLAG_UNSHADED); ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/on_top"),_SCS("set_flag"),_SCS("get_flag"),FLAG_ONTOP); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/vcol_albedo"),_SCS("set_flag"),_SCS("get_flag"),FLAG_ALBEDO_FROM_VERTEX_COLOR); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"flags/use_point_size"),_SCS("set_flag"),_SCS("get_flag"),FLAG_USE_POINT_SIZE); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"vertex_color/use_as_albedo"),_SCS("set_flag"),_SCS("get_flag"),FLAG_ALBEDO_FROM_VERTEX_COLOR); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"vertex_color/is_srgb"),_SCS("set_flag"),_SCS("get_flag"),FLAG_SRGB_VERTEX_COLOR); ADD_PROPERTY(PropertyInfo(Variant::INT,"params/diffuse_mode",PROPERTY_HINT_ENUM,"Labert,Lambert Wrap,Oren Nayar,Burley"),_SCS("set_diffuse_mode"),_SCS("get_diffuse_mode")); ADD_PROPERTY(PropertyInfo(Variant::INT,"params/blend_mode",PROPERTY_HINT_ENUM,"Mix,Add,Sub,Mul"),_SCS("set_blend_mode"),_SCS("get_blend_mode")); ADD_PROPERTY(PropertyInfo(Variant::INT,"params/cull_mode",PROPERTY_HINT_ENUM,"Back,Front,Disabled"),_SCS("set_cull_mode"),_SCS("get_cull_mode")); ADD_PROPERTY(PropertyInfo(Variant::INT,"params/depth_draw_mode",PROPERTY_HINT_ENUM,"Opaque Only,Always,Never,Opaque Pre-Pass"),_SCS("set_depth_draw_mode"),_SCS("get_depth_draw_mode")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"params/line_width",PROPERTY_HINT_RANGE,"0.1,128,0.1"),_SCS("set_line_width"),_SCS("get_line_width")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"params/point_size",PROPERTY_HINT_RANGE,"0.1,128,0.1"),_SCS("set_point_size"),_SCS("get_point_size")); ADD_PROPERTY(PropertyInfo(Variant::COLOR,"albedo/color"),_SCS("set_albedo"),_SCS("get_albedo")); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"albedo/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_ALBEDO); @@ -737,6 +790,8 @@ void FixedSpatialMaterial::_bind_methods() { BIND_CONSTANT( FLAG_UNSHADED ); BIND_CONSTANT( FLAG_ONTOP ); BIND_CONSTANT( FLAG_ALBEDO_FROM_VERTEX_COLOR ); + BIND_CONSTANT( FLAG_SRGB_VERTEX_COLOR ) + BIND_CONSTANT( FLAG_USE_POINT_SIZE ) BIND_CONSTANT( FLAG_MAX ); BIND_CONSTANT( DIFFUSE_LAMBERT ); @@ -763,6 +818,8 @@ FixedSpatialMaterial::FixedSpatialMaterial() : element(this) { set_subsurface_scattering(0); set_refraction(0); set_refraction_roughness(0); + set_line_width(1); + set_point_size(1); detail_uv=DETAIL_UV_1; blend_mode=BLEND_MODE_MIX; diff --git a/scene/resources/material.h b/scene/resources/material.h index 0f0bf4802..35f01d475 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -132,6 +132,8 @@ public: FLAG_UNSHADED, FLAG_ONTOP, FLAG_ALBEDO_FROM_VERTEX_COLOR, + FLAG_SRGB_VERTEX_COLOR, + FLAG_USE_POINT_SIZE, FLAG_MAX }; @@ -146,12 +148,12 @@ private: union MaterialKey { struct { - uint32_t feature_mask : 16; + uint32_t feature_mask : 15; uint32_t detail_uv : 1; uint32_t blend_mode : 2; uint32_t depth_draw_mode : 2; uint32_t cull_mode : 2; - uint32_t flags : 3; + uint32_t flags : 5; uint32_t detail_blend_mode : 2; uint32_t diffuse_mode : 2; uint32_t invalid_key : 1; @@ -213,7 +215,9 @@ private: StringName subsurface_scattering; StringName refraction; StringName refraction_roughness; + StringName point_size; StringName texture_names[TEXTURE_MAX]; + }; static Mutex *material_mutex; @@ -240,6 +244,8 @@ private: float subsurface_scattering; float refraction; float refraction_roughness; + float line_width; + float point_size; DetailUV detail_uv; @@ -306,6 +312,12 @@ public: void set_refraction_roughness(float p_refraction_roughness); float get_refraction_roughness() const; + void set_line_width(float p_line_width); + float get_line_width() const; + + void set_point_size(float p_point_size); + float get_point_size() const; + void set_detail_uv(DetailUV p_detail_uv); DetailUV get_detail_uv() const; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 78757c799..b61a2d0a4 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -54,11 +54,8 @@ public: virtual void environment_set_glow(RID p_env,bool p_enable,int p_radius,float p_intensity,float p_strength,float p_bloom_treshold,VS::EnvironmentGlowBlendMode p_blend_mode)=0; virtual void environment_set_fog(RID p_env,bool p_enable,float p_begin,float p_end,RID p_gradient_texture)=0; - virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,VS::EnvironmentToneMapper p_tone_mapper)=0; - virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness)=0; - virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast)=0; - virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation)=0; - virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp)=0; + virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,float p_auto_exp_scale,VS::EnvironmentToneMapper p_tone_mapper)=0; + virtual void environment_set_adjustment(RID p_env,bool p_enable,float p_brightness,float p_contrast,float p_saturation,RID p_ramp)=0; struct InstanceBase : RID_Data { @@ -176,6 +173,8 @@ public: virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value)=0; virtual Variant material_get_param(RID p_material, const StringName& p_param) const=0; + virtual void material_set_line_width(RID p_material, float p_width)=0; + /* MESH API */ virtual RID mesh_create()=0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 655ce410b..6c7048bd6 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -658,6 +658,10 @@ public: BIND3(material_set_param,RID, const StringName&, const Variant& ) BIND2RC(Variant,material_get_param,RID, const StringName& ) + BIND2(material_set_line_width,RID, float ) + + + /* MESH API */ BIND0R(RID,mesh_create) @@ -864,11 +868,8 @@ public: BIND7(environment_set_glow,RID,bool ,int ,float ,float ,float ,EnvironmentGlowBlendMode ) BIND5(environment_set_fog,RID,bool ,float ,float ,RID ) - BIND8(environment_set_tonemap,RID,bool ,float ,float ,float ,float ,float ,EnvironmentToneMapper ) - BIND3(environment_set_brightness,RID,bool ,float ) - BIND3(environment_set_contrast,RID,bool ,float ) - BIND3(environment_set_saturation,RID,bool ,float ) - BIND3(environment_set_color_correction,RID,bool ,RID ) + BIND9(environment_set_tonemap,RID,bool ,float ,float ,float ,float ,float,float ,EnvironmentToneMapper ) + BIND6(environment_set_adjustment,RID,bool ,float ,float ,float ,RID ) /* SCENARIO API */ diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 2f0f8f263..d958ea4bd 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -692,21 +692,81 @@ void VisualServerScene::instance_set_extra_visibility_margin( RID p_instance, re } -// don't use these in a game! -Vector VisualServerScene::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const{ +Vector VisualServerScene::instances_cull_aabb(const AABB& p_aabb, RID p_scenario) const { - return Vector(); -} -Vector VisualServerScene::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{ + Vector instances; + Scenario *scenario=scenario_owner.get(p_scenario); + ERR_FAIL_COND_V(!scenario,instances); + + const_cast(this)->update_dirty_instances(); // check dirty instances before culling + + int culled=0; + Instance *cull[1024]; + culled=scenario->octree.cull_AABB(p_aabb,cull,1024); - return Vector(); + for (int i=0;iobject_ID==0) + continue; + + instances.push_back(instance->object_ID); + } + + return instances; } -Vector VisualServerScene::instances_cull_convex(const Vector& p_convex, RID p_scenario) const { +Vector VisualServerScene::instances_cull_ray(const Vector3& p_from, const Vector3& p_to, RID p_scenario) const{ + + Vector instances; + Scenario *scenario=scenario_owner.get(p_scenario); + ERR_FAIL_COND_V(!scenario,instances); + const_cast(this)->update_dirty_instances(); // check dirty instances before culling + + int culled=0; + Instance *cull[1024]; + culled=scenario->octree.cull_segment(p_from,p_to*10000,cull,1024); + + + for (int i=0;iobject_ID==0) + continue; + + instances.push_back(instance->object_ID); + } + + return instances; - return Vector(); } +Vector VisualServerScene::instances_cull_convex(const Vector& p_convex, RID p_scenario) const{ + + Vector instances; + Scenario *scenario=scenario_owner.get(p_scenario); + ERR_FAIL_COND_V(!scenario,instances); + const_cast(this)->update_dirty_instances(); // check dirty instances before culling + + int culled=0; + Instance *cull[1024]; + + + culled=scenario->octree.cull_convex(p_convex,cull,1024); + for (int i=0;iobject_ID==0) + continue; + + instances.push_back(instance->object_ID); + } + + return instances; + +} void VisualServerScene::instance_geometry_set_flag(RID p_instance,VS::InstanceFlags p_flags,bool p_enabled){ diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 515d52db7..10a159f27 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -162,7 +162,7 @@ public: Scenario() { debug=VS::SCENARIO_DEBUG_DISABLED; } }; - RID_Owner scenario_owner; + mutable RID_Owner scenario_owner; static void* _instance_pair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int); static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A,int, OctreeElementID, Instance *p_B,int,void*); diff --git a/servers/visual_server.h b/servers/visual_server.h index bbe6c2c68..78769c17f 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -172,6 +172,8 @@ public: virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value)=0; virtual Variant material_get_param(RID p_material, const StringName& p_param) const=0; + virtual void material_set_line_width(RID p_material, float p_width)=0; + /* MESH API */ enum ArrayType { @@ -512,15 +514,14 @@ public: enum EnvironmentToneMapper { ENV_TONE_MAPPER_LINEAR, + ENV_TONE_MAPPER_LOG, ENV_TONE_MAPPER_REINHARDT, - ENV_TONE_MAPPER_FILMIC + ENV_TONE_MAPPER_FILMIC, + ENV_TONE_MAPPER_ACES_FILMIC }; - virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,EnvironmentToneMapper p_tone_mapper)=0; - virtual void environment_set_brightness(RID p_env,bool p_enable,float p_brightness)=0; - virtual void environment_set_contrast(RID p_env,bool p_enable,float p_contrast)=0; - virtual void environment_set_saturation(RID p_env,bool p_enable,float p_saturation)=0; - virtual void environment_set_color_correction(RID p_env,bool p_enable,RID p_ramp)=0; + virtual void environment_set_tonemap(RID p_env,bool p_enable,float p_exposure,float p_white,float p_min_luminance,float p_max_luminance,float p_auto_exp_speed,float p_auto_exp_scale,EnvironmentToneMapper p_tone_mapper)=0; + virtual void environment_set_adjustment(RID p_env,bool p_enable,float p_brightness,float p_contrast,float p_saturation,RID p_ramp)=0; /* SCENARIO API */ diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index a4ee102ae..99c2b468f 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -4144,7 +4144,7 @@ void EditorNode::register_editor_types() { ObjectTypeDB::register_type(); //ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); -// ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 7a24ab418..13c69692c 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -2553,6 +2553,7 @@ void SpatialEditor::_generate_selection_box() { mat->set_albedo(Color(1,1,1)); mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true); mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); + mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true); st->set_material(mat); selection_box = st->commit(); } @@ -3143,6 +3144,8 @@ void SpatialEditor::_init_indicators() { indicator_mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ONTOP,true); indicator_mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); + indicator_mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true); + indicator_mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true); DVector grid_colors[3]; @@ -3543,7 +3546,7 @@ void SpatialEditor::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { - //gizmos = memnew( SpatialEditorGizmos ); + gizmos = memnew( SpatialEditorGizmos ); _init_indicators(); _update_default_light_angle(); } @@ -3551,7 +3554,7 @@ void SpatialEditor::_notification(int p_what) { if (p_what==NOTIFICATION_EXIT_TREE) { _finish_indicators(); -// memdelete( gizmos ); + memdelete( gizmos ); } } @@ -3597,7 +3600,7 @@ void SpatialEditor::_request_gizmo(Object* p_obj) { } if (!seg.is_valid()) { - // seg = gizmos->get_gizmo(sp); + seg = gizmos->get_gizmo(sp); } if (seg.is_valid()) { diff --git a/tools/editor/plugins/spatial_editor_plugin.h b/tools/editor/plugins/spatial_editor_plugin.h index 8c8a80bc3..1617acaef 100644 --- a/tools/editor/plugins/spatial_editor_plugin.h +++ b/tools/editor/plugins/spatial_editor_plugin.h @@ -467,7 +467,7 @@ private: static SpatialEditor *singleton; void _node_removed(Node* p_node); - //SpatialEditorGizmos *gizmos; + SpatialEditorGizmos *gizmos; SpatialEditor(); void _update_ambient_light_color(const Color& p_color); diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index bc76f6c20..b1accac76 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -41,7 +41,7 @@ // Keep small children away from this file. // It's so ugly it will eat them alive -#if 0 + #define HANDLE_HALF_SIZE 0.05 @@ -84,7 +84,6 @@ void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) { if (extra_margin) VS::get_singleton()->instance_set_extra_visibility_margin(instance,1); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance,VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_RECEIVE_SHADOWS,false); VS::get_singleton()->instance_set_layer_mask(instance,1<get_parameter(Light::PARAM_RADIUS); + return light->get_param(Light::PARAM_RANGE); if (p_idx==1) - return light->get_parameter(Light::PARAM_SPOT_ANGLE); + return light->get_param(Light::PARAM_SPOT_ANGLE); return Variant(); } @@ -729,7 +728,7 @@ void LightSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_p if (d<0) d=0; - light->set_parameter(Light::PARAM_RADIUS,d); + light->set_param(Light::PARAM_RANGE,d); } else if (light->cast_to()) { Plane cp=Plane( gt.origin, p_camera->get_transform().basis.get_axis(2)); @@ -738,15 +737,15 @@ void LightSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_p if (cp.intersects_ray(ray_from,ray_dir,&inters)) { float r = inters.distance_to(gt.origin); - light->set_parameter(Light::PARAM_RADIUS,r); + light->set_param(Light::PARAM_RANGE,r); } } } else if (p_idx==1) { - float a = _find_closest_angle_to_half_pi_arc(s[0],s[1],light->get_parameter(Light::PARAM_RADIUS),gt); - light->set_parameter(Light::PARAM_SPOT_ANGLE,CLAMP(a,0.01,89.99)); + float a = _find_closest_angle_to_half_pi_arc(s[0],s[1],light->get_param(Light::PARAM_RANGE),gt); + light->set_param(Light::PARAM_SPOT_ANGLE,CLAMP(a,0.01,89.99)); } } @@ -754,21 +753,21 @@ void LightSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_ if (p_cancel) { - light->set_parameter(p_idx==0?Light::PARAM_RADIUS:Light::PARAM_SPOT_ANGLE,p_restore); + light->set_param(p_idx==0?Light::PARAM_RANGE:Light::PARAM_SPOT_ANGLE,p_restore); } else if (p_idx==0) { UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); ur->create_action(TTR("Change Light Radius")); - ur->add_do_method(light,"set_parameter",Light::PARAM_RADIUS,light->get_parameter(Light::PARAM_RADIUS)); - ur->add_undo_method(light,"set_parameter",Light::PARAM_RADIUS,p_restore); + ur->add_do_method(light,"set_param",Light::PARAM_RANGE,light->get_param(Light::PARAM_RANGE)); + ur->add_undo_method(light,"set_param",Light::PARAM_RANGE,p_restore); ur->commit_action(); } else if (p_idx==1) { UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); ur->create_action(TTR("Change Light Radius")); - ur->add_do_method(light,"set_parameter",Light::PARAM_SPOT_ANGLE,light->get_parameter(Light::PARAM_SPOT_ANGLE)); - ur->add_undo_method(light,"set_parameter",Light::PARAM_SPOT_ANGLE,p_restore); + ur->add_do_method(light,"set_param",Light::PARAM_SPOT_ANGLE,light->get_param(Light::PARAM_SPOT_ANGLE)); + ur->add_undo_method(light,"set_param",Light::PARAM_SPOT_ANGLE,p_restore); ur->commit_action(); } @@ -831,7 +830,7 @@ void LightSpatialGizmo::redraw() { OmniLight *on = light->cast_to(); - float r = on->get_parameter(Light::PARAM_RADIUS); + float r = on->get_param(Light::PARAM_RANGE); Vector points; @@ -871,9 +870,9 @@ void LightSpatialGizmo::redraw() { Vector points; SpotLight *on = light->cast_to(); - float r = on->get_parameter(Light::PARAM_RADIUS); - float w = r*Math::sin(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE))); - float d = r*Math::cos(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE))); + float r = on->get_param(Light::PARAM_RANGE); + float w = r*Math::sin(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE))); + float d = r*Math::cos(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE))); @@ -1543,7 +1542,7 @@ void RayCastSpatialGizmo::redraw() { } -RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast* p_raycast){ +RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast* p_raycast) { set_spatial_node(p_raycast); raycast=p_raycast; @@ -2979,11 +2978,12 @@ Ref SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { Ref SpatialEditorGizmos::create_line_material(const Color& p_base_color) { Ref line_material = Ref( memnew( FixedSpatialMaterial )); - line_material->set_flag(Material::FLAG_UNSHADED, true); + line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); line_material->set_line_width(3.0); - line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,p_base_color); + line_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + line_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + line_material->set_albedo(p_base_color); return line_material; @@ -2992,9 +2992,9 @@ Ref SpatialEditorGizmos::create_line_material(const Color& Ref SpatialEditorGizmos::create_solid_material(const Color& p_base_color) { Ref line_material = Ref( memnew( FixedSpatialMaterial )); - line_material->set_flag(Material::FLAG_UNSHADED, true); - line_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - line_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,p_base_color); + line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + line_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + line_material->set_albedo(p_base_color); return line_material; @@ -3005,56 +3005,59 @@ SpatialEditorGizmos::SpatialEditorGizmos() { singleton=this; handle_material = Ref( memnew( FixedSpatialMaterial )); - handle_material->set_flag(Material::FLAG_UNSHADED, true); - handle_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.8)); + handle_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + handle_material->set_albedo(Color(0.8,0.8,0.8)); handle2_material = Ref( memnew( FixedSpatialMaterial )); - handle2_material->set_flag(Material::FLAG_UNSHADED, true); - handle2_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_POINT_SIZE, true); + handle2_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + handle2_material->set_flag(FixedSpatialMaterial::FLAG_USE_POINT_SIZE, true); handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle","EditorIcons"); handle2_material->set_point_size(handle_t->get_width()); - handle2_material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,handle_t); - handle2_material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1)); - handle2_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - handle2_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + handle2_material->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,handle_t); + handle2_material->set_albedo(Color(1,1,1)); + handle2_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + handle2_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + handle2_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); light_material = create_line_material(Color(1,1,0.2)); light_material_omni_icon = Ref( memnew( FixedSpatialMaterial )); - light_material_omni_icon->set_flag(Material::FLAG_UNSHADED, true); - light_material_omni_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); - light_material_omni_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - light_material_omni_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - light_material_omni_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - light_material_omni_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoLight","EditorIcons")); + light_material_omni_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + light_material_omni_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + light_material_omni_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED); + light_material_omni_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + light_material_omni_icon->set_albedo(Color(1,1,1,0.9)); + light_material_omni_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,SpatialEditor::get_singleton()->get_icon("GizmoLight","EditorIcons")); light_material_directional_icon = Ref( memnew( FixedSpatialMaterial )); - light_material_directional_icon->set_flag(Material::FLAG_UNSHADED, true); - light_material_directional_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); - light_material_directional_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - light_material_directional_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - light_material_directional_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - light_material_directional_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight","EditorIcons")); + light_material_directional_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + light_material_directional_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + light_material_directional_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED); + light_material_directional_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + light_material_directional_icon->set_albedo(Color(1,1,1,0.9)); + light_material_directional_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight","EditorIcons")); camera_material = create_line_material(Color(1.0,0.5,1.0)); navmesh_edge_material = create_line_material(Color(0.1,0.8,1.0)); navmesh_solid_material = create_solid_material(Color(0.1,0.8,1.0,0.4)); - navmesh_edge_material->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, false); - navmesh_solid_material->set_flag(Material::FLAG_DOUBLE_SIDED,true); + navmesh_edge_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false); + navmesh_edge_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false); + navmesh_solid_material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); navmesh_edge_material_disabled = create_line_material(Color(1.0,0.8,0.1)); navmesh_solid_material_disabled = create_solid_material(Color(1.0,0.8,0.1,0.4)); - navmesh_edge_material_disabled->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, false); - navmesh_solid_material_disabled->set_flag(Material::FLAG_DOUBLE_SIDED,true); + navmesh_edge_material_disabled->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false); + navmesh_edge_material_disabled->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false); + navmesh_solid_material_disabled->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); skeleton_material = create_line_material(Color(0.6,1.0,0.3)); - skeleton_material->set_flag(Material::FLAG_DOUBLE_SIDED,true); - skeleton_material->set_flag(Material::FLAG_UNSHADED,true); - skeleton_material->set_flag(Material::FLAG_ONTOP,true); - skeleton_material->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); + skeleton_material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + skeleton_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + skeleton_material->set_flag(FixedSpatialMaterial::FLAG_ONTOP,true); + skeleton_material->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED); //position 3D Shared mesh @@ -3078,9 +3081,10 @@ SpatialEditorGizmos::SpatialEditorGizmos() { cursor_colors.push_back(Color(0.5,0.5,1,0.7)); Ref mat = memnew( FixedSpatialMaterial ); - mat->set_flag(Material::FLAG_UNSHADED,true); - mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY,true); - mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA,true); + mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); + mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true); + mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT,true); mat->set_line_width(3); Array d; d.resize(VS::ARRAY_MAX); @@ -3101,9 +3105,10 @@ SpatialEditorGizmos::SpatialEditorGizmos() { cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); Ref mat = memnew(FixedSpatialMaterial); - mat->set_flag(Material::FLAG_UNSHADED, true); - mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_COLOR_ARRAY, true); - mat->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); + mat->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + mat->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + mat->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); mat->set_line_width(3); Array d; d.resize(VS::ARRAY_MAX); @@ -3115,12 +3120,12 @@ SpatialEditorGizmos::SpatialEditorGizmos() { sample_player_icon = Ref( memnew( FixedSpatialMaterial )); - sample_player_icon->set_flag(Material::FLAG_UNSHADED, true); - sample_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); - sample_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - sample_player_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - sample_player_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - sample_player_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer","EditorIcons")); + sample_player_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + sample_player_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + sample_player_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED); + sample_player_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + sample_player_icon->set_albedo(Color(1,1,1,0.9)); + sample_player_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer","EditorIcons")); room_material = create_line_material(Color(1.0,0.6,0.9)); portal_material = create_line_material(Color(1.0,0.8,0.6)); @@ -3130,28 +3135,28 @@ SpatialEditorGizmos::SpatialEditorGizmos() { joint_material = create_line_material(Color(0.6,0.8,1.0)); stream_player_icon = Ref( memnew( FixedSpatialMaterial )); - stream_player_icon->set_flag(Material::FLAG_UNSHADED, true); - stream_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); - stream_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - stream_player_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - stream_player_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - stream_player_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer","EditorIcons")); + stream_player_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + stream_player_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + stream_player_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED); + stream_player_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + stream_player_icon->set_albedo(Color(1,1,1,0.9)); + stream_player_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer","EditorIcons")); visibility_notifier_icon = Ref( memnew( FixedSpatialMaterial )); - visibility_notifier_icon->set_flag(Material::FLAG_UNSHADED, true); - visibility_notifier_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); - visibility_notifier_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - visibility_notifier_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - visibility_notifier_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9)); - visibility_notifier_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons")); + visibility_notifier_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + visibility_notifier_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + visibility_notifier_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED); + visibility_notifier_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + visibility_notifier_icon->set_albedo(Color(1,1,1,0.9)); + visibility_notifier_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons")); listener_icon = Ref(memnew(FixedSpatialMaterial)); - listener_icon->set_flag(Material::FLAG_UNSHADED, true); - listener_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true); - listener_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER); - listener_icon->set_fixed_flag(FixedSpatialMaterial::FLAG_USE_ALPHA, true); - listener_icon->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9)); - listener_icon->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons")); + listener_icon->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); + listener_icon->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + listener_icon->set_depth_draw_mode(FixedSpatialMaterial::DEPTH_DRAW_DISABLED); + listener_icon->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); + listener_icon->set_albedo( Color(1, 1, 1, 0.9)); + listener_icon->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons")); { @@ -3200,4 +3205,4 @@ SpatialEditorGizmos::SpatialEditorGizmos() { } -#endif + diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h index 64c6a6e82..2c0033cdc 100644 --- a/tools/editor/spatial_editor_gizmos.h +++ b/tools/editor/spatial_editor_gizmos.h @@ -52,7 +52,7 @@ class Camera; -#if 0 + class EditorSpatialGizmo : public SpatialEditorGizmo { OBJ_TYPE(EditorSpatialGizmo,SpatialGizmo); @@ -505,5 +505,4 @@ public: SpatialEditorGizmos(); }; -#endif #endif // SPATIAL_EDITOR_GIZMOS_H -- cgit v1.2.3-70-g09d2 From 6b2a27bbe5fa112365fc88b9b4678a61293bcb53 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 31 Oct 2016 08:47:46 -0300 Subject: shadow atlas allocation (work in progress) --- drivers/gles3/rasterizer_scene_gles3.cpp | 433 ++++++++++++++++++++++++++++++- drivers/gles3/rasterizer_scene_gles3.h | 62 ++++- drivers/gles3/shadow_atlas_gles3.cpp | 2 + drivers/gles3/shadow_atlas_gles3.h | 8 + servers/visual/rasterizer.h | 4 + servers/visual/visual_server_scene.cpp | 4 + 6 files changed, 501 insertions(+), 12 deletions(-) create mode 100644 drivers/gles3/shadow_atlas_gles3.cpp create mode 100644 drivers/gles3/shadow_atlas_gles3.h (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index f7baf1a30..93dc01d47 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1,6 +1,6 @@ #include "rasterizer_scene_gles3.h" #include "globals.h" - +#include "os/os.h" @@ -55,7 +55,351 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix& p_mtx, float* p_arra } } +/* SHADOW ATLAS API */ + +RID RasterizerSceneGLES3::shadow_atlas_create() { + + ShadowAtlas *shadow_atlas = memnew( ShadowAtlas ); + shadow_atlas->fbo=0; + shadow_atlas->depth=0; + shadow_atlas->size=0; + shadow_atlas->smallest_subdiv=0; + + for(int i=0;i<4;i++) { + shadow_atlas->size_order[i]=i; + } + + + return shadow_atlas_owner.make_rid(shadow_atlas); +} + +void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_COND(p_size<0); + if (p_size==shadow_atlas->size) + return; + + if (shadow_atlas->fbo) { + glDeleteTextures(1,&shadow_atlas->depth); + glDeleteFramebuffers(1,&shadow_atlas->fbo); + + shadow_atlas->depth=0; + shadow_atlas->fbo=0; + } + for(int i=0;i<4;i++) { + //clear subdivisions + shadow_atlas->quadrants[i].shadows.resize(0); + shadow_atlas->quadrants[i].shadows.resize( 1<quadrants[i].subdivision ); + } + + //erase shadow atlas reference from lights + for (Map::Element *E=shadow_atlas->shadow_owners.front();E;E=E->next()) { + LightInstance *li = light_instance_owner.getornull(E->key()); + ERR_CONTINUE(!li); + li->shadow_atlases.erase(p_atlas); + } + + //clear owners + shadow_atlas->shadow_owners.clear(); + + shadow_atlas->size=nearest_power_of_2(p_size); + + if (shadow_atlas->size) { + glGenFramebuffers(1, &shadow_atlas->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo); + + // Create a texture for storing the depth + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &shadow_atlas->depth); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadow_atlas->size, shadow_atlas->size, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + + //interpola nearest (though nvidia can improve this) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // Remove artifact on the edges of the shadowmap + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // We'll use a depth texture to store the depths in the shadow map + // Attach the depth texture to FBO depth attachment point + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, shadow_atlas->depth, 0); + } +} + + +void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision){ + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_INDEX(p_quadrant,4); + ERR_FAIL_INDEX(p_subdivision,16384); + + + uint32_t subdiv = nearest_power_of_2(p_subdivision); + if (subdiv&0xaaaaaaaa) { //sqrt(subdiv) must be integer + subdiv<<=1; + } + + subdiv=int(Math::sqrt(subdiv)); + + //obtain the number that will be x*x + + if (shadow_atlas->quadrants[p_quadrant].subdivision==subdiv) + return; + + //erase all data from quadrant + for(int i=0;iquadrants[p_quadrant].shadows.size();i++) { + + if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) { + shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); + LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); + ERR_CONTINUE(!li); + li->shadow_atlases.erase(p_atlas); + } + } + + shadow_atlas->quadrants[p_quadrant].shadows.resize(0); + shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv*subdiv); + shadow_atlas->quadrants[p_quadrant].subdivision=subdiv; + + //cache the smallest subdiv (for faster allocation in light update) + + shadow_atlas->smallest_subdiv=1<<30; + + for(int i=0;i<4;i++) { + if (shadow_atlas->quadrants[i].subdivision) { + shadow_atlas->smallest_subdiv=MIN(shadow_atlas->smallest_subdiv,shadow_atlas->quadrants[i].subdivision); + } + } + + if (shadow_atlas->smallest_subdiv==1<<30) { + shadow_atlas->smallest_subdiv=0; + } + + //resort the size orders, simple bublesort for 4 elements.. + + int swaps=0; + do { + swaps=0; + + for(int i=0;i<3;i++) { + if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision > shadow_atlas->quadrants[shadow_atlas->size_order[i+1]].subdivision) { + SWAP(shadow_atlas->size_order[i],shadow_atlas->size_order[i+1]); + swaps++; + } + } + } while(swaps>0); + + + + + +} + +bool RasterizerSceneGLES3::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,int *p_in_quadrants,int p_quadrant_count,int p_current_subdiv,uint64_t p_tick,int &r_quadrant,int &r_shadow) { + + + for(int i=p_quadrant_count-1;i>=0;i--) { + int qidx = p_in_quadrants[i]; + + if (shadow_atlas->quadrants[qidx].subdivision==p_current_subdiv) { + return false; + } + + //look for an empty space + int sc = shadow_atlas->quadrants[qidx].shadows.size(); + ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr(); + + int found_free_idx=-1; //found a free one + int found_used_idx=-1; //found existing one, must steal it + uint64_t min_pass; // pass of the existing one, try to use the least recently used one (LRU fashion) + + for(int j=0;jlast_scene_pass!=scene_pass) { + + //was just allocated, don't kill it so soon, wait a bit.. + if (p_tick-sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) + continue; + + if (found_used_idx==-1 || sli->last_scene_passlast_scene_pass; + } + } + } + + if (found_free_idx==-1 && found_used_idx==-1) + continue; //nothing found + + if (found_free_idx==-1 && found_used_idx!=-1) { + found_free_idx=found_used_idx; + } + + r_quadrant=qidx; + r_shadow=found_free_idx; + + return true; + } + + return false; + +} + + +uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version){ + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ERR_FAIL_COND_V(!shadow_atlas,ShadowAtlas::SHADOW_INVALID); + + LightInstance *li = light_instance_owner.getornull(p_light_intance); + ERR_FAIL_COND_V(!li,ShadowAtlas::SHADOW_INVALID); + + if (shadow_atlas->size==0 || shadow_atlas->smallest_subdiv==0) { + return ShadowAtlas::SHADOW_INVALID; + } + + uint32_t quad_size = shadow_atlas->size>>1; + int desired_fit = MAX(quad_size/shadow_atlas->smallest_subdiv,nearest_power_of_2(quad_size*p_coverage)); + + int valid_quadrants[4]; + int valid_quadrant_count=0; + int best_size=-1; //best size found + int best_subdiv=-1; //subdiv for the best size + + //find the quadrants this fits into, and the best possible size it can fit into + for(int i=0;i<4;i++) { + int q = shadow_atlas->size_order[i]; + int sd = shadow_atlas->quadrants[q].subdivision; + if (sd==0) + continue; //unused + + int max_fit = quad_size / sd; + + if (best_size!=-1 && max_fit>best_size) + break; //too large + + valid_quadrants[valid_quadrant_count++]=q; + best_subdiv=sd; + + if (max_fit>=desired_fit) { + best_size=max_fit; + } + } + + + ERR_FAIL_COND_V(valid_quadrant_count==0,ShadowAtlas::SHADOW_INVALID); + + uint64_t tick = OS::get_singleton()->get_ticks_msec(); + + + //see if it already exists + + if (shadow_atlas->shadow_owners.has(p_light_intance)) { + //it does! + uint32_t key = shadow_atlas->shadow_owners[p_light_intance]; + uint32_t q = (key>>ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t s = key&ShadowAtlas::SHADOW_INDEX_MASK; + + bool should_realloc=shadow_atlas->quadrants[q].subdivision!=best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick-tick > shadow_atlas_realloc_tolerance_msec); + bool should_redraw=shadow_atlas->quadrants[q].shadows[s].version!=p_light_version; + + if (!should_realloc) { + //already existing, see if it should redraw or it's just OK + if (should_redraw) { + key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; + } + + return key; + } + + int new_quadrant,new_shadow; + + //find a better place + if (_shadow_atlas_find_shadow(shadow_atlas,valid_quadrants,valid_quadrant_count,shadow_atlas->quadrants[q].subdivision,tick,new_quadrant,new_shadow)) { + //found a better place! + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows[new_shadow]; + if (sh->owner.is_valid()) { + //is taken, but is invalid, erasing it + shadow_atlas->shadow_owners.erase(sh->owner); + LightInstance *sli = light_instance_owner.get(sh->owner); + sli->shadow_atlases.erase(p_atlas); + } + + sh->owner=p_light_intance; + sh->alloc_tick=tick; + sh->version=p_light_version; + + //make new key + key=new_quadrant<shadow_owners[p_light_intance]=key; + //make it dirty, as it should redraw anyway + key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; + + return key; + } + + //no better place for this shadow found, keep current + + //already existing, see if it should redraw or it's just OK + if (should_redraw) { + key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; + } + + return key; + } + + int new_quadrant,new_shadow; + + //find a better place + if (_shadow_atlas_find_shadow(shadow_atlas,valid_quadrants,valid_quadrant_count,-1,tick,new_quadrant,new_shadow)) { + //found a better place! + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows[new_shadow]; + if (sh->owner.is_valid()) { + //is taken, but is invalid, erasing it + shadow_atlas->shadow_owners.erase(sh->owner); + LightInstance *sli = light_instance_owner.get(sh->owner); + sli->shadow_atlases.erase(p_atlas); + } + + sh->owner=p_light_intance; + sh->alloc_tick=tick; + sh->version=p_light_version; + + //make new key + uint32_t key=new_quadrant<shadow_owners[p_light_intance]=key; + //make it dirty, as it should redraw anyway + key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; + + return key; + } + + //no place to allocate this light, apologies + + return ShadowAtlas::SHADOW_INVALID; + + + + +} /* ENVIRONMENT API */ @@ -162,9 +506,12 @@ void RasterizerSceneGLES3::environment_set_adjustment(RID p_env,bool p_enable,fl RID RasterizerSceneGLES3::light_instance_create(RID p_light) { - print_line("hello light"); + LightInstance *light_instance = memnew( LightInstance ); + light_instance->last_pass=0; + light_instance->last_scene_pass=0; + light_instance->light=p_light; light_instance->light_ptr=storage->light_owner.getornull(p_light); @@ -187,6 +534,18 @@ void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,con light_instance->transform=p_transform; } +void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { + + LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->last_scene_pass=scene_pass; +} + + +//////////////////////////// +//////////////////////////// +//////////////////////////// bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass) { @@ -851,13 +1210,13 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g if (shadow || m->shader->spatial.unshaded /*|| current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) { - e->sort_key=RenderList::SORT_KEY_LIGHT_INDEX_UNSHADED; + e->sort_key|=RenderList::SORT_KEY_LIGHT_INDEX_UNSHADED; e->sort_key|=uint64_t(0xF)<sort_key|=uint64_t(0xFFFF)<additive_ptr=&e->additive; + ec->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; ec->sort_key|=uint64_t(directional_light_instances[i]->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; - lighted=true; + lit=true; } @@ -922,14 +1282,16 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g ec->additive_ptr=&e->additive; + ec->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; ec->sort_key|=uint64_t(li->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; ec->sort_key|=uint64_t(li->light_ptr->type) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; - lighted=true; + lit=true; } - if (!lighted) { + if (!lit) { + e->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; e->sort_key|=uint64_t(0xE)<sort_key|=uint64_t(0xFFFF)< lpercent; + for(int i=0;i=RenderList::MAX_LIGHTS ); @@ -1140,6 +1504,7 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu + #if 0 if (li->light_ptr->shadow_enabled) { CameraMatrix bias; @@ -1181,6 +1546,26 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu li->light_ubo_data.light_params[2]=0; li->light_ubo_data.light_params[3]=0; +#if 0 + + Transform ai = p_camera_inverse_transform.affine_inverse(); + float zn = p_camera_projection.get_z_near(); + Plane p (ai.origin + ai.basis.get_axis(2) * -zn, -ai.basis.get_axis(2) ); + + Vector3 point1 = li->transform.origin; + Vector3 point2 = li->transform.origin+p_camera_inverse_transform.affine_inverse().basis.get_axis(1).normalized()*li->light_ptr->param[VS::LIGHT_PARAM_RANGE]; + + p.intersects_segment(ai.origin,point1,&point1); + p.intersects_segment(ai.origin,point2,&point2); + float r = point1.distance_to(point2); + + float vp_w,vp_h; + p_camera_projection.get_viewport_size(vp_w,vp_h); + + lpercent.push_back(r*2/((vp_h+vp_w)*0.5)); + +#endif + #if 0 if (li->light_ptr->shadow_enabled) { li->shadow_projection[0] = Transform(camera_transform_inverse * li->transform).inverse(); @@ -1245,8 +1630,8 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu glBindBuffer(GL_UNIFORM_BUFFER, 0); light_instances[i]=li; + light_instance_count++; } - } void RasterizerSceneGLES3::_copy_screen() { @@ -1305,7 +1690,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM _setup_environment(env,p_cam_projection,p_cam_transform); - _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse()); + _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection); render_list.clear(); @@ -1609,16 +1994,40 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM #endif } +void RasterizerSceneGLES3::set_scene_pass(uint64_t p_pass) { + scene_pass=p_pass; +} + bool RasterizerSceneGLES3::free(RID p_rid) { if (light_instance_owner.owns(p_rid)) { - print_line("bye light"); + LightInstance *light_instance = light_instance_owner.getptr(p_rid); + + //remove from shadow atlases.. + for(Set::Element *E=light_instance->shadow_atlases.front();E;E=E->next()) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(E->get()); + ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); + uint32_t key = shadow_atlas->shadow_owners[p_rid]; + uint32_t q = (key>>ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t s = key&ShadowAtlas::SHADOW_INDEX_MASK; + + shadow_atlas->quadrants[q].shadows[s].owner=RID(); + shadow_atlas->shadow_owners.erase(p_rid); + } + + glDeleteBuffers(1,&light_instance->light_ubo); light_instance_owner.free(p_rid); memdelete(light_instance); + } else if (shadow_atlas_owner.owns(p_rid)) { + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(p_rid); + shadow_atlas_set_size(p_rid,0); + shadow_atlas_owner.free(p_rid); + memdelete(shadow_atlas); } else { return false; @@ -1800,6 +2209,8 @@ void RasterizerSceneGLES3::initialize() { } render_list.init(); _generate_brdf(); + + shadow_atlas_realloc_tolerance_msec=500; } void RasterizerSceneGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 5457b5cde..9df6315e4 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -7,7 +7,11 @@ class RasterizerSceneGLES3 : public RasterizerScene { public: + uint64_t shadow_atlas_realloc_tolerance_msec; + + uint64_t render_pass; + uint64_t scene_pass; uint32_t current_material_index; uint32_t current_geometry_index; @@ -62,8 +66,58 @@ public: } state; + /* SHADOW ATLAS API */ + + struct ShadowAtlas : public RID_Data { + + enum { + SHADOW_INDEX_DIRTY_BIT=(1<<31), + QUADRANT_SHIFT=27, + SHADOW_INDEX_MASK=(1< shadows; + Quadrant() { + subdivision=0; //not in use + } + + } quadrants[4]; + + int size_order[4]; + uint32_t smallest_subdiv; + + int size; + + GLuint fbo; + GLuint depth; + + Map shadow_owners; + }; + + RID_Owner shadow_atlas_owner; + + RID shadow_atlas_create(); + void shadow_atlas_set_size(RID p_atlas,int p_size); + void shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision); + bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); + uint32_t shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version); /* ENVIRONMENT API */ @@ -159,6 +213,7 @@ public: GLuint light_ubo; uint64_t shadow_pass; + uint64_t last_scene_pass; uint64_t last_pass; uint16_t light_index; @@ -166,6 +221,7 @@ public: CameraMatrix shadow_projection[4]; + Set shadow_atlases; //shadow atlases where this light is registered LightInstance() { } @@ -175,6 +231,7 @@ public: virtual RID light_instance_create(RID p_light); virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform); + virtual void light_instance_mark_visible(RID p_light_instance); /* RENDER LIST */ @@ -190,6 +247,7 @@ public: SORT_KEY_LIGHT_TYPE_SHIFT=54, //type is most important SORT_KEY_LIGHT_INDEX_SHIFT=38, //type is most important SORT_KEY_LIGHT_INDEX_UNSHADED=uint64_t(0xF) << SORT_KEY_LIGHT_TYPE_SHIFT, //type is most important + SORT_KEY_LIGHT_MASK=(uint64_t(0xFFFFF) << SORT_KEY_LIGHT_INDEX_SHIFT), //type is most important SORT_KEY_MATERIAL_INDEX_SHIFT=22, SORT_KEY_GEOMETRY_INDEX_SHIFT=6, SORT_KEY_GEOMETRY_TYPE_SHIFT=2, @@ -327,7 +385,7 @@ public: void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); void _setup_environment(Environment *env,CameraMatrix& p_cam_projection, const Transform& p_cam_transform); - void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform); + void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform,const CameraMatrix& p_camera_projection); void _copy_screen(); void _copy_to_front_buffer(Environment *env); @@ -337,6 +395,8 @@ public: void _generate_brdf(); + virtual void set_scene_pass(uint64_t p_pass); + void initialize(); void finalize(); RasterizerSceneGLES3(); diff --git a/drivers/gles3/shadow_atlas_gles3.cpp b/drivers/gles3/shadow_atlas_gles3.cpp new file mode 100644 index 000000000..38dee8bce --- /dev/null +++ b/drivers/gles3/shadow_atlas_gles3.cpp @@ -0,0 +1,2 @@ +#include "shadow_atlas_gles3.h" + diff --git a/drivers/gles3/shadow_atlas_gles3.h b/drivers/gles3/shadow_atlas_gles3.h new file mode 100644 index 000000000..46eaf581c --- /dev/null +++ b/drivers/gles3/shadow_atlas_gles3.h @@ -0,0 +1,8 @@ +#ifndef SHADOW_ATLAS_GLES3_H +#define SHADOW_ATLAS_GLES3_H + +#include "rasterizer_storage_gles3.h" + + + +#endif // SHADOW_ATLAS_GLES3_H diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index b61a2d0a4..feaac38ac 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -109,9 +109,13 @@ public: virtual RID light_instance_create(RID p_light)=0; virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform)=0; + virtual void light_instance_mark_visible(RID p_light_instance)=0; + virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment)=0; + virtual void set_scene_pass(uint64_t p_pass)=0; + virtual bool free(RID p_rid)=0; virtual ~RasterizerScene() {} diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index d958ea4bd..e7900bdcc 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1107,6 +1107,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp render_pass++; uint32_t camera_layer_mask=camera->visible_layers; + VSG::scene_render->set_scene_pass(render_pass); + /* STEP 1 - SETUP CAMERA */ CameraMatrix camera_matrix; @@ -1266,6 +1268,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp //do not add this light if no geometry is affected by it.. light_cull_result[light_cull_count]=ins; light_instance_cull_result[light_cull_count]=light->instance; + VSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later light_cull_count++; } @@ -1488,6 +1491,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp #endif + VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count,directional_light_ptr,directional_light_count,environment); } -- cgit v1.2.3-70-g09d2 From cacf9ebb7fd8df8845daca9da2fe55456cc179aa Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 9 Nov 2016 23:55:06 -0300 Subject: all light types and shadows are working, pending a lot of clean-up --- core/math/camera_matrix.cpp | 22 + core/math/camera_matrix.h | 2 + core/math/math_funcs.h | 2 +- drivers/gles3/rasterizer_canvas_gles3.cpp | 2 - drivers/gles3/rasterizer_scene_gles3.cpp | 1043 +++++++++++++++++---- drivers/gles3/rasterizer_scene_gles3.h | 74 +- drivers/gles3/rasterizer_storage_gles3.cpp | 324 ++++++- drivers/gles3/rasterizer_storage_gles3.h | 101 +- drivers/gles3/shader_compiler_gles3.cpp | 15 +- drivers/gles3/shader_compiler_gles3.h | 7 + drivers/gles3/shaders/SCsub | 1 + drivers/gles3/shaders/cube_to_dp.glsl | 79 ++ drivers/gles3/shaders/scene.glsl | 341 +++++-- main/main.cpp | 23 +- scene/3d/light.cpp | 91 +- scene/3d/light.h | 71 +- scene/3d/navigation_mesh.cpp | 2 +- scene/main/scene_main_loop.cpp | 2 +- scene/main/viewport.cpp | 61 ++ scene/main/viewport.h | 24 +- scene/resources/material.cpp | 2 +- scene/resources/mesh.cpp | 102 +- scene/resources/mesh.h | 4 +- scene/resources/mesh_data_tool.cpp | 2 +- scene/resources/shape.cpp | 2 +- scene/resources/surface_tool.cpp | 2 +- servers/visual/rasterizer.h | 37 +- servers/visual/shader_types.cpp | 2 +- servers/visual/visual_server_raster.h | 10 +- servers/visual/visual_server_scene.cpp | 638 ++++++++++++- servers/visual/visual_server_scene.h | 19 +- servers/visual/visual_server_viewport.cpp | 27 +- servers/visual/visual_server_viewport.h | 7 + servers/visual_server.cpp | 450 ++++++++- servers/visual_server.h | 28 +- tools/editor/io_plugins/editor_import_collada.cpp | 2 +- tools/editor/plugins/spatial_editor_plugin.cpp | 14 + tools/editor/spatial_editor_gizmos.cpp | 12 +- 38 files changed, 3235 insertions(+), 412 deletions(-) create mode 100644 drivers/gles3/shaders/cube_to_dp.glsl (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index f7dd8839b..3e3cd1af4 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -495,6 +495,28 @@ void CameraMatrix::set_light_bias() { } +void CameraMatrix::set_light_atlas_rect(const Rect2& p_rect) { + + float *m=&matrix[0][0]; + + m[0]=p_rect.size.width, + m[1]=0.0, + m[2]=0.0, + m[3]=0.0, + m[4]=0.0, + m[5]=p_rect.size.height, + m[6]=0.0, + m[7]=0.0, + m[8]=0.0, + m[9]=0.0, + m[10]=1.0, + m[11]=0.0, + m[12]=p_rect.pos.x, + m[13]=p_rect.pos.y, + m[14]=0.0, + m[15]=1.0; +} + CameraMatrix::operator String() const { String str; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index d192b1fef..bf8cf3592 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -30,6 +30,7 @@ #define CAMERA_MATRIX_H #include "transform.h" +#include "math_2d.h" /** @author Juan Linietsky */ @@ -53,6 +54,7 @@ struct CameraMatrix { void set_identity(); void set_zero(); void set_light_bias(); + void set_light_atlas_rect(const Rect2& p_rect); void set_perspective(float p_fovy_degrees, float p_aspect, float p_z_near, float p_z_far,bool p_flip_fov=false); void set_orthogonal(float p_left, float p_right, float p_bottom, float p_top, float p_znear, float p_zfar); void set_orthogonal(float p_size, float p_aspect, float p_znear, float p_zfar,bool p_flip_fov=false); diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index c8ced0b30..9d7e881c6 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -208,7 +208,7 @@ public: } } - static _FORCE_INLINE_ float halfptr_to_float(uint16_t *h) { + static _FORCE_INLINE_ float halfptr_to_float(const uint16_t *h) { union { uint32_t u32; diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c10c5fee6..c455d4bd1 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -824,8 +824,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const bool prev_distance_field=false; - - while(p_item_list) { Item *ci=p_item_list; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 93dc01d47..287801b59 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1,8 +1,18 @@ #include "rasterizer_scene_gles3.h" #include "globals.h" #include "os/os.h" +#include "rasterizer_canvas_gles3.h" +static const GLenum _cube_side_enum[6]={ + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + +}; static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) { @@ -78,6 +88,9 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(p_size<0); + + p_size = nearest_power_of_2(p_size); + if (p_size==shadow_atlas->size) return; @@ -104,7 +117,7 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ //clear owners shadow_atlas->shadow_owners.clear(); - shadow_atlas->size=nearest_power_of_2(p_size); + shadow_atlas->size=p_size; if (shadow_atlas->size) { glGenFramebuffers(1, &shadow_atlas->fbo); @@ -188,7 +201,7 @@ void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas,int swaps=0; for(int i=0;i<3;i++) { - if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision > shadow_atlas->quadrants[shadow_atlas->size_order[i+1]].subdivision) { + if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i+1]].subdivision) { SWAP(shadow_atlas->size_order[i],shadow_atlas->size_order[i+1]); swaps++; } @@ -260,20 +273,22 @@ bool RasterizerSceneGLES3::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,i } -uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version){ +bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version){ + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); - ERR_FAIL_COND_V(!shadow_atlas,ShadowAtlas::SHADOW_INVALID); + ERR_FAIL_COND_V(!shadow_atlas,false); LightInstance *li = light_instance_owner.getornull(p_light_intance); - ERR_FAIL_COND_V(!li,ShadowAtlas::SHADOW_INVALID); + ERR_FAIL_COND_V(!li,false); if (shadow_atlas->size==0 || shadow_atlas->smallest_subdiv==0) { - return ShadowAtlas::SHADOW_INVALID; + return false; } uint32_t quad_size = shadow_atlas->size>>1; - int desired_fit = MAX(quad_size/shadow_atlas->smallest_subdiv,nearest_power_of_2(quad_size*p_coverage)); + int desired_fit = MIN(quad_size/shadow_atlas->smallest_subdiv,nearest_power_of_2(quad_size*p_coverage)); + int valid_quadrants[4]; int valid_quadrant_count=0; @@ -300,8 +315,7 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh } } - - ERR_FAIL_COND_V(valid_quadrant_count==0,ShadowAtlas::SHADOW_INVALID); + ERR_FAIL_COND_V(valid_quadrant_count==0,false); uint64_t tick = OS::get_singleton()->get_ticks_msec(); @@ -317,13 +331,12 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh bool should_realloc=shadow_atlas->quadrants[q].subdivision!=best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick-tick > shadow_atlas_realloc_tolerance_msec); bool should_redraw=shadow_atlas->quadrants[q].shadows[s].version!=p_light_version; + + if (!should_realloc) { + shadow_atlas->quadrants[q].shadows[s].version=p_light_version; //already existing, see if it should redraw or it's just OK - if (should_redraw) { - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - } - - return key; + return should_redraw; } int new_quadrant,new_shadow; @@ -339,6 +352,10 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh sli->shadow_atlases.erase(p_atlas); } + //erase previous + shadow_atlas->quadrants[q].shadows[s].version=0; + shadow_atlas->quadrants[q].shadows[s].owner=RID(); + sh->owner=p_light_intance; sh->alloc_tick=tick; sh->version=p_light_version; @@ -349,19 +366,16 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh //update it in map shadow_atlas->shadow_owners[p_light_intance]=key; //make it dirty, as it should redraw anyway - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - - return key; + return true; } //no better place for this shadow found, keep current //already existing, see if it should redraw or it's just OK - if (should_redraw) { - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - } - return key; + shadow_atlas->quadrants[q].shadows[s].version=p_light_version; + + return should_redraw; } int new_quadrant,new_shadow; @@ -387,20 +401,49 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh //update it in map shadow_atlas->shadow_owners[p_light_intance]=key; //make it dirty, as it should redraw anyway - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - return key; + return true; } //no place to allocate this light, apologies - return ShadowAtlas::SHADOW_INVALID; + return false; } +void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) { + + directional_shadow.light_count=p_count; + directional_shadow.current_light=0; +} + +int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) { + + ERR_FAIL_COND_V(directional_shadow.light_count==0,0); + + int shadow_size; + + if (directional_shadow.light_count==1) { + shadow_size = directional_shadow.size; + } else { + shadow_size = directional_shadow.size/2; //more than 4 not supported anyway + } + + LightInstance *light_instance = light_instance_owner.getornull(p_light_intance); + ERR_FAIL_COND_V(!light_instance,0); + + switch(light_instance->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: break; //none + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: shadow_size/=2; break; + } + + return shadow_size; + +} /* ENVIRONMENT API */ @@ -511,6 +554,7 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { light_instance->last_pass=0; light_instance->last_scene_pass=0; + light_instance->last_scene_shadow_pass=0; light_instance->light=p_light; light_instance->light_ptr=storage->light_owner.getornull(p_light); @@ -520,10 +564,11 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInstance::LightDataUBO), NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); - ERR_FAIL_COND_V(!light_instance->light_ptr,RID()); - return light_instance_owner.make_rid(light_instance); + light_instance->self=light_instance_owner.make_rid(light_instance); + + return light_instance->self; } void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,const Transform& p_transform){ @@ -534,6 +579,25 @@ void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,con light_instance->transform=p_transform; } +void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass) { + + LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND(!light_instance); + + if (light_instance->light_ptr->type!=VS::LIGHT_DIRECTIONAL) { + p_pass=0; + } + + ERR_FAIL_INDEX(p_pass,4); + + light_instance->shadow_transform[p_pass].camera=p_projection; + light_instance->shadow_transform[p_pass].transform=p_transform; + light_instance->shadow_transform[p_pass].far=p_far; + light_instance->shadow_transform[p_pass].split=p_split; + +} + + void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); @@ -542,7 +606,6 @@ void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { light_instance->last_scene_pass=scene_pass; } - //////////////////////////// //////////////////////////// //////////////////////////// @@ -757,9 +820,10 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { void RasterizerSceneGLES3::_setup_light(LightInstance *p_light) { - glBindBufferBase(GL_UNIFORM_BUFFER,3,p_light->light_ubo); //bind light uniform } + + void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection) { if (p_instance->billboard || p_instance->billboard_y || p_instance->depth_scale) { @@ -815,7 +879,22 @@ void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance,const Trans } } -void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass) { +void RasterizerSceneGLES3::_set_cull(bool p_front,bool p_reverse_cull) { + + bool front = p_front; + if (p_reverse_cull) + front=!front; + + if (front!=state.cull_front) { + + glCullFace(front?GL_FRONT:GL_BACK); + state.cull_front=front; + } +} + + + +void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow) { if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { //p_reverse_cull=!p_reverse_cull; @@ -824,25 +903,30 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glFrontFace(GL_CW); } - bool shadow=false; - glBindBufferBase(GL_UNIFORM_BUFFER,0,state.scene_ubo); //bind globals ubo - glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info - glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1); - glBindTexture(GL_TEXTURE_2D,state.brdf_texture); + if (!p_shadow) { + glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1); + glBindTexture(GL_TEXTURE_2D,state.brdf_texture); - if (p_base_env) { - glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); - glBindTexture(p_base_env->target,p_base_env->tex_id); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true); + if (p_base_env) { + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); + glBindTexture(p_base_env->target,p_base_env->tex_id); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true); + } else { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + + } } else { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); } + state.cull_front=false; + glCullFace(GL_BACK); state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false); @@ -875,28 +959,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e bool additive=false; - if (!shadow) { -#if 0 - if (texscreen_used && !texscreen_copied && material->shader_cache && material->shader_cache->valid && material->shader_cache->has_texscreen) { - texscreen_copied=true; - _copy_to_texscreen(); - - //force reset state - prev_material=NULL; - prev_light=0x777E; - prev_geometry_cmp=NULL; - prev_light_type=0xEF; - prev_skeleton =NULL; - prev_sort_flags=0xFF; - prev_morph_values=NULL; - prev_receive_shadows_state=-1; - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); + if (!p_shadow) { - } -#endif if (light_type!=prev_light_type /* || receive_shadows_state!=prev_receive_shadows_state*/) { if (material->shader->spatial.unshaded/* || current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) { @@ -905,27 +969,38 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + //state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); } else { state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,light_type!=0xF); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,light_type==VS::LIGHT_DIRECTIONAL); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,light_type==VS::LIGHT_OMNI); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,light_type==VS::LIGHT_SPOT); - /* - if (receive_shadows_state==1) { - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,(light_type&0x8)); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,(light_type&0x10)); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,(light_type&0x20)); - } - else { - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,(light_type&3)==VS::LIGHT_DIRECTIONAL); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,(light_type&0xF)==VS::LIGHT_OMNI); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,(light_type&0xF)==VS::LIGHT_SPOT); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + + if ((light_type&3)==VS::LIGHT_DIRECTIONAL) { + + if (light_instances[light_index]->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,true); + + switch(light_instances[light_index]->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: break; //none + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,true); break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,true); break; + } + } } - state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); - */ + + } rebind=true; @@ -1007,14 +1082,16 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e current_blend_mode=desired_blend_mode; } - } - if (light_index!=prev_light_index) { - if (light_index!=0xFFFF) { //not unshaded - _setup_light(light_instances[light_index]); + if (light_index!=prev_light_index) { + if (light_index!=0xFFFF) { //not unshaded + _setup_light(light_instances[light_index]); + } } + } + if (material!=prev_material || rebind) { rebind = _setup_material(material,p_alpha_pass); @@ -1027,20 +1104,17 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e _setup_geometry(e); } - if (rebind || prev_additive!=additive) { + if (!p_shadow && (rebind || prev_additive!=additive)) { state.scene_shader.set_uniform(SceneShaderGLES3::NO_AMBIENT_LIGHT, additive); } -// _set_cull(e->mirror,p_reverse_cull); + _set_cull(e->sort_key&RenderList::SORT_KEY_MIRROR_FLAG,p_reverse_cull); state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror?-1.0:1.0); _setup_transform(e->instance,p_view_transform,p_projection); - -// _render(e->geometry, material, skeleton,e->owner,e->instance->transform); - _render_geometry(e); prev_material=material; @@ -1052,15 +1126,26 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } - //print_line("shaderchanges: "+itos(p_alpha_pass)+": "+itos(_rinfo.shader_change_count)); glFrontFace(GL_CW); glBindVertexArray(0); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); + } -void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material) { + +void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow) { RasterizerStorageGLES3::Material *m=NULL; RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override :(p_material>=0?p_instance->materials[p_material]:p_geometry->material); @@ -1096,57 +1181,29 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g bool has_alpha = has_base_alpha || has_blend_alpha; bool shadow = false; -#if 0 - if (shadow) { + bool mirror = p_instance->mirror; - if (has_blend_alpha || (has_base_alpha && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA)) + if (m->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) { + mirror=!mirror; + } + + if (p_shadow) { + + if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) return; //bye - if (!m->shader_cache || (!m->shader_cache->writes_vertex && !m->shader_cache->uses_discard && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA)) { + if (!m->shader->spatial.uses_vertex && !m->shader->spatial.uses_discard && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { //shader does not use discard and does not write a vertex position, use generic material if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) - m = shadow_mat_double_sided_ptr; + m = storage->material_owner.getptr(default_material_twosided); else - m = shadow_mat_ptr; - if (m->last_pass!=frame) { - - if (m->shader.is_valid()) { - - m->shader_cache=shader_owner.get(m->shader); - if (m->shader_cache) { - - - if (!m->shader_cache->valid) - m->shader_cache=NULL; - } else { - m->shader=RID(); - } - - } else { - m->shader_cache=NULL; - } - - m->last_pass=frame; - } + m = storage->material_owner.getptr(default_material); } - render_list = &opaque_render_list; - /* notyet - if (!m->shader_cache || m->shader_cache->can_zpass) - render_list = &alpha_render_list; - } else { - render_list = &opaque_render_list; - }*/ - - } else { - if (has_alpha) { - render_list = &alpha_render_list; - } else { - render_list = &opaque_render_list; + has_alpha=false; - } } -#endif + RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); @@ -1161,50 +1218,49 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g e->additive_ptr=&e->additive; e->sort_key=0; - if (e->geometry->last_pass!=render_pass) { e->geometry->last_pass=render_pass; e->geometry->index=current_geometry_index++; } + e->sort_key|=uint64_t(e->geometry->index)<sort_key|=uint64_t(e->instance->base_type)<material->last_pass!=render_pass) { - e->material->last_pass=render_pass; - e->material->index=current_material_index++; - } + if (!p_shadow) { - e->sort_key|=uint64_t(e->material->index)<sort_key|=uint64_t(e->instance->depth_layer)<geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) - // e->sort_flags|=RenderList::SORT_FLAG_INSTANCING; + if (e->material->last_pass!=render_pass) { + e->material->last_pass=render_pass; + e->material->index=current_material_index++; + } - bool mirror = e->instance->mirror; + e->sort_key|=uint64_t(e->material->index)<sort_key|=uint64_t(e->instance->depth_layer)<shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) { - mirror=!mirror; - } + if (!has_blend_alpha && has_alpha && m->shader->spatial.depth_draw_mode==RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - if (mirror) { - e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG; - } + //if nothing exists, add this element as opaque too + RenderList::Element *oe = render_list.add_element(); - //e->light_type=0xFF; // no lights! + if (!oe) + return; - if (!shadow && !has_blend_alpha && has_alpha && m->shader->spatial.depth_draw_mode==RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + copymem(oe,e,sizeof(RenderList::Element)); + oe->additive_ptr=&oe->additive; + } + } - //if nothing exists, add this element as opaque too - RenderList::Element *oe = render_list.add_element(); + //if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) + // e->sort_flags|=RenderList::SORT_FLAG_INSTANCING; - if (!oe) - return; - copymem(oe,e,sizeof(RenderList::Element)); - oe->additive_ptr=&oe->additive; + if (mirror) { + e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG; } + //e->light_type=0xFF; // no lights! + @@ -1246,7 +1302,12 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g ec->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; ec->sort_key|=uint64_t(directional_light_instances[i]->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; - ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; + ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; //this is zero byt whathever + + if (directional_light_instances[i]->light_ptr->shadow) { + //add proper flags for directional shadow mode + ec->sort_key|=uint64_t(directional_light_instances[i]->light_ptr->directional_shadow_mode+1) << (RenderList::SORT_KEY_LIGHT_TYPE_SHIFT+2); + } lit=true; } @@ -1302,7 +1363,7 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g } -void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { +void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox); @@ -1382,7 +1443,7 @@ void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection, } -void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_cam_projection,const Transform& p_cam_transform) { +void RasterizerSceneGLES3::_setup_environment(Environment *env,const CameraMatrix& p_cam_projection,const Transform& p_cam_transform) { //store camera into ubo @@ -1444,6 +1505,20 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_c } + { + //directional shadow + + state.ubo_data.shadow_directional_pixel_size[0]=1.0/directional_shadow.size; + state.ubo_data.shadow_directional_pixel_size[1]=1.0/directional_shadow.size; + + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-4); + glBindTexture(GL_TEXTURE_2D,directional_shadow.depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + } + + + glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(State::SceneDataUBO), &state.ubo_data); glBindBuffer(GL_UNIFORM_BUFFER, 0); @@ -1459,13 +1534,14 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_c } -void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection) { +void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection,RID p_shadow_atlas) { + + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); directional_light_instance_count=0; light_instance_count=0; - Vector lpercent; - for(int i=0;i=RenderList::MAX_LIGHTS ); @@ -1502,23 +1578,90 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu li->light_ubo_data.light_params[2]=0; li->light_ubo_data.light_params[3]=0; + if (li->light_ptr->shadow) { + int shadow_count=0; + switch(li->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + shadow_count=1; + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + shadow_count=2; + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + shadow_count=4; + } break; -#if 0 - if (li->light_ptr->shadow_enabled) { - CameraMatrix bias; - bias.set_light_bias(); + } + + for(int j=0;jdirectional_rect.pos.x; + uint32_t y=li->directional_rect.pos.y; + uint32_t width=li->directional_rect.size.x; + uint32_t height=li->directional_rect.size.y; + + + + if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + + + width/=2; + height/=2; + + if (j==0) { + + } else if (j==1) { + x+=width; + } else if (j==2) { + y+=height; + } else if (j==3) { + x+=width; + y+=height; + + } + + + + } else if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - int passes=light_instance_get_shadow_passes(p_light_instance); + height/=2; + + if (j==0) { + + } else { + y+=height; + } + + } + + li->light_ubo_data.shadow_split_offsets[j]=1.0/li->shadow_transform[j].split; + + Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse(); + + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + Rect2 atlas_rect = Rect2(float(x)/directional_shadow.size,float(y)/directional_shadow.size,float(width)/directional_shadow.size,float(height)/directional_shadow.size); + rectm.set_light_atlas_rect(atlas_rect); + +// print_line("atlas rect: "+atlas_rect); + + CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview; + + store_camera(shadow_mtx,&li->light_ubo_data.shadow_matrix1[16*j]); + + li->light_ubo_data.light_clamp[0]=atlas_rect.pos.x; + li->light_ubo_data.light_clamp[1]=atlas_rect.pos.y; + li->light_ubo_data.light_clamp[2]=atlas_rect.size.x; + li->light_ubo_data.light_clamp[3]=atlas_rect.size.y; - for(int i=0;icustom_transform[i]).inverse(); - li->shadow_projection[i] = bias * li->custom_projection[i] * modelview; } - lights_use_shadow=true; + } -#endif + } break; case VS::LIGHT_OMNI: { @@ -1542,29 +1685,57 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; li->light_ubo_data.light_params[0]=0; - li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - li->light_ubo_data.light_params[2]=0; + li->light_ubo_data.light_params[1]=0; + li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; li->light_ubo_data.light_params[3]=0; -#if 0 - Transform ai = p_camera_inverse_transform.affine_inverse(); - float zn = p_camera_projection.get_z_near(); - Plane p (ai.origin + ai.basis.get_axis(2) * -zn, -ai.basis.get_axis(2) ); + if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { + // fill in the shadow information - Vector3 point1 = li->transform.origin; - Vector3 point2 = li->transform.origin+p_camera_inverse_transform.affine_inverse().basis.get_axis(1).normalized()*li->light_ptr->param[VS::LIGHT_PARAM_RANGE]; + uint32_t key = shadow_atlas->shadow_owners[li->self]; - p.intersects_segment(ai.origin,point1,&point1); - p.intersects_segment(ai.origin,point2,&point2); - float r = point1.distance_to(point2); + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_CONTINUE(shadow>=shadow_atlas->quadrants[quadrant].shadows.size()); + + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size>>1; + + uint32_t x=(quadrant&1)*quadrant_size; + uint32_t y=(quadrant>>1)*quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + uint32_t width=shadow_size; + uint32_t height=shadow_size; + + + if (li->light_ptr->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + height/=2; + } else { + width/=2; + + } + + Transform proj = (p_camera_inverse_transform * li->transform).inverse(); + + store_transform(proj,li->light_ubo_data.shadow_matrix1); + + li->light_ubo_data.light_params[3]=1.0; //means it has shadow + li->light_ubo_data.light_clamp[0]=float(x)/atlas_size; + li->light_ubo_data.light_clamp[1]=float(y)/atlas_size; + li->light_ubo_data.light_clamp[2]=float(width)/atlas_size; + li->light_ubo_data.light_clamp[3]=float(height)/atlas_size; + + } - float vp_w,vp_h; - p_camera_projection.get_viewport_size(vp_w,vp_h); - lpercent.push_back(r*2/((vp_h+vp_w)*0.5)); -#endif #if 0 if (li->light_ptr->shadow_enabled) { @@ -1596,10 +1767,54 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; li->light_ubo_data.light_params[0]=li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; - li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - li->light_ubo_data.light_params[2]=0; + li->light_ubo_data.light_params[1]=Math::cos(Math::deg2rad(li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE])); + li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; li->light_ubo_data.light_params[3]=0; + if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { + // fill in the shadow information + + uint32_t key = shadow_atlas->shadow_owners[li->self]; + + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_CONTINUE(shadow>=shadow_atlas->quadrants[quadrant].shadows.size()); + + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size>>1; + + uint32_t x=(quadrant&1)*quadrant_size; + uint32_t y=(quadrant>>1)*quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + uint32_t width=shadow_size; + uint32_t height=shadow_size; + + Rect2 rect(float(x)/atlas_size,float(y)/atlas_size,float(width)/atlas_size,float(height)/atlas_size); + + li->light_ubo_data.light_params[3]=1.0; //means it has shadow + li->light_ubo_data.light_clamp[0]=rect.pos.x; + li->light_ubo_data.light_clamp[1]=rect.pos.y; + li->light_ubo_data.light_clamp[2]=rect.size.x; + li->light_ubo_data.light_clamp[3]=rect.size.y; + + Transform modelview = (p_camera_inverse_transform * li->transform).inverse(); + + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + rectm.set_light_atlas_rect(rect); + + CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[0].camera * modelview; + + store_camera(shadow_mtx,li->light_ubo_data.shadow_matrix1); + + + } #if 0 if (li->light_ptr->shadow_enabled) { CameraMatrix bias; @@ -1679,24 +1894,39 @@ void RasterizerSceneGLES3::_copy_to_front_buffer(Environment *env) { } -void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){ +void RasterizerSceneGLES3::_copy_texture_to_front_buffer(GLuint p_texture) { - //first of all, make a new render pass - render_pass++; + //copy to front buffer + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); - //fill up ubo + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1,1,1,1); - Environment *env = environment_owner.getornull(p_environment); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,p_texture); - _setup_environment(env,p_cam_projection,p_cam_transform); + glViewport(0,0,storage->frame.current_rt->width*0.5,storage->frame.current_rt->height*0.5); - _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,true); + storage->shaders.copy.bind(); - render_list.clear(); + _copy_screen(); - current_material_index=0; + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB,false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,false); - bool use_mrt=false; + +} + +void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow){ + + current_geometry_index=0; + current_material_index=0; //fill list @@ -1716,7 +1946,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM int mat_idx = inst->materials[i].is_valid() ? i : -1; RasterizerStorageGLES3::Surface *s = mesh->surfaces[i]; - _add_geometry(s,inst,NULL,mat_idx); + _add_geometry(s,inst,NULL,mat_idx,p_shadow); } //mesh->last_pass=frame; @@ -1731,7 +1961,39 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM } } +} + + +void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas){ + + //first of all, make a new render pass + render_pass++; + + //fill up ubo + + Environment *env = environment_owner.getornull(p_environment); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + + if (shadow_atlas && shadow_atlas->size) { + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-3); + glBindTexture(GL_TEXTURE_2D,shadow_atlas->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + state.ubo_data.shadow_atlas_pixel_size[0]=1.0/shadow_atlas->size; + state.ubo_data.shadow_atlas_pixel_size[1]=1.0/shadow_atlas->size; + } + + _setup_environment(env,p_cam_projection,p_cam_transform); + + _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_shadow_atlas); + + render_list.clear(); + + bool use_mrt=false; + + + _fill_render_list(p_cull_result,p_cull_count,false); // @@ -1742,6 +2004,8 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM RasterizerStorageGLES3::Texture* env_radiance_tex=NULL; + glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height); + if (use_mrt) { glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); @@ -1811,7 +2075,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); @@ -1843,11 +2107,34 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM render_list.sort_by_depth(true); - _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true); + _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false); _copy_to_front_buffer(env); +/* if (shadow_atlas) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,shadow_atlas->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1)); + + } +*/ + if (directional_shadow.fbo) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,directional_shadow.depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1)); + + } + + #if 0 if (use_fb) { @@ -1994,6 +2281,294 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM #endif } +void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count) { + + render_pass++; + + LightInstance *light_instance = light_instance_owner.getornull(p_light); + ERR_FAIL_COND(!light_instance); + RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light); + ERR_FAIL_COND(!light); + + uint32_t x,y,width,height,vp_height; + + + float dp_direction=0.0; + float zfar=0; + bool flip_facing=false; + int custom_vp_size=0; + GLuint fbo; + int current_cubemap=-1; + float bias=0; + float normal_bias=0; + + CameraMatrix light_projection; + Transform light_transform; + + + if (light->type==VS::LIGHT_DIRECTIONAL) { + //set pssm stuff + if (light_instance->last_scene_shadow_pass!=scene_pass) { + //assign rect if unassigned + light_instance->light_directional_index = directional_shadow.current_light; + light_instance->last_scene_shadow_pass=scene_pass; + directional_shadow.current_light++; + + if (directional_shadow.light_count==1) { + light_instance->directional_rect=Rect2(0,0,directional_shadow.size,directional_shadow.size); + } else if (directional_shadow.light_count==2) { + light_instance->directional_rect=Rect2(0,0,directional_shadow.size,directional_shadow.size/2); + if (light_instance->light_directional_index==1) { + light_instance->directional_rect.pos.x+=light_instance->directional_rect.size.x; + } + } else { //3 and 4 + light_instance->directional_rect=Rect2(0,0,directional_shadow.size/2,directional_shadow.size/2); + if (light_instance->light_directional_index&1) { + light_instance->directional_rect.pos.x+=light_instance->directional_rect.size.x; + } + if (light_instance->light_directional_index/2) { + light_instance->directional_rect.pos.y+=light_instance->directional_rect.size.y; + } + } + } + + light_projection=light_instance->shadow_transform[p_pass].camera; + light_transform=light_instance->shadow_transform[p_pass].transform; + + x=light_instance->directional_rect.pos.x; + y=light_instance->directional_rect.pos.y; + width=light_instance->directional_rect.size.x; + height=light_instance->directional_rect.size.y; + + + + if (light->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + + + width/=2; + height/=2; + + if (p_pass==0) { + + } else if (p_pass==1) { + x+=width; + } else if (p_pass==2) { + y+=height; + } else if (p_pass==3) { + x+=width; + y+=height; + + } + + + + } else if (light->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + + height/=2; + + if (p_pass==0) { + + } else { + y+=height; + } + + } + + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + normal_bias=light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]; + fbo=directional_shadow.fbo; + vp_height=directional_shadow.size; + + } else { + //set from shadow atlas + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); + + fbo=shadow_atlas->fbo; + vp_height=shadow_atlas->size; + + + uint32_t key = shadow_atlas->shadow_owners[p_light]; + + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_FAIL_INDEX(shadow,shadow_atlas->quadrants[quadrant].shadows.size()); + + uint32_t quadrant_size = shadow_atlas->size>>1; + + x=(quadrant&1)*quadrant_size; + y=(quadrant>>1)*quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + width=shadow_size; + height=shadow_size; + + if (light->type==VS::LIGHT_OMNI) { + + + if (light->omni_shadow_mode==VS::LIGHT_OMNI_SHADOW_CUBE) { + + int cubemap_index=shadow_cubemaps.size()-1; + + for(int i=shadow_cubemaps.size()-1;i>=0;i--) { + //find appropriate cubemap to render to + if (shadow_cubemaps[i].size>shadow_size*2) + break; + + cubemap_index=i; + } + + fbo=shadow_cubemaps[cubemap_index].fbo_id[p_pass]; + light_projection=light_instance->shadow_transform[0].camera; + light_transform=light_instance->shadow_transform[0].transform; + custom_vp_size=shadow_cubemaps[cubemap_index].size; + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + + current_cubemap=cubemap_index; + + + } else { + + light_projection=light_instance->shadow_transform[0].camera; + light_transform=light_instance->shadow_transform[0].transform; + + if (light->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + height/=2; + y+=p_pass*height; + } else { + width/=2; + x+=p_pass*width; + + } + + dp_direction = p_pass==0?1.0:-1.0; + flip_facing = (p_pass == 1); + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,true); + } + + } else if (light->type==VS::LIGHT_SPOT) { + + light_projection=light_instance->shadow_transform[0].camera; + light_transform=light_instance->shadow_transform[0].transform; + + dp_direction = 1.0; + flip_facing = false; + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + normal_bias=light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]; + } + + } + + //todo hacer que se redibuje cuando corresponde + + + render_list.clear(); + _fill_render_list(p_cull_result,p_cull_count,true); + + render_list.sort_by_depth(false); //shadow is front to back for performance + + glDepthMask(true); + glColorMask(0,0,0,0); + glDisable(GL_BLEND); + glDisable(GL_DITHER); + glEnable(GL_DEPTH_TEST); + + glBindFramebuffer(GL_FRAMEBUFFER,fbo); + + if (custom_vp_size) { + glViewport(0,0,custom_vp_size,custom_vp_size); + glScissor(0,0,custom_vp_size,custom_vp_size); + + } else { + glViewport(x,y,width,height); + glScissor(x,y,width,height); + } + + //glViewport(x,vp_height-(height+y),width,height); + //glScissor(x,vp_height-(height+y),width,height); + glEnable(GL_SCISSOR_TEST); + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + + state.ubo_data.shadow_z_offset=bias; + state.ubo_data.shadow_slope_scale=normal_bias; + state.ubo_data.shadow_dual_paraboloid_render_side=dp_direction; + state.ubo_data.shadow_dual_paraboloid_render_zfar=zfar; + + _setup_environment(NULL,light_projection,light_transform); + + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,true); + + _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true); + + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false); + + + if (light->type==VS::LIGHT_OMNI && light->omni_shadow_mode==VS::LIGHT_OMNI_SHADOW_CUBE && p_pass==5) { + //convert the chosen cubemap to dual paraboloid! + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + + glBindFramebuffer(GL_FRAMEBUFFER,shadow_atlas->fbo); + state.cube_to_dp_shader.bind(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP,shadow_cubemaps[current_cubemap].cubemap); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glDisable(GL_CULL_FACE); + + for(int i=0;i<2;i++) { + + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FLIP,i==1); + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_NEAR,light_projection.get_z_near()); + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FAR,light_projection.get_z_far()); + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::BIAS,light->param[VS::LIGHT_PARAM_SHADOW_BIAS]); + + uint32_t local_width=width,local_height=height; + uint32_t local_x=x,local_y=y; + if (light->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + local_height/=2; + local_y+=i*local_height; + } else { + local_width/=2; + local_x+=i*local_width; + } + + glViewport(local_x,local_y,local_width,local_height); + glScissor(local_x,local_y,local_width,local_height); + glEnable(GL_SCISSOR_TEST); + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + //glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + _copy_screen(); + + } + + } + + glColorMask(1,1,1,1); + + +} + void RasterizerSceneGLES3::set_scene_pass(uint64_t p_pass) { scene_pass=p_pass; } @@ -2169,6 +2744,12 @@ void RasterizerSceneGLES3::initialize() { default_material = storage->material_create(); storage->material_set_shader(default_material,default_shader); + default_shader_twosided = storage->shader_create(VS::SHADER_SPATIAL); + default_material_twosided = storage->material_create(); + storage->shader_set_code(default_shader_twosided,"render_mode cull_disabled;\n"); + storage->material_set_shader(default_material_twosided,default_shader_twosided); + + glGenBuffers(1, &state.scene_ubo); glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.scene_ubo, GL_DYNAMIC_DRAW); @@ -2208,9 +2789,77 @@ void RasterizerSceneGLES3::initialize() { glBindBuffer(GL_ARRAY_BUFFER,0); //unbind } render_list.init(); + state.cube_to_dp_shader.init(); _generate_brdf(); shadow_atlas_realloc_tolerance_msec=500; + + + + + + int max_shadow_cubemap_sampler_size=512; + + int cube_size = max_shadow_cubemap_sampler_size; + + glActiveTexture(GL_TEXTURE0); + + while(cube_size>=32) { + + ShadowCubeMap cube; + cube.size=cube_size; + + glGenTextures(1,&cube.cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP,cube.cubemap); + //gen cubemap first + for(int i=0;i<6;i++) { + + glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube.size, cube.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // Remove artifact on the edges of the shadowmap + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + //gen renderbuffers second, because it needs a complete cubemap + for(int i=0;i<6;i++) { + + glGenFramebuffers(1, &cube.fbo_id[i]); + glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo_id[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,_cube_side_enum[i], cube.cubemap, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); + } + + shadow_cubemaps.push_back(cube); + + cube_size>>=1; + } + + { + //directional light shadow + directional_shadow.light_count=0; + directional_shadow.size=nearest_power_of_2(GLOBAL_DEF("renderer/directional_shadow_size",2048)); + glGenFramebuffers(1,&directional_shadow.fbo); + glBindFramebuffer(GL_FRAMEBUFFER,directional_shadow.fbo); + glGenTextures(1,&directional_shadow.depth); + glBindTexture(GL_TEXTURE_2D,directional_shadow.depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D, directional_shadow.depth, 0); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status!=GL_FRAMEBUFFER_COMPLETE) { + ERR_PRINT("Directional shadow framebuffer status invalid"); + } + } } void RasterizerSceneGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 9df6315e4..d7beebbcf 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -3,6 +3,7 @@ #include "rasterizer_storage_gles3.h" #include "drivers/gles3/shaders/scene.glsl.h" +#include "drivers/gles3/shaders/cube_to_dp.glsl.h" class RasterizerSceneGLES3 : public RasterizerScene { public: @@ -16,10 +17,13 @@ public: uint32_t current_geometry_index; RID default_material; + RID default_material_twosided; RID default_shader; + RID default_shader_twosided; RasterizerStorageGLES3 *storage; + struct State { @@ -29,6 +33,7 @@ public: int current_depth_draw; SceneShaderGLES3 scene_shader; + CubeToDpShaderGLES3 cube_to_dp_shader; struct SceneDataUBO { @@ -41,6 +46,12 @@ public: float bg_color[4]; float ambient_energy; float bg_energy; + float shadow_z_offset; + float shadow_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + float shadow_atlas_pixel_size[2]; + float shadow_directional_pixel_size[2]; } ubo_data; @@ -62,7 +73,7 @@ public: GLuint skybox_verts; GLuint skybox_array; - + bool cull_front; } state; @@ -71,7 +82,6 @@ public: struct ShadowAtlas : public RID_Data { enum { - SHADOW_INDEX_DIRTY_BIT=(1<<31), QUADRANT_SHIFT=27, SHADOW_INDEX_MASK=(1< shadow_owners; }; + struct ShadowCubeMap { + + GLuint fbo_id[6]; + GLuint cubemap; + int size; + }; + + Vector shadow_cubemaps; + RID_Owner shadow_atlas_owner; RID shadow_atlas_create(); void shadow_atlas_set_size(RID p_atlas,int p_size); void shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision); bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); - uint32_t shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version); + bool shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version); + + + struct DirectionalShadow { + GLuint fbo; + GLuint depth; + int light_count; + int size; + int current_light; + } directional_shadow; + + virtual int get_directional_light_shadow_size(RID p_light_intance); + virtual void set_directional_shadow_count(int p_count); + /* ENVIRONMENT API */ @@ -174,12 +206,12 @@ public: struct LightInstance : public RID_Data { - struct SplitInfo { + struct ShadowTransform { CameraMatrix camera; Transform transform; - float near; float far; + float split; }; struct LightDataUBO { @@ -188,6 +220,7 @@ public: float light_direction_attenuation[4]; float light_color_energy[4]; float light_params[4]; //cone attenuation, specular, shadow darkening, + float light_clamp[4]; //cone attenuation, specular, shadow darkening, float shadow_split_offsets[4]; float shadow_matrix1[16]; float shadow_matrix2[16]; @@ -197,13 +230,11 @@ public: } light_ubo_data; - SplitInfo split_info[4]; + ShadowTransform shadow_transform[4]; + RID self; RID light; RasterizerStorageGLES3::Light *light_ptr; - - CameraMatrix shadow_matrix[4]; - Transform transform; Vector3 light_vector; @@ -214,12 +245,17 @@ public: uint64_t shadow_pass; uint64_t last_scene_pass; + uint64_t last_scene_shadow_pass; uint64_t last_pass; uint16_t light_index; + uint16_t light_directional_index; + + uint32_t current_shadow_atlas_key; Vector2 dp; - CameraMatrix shadow_projection[4]; + Rect2 directional_rect; + Set shadow_atlases; //shadow atlases where this light is registered @@ -231,6 +267,7 @@ public: virtual RID light_instance_create(RID p_light); virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform); + virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass); virtual void light_instance_mark_visible(RID p_light_instance); /* RENDER LIST */ @@ -371,26 +408,31 @@ public: RenderList render_list; + _FORCE_INLINE_ void _set_cull(bool p_front,bool p_reverse_cull); + _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass); _FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e); _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); _FORCE_INLINE_ void _setup_light(LightInstance *p_light); - void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass); + void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow); - _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material); + _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow); - void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); + void _draw_skybox(RID p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); - void _setup_environment(Environment *env,CameraMatrix& p_cam_projection, const Transform& p_cam_transform); - void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform,const CameraMatrix& p_camera_projection); + void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform& p_cam_transform); + void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_shadow_atlas); void _copy_screen(); void _copy_to_front_buffer(Environment *env); + void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug - virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment); + void _fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow); + virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas); + virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count); virtual bool free(RID p_rid); void _generate_brdf(); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 4b2c60729..b988781e1 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1290,12 +1290,13 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { shaders.actions_scene.render_mode_values["cull_front"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_FRONT); shaders.actions_scene.render_mode_values["cull_back"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_BACK); - shaders.actions_scene.render_mode_values["cull_disable"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED); + shaders.actions_scene.render_mode_values["cull_disabled"]=Pair(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED); shaders.actions_scene.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded; shaders.actions_scene.render_mode_flags["ontop"]=&p_shader->spatial.ontop; shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha; + shaders.actions_scene.usage_flag_pointers["VERTEX"]=&p_shader->spatial.uses_vertex; actions=&shaders.actions_scene; actions->uniforms=&p_shader->uniforms; @@ -1318,6 +1319,9 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { p_shader->texture_count=gen_code.texture_uniforms.size(); p_shader->texture_hints=gen_code.texture_hints; + p_shader->uses_vertex_time=gen_code.uses_vertex_time; + p_shader->uses_fragment_time=gen_code.uses_fragment_time; + //all materials using this shader will have to be invalidated, unfortunately for (SelfList* E = p_shader->materials.first();E;E=E->next() ) { @@ -1535,6 +1539,57 @@ void RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_wid } +bool RasterizerStorageGLES3::material_is_animated(RID p_material) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND_V(!material,false); + if (material->dirty_list.in_list()) { + _update_material(material); + } + + return material->is_animated_cache; + +} +bool RasterizerStorageGLES3::material_casts_shadows(RID p_material) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND_V(!material,false); + if (material->dirty_list.in_list()) { + _update_material(material); + } + + return material->can_cast_shadow_cache; +} + +void RasterizerStorageGLES3::material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND(!material); + + Map::Element *E=material->instance_owners.find(p_instance); + if (E) { + E->get()++; + } else { + material->instance_owners[p_instance]=1; + } +} + +void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND(!material); + + Map::Element *E=material->instance_owners.find(p_instance); + ERR_FAIL_COND(!E); + E->get()--; + + if (E->get()==0) { + material->instance_owners.erase(E); + } +} + + + _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant& value, uint8_t *data,bool p_linear_color) { switch(type) { case ShaderLanguage::TYPE_BOOL: { @@ -2011,6 +2066,48 @@ void RasterizerStorageGLES3::_update_material(Material* material) { if (material->dirty_list.in_list()) _material_dirty_list.remove( &material->dirty_list ); + + if (material->shader && material->shader->dirty_list.in_list()) { + _update_shader(material->shader); + } + //update caches + + { + bool can_cast_shadow = false; + bool is_animated = false; + + if (material->shader && material->shader->mode==VS::SHADER_SPATIAL) { + if (!material->shader->spatial.uses_alpha && material->shader->spatial.blend_mode==Shader::Spatial::BLEND_MODE_MIX) { + can_cast_shadow=true; + } + + if (material->shader->spatial.uses_discard && material->shader->uses_fragment_time) { + is_animated=true; + } + + if (material->shader->spatial.uses_vertex && material->shader->uses_vertex_time) { + is_animated=true; + } + + } + + if (can_cast_shadow!=material->can_cast_shadow_cache || is_animated!=material->is_animated_cache) { + material->can_cast_shadow_cache=can_cast_shadow; + material->is_animated_cache=is_animated; + + for(Map::Element *E=material->instantiable_owners.front();E;E=E->next()) { + E->key()->instance_material_change_notify(); + } + + for(Map::Element *E=material->instance_owners.front();E;E=E->next()) { + E->key()->base_material_changed(); + } + + } + + } + + //clear ubo if it needs to be cleared if (material->ubo_size) { @@ -2102,6 +2199,36 @@ void RasterizerStorageGLES3::_update_material(Material* material) { } +void RasterizerStorageGLES3::_material_add_instantiable(RID p_material,Instantiable *p_instantiable) { + + Material * material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + + Map::Element *I = material->instantiable_owners.find(p_instantiable); + + if (I) { + I->get()++; + } else { + material->instantiable_owners[p_instantiable]=1; + } + +} + +void RasterizerStorageGLES3::_material_remove_instantiable(RID p_material,Instantiable *p_instantiable) { + + Material * material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + + Map::Element *I = material->instantiable_owners.find(p_instantiable); + ERR_FAIL_COND(!I); + + I->get()--; + if (I->get()==0) { + material->instantiable_owners.erase(I); + } +} + + void RasterizerStorageGLES3::update_dirty_materials() { while( _material_dirty_list.first() ) { @@ -2406,6 +2533,8 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P surface->active=true; surface->array_len=p_vertex_count; surface->index_array_len=p_index_count; + surface->array_byte_size=p_array.size(); + surface->index_array_byte_size=p_index_array.size(); surface->primitive=p_primitive; surface->mesh=mesh; surface->format=p_format; @@ -2556,8 +2685,22 @@ void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface ERR_FAIL_COND(!mesh); ERR_FAIL_INDEX(p_surface,mesh->surfaces.size()); + if (mesh->surfaces[p_surface]->material==p_material) + return; + + if (mesh->surfaces[p_surface]->material.is_valid()) { + _material_remove_instantiable(mesh->surfaces[p_surface]->material,mesh); + } + mesh->surfaces[p_surface]->material=p_material; + if (mesh->surfaces[p_surface]->material.is_valid()) { + _material_add_instantiable(mesh->surfaces[p_surface]->material,mesh); + } + + mesh->instance_material_change_notify(); + + } RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const{ @@ -2595,17 +2738,17 @@ DVector RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int Surface *surface = mesh->surfaces[p_surface]; glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); - void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_len,GL_MAP_READ_BIT); + void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_byte_size,GL_MAP_READ_BIT); ERR_FAIL_COND_V(!data,DVector()); DVector ret; - ret.resize(surface->array_len); + ret.resize(surface->array_byte_size); { DVector::Write w = ret.write(); - copymem(w.ptr(),data,surface->array_len); + copymem(w.ptr(),data,surface->array_byte_size); } glUnmapBuffer(GL_ARRAY_BUFFER); @@ -2622,18 +2765,18 @@ DVector RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh ERR_FAIL_COND_V(surface->index_array_len==0,DVector()); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->vertex_id); - void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_len,GL_MAP_READ_BIT); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); + void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_byte_size,GL_MAP_READ_BIT); ERR_FAIL_COND_V(!data,DVector()); DVector ret; - ret.resize(surface->index_array_len); + ret.resize(surface->index_array_byte_size); { DVector::Write w = ret.write(); - copymem(w.ptr(),data,surface->index_array_len); + copymem(w.ptr(),data,surface->index_array_byte_size); } glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); @@ -2662,6 +2805,59 @@ VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_ return mesh->surfaces[p_surface]->primitive; } +AABB RasterizerStorageGLES3::mesh_surface_get_aabb(RID p_mesh, int p_surface) const { + + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh,AABB()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),AABB()); + + return mesh->surfaces[p_surface]->aabb; + + +} +Vector > RasterizerStorageGLES3::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const{ + + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh,Vector >()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector >()); + + Vector > bsarr; + + for(int i=0;isurfaces[p_surface]->morph_targets.size();i++) { + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh->surfaces[p_surface]->morph_targets[i].vertex_id); + void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,mesh->surfaces[p_surface]->array_byte_size,GL_MAP_READ_BIT); + + ERR_FAIL_COND_V(!data,Vector >()); + + DVector ret; + ret.resize(mesh->surfaces[p_surface]->array_byte_size); + + { + + DVector::Write w = ret.write(); + copymem(w.ptr(),data,mesh->surfaces[p_surface]->array_byte_size); + } + + bsarr.push_back(ret); + + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + } + + return bsarr; + +} +Vector RasterizerStorageGLES3::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const{ + + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh,Vector()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector()); + + return mesh->surfaces[p_surface]->skeleton_bone_aabb; + +} + + void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ Mesh *mesh = mesh_owner.getornull(p_mesh); @@ -2670,6 +2866,10 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ Surface *surface = mesh->surfaces[p_surface]; + if (surface->material.is_valid()) { + _material_remove_instantiable(surface->material,mesh); + } + glDeleteBuffers(1,&surface->vertex_id); if (surface->index_id) { glDeleteBuffers(1,&surface->index_id); @@ -2683,6 +2883,8 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ glDeleteVertexArrays(1,&surface->morph_targets[i].array_id); } + mesh->instance_material_change_notify(); + memdelete(surface); mesh->surfaces.remove(p_surface); @@ -2971,7 +3173,6 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET]=0.1; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET]=0.3; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET]=0.6; - light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET]=1.0; light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]=0.1; light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]=0.1; @@ -2981,6 +3182,10 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ light->negative=false; light->cull_mask=0xFFFFFFFF; light->directional_shadow_mode=VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; + light->omni_shadow_mode=VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; + light->omni_shadow_detail=VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL; + + light->version=0; return light_owner.make_rid(light); } @@ -2998,9 +3203,23 @@ void RasterizerStorageGLES3::light_set_param(RID p_light,VS::LightParam p_param, ERR_FAIL_COND(!light); ERR_FAIL_INDEX(p_param,VS::LIGHT_PARAM_MAX); - if (p_param==VS::LIGHT_PARAM_RANGE || p_param==VS::LIGHT_PARAM_SPOT_ANGLE) { - light->instance_change_notify(); + switch(p_param) { + case VS::LIGHT_PARAM_RANGE: + case VS::LIGHT_PARAM_SPOT_ANGLE: + case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE: + case VS::LIGHT_PARAM_SHADOW_DARKNESS: + case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET: + case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: + case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: + case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: + case VS::LIGHT_PARAM_SHADOW_BIAS: + case VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE: { + + light->version++; + light->instance_change_notify(); + } break; } + light->param[p_param]=p_value; } void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){ @@ -3009,6 +3228,10 @@ void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){ ERR_FAIL_COND(!light); light->shadow=p_enabled; + light->version++; + light->instance_change_notify(); + + } void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){ @@ -3021,9 +3244,8 @@ void RasterizerStorageGLES3::light_set_attenuation_texure(RID p_light,RID p_text Light * light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); - - } + void RasterizerStorageGLES3::light_set_negative(RID p_light,bool p_enable){ Light * light = light_owner.getornull(p_light); @@ -3037,6 +3259,10 @@ void RasterizerStorageGLES3::light_set_cull_mask(RID p_light,uint32_t p_mask){ ERR_FAIL_COND(!light); light->cull_mask=p_mask; + + light->version++; + light->instance_change_notify(); + } void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){ @@ -3045,22 +3271,92 @@ void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){ } +void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) { + + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->omni_shadow_mode=p_mode; + + light->version++; + light->instance_change_notify(); + + +} + +VS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI_SHADOW_CUBE); + + return light->omni_shadow_mode; +} + + +void RasterizerStorageGLES3::light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail) { + + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->omni_shadow_detail=p_detail; + light->version++; + light->instance_change_notify(); +} + void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode){ Light * light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); + light->directional_shadow_mode=p_mode; + light->version++; + light->instance_change_notify(); + +} + +VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); + + return light->directional_shadow_mode; } + VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const { const Light * light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL); - return VS::LIGHT_DIRECTIONAL; + return light->type; } +float RasterizerStorageGLES3::light_get_param(RID p_light,VS::LightParam p_param) { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL); + + return light->param[p_param]; +} + +bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL); + + return light->shadow; +} + +uint64_t RasterizerStorageGLES3::light_get_version(RID p_light) const { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,0); + + return light->version; +} + + AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { const Light * light = light_owner.getornull(p_light); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b12c2d93b..f8b34d6a1 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -99,6 +99,38 @@ public: + struct Instantiable : public RID_Data { + + SelfList::List instance_list; + + _FORCE_INLINE_ void instance_change_notify() { + + SelfList *instances = instance_list.first(); + while(instances) { + + instances->self()->base_changed(); + instances=instances->next(); + } + } + + _FORCE_INLINE_ void instance_material_change_notify() { + + SelfList *instances = instance_list.first(); + while(instances) { + + instances->self()->base_material_changed(); + instances=instances->next(); + } + } + + Instantiable() { } + virtual ~Instantiable() { + + while(instance_list.first()) { + instance_list.first()->self()->base_removed(); + } + } + }; @@ -282,9 +314,14 @@ public: bool uses_alpha; bool unshaded; bool ontop; + bool uses_vertex; + bool uses_discard; } spatial; + bool uses_vertex_time; + bool uses_fragment_time; + Shader() : dirty_list(this) { shader=NULL; @@ -315,6 +352,8 @@ public: void update_dirty_shaders(); + + /* COMMON MATERIAL API */ struct Material : public RID_Data { @@ -331,7 +370,15 @@ public: uint32_t index; uint64_t last_pass; + Map instantiable_owners; + Map instance_owners; + + bool can_cast_shadow_cache; + bool is_animated_cache; + Material() : list(this), dirty_list(this) { + can_cast_shadow_cache=false; + is_animated_cache=false; shader=NULL; line_width=1.0; ubo_id=0; @@ -343,6 +390,8 @@ public: mutable SelfList::List _material_dirty_list; void _material_make_dirty(Material *p_material) const; + void _material_add_instantiable(RID p_material,Instantiable *p_instantiable); + void _material_remove_instantiable(RID p_material, Instantiable *p_instantiable); mutable RID_Owner material_owner; @@ -357,34 +406,18 @@ public: virtual void material_set_line_width(RID p_material, float p_width); + virtual bool material_is_animated(RID p_material); + virtual bool material_casts_shadows(RID p_material); + + virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); + virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); + void _update_material(Material* material); void update_dirty_materials(); /* MESH API */ - struct Instantiable : public RID_Data { - - SelfList::List instance_list; - - _FORCE_INLINE_ void instance_change_notify() { - - SelfList *instances = instance_list.first(); - while(instances) { - - instances->self()->base_changed(); - instances=instances->next(); - } - } - - Instantiable() { } - virtual ~Instantiable() { - - while(instance_list.first()) { - instance_list.first()->self()->base_removed(); - } - } - }; struct Geometry : Instantiable { @@ -455,7 +488,8 @@ public: int index_array_len; int max_bone; - int array_bytes; + int array_byte_size; + int index_array_byte_size; VS::PrimitiveType primitive; @@ -464,7 +498,8 @@ public: Surface() { - array_bytes=0; + array_byte_size=0; + index_array_byte_size=0; mesh=NULL; format=0; array_id=0; @@ -526,6 +561,10 @@ public: virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const; virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const; + virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const; + virtual Vector > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const; + virtual Vector mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const; + virtual void mesh_remove_surface(RID p_mesh, int p_surface); virtual int mesh_get_surface_count(RID p_mesh) const; @@ -598,7 +637,10 @@ public: bool shadow; bool negative; uint32_t cull_mask; + VS::LightOmniShadowMode omni_shadow_mode; + VS::LightOmniShadowDetail omni_shadow_detail; VS::LightDirectionalShadowMode directional_shadow_mode; + uint64_t version; }; mutable RID_Owner light_owner; @@ -614,11 +656,22 @@ public: virtual void light_set_cull_mask(RID p_light,uint32_t p_mask); virtual void light_set_shader(RID p_light,RID p_shader); + virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode); + + virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail); virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode); + virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); + virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); + + virtual bool light_has_shadow(RID p_light) const; virtual VS::LightType light_get_type(RID p_light) const; + virtual float light_get_param(RID p_light,VS::LightParam p_param); + virtual AABB light_get_aabb(RID p_light) const; + virtual uint64_t light_get_version(RID p_light) const; + /* PROBE API */ virtual RID reflection_probe_create(); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 0dff53bfb..dce52ecd9 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -330,6 +330,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::FunctionNode *fnode=pnode->functions[i].function; + current_func_name=fnode->name; if (fnode->name=="vertex") { @@ -401,6 +402,14 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener else code=_mkid(vnode->name); + if (vnode->name==time_name) { + if (current_func_name==vertex_name) { + r_gen_code.uses_vertex_time=true; + } + if (current_func_name==fragment_name) { + r_gen_code.uses_fragment_time=true; + } + } } break; case SL::Node::TYPE_CONSTANT: { @@ -536,6 +545,8 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String& p_code, r_gen_code.fragment=String(); r_gen_code.fragment_global=String(); r_gen_code.light=String(); + r_gen_code.uses_fragment_time=false; + r_gen_code.uses_vertex_time=false; @@ -645,7 +656,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { - + vertex_name="vertex"; + fragment_name="fragment"; + time_name="TIME"; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index dcea82d77..354952680 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -32,6 +32,9 @@ public: String fragment; String light; + bool uses_fragment_time; + bool uses_vertex_time; + }; private: @@ -49,6 +52,10 @@ private: String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions& p_actions, const DefaultIdentifierActions& p_default_actions); + StringName current_func_name; + StringName vertex_name; + StringName fragment_name; + StringName time_name; Set used_name_defines; Set used_rmode_defines; diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index afffe1031..44d325b09 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -6,4 +6,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'): env.GLES3_GLSL('canvas_shadow.glsl'); env.GLES3_GLSL('scene.glsl'); env.GLES3_GLSL('cubemap_filter.glsl'); + env.GLES3_GLSL('cube_to_dp.glsl'); diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl new file mode 100644 index 000000000..5ffc78c0b --- /dev/null +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -0,0 +1,79 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; +layout(location=4) in vec2 uv_in; + +out vec2 uv_interp; + +void main() { + + uv_interp = uv_in; + gl_Position = vertex_attrib; +} + +[fragment] + + +uniform highp samplerCube source_cube; //texunit:0 +in vec2 uv_interp; + +uniform bool z_flip; +uniform highp float z_far; +uniform highp float z_near; +uniform highp float bias; + +void main() { + + highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 ); +/* + if(z_flip) { + normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + } else { + normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + } +*/ + + //normal.z = sqrt(1.0-dot(normal.xy,normal.xy)); + //normal.xy*=1.0+normal.z; + + normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + +/* + normal.z=0.5; + normal=normalize(normal); +*/ + if (!z_flip) { + normal.z=-normal.z; + } + + //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 )); + float depth = texture(source_cube,normal).r; + + // absolute values for direction cosines, bigger value equals closer to basis axis + vec3 unorm = abs(normal); + + if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) { + // x code + unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ; + } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) { + // y code + unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ; + } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) { + // z code + unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ; + } else { + // oh-no we messed up code + // has to be + unorm = vec3( 1.0, 0.0, 0.0 ); + } + + float depth_fix = 1.0 / dot(normal,unorm); + + + depth = 2.0 * depth - 1.0; + float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near)); + gl_FragDepth = (linear_depth*depth_fix+bias) / z_far; +} + diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 60ac015a1..de1591e8f 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1,7 +1,6 @@ [vertex] -#define ENABLE_UV_INTERP /* from VisualServer: @@ -56,6 +55,15 @@ layout(std140) uniform SceneData { //ubo:0 highp vec4 bg_color; float ambient_energy; float bg_energy; + + float shadow_z_offset; + float shadow_z_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + }; uniform highp mat4 world_transform; @@ -68,6 +76,7 @@ layout(std140) uniform LightData { //ubo:3 mediump vec4 light_direction_attenuation; mediump vec4 light_color_energy; mediump vec4 light_params; //cone attenuation, specular, shadow darkening, + mediump vec4 light_clamp; mediump vec4 shadow_split_offsets; highp mat4 shadow_matrix1; highp mat4 shadow_matrix2; @@ -75,19 +84,6 @@ layout(std140) uniform LightData { //ubo:3 highp mat4 shadow_matrix4; }; -#ifdef USE_FORWARD_1_SHADOW_MAP -out mediump vec4 forward_shadow_pos1; -#endif - -#ifdef USE_FORWARD_2_SHADOW_MAP -out mediump vec4 forward_shadow_pos2; -#endif - -#ifdef USE_FORWARD_4_SHADOW_MAP -out mediump vec4 forward_shadow_pos3; -out mediump vec4 forward_shadow_pos4; -#endif - #endif /* Varyings */ @@ -120,13 +116,6 @@ varying vec4 position_interp; #endif -#ifdef USE_SHADOW_PASS - -uniform highp float shadow_z_offset; -uniform highp float shadow_z_slope_scale; - -#endif - VERTEX_SHADER_GLOBALS @@ -141,6 +130,11 @@ MATERIAL_UNIFORMS #endif +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + +out highp float dp_clip; + +#endif void main() { @@ -206,24 +200,49 @@ VERTEX_SHADER_CODE } + vertex_interp = vertex.xyz; + normal_interp = normal; + +#if defined(ENABLE_TANGENT_INTERP) + tangent_interp = tangent; + binormal_interp = binormal; +#endif + +#ifdef RENDER_SHADOW + + +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + + vertex_interp.z*= shadow_dual_paraboloid_render_side; + normal_interp.z*= shadow_dual_paraboloid_render_side; -#ifdef USE_SHADOW_PASS + dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + highp vec3 vtx = vertex_interp+normalize(vertex_interp)*shadow_z_offset; + highp float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy/=1.0-vtx.z; + vtx.z=(distance/shadow_dual_paraboloid_render_zfar); + vtx.z=vtx.z * 2.0 - 1.0; + + vertex.xyz=vtx; + vertex.w=1.0; + + +#else float z_ofs = shadow_z_offset; z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale; vertex_interp.z-=z_ofs; -#endif +#endif //RENDER_SHADOW_DUAL_PARABOLOID - vertex_interp = vertex.xyz; - normal_interp = normal; +#endif //RENDER_SHADOW -#if defined(ENABLE_TANGENT_INTERP) - tangent_interp = tangent; - binormal_interp = binormal; -#endif -#if !defined(SKIP_TRANSFORM_USED) +#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_SHADOW_DUAL_PARABOLOID) gl_Position = projection_matrix * vec4(vertex_interp,1.0); #else gl_Position = vertex; @@ -239,11 +258,6 @@ VERTEX_SHADER_CODE #define M_PI 3.14159265359 - -#define ENABLE_UV_INTERP -//hack to use uv if no uv present so it works with lightmap - - /* Varyings */ #if defined(ENABLE_COLOR_INTERP) @@ -318,6 +332,15 @@ layout(std140) uniform SceneData { highp vec4 bg_color; float ambient_energy; float bg_energy; + + float shadow_z_offset; + float shadow_z_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + }; @@ -328,7 +351,8 @@ layout(std140) uniform LightData { highp vec4 light_pos_inv_radius; mediump vec4 light_direction_attenuation; mediump vec4 light_color_energy; - mediump vec4 light_params; //cone attenuation, specular, shadow darkening, + mediump vec4 light_params; //cone attenuation, specular, shadow darkening, shadow enabled + mediump vec4 light_clamp; mediump vec4 shadow_split_offsets; highp mat4 shadow_matrix1; highp mat4 shadow_matrix2; @@ -336,20 +360,12 @@ layout(std140) uniform LightData { highp mat4 shadow_matrix4; }; -#ifdef USE_FORWARD_1_SHADOW_MAP -in mediump vec4 forward_shadow_pos1; #endif -#ifdef USE_FORWARD_2_SHADOW_MAP -in mediump vec4 forward_shadow_pos2; -#endif -#ifdef USE_FORWARD_4_SHADOW_MAP -in mediump vec4 forward_shadow_pos3; -in mediump vec4 forward_shadow_pos4; -#endif +uniform highp sampler2DShadow directional_shadow; //texunit:-4 +uniform highp sampler2DShadow shadow_atlas; //texunit:-3 -#endif #ifdef USE_MULTIPLE_RENDER_TARGETS @@ -408,10 +424,27 @@ void light_compute(vec3 normal, vec3 light_vec,vec3 eye_vec,vec3 diffuse_color, } +float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) { + + return textureProj(shadow,vec4(pos,depth,1.0)); +} + +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + +in highp float dp_clip; + +#endif + void main() { +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + + if (dp_clip>0.0) + discard; +#endif + //lay out everything, whathever is unused is optimized away anyway - vec3 vertex = vertex_interp; + highp vec3 vertex = vertex_interp; vec3 albedo = vec3(0.8,0.8,0.8); vec3 specular = vec3(0.2,0.2,0.2); float roughness = 1.0; @@ -528,27 +561,216 @@ FRAGMENT_SHADER_CODE #endif -#ifdef USE_FORWARD_LIGHTING - #ifdef USE_FORWARD_DIRECTIONAL - light_compute(normal,light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,1.0,diffuse_light,specular_light); + float light_attenuation=1.0; + +#ifdef LIGHT_DIRECTIONAL_SHADOW + + if (gl_FragCoord.w > shadow_split_offsets.w) { + + vec3 pssm_coord; + +#ifdef LIGHT_USE_PSSM_BLEND + float pssm_blend; + vec3 pssm_coord2; + bool use_blend=true; + vec3 light_pssm_split_inv = 1.0/shadow_split_offsets.xyz; + float w_inv = 1.0/gl_FragCoord.w; #endif + +#ifdef LIGHT_USE_PSSM4 + + + if (gl_FragCoord.w > shadow_split_offsets.y) { + + if (gl_FragCoord.w > shadow_split_offsets.x) { + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + ambient_light=vec3(1.0,0.4,0.4); + + +#if defined(LIGHT_USE_PSSM_BLEND) + + splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif + + } else { + + highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + ambient_light=vec3(0.4,1.0,0.4); + +#if defined(LIGHT_USE_PSSM_BLEND) + splane=(shadow_matrix3 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv); +#endif + + } + } else { + + + if (gl_FragCoord.w > shadow_split_offsets.z) { + + highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + ambient_light=vec3(0.4,0.4,1.0); + +#if defined(LIGHT_USE_PSSM_BLEND) + splane=(shadow_matrix4 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv); +#endif + + } else { + highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + diffuse_light*=vec3(1.0,0.4,1.0); + +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend=false; + +#endif + + } + } + +#endif //LIGHT_USE_PSSM4 + +#ifdef LIGHT_USE_PSSM2 + + if (gl_FragCoord.w > shadow_split_offsets.x) { + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + + +#if defined(LIGHT_USE_PSSM_BLEND) + + splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif + + } else { + highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend=false; + +#endif + + } + +#endif //LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + { //regular orthogonal + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + } +#endif + + + //one one sample + light_attenuation=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp); + + +#if defined(LIGHT_USE_PSSM_BLEND) + if (use_blend) { + float light_attenuation2=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp); + light_attenuation=mix(light_attenuation,light_attenuation2,pssm_blend); + } +#endif + + } + +#endif //LIGHT_DIRECTIONAL_SHADOW + + light_compute(normal,-light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light); + + +#endif //USE_FORWARD_DIRECTIONAL + + #ifdef USE_FORWARD_OMNI vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex; float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w; float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w ); + + if (light_params.w>0.5) { + //there is a shadowmap + + highp vec3 splane=(shadow_matrix1 * vec4(vertex,1.0)).xyz; + float shadow_len=length(splane); + splane=normalize(splane); + vec4 clamp_rect=light_clamp; + + if (splane.z>=0.0) { + + splane.z+=1.0; + + clamp_rect.y+=clamp_rect.w; + + } else { + + splane.z=1.0 - splane.z; + + //if (clamp_rect.z0.5) { + //there is a shadowmap + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + splane.xyz/=splane.w; + // splane.xy=splane.xy*0.5+0.5; + + //splane.xy=light_clamp.xy+splane.xy*light_clamp.zw; + light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,light_clamp); + + } + + light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light); + +#endif //USE_FORWARD_SPOT -#endif #if defined(USE_LIGHT_SHADER_CODE) @@ -560,6 +782,11 @@ LIGHT_SHADER_CODE } #endif +#ifdef RENDER_SHADOW +//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) +#else + + #ifdef USE_MULTIPLE_RENDER_TARGETS //approximate ambient scale for SSAO, since we will lack full ambient @@ -574,13 +801,17 @@ LIGHT_SHADER_CODE #else + #ifdef SHADELESS frag_color=vec4(albedo,alpha); #else frag_color=vec4(ambient_light+diffuse_light+specular_light,alpha); -#endif +#endif //SHADELESS + +#endif //USE_MULTIPLE_RENDER_TARGETS + +#endif //RENDER_SHADOW -#endif } diff --git a/main/main.cpp b/main/main.cpp index 912e8adf4..bd4af2e79 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1296,6 +1296,17 @@ bool Main::start() { appname = TranslationServer::get_singleton()->translate(appname); OS::get_singleton()->set_window_title(appname); + int shadow_atlas_size = GLOBAL_DEF("rendering/shadow_atlas/size",2048); + int shadow_atlas_q0_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2); + int shadow_atlas_q1_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2); + int shadow_atlas_q2_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3); + int shadow_atlas_q3_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4); + + sml->get_root()->set_shadow_atlas_size(shadow_atlas_size); + sml->get_root()->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q0_subdiv)); + sml->get_root()->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q1_subdiv)); + sml->get_root()->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q2_subdiv)); + sml->get_root()->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q3_subdiv)); } else { GLOBAL_DEF("display/stretch_mode","disabled"); @@ -1304,7 +1315,17 @@ bool Main::start() { Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height")); sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true)); - + GLOBAL_DEF("rendering/shadow_atlas/size",2048); + Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/size",PropertyInfo(Variant::INT,"rendering/shadow_atlas/size",PROPERTY_HINT_RANGE,"256,16384")); + + GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2); + GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2); + GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3); + GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4); + Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_0_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_0_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_1_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_1_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_2_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_2_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_3_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_3_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); } diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 88ba7b373..cfc829078 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -202,7 +202,7 @@ void Light::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::BOOL, "light/negative"), _SCS("set_negative"), _SCS("is_negative")); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/specular"), _SCS("set_param"), _SCS("get_param"), PARAM_SPECULAR); ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask"), _SCS("set_cull_mask"), _SCS("get_cull_mask")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow")); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkness"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_DARKNESS); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/normal_bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_NORMAL_BIAS); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS); @@ -222,7 +222,6 @@ void Light::_bind_methods() { BIND_CONSTANT( PARAM_SHADOW_SPLIT_1_OFFSET ); BIND_CONSTANT( PARAM_SHADOW_SPLIT_2_OFFSET ); BIND_CONSTANT( PARAM_SHADOW_SPLIT_3_OFFSET ); - BIND_CONSTANT( PARAM_SHADOW_SPLIT_4_OFFSET ); BIND_CONSTANT( PARAM_SHADOW_NORMAL_BIAS ); BIND_CONSTANT( PARAM_SHADOW_BIAS ); BIND_CONSTANT( PARAM_SHADOW_BIAS_SPLIT_SCALE ); @@ -255,7 +254,6 @@ Light::Light(VisualServer::LightType p_type) { set_param(PARAM_SHADOW_SPLIT_1_OFFSET,0.1); set_param(PARAM_SHADOW_SPLIT_2_OFFSET,0.2); set_param(PARAM_SHADOW_SPLIT_3_OFFSET,0.5); - set_param(PARAM_SHADOW_SPLIT_4_OFFSET,1.0); set_param(PARAM_SHADOW_NORMAL_BIAS,0.1); set_param(PARAM_SHADOW_BIAS,0.1); set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE,0.1); @@ -279,36 +277,107 @@ Light::~Light() { } ///////////////////////////////////////// +void DirectionalLight::set_shadow_mode(ShadowMode p_mode) { + + shadow_mode=p_mode; + VS::get_singleton()->light_directional_set_shadow_mode(light,VS::LightDirectionalShadowMode(p_mode)); +} + +DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const { + + return shadow_mode; +} + +void DirectionalLight::set_blend_splits(bool p_enable) { + + blend_splits=p_enable; +} + +bool DirectionalLight::is_blend_splits_enabled() const { + + return blend_splits; +} + void DirectionalLight::_bind_methods() { + ObjectTypeDB::bind_method( _MD("set_shadow_mode","mode"),&DirectionalLight::set_shadow_mode); + ObjectTypeDB::bind_method( _MD("get_shadow_mode"),&DirectionalLight::get_shadow_mode); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_4"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_4_OFFSET); + ObjectTypeDB::bind_method( _MD("set_blend_splits","enabled"),&DirectionalLight::set_blend_splits); + ObjectTypeDB::bind_method( _MD("is_blend_splits_enabled"),&DirectionalLight::is_blend_splits_enabled); + + ADD_PROPERTY( PropertyInfo( Variant::INT, "directional/shadow_mode",PROPERTY_HINT_ENUM,"Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "directional/blend_splits"), _SCS("set_blend_splits"), _SCS("is_blend_splits_enabled")); + + BIND_CONSTANT( SHADOW_ORTHOGONAL ); + BIND_CONSTANT( SHADOW_PARALLEL_2_SPLITS ); + BIND_CONSTANT( SHADOW_PARALLEL_4_SPLITS ); } DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL ) { + set_shadow_mode(SHADOW_PARALLEL_4_SPLITS); + blend_splits=false; +} +void OmniLight::set_shadow_mode(ShadowMode p_mode) { + shadow_mode=p_mode; + VS::get_singleton()->light_omni_set_shadow_mode(light,VS::LightOmniShadowMode(p_mode)); } +OmniLight::ShadowMode OmniLight::get_shadow_mode() const{ + + return shadow_mode; +} + +void OmniLight::set_shadow_detail(ShadowDetail p_detail){ + + shadow_detail=p_detail; + VS::get_singleton()->light_omni_set_shadow_detail(light,VS::LightOmniShadowDetail(p_detail)); +} +OmniLight::ShadowDetail OmniLight::get_shadow_detail() const{ + + return shadow_detail; +} + + + void OmniLight::_bind_methods() { - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); + ObjectTypeDB::bind_method( _MD("set_shadow_mode","mode"),&OmniLight::set_shadow_mode); + ObjectTypeDB::bind_method( _MD("get_shadow_mode"),&OmniLight::get_shadow_mode); + + ObjectTypeDB::bind_method( _MD("set_shadow_detail","detail"),&OmniLight::set_shadow_detail); + ObjectTypeDB::bind_method( _MD("get_shadow_detail"),&OmniLight::get_shadow_detail); + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); + ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_mode",PROPERTY_HINT_ENUM,"Dual Paraboloid,Cube"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_detail",PROPERTY_HINT_ENUM,"Vertical,Horizontal"), _SCS("set_shadow_detail"), _SCS("get_shadow_detail")); + +} + +OmniLight::OmniLight() : Light( VisualServer::LIGHT_OMNI ) { + + set_shadow_mode(SHADOW_DUAL_PARABOLOID); + set_shadow_detail(SHADOW_DETAIL_HORIZONTAL); } void SpotLight::_bind_methods() { - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION); } diff --git a/scene/3d/light.h b/scene/3d/light.h index 7da2d8e7c..da2854281 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -45,22 +45,21 @@ class Light : public VisualInstance { public: enum Param { - PARAM_ENERGY, - PARAM_SPECULAR, - PARAM_RANGE, - PARAM_ATTENUATION, - PARAM_SPOT_ANGLE, - PARAM_SPOT_ATTENUATION, - PARAM_SHADOW_MAX_DISTANCE, - PARAM_SHADOW_DARKNESS, - PARAM_SHADOW_SPLIT_1_OFFSET, - PARAM_SHADOW_SPLIT_2_OFFSET, - PARAM_SHADOW_SPLIT_3_OFFSET, - PARAM_SHADOW_SPLIT_4_OFFSET, - PARAM_SHADOW_NORMAL_BIAS, - PARAM_SHADOW_BIAS, - PARAM_SHADOW_BIAS_SPLIT_SCALE, - PARAM_MAX + PARAM_ENERGY = VS::LIGHT_PARAM_ENERGY, + PARAM_SPECULAR = VS::LIGHT_PARAM_SPECULAR, + PARAM_RANGE = VS::LIGHT_PARAM_RANGE, + PARAM_ATTENUATION = VS::LIGHT_PARAM_ATTENUATION, + PARAM_SPOT_ANGLE = VS::LIGHT_PARAM_SPOT_ANGLE, + PARAM_SPOT_ATTENUATION = VS::LIGHT_PARAM_SPOT_ATTENUATION, + PARAM_SHADOW_MAX_DISTANCE = VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE, + PARAM_SHADOW_DARKNESS = VS::LIGHT_PARAM_SHADOW_DARKNESS, + PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET, + PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET, + PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET, + PARAM_SHADOW_NORMAL_BIAS = VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS, + PARAM_SHADOW_BIAS = VS::LIGHT_PARAM_SHADOW_BIAS, + PARAM_SHADOW_BIAS_SPLIT_SCALE = VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE, + PARAM_MAX = VS::LIGHT_PARAM_MAX }; private: @@ -126,31 +125,69 @@ class DirectionalLight : public Light { public: + enum ShadowMode { + SHADOW_ORTHOGONAL, + SHADOW_PARALLEL_2_SPLITS, + SHADOW_PARALLEL_4_SPLITS + }; private: + bool blend_splits; + ShadowMode shadow_mode; protected: static void _bind_methods(); public: + void set_shadow_mode(ShadowMode p_mode); + ShadowMode get_shadow_mode() const; + + void set_blend_splits(bool p_enable); + bool is_blend_splits_enabled() const; DirectionalLight(); }; +VARIANT_ENUM_CAST(DirectionalLight::ShadowMode) class OmniLight : public Light { OBJ_TYPE( OmniLight, Light ); +public: + // omni light + enum ShadowMode { + SHADOW_DUAL_PARABOLOID, + SHADOW_CUBE, + }; + + // omni light + enum ShadowDetail { + SHADOW_DETAIL_VERTICAL, + SHADOW_DETAIL_HORIZONTAL + }; + +private: + + ShadowMode shadow_mode; + ShadowDetail shadow_detail; protected: static void _bind_methods(); public: + void set_shadow_mode(ShadowMode p_mode); + ShadowMode get_shadow_mode() const; - OmniLight() : Light( VisualServer::LIGHT_OMNI ) { } + void set_shadow_detail(ShadowDetail p_detail); + ShadowDetail get_shadow_detail() const; + + OmniLight(); }; +VARIANT_ENUM_CAST(OmniLight::ShadowMode) +VARIANT_ENUM_CAST(OmniLight::ShadowDetail) + class SpotLight : public Light { OBJ_TYPE( SpotLight, Light ); diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 386a0fab5..5e1bda343 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -201,7 +201,7 @@ Ref NavigationMesh::get_debug_mesh() { arr.resize(Mesh::ARRAY_MAX); arr[Mesh::ARRAY_VERTEX]=varr; - debug_mesh->add_surface(Mesh::PRIMITIVE_LINES,arr); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,arr); return debug_mesh; } diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index cfc675337..ef619244d 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -845,7 +845,7 @@ Ref SceneTree::get_debug_contact_mesh() { arr[Mesh::ARRAY_INDEX]=indices; - debug_contact_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr); + debug_contact_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr); debug_contact_mesh->surface_set_material(0,mat); return debug_contact_mesh; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 35f72c5ce..0ca72eaa2 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1297,6 +1297,39 @@ bool Viewport::get_clear_on_new_frame() const{ return clear_on_new_frame; } +void Viewport::set_shadow_atlas_size(int p_size) { + + shadow_atlas_size=p_size; + VS::get_singleton()->viewport_set_shadow_atlas_size(viewport,p_size); +} + +int Viewport::get_shadow_atlas_size() const{ + + return shadow_atlas_size; +} + +void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant,ShadowAtlasQuadrantSubdiv p_subdiv){ + + + ERR_FAIL_INDEX(p_quadrant,4); + ERR_FAIL_INDEX(p_subdiv,SHADOW_ATLAS_QUADRANT_SUBDIV_MAX); + + if (shadow_atlas_quadrant_subdiv[p_quadrant]==p_subdiv) + return; + + shadow_atlas_quadrant_subdiv[p_quadrant]=p_subdiv; + static const int subdiv[SHADOW_ATLAS_QUADRANT_SUBDIV_MAX]={0,1,4,16,64,256,1024}; + + VS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport,p_quadrant,subdiv[p_subdiv]); + +} +Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const{ + + ERR_FAIL_INDEX_V(p_quadrant,4,SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED); + return shadow_atlas_quadrant_subdiv[p_quadrant]; +} + + void Viewport::clear() { //clear=true; @@ -2661,6 +2694,12 @@ void Viewport::_bind_methods() { ObjectTypeDB::bind_method(_MD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip); ObjectTypeDB::bind_method(_MD("_gui_remove_focus"), &Viewport::_gui_remove_focus); + ObjectTypeDB::bind_method(_MD("set_shadow_atlas_size","size"), &Viewport::set_shadow_atlas_size); + ObjectTypeDB::bind_method(_MD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size); + + ObjectTypeDB::bind_method(_MD("set_shadow_atlas_quadrant_subdiv","quadrant","subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv); + ObjectTypeDB::bind_method(_MD("get_shadow_atlas_quadrant_subdiv","quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv); + ADD_PROPERTY( PropertyInfo(Variant::RECT2,"size"), _SCS("set_size"), _SCS("get_size") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"own_world"), _SCS("set_use_own_world"), _SCS("is_using_own_world") ); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world",PROPERTY_HINT_RESOURCE_TYPE,"World"), _SCS("set_world"), _SCS("get_world") ); @@ -2674,6 +2713,11 @@ void Viewport::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::BOOL,"physics/object_picking"), _SCS("set_physics_object_picking"), _SCS("get_physics_object_picking") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gui/disable_input"), _SCS("set_disable_input"), _SCS("is_input_disabled") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"3d/disable_3d"), _SCS("set_disable_3d"), _SCS("is_3d_disabled") ); + ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow_atlas/size"), _SCS("set_shadow_atlas_size"), _SCS("get_shadow_atlas_size") ); + ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_0",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),0 ); + ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_1",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),1 ); + ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_2",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),2 ); + ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_3",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),3 ); ADD_SIGNAL(MethodInfo("size_changed")); @@ -2682,6 +2726,14 @@ void Viewport::_bind_methods() { BIND_CONSTANT( UPDATE_WHEN_VISIBLE ); BIND_CONSTANT( UPDATE_ALWAYS ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_1 ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_4 ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_16 ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_64 ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_256 ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_1024 ); + BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_MAX ); } @@ -2719,6 +2771,15 @@ Viewport::Viewport() { physics_object_over=0; physics_last_mousepos=Vector2(1e20,1e20); + shadow_atlas_size=0; + for(int i=0;i<4;i++) { + shadow_atlas_quadrant_subdiv[0]=SHADOW_ATLAS_QUADRANT_SUBDIV_MAX; + } + set_shadow_atlas_quadrant_subdiv(0,SHADOW_ATLAS_QUADRANT_SUBDIV_4); + set_shadow_atlas_quadrant_subdiv(1,SHADOW_ATLAS_QUADRANT_SUBDIV_4); + set_shadow_atlas_quadrant_subdiv(2,SHADOW_ATLAS_QUADRANT_SUBDIV_16); + set_shadow_atlas_quadrant_subdiv(3,SHADOW_ATLAS_QUADRANT_SUBDIV_64); + String id=itos(get_instance_ID()); input_group = "_vp_input"+id; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index c5d61469d..462ecff93 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -86,6 +86,18 @@ public: UPDATE_ALWAYS }; + enum ShadowAtlasQuadrantSubdiv { + SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED, + SHADOW_ATLAS_QUADRANT_SUBDIV_1, + SHADOW_ATLAS_QUADRANT_SUBDIV_4, + SHADOW_ATLAS_QUADRANT_SUBDIV_16, + SHADOW_ATLAS_QUADRANT_SUBDIV_64, + SHADOW_ATLAS_QUADRANT_SUBDIV_256, + SHADOW_ATLAS_QUADRANT_SUBDIV_1024, + SHADOW_ATLAS_QUADRANT_SUBDIV_MAX, + + }; + private: friend class ViewportTexture; @@ -120,8 +132,6 @@ friend class ViewportTexture; RID contact_3d_debug_multimesh; RID contact_3d_debug_instance; - - bool size_override; bool size_override_stretch; Size2 size_override_size; @@ -175,6 +185,9 @@ friend class ViewportTexture; RID texture_rid; Ref texture; + int shadow_atlas_size; + ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4]; + struct GUI { // info used when this is a window @@ -347,6 +360,11 @@ public: UpdateMode get_update_mode() const; Ref get_texture() const; + void set_shadow_atlas_size(int p_size); + int get_shadow_atlas_size() const; + + void set_shadow_atlas_quadrant_subdiv(int p_quadrant,ShadowAtlasQuadrantSubdiv p_subdiv); + ShadowAtlasQuadrantSubdiv get_shadow_atlas_quadrant_subdiv(int p_quadrant) const; Vector2 get_camera_coords(const Vector2& p_viewport_coords) const; Vector2 get_camera_rect_size() const; @@ -393,4 +411,6 @@ public: }; VARIANT_ENUM_CAST(Viewport::UpdateMode); +VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv); + #endif diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 3c7b0fbe6..cb55f4f03 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -152,7 +152,7 @@ void FixedSpatialMaterial::_update_shader() { switch(cull_mode) { case CULL_BACK: code+=",cull_back"; break; case CULL_FRONT: code+=",cull_front"; break; - case CULL_DISABLED: code+=",cull_disable"; break; + case CULL_DISABLED: code+=",cull_disabled"; break; } diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 132ec54e4..e737c5c37 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -125,11 +125,61 @@ bool Mesh::_set(const StringName& p_name, const Variant& p_value) { //create Dictionary d=p_value; ERR_FAIL_COND_V(!d.has("primitive"),false); - ERR_FAIL_COND_V(!d.has("arrays"),false); - ERR_FAIL_COND_V(!d.has("morph_arrays"),false); + + if (d.has("arrays")) { + //old format + ERR_FAIL_COND_V(!d.has("morph_arrays"),false); + add_surface_from_arrays(PrimitiveType(int(d["primitive"])),d["arrays"],d["morph_arrays"]); + + } else if (d.has("array_data")) { + + DVector array_data = d["array_data"]; + DVector array_index_data; + if (d.has("array_index_data")) + array_index_data=d["array_index_data"]; + + ERR_FAIL_COND_V(!d.has("format"),false); + uint32_t format = d["format"]; + + ERR_FAIL_COND_V(!d.has("primitive"),false); + uint32_t primitive = d["primitive"]; + + ERR_FAIL_COND_V(!d.has("vertex_count"),false); + int vertex_count = d["vertex_count"]; + + int index_count=0; + if (d.has("index_count")) + index_count=d["index_count"]; + + Vector< DVector > morphs; + + if (d.has("morph_data")) { + Array morph_data=d["morph_data"]; + for(int i=0;i morph = morph_data[i]; + morphs.push_back(morph_data[i]); + } + } + + ERR_FAIL_COND_V(!d.has("aabb"),false); + AABB aabb = d["aabb"]; + + Vector bone_aabb; + if (d.has("bone_aabb")) { + Array baabb = d["bone_aabb"]; + bone_aabb.resize(baabb.size()); + + for(int i=0;imesh_surface_get_array(mesh,idx); + d["vertex_count"]=VS::get_singleton()->mesh_surface_get_array_len(mesh,idx); + d["array_index_data"]=VS::get_singleton()->mesh_surface_get_index_array(mesh,idx); + d["index_count"]=VS::get_singleton()->mesh_surface_get_array_index_len(mesh,idx); + d["primitive"]=VS::get_singleton()->mesh_surface_get_primitive_type(mesh,idx); + d["format"]=VS::get_singleton()->mesh_surface_get_format(mesh,idx); + d["aabb"]=VS::get_singleton()->mesh_surface_get_aabb(mesh,idx); + + Vector skel_aabb = VS::get_singleton()->mesh_surface_get_skeleton_aabb(mesh,idx); + Array arr; + for(int i=0;i > morph_data = VS::get_singleton()->mesh_surface_get_blend_shapes(mesh,idx); + + Array md; + for(int i=0;i m = surface_get_material(idx); if (m.is_valid()) d["material"]=m; @@ -234,7 +306,17 @@ void Mesh::_recompute_aabb() { } -void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes) { +void Mesh::add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const AABB& p_aabb,const Vector >& p_blend_shapes,const Vector& p_bone_aabbs) { + + Surface s; + s.aabb=p_aabb; + surfaces.push_back(s); + + VisualServer::get_singleton()->mesh_add_surface(mesh,p_format,(VS::PrimitiveType)p_primitive,p_array,p_vertex_count,p_index_array,p_index_count,p_aabb,p_blend_shapes,p_bone_aabbs); + +} + +void Mesh::add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes) { ERR_FAIL_COND(p_arrays.size()!=ARRAY_MAX); @@ -279,8 +361,7 @@ void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Arr Array Mesh::surface_get_arrays(int p_surface) const { ERR_FAIL_INDEX_V(p_surface,surfaces.size(),Array()); - //return VisualServer::get_singleton()->mesh_get_surface_arrays(mesh,p_surface); - return Array(); + return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh,p_surface); } Array Mesh::surface_get_morph_arrays(int p_surface) const { @@ -929,7 +1010,7 @@ Ref Mesh::create_outline(float p_margin) const { Ref newmesh = memnew( Mesh ); - newmesh->add_surface(PRIMITIVE_TRIANGLES,arrays); + newmesh->add_surface_from_arrays(PRIMITIVE_TRIANGLES,arrays); return newmesh; } @@ -943,6 +1024,7 @@ void Mesh::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_morph_target_mode","mode"),&Mesh::set_morph_target_mode); ObjectTypeDB::bind_method(_MD("get_morph_target_mode"),&Mesh::get_morph_target_mode); + ObjectTypeDB::bind_method(_MD("add_surface_from_arrays","primitive","arrays","blend_shapes"),&Mesh::add_surface_from_arrays,DEFVAL(Array())); ObjectTypeDB::bind_method(_MD("get_surface_count"),&Mesh::get_surface_count); ObjectTypeDB::bind_method(_MD("surface_remove","surf_idx"),&Mesh::surface_remove); ObjectTypeDB::bind_method(_MD("surface_get_array_len","surf_idx"),&Mesh::surface_get_array_len); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index e329c353a..2b28f1187 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -122,7 +122,9 @@ protected: public: - void add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array()); + void add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array()); + void add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const AABB& p_aabb,const Vector >& p_blend_shapes=Vector >(),const Vector& p_bone_aabbs=Vector()); + Array surface_get_arrays(int p_surface) const; virtual Array surface_get_morph_arrays(int p_surface) const; diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index fb0fc2a24..758d78e51 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -328,7 +328,7 @@ Error MeshDataTool::commit_to_surface(const Ref& p_mesh) { Ref ncmesh=p_mesh; int sc = ncmesh->get_surface_count(); - ncmesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr); + ncmesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr); ncmesh->surface_set_material(sc,material); return OK; diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp index a71e414f6..778764a83 100644 --- a/scene/resources/shape.cpp +++ b/scene/resources/shape.cpp @@ -77,7 +77,7 @@ Ref Shape::get_debug_mesh() { SceneTree *st=OS::get_singleton()->get_main_loop()->cast_to(); - debug_mesh_cache->add_surface(Mesh::PRIMITIVE_LINES,arr); + debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,arr); if (st) { debug_mesh_cache->surface_set_material(0,st->get_debug_collision_material()); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index e1769d099..6f08d6922 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -410,7 +410,7 @@ Ref SurfaceTool::commit(const Ref& p_existing) { } - mesh->add_surface(primitive,a); + mesh->add_surface_from_arrays(primitive,a); if (material.is_valid()) mesh->surface_set_material(surface,material); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index feaac38ac..d87cc0fd8 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -39,6 +39,16 @@ class RasterizerScene { public: + /* SHADOW ATLAS API */ + + virtual RID shadow_atlas_create()=0; + virtual void shadow_atlas_set_size(RID p_atlas,int p_size)=0; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision)=0; + virtual bool shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version)=0; + + virtual int get_directional_light_shadow_size(RID p_light_intance)=0; + virtual void set_directional_shadow_count(int p_count)=0; + /* ENVIRONMENT API */ virtual RID environment_create()=0; @@ -93,6 +103,7 @@ public: virtual void base_removed()=0; virtual void base_changed()=0; + virtual void base_material_changed()=0; InstanceBase() : dependency_item(this) { @@ -109,10 +120,11 @@ public: virtual RID light_instance_create(RID p_light)=0; virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform)=0; + virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass)=0; virtual void light_instance_mark_visible(RID p_light_instance)=0; - - virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment)=0; + virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas)=0; + virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count)=0; virtual void set_scene_pass(uint64_t p_pass)=0; @@ -179,6 +191,12 @@ public: virtual void material_set_line_width(RID p_material, float p_width)=0; + virtual bool material_is_animated(RID p_material)=0; + virtual bool material_casts_shadows(RID p_material)=0; + + virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance)=0; + virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance)=0; + /* MESH API */ virtual RID mesh_create()=0; @@ -205,6 +223,10 @@ public: virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const=0; virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const=0; + virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const=0; + virtual Vector > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const=0; + virtual Vector mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const=0; + virtual void mesh_remove_surface(RID p_mesh,int p_index)=0; virtual int mesh_get_surface_count(RID p_mesh) const=0; @@ -279,10 +301,21 @@ public: virtual void light_set_cull_mask(RID p_light,uint32_t p_mask)=0; virtual void light_set_shader(RID p_light,RID p_shader)=0; + virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode)=0; + virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail)=0; + virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode)=0; + virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light)=0; + virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light)=0; + + virtual bool light_has_shadow(RID p_light) const=0; + virtual VS::LightType light_get_type(RID p_light) const=0; virtual AABB light_get_aabb(RID p_light) const=0; + virtual float light_get_param(RID p_light,VS::LightParam p_param)=0; + virtual uint64_t light_get_version(RID p_light) const=0; + /* PROBE API */ diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 8c54ef11f..8a0818c29 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -84,7 +84,7 @@ ShaderTypes::ShaderTypes() shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_front"); shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_back"); - shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_disable"); + shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_disabled"); shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded"); shader_modes[VS::SHADER_SPATIAL].modes.insert("ontop"); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 6c7048bd6..7810cc901 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -687,6 +687,10 @@ public: BIND2RC(uint32_t,mesh_surface_get_format,RID,int) BIND2RC(PrimitiveType,mesh_surface_get_primitive_type,RID,int) + BIND2RC(AABB,mesh_surface_get_aabb,RID,int) + BIND2RC(Vector >,mesh_surface_get_blend_shapes,RID,int) + BIND2RC(Vector,mesh_surface_get_skeleton_aabb,RID,int) + BIND2(mesh_remove_surface,RID,int) BIND1RC(int,mesh_get_surface_count,RID) @@ -759,6 +763,9 @@ public: BIND2(light_set_cull_mask,RID ,uint32_t ) BIND2(light_set_shader,RID ,RID ) + BIND2(light_omni_set_shadow_mode,RID,LightOmniShadowMode) + BIND2(light_omni_set_shadow_detail,RID,LightOmniShadowDetail) + BIND2(light_directional_set_shadow_mode,RID,LightDirectionalShadowMode) /* PROBE API */ @@ -847,7 +854,8 @@ public: BIND2(viewport_set_global_canvas_transform,RID,const Matrix32& ) BIND3(viewport_set_canvas_layer,RID ,RID ,int ) - + BIND2(viewport_set_shadow_atlas_size,RID ,int ) + BIND3(viewport_set_shadow_atlas_quadrant_subdivision,RID ,int, int ) /* ENVIRONMENT API */ diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index e7900bdcc..e36e31e19 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -96,7 +96,10 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance List::Element *E = light->geometries.push_back(pinfo); - light->shadow_sirty=true; + if (geom->can_cast_shadows) { + + light->shadow_dirty=true; + } geom->lighting_dirty=true; return E; //this element should make freeing faster @@ -180,7 +183,9 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance geom->lighting.erase(E->get().L); light->geometries.erase(E); - light->shadow_sirty=true; + if (geom->can_cast_shadows) { + light->shadow_dirty=true; + } geom->lighting_dirty=true; @@ -346,6 +351,12 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ } instance->morph_values.clear(); + + for(int i=0;imaterials.size();i++) { + if (instance->materials[i].is_valid()) { + VSG::storage->material_remove_instance_owner(instance->materials[i],instance); + } + } instance->materials.clear(); #if 0 @@ -667,7 +678,16 @@ void VisualServerScene::instance_set_surface_material(RID p_instance,int p_surfa ERR_FAIL_INDEX(p_surface,instance->materials.size()); + if (instance->materials[p_surface].is_valid()) { + VSG::storage->material_remove_instance_owner(instance->materials[p_surface],instance); + } instance->materials[p_surface]=p_material; + instance->base_material_changed(); + + if (instance->materials[p_surface].is_valid()) { + VSG::storage->material_add_instance_owner(instance->materials[p_surface],instance); + } + } @@ -791,12 +811,14 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance,VS::InstanceFl } break; case VS::INSTANCE_FLAG_CAST_SHADOW: { - /*if (p_enabled == true) { - instance->cast_shadows = SHADOW_CASTING_SETTING_ON; + if (p_enabled == true) { + instance->cast_shadows = VS::SHADOW_CASTING_SETTING_ON; } else { - instance->cast_shadows = SHADOW_CASTING_SETTING_OFF; - }*/ + instance->cast_shadows = VS::SHADOW_CASTING_SETTING_OFF; + } + + instance->base_material_changed(); // to actually compute if shadows are visible or not } break; case VS::INSTANCE_FLAG_DEPH_SCALE: { @@ -820,8 +842,15 @@ void VisualServerScene::instance_geometry_set_material_override(RID p_instance, Instance *instance = instance_owner.get( p_instance ); ERR_FAIL_COND( !instance ); + if (instance->material_override.is_valid()) { + VSG::storage->material_remove_instance_owner(instance->material_override,instance); + } instance->material_override=p_material; + instance->base_material_changed(); + if (instance->material_override.is_valid()) { + VSG::storage->material_add_instance_owner(instance->material_override,instance); + } } @@ -843,6 +872,7 @@ void VisualServerScene::_update_instance(Instance *p_instance) { InstanceLightData *light = static_cast(p_instance->base_data); VSG::scene_render->light_instance_set_transform( light->instance, p_instance->transform ); + light->shadow_dirty=true; } @@ -860,11 +890,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) { if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { InstanceGeometryData *geom = static_cast(p_instance->base_data); - //make sure lights are updated + //make sure lights are updated if it casts shadow - for (List::Element *E=geom->lighting.front();E;E=E->next()) { - InstanceLightData *light = static_cast(E->get()->base_data); - light->shadow_sirty=true; + if (geom->can_cast_shadows) { + for (List::Element *E=geom->lighting.front();E;E=E->next()) { + InstanceLightData *light = static_cast(E->get()->base_data); + light->shadow_dirty=true; + } } } @@ -1095,9 +1127,371 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { -void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size) { +void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect) { + + + InstanceLightData * light = static_cast(p_instance->base_data); + + switch(VSG::storage->light_get_type(p_instance->base)) { + + case VS::LIGHT_DIRECTIONAL: { + + float max_distance = p_camera->zfar; + float shadow_max = VSG::storage->light_get_param(p_instance->base,VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); + if (shadow_max>0) { + max_distance=MIN(shadow_max,max_distance); + } + max_distance=MAX(max_distance,p_camera->znear+0.001); + + float range = max_distance-p_camera->znear; + + int splits=0; + switch(VSG::storage->light_directional_get_shadow_mode(p_instance->base)) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: splits=1; break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: splits=2; break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: splits=4; break; + } + + float distances[5]; + + distances[0]=p_camera->znear; + for(int i=0;iznear+VSG::storage->light_get_param(p_instance->base,VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET+i))*range; + }; + + distances[splits]=max_distance; + + float texture_size=VSG::scene_render->get_directional_light_shadow_size(light->instance); + + bool overlap = false;//rasterizer->light_instance_get_pssm_shadow_overlap(p_light->light_info->instance); + + for (int i=0;itype) { + + case Camera::ORTHOGONAL: { + + camera_matrix.set_orthogonal( + p_camera->size, + p_viewport_rect.width / p_viewport_rect.height, + distances[(i==0 || !overlap )?i:i-1], + distances[i+1], + p_camera->vaspect + + ); + } break; + case Camera::PERSPECTIVE: { + + + camera_matrix.set_perspective( + p_camera->fov, + p_viewport_rect.width / (float)p_viewport_rect.height, + distances[(i==0 || !overlap )?i:i-1], + distances[i+1], + p_camera->vaspect + + ); + + } break; + } + + //obtain the frustum endpoints + + Vector3 endpoints[8]; // frustum plane endpoints + bool res = camera_matrix.get_endpoints(p_camera->transform,endpoints); + ERR_CONTINUE(!res); + + // obtain the light frustm ranges (given endpoints) + + Vector3 x_vec=p_instance->transform.basis.get_axis( Vector3::AXIS_X ).normalized(); + Vector3 y_vec=p_instance->transform.basis.get_axis( Vector3::AXIS_Y ).normalized(); + Vector3 z_vec=p_instance->transform.basis.get_axis( Vector3::AXIS_Z ).normalized(); + //z_vec points agsint the camera, like in default opengl + + float x_min,x_max; + float y_min,y_max; + float z_min,z_max; + + float x_min_cam,x_max_cam; + float y_min_cam,y_max_cam; + float z_min_cam,z_max_cam; + + + //used for culling + for(int j=0;j<8;j++) { + + float d_x=x_vec.dot(endpoints[j]); + float d_y=y_vec.dot(endpoints[j]); + float d_z=z_vec.dot(endpoints[j]); + + if (j==0 || d_xx_max) + x_max=d_x; + + if (j==0 || d_yy_max) + y_max=d_y; + + if (j==0 || d_zz_max) + z_max=d_z; + + + } + + + + + + { + //camera viewport stuff + //this trick here is what stabilizes the shadow (make potential jaggies to not move) + //at the cost of some wasted resolution. Still the quality increase is very well worth it + + + Vector3 center; + + for(int j=0;j<8;j++) { + + center+=endpoints[j]; + } + center/=8.0; + + //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5; + + float radius=0; + + for(int j=0;j<8;j++) { + + float d = center.distance_to(endpoints[j]); + if (d>radius) + radius=d; + } + + + radius *= texture_size/(texture_size-2.0); //add a texel by each side, so stepified texture will always fit + + x_max_cam=x_vec.dot(center)+radius; + x_min_cam=x_vec.dot(center)-radius; + y_max_cam=y_vec.dot(center)+radius; + y_min_cam=y_vec.dot(center)-radius; + z_max_cam=z_vec.dot(center)+radius; + z_min_cam=z_vec.dot(center)-radius; + + float unit = radius*2.0/texture_size; + + x_max_cam=Math::stepify(x_max_cam,unit); + x_min_cam=Math::stepify(x_min_cam,unit); + y_max_cam=Math::stepify(y_max_cam,unit); + y_min_cam=Math::stepify(y_min_cam,unit); + + } + + //now that we now all ranges, we can proceed to make the light frustum planes, for culling octree + + Vector light_frustum_planes; + light_frustum_planes.resize(6); + + //right/left + light_frustum_planes[0]=Plane( x_vec, x_max ); + light_frustum_planes[1]=Plane( -x_vec, -x_min ); + //top/bottom + light_frustum_planes[2]=Plane( y_vec, y_max ); + light_frustum_planes[3]=Plane( -y_vec, -y_min ); + //near/far + light_frustum_planes[4]=Plane( z_vec, z_max+1e6 ); + light_frustum_planes[5]=Plane( -z_vec, -z_min ); // z_min is ok, since casters further than far-light plane are not needed + + int cull_count = p_scenario->octree.cull_convex(light_frustum_planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK); + + // a pre pass will need to be needed to determine the actual z-near to be used + + + for (int j=0;jvisible || !((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows) { + cull_count--; + SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]); + j--; + + } + + instance->transformed_aabb.project_range_in_plane(Plane(z_vec,0),min,max); + if (max>z_max) + z_max=max; + } + + { + CameraMatrix ortho_camera; + real_t half_x = (x_max_cam-x_min_cam) * 0.5; + real_t half_y = (y_max_cam-y_min_cam) * 0.5; + + + ortho_camera.set_orthogonal( -half_x, half_x,-half_y,half_y, 0, (z_max-z_min_cam) ); + + Transform ortho_transform; + ortho_transform.basis=p_instance->transform.basis; + ortho_transform.origin=x_vec*(x_min_cam+half_x)+y_vec*(y_min_cam+half_y)+z_vec*z_max; + + VSG::scene_render->light_instance_set_shadow_transform(light->instance,ortho_camera,ortho_transform,0,distances[i+1],i); + } + + + + VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,i,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count); + + } + + } break; + case VS::LIGHT_OMNI: { + + VS::LightOmniShadowMode shadow_mode = VSG::storage->light_omni_get_shadow_mode(p_instance->base); + + switch(shadow_mode) { + case VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID: { + + for(int i=0;i<2;i++) { + + //using this one ensures that raster deferred will have it + + float radius = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_RANGE); + + float z =i==0?-1:1; + Vector planes; + planes.resize(5); + planes[0]=p_instance->transform.xform(Plane(Vector3(0,0,z),radius)); + planes[1]=p_instance->transform.xform(Plane(Vector3(1,0,z).normalized(),radius)); + planes[2]=p_instance->transform.xform(Plane(Vector3(-1,0,z).normalized(),radius)); + planes[3]=p_instance->transform.xform(Plane(Vector3(0,1,z).normalized(),radius)); + planes[4]=p_instance->transform.xform(Plane(Vector3(0,-1,z).normalized(),radius)); + + + int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK); + + for (int j=0;jvisible || !((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows) { + cull_count--; + SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]); + j--; + + } + } + + VSG::scene_render->light_instance_set_shadow_transform(light->instance,CameraMatrix(),p_instance->transform,radius,0,i); + VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,i,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count); + } + } break; + case VS::LIGHT_OMNI_SHADOW_CUBE: { + + float radius = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_RANGE); + CameraMatrix cm; + cm.set_perspective(90,1,0.01,radius); + + for(int i=0;i<6;i++) { + + //using this one ensures that raster deferred will have it + + + + static const Vector3 view_normals[6]={ + Vector3(-1, 0, 0), + Vector3(+1, 0, 0), + Vector3( 0,-1, 0), + Vector3( 0,+1, 0), + Vector3( 0, 0,-1), + Vector3( 0, 0,+1) + }; + static const Vector3 view_up[6]={ + Vector3( 0,-1, 0), + Vector3( 0,-1, 0), + Vector3( 0, 0,-1), + Vector3( 0, 0,+1), + Vector3( 0,-1, 0), + Vector3( 0,-1, 0) + }; + + Transform xform = p_instance->transform * Transform().looking_at(view_normals[i],view_up[i]); + + + Vector planes = cm.get_projection_planes(xform); + + int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK); + + for (int j=0;jvisible || !((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows) { + cull_count--; + SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]); + j--; + + } + } + + VSG::scene_render->light_instance_set_shadow_transform(light->instance,cm,xform,radius,0,i); + VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,i,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count); + } + + //restore the regular DP matrix + VSG::scene_render->light_instance_set_shadow_transform(light->instance,CameraMatrix(),p_instance->transform,radius,0,0); + + } break; + } + + + } break; + case VS::LIGHT_SPOT: { + + + float radius = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_RANGE); + float angle = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE); + + CameraMatrix cm; + cm.set_perspective( 90, 1.0, 0.01, radius ); + print_line("perspective: "+cm); + + Vector planes = cm.get_projection_planes(p_instance->transform); + int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK); + + for (int j=0;jvisible || !((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast(instance->base_data)->can_cast_shadows) { + cull_count--; + SWAP(instance_shadow_cull_result[j],instance_shadow_cull_result[cull_count]); + j--; + + } + } + + + print_line("MOMONGO"); + VSG::scene_render->light_instance_set_shadow_transform(light->instance,cm,p_instance->transform,radius,0,0); + VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,0,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count); + + } break; + } + +} + + + + + +void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size,RID p_shadow_atlas) { + Camera *camera = camera_owner.getornull(p_camera); ERR_FAIL_COND(!camera); @@ -1112,8 +1506,10 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp /* STEP 1 - SETUP CAMERA */ CameraMatrix camera_matrix; + Transform camera_inverse_xform = camera->transform.affine_inverse(); bool ortho=false; + switch(camera->type) { case Camera::ORTHOGONAL: { @@ -1268,12 +1664,14 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp //do not add this light if no geometry is affected by it.. light_cull_result[light_cull_count]=ins; light_instance_cull_result[light_cull_count]=light->instance; - VSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later + if (p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(ins->base)) { + VSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later + } light_cull_count++; } -// rasterizer->light_instance_set_active_hint(ins->light_info->instance); + } } else if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { @@ -1386,6 +1784,10 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp // directional lights { + + Instance** lights_with_shadow = (Instance**)alloca(sizeof(Instance*)*light_cull_count); + int directional_shadow_count=0; + for (List::Element *E=scenario->directional_lights.front();E;E=E->next()) { if (light_cull_count+directional_light_count>=MAX_LIGHTS_CULLED) { @@ -1401,42 +1803,142 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp //check shadow.. -/* if (light && light->light_info->enabled && rasterizer->light_has_shadow(light->base_rid)) { - //rasterizer->light_instance_set_active_hint(light->light_info->instance); - _light_instance_update_shadow(light,p_scenario,camera,cull_range); + if (light && VSG::storage->light_has_shadow(E->get()->base)) { + lights_with_shadow[directional_shadow_count++]=E->get(); + } -*/ //add to list - directional_light_ptr[directional_light_count++]=light->instance; + } + + VSG::scene_render->set_directional_shadow_count(directional_shadow_count); + + for(int i=0;i sorter; - sorter.sort(light_cull_result,light_cull_count); + + { //setup shadow maps + + //SortArray sorter; + //sorter.sort(light_cull_result,light_cull_count); for (int i=0;ilight_has_shadow(ins->base_rid) || !shadows_enabled) + if (!p_shadow_atlas.is_valid() || !VSG::storage->light_has_shadow(ins->base)) continue; - /* for far shadows? - if (ins->version == ins->light_info->last_version && rasterizer->light_instance_has_far_shadow(ins->light_info->instance)) - continue; // didn't change - */ + InstanceLightData * light = static_cast(ins->base_data); + + float coverage; + + { //compute coverage + + + Transform cam_xf = camera->transform; + float zn = camera_matrix.get_z_near(); + Plane p (cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2) ); //camera near plane + + float vp_w,vp_h; //near plane size in screen coordinates + camera_matrix.get_viewport_size(vp_w,vp_h); + + + switch(VSG::storage->light_get_type(ins->base)) { + + case VS::LIGHT_OMNI: { + + float radius = VSG::storage->light_get_param(ins->base,VS::LIGHT_PARAM_RANGE); + + //get two points parallel to near plane + Vector3 points[2]={ + ins->transform.origin, + ins->transform.origin+cam_xf.basis.get_axis(0)*radius + }; + + if (!ortho) { + //if using perspetive, map them to near plane + for(int j=0;j<2;j++) { + if (p.distance_to(points[j]) < 0 ) { + points[j].z=-zn; //small hack to keep size constant when hitting the screen + + } + + p.intersects_segment(cam_xf.origin,points[j],&points[j]); //map to plane + } + + + } + + float screen_diameter = points[0].distance_to(points[1])*2; + coverage = screen_diameter / (vp_w+vp_h); + } break; + case VS::LIGHT_SPOT: { + + float radius = VSG::storage->light_get_param(ins->base,VS::LIGHT_PARAM_RANGE); + float angle = VSG::storage->light_get_param(ins->base,VS::LIGHT_PARAM_SPOT_ANGLE); + + + float w = radius*Math::sin(Math::deg2rad(angle)); + float d = radius*Math::cos(Math::deg2rad(angle)); + + + Vector3 base = ins->transform.origin-ins->transform.basis.get_axis(2).normalized()*d; + + Vector3 points[2]={ + base, + base+cam_xf.basis.get_axis(0)*w + }; + + if (!ortho) { + //if using perspetive, map them to near plane + for(int j=0;j<2;j++) { + if (p.distance_to(points[j]) < 0 ) { + points[j].z=-zn; //small hack to keep size constant when hitting the screen + + } + + p.intersects_segment(cam_xf.origin,points[j],&points[j]); //map to plane + } + + + } + + float screen_diameter = points[0].distance_to(points[1])*2; + coverage = screen_diameter / (vp_w+vp_h); + + + } break; + default: { + ERR_PRINT("Invalid Light Type"); + } + } + + } + + + if (light->shadow_dirty) { + light->last_version++; + light->shadow_dirty=false; + } + + + + bool redraw = VSG::scene_render->shadow_atlas_update_light(p_shadow_atlas,light->instance,coverage,light->last_version); + + if (redraw) { + //must redraw! + _light_instance_update_shadow(ins,camera,p_shadow_atlas,scenario,p_viewport_size); + } - _light_instance_update_shadow(ins,p_scenario,camera,cull_range); - ins->light_info->last_version=ins->version; } } -#endif + /* ENVIRONMENT */ RID environment; @@ -1492,7 +1994,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp - VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count,directional_light_ptr,directional_light_count,environment); + VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count+directional_light_count,environment,p_shadow_atlas); + } @@ -1505,9 +2008,77 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { _update_instance_aabb(p_instance); if (p_instance->update_materials) { + if (p_instance->base_type==VS::INSTANCE_MESH) { - p_instance->materials.resize(VSG::storage->mesh_get_surface_count(p_instance->base)); + //remove materials no longer used and un-own them + + int new_mat_count = VSG::storage->mesh_get_surface_count(p_instance->base); + for(int i=p_instance->materials.size()-1;i>=new_mat_count;i--) { + if (p_instance->materials[i].is_valid()) { + VSG::storage->material_remove_instance_owner(p_instance->materials[i],p_instance); + } + } + p_instance->materials.resize(new_mat_count); + } + + if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceGeometryData *geom = static_cast(p_instance->base_data); + + bool can_cast_shadows=true; + + if (p_instance->cast_shadows==VS::SHADOW_CASTING_SETTING_OFF) { + can_cast_shadows=false; + } else if (p_instance->material_override.is_valid()) { + can_cast_shadows=VSG::storage->material_casts_shadows(p_instance->material_override); + } else { + + RID mesh; + + if (p_instance->base_type==VS::INSTANCE_MESH) { + mesh=p_instance->base; + } else if (p_instance->base_type==VS::INSTANCE_MULTIMESH) { + + } + + if (mesh.is_valid()) { + + bool cast_shadows=false; + + for(int i=0;imaterials.size();i++) { + + + RID mat = p_instance->materials[i].is_valid()?p_instance->materials[i]:VSG::storage->mesh_surface_get_material(mesh,i); + + if (!mat.is_valid()) { + cast_shadows=true; + break; + } + + if (VSG::storage->material_casts_shadows(mat)) { + cast_shadows=true; + break; + } + } + + if (!cast_shadows) { + can_cast_shadows=false; + } + } + + } + + if (can_cast_shadows!=geom->can_cast_shadows) { + //ability to cast shadows change, let lights now + for (List::Element *E=geom->lighting.front();E;E=E->next()) { + InstanceLightData *light = static_cast(E->get()->base_data); + light->shadow_dirty=true; + } + + geom->can_cast_shadows=can_cast_shadows; + } } + } _update_instance(p_instance); @@ -1557,6 +2128,7 @@ bool VisualServerScene::free(RID p_rid) { instance_set_room(p_rid,RID()); instance_set_scenario(p_rid,RID()); instance_set_base(p_rid,RID()); + instance_geometry_set_material_override(p_rid,RID()); if (instance->skeleton.is_valid()) instance_attach_skeleton(p_rid,RID()); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 10a159f27..1b62583dc 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -195,6 +195,7 @@ public: //aabb stuff bool update_aabb; bool update_materials; + SelfList update_item; @@ -232,6 +233,11 @@ public: singleton->_instance_queue_update(this,true,true); } + virtual void base_material_changed() { + + singleton->_instance_queue_update(this,false,true); + } + Instance() : scenario_item(this), update_item(this), room_item(this) { @@ -282,10 +288,12 @@ public: List lighting; bool lighting_dirty; + bool can_cast_shadows; InstanceGeometryData() { lighting_dirty=false; + can_cast_shadows=true; } }; @@ -298,18 +306,18 @@ public: }; RID instance; - uint64_t last_hash; + uint64_t last_version; List::Element *D; // directional light in scenario - bool shadow_sirty; + bool shadow_dirty; List geometries; InstanceLightData() { - shadow_sirty=true; + shadow_dirty=true; D=NULL; - last_hash=0; + last_version=0; } }; @@ -360,8 +368,9 @@ public: _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); + _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect); - void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size); + void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); bool free(RID p_rid); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 583b42bfc..18742aa21 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -64,7 +64,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { if (!p_viewport->disable_3d && p_viewport->camera.is_valid()) { - VSG::scene->render_camera(p_viewport->camera,p_viewport->scenario,p_viewport->size); + VSG::scene->render_camera(p_viewport->camera,p_viewport->scenario,p_viewport->size,p_viewport->shadow_atlas); } if (!p_viewport->hide_canvas) { @@ -287,7 +287,8 @@ RID VisualServerViewport::viewport_create() { viewport->self=rid; viewport->hide_scenario=false; viewport->hide_canvas=false; - viewport->render_target=VSG::storage->render_target_create(); + viewport->render_target=VSG::storage->render_target_create(); + viewport->shadow_atlas=VSG::scene_render->shadow_atlas_create(); return rid; @@ -496,6 +497,27 @@ void VisualServerViewport::viewport_set_canvas_layer(RID p_viewport,RID p_canvas } +void VisualServerViewport::viewport_set_shadow_atlas_size(RID p_viewport,int p_size) { + + Viewport * viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->shadow_atlas_size=p_size; + + VSG::scene_render->shadow_atlas_set_size( viewport->shadow_atlas, viewport->shadow_atlas_size); + +} + +void VisualServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport,int p_quadrant,int p_subdiv) { + + Viewport * viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + VSG::scene_render->shadow_atlas_set_quadrant_subdivision( viewport->shadow_atlas, p_quadrant, p_subdiv); + +} + + bool VisualServerViewport::free(RID p_rid) { Viewport * viewport = viewport_owner.getornull(p_rid); @@ -504,6 +526,7 @@ bool VisualServerViewport::free(RID p_rid) { VSG::storage->free( viewport->render_target ); + VSG::scene_render->free( viewport->shadow_atlas ); while(viewport->canvas_map.front()) { viewport_remove_canvas(p_rid,viewport->canvas_map.front()->key()); diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index cba33a3b2..a9b8fe4e9 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -36,6 +36,9 @@ public: bool disable_environment; bool disable_3d; + RID shadow_atlas; + int shadow_atlas_size; + VS::ViewportClearMode clear_mode; @@ -67,6 +70,7 @@ public: rendered_in_prev_frame=false; disable_environment=false; viewport_to_screen=0; + shadow_atlas_size=0; } }; @@ -129,6 +133,9 @@ public: void viewport_set_global_canvas_transform(RID p_viewport,const Matrix32& p_transform); void viewport_set_canvas_layer(RID p_viewport,RID p_canvas,int p_layer); + void viewport_set_shadow_atlas_size(RID p_viewport,int p_size); + void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport,int p_quadrant,int p_subdiv); + void draw_viewports(); bool free(RID p_rid); diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 95636d2bc..953448db5 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1021,7 +1021,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi break; } /* determine wether using 16 or 32 bits indices */ - if (array_len>(1<<16)) { + if (array_len>=(1<<16)) { elem_size=4; @@ -1089,6 +1089,454 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi } +Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector p_vertex_data,int p_vertex_len,DVector p_index_data,int p_index_len) const { + + + uint32_t offsets[ARRAY_MAX]; + + int total_elem_size=0; + + for (int i=0;i=(1<<16)) { + + elem_size=4; + + } else { + elem_size=2; + } + offsets[i]=elem_size; + continue; + } break; + default: { + ERR_FAIL_V( Array() ); + } + } + + offsets[i]=total_elem_size; + total_elem_size+=elem_size; + + + } + + Array ret; + ret.resize(VS::ARRAY_MAX); + + DVector::Read r = p_vertex_data.read(); + + for(int i=0;i arr_2d; + arr_2d.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_VERTEX) { + + DVector::Write w = arr_2d.write(); + + for(int j=0;j::Write w = arr_2d.write(); + + for(int j=0;j arr_3d; + arr_3d.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_VERTEX) { + + DVector::Write w = arr_3d.write(); + + for(int j=0;j::Write w = arr_3d.write(); + + for(int j=0;j arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_NORMAL) { + + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j arr; + arr.resize(p_vertex_len*4); + if (p_format&ARRAY_COMPRESS_TANGENT) { + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_COLOR) { + + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_TEX_UV) { + + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_TEX_UV2) { + + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j arr; + arr.resize(p_vertex_len*4); + if (p_format&ARRAY_COMPRESS_WEIGHTS) { + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j arr; + arr.resize(p_vertex_len*4); + if (p_format&ARRAY_FLAG_USE_16_BIT_BONES) { + + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j::Read ir = p_index_data.read(); + + DVector arr; + arr.resize(p_index_len); + if (p_index_len<(1<<16)) { + + DVector::Write w = arr.write(); + + for(int j=0;j::Write w = arr.write(); + + for(int j=0;j vertex_data = mesh_surface_get_array(p_mesh,p_surface); + ERR_FAIL_COND_V(vertex_data.size()==0,Array()); + int vertex_len = mesh_surface_get_array_len(p_mesh,p_surface); + + DVector index_data = mesh_surface_get_index_array(p_mesh,p_surface); + int index_len = mesh_surface_get_array_index_len(p_mesh,p_surface); + + uint32_t format = mesh_surface_get_format(p_mesh,p_surface); + + + return _get_array_from_surface(format,vertex_data,vertex_len,index_data,index_len); + +} + void VisualServer::_bind_methods() { diff --git a/servers/visual_server.h b/servers/visual_server.h index 78769c17f..c2d7aaece 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -51,6 +51,8 @@ class VisualServer : public Object { DVector _shader_get_param_list(RID p_shader) const; void _camera_set_orthogonal(RID p_camera,float p_size,float p_z_near,float p_z_far); void _canvas_item_add_style_box(RID p_item, const Rect2& p_rect, const Rect2& p_source, RID p_texture,const Vector& p_margins, const Color& p_modulate=Color(1,1,1)); + Array _get_array_from_surface(uint32_t p_format,DVector p_vertex_data,int p_vertex_len,DVector p_index_data,int p_index_len) const; + protected: RID _make_test_cube(); void _free_internal_rids(); @@ -258,10 +260,15 @@ public: virtual DVector mesh_surface_get_array(RID p_mesh, int p_surface) const=0; virtual DVector mesh_surface_get_index_array(RID p_mesh, int p_surface) const=0; + virtual Array mesh_surface_get_arrays(RID p_mesh,int p_surface) const; virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const=0; virtual PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const=0; + virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const=0; + virtual Vector > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const=0; + virtual Vector mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const=0; + virtual void mesh_remove_surface(RID p_mesh,int p_index)=0; virtual int mesh_get_surface_count(RID p_mesh) const=0; @@ -354,7 +361,6 @@ public: LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET, LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET, LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET, - LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET, LIGHT_PARAM_SHADOW_NORMAL_BIAS, LIGHT_PARAM_SHADOW_BIAS, LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE, @@ -372,10 +378,25 @@ public: virtual void light_set_cull_mask(RID p_light,uint32_t p_mask)=0; virtual void light_set_shader(RID p_light,RID p_shader)=0; + // omni light + enum LightOmniShadowMode { + LIGHT_OMNI_SHADOW_DUAL_PARABOLOID, + LIGHT_OMNI_SHADOW_CUBE, + }; + + virtual void light_omni_set_shadow_mode(RID p_light,LightOmniShadowMode p_mode)=0; + + // omni light + enum LightOmniShadowDetail { + LIGHT_OMNI_SHADOW_DETAIL_VERTICAL, + LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL + }; + + virtual void light_omni_set_shadow_detail(RID p_light,LightOmniShadowDetail p_detail)=0; + // directional light enum LightDirectionalShadowMode { LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL, - LIGHT_DIRECTIONAL_SHADOW_PERSPECTIVE, LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS, LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS }; @@ -475,6 +496,9 @@ public: virtual void viewport_set_global_canvas_transform(RID p_viewport,const Matrix32& p_transform)=0; virtual void viewport_set_canvas_layer(RID p_viewport,RID p_canvas,int p_layer)=0; + virtual void viewport_set_shadow_atlas_size(RID p_viewport,int p_size)=0; + virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport,int p_quadrant,int p_subdiv)=0; + /* ENVIRONMENT API */ diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index e8207c957..fa9e372eb 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -1468,7 +1468,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref& p_mesh,con mr.push_back(a); } - p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,d,mr); + p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,d,mr); if (material.is_valid()) { p_mesh->surface_set_material(surface, material); diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 13c69692c..e5e8668df 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -1823,6 +1823,19 @@ void SpatialEditorViewport::_notification(int p_what) { surface->update(); } + + int shadowmap_size = Globals::get_singleton()->get("rendering/shadow_atlas/size"); + int atlas_q0 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_0_subdiv"); + int atlas_q1 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_1_subdiv"); + int atlas_q2 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_2_subdiv"); + int atlas_q3 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_3_subdiv"); + + viewport->set_shadow_atlas_size(shadowmap_size); + viewport->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0)); + viewport->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1)); + viewport->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2)); + viewport->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3)); + } if (p_what==NOTIFICATION_ENTER_TREE) { @@ -2354,6 +2367,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed c->set_area_as_parent_rect(); viewport = memnew( Viewport ); viewport->set_disable_input(true); + c->add_child(viewport); surface = memnew( Control ); add_child(surface); diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index b1accac76..cdd56bbac 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -133,7 +133,7 @@ void EditorSpatialGizmo::add_lines(const Vector &p_lines, const Refadd_surface(Mesh::PRIMITIVE_LINES,a); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,a); mesh->surface_set_material(0,p_material); if (p_billboard) { @@ -182,7 +182,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref& p_material, a.resize(Mesh::ARRAY_MAX); a[Mesh::ARRAY_VERTEX]=vs; a[Mesh::ARRAY_TEX_UV]=uv; - mesh->add_surface(Mesh::PRIMITIVE_TRIANGLE_FAN,a); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_FAN,a); mesh->surface_set_material(0,p_material); if (true) { @@ -259,7 +259,7 @@ void EditorSpatialGizmo::add_handles(const Vector &p_handles, bool p_bi } a[VS::ARRAY_COLOR]=colors; - mesh->add_surface(Mesh::PRIMITIVE_POINTS,a); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS,a); mesh->surface_set_material(0,SpatialEditorGizmos::singleton->handle2_material); if (p_billboard) { @@ -2321,7 +2321,7 @@ void NavigationMeshSpatialGizmo::redraw() { Array a; a.resize(Mesh::ARRAY_MAX); a[0]=tmeshfaces; - m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a); + m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,a); m->surface_set_material(0,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_solid_material:SpatialEditorGizmos::singleton->navmesh_solid_material_disabled); add_mesh(m); add_collision_segments(lines); @@ -3090,7 +3090,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() { d.resize(VS::ARRAY_MAX); d[Mesh::ARRAY_VERTEX]=cursor_points; d[Mesh::ARRAY_COLOR]=cursor_colors; - pos3d_mesh->add_surface(Mesh::PRIMITIVE_LINES,d); + pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,d); pos3d_mesh->surface_set_material(0,mat); } @@ -3114,7 +3114,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() { d.resize(VS::ARRAY_MAX); d[Mesh::ARRAY_VERTEX] = cursor_points; d[Mesh::ARRAY_COLOR] = cursor_colors; - listener_line_mesh->add_surface(Mesh::PRIMITIVE_LINES, d); + listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); listener_line_mesh->surface_set_material(0, mat); } -- cgit v1.2.3-70-g09d2 From a7078a4be9f4c44a41e5c7e7a633169b53f78d48 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 11 Nov 2016 12:27:52 -0300 Subject: Done with lights and shadows (wonder if i'm missing something..) --- drivers/gles3/rasterizer_gles3.cpp | 2 +- drivers/gles3/rasterizer_scene_gles3.cpp | 786 ++++++++++++++++------------- drivers/gles3/rasterizer_scene_gles3.h | 91 ++-- drivers/gles3/rasterizer_storage_gles3.cpp | 41 +- drivers/gles3/rasterizer_storage_gles3.h | 11 +- drivers/gles3/shader_gles3.cpp | 9 + drivers/gles3/shader_gles3.h | 6 + drivers/gles3/shaders/scene.glsl | 254 ++++++---- scene/3d/light.cpp | 58 ++- scene/3d/light.h | 5 +- servers/visual/rasterizer.h | 7 +- servers/visual/visual_server_raster.h | 4 +- servers/visual/visual_server_scene.cpp | 2 +- servers/visual/visual_server_scene.h | 2 - servers/visual_server.h | 5 +- 15 files changed, 754 insertions(+), 529 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index e838020c4..c799cd12a 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -125,6 +125,7 @@ void RasterizerGLES3::begin_frame(){ storage->update_dirty_shaders(); storage->update_dirty_materials(); + scene->iteration(); } @@ -258,7 +259,6 @@ void RasterizerGLES3::register_config() { GLOBAL_DEF("rendering/gles3/use_nearest_mipmap_filter",false); GLOBAL_DEF("rendering/gles3/anisotropic_filter_level",4.0); - } RasterizerGLES3::RasterizerGLES3() diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 287801b59..4ae257abc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -131,8 +131,10 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); //interpola nearest (though nvidia can improve this) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Remove artifact on the edges of the shadowmap glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -559,11 +561,6 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { light_instance->light=p_light; light_instance->light_ptr=storage->light_owner.getornull(p_light); - glGenBuffers(1, &light_instance->light_ubo); - glBindBuffer(GL_UNIFORM_BUFFER, light_instance->light_ubo); - glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInstance::LightDataUBO), NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - ERR_FAIL_COND_V(!light_instance->light_ptr,RID()); light_instance->self=light_instance_owner.make_rid(light_instance); @@ -818,9 +815,50 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } -void RasterizerSceneGLES3::_setup_light(LightInstance *p_light) { +void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) { + + int omni_indices[16]; + int omni_count=0; + int spot_indices[16]; + int spot_count=0; + + int maxobj = MIN(16,state.max_forward_lights_per_object); + + int lc = e->instance->light_instances.size(); + if (lc) { + + const RID* lights=e->instance->light_instances.ptr(); + + for(int i=0;ilast_pass!=render_pass) //not visible + continue; + + if (li->light_ptr->type==VS::LIGHT_OMNI) { + if (omni_countinstance->layer_mask&li->light_ptr->cull_mask) { + omni_indices[omni_count++]=li->light_index; + } + } + + if (li->light_ptr->type==VS::LIGHT_SPOT) { + if (spot_countinstance->layer_mask&li->light_ptr->cull_mask) { + spot_indices[spot_count++]=li->light_index; + } + } + } + } + + state.scene_shader.set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT,omni_count); + + if (omni_count) { + glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES),omni_count,omni_indices); + } + + state.scene_shader.set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT,spot_count); + if (spot_count) { + glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES),spot_count,spot_indices); + } - glBindBufferBase(GL_UNIFORM_BUFFER,3,p_light->light_ubo); //bind light uniform } @@ -894,7 +932,7 @@ void RasterizerSceneGLES3::_set_cull(bool p_front,bool p_reverse_cull) { -void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow) { +void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow,bool p_directional_add) { if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { //p_reverse_cull=!p_reverse_cull; @@ -906,7 +944,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glBindBufferBase(GL_UNIFORM_BUFFER,0,state.scene_ubo); //bind globals ubo - if (!p_shadow) { + if (!p_shadow && !p_directional_add) { glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1); glBindTexture(GL_TEXTURE_2D,state.brdf_texture); @@ -934,160 +972,147 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e state.current_line_width=-1; state.current_depth_draw=-1; - glDisable(GL_BLEND); - RasterizerStorageGLES3::Material* prev_material=NULL; RasterizerStorageGLES3::Geometry* prev_geometry=NULL; VS::InstanceType prev_base_type = VS::INSTANCE_MAX; - int prev_light_type=-1; - int prev_light_index=-1; - int prev_blend=-1; int current_blend_mode=-1; - bool prev_additive=false; + int prev_shading=-1; + + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); //by default unshaded (easier to set) + + bool first=true; for (int i=0;imaterial; - bool rebind=i==0; - - int light_type=(e->sort_key>>RenderList::SORT_KEY_LIGHT_TYPE_SHIFT)&0xF; - int light_index=(e->sort_key>>RenderList::SORT_KEY_LIGHT_INDEX_SHIFT)&0xFFFF; + bool rebind=first; - bool additive=false; + int shading = (e->sort_key>>RenderList::SORT_KEY_SHADING_SHIFT)&RenderList::SORT_KEY_SHADING_MASK; if (!p_shadow) { - if (light_type!=prev_light_type /* || receive_shadows_state!=prev_receive_shadows_state*/) { - if (material->shader->spatial.unshaded/* || current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false); + + if (p_directional_add) { + if (e->sort_key&RenderList::SORT_KEY_UNSHADED_FLAG || !(e->instance->layer_mask&directional_light->light_ptr->cull_mask)) { + continue; + } + + shading&=~1; //ignore the ignore directional for base pass + } + + if (shading!=prev_shading) { + + if (e->sort_key&RenderList::SORT_KEY_UNSHADED_FLAG) { + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false); + //state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); } else { state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,light_type!=0xF); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,(light_type&3)==VS::LIGHT_DIRECTIONAL); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,(light_type&0xF)==VS::LIGHT_OMNI); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,(light_type&0xF)==VS::LIGHT_SPOT); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,!p_directional_add); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,shadow_filter_mode==SHADOW_FILTER_PCF5); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,shadow_filter_mode==SHADOW_FILTER_PCF13); - if ((light_type&3)==VS::LIGHT_DIRECTIONAL) { - if (light_instances[light_index]->light_ptr->shadow) { + if (p_directional_add || (directional_light && (e->sort_key&RenderList::SORT_KEY_NO_DIRECTIONAL_FLAG)==0)) { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,true); + + if (directional_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,true); - switch(light_instances[light_index]->light_ptr->directional_shadow_mode) { + switch(directional_light->light_ptr->directional_shadow_mode) { case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: break; //none - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,true); break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,true); break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,true); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,directional_light->light_ptr->directional_blend_splits); + break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,true); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,directional_light->light_ptr->directional_blend_splits); + break; } } - } + } } rebind=true; } - - if (!*e->additive_ptr) { - - additive=false; - *e->additive_ptr=true; - } else { - additive=true; - } - - bool desired_blend=false; - int desired_blend_mode=RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX; - - if (additive) { - desired_blend=true; - desired_blend_mode=RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD; - } else { - desired_blend=p_alpha_pass; - desired_blend_mode=material->shader->spatial.blend_mode; - } - - if (prev_blend!=desired_blend) { - - if (desired_blend) { - glEnable(GL_BLEND); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glColorMask(1,1,1,0); - } + if (p_alpha_pass || p_directional_add) { + int desired_blend_mode; + if (p_directional_add) { + desired_blend_mode=RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD; } else { - glDisable(GL_BLEND); - glColorMask(1,1,1,1); + desired_blend_mode=material->shader->spatial.blend_mode; } - prev_blend=desired_blend; - } + if (desired_blend_mode!=current_blend_mode) { - if (desired_blend && desired_blend_mode!=current_blend_mode) { + switch(desired_blend_mode) { - switch(desired_blend_mode) { + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } - else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } + } break; + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD: { - } break; - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_ADD: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(p_alpha_pass?GL_SRC_ALPHA:GL_ONE,GL_ONE); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(p_alpha_pass?GL_SRC_ALPHA:GL_ONE,GL_ONE); + } break; + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_SUB: { - } break; - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_SUB: { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + } break; + case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA,GL_ONE); - } break; - case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } - else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } + } break; - } break; + } + current_blend_mode=desired_blend_mode; } - current_blend_mode=desired_blend_mode; } - if (light_index!=prev_light_index) { - if (light_index!=0xFFFF) { //not unshaded - _setup_light(light_instances[light_index]); - } - } } @@ -1098,17 +1123,16 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e // _rinfo.mat_change_count++; } + if (!(e->sort_key&RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) { + _setup_light(e); + } + if (prev_base_type != e->instance->base_type || prev_geometry!=e->geometry) { _setup_geometry(e); } - if (!p_shadow && (rebind || prev_additive!=additive)) { - state.scene_shader.set_uniform(SceneShaderGLES3::NO_AMBIENT_LIGHT, additive); - - } - _set_cull(e->sort_key&RenderList::SORT_KEY_MIRROR_FLAG,p_reverse_cull); state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror?-1.0:1.0); @@ -1120,9 +1144,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e prev_material=material; prev_base_type=e->instance->base_type; prev_geometry=e->geometry; - prev_additive=additive; - prev_light_type=light_type; - prev_light_index=light_index; + prev_shading=shading; + first=false; } @@ -1133,14 +1156,14 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false); } @@ -1214,8 +1237,6 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g e->material=m; e->instance=p_instance; e->owner=p_owner; - e->additive=false; - e->additive_ptr=&e->additive; e->sort_key=0; if (e->geometry->last_pass!=render_pass) { @@ -1223,6 +1244,9 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g e->geometry->index=current_geometry_index++; } + if (!p_shadow && directional_light && (directional_light->light_ptr->cull_mask&e->instance->layer_mask)==0) { + e->sort_key|=RenderList::SORT_KEY_NO_DIRECTIONAL_FLAG; + } e->sort_key|=uint64_t(e->geometry->index)<sort_key|=uint64_t(e->instance->base_type)<additive_ptr=&oe->additive; } } @@ -1261,106 +1284,10 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g //e->light_type=0xFF; // no lights! - - - if (shadow || m->shader->spatial.unshaded /*|| current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) { - e->sort_key|=RenderList::SORT_KEY_LIGHT_INDEX_UNSHADED; - e->sort_key|=uint64_t(0xF)<sort_key|=uint64_t(0xFFFF)<base->shadow_enabled) { - light_type|=0x8; - if (directional_lights[i]->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) - light_type|=0x10; - else if (directional_lights[i]->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) - light_type|=0x30; - - } -*/ - - RenderList::Element *ec; - if (duplicate) { - ec = render_list.add_element(); - copymem(ec,e,sizeof(RenderList::Element)); - } else { - - ec=e; - duplicate=true; - } - - ec->additive_ptr=&e->additive; - - ec->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; - ec->sort_key|=uint64_t(directional_light_instances[i]->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; - ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; //this is zero byt whathever - - if (directional_light_instances[i]->light_ptr->shadow) { - //add proper flags for directional shadow mode - ec->sort_key|=uint64_t(directional_light_instances[i]->light_ptr->directional_shadow_mode+1) << (RenderList::SORT_KEY_LIGHT_TYPE_SHIFT+2); - } - - lit=true; - } - - - const RID *liptr = p_instance->light_instances.ptr(); - int ilc=p_instance->light_instances.size(); - - - - for(int i=0;ilast_pass!=render_pass) //lit by light not in visible scene - continue; - - -// if (li->base->shadow_enabled) { -// light_type|=0x8; -// } - - RenderList::Element *ec; - if (duplicate) { - - ec = render_list.add_element(); - copymem(ec,e,sizeof(RenderList::Element)); - } else { - - duplicate=true; - ec=e; - } - - ec->additive_ptr=&e->additive; - - ec->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; - ec->sort_key|=uint64_t(li->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; - ec->sort_key|=uint64_t(li->light_ptr->type) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; - - lit=true; - } - - - if (!lit) { - e->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; - e->sort_key|=uint64_t(0xE)<sort_key|=uint64_t(0xFFFF)<sort_key|=RenderList::SORT_KEY_UNSHADED_FLAG; } - - } void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { @@ -1534,161 +1461,202 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,const CameraMatri } -void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection,RID p_shadow_atlas) { +void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& p_camera_inverse_transform) { + LightInstance *li = directional_lights[p_index]; - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + LightDataUBO ubo_data; //used for filling - directional_light_instance_count=0; - light_instance_count=0; + float sign = li->light_ptr->negative?-1:1; - for(int i=0;ilight_ptr->color.to_linear(); + ubo_data.light_color_energy[0]=linear_col.r*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[1]=linear_col.g*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[2]=linear_col.b*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[3]=0; - ERR_BREAK( i>=RenderList::MAX_LIGHTS ); + //omni, keep at 0 + ubo_data.light_pos_inv_radius[0]=0.0; + ubo_data.light_pos_inv_radius[1]=0.0; + ubo_data.light_pos_inv_radius[2]=0.0; + ubo_data.light_pos_inv_radius[3]=0.0; - LightInstance *li = light_instance_owner.getptr(p_light_cull_result[i]); + Vector3 direction = p_camera_inverse_transform.basis.xform(li->transform.basis.xform(Vector3(0,0,-1))).normalized(); + ubo_data.light_direction_attenuation[0]=direction.x; + ubo_data.light_direction_attenuation[1]=direction.y; + ubo_data.light_direction_attenuation[2]=direction.z; + ubo_data.light_direction_attenuation[3]=1.0; - switch(li->light_ptr->type) { + ubo_data.light_params[0]=0; + ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + ubo_data.light_params[2]=0; + ubo_data.light_params[3]=0; - case VS::LIGHT_DIRECTIONAL: { + Color shadow_color = li->light_ptr->shadow_color.to_linear(); + ubo_data.light_shadow_color[0]=shadow_color.r; + ubo_data.light_shadow_color[1]=shadow_color.g; + ubo_data.light_shadow_color[2]=shadow_color.b; + ubo_data.light_shadow_color[3]=1.0; - ERR_FAIL_COND( directional_light_instance_count >= RenderList::MAX_LIGHTS); - directional_light_instances[directional_light_instance_count++]=li; - Color linear_col = li->light_ptr->color.to_linear(); - li->light_ubo_data.light_color_energy[0]=linear_col.r; - li->light_ubo_data.light_color_energy[1]=linear_col.g; - li->light_ubo_data.light_color_energy[2]=linear_col.b; - li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + if (li->light_ptr->shadow) { - //omni, keep at 0 - li->light_ubo_data.light_pos_inv_radius[0]=0.0; - li->light_ubo_data.light_pos_inv_radius[1]=0.0; - li->light_ubo_data.light_pos_inv_radius[2]=0.0; - li->light_ubo_data.light_pos_inv_radius[3]=0.0; + int shadow_count=0; - Vector3 direction = p_camera_inverse_transform.basis.xform(li->transform.basis.xform(Vector3(0,0,-1))).normalized(); - li->light_ubo_data.light_direction_attenuation[0]=direction.x; - li->light_ubo_data.light_direction_attenuation[1]=direction.y; - li->light_ubo_data.light_direction_attenuation[2]=direction.z; - li->light_ubo_data.light_direction_attenuation[3]=1.0; + switch(li->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + shadow_count=1; + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + shadow_count=2; + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + shadow_count=4; + } break; - li->light_ubo_data.light_params[0]=0; - li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - li->light_ubo_data.light_params[2]=0; - li->light_ubo_data.light_params[3]=0; + } - if (li->light_ptr->shadow) { + for(int j=0;jlight_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - shadow_count=1; - } break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - shadow_count=2; - } break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - shadow_count=4; - } break; + uint32_t x=li->directional_rect.pos.x; + uint32_t y=li->directional_rect.pos.y; + uint32_t width=li->directional_rect.size.x; + uint32_t height=li->directional_rect.size.y; - } - for(int j=0;jlight_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - uint32_t x=li->directional_rect.pos.x; - uint32_t y=li->directional_rect.pos.y; - uint32_t width=li->directional_rect.size.x; - uint32_t height=li->directional_rect.size.y; + width/=2; + height/=2; + if (j==0) { - if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + } else if (j==1) { + x+=width; + } else if (j==2) { + y+=height; + } else if (j==3) { + x+=width; + y+=height; + } - width/=2; - height/=2; - if (j==0) { - } else if (j==1) { - x+=width; - } else if (j==2) { - y+=height; - } else if (j==3) { - x+=width; - y+=height; + } else if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - } + height/=2; + if (j==0) { + } else { + y+=height; + } - } else if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + } - height/=2; + ubo_data.shadow_split_offsets[j]=1.0/li->shadow_transform[j].split; - if (j==0) { + Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse(); - } else { - y+=height; - } + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + Rect2 atlas_rect = Rect2(float(x)/directional_shadow.size,float(y)/directional_shadow.size,float(width)/directional_shadow.size,float(height)/directional_shadow.size); + rectm.set_light_atlas_rect(atlas_rect); - } +// print_line("atlas rect: "+atlas_rect); - li->light_ubo_data.shadow_split_offsets[j]=1.0/li->shadow_transform[j].split; + CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview; - Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse(); + store_camera(shadow_mtx,&ubo_data.shadow_matrix1[16*j]); - CameraMatrix bias; - bias.set_light_bias(); - CameraMatrix rectm; - Rect2 atlas_rect = Rect2(float(x)/directional_shadow.size,float(y)/directional_shadow.size,float(width)/directional_shadow.size,float(height)/directional_shadow.size); - rectm.set_light_atlas_rect(atlas_rect); + ubo_data.light_clamp[0]=atlas_rect.pos.x; + ubo_data.light_clamp[1]=atlas_rect.pos.y; + ubo_data.light_clamp[2]=atlas_rect.size.x; + ubo_data.light_clamp[3]=atlas_rect.size.y; -// print_line("atlas rect: "+atlas_rect); + } - CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview; + } - store_camera(shadow_mtx,&li->light_ubo_data.shadow_matrix1[16*j]); + glBindBuffer(GL_UNIFORM_BUFFER, state.directional_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightDataUBO), &ubo_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); - li->light_ubo_data.light_clamp[0]=atlas_rect.pos.x; - li->light_ubo_data.light_clamp[1]=atlas_rect.pos.y; - li->light_ubo_data.light_clamp[2]=atlas_rect.size.x; - li->light_ubo_data.light_clamp[3]=atlas_rect.size.y; + directional_light=li; - } + glBindBufferBase(GL_UNIFORM_BUFFER,3,state.directional_ubo); +} + +void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection,RID p_shadow_atlas) { + + + state.omni_light_count=0; + state.spot_light_count=0; + state.directional_light_count=0; + + directional_light=NULL; + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + + + for(int i=0;i=RenderList::MAX_LIGHTS ); + + LightInstance *li = light_instance_owner.getptr(p_light_cull_result[i]); + + LightDataUBO ubo_data; //used for filling + + switch(li->light_ptr->type) { + + case VS::LIGHT_DIRECTIONAL: { + + if (state.directional_light_countlight_ptr->negative?-1:1; + Color linear_col = li->light_ptr->color.to_linear(); - li->light_ubo_data.light_color_energy[0]=linear_col.r; - li->light_ubo_data.light_color_energy[1]=linear_col.g; - li->light_ubo_data.light_color_energy[2]=linear_col.b; - li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + ubo_data.light_color_energy[0]=linear_col.r*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[1]=linear_col.g*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[2]=linear_col.b*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[3]=0; + Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); //directional, keep at 0 - li->light_ubo_data.light_pos_inv_radius[0]=pos.x; - li->light_ubo_data.light_pos_inv_radius[1]=pos.y; - li->light_ubo_data.light_pos_inv_radius[2]=pos.z; - li->light_ubo_data.light_pos_inv_radius[3]=1.0/MAX(0.001,li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); - - li->light_ubo_data.light_direction_attenuation[0]=0; - li->light_ubo_data.light_direction_attenuation[1]=0; - li->light_ubo_data.light_direction_attenuation[2]=0; - li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - - li->light_ubo_data.light_params[0]=0; - li->light_ubo_data.light_params[1]=0; - li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - li->light_ubo_data.light_params[3]=0; - + ubo_data.light_pos_inv_radius[0]=pos.x; + ubo_data.light_pos_inv_radius[1]=pos.y; + ubo_data.light_pos_inv_radius[2]=pos.z; + ubo_data.light_pos_inv_radius[3]=1.0/MAX(0.001,li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); + + ubo_data.light_direction_attenuation[0]=0; + ubo_data.light_direction_attenuation[1]=0; + ubo_data.light_direction_attenuation[2]=0; + ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + + ubo_data.light_params[0]=0; + ubo_data.light_params[1]=0; + ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + ubo_data.light_params[3]=0; + + Color shadow_color = li->light_ptr->shadow_color.to_linear(); + ubo_data.light_shadow_color[0]=shadow_color.r; + ubo_data.light_shadow_color[1]=shadow_color.g; + ubo_data.light_shadow_color[2]=shadow_color.b; + ubo_data.light_shadow_color[3]=1.0; if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { // fill in the shadow information @@ -1724,17 +1692,21 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu Transform proj = (p_camera_inverse_transform * li->transform).inverse(); - store_transform(proj,li->light_ubo_data.shadow_matrix1); + store_transform(proj,ubo_data.shadow_matrix1); - li->light_ubo_data.light_params[3]=1.0; //means it has shadow - li->light_ubo_data.light_clamp[0]=float(x)/atlas_size; - li->light_ubo_data.light_clamp[1]=float(y)/atlas_size; - li->light_ubo_data.light_clamp[2]=float(width)/atlas_size; - li->light_ubo_data.light_clamp[3]=float(height)/atlas_size; + ubo_data.light_params[3]=1.0; //means it has shadow + ubo_data.light_clamp[0]=float(x)/atlas_size; + ubo_data.light_clamp[1]=float(y)/atlas_size; + ubo_data.light_clamp[2]=float(width)/atlas_size; + ubo_data.light_clamp[3]=float(height)/atlas_size; } + li->light_index=state.omni_light_count; + copymem(&state.omni_array_tmp[li->light_index*state.ubo_light_size],&ubo_data,state.ubo_light_size); + state.omni_light_count++; + #if 0 @@ -1746,30 +1718,38 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu } break; case VS::LIGHT_SPOT: { + float sign = li->light_ptr->negative?-1:1; + Color linear_col = li->light_ptr->color.to_linear(); - li->light_ubo_data.light_color_energy[0]=linear_col.r; - li->light_ubo_data.light_color_energy[1]=linear_col.g; - li->light_ubo_data.light_color_energy[2]=linear_col.b; - li->light_ubo_data.light_color_energy[3]=li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + ubo_data.light_color_energy[0]=linear_col.r*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[1]=linear_col.g*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[2]=linear_col.b*sign*li->light_ptr->param[VS::LIGHT_PARAM_ENERGY];; + ubo_data.light_color_energy[3]=0; Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); //directional, keep at 0 - li->light_ubo_data.light_pos_inv_radius[0]=pos.x; - li->light_ubo_data.light_pos_inv_radius[1]=pos.y; - li->light_ubo_data.light_pos_inv_radius[2]=pos.z; - li->light_ubo_data.light_pos_inv_radius[3]=1.0/MAX(0.001,li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); + ubo_data.light_pos_inv_radius[0]=pos.x; + ubo_data.light_pos_inv_radius[1]=pos.y; + ubo_data.light_pos_inv_radius[2]=pos.z; + ubo_data.light_pos_inv_radius[3]=1.0/MAX(0.001,li->light_ptr->param[VS::LIGHT_PARAM_RANGE]); Vector3 direction = p_camera_inverse_transform.basis.xform(li->transform.basis.xform(Vector3(0,0,-1))).normalized(); - li->light_ubo_data.light_direction_attenuation[0]=direction.x; - li->light_ubo_data.light_direction_attenuation[1]=direction.y; - li->light_ubo_data.light_direction_attenuation[2]=direction.z; - li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - - li->light_ubo_data.light_params[0]=li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; - li->light_ubo_data.light_params[1]=Math::cos(Math::deg2rad(li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE])); - li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - li->light_ubo_data.light_params[3]=0; + ubo_data.light_direction_attenuation[0]=direction.x; + ubo_data.light_direction_attenuation[1]=direction.y; + ubo_data.light_direction_attenuation[2]=direction.z; + ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + + ubo_data.light_params[0]=li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; + ubo_data.light_params[1]=Math::cos(Math::deg2rad(li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE])); + ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + ubo_data.light_params[3]=0; + + Color shadow_color = li->light_ptr->shadow_color.to_linear(); + ubo_data.light_shadow_color[0]=shadow_color.r; + ubo_data.light_shadow_color[1]=shadow_color.g; + ubo_data.light_shadow_color[2]=shadow_color.b; + ubo_data.light_shadow_color[3]=1.0; if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { // fill in the shadow information @@ -1796,11 +1776,11 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu Rect2 rect(float(x)/atlas_size,float(y)/atlas_size,float(width)/atlas_size,float(height)/atlas_size); - li->light_ubo_data.light_params[3]=1.0; //means it has shadow - li->light_ubo_data.light_clamp[0]=rect.pos.x; - li->light_ubo_data.light_clamp[1]=rect.pos.y; - li->light_ubo_data.light_clamp[2]=rect.size.x; - li->light_ubo_data.light_clamp[3]=rect.size.y; + ubo_data.light_params[3]=1.0; //means it has shadow + ubo_data.light_clamp[0]=rect.pos.x; + ubo_data.light_clamp[1]=rect.pos.y; + ubo_data.light_clamp[2]=rect.size.x; + ubo_data.light_clamp[3]=rect.size.y; Transform modelview = (p_camera_inverse_transform * li->transform).inverse(); @@ -1811,10 +1791,15 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[0].camera * modelview; - store_camera(shadow_mtx,li->light_ubo_data.shadow_matrix1); + store_camera(shadow_mtx,ubo_data.shadow_matrix1); } + + li->light_index=state.spot_light_count; + copymem(&state.spot_array_tmp[li->light_index*state.ubo_light_size],&ubo_data,state.ubo_light_size); + state.spot_light_count++; + #if 0 if (li->light_ptr->shadow_enabled) { CameraMatrix bias; @@ -1829,24 +1814,34 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu } - /* make light hash */ + li->last_pass=render_pass; - // actually, not really a hash, but helps to sort the lights - // and avoid recompiling redudant shader versions + //update UBO for forward rendering, blit to texture for clustered + } - li->last_pass=render_pass; - li->light_index=i; - //update UBO for forward rendering, blit to texture for clustered - glBindBuffer(GL_UNIFORM_BUFFER, li->light_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightInstance::LightDataUBO), &li->light_ubo_data); + if (state.omni_light_count) { + + glBindBuffer(GL_UNIFORM_BUFFER, state.omni_array_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, state.omni_light_count*state.ubo_light_size, state.omni_array_tmp); glBindBuffer(GL_UNIFORM_BUFFER, 0); - light_instances[i]=li; - light_instance_count++; + glBindBufferBase(GL_UNIFORM_BUFFER,4,state.omni_array_ubo); } + + if (state.spot_light_count) { + + glBindBuffer(GL_UNIFORM_BUFFER, state.spot_array_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, state.spot_light_count*state.ubo_light_size, state.spot_array_tmp); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + glBindBufferBase(GL_UNIFORM_BUFFER,5,state.spot_array_ubo); + } + + + } void RasterizerSceneGLES3::_copy_screen() { @@ -1969,6 +1964,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C //first of all, make a new render pass render_pass++; + //fill up ubo Environment *env = environment_owner.getornull(p_environment); @@ -2075,7 +2071,20 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false); + if (state.directional_light_count==0) { + directional_light=NULL; + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,false); + } else { + for(int i=0;i0) { + glEnable(GL_BLEND); + } + _setup_directional_light(i,p_cam_transform.affine_inverse()); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,i>0); + + } + } state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); @@ -2107,9 +2116,20 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C render_list.sort_by_depth(true); - _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false); + if (state.directional_light_count==0) { + directional_light=NULL; + _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false,false); + } else { + for(int i=0;i0); + + } + } + _copy_to_front_buffer(env); /* if (shadow_atlas) { @@ -2123,7 +2143,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C } */ - if (directional_shadow.fbo) { + if (false && directional_shadow.fbo) { //_copy_texture_to_front_buffer(shadow_atlas->depth); storage->canvas->canvas_begin(); @@ -2285,6 +2305,8 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa render_pass++; + directional_light=NULL; + LightInstance *light_instance = light_instance_owner.getornull(p_light); ERR_FAIL_COND(!light_instance); RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light); @@ -2512,7 +2534,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,true); - _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true); + _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false); @@ -2593,7 +2615,6 @@ bool RasterizerSceneGLES3::free(RID p_rid) { } - glDeleteBuffers(1,&light_instance->light_ubo); light_instance_owner.free(p_rid); memdelete(light_instance); @@ -2860,6 +2881,53 @@ void RasterizerSceneGLES3::initialize() { ERR_PRINT("Directional shadow framebuffer status invalid"); } } + + { + //spot and omni ubos + + int max_ubo_size; + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,&max_ubo_size); + const int ubo_light_size=160; + state.ubo_light_size=ubo_light_size; + state.max_ubo_lights=max_ubo_size/ubo_light_size; + + state.spot_array_tmp = (uint8_t*)memalloc(ubo_light_size*state.max_ubo_lights); + state.omni_array_tmp = (uint8_t*)memalloc(ubo_light_size*state.max_ubo_lights); + + + glGenBuffers(1, &state.spot_array_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.spot_array_ubo); + glBufferData(GL_UNIFORM_BUFFER, ubo_light_size*state.max_ubo_lights, NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + glGenBuffers(1, &state.omni_array_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.omni_array_ubo); + glBufferData(GL_UNIFORM_BUFFER, ubo_light_size*state.max_ubo_lights, NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + glGenBuffers(1, &state.directional_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.directional_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDataUBO), NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + state.max_forward_lights_per_object=8; + + state.scene_shader.add_custom_define("#define MAX_LIGHT_DATA_STRUCTS "+itos(state.max_ubo_lights)+"\n"); + state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS "+itos(state.max_forward_lights_per_object)+"\n"); + + + + } + + GLOBAL_DEF("rendering/gles3/shadow_filter_mode",1); + Globals::get_singleton()->set_custom_property_info("rendering/gles3/shadow_filter_mode",PropertyInfo(Variant::INT,"rendering/gles3/shadow_filter_mode",PROPERTY_HINT_ENUM,"Disabled,PCF5,PCF13")); + shadow_filter_mode=SHADOW_FILTER_NEAREST; + +} + +void RasterizerSceneGLES3::iteration() { + + shadow_filter_mode=ShadowFilterMode(int(Globals::get_singleton()->get("rendering/gles3/shadow_filter_mode"))); } void RasterizerSceneGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index d7beebbcf..24b6a36fc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -8,6 +8,15 @@ class RasterizerSceneGLES3 : public RasterizerScene { public: + enum ShadowFilterMode { + SHADOW_FILTER_NEAREST, + SHADOW_FILTER_PCF5, + SHADOW_FILTER_PCF13, + }; + + + ShadowFilterMode shadow_filter_mode; + uint64_t shadow_atlas_realloc_tolerance_msec; @@ -27,6 +36,7 @@ public: struct State { + bool texscreen_copied; int current_blend_mode; float current_line_width; @@ -73,6 +83,22 @@ public: GLuint skybox_verts; GLuint skybox_array; + GLuint directional_ubo; + + GLuint spot_array_ubo; + GLuint omni_array_ubo; + + uint32_t ubo_light_size; + uint8_t *spot_array_tmp; + uint8_t *omni_array_tmp; + + int max_ubo_lights; + int max_forward_lights_per_object; + + int spot_light_count; + int omni_light_count; + int directional_light_count; + bool cull_front; } state; @@ -204,6 +230,22 @@ public: /* LIGHT INSTANCE */ + struct LightDataUBO { + + float light_pos_inv_radius[4]; + float light_direction_attenuation[4]; + float light_color_energy[4]; + float light_params[4]; //spot attenuation, spot angle, specular, shadow enabled + float light_clamp[4]; + float light_shadow_color[4]; + float shadow_matrix1[16]; //up to here for spot and omni, rest is for directional + float shadow_matrix2[16]; + float shadow_matrix3[16]; + float shadow_matrix4[16]; + float shadow_split_offsets[4]; + + }; + struct LightInstance : public RID_Data { struct ShadowTransform { @@ -214,20 +256,6 @@ public: float split; }; - struct LightDataUBO { - - float light_pos_inv_radius[4]; - float light_direction_attenuation[4]; - float light_color_energy[4]; - float light_params[4]; //cone attenuation, specular, shadow darkening, - float light_clamp[4]; //cone attenuation, specular, shadow darkening, - float shadow_split_offsets[4]; - float shadow_matrix1[16]; - float shadow_matrix2[16]; - float shadow_matrix3[16]; - float shadow_matrix4[16]; - - } light_ubo_data; ShadowTransform shadow_transform[4]; @@ -241,8 +269,6 @@ public: Vector3 spot_vector; float linear_att; - GLuint light_ubo; - uint64_t shadow_pass; uint64_t last_scene_pass; uint64_t last_scene_shadow_pass; @@ -280,14 +306,16 @@ public: SORT_FLAG_INSTANCING=2, MAX_DIRECTIONAL_LIGHTS=16, MAX_LIGHTS=4096, - SORT_KEY_DEPTH_LAYER_SHIFT=58, - SORT_KEY_LIGHT_TYPE_SHIFT=54, //type is most important - SORT_KEY_LIGHT_INDEX_SHIFT=38, //type is most important - SORT_KEY_LIGHT_INDEX_UNSHADED=uint64_t(0xF) << SORT_KEY_LIGHT_TYPE_SHIFT, //type is most important - SORT_KEY_LIGHT_MASK=(uint64_t(0xFFFFF) << SORT_KEY_LIGHT_INDEX_SHIFT), //type is most important - SORT_KEY_MATERIAL_INDEX_SHIFT=22, - SORT_KEY_GEOMETRY_INDEX_SHIFT=6, - SORT_KEY_GEOMETRY_TYPE_SHIFT=2, + + + SORT_KEY_DEPTH_LAYER_SHIFT=60, + SORT_KEY_UNSHADED_FLAG=uint64_t(1)<<59, + SORT_KEY_NO_DIRECTIONAL_FLAG=uint64_t(1)<<58, + SORT_KEY_SHADING_SHIFT=58, + SORT_KEY_SHADING_MASK=3, + SORT_KEY_MATERIAL_INDEX_SHIFT=40, + SORT_KEY_GEOMETRY_INDEX_SHIFT=20, + SORT_KEY_GEOMETRY_TYPE_SHIFT=15, SORT_KEY_SKELETON_FLAG=2, SORT_KEY_MIRROR_FLAG=1 @@ -302,8 +330,6 @@ public: RasterizerStorageGLES3::Material *material; RasterizerStorageGLES3::GeometryOwner *owner; uint64_t sort_key; - bool *additive_ptr; - bool additive; }; @@ -314,6 +340,7 @@ public: int element_count; int alpha_element_count; + void clear() { element_count=0; @@ -399,12 +426,10 @@ public: }; + LightInstance *directional_light; + LightInstance *directional_lights[RenderList::MAX_DIRECTIONAL_LIGHTS]; - LightInstance *directional_light_instances[RenderList::MAX_DIRECTIONAL_LIGHTS]; - int directional_light_instance_count; - LightInstance *light_instances[RenderList::MAX_LIGHTS]; - int light_instance_count; RenderList render_list; @@ -414,9 +439,9 @@ public: _FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e); _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); - _FORCE_INLINE_ void _setup_light(LightInstance *p_light); + _FORCE_INLINE_ void _setup_light(RenderList::Element *e); - void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow); + void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add); _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow); @@ -424,6 +449,7 @@ public: void _draw_skybox(RID p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform& p_cam_transform); + void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transform); void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_shadow_atlas); void _copy_screen(); void _copy_to_front_buffer(Environment *env); @@ -439,6 +465,7 @@ public: virtual void set_scene_pass(uint64_t p_pass); + void iteration(); void initialize(); void finalize(); RasterizerSceneGLES3(); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index b988781e1..6e278e563 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -3169,7 +3169,6 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ light->param[VS::LIGHT_PARAM_RANGE]=1.0; light->param[VS::LIGHT_PARAM_SPOT_ANGLE]=45; light->param[VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE]=0; - light->param[VS::LIGHT_PARAM_SHADOW_DARKNESS]=0; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET]=0.1; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET]=0.3; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET]=0.6; @@ -3184,6 +3183,7 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ light->directional_shadow_mode=VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; light->omni_shadow_mode=VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; light->omni_shadow_detail=VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL; + light->directional_blend_splits=false; light->version=0; @@ -3207,7 +3207,6 @@ void RasterizerStorageGLES3::light_set_param(RID p_light,VS::LightParam p_param, case VS::LIGHT_PARAM_RANGE: case VS::LIGHT_PARAM_SPOT_ANGLE: case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE: - case VS::LIGHT_PARAM_SHADOW_DARKNESS: case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET: case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: @@ -3230,20 +3229,22 @@ void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){ light->version++; light->instance_change_notify(); - - } -void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){ + +void RasterizerStorageGLES3::light_set_shadow_color(RID p_light,const Color& p_color) { Light * light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); - + light->shadow_color=p_color; } -void RasterizerStorageGLES3::light_set_attenuation_texure(RID p_light,RID p_texture){ + +void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){ Light * light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); + + light->projector=p_texture; } void RasterizerStorageGLES3::light_set_negative(RID p_light,bool p_enable){ @@ -3263,12 +3264,6 @@ void RasterizerStorageGLES3::light_set_cull_mask(RID p_light,uint32_t p_mask){ light->version++; light->instance_change_notify(); -} -void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){ - - Light * light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - } void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) { @@ -3315,6 +3310,26 @@ void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::L } +void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light,bool p_enable) { + + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->directional_blend_splits=p_enable; + light->version++; + light->instance_change_notify(); + +} + + +bool RasterizerStorageGLES3::light_directional_get_blend_splits(RID p_light) const { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,false); + + return light->directional_blend_splits; +} + VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) { const Light * light = light_owner.getornull(p_light); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index f8b34d6a1..0e3d47b61 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -634,12 +634,15 @@ public: VS::LightType type; float param[VS::LIGHT_PARAM_MAX]; Color color; + Color shadow_color; + RID projector; bool shadow; bool negative; uint32_t cull_mask; VS::LightOmniShadowMode omni_shadow_mode; VS::LightOmniShadowDetail omni_shadow_detail; VS::LightDirectionalShadowMode directional_shadow_mode; + bool directional_blend_splits; uint64_t version; }; @@ -650,17 +653,19 @@ public: virtual void light_set_color(RID p_light,const Color& p_color); virtual void light_set_param(RID p_light,VS::LightParam p_param,float p_value); virtual void light_set_shadow(RID p_light,bool p_enabled); + virtual void light_set_shadow_color(RID p_light,const Color& p_color); virtual void light_set_projector(RID p_light,RID p_texture); - virtual void light_set_attenuation_texure(RID p_light,RID p_texture); virtual void light_set_negative(RID p_light,bool p_enable); virtual void light_set_cull_mask(RID p_light,uint32_t p_mask); - virtual void light_set_shader(RID p_light,RID p_shader); - virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode); + virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode); virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail); virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode); + virtual void light_directional_set_blend_splits(RID p_light,bool p_enable); + virtual bool light_directional_get_blend_splits(RID p_light) const; + virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 052c91524..6f0616035 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -228,8 +228,15 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() { #endif + int define_line_ofs=1; + for(int i=0;i custom_defines; + int base_material_tex_index; Version * get_current_version(); @@ -357,6 +359,10 @@ public: void set_base_material_tex_index(int p_idx); + void add_custom_define(const String& p_define) { + custom_defines.push_back(p_define.utf8()); + } + virtual ~ShaderGLES3(); }; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index de1591e8f..ceb5a7211 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -68,24 +68,26 @@ layout(std140) uniform SceneData { //ubo:0 uniform highp mat4 world_transform; -#ifdef USE_FORWARD_LIGHTING +#ifdef USE_LIGHT_DIRECTIONAL -layout(std140) uniform LightData { //ubo:3 +layout(std140) uniform DirectionalLightData { //ubo:3 highp vec4 light_pos_inv_radius; mediump vec4 light_direction_attenuation; mediump vec4 light_color_energy; - mediump vec4 light_params; //cone attenuation, specular, shadow darkening, + mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled, mediump vec4 light_clamp; - mediump vec4 shadow_split_offsets; + mediump vec4 shadow_color; highp mat4 shadow_matrix1; highp mat4 shadow_matrix2; highp mat4 shadow_matrix3; highp mat4 shadow_matrix4; + mediump vec4 shadow_split_offsets; }; #endif + /* Varyings */ out highp vec3 vertex_interp; @@ -343,30 +345,71 @@ layout(std140) uniform SceneData { }; +//directional light data -#ifdef USE_FORWARD_LIGHTING +#ifdef USE_LIGHT_DIRECTIONAL -layout(std140) uniform LightData { +layout(std140) uniform DirectionalLightData { highp vec4 light_pos_inv_radius; mediump vec4 light_direction_attenuation; mediump vec4 light_color_energy; - mediump vec4 light_params; //cone attenuation, specular, shadow darkening, shadow enabled + mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled, mediump vec4 light_clamp; - mediump vec4 shadow_split_offsets; + mediump vec4 shadow_color; highp mat4 shadow_matrix1; highp mat4 shadow_matrix2; highp mat4 shadow_matrix3; highp mat4 shadow_matrix4; + mediump vec4 shadow_split_offsets; }; + +uniform highp sampler2DShadow directional_shadow; //texunit:-4 + #endif +//omni and spot + +struct LightData { + + highp vec4 light_pos_inv_radius; + mediump vec4 light_direction_attenuation; + mediump vec4 light_color_energy; + mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled, + mediump vec4 light_clamp; + mediump vec4 shadow_color; + highp mat4 shadow_matrix; + +}; + + +layout(std140) uniform OmniLightData { //ubo:4 + + LightData omni_lights[MAX_LIGHT_DATA_STRUCTS]; +}; + +layout(std140) uniform SpotLightData { //ubo:5 + + LightData spot_lights[MAX_LIGHT_DATA_STRUCTS]; +}; + -uniform highp sampler2DShadow directional_shadow; //texunit:-4 uniform highp sampler2DShadow shadow_atlas; //texunit:-3 +#ifdef USE_FORWARD_LIGHTING + +uniform int omni_light_indices[MAX_FORWARD_LIGHTS]; +uniform int omni_light_count; + +uniform int spot_light_indices[MAX_FORWARD_LIGHTS]; +uniform int spot_light_count; + +#endif + + + #ifdef USE_MULTIPLE_RENDER_TARGETS layout(location=0) out vec4 diffuse_buffer; @@ -415,18 +458,51 @@ float specularGGX(vec3 N, vec3 V, vec3 L, float roughness, float F0) return dotNL * D * F * vis; } -void light_compute(vec3 normal, vec3 light_vec,vec3 eye_vec,vec3 diffuse_color, vec3 specular_color, float roughness, float attenuation, inout vec3 diffuse, inout vec3 specular) { +void light_compute(vec3 normal, vec3 light_vec,vec3 eye_vec,vec3 light_color,vec3 diffuse_color, vec3 specular_color, float roughness, inout vec3 diffuse, inout vec3 specular) { - diffuse += max(0.0,dot(normal,light_vec)) * diffuse_color * attenuation; + diffuse += max(0.0,dot(normal,light_vec)) * light_color * diffuse_color; //specular += specular_ggx( roughness, max(0.0,dot(normal,eye_vec)) ) * specular_color * attenuation; float s = roughness > 0.0 ? specularGGX(normal,eye_vec,light_vec,roughness,1.0) : 0.0; - specular += s * specular_color * attenuation; + specular += s * light_color * specular_color; } float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) { +#ifdef SHADOW_MODE_PCF_13 + + float avg=textureProj(shadow,vec4(pos,depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x*2.0,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x*2.0,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y*2.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y*2.0),depth,1.0)); + return avg*(1.0/13.0); + +#endif + +#ifdef SHADOW_MODE_PCF_5 + + float avg=textureProj(shadow,vec4(pos,depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0)); + avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0)); + return avg*(1.0/5.0); +#endif + +#if !defined(SHADOW_MODE_PCF_5) && !defined(SHADOW_MODE_PCF_13) + return textureProj(shadow,vec4(pos,depth,1.0)); +#endif + } #ifdef RENDER_SHADOW_DUAL_PARABOLOID @@ -435,6 +511,73 @@ in highp float dp_clip; #endif +void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal,vec3 albedo, vec3 specular, float roughness, inout vec3 diffuse_light, inout vec3 specular_light) { + + vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex; + float normalized_distance = length( light_rel_vec )*omni_lights[idx].light_pos_inv_radius.w; + vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w )); + + if (omni_lights[idx].light_params.w>0.5) { + //there is a shadowmap + + highp vec3 splane=(omni_lights[idx].shadow_matrix * vec4(vertex,1.0)).xyz; + float shadow_len=length(splane); + splane=normalize(splane); + vec4 clamp_rect=omni_lights[idx].light_clamp; + + if (splane.z>=0.0) { + + splane.z+=1.0; + + clamp_rect.y+=clamp_rect.w; + + } else { + + splane.z=1.0 - splane.z; + + //if (clamp_rect.z0.5) { + //there is a shadowmap + highp vec4 splane=(spot_lights[idx].shadow_matrix * vec4(vertex,1.0)); + splane.xyz/=splane.w; + light_attenuation*=mix(spot_lights[idx].shadow_color.rgb,vec3(1.0),sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,spot_lights[idx].light_clamp)); + } + + light_compute(normal,normalize(light_rel_vec),eye_vec,spot_lights[idx].light_color_energy.rgb*light_attenuation,albedo,specular,roughness,diffuse_light,specular_light); + +} + void main() { #ifdef RENDER_SHADOW_DUAL_PARABOLOID @@ -561,9 +704,9 @@ FRAGMENT_SHADER_CODE #endif -#ifdef USE_FORWARD_DIRECTIONAL +#ifdef USE_LIGHT_DIRECTIONAL - float light_attenuation=1.0; + vec3 light_attenuation=vec3(1.0); #ifdef LIGHT_DIRECTIONAL_SHADOW @@ -589,7 +732,6 @@ FRAGMENT_SHADER_CODE highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; - ambient_light=vec3(1.0,0.4,0.4); #if defined(LIGHT_USE_PSSM_BLEND) @@ -603,7 +745,6 @@ FRAGMENT_SHADER_CODE highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; - ambient_light=vec3(0.4,1.0,0.4); #if defined(LIGHT_USE_PSSM_BLEND) splane=(shadow_matrix3 * vec4(vertex,1.0)); @@ -619,7 +760,6 @@ FRAGMENT_SHADER_CODE highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; - ambient_light=vec3(0.4,0.4,1.0); #if defined(LIGHT_USE_PSSM_BLEND) splane=(shadow_matrix4 * vec4(vertex,1.0)); @@ -678,12 +818,12 @@ FRAGMENT_SHADER_CODE //one one sample - light_attenuation=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp); + light_attenuation=mix(shadow_color.rgb,vec3(1.0),sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp)); #if defined(LIGHT_USE_PSSM_BLEND) if (use_blend) { - float light_attenuation2=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp); + vec3 light_attenuation2=mix(shadow_color.rgb,vec3(1.0),sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp)); light_attenuation=mix(light_attenuation,light_attenuation2,pssm_blend); } #endif @@ -692,84 +832,24 @@ FRAGMENT_SHADER_CODE #endif //LIGHT_DIRECTIONAL_SHADOW - light_compute(normal,-light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light); - - -#endif //USE_FORWARD_DIRECTIONAL - + light_compute(normal,-light_direction_attenuation.xyz,eye_vec,light_color_energy.rgb*light_attenuation,albedo,specular,roughness,diffuse_light,specular_light); -#ifdef USE_FORWARD_OMNI - vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex; - float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w; - float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w ); +#endif //#USE_LIGHT_DIRECTIONAL - if (light_params.w>0.5) { - //there is a shadowmap - - highp vec3 splane=(shadow_matrix1 * vec4(vertex,1.0)).xyz; - float shadow_len=length(splane); - splane=normalize(splane); - vec4 clamp_rect=light_clamp; - - if (splane.z>=0.0) { - - splane.z+=1.0; - clamp_rect.y+=clamp_rect.w; - - } else { - - splane.z=1.0 - splane.z; - - //if (clamp_rect.z0.5) { - //there is a shadowmap - - highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); - splane.xyz/=splane.w; - // splane.xy=splane.xy*0.5+0.5; - - //splane.xy=light_clamp.xy+splane.xy*light_clamp.zw; - light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,light_clamp); - + for(int i=0;ilight_set_shadow_color(light,p_shadow_color); +} + +Color Light::get_shadow_color() const{ + + return shadow_color; +} + AABB Light::get_aabb() const { @@ -197,18 +208,18 @@ void Light::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_color","color"), &Light::set_color ); ObjectTypeDB::bind_method(_MD("get_color"), &Light::get_color ); - ADD_PROPERTY( PropertyInfo( Variant::COLOR, "light/color"), _SCS("set_color"), _SCS("get_color")); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/energy"), _SCS("set_param"), _SCS("get_param"), PARAM_ENERGY); + ObjectTypeDB::bind_method(_MD("set_shadow_color","shadow_color"), &Light::set_shadow_color ); + ObjectTypeDB::bind_method(_MD("get_shadow_color"), &Light::get_shadow_color ); + + ADD_PROPERTY( PropertyInfo( Variant::COLOR, "light/color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_color"), _SCS("get_color")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/energy",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_ENERGY); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "light/negative"), _SCS("set_negative"), _SCS("is_negative")); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/specular"), _SCS("set_param"), _SCS("get_param"), PARAM_SPECULAR); - ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask"), _SCS("set_cull_mask"), _SCS("get_cull_mask")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/specular",PROPERTY_HINT_RANGE,"0,1,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SPECULAR); + ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_cull_mask"), _SCS("get_cull_mask")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow")); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkness"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_DARKNESS); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/normal_bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_NORMAL_BIAS); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias_split_scale"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS_SPLIT_SCALE); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/max_distance"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE); - + ADD_PROPERTY( PropertyInfo( Variant::COLOR, "shadow/color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_shadow_color"), _SCS("get_shadow_color")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/max_distance",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editor/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only")); BIND_CONSTANT( PARAM_ENERGY ); @@ -218,7 +229,6 @@ void Light::_bind_methods() { BIND_CONSTANT( PARAM_SPOT_ANGLE ); BIND_CONSTANT( PARAM_SPOT_ATTENUATION ); BIND_CONSTANT( PARAM_SHADOW_MAX_DISTANCE ); - BIND_CONSTANT( PARAM_SHADOW_DARKNESS ); BIND_CONSTANT( PARAM_SHADOW_SPLIT_1_OFFSET ); BIND_CONSTANT( PARAM_SHADOW_SPLIT_2_OFFSET ); BIND_CONSTANT( PARAM_SHADOW_SPLIT_3_OFFSET ); @@ -250,7 +260,6 @@ Light::Light(VisualServer::LightType p_type) { set_param(PARAM_SPOT_ANGLE,45); set_param(PARAM_SPOT_ATTENUATION,1); set_param(PARAM_SHADOW_MAX_DISTANCE,0); - set_param(PARAM_SHADOW_DARKNESS,0); set_param(PARAM_SHADOW_SPLIT_1_OFFSET,0.1); set_param(PARAM_SHADOW_SPLIT_2_OFFSET,0.2); set_param(PARAM_SHADOW_SPLIT_3_OFFSET,0.5); @@ -291,6 +300,7 @@ DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const { void DirectionalLight::set_blend_splits(bool p_enable) { blend_splits=p_enable; + VS::get_singleton()->light_directional_set_blend_splits(light,p_enable); } bool DirectionalLight::is_blend_splits_enabled() const { @@ -307,11 +317,13 @@ void DirectionalLight::_bind_methods() { ObjectTypeDB::bind_method( _MD("set_blend_splits","enabled"),&DirectionalLight::set_blend_splits); ObjectTypeDB::bind_method( _MD("is_blend_splits_enabled"),&DirectionalLight::is_blend_splits_enabled); - ADD_PROPERTY( PropertyInfo( Variant::INT, "directional/shadow_mode",PROPERTY_HINT_ENUM,"Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode")); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "directional/blend_splits"), _SCS("set_blend_splits"), _SCS("is_blend_splits_enabled")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "directional_shadow/mode",PROPERTY_HINT_ENUM,"Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/split_1",PROPERTY_HINT_RANGE,"0,1,0.001"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/split_2",PROPERTY_HINT_RANGE,"0,1,0.001"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/split_3",PROPERTY_HINT_RANGE,"0,1,0.001"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "directional_shadow/blend_splits"), _SCS("set_blend_splits"), _SCS("is_blend_splits_enabled")); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/normal_bias",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_NORMAL_BIAS); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/bias_split_scale",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS_SPLIT_SCALE); BIND_CONSTANT( SHADOW_ORTHOGONAL ); BIND_CONSTANT( SHADOW_PARALLEL_2_SPLITS ); @@ -358,8 +370,8 @@ void OmniLight::_bind_methods() { ObjectTypeDB::bind_method( _MD("set_shadow_detail","detail"),&OmniLight::set_shadow_detail); ObjectTypeDB::bind_method( _MD("get_shadow_detail"),&OmniLight::get_shadow_detail); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/range",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/attenuation",PROPERTY_HINT_EXP_EASING), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_mode",PROPERTY_HINT_ENUM,"Dual Paraboloid,Cube"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode")); ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_detail",PROPERTY_HINT_ENUM,"Vertical,Horizontal"), _SCS("set_shadow_detail"), _SCS("get_shadow_detail")); @@ -374,10 +386,10 @@ OmniLight::OmniLight() : Light( VisualServer::LIGHT_OMNI ) { void SpotLight::_bind_methods() { - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/range",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/attenuation",PROPERTY_HINT_EXP_EASING), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_angle",PROPERTY_HINT_RANGE,"0,180,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_attenuation",PROPERTY_HINT_EXP_EASING), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION); } diff --git a/scene/3d/light.h b/scene/3d/light.h index da2854281..fcf5ce90f 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -52,7 +52,6 @@ public: PARAM_SPOT_ANGLE = VS::LIGHT_PARAM_SPOT_ANGLE, PARAM_SPOT_ATTENUATION = VS::LIGHT_PARAM_SPOT_ATTENUATION, PARAM_SHADOW_MAX_DISTANCE = VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE, - PARAM_SHADOW_DARKNESS = VS::LIGHT_PARAM_SHADOW_DARKNESS, PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET, PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET, PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET, @@ -66,6 +65,7 @@ private: Color color; float param[PARAM_MAX]; + Color shadow_color; bool shadow; bool negative; uint32_t cull_mask; @@ -107,6 +107,9 @@ public: void set_color(const Color& p_color); Color get_color() const; + void set_shadow_color(const Color& p_shadow_color); + Color get_shadow_color() const; + virtual AABB get_aabb() const; virtual DVector get_faces(uint32_t p_usage_flags) const; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index d87cc0fd8..06509c6fd 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -78,6 +78,7 @@ public: Transform transform; int depth_layer; + uint32_t layer_mask; //RID sampled_light; @@ -114,6 +115,7 @@ public: billboard=false; billboard_y=false; depth_layer=0; + layer_mask=1; } }; @@ -295,16 +297,17 @@ public: virtual void light_set_color(RID p_light,const Color& p_color)=0; virtual void light_set_param(RID p_light,VS::LightParam p_param,float p_value)=0; virtual void light_set_shadow(RID p_light,bool p_enabled)=0; + virtual void light_set_shadow_color(RID p_light,const Color& p_color)=0; virtual void light_set_projector(RID p_light,RID p_texture)=0; - virtual void light_set_attenuation_texure(RID p_light,RID p_texture)=0; virtual void light_set_negative(RID p_light,bool p_enable)=0; virtual void light_set_cull_mask(RID p_light,uint32_t p_mask)=0; - virtual void light_set_shader(RID p_light,RID p_shader)=0; virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode)=0; virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail)=0; virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode)=0; + virtual void light_directional_set_blend_splits(RID p_light,bool p_enable)=0; + virtual bool light_directional_get_blend_splits(RID p_light) const=0; virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light)=0; virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light)=0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 7810cc901..4d8a46122 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -757,16 +757,16 @@ public: BIND2(light_set_color,RID,const Color&) BIND3(light_set_param,RID ,LightParam ,float ) BIND2(light_set_shadow,RID ,bool ) + BIND2(light_set_shadow_color,RID ,const Color& ) BIND2(light_set_projector,RID,RID ) - BIND2(light_set_attenuation_texure,RID,RID ) BIND2(light_set_negative,RID,bool ) BIND2(light_set_cull_mask,RID ,uint32_t ) - BIND2(light_set_shader,RID ,RID ) BIND2(light_omni_set_shadow_mode,RID,LightOmniShadowMode) BIND2(light_omni_set_shadow_detail,RID,LightOmniShadowDetail) BIND2(light_directional_set_shadow_mode,RID,LightDirectionalShadowMode) + BIND2(light_directional_set_blend_splits,RID,bool) /* PROBE API */ diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index e36e31e19..e214374f4 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1165,7 +1165,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer float texture_size=VSG::scene_render->get_directional_light_shadow_size(light->instance); - bool overlap = false;//rasterizer->light_instance_get_pssm_shadow_overlap(p_light->light_info->instance); + bool overlap = VSG::storage->light_directional_get_blend_splits(p_instance->base); for (int i=0;iframe.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index c799cd12a..dabb7918a 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -122,11 +122,13 @@ void RasterizerGLES3::begin_frame(){ storage->frame.time[1]=Math::fmod(time_total,3600); storage->frame.time[2]=Math::fmod(time_total,900); storage->frame.time[3]=Math::fmod(time_total,60); + storage->frame.count++; storage->update_dirty_shaders(); storage->update_dirty_materials(); scene->iteration(); + } void RasterizerGLES3::set_current_render_target(RID p_render_target){ diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 4ae257abc..e04908ea6 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -446,6 +446,338 @@ int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) return shadow_size; } +////////////////////////////////////////////////////// + +RID RasterizerSceneGLES3::reflection_atlas_create() { + + ReflectionAtlas *reflection_atlas = memnew( ReflectionAtlas ); + reflection_atlas->subdiv=0; + reflection_atlas->color=0; + for(int i=0;i<6;i++) { + reflection_atlas->fbo[i]=0; + } + + return reflection_atlas_owner.make_rid(reflection_atlas); +} + +void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas,int p_size) { + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND(!reflection_atlas); + + int size = nearest_power_of_2(p_size); + + if (size==reflection_atlas->size) + return; + if (reflection_atlas->size) { + for(int i=0;i<6;i++) { + glDeleteFramebuffers(1,&reflection_atlas->fbo[i]); + reflection_atlas->fbo[i]=0; + } + glDeleteTextures(1,&reflection_atlas->color); + reflection_atlas->color=0; + } + + reflection_atlas->size=size; + + for(int i=0;ireflections.size();i++) { + //erase probes reference to this + if (reflection_atlas->reflections[i].owner.is_valid()) { + ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); + reflection_atlas->reflections[i].owner=RID(); + + ERR_CONTINUE(!reflection_probe_instance); + reflection_probe_instance->reflection_atlas_index=-1; + reflection_probe_instance->atlas=RID(); + reflection_probe_instance->render_step=-1; + } + } + + + if (reflection_atlas->size) { + + bool use_float=true; + + + GLenum internal_format = use_float?GL_RGBA16F:GL_RGB10_A2; + GLenum format = GL_RGBA; + GLenum type = use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV; + + + // Create a texture for storing the color + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &reflection_atlas->color); + glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); + + int mmsize=reflection_atlas->size; + + for(int i=0;i<6;i++) { + glTexImage2D(GL_TEXTURE_2D, i, internal_format, mmsize, mmsize, 0, + format, type, NULL); + + mmsize>>=1; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + mmsize=reflection_atlas->size; + + for(int i=0;i<6;i++) { + glGenFramebuffers(1, &reflection_atlas->fbo[i]); + glBindFramebuffer(GL_FRAMEBUFFER, reflection_atlas->fbo[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, reflection_atlas->color, i); + glDisable(GL_SCISSOR_TEST); + glViewport(0,0,mmsize,mmsize); + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT); //it needs to be cleared, to avoid generating garbage + + mmsize>>=1; + + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); + + } + + + +} +void RasterizerSceneGLES3::reflection_atlas_set_subdivision(RID p_ref_atlas,int p_subdiv) { + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND(!reflection_atlas); + + uint32_t subdiv = nearest_power_of_2(p_subdiv); + if (subdiv&0xaaaaaaaa) { //sqrt(subdiv) must be integer + subdiv<<=1; + } + + subdiv=int(Math::sqrt(subdiv)); + + if (reflection_atlas->subdiv==subdiv) + return; + + + if (subdiv) { + + for(int i=0;ireflections.size();i++) { + //erase probes reference to this + if (reflection_atlas->reflections[i].owner.is_valid()) { + ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); + reflection_atlas->reflections[i].owner=RID(); + + ERR_CONTINUE(!reflection_probe_instance); + reflection_probe_instance->reflection_atlas_index=-1; + reflection_probe_instance->atlas=RID(); + reflection_probe_instance->render_step=-1; + } + } + } + + reflection_atlas->subdiv=subdiv; + + reflection_atlas->reflections.resize(subdiv*subdiv); +} + + +//////////////////////////////////////////////////// + +RID RasterizerSceneGLES3::reflection_probe_instance_create(RID p_probe) { + + RasterizerStorageGLES3::ReflectionProbe *probe = storage->reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!probe,RID()); + + ReflectionProbeInstance *rpi = memnew( ReflectionProbeInstance ); + + rpi->probe_ptr=probe; + rpi->self=reflection_probe_instance_owner.make_rid(rpi); + rpi->probe=p_probe; + rpi->reflection_atlas_index=-1; + rpi->render_step=-1; + rpi->last_pass=0; + + return rpi->self; +} + +void RasterizerSceneGLES3::reflection_probe_instance_set_transform(RID p_instance,const Transform& p_transform) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + rpi->transform=p_transform; + +} + +void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + if (rpi->reflection_atlas_index==-1) + return; + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(rpi->atlas); + ERR_FAIL_COND(!reflection_atlas); + + ERR_FAIL_INDEX(rpi->reflection_atlas_index,reflection_atlas->reflections.size()); + + ERR_FAIL_COND(reflection_atlas->reflections[rpi->reflection_atlas_index].owner!=rpi->self); + + reflection_atlas->reflections[rpi->reflection_atlas_index].owner=RID(); + + rpi->reflection_atlas_index=-1; + rpi->atlas=RID(); + rpi->render_step=-1; + +} + +bool RasterizerSceneGLES3::reflection_probe_instance_needs_redraw(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,false); + + return rpi->reflection_atlas_index==-1 || rpi->probe_ptr->update_mode==VS::REFLECTION_PROBE_UPDATE_ALWAYS; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_has_reflection(RID p_instance){ + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,false); + + return rpi->reflection_atlas_index!=-1; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance,RID p_reflection_atlas) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,false); + + rpi->render_step=0; + + if (rpi->reflection_atlas_index!=-1) { + return true; //got one already + } + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); + ERR_FAIL_COND_V(!reflection_atlas,false); + + + if (reflection_atlas->size==0 || reflection_atlas->subdiv==0) { + return false; + } + + + int best_free=-1; + int best_used=-1; + uint64_t best_used_frame; + + for(int i=0;ireflections.size();i++) { + if (reflection_atlas->reflections[i].owner==RID()) { + best_free=i; + break; + } + + if (rpi->render_step<0 && reflection_atlas->reflections[i].last_frameframe.count && + (best_used==-1 || reflection_atlas->reflections[i].last_framereflections[i].last_frame; + } + } + + if (best_free==-1 && best_used==-1) { + return false ;// sorry, can not do. Try again next frame. + } + + if (best_free==-1) { + //find best from what is used + best_free=best_used; + + ReflectionProbeInstance *victim_rpi = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[best_free].owner); + ERR_FAIL_COND_V(!victim_rpi,false); + victim_rpi->atlas=RID(); + victim_rpi->reflection_atlas_index=-1; + + } + + reflection_atlas->reflections[best_free].owner=p_instance; + reflection_atlas->reflections[best_free].last_frame=storage->frame.count; + + rpi->reflection_atlas_index=best_free; + rpi->atlas=p_reflection_atlas; + rpi->render_step=0; + + return true; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_postprocess_step(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,true); + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(rpi->atlas); + ERR_FAIL_COND_V(!reflection_atlas,false); + + ERR_FAIL_COND_V(rpi->render_step>=6,true); + + glBindFramebuffer(GL_FRAMEBUFFER,reflection_atlas->fbo[rpi->render_step]); + state.cube_to_dp_shader.bind(); + + int target_size=reflection_atlas->size/reflection_atlas->subdiv; + + int cubemap_index=reflection_cubemaps.size()-1; + + for(int i=reflection_cubemaps.size()-1;i>=0;i--) { + //find appropriate cubemap to render to + if (reflection_cubemaps[i].size>target_size*2) + break; + + cubemap_index=i; + } + + glDisable(GL_BLEND); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP,reflection_cubemaps[cubemap_index].cubemap); + glDisable(GL_CULL_FACE); + + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,true); + storage->shaders.cubemap_filter.bind(); + + int cell_size = reflection_atlas->size / reflection_atlas->subdiv; + for(int i=0;irender_step;i++) { + cell_size>>=1; //mipmaps! + } + int x = (rpi->reflection_atlas_index % reflection_atlas->subdiv) * cell_size; + int y = (rpi->reflection_atlas_index / reflection_atlas->subdiv) * cell_size; + int width=cell_size; + int height=cell_size; + + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE,rpi->render_step==0); + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY,rpi->probe_ptr->update_mode==VS::REFLECTION_PROBE_UPDATE_ALWAYS); + for(int i=0;i<2;i++) { + + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP,i>0); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,rpi->render_step/5.0); + + uint32_t local_width=width,local_height=height; + uint32_t local_x=x,local_y=y; + + local_height/=2; + local_y+=i*local_height; + + glViewport(local_x,local_y,local_width,local_height); + + _copy_screen(); + } + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE,false); + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY,false); + + + rpi->render_step++; + + return rpi->render_step==6; +} /* ENVIRONMENT API */ @@ -464,26 +796,12 @@ void RasterizerSceneGLES3::environment_set_background(RID p_env,VS::EnvironmentB env->bg_mode=p_bg; } -void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox, int p_radiance_size){ +void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox){ Environment *env=environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - if (env->skybox_color.is_valid()) { - env->skybox_color=RID(); - } - if (env->skybox_radiance.is_valid()) { - storage->free(env->skybox_radiance); - env->skybox_radiance=RID(); - } - - - if (p_skybox.is_valid()) { - - env->skybox_color=p_skybox; - env->skybox_radiance=storage->texture_create_radiance_cubemap(p_skybox,p_radiance_size); - //env->skybox_irradiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_IRRADIANCE,p_irradiance_size); - } + env->skybox=p_skybox; } @@ -775,6 +1093,7 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) { RasterizerStorageGLES3::Surface *s = static_cast(e->geometry); glBindVertexArray(s->array_id); // everything is so easy nowadays + } break; } @@ -821,6 +1140,8 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) { int omni_count=0; int spot_indices[16]; int spot_count=0; + int reflection_indices[16]; + int reflection_count=0; int maxobj = MIN(16,state.max_forward_lights_per_object); @@ -859,6 +1180,32 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) { glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES),spot_count,spot_indices); } + + int rc = e->instance->reflection_probe_instances.size(); + + + if (rc) { + + + const RID* reflections=e->instance->reflection_probe_instances.ptr(); + + for(int i=0;ilast_pass!=render_pass) //not visible + continue; + + if (reflection_countreflection_index; + } + } + } + + state.scene_shader.set_uniform(SceneShaderGLES3::REFLECTION_COUNT,reflection_count); + if (reflection_count) { + glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::REFLECTION_INDICES),reflection_count,reflection_indices); + } + + } @@ -932,9 +1279,9 @@ void RasterizerSceneGLES3::_set_cull(bool p_front,bool p_reverse_cull) { -void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow,bool p_directional_add) { +void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,GLuint p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow,bool p_directional_add,bool p_directional_shadows) { - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { //p_reverse_cull=!p_reverse_cull; glFrontFace(GL_CCW); } else { @@ -951,15 +1298,15 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e if (p_base_env) { glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); - glBindTexture(p_base_env->target,p_base_env->tex_id); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true); + glBindTexture(GL_TEXTURE_2D,p_base_env); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,true); } else { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); } } else { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); } @@ -1038,7 +1385,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e if (p_directional_add || (directional_light && (e->sort_key&RenderList::SORT_KEY_NO_DIRECTIONAL_FLAG)==0)) { state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,true); - if (directional_light->light_ptr->shadow) { + if (p_directional_shadows && directional_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,true); switch(directional_light->light_ptr->directional_shadow_mode) { @@ -1076,7 +1423,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: { glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { @@ -1097,7 +1444,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } break; case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: { glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { @@ -1154,7 +1501,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glFrontFace(GL_CW); glBindVertexArray(0); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); @@ -1290,9 +1637,12 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g } } -void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { +void RasterizerSceneGLES3::_draw_skybox(RasterizerStorageGLES3::SkyBox *p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { + + if (!p_skybox) + return; - RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox); + RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox->cubemap); ERR_FAIL_COND(!tex); glActiveTexture(GL_TEXTURE0); @@ -1461,7 +1811,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,const CameraMatri } -void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& p_camera_inverse_transform) { +void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& p_camera_inverse_transform,bool p_use_shadows) { LightInstance *li = directional_lights[p_index]; @@ -1499,7 +1849,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& ubo_data.light_shadow_color[3]=1.0; - if (li->light_ptr->shadow) { + if (p_use_shadows && li->light_ptr->shadow) { int shadow_count=0; @@ -1568,7 +1918,6 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& Rect2 atlas_rect = Rect2(float(x)/directional_shadow.size,float(y)/directional_shadow.size,float(width)/directional_shadow.size,float(height)/directional_shadow.size); rectm.set_light_atlas_rect(atlas_rect); -// print_line("atlas rect: "+atlas_rect); CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview; @@ -1844,6 +2193,103 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu } +void RasterizerSceneGLES3::_setup_reflections(RID *p_reflection_probe_cull_result,int p_reflection_probe_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection,RID p_reflection_atlas,Environment *p_env) { + + state.reflection_probe_count=0; + + for(int i=0;ireflection_atlas_index<0); + + + if (state.reflection_probe_count>=state.max_ubo_reflections) + break; + + rpi->last_pass=render_pass; + + + ReflectionProbeDataUBO reflection_ubo; + + reflection_ubo.box_extents[0]=rpi->probe_ptr->extents.x; + reflection_ubo.box_extents[1]=rpi->probe_ptr->extents.y; + reflection_ubo.box_extents[2]=rpi->probe_ptr->extents.z; + reflection_ubo.box_extents[3]=0; + + + + reflection_ubo.box_ofs[0]=rpi->probe_ptr->origin_offset.x; + reflection_ubo.box_ofs[1]=rpi->probe_ptr->origin_offset.y; + reflection_ubo.box_ofs[2]=rpi->probe_ptr->origin_offset.z; + reflection_ubo.box_ofs[3]=0; + + reflection_ubo.params[0]=rpi->probe_ptr->intensity; + reflection_ubo.params[1]=0; + reflection_ubo.params[2]=rpi->probe_ptr->interior?1.0:0.0; + reflection_ubo.params[3]=rpi->probe_ptr->box_projection?1.0:0.0; + + if (rpi->probe_ptr->interior) { + Color ambient_linear = rpi->probe_ptr->interior_ambient.to_linear(); + reflection_ubo.ambient[0]=ambient_linear.r*rpi->probe_ptr->interior_ambient_energy; + reflection_ubo.ambient[1]=ambient_linear.g*rpi->probe_ptr->interior_ambient_energy; + reflection_ubo.ambient[2]=ambient_linear.b*rpi->probe_ptr->interior_ambient_energy; + reflection_ubo.ambient[3]=rpi->probe_ptr->interior_ambient_probe_contrib; + } else { + Color ambient_linear; + float contrib=0; + if (p_env) { + ambient_linear=p_env->ambient_color.to_linear(); + ambient_linear.r*=p_env->ambient_energy; + ambient_linear.g*=p_env->ambient_energy; + ambient_linear.b*=p_env->ambient_energy; + contrib=p_env->ambient_skybox_contribution; + } + + reflection_ubo.ambient[0]=ambient_linear.r; + reflection_ubo.ambient[1]=ambient_linear.g; + reflection_ubo.ambient[2]=ambient_linear.b; + reflection_ubo.ambient[3]=0; + } + + int cell_size = reflection_atlas->size / reflection_atlas->subdiv; + int x = (rpi->reflection_atlas_index % reflection_atlas->subdiv) * cell_size; + int y = (rpi->reflection_atlas_index / reflection_atlas->subdiv) * cell_size; + int width=cell_size; + int height=cell_size; + + reflection_ubo.atlas_clamp[0]=float(x)/reflection_atlas->size; + reflection_ubo.atlas_clamp[1]=float(y)/reflection_atlas->size; + reflection_ubo.atlas_clamp[2]=float(width)/reflection_atlas->size; + reflection_ubo.atlas_clamp[3]=float(height/2)/reflection_atlas->size; + + Transform proj = (p_camera_inverse_transform * rpi->transform).inverse(); + store_transform(proj,reflection_ubo.local_matrix); + + rpi->reflection_index=state.reflection_probe_count; + copymem(&state.reflection_array_tmp[rpi->reflection_index*sizeof(ReflectionProbeDataUBO)],&reflection_ubo,sizeof(ReflectionProbeDataUBO)); + state.reflection_probe_count++; + + } + + + if (state.reflection_probe_count) { + + + glBindBuffer(GL_UNIFORM_BUFFER, state.reflection_array_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, state.reflection_probe_count*sizeof(ReflectionProbeDataUBO), state.reflection_array_tmp); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + glBindBufferBase(GL_UNIFORM_BUFFER,6,state.reflection_array_ubo); + } + +} + + void RasterizerSceneGLES3::_copy_screen() { glBindVertexArray(storage->resources.quadie_array); @@ -1959,7 +2405,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_ } -void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas){ +void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass){ //first of all, make a new render pass render_pass++; @@ -1969,6 +2415,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C Environment *env = environment_owner.getornull(p_environment); ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); if (shadow_atlas && shadow_atlas->size) { glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-3); @@ -1979,9 +2426,21 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C state.ubo_data.shadow_atlas_pixel_size[1]=1.0/shadow_atlas->size; } + + if (reflection_atlas && reflection_atlas->size) { + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-5); + glBindTexture(GL_TEXTURE_2D,reflection_atlas->color); + } + + if (p_reflection_probe.is_valid()) { + state.ubo_data.reflection_multiplier=0.0; + } else { + state.ubo_data.reflection_multiplier=1.0; + } _setup_environment(env,p_cam_projection,p_cam_transform); _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_shadow_atlas); + _setup_reflections(p_reflection_probe_cull_result,p_reflection_probe_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_reflection_atlas,env); render_list.clear(); @@ -1998,24 +2457,55 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glEnable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - RasterizerStorageGLES3::Texture* env_radiance_tex=NULL; - glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height); + ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe); + GLuint current_fbo; - if (use_mrt) { + if (probe) { - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,true); + ReflectionAtlas *ref_atlas = reflection_atlas_owner.getptr(probe->atlas); + ERR_FAIL_COND(!ref_atlas); - Color black(0,0,0,0); - glClearBufferfv(GL_COLOR,1,black.components); // specular - glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough + int target_size=ref_atlas->size/ref_atlas->subdiv; - } else { + int cubemap_index=reflection_cubemaps.size()-1; - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); + for(int i=reflection_cubemaps.size()-1;i>=0;i--) { + //find appropriate cubemap to render to + if (reflection_cubemaps[i].size>target_size*2) + break; + + cubemap_index=i; + } + + current_fbo=reflection_cubemaps[cubemap_index].fbo_id[p_reflection_probe_pass]; + use_mrt=false; state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); + glViewport(0,0,reflection_cubemaps[cubemap_index].size,reflection_cubemaps[cubemap_index].size); + glBindFramebuffer(GL_FRAMEBUFFER,current_fbo); + } else { + + glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height); + + if (use_mrt) { + + current_fbo=storage->frame.current_rt->buffers.fbo; + + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,true); + + Color black(0,0,0,0); + glClearBufferfv(GL_COLOR,1,black.components); // specular + glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough + + } else { + + current_fbo = storage->frame.current_rt->buffers.alpha_fbo; + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); + + } } @@ -2024,6 +2514,9 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C Color clear_color(0,0,0,0); + RasterizerStorageGLES3::SkyBox *skybox=NULL; + GLuint env_radiance_tex=0; + if (!env || env->bg_mode==VS::ENV_BG_CLEAR_COLOR) { if (storage->frame.clear_request) { @@ -2039,8 +2532,10 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C storage->frame.clear_request=false; } else if (env->bg_mode==VS::ENV_BG_SKYBOX) { - if (env->skybox_radiance.is_valid()) { - env_radiance_tex = storage->texture_owner.getornull(env->skybox_radiance); + skybox = storage->skybox_owner.getornull(env->skybox); + + if (skybox) { + env_radiance_tex=skybox->radiance; } storage->frame.clear_request=false; @@ -2055,7 +2550,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -2065,23 +2560,25 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C render_list.sort_by_key(false); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } + + if (state.directional_light_count==0) { directional_light=NULL; - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,false); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,false,shadow_atlas!=NULL); } else { for(int i=0;i0) { glEnable(GL_BLEND); } - _setup_directional_light(i,p_cam_transform.affine_inverse()); - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,i>0); + _setup_directional_light(i,p_cam_transform.affine_inverse(),shadow_atlas!=NULL); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,i>0,shadow_atlas!=NULL); } } @@ -2095,7 +2592,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); //switch to alpha fbo for skybox, only diffuse/ambient matters } - _draw_skybox(env->skybox_color,p_cam_projection,p_cam_transform,storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP],env->skybox_scale); + _draw_skybox(skybox,p_cam_projection,p_cam_transform,storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP],env->skybox_scale); } @@ -2112,24 +2609,30 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); - - render_list.sort_by_depth(true); + if (use_mrt) { + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); + } + render_list.sort_by_depth(true); if (state.directional_light_count==0) { directional_light=NULL; - _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false,false); + _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false,false,shadow_atlas!=NULL); } else { for(int i=0;i0); + _setup_directional_light(i,p_cam_transform.affine_inverse(),shadow_atlas!=NULL); + _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false,i>0,shadow_atlas!=NULL); } } + if (probe) { + //rendering a probe, do no more! + return; + } + _copy_to_front_buffer(env); /* if (shadow_atlas) { @@ -2143,6 +2646,17 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C } */ + + if (false && reflection_atlas && storage->frame.current_rt) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,reflection_atlas->color); + storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1)); + + } + if (false && directional_shadow.fbo) { //_copy_texture_to_front_buffer(shadow_atlas->depth); @@ -2154,6 +2668,16 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C } + if (false && env_radiance_tex) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,env_radiance_tex); + storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1)); + + } + #if 0 if (use_fb) { @@ -2534,7 +3058,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,true); - _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true,false); + _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true,false,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false); @@ -2624,6 +3148,19 @@ bool RasterizerSceneGLES3::free(RID p_rid) { shadow_atlas_set_size(p_rid,0); shadow_atlas_owner.free(p_rid); memdelete(shadow_atlas); + } else if (reflection_atlas_owner.owns(p_rid)) { + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.get(p_rid); + reflection_atlas_set_size(p_rid,0); + reflection_atlas_owner.free(p_rid); + memdelete(reflection_atlas); + } else if (reflection_probe_instance_owner.owns(p_rid)) { + + ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid); + + reflection_probe_release_atlas_index(p_rid); + reflection_probe_instance_owner.free(p_rid); + memdelete(reflection_instance); } else { return false; @@ -2890,6 +3427,7 @@ void RasterizerSceneGLES3::initialize() { const int ubo_light_size=160; state.ubo_light_size=ubo_light_size; state.max_ubo_lights=max_ubo_size/ubo_light_size; + print_line("max ubo light: "+itos(state.max_ubo_lights)); state.spot_array_tmp = (uint8_t*)memalloc(ubo_light_size*state.max_ubo_lights); state.omni_array_tmp = (uint8_t*)memalloc(ubo_light_size*state.max_ubo_lights); @@ -2912,10 +3450,21 @@ void RasterizerSceneGLES3::initialize() { state.max_forward_lights_per_object=8; + state.scene_shader.add_custom_define("#define MAX_LIGHT_DATA_STRUCTS "+itos(state.max_ubo_lights)+"\n"); state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS "+itos(state.max_forward_lights_per_object)+"\n"); + state.max_ubo_reflections=max_ubo_size/sizeof(ReflectionProbeDataUBO); + print_line("max ubo reflections: "+itos(state.max_ubo_reflections)+" ubo size: "+itos(sizeof(ReflectionProbeDataUBO))); + state.reflection_array_tmp = (uint8_t*)memalloc(sizeof(ReflectionProbeDataUBO)*state.max_ubo_reflections); + + glGenBuffers(1, &state.reflection_array_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.reflection_array_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeDataUBO)*state.max_ubo_reflections, NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + state.scene_shader.add_custom_define("#define MAX_REFLECTION_DATA_STRUCTS "+itos(state.max_ubo_reflections)+"\n"); } @@ -2923,6 +3472,73 @@ void RasterizerSceneGLES3::initialize() { Globals::get_singleton()->set_custom_property_info("rendering/gles3/shadow_filter_mode",PropertyInfo(Variant::INT,"rendering/gles3/shadow_filter_mode",PROPERTY_HINT_ENUM,"Disabled,PCF5,PCF13")); shadow_filter_mode=SHADOW_FILTER_NEAREST; + { //reflection cubemaps + int max_reflection_cubemap_sampler_size=512; + + int cube_size = max_reflection_cubemap_sampler_size; + + glActiveTexture(GL_TEXTURE0); + + bool use_float=true; + + GLenum internal_format = use_float?GL_RGBA16F:GL_RGB10_A2; + GLenum format = GL_RGBA; + GLenum type = use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV; + + while(cube_size>=32) { + + ReflectionCubeMap cube; + cube.size=cube_size; + + glGenTextures(1,&cube.depth); + glBindTexture(GL_TEXTURE_2D,cube.depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cube.size, cube.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + + glGenTextures(1,&cube.cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP,cube.cubemap); + //gen cubemap first + for(int i=0;i<6;i++) { + + glTexImage2D(_cube_side_enum[i], 0, internal_format, cube.size, cube.size, 0, format, type, NULL); + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // Remove artifact on the edges of the reflectionmap + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + //gen renderbuffers second, because it needs a complete cubemap + for(int i=0;i<6;i++) { + + glGenFramebuffers(1, &cube.fbo_id[i]); + glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo_id[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,_cube_side_enum[i], cube.cubemap, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D, cube.depth, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); + } + + reflection_cubemaps.push_back(cube); + + cube_size>>=1; + } + } + + +#ifdef GLEW_ENABLED +//"desktop" opengl needs this. + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + +#endif } void RasterizerSceneGLES3::iteration() { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 24b6a36fc..81c13bdc0 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -62,6 +62,7 @@ public: float shadow_dual_paraboloid_render_side; float shadow_atlas_pixel_size[2]; float shadow_directional_pixel_size[2]; + float reflection_multiplier; } ubo_data; @@ -87,17 +88,23 @@ public: GLuint spot_array_ubo; GLuint omni_array_ubo; + GLuint reflection_array_ubo; uint32_t ubo_light_size; uint8_t *spot_array_tmp; uint8_t *omni_array_tmp; + uint8_t *reflection_array_tmp; int max_ubo_lights; int max_forward_lights_per_object; + int max_ubo_reflections; + + int spot_light_count; int omni_light_count; int directional_light_count; + int reflection_probe_count; bool cull_front; @@ -176,6 +183,87 @@ public: virtual int get_directional_light_shadow_size(RID p_light_intance); virtual void set_directional_shadow_count(int p_count); + /* REFLECTION PROBE ATLAS API */ + + struct ReflectionAtlas : public RID_Data { + + int subdiv; + int size; + + struct Reflection { + RID owner; + uint64_t last_frame; + }; + + GLuint fbo[6]; + GLuint color; + + Vector reflections; + }; + + mutable RID_Owner reflection_atlas_owner; + + virtual RID reflection_atlas_create(); + virtual void reflection_atlas_set_size(RID p_ref_atlas,int p_size); + virtual void reflection_atlas_set_subdivision(RID p_ref_atlas,int p_subdiv); + + /* REFLECTION CUBEMAPS */ + + struct ReflectionCubeMap { + + GLuint fbo_id[6]; + GLuint cubemap; + GLuint depth; + int size; + }; + + Vector reflection_cubemaps; + + /* REFLECTION PROBE INSTANCE */ + + struct ReflectionProbeInstance : public RID_Data { + + RasterizerStorageGLES3::ReflectionProbe *probe_ptr; + RID probe; + RID self; + RID atlas; + + int reflection_atlas_index; + + int render_step; + + + + uint64_t last_pass; + int reflection_index; + + Transform transform; + }; + + struct ReflectionProbeDataUBO { + + float box_extents[4]; + float box_ofs[4]; + float params[4]; // intensity, 0, 0, boxproject + float ambient[4]; //color, probe contrib + float atlas_clamp[4]; + float local_matrix[16]; //up to here for spot and omni, rest is for directional + //notes: for ambientblend, use distance to edge to blend between already existing global environment + }; + + + mutable RID_Owner reflection_probe_instance_owner; + + virtual RID reflection_probe_instance_create(RID p_probe); + virtual void reflection_probe_instance_set_transform(RID p_instance,const Transform& p_transform); + virtual void reflection_probe_release_atlas_index(RID p_instance); + virtual bool reflection_probe_instance_needs_redraw(RID p_instance); + virtual bool reflection_probe_instance_has_reflection(RID p_instance); + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas); + virtual bool reflection_probe_instance_postprocess_step(RID p_instance); + + + /* ENVIRONMENT API */ @@ -183,8 +271,7 @@ public: VS::EnvironmentBG bg_mode; - RID skybox_color; - RID skybox_radiance; + RID skybox; float skybox_scale; Color bg_color; @@ -214,7 +301,7 @@ public: virtual RID environment_create(); virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size); + virtual void environment_set_skybox(RID p_env,RID p_skybox); virtual void environment_set_skybox_scale(RID p_env,float p_scale); virtual void environment_set_bg_color(RID p_env,const Color& p_color); virtual void environment_set_bg_energy(RID p_env,float p_energy); @@ -441,23 +528,25 @@ public: _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); _FORCE_INLINE_ void _setup_light(RenderList::Element *e); - void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add); + void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, GLuint p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows); _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow); - void _draw_skybox(RID p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); + void _draw_skybox(RasterizerStorageGLES3::SkyBox *p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform& p_cam_transform); - void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transform); + void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transformm, bool p_use_shadows); void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_shadow_atlas); + void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform& p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_reflection_atlas, Environment *p_env); + void _copy_screen(); void _copy_to_front_buffer(Environment *env); void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug void _fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow); - virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas); + virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass); virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count); virtual bool free(RID p_rid); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 6e278e563..8188fe3ad 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1015,10 +1015,6 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_r glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); -#ifdef GLEW_ENABLED - glDisable(GL_POINT_SPRITE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif glDisable(GL_BLEND); @@ -1086,6 +1082,8 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_r size = p_resolution; + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,false); + while(mm_level) { for(int i=0;i<6;i++) { @@ -1156,6 +1154,147 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_r } +RID RasterizerStorageGLES3::skybox_create() { + + SkyBox *skybox = memnew( SkyBox ); + skybox->radiance=0; + return skybox_owner.make_rid(skybox); +} + +void RasterizerStorageGLES3::skybox_set_texture(RID p_skybox, RID p_cube_map, int p_radiance_size){ + + SkyBox *skybox = skybox_owner.getornull(p_skybox); + ERR_FAIL_COND(!skybox); + + if (skybox->cubemap.is_valid()) { + skybox->cubemap=RID(); + glDeleteTextures(1,&skybox->radiance); + skybox->radiance=0; + } + + skybox->cubemap=p_cube_map; + if (!skybox->cubemap.is_valid()) + return; //cleared + + Texture *texture = texture_owner.getornull(skybox->cubemap); + if (!texture || !(texture->flags&VS::TEXTURE_FLAG_CUBEMAP)) { + skybox->cubemap=RID(); + ERR_FAIL_COND(!texture || !(texture->flags&VS::TEXTURE_FLAG_CUBEMAP)); + } + + glBindVertexArray(0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + if (config.srgb_decode_supported && texture->srgb && !texture->using_srgb) { + + glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + texture->using_srgb=true; +#ifdef TOOLS_ENABLED + if (!(texture->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { + texture->flags|=VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; + //notify that texture must be set to linear beforehand, so it works in other platforms when exported + } +#endif + } + + + glActiveTexture(GL_TEXTURE1); + glGenTextures(1, &skybox->radiance); + glBindTexture(GL_TEXTURE_2D, skybox->radiance); + + GLuint tmp_fb; + + glGenFramebuffers(1, &tmp_fb); + glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); + + + int size = p_radiance_size; + + int lod=0; + + + int mipmaps=6; + + int mm_level=mipmaps; + + bool use_float=true; + + GLenum internal_format = use_float?GL_RGBA16F:GL_RGB10_A2; + GLenum format = GL_RGBA; + GLenum type = use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV; + + while(mm_level) { + + glTexImage2D(GL_TEXTURE_2D, lod, internal_format, size, size*2, 0, format, type, NULL); + lod++; + mm_level--; + + if (size>1) + size>>=1; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod-1); + + lod=0; + mm_level=mipmaps; + + size = p_radiance_size; + + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,true); + shaders.cubemap_filter.bind(); + + while(mm_level) { + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, skybox->radiance, lod); +#ifdef DEBUG_ENABLED + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); +#endif + + for(int i=0;i<2;i++) { + glViewport(0,i*size,size,size); + glBindVertexArray(resources.quadie_array); + + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP,i>0); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,lod/float(mipmaps-1)); + + + glDrawArrays(GL_TRIANGLE_FAN,0,4); + glBindVertexArray(0); + } + + if (size>1) + size>>=1; + lod++; + mm_level--; + + } + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,false); + + + //restore ranges + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod-1); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + glDeleteFramebuffers(1, &tmp_fb); + +} + + /* SHADER API */ @@ -2144,7 +2283,7 @@ void RasterizerStorageGLES3::_update_material(Material* material) { Map::Element *V = material->params.find(E->key()); if (V) { - //user provided + //user provided _fill_std140_variant_ubo_value(E->get().type,V->get(),data,material->shader->mode==VS::SHADER_SPATIAL); } else if (E->get().default_value.size()){ //default value @@ -3405,46 +3544,197 @@ AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { RID RasterizerStorageGLES3::reflection_probe_create(){ - return RID(); + ReflectionProbe *reflection_probe = memnew( ReflectionProbe ); + + reflection_probe->intensity=1.0; + reflection_probe->interior_ambient=Color(); + reflection_probe->interior_ambient_energy=1.0; + reflection_probe->max_distance=0; + reflection_probe->extents=Vector3(1,1,1); + reflection_probe->origin_offset=Vector3(0,0,0); + reflection_probe->interior=false; + reflection_probe->box_projection=false; + reflection_probe->enable_shadows=false; + reflection_probe->cull_mask=(1<<20)-1; + reflection_probe->update_mode=VS::REFLECTION_PROBE_UPDATE_ONCE; + + return reflection_probe_owner.make_rid(reflection_probe); } -void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity){ +void RasterizerStorageGLES3::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->update_mode=p_mode; + reflection_probe->instance_change_notify(); } -void RasterizerStorageGLES3::reflection_probe_set_clip(RID p_probe, float p_near, float p_far){ +void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->intensity=p_intensity; + +} + +void RasterizerStorageGLES3::reflection_probe_set_interior_ambient(RID p_probe, const Color& p_ambient) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient=p_ambient; + +} + +void RasterizerStorageGLES3::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_energy=p_energy; } -void RasterizerStorageGLES3::reflection_probe_set_min_blend_distance(RID p_probe, float p_distance){ +void RasterizerStorageGLES3::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_probe_contrib=p_contrib; + +} + + +void RasterizerStorageGLES3::reflection_probe_set_max_distance(RID p_probe, float p_distance){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->max_distance=p_distance; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3& p_extents){ + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->extents=p_extents; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset){ + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->origin_offset=p_offset; + reflection_probe->instance_change_notify(); } -void RasterizerStorageGLES3::reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable){ +void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool p_enable){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior=p_enable; } -void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution){ +void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + reflection_probe->box_projection=p_enable; } -void RasterizerStorageGLES3::reflection_probe_set_hide_skybox(RID p_probe, bool p_hide){ +void RasterizerStorageGLES3::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->enable_shadows=p_enable; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers){ + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->cull_mask=p_layers; + reflection_probe->instance_change_notify(); } +AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,AABB()); + + AABB aabb; + aabb.pos=-reflection_probe->extents; + aabb.size=reflection_probe->extents*2.0; + + return aabb; + + +} +VS::ReflectionProbeUpdateMode RasterizerStorageGLES3::reflection_probe_get_update_mode(RID p_probe) const{ + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,VS::REFLECTION_PROBE_UPDATE_ALWAYS); + + return reflection_probe->update_mode; +} + +uint32_t RasterizerStorageGLES3::reflection_probe_get_cull_mask(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,0); + + return reflection_probe->cull_mask; + +} + +Vector3 RasterizerStorageGLES3::reflection_probe_get_extents(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,Vector3()); + + return reflection_probe->extents; + +} +Vector3 RasterizerStorageGLES3::reflection_probe_get_origin_offset(RID p_probe) const{ + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,Vector3()); + + return reflection_probe->origin_offset; + +} + +bool RasterizerStorageGLES3::reflection_probe_renders_shadows(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,false); + + return reflection_probe->enable_shadows; + +} + +float RasterizerStorageGLES3::reflection_probe_get_origin_max_distance(RID p_probe) const{ + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,0); + + return reflection_probe->max_distance; + +} /* ROOM API */ @@ -3495,6 +3785,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: inst = mesh_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_LIGHT: { inst = light_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -3517,6 +3811,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_LIGHT: { inst = light_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -4005,6 +4303,9 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { if (light_owner.owns(p_rid)) { return VS::INSTANCE_LIGHT; } + if (reflection_probe_owner.owns(p_rid)) { + return VS::INSTANCE_REFLECTION_PROBE; + } return VS::INSTANCE_NONE; } @@ -4028,6 +4329,12 @@ bool RasterizerStorageGLES3::free(RID p_rid){ info.texture_mem-=texture->total_data_size; texture_owner.free(p_rid); memdelete(texture); + } else if (skybox_owner.owns(p_rid)) { + // delete the skybox + SkyBox *skybox = skybox_owner.get(p_rid); + skybox_set_texture(p_rid,RID(),256); + skybox_owner.free(p_rid); + memdelete(skybox); } else if (shader_owner.owns(p_rid)) { @@ -4259,6 +4566,8 @@ void RasterizerStorageGLES3::initialize() { shaders.cubemap_filter.init(); glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); + + frame.count=0; } void RasterizerStorageGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 0e3d47b61..5f07efeb0 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -226,6 +226,19 @@ public: virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const; + /* SKYBOX API */ + + struct SkyBox : public RID_Data { + + RID cubemap; + GLuint radiance; + int radiance_size; + }; + + mutable RID_Owner skybox_owner; + + virtual RID skybox_create(); + virtual void skybox_set_texture(RID p_skybox,RID p_cube_map,int p_radiance_size); /* SHADER API */ @@ -679,18 +692,51 @@ public: /* PROBE API */ + struct ReflectionProbe : Instantiable { + + VS::ReflectionProbeUpdateMode update_mode; + float intensity; + Color interior_ambient; + float interior_ambient_energy; + float interior_ambient_probe_contrib; + float max_distance; + Vector3 extents; + Vector3 origin_offset; + bool interior; + bool box_projection; + bool enable_shadows; + uint32_t cull_mask; + + }; + + mutable RID_Owner reflection_probe_owner; + virtual RID reflection_probe_create(); + virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode); virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity); - virtual void reflection_probe_set_clip(RID p_probe, float p_near, float p_far); - virtual void reflection_probe_set_min_blend_distance(RID p_probe, float p_distance); + virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color& p_ambient); + virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy); + virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib); + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance); virtual void reflection_probe_set_extents(RID p_probe, const Vector3& p_extents); virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset); - virtual void reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable); - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); - virtual void reflection_probe_set_hide_skybox(RID p_probe, bool p_hide); + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable); + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + virtual AABB reflection_probe_get_aabb(RID p_probe) const; + virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; + virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const; + + virtual Vector3 reflection_probe_get_extents(RID p_probe) const; + virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const; + virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; + virtual bool reflection_probe_renders_shadows(RID p_probe) const; + + + /* ROOM API */ @@ -813,6 +859,7 @@ public: Color clear_request_color; int canvas_draw_commands; float time[4]; + uint64_t count; } frame; void initialize(); diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index 998a59833..768d20ad2 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -151,14 +151,47 @@ vec2 Hammersley(uint i, uint N) { return vec2(float(i)/float(N), radicalInverse_VdC(i)); } -#define SAMPLE_COUNT 1024u + + +#ifdef LOW_QUALITY + +#define SAMPLE_COUNT 64u + +#else + +#define SAMPLE_COUNT 512u + +#endif + +uniform bool z_flip; void main() { +#ifdef USE_DUAL_PARABOLOID + + vec3 N = vec3( uv_interp * 2.0 - 1.0, 0.0 ); + N.z = 0.5 - 0.5*((N.x * N.x) + (N.y * N.y)); + N = normalize(N); + + if (!z_flip) { + N.y=-N.y; //y is flipped to improve blending between both sides + } else { + N.z=-N.z; + } + + +#else vec2 uv = (uv_interp * 2.0) - 1.0; vec3 N = texelCoordToVec(uv, face_id); - +#endif //vec4 color = color_interp; + +#ifdef USE_DIRECT_WRITE + + frag_color=vec4(texture(N,source_cube).rgb,1.0); + +#else + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) { @@ -178,5 +211,8 @@ void main() { sum /= sum.a; frag_color = vec4(sum.rgb, 1.0); + +#endif + } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index ceb5a7211..a923c130d 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -64,6 +64,8 @@ layout(std140) uniform SceneData { //ubo:0 vec2 shadow_atlas_pixel_size; vec2 directional_shadow_pixel_size; + float reflection_multiplier; + }; uniform highp mat4 world_transform; @@ -288,11 +290,11 @@ in vec3 normal_interp; //used on forward mainly uniform bool no_ambient_light; +uniform sampler2D brdf_texture; //texunit:-1 -#ifdef USE_RADIANCE_CUBEMAP +#ifdef USE_RADIANCE_MAP -uniform sampler2D brdf_texture; //texunit:-1 -uniform samplerCube radiance_cube; //texunit:-2 +uniform sampler2D radiance_map; //texunit:-2 layout(std140) uniform Radiance { //ubo:2 @@ -343,6 +345,8 @@ layout(std140) uniform SceneData { vec2 shadow_atlas_pixel_size; vec2 directional_shadow_pixel_size; + float reflection_multiplier; + }; //directional light data @@ -398,6 +402,24 @@ layout(std140) uniform SpotLightData { //ubo:5 uniform highp sampler2DShadow shadow_atlas; //texunit:-3 +struct ReflectionData { + + mediump vec4 box_extents; + mediump vec4 box_offset; + mediump vec4 params; // intensity, 0, interior , boxproject + mediump vec4 ambient; //ambient color, energy + mediump vec4 atlas_clamp; + highp mat4 local_matrix; //up to here for spot and omni, rest is for directional + //notes: for ambientblend, use distance to edge to blend between already existing global environment +}; + +layout(std140) uniform ReflectionProbeData { //ubo:6 + + ReflectionData reflections[MAX_REFLECTION_DATA_STRUCTS]; +}; +uniform mediump sampler2D reflection_atlas; //texunit:-5 + + #ifdef USE_FORWARD_LIGHTING uniform int omni_light_indices[MAX_FORWARD_LIGHTS]; @@ -406,6 +428,9 @@ uniform int omni_light_count; uniform int spot_light_indices[MAX_FORWARD_LIGHTS]; uniform int spot_light_count; +uniform int reflection_indices[MAX_FORWARD_LIGHTS]; +uniform int reflection_count; + #endif @@ -578,6 +603,120 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 al } +void reflection_process(int idx, vec3 vertex, vec3 normal,float roughness,vec3 ambient,vec3 skybox,vec2 brdf, inout highp vec4 reflection_accum,inout highp vec4 ambient_accum) { + + vec3 ref_vec = normalize(reflect(vertex,normal)); + vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex,1.0)).xyz; + vec3 box_extents = reflections[idx].box_extents.xyz; + + if (any(greaterThan(abs(local_pos),box_extents))) { //out of the reflection box + return; + } + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x,max(inner_pos.y,inner_pos.z)); + //make blend more rounded + blend=mix(length(inner_pos),blend,blend); + blend*=blend; + blend=1.001-blend; + + if (reflections[idx].params.x>0.0){// compute reflection + + vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec,0.0)).xyz; + + if (reflections[idx].params.w > 0.5) { //box project + + vec3 nrdir = normalize(local_ref_vec); + vec3 rbmax = (box_extents - local_pos)/nrdir; + vec3 rbmin = (-box_extents - local_pos)/nrdir; + + + vec3 rbminmax = mix(rbmin,rbmax,greaterThan(nrdir,vec3(0.0,0.0,0.0))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + local_ref_vec = posonbox - reflections[idx].box_offset.xyz; + } + + + + vec3 splane=normalize(local_ref_vec); + vec4 clamp_rect=reflections[idx].atlas_clamp; + + splane.z*=-1.0; + if (splane.z>=0.0) { + splane.z+=1.0; + clamp_rect.y+=clamp_rect.w; + } else { + splane.z=1.0 - splane.z; + splane.y=-splane.y; + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + + splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy; + splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw); + + highp vec4 reflection; + reflection.rgb = textureLod(reflection_atlas,splane.xy,roughness*5.0).rgb * ( brdf.x + brdf.y); + if (reflections[idx].params.z < 0.5) { + reflection.rgb = mix(skybox,reflection.rgb,blend); + } + reflection.rgb*=reflections[idx].params.x; + reflection.a = blend; + reflection.rgb*=reflection.a; + + reflection_accum+=reflection; + } + + if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox + + + vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal,0.0)).xyz; + + vec3 splane=normalize(local_amb_vec); + vec4 clamp_rect=reflections[idx].atlas_clamp; + + splane.z*=-1.0; + if (splane.z>=0.0) { + splane.z+=1.0; + clamp_rect.y+=clamp_rect.w; + } else { + splane.z=1.0 - splane.z; + splane.y=-splane.y; + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + + splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy; + splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw); + + highp vec4 ambient_out; + ambient_out.a=blend; + ambient_out.rgb = textureLod(reflection_atlas,splane.xy,5.0).rgb; + ambient_out.rgb=mix(reflections[idx].ambient.rgb,ambient_out.rgb,reflections[idx].ambient.a); + if (reflections[idx].params.z < 0.5) { + ambient_out.rgb = mix(ambient,ambient_out.rgb,blend); + } + + ambient_out.rgb *= ambient_out.a; + ambient_accum+=ambient_out; + } else { + + highp vec4 ambient_out; + ambient_out.a=blend; + ambient_out.rgb=reflections[idx].ambient.rgb; + if (reflections[idx].params.z < 0.5) { + ambient_out.rgb = mix(ambient,ambient_out.rgb,blend); + } + ambient_out.rgb *= ambient_out.a; + ambient_accum+=ambient_out; + + } +} + void main() { #ifdef RENDER_SHADOW_DUAL_PARABOLOID @@ -666,31 +805,56 @@ FRAGMENT_SHADER_CODE vec3 eye_vec = -normalize( vertex_interp ); -#ifdef USE_RADIANCE_CUBEMAP +#ifndef RENDER_SHADOW + float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); + vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; +#endif + +#ifdef USE_RADIANCE_MAP if (no_ambient_light) { ambient_light=vec3(0.0,0.0,0.0); } else { { - float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); - vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; + float lod = roughness * 5.0; - vec3 r = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); - r=normalize((radiance_inverse_xform * vec4(r,0.0)).xyz); - vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); - specular_light=mix(albedo,radiance,specular); + { //read radiance from dual paraboloid + + vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); + ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz); + + vec3 norm = normalize(ref_vec); + float y_ofs=0.0; + if (norm.z>=0.0) { + + norm.z+=1.0; + y_ofs+=0.5; + } else { + norm.z=1.0 - norm.z; + norm.y=-norm.y; + } + + norm.xy/=norm.z; + norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25+y_ofs); + vec3 radiance = textureLod(radiance_map, norm.xy, lod).xyz * ( brdf.x + brdf.y); + specular_light=mix(albedo,radiance,specular); + + } + //no longer a cubemap + //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); } { - vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); + /*vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz; - ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution); + ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);*/ + ambient_light=vec3(0.0,0.0,0.0); } } @@ -840,6 +1004,21 @@ FRAGMENT_SHADER_CODE #ifdef USE_FORWARD_LIGHTING + highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0); + highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0); + + for(int i=0;i0.0) { + specular_light=reflection_accum.rgb/reflection_accum.a; + specular_light*=specular; + } + if (ambient_accum.a>0.0) { + ambient_light=ambient_accum.rgb/ambient_accum.a; + } + for(int i=0;ireflection_probe_set_intensity(probe,p_intensity); +} + +float ReflectionProbe::get_intensity() const{ + + return intensity; +} + + +void ReflectionProbe::set_interior_ambient(Color p_ambient) { + + interior_ambient=p_ambient; + VS::get_singleton()->reflection_probe_set_interior_ambient(probe,p_ambient); +} + +void ReflectionProbe::set_interior_ambient_energy(float p_energy) { + interior_ambient_energy=p_energy; + VS::get_singleton()->reflection_probe_set_interior_ambient_energy(probe,p_energy); +} + +float ReflectionProbe::get_interior_ambient_energy() const{ + return interior_ambient_energy; +} + + +Color ReflectionProbe::get_interior_ambient() const{ + + return interior_ambient; +} + +void ReflectionProbe::set_interior_ambient_probe_contribution(float p_contribution) { + + interior_ambient_probe_contribution=p_contribution; + VS::get_singleton()->reflection_probe_set_interior_ambient_probe_contribution(probe,p_contribution); +} + +float ReflectionProbe::get_interior_ambient_probe_contribution() const{ + + return interior_ambient_probe_contribution; +} + + +void ReflectionProbe::set_max_distance(float p_distance){ + + max_distance=p_distance; + VS::get_singleton()->reflection_probe_set_max_distance(probe,p_distance); +} +float ReflectionProbe::get_max_distance() const{ + + return max_distance; +} + + +void ReflectionProbe::set_extents(const Vector3& p_extents){ + + extents=p_extents; + + for(int i=0;i<3;i++) { + if (extents[i]<0.01) { + extents[i]=0.01; + } + + if (extents[i]-0.01reflection_probe_set_extents(probe,extents); + VS::get_singleton()->reflection_probe_set_origin_offset(probe,origin_offset); + _change_notify("extents"); + update_gizmo(); + +} +Vector3 ReflectionProbe::get_extents() const{ + + return extents; +} + +void ReflectionProbe::set_origin_offset(const Vector3& p_extents){ + + origin_offset=p_extents; + + for(int i=0;i<3;i++) { + + if (extents[i]-0.01reflection_probe_set_extents(probe,extents); + VS::get_singleton()->reflection_probe_set_origin_offset(probe,origin_offset); + + _change_notify("origin_offset"); + update_gizmo(); +} +Vector3 ReflectionProbe::get_origin_offset() const{ + + return origin_offset; +} + +void ReflectionProbe::set_enable_box_projection(bool p_enable){ + + box_projection=p_enable; + VS::get_singleton()->reflection_probe_set_enable_box_projection(probe,p_enable); + +} +bool ReflectionProbe::is_box_projection_enabled() const{ + + return box_projection; +} + + +void ReflectionProbe::set_as_interior(bool p_enable) { + + interior=p_enable; + VS::get_singleton()->reflection_probe_set_as_interior(probe,interior); + _change_notify(); + +} + +bool ReflectionProbe::is_set_as_interior() const { + + return interior; +} + + + +void ReflectionProbe::set_enable_shadows(bool p_enable) { + + enable_shadows=p_enable; + VS::get_singleton()->reflection_probe_set_enable_shadows(probe,p_enable); +} +bool ReflectionProbe::are_shadows_enabled() const { + + return enable_shadows; +} + +void ReflectionProbe::set_cull_mask(uint32_t p_layers) { + + cull_mask=p_layers; + VS::get_singleton()->reflection_probe_set_enable_shadows(probe,p_layers); +} +uint32_t ReflectionProbe::get_cull_mask() const { + + return cull_mask; +} + +void ReflectionProbe::set_update_mode(UpdateMode p_mode) { + update_mode=p_mode; + VS::get_singleton()->reflection_probe_set_update_mode(probe,VS::ReflectionProbeUpdateMode(p_mode)); +} + +ReflectionProbe::UpdateMode ReflectionProbe::get_update_mode() const { + return update_mode; +} + + +AABB ReflectionProbe::get_aabb() const { + + AABB aabb; + aabb.pos=-origin_offset; + aabb.size=origin_offset+extents; + return aabb; +} +DVector ReflectionProbe::get_faces(uint32_t p_usage_flags) const { + + return DVector(); +} + +void ReflectionProbe::_validate_property(PropertyInfo& property) const { + + if (property.name=="interior/ambient_color" || property.name=="interior/ambient_energy" || property.name=="interior/ambient_contrib") { + if (!interior) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } +} + +void ReflectionProbe::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_intensity","intensity"),&ReflectionProbe::set_intensity); + ObjectTypeDB::bind_method(_MD("get_intensity"),&ReflectionProbe::get_intensity); + + ObjectTypeDB::bind_method(_MD("set_interior_ambient","ambient"),&ReflectionProbe::set_interior_ambient); + ObjectTypeDB::bind_method(_MD("get_interior_ambient"),&ReflectionProbe::get_interior_ambient); + + ObjectTypeDB::bind_method(_MD("set_interior_ambient_energy","ambient_energy"),&ReflectionProbe::set_interior_ambient_energy); + ObjectTypeDB::bind_method(_MD("get_interior_ambient_energy"),&ReflectionProbe::get_interior_ambient_energy); + + ObjectTypeDB::bind_method(_MD("set_interior_ambient_probe_contribution","ambient_probe_contribution"),&ReflectionProbe::set_interior_ambient_probe_contribution); + ObjectTypeDB::bind_method(_MD("get_interior_ambient_probe_contribution"),&ReflectionProbe::get_interior_ambient_probe_contribution); + + ObjectTypeDB::bind_method(_MD("set_max_distance","max_distance"),&ReflectionProbe::set_max_distance); + ObjectTypeDB::bind_method(_MD("get_max_distance"),&ReflectionProbe::get_max_distance); + + ObjectTypeDB::bind_method(_MD("set_extents","extents"),&ReflectionProbe::set_extents); + ObjectTypeDB::bind_method(_MD("get_extents"),&ReflectionProbe::get_extents); + + ObjectTypeDB::bind_method(_MD("set_origin_offset","origin_offset"),&ReflectionProbe::set_origin_offset); + ObjectTypeDB::bind_method(_MD("get_origin_offset"),&ReflectionProbe::get_origin_offset); + + ObjectTypeDB::bind_method(_MD("set_as_interior","enable"),&ReflectionProbe::set_as_interior); + ObjectTypeDB::bind_method(_MD("is_set_as_interior"),&ReflectionProbe::is_set_as_interior); + + ObjectTypeDB::bind_method(_MD("set_enable_box_projection","enable"),&ReflectionProbe::set_enable_box_projection); + ObjectTypeDB::bind_method(_MD("is_box_projection_enabled"),&ReflectionProbe::is_box_projection_enabled); + + + ObjectTypeDB::bind_method(_MD("set_enable_shadows","enable"),&ReflectionProbe::set_enable_shadows); + ObjectTypeDB::bind_method(_MD("are_shadows_enabled"),&ReflectionProbe::are_shadows_enabled); + + ObjectTypeDB::bind_method(_MD("set_cull_mask","layers"),&ReflectionProbe::set_cull_mask); + ObjectTypeDB::bind_method(_MD("get_cull_mask"),&ReflectionProbe::get_cull_mask); + + ObjectTypeDB::bind_method(_MD("set_update_mode","mode"),&ReflectionProbe::set_update_mode); + ObjectTypeDB::bind_method(_MD("get_update_mode"),&ReflectionProbe::get_update_mode); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"update_mode",PROPERTY_HINT_ENUM,"Once,Always"),_SCS("set_update_mode"),_SCS("get_update_mode")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"intensity",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_intensity"),_SCS("get_intensity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"max_distance",PROPERTY_HINT_RANGE,"0,16384,0.1"),_SCS("set_max_distance"),_SCS("get_max_distance")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"extents"),_SCS("set_extents"),_SCS("get_extents")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"origin_offset"),_SCS("set_origin_offset"),_SCS("get_origin_offset")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"box_projection"),_SCS("set_enable_box_projection"),_SCS("is_box_projection_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enable_shadows"),_SCS("set_enable_shadows"),_SCS("are_shadows_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_cull_mask"),_SCS("get_cull_mask")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"interior/enable"),_SCS("set_as_interior"),_SCS("is_set_as_interior")); + ADD_PROPERTY( PropertyInfo(Variant::COLOR,"interior/ambient_color",PROPERTY_HINT_COLOR_NO_ALPHA),_SCS("set_interior_ambient"),_SCS("get_interior_ambient")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"interior/ambient_energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_interior_ambient_energy"),_SCS("get_interior_ambient_energy")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"interior/ambient_contrib",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_interior_ambient_probe_contribution"),_SCS("get_interior_ambient_probe_contribution")); + + + BIND_CONSTANT( UPDATE_ONCE ); + BIND_CONSTANT( UPDATE_ALWAYS ); + +} + +ReflectionProbe::ReflectionProbe() { + + intensity=1.0; + interior_ambient=Color(0,0,0); + interior_ambient_probe_contribution=0; + interior_ambient_energy=1.0; + max_distance=0; + extents=Vector3(1,1,1); + origin_offset=Vector3(0,0,0); + box_projection=false; + interior=false; + enable_shadows=false; + cull_mask=(1<<20)-1; + update_mode=UPDATE_ONCE; + + probe=VisualServer::get_singleton()->reflection_probe_create(); + VS::get_singleton()->instance_set_base(get_instance(),probe); +} + +ReflectionProbe::~ReflectionProbe() { + + VS::get_singleton()->free(probe); +} diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h new file mode 100644 index 000000000..5ea41a91c --- /dev/null +++ b/scene/3d/reflection_probe.h @@ -0,0 +1,92 @@ +#ifndef REFLECTIONPROBE_H +#define REFLECTIONPROBE_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/texture.h" +#include "scene/resources/sky_box.h" +#include "servers/visual_server.h" + +class ReflectionProbe : public VisualInstance { + OBJ_TYPE(ReflectionProbe,VisualInstance); + +public: + + enum UpdateMode { + UPDATE_ONCE, + UPDATE_ALWAYS, + }; + + +private: + + RID probe; + float intensity; + float max_distance; + Vector3 extents; + Vector3 origin_offset; + bool box_projection; + bool enable_shadows; + bool interior; + Color interior_ambient; + float interior_ambient_energy; + float interior_ambient_probe_contribution; + + uint32_t cull_mask; + UpdateMode update_mode; + +protected: + + static void _bind_methods(); + void _validate_property(PropertyInfo& property) const; + +public: + + void set_intensity(float p_intensity); + float get_intensity() const; + + void set_interior_ambient(Color p_ambient); + Color get_interior_ambient() const; + + void set_interior_ambient_energy(float p_energy); + float get_interior_ambient_energy() const; + + void set_interior_ambient_probe_contribution(float p_contribution); + float get_interior_ambient_probe_contribution() const; + + void set_max_distance(float p_distance); + float get_max_distance() const; + + void set_extents(const Vector3& p_extents); + Vector3 get_extents() const; + + void set_origin_offset(const Vector3& p_extents); + Vector3 get_origin_offset() const; + + void set_as_interior(bool p_enable); + bool is_set_as_interior() const; + + void set_enable_box_projection(bool p_enable); + bool is_box_projection_enabled() const; + + void set_enable_shadows(bool p_enable); + bool are_shadows_enabled() const; + + void set_cull_mask(uint32_t p_layers); + uint32_t get_cull_mask() const; + + void set_update_mode(UpdateMode p_mode); + UpdateMode get_update_mode() const; + + virtual AABB get_aabb() const; + virtual DVector get_faces(uint32_t p_usage_flags) const; + + + + ReflectionProbe(); + ~ReflectionProbe(); +}; + + +VARIANT_ENUM_CAST( ReflectionProbe::UpdateMode ); + +#endif // REFLECTIONPROBE_H diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index ef619244d..abc4bf3fe 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -2296,6 +2296,7 @@ SceneTree::SceneTree() { collision_debug_contacts=GLOBAL_DEF("debug/collision_max_contacts_displayed",10000); + tree_version=1; fixed_process_time=1; idle_process_time=1; @@ -2319,6 +2320,12 @@ SceneTree::SceneTree() { root->set_as_audio_listener_2d(true); current_scene=NULL; + int ref_atlas_size = GLOBAL_DEF("rendering/reflections/atlas_size",2048); + int ref_atlas_subdiv = GLOBAL_DEF("rendering/reflections/atlas_subdiv",8); + + VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(),ref_atlas_size,ref_atlas_subdiv); + + stretch_mode=STRETCH_MODE_DISABLED; stretch_aspect=STRETCH_ASPECT_IGNORE; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index e2f5b5679..d2b9def5c 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -166,6 +166,7 @@ #include "scene/resources/sample.h" #include "scene/audio/sample_player.h" #include "scene/resources/texture.h" +#include "scene/resources/sky_box.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" #include "scene/resources/room.h" @@ -203,6 +204,7 @@ #include "scene/3d/mesh_instance.h" #include "scene/3d/quad.h" #include "scene/3d/light.h" +#include "scene/3d/reflection_probe.h" #include "scene/3d/particles.h" #include "scene/3d/portal.h" #include "scene/resources/environment.h" @@ -421,6 +423,7 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); //ObjectTypeDB::register_type(); @@ -578,6 +581,8 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_virtual_type(); + ObjectTypeDB::register_virtual_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 47f4370cc..d35200d98 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -44,16 +44,15 @@ void Environment::set_background(BGMode p_bg) { _change_notify(); } -void Environment::set_skybox(const Ref& p_skybox){ +void Environment::set_skybox(const Ref &p_skybox){ bg_skybox=p_skybox; RID sb_rid; if (bg_skybox.is_valid()) sb_rid=bg_skybox->get_rid(); - print_line("skybox valid: "+itos(sb_rid.is_valid())); - VS::get_singleton()->environment_set_skybox(environment,sb_rid,Globals::get_singleton()->get("rendering/skybox/radiance_cube_resolution")); + VS::get_singleton()->environment_set_skybox(environment,sb_rid); } void Environment::set_skybox_scale(float p_scale) { @@ -97,7 +96,7 @@ Environment::BGMode Environment::get_background() const{ return bg_mode; } -Ref Environment::get_skybox() const{ +Ref Environment::get_skybox() const{ return bg_skybox; } @@ -326,7 +325,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT,"background/mode",PROPERTY_HINT_ENUM,"Clear Color,Custom Color,Skybox,Canvas,Keep"),_SCS("set_background"),_SCS("get_background") ); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"background/skybox",PROPERTY_HINT_RESOURCE_TYPE,"CubeMap"),_SCS("set_skybox"),_SCS("get_skybox") ); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"background/skybox",PROPERTY_HINT_RESOURCE_TYPE,"SkyBox"),_SCS("set_skybox"),_SCS("get_skybox") ); ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/skybox_scale",PROPERTY_HINT_RANGE,"0,32,0.01"),_SCS("set_skybox_scale"),_SCS("get_skybox_scale") ); ADD_PROPERTY(PropertyInfo(Variant::COLOR,"background/color"),_SCS("set_bg_color"),_SCS("get_bg_color") ); ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_bg_energy"),_SCS("get_bg_energy") ); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 394b67dad..ca55b51b2 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -32,6 +32,7 @@ #include "resource.h" #include "servers/visual_server.h" #include "scene/resources/texture.h" +#include "scene/resources/sky_box.h" class Environment : public Resource { @@ -69,7 +70,7 @@ private: RID environment; BGMode bg_mode; - Ref bg_skybox; + Ref bg_skybox; float bg_skybox_scale; Color bg_color; float bg_energy; @@ -102,7 +103,7 @@ public: void set_background(BGMode p_bg); - void set_skybox(const Ref& p_skybox); + void set_skybox(const Ref& p_skybox); void set_skybox_scale(float p_scale); void set_bg_color(const Color& p_color); void set_bg_energy(float p_energy); @@ -112,7 +113,7 @@ public: void set_ambient_light_skybox_contribution(float p_energy); BGMode get_background() const; - Ref get_skybox() const; + Ref get_skybox() const; float get_skybox_scale() const; Color get_bg_color() const; float get_bg_energy() const; diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp new file mode 100644 index 000000000..e8017cb08 --- /dev/null +++ b/scene/resources/sky_box.cpp @@ -0,0 +1,158 @@ +#include "sky_box.h" +#include "io/image_loader.h" + + +void SkyBox::set_radiance_size(RadianceSize p_size) { + ERR_FAIL_INDEX(p_size,RADIANCE_SIZE_MAX); + + radiance_size=p_size; + _radiance_changed(); +} + +SkyBox::RadianceSize SkyBox::get_radiance_size() const { + + return radiance_size; +} + +void SkyBox::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_radiance_size","size"),&SkyBox::set_radiance_size); + ObjectTypeDB::bind_method(_MD("get_radiance_size"),&SkyBox::get_radiance_size); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"radiance_size",PROPERTY_HINT_ENUM,"256,512,1024,2048"),_SCS("set_radiance_size"),_SCS("get_radiance_size")); + + + BIND_CONSTANT( RADIANCE_SIZE_256 ); + BIND_CONSTANT( RADIANCE_SIZE_512 ); + BIND_CONSTANT( RADIANCE_SIZE_1024 ); + BIND_CONSTANT( RADIANCE_SIZE_2048 ); + BIND_CONSTANT( RADIANCE_SIZE_MAX ); +} + +SkyBox::SkyBox() +{ + radiance_size=RADIANCE_SIZE_512; +} + +///////////////////////////////////////// + + + +void ImageSkyBox::_radiance_changed() { + + if (cube_map_valid) { + static const int size[RADIANCE_SIZE_MAX]={ + 256,512,1024,2048 + }; + VS::get_singleton()->skybox_set_texture(sky_box,cube_map,size[get_radiance_size()]); + } +} + +void ImageSkyBox::set_image_path(ImagePath p_image,const String &p_path) { + + ERR_FAIL_INDEX(p_image,IMAGE_PATH_MAX); + image_path[p_image]=p_path; + + bool all_ok=true; + for(int i=0;itexture_allocate(cube_map,w,h,format,VS::TEXTURE_FLAG_FILTER|VS::TEXTURE_FLAG_CUBEMAP|VS::TEXTURE_FLAG_MIPMAPS); + for(int i=0;itexture_set_data(cube_map,images[i],VS::CubeMapSide(i)); + } + + cube_map_valid=true; + _radiance_changed(); + } + + +} + +String ImageSkyBox::get_image_path(ImagePath p_image) const { + + ERR_FAIL_INDEX_V(p_image,IMAGE_PATH_MAX,String()); + return image_path[p_image]; + +} + +RID ImageSkyBox::get_rid() const { + + return sky_box; +} + +void ImageSkyBox::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_image_path","image","path"),&ImageSkyBox::set_image_path); + ObjectTypeDB::bind_method(_MD("get_image_path","image"),&ImageSkyBox::get_image_path); + + List extensions; + ImageLoader::get_recognized_extensions(&extensions); + String hints; + for(List::Element *E=extensions.front();E;E=E->next()) { + if (hints!=String()) { + hints+=","; + } + hints+="*."+E->get(); + } + + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/negative_x",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_NEGATIVE_X); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/positive_x",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_POSITIVE_X); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/negative_y",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_NEGATIVE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/positive_y",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_POSITIVE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/negative_z",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_NEGATIVE_Z); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/positive_z",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_POSITIVE_Z); + + BIND_CONSTANT( IMAGE_PATH_NEGATIVE_X ); + BIND_CONSTANT( IMAGE_PATH_POSITIVE_X ); + BIND_CONSTANT( IMAGE_PATH_NEGATIVE_Y ); + BIND_CONSTANT( IMAGE_PATH_POSITIVE_Y ); + BIND_CONSTANT( IMAGE_PATH_NEGATIVE_Z ); + BIND_CONSTANT( IMAGE_PATH_POSITIVE_Z ); + BIND_CONSTANT( IMAGE_PATH_MAX ); + +} + +ImageSkyBox::ImageSkyBox() { + + cube_map=VS::get_singleton()->texture_create(); + sky_box=VS::get_singleton()->skybox_create(); + cube_map_valid=false; +} + +ImageSkyBox::~ImageSkyBox() { + + VS::get_singleton()->free(cube_map); + VS::get_singleton()->free(sky_box); +} + diff --git a/scene/resources/sky_box.h b/scene/resources/sky_box.h new file mode 100644 index 000000000..3a3dd1b2d --- /dev/null +++ b/scene/resources/sky_box.h @@ -0,0 +1,71 @@ +#ifndef SKYBOX_H +#define SKYBOX_H + +#include "scene/resources/texture.h" + +class SkyBox : public Resource { + OBJ_TYPE(SkyBox,Resource); + +public: + + enum RadianceSize { + RADIANCE_SIZE_256, + RADIANCE_SIZE_512, + RADIANCE_SIZE_1024, + RADIANCE_SIZE_2048, + RADIANCE_SIZE_MAX + }; +private: + + RadianceSize radiance_size; +protected: + static void _bind_methods(); + virtual void _radiance_changed()=0; +public: + + void set_radiance_size(RadianceSize p_size); + RadianceSize get_radiance_size() const; + SkyBox(); +}; + +VARIANT_ENUM_CAST(SkyBox::RadianceSize) + + +class ImageSkyBox : public SkyBox { + OBJ_TYPE(ImageSkyBox,SkyBox); + +public: + + enum ImagePath { + IMAGE_PATH_NEGATIVE_X, + IMAGE_PATH_POSITIVE_X, + IMAGE_PATH_NEGATIVE_Y, + IMAGE_PATH_POSITIVE_Y, + IMAGE_PATH_NEGATIVE_Z, + IMAGE_PATH_POSITIVE_Z, + IMAGE_PATH_MAX + }; +private: + RID cube_map; + RID sky_box; + bool cube_map_valid; + + String image_path[IMAGE_PATH_MAX]; +protected: + static void _bind_methods(); + virtual void _radiance_changed(); +public: + + void set_image_path(ImagePath p_image, const String &p_path); + String get_image_path(ImagePath p_image) const; + + virtual RID get_rid() const; + + ImageSkyBox(); + ~ImageSkyBox(); +}; + +VARIANT_ENUM_CAST(ImageSkyBox::ImagePath) + + +#endif // SKYBOX_H diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 06509c6fd..0f70b036a 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -54,7 +54,7 @@ public: virtual RID environment_create()=0; virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox)=0; virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; @@ -84,6 +84,7 @@ public: Vector materials; Vector light_instances; + Vector reflection_probe_instances; Vector morph_values; @@ -125,7 +126,19 @@ public: virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass)=0; virtual void light_instance_mark_visible(RID p_light_instance)=0; - virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas)=0; + virtual RID reflection_atlas_create()=0; + virtual void reflection_atlas_set_size(RID p_ref_atlas,int p_size)=0; + virtual void reflection_atlas_set_subdivision(RID p_ref_atlas,int p_subdiv)=0; + + virtual RID reflection_probe_instance_create(RID p_probe)=0; + virtual void reflection_probe_instance_set_transform(RID p_instance,const Transform& p_transform)=0; + virtual void reflection_probe_release_atlas_index(RID p_instance)=0; + virtual bool reflection_probe_instance_needs_redraw(RID p_instance)=0; + virtual bool reflection_probe_instance_has_reflection(RID p_instance)=0; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas)=0; + virtual bool reflection_probe_instance_postprocess_step(RID p_instance)=0; + + virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass)=0; virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count)=0; virtual void set_scene_pass(uint64_t p_pass)=0; @@ -165,6 +178,11 @@ public: virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const=0; + /* SKYBOX API */ + + virtual RID skybox_create()=0; + virtual void skybox_set_texture(RID p_skybox,RID p_cube_map,int p_radiance_size)=0; + /* SHADER API */ @@ -324,16 +342,27 @@ public: virtual RID reflection_probe_create()=0; + virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode)=0; virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity)=0; - virtual void reflection_probe_set_clip(RID p_probe, float p_near, float p_far)=0; - virtual void reflection_probe_set_min_blend_distance(RID p_probe, float p_distance)=0; + virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color& p_ambient)=0; + virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy)=0; + virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib)=0; + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance)=0; virtual void reflection_probe_set_extents(RID p_probe, const Vector3& p_extents)=0; virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset)=0; - virtual void reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable)=0; - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution)=0; - virtual void reflection_probe_set_hide_skybox(RID p_probe, bool p_hide)=0; + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable)=0; virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers)=0; + virtual AABB reflection_probe_get_aabb(RID p_probe) const=0; + virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const=0; + virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const=0; + virtual Vector3 reflection_probe_get_extents(RID p_probe) const=0; + virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const=0; + virtual float reflection_probe_get_origin_max_distance(RID p_probe) const=0; + virtual bool reflection_probe_renders_shadows(RID p_probe) const=0; + /* ROOM API */ diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index bbad460f4..6ba63a769 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -94,6 +94,7 @@ void VisualServerRaster::draw(){ VSG::rasterizer->begin_frame(); VSG::viewport->draw_viewports(); + VSG::scene->render_probes(); //_draw_cursors_and_margins(); VSG::rasterizer->end_frame(); //draw_extra_frame=VS:rasterizer->needs_to_draw_next_frame(); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 4d8a46122..4e9110445 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -629,7 +629,10 @@ public: BIND1(texture_set_shrink_all_x2_on_set_data,bool) BIND1(texture_debug_usage,List*) + /* SKYBOX API */ + BIND0R(RID,skybox_create) + BIND3(skybox_set_texture,RID,RID,int) /* SHADER API */ @@ -772,17 +775,19 @@ public: BIND0R(RID,reflection_probe_create) + BIND2(reflection_probe_set_update_mode,RID, ReflectionProbeUpdateMode ) BIND2(reflection_probe_set_intensity,RID, float ) - BIND3(reflection_probe_set_clip,RID, float , float ) - BIND2(reflection_probe_set_min_blend_distance,RID, float ) + BIND2(reflection_probe_set_interior_ambient,RID, const Color& ) + BIND2(reflection_probe_set_interior_ambient_energy,RID, float ) + BIND2(reflection_probe_set_interior_ambient_probe_contribution,RID, float ) + BIND2(reflection_probe_set_max_distance,RID, float ) BIND2(reflection_probe_set_extents,RID, const Vector3& ) BIND2(reflection_probe_set_origin_offset,RID, const Vector3& ) - BIND2(reflection_probe_set_enable_parallax_correction,RID, bool ) - BIND2(reflection_probe_set_resolution,RID, int ) - BIND2(reflection_probe_set_hide_skybox,RID, bool ) + BIND2(reflection_probe_set_as_interior,RID, bool ) + BIND2(reflection_probe_set_enable_box_projection,RID, bool ) + BIND2(reflection_probe_set_enable_shadows,RID, bool ) BIND2(reflection_probe_set_cull_mask,RID, uint32_t ) - /* ROOM API */ BIND0R(RID,room_create) @@ -866,7 +871,7 @@ public: BIND0R(RID,environment_create) BIND2(environment_set_background,RID ,EnvironmentBG ) - BIND3(environment_set_skybox,RID,RID ,int ) + BIND2(environment_set_skybox,RID,RID ) BIND2(environment_set_skybox_scale,RID,float) BIND2(environment_set_bg_color,RID,const Color& ) BIND2(environment_set_bg_energy,RID,float ) @@ -890,6 +895,7 @@ public: BIND2(scenario_set_debug,RID,ScenarioDebugMode ) BIND2(scenario_set_environment,RID, RID ) + BIND3(scenario_set_reflection_atlas_size,RID, int,int ) BIND2(scenario_set_fallback_environment,RID, RID ) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index e214374f4..74d77c526 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -102,9 +102,26 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance } geom->lighting_dirty=true; + return E; //this element should make freeing faster + } else if (B->base_type==VS::INSTANCE_REFLECTION_PROBE && (1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceReflectionProbeData * reflection_probe = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + + InstanceReflectionProbeData::PairInfo pinfo; + pinfo.geometry=A; + pinfo.L = geom->reflection_probes.push_back(B); + + List::Element *E = reflection_probe->geometries.push_back(pinfo); + + geom->reflection_dirty=true; + return E; //this element should make freeing faster } + + #if 0 if (A->base_type==INSTANCE_PORTAL) { @@ -189,6 +206,18 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance geom->lighting_dirty=true; + } else if (B->base_type==VS::INSTANCE_REFLECTION_PROBE && (1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceReflectionProbeData * reflection_probe = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + List::Element *E = reinterpret_cast::Element*>(udata); + + geom->reflection_probes.erase(E->get().L); + reflection_probe->geometries.erase(E); + + geom->reflection_dirty=true; + } #if 0 if (A->base_type==INSTANCE_PORTAL) { @@ -252,6 +281,13 @@ RID VisualServerScene::scenario_create() { scenario->octree.set_pair_callback(_instance_pair,this); scenario->octree.set_unpair_callback(_instance_unpair,this); + scenario->reflection_probe_shadow_atlas=VSG::scene_render->shadow_atlas_create(); + VSG::scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas,1024); //make enough shadows for close distance, don't bother with rest + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,0,4); + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,1,4); + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,2,4); + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,3,8); + scenario->reflection_atlas=VSG::scene_render->reflection_atlas_create(); return scenario_rid; } @@ -281,6 +317,16 @@ void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_ } +void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_size,int p_subdiv) { + + Scenario *scenario = scenario_owner.get(p_scenario); + ERR_FAIL_COND(!scenario); + VSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas,p_size); + VSG::scene_render->reflection_atlas_set_subdivision(scenario->reflection_atlas,p_subdiv); + + +} + /* INSTANCING API */ @@ -343,6 +389,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ } VSG::scene_render->free(light->instance); } break; + case VS::INSTANCE_REFLECTION_PROBE: { + + InstanceReflectionProbeData *reflection_probe = static_cast(instance->base_data); + VSG::scene_render->free(reflection_probe->instance); + if (reflection_probe->update_list.in_list()) { + reflection_probe_render_list.remove(&reflection_probe->update_list); + } + } break; } if (instance->base_data) { @@ -508,6 +562,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ InstanceGeometryData *geom = memnew( InstanceGeometryData ); instance->base_data=geom; } break; + case VS::INSTANCE_REFLECTION_PROBE: { + + InstanceReflectionProbeData *reflection_probe = memnew( InstanceReflectionProbeData ); + reflection_probe->owner=instance; + instance->base_data=reflection_probe; + + reflection_probe->instance=VSG::scene_render->reflection_probe_instance_create(p_base); + } break; } @@ -607,6 +669,12 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){ light->D=NULL; } } break; + case VS::INSTANCE_REFLECTION_PROBE: { + + InstanceReflectionProbeData *reflection_probe = static_cast(instance->base_data); + VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); + } break; + } instance->scenario=NULL; @@ -876,6 +944,15 @@ void VisualServerScene::_update_instance(Instance *p_instance) { } + if (p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE) { + + InstanceReflectionProbeData *reflection_probe = static_cast(p_instance->base_data); + + VSG::scene_render->reflection_probe_instance_set_transform( reflection_probe->instance, p_instance->transform ); + reflection_probe->reflection_dirty=true; + + } + if (p_instance->aabb.has_no_surface()) return; @@ -970,7 +1047,7 @@ void VisualServerScene::_update_instance(Instance *p_instance) { uint32_t pairable_mask=0; bool pairable=false; - if (p_instance->base_type == VS::INSTANCE_LIGHT) { + if (p_instance->base_type == VS::INSTANCE_LIGHT || p_instance->base_type==VS::INSTANCE_REFLECTION_PROBE) { pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK:0; pairable=true; @@ -1072,6 +1149,12 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { new_aabb = VSG::storage->light_get_aabb(p_instance->base); } break; + case VisualServer::INSTANCE_REFLECTION_PROBE: { + + new_aabb = VSG::storage->reflection_probe_get_aabb(p_instance->base); + + } break; + #if 0 case VisualServer::INSTANCE_ROOM: { @@ -1129,7 +1212,7 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { -void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect) { +void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,const Transform p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_orthogonal,RID p_shadow_atlas,Scenario* p_scenario) { InstanceLightData * light = static_cast(p_instance->base_data); @@ -1138,14 +1221,14 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer case VS::LIGHT_DIRECTIONAL: { - float max_distance = p_camera->zfar; + float max_distance =p_cam_projection.get_z_far(); float shadow_max = VSG::storage->light_get_param(p_instance->base,VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); if (shadow_max>0) { max_distance=MIN(shadow_max,max_distance); } - max_distance=MAX(max_distance,p_camera->znear+0.001); + max_distance=MAX(max_distance,p_cam_projection.get_z_near()+0.001); - float range = max_distance-p_camera->znear; + float range = max_distance-p_cam_projection.get_z_near(); int splits=0; switch(VSG::storage->light_directional_get_shadow_mode(p_instance->base)) { @@ -1156,9 +1239,9 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer float distances[5]; - distances[0]=p_camera->znear; + distances[0]=p_cam_projection.get_z_near(); for(int i=0;iznear+VSG::storage->light_get_param(p_instance->base,VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET+i))*range; + distances[i+1]=p_cam_projection.get_z_near()+VSG::storage->light_get_param(p_instance->base,VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET+i))*range; }; distances[splits]=max_distance; @@ -1172,38 +1255,24 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer // setup a camera matrix for that range! CameraMatrix camera_matrix; - switch(p_camera->type) { - - case Camera::ORTHOGONAL: { - - camera_matrix.set_orthogonal( - p_camera->size, - p_viewport_rect.width / p_viewport_rect.height, - distances[(i==0 || !overlap )?i:i-1], - distances[i+1], - p_camera->vaspect - - ); - } break; - case Camera::PERSPECTIVE: { + float aspect = p_cam_projection.get_aspect(); - camera_matrix.set_perspective( - p_camera->fov, - p_viewport_rect.width / (float)p_viewport_rect.height, - distances[(i==0 || !overlap )?i:i-1], - distances[i+1], - p_camera->vaspect + if (p_cam_orthogonal) { - ); + float w,h; + p_cam_projection.get_viewport_size(w,h); + camera_matrix.set_orthogonal(w,aspect,distances[(i==0 || !overlap )?i:i-1],distances[i+1],false); + } else { - } break; + float fov = p_cam_projection.get_fov(); + camera_matrix.set_perspective(fov,aspect,distances[(i==0 || !overlap )?i:i-1],distances[i+1],false); } //obtain the frustum endpoints Vector3 endpoints[8]; // frustum plane endpoints - bool res = camera_matrix.get_endpoints(p_camera->transform,endpoints); + bool res = camera_matrix.get_endpoints(p_cam_transform,endpoints); ERR_CONTINUE(!res); // obtain the light frustm ranges (given endpoints) @@ -1459,8 +1528,8 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer float angle = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE); CameraMatrix cm; - cm.set_perspective( 90, 1.0, 0.01, radius ); - print_line("perspective: "+cm); + cm.set_perspective( angle, 1.0, 0.01, radius ); + Vector planes = cm.get_projection_planes(p_instance->transform); int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK); @@ -1477,7 +1546,6 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer } - print_line("MOMONGO"); VSG::scene_render->light_instance_set_shadow_transform(light->instance,cm,p_instance->transform,radius,0,0); VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,0,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count); @@ -1487,26 +1555,13 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer } - - - void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size,RID p_shadow_atlas) { - Camera *camera = camera_owner.getornull(p_camera); ERR_FAIL_COND(!camera); - Scenario *scenario = scenario_owner.getornull(p_scenario); - - render_pass++; - uint32_t camera_layer_mask=camera->visible_layers; - - VSG::scene_render->set_scene_pass(render_pass); - - /* STEP 1 - SETUP CAMERA */ CameraMatrix camera_matrix; - Transform camera_inverse_xform = camera->transform.affine_inverse(); bool ortho=false; @@ -1538,16 +1593,36 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp } break; } + _render_scene(camera->transform,camera_matrix,ortho,camera->env,camera->visible_layers,p_scenario,p_shadow_atlas,RID(),-1); + +} + + +void VisualServerScene::_render_scene(const Transform p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_orthogonal,RID p_force_environment,uint32_t p_visible_layers, RID p_scenario,RID p_shadow_atlas,RID p_reflection_probe,int p_reflection_probe_pass) { + + + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + render_pass++; + uint32_t camera_layer_mask=p_visible_layers; + + VSG::scene_render->set_scene_pass(render_pass); + // rasterizer->set_camera(camera->transform, camera_matrix,ortho); - Vector planes = camera_matrix.get_projection_planes(camera->transform); + Vector planes = p_cam_projection.get_projection_planes(p_cam_transform); - Plane near_plane(camera->transform.origin,-camera->transform.basis.get_axis(2).normalized()); + Plane near_plane(p_cam_transform.origin,-p_cam_transform.basis.get_axis(2).normalized()); + float z_far = p_cam_projection.get_z_far(); /* STEP 2 - CULL */ int cull_count = scenario->octree.cull_convex(planes,instance_cull_result,MAX_INSTANCE_CULL); light_cull_count=0; + + reflection_probe_cull_count=0; + // light_samplers_culled=0; /* print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0)); @@ -1649,7 +1724,6 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp bool keep=false; - if ((camera_layer_mask&ins->layer_mask)==0) { //failure @@ -1673,6 +1747,36 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp } + } else if (ins->base_type==VS::INSTANCE_REFLECTION_PROBE && ins->visible) { + + + if (ins->visible && reflection_probe_cull_count(ins->base_data); + + if (p_reflection_probe!=reflection_probe->instance) { + //avoid entering The Matrix + + if (!reflection_probe->geometries.empty()) { + //do not add this light if no geometry is affected by it.. + + if (reflection_probe->reflection_dirty || VSG::scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) { + if (!reflection_probe->update_list.in_list()) { + reflection_probe->render_step=0; + reflection_probe_render_list.add(&reflection_probe->update_list); + } + + reflection_probe->reflection_dirty=false; + } + + if (VSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { + reflection_probe_instance_cull_result[reflection_probe_cull_count]=reflection_probe->instance; + reflection_probe_cull_count++; + } + + } + } + } } else if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { @@ -1746,6 +1850,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp InstanceGeometryData * geom = static_cast(ins->base_data); + if (geom->lighting_dirty) { int l=0; //only called when lights AABB enter/exit this geometry @@ -1761,7 +1866,23 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp geom->lighting_dirty=false; } + if (geom->reflection_dirty) { + int l=0; + //only called when reflection probe AABB enter/exit this geometry + ins->reflection_probe_instances.resize(geom->reflection_probes.size()); + + for (List::Element *E=geom->reflection_probes.front();E;E=E->next()) { + + InstanceReflectionProbeData * reflection_probe = static_cast(E->get()->base_data); + + ins->reflection_probe_instances[l++]=reflection_probe->instance; + } + + geom->reflection_dirty=false; + } + ins->depth = near_plane.distance_to(ins->transform.origin); + ins->depth_layer=CLAMP(int(ins->depth*8/z_far),0,7); } @@ -1803,7 +1924,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp //check shadow.. - if (light && VSG::storage->light_has_shadow(E->get()->base)) { + if (light && p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(E->get()->base)) { lights_with_shadow[directional_shadow_count++]=E->get(); } @@ -1817,7 +1938,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp for(int i=0;itransform; - float zn = camera_matrix.get_z_near(); + Transform cam_xf = p_cam_transform; + float zn = p_cam_projection.get_z_near(); Plane p (cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2) ); //camera near plane float vp_w,vp_h; //near plane size in screen coordinates - camera_matrix.get_viewport_size(vp_w,vp_h); + p_cam_projection.get_viewport_size(vp_w,vp_h); switch(VSG::storage->light_get_type(ins->base)) { @@ -1861,7 +1982,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp ins->transform.origin+cam_xf.basis.get_axis(0)*radius }; - if (!ortho) { + if (!p_cam_orthogonal) { //if using perspetive, map them to near plane for(int j=0;j<2;j++) { if (p.distance_to(points[j]) < 0 ) { @@ -1895,7 +2016,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp base+cam_xf.basis.get_axis(0)*w }; - if (!ortho) { + if (!p_cam_orthogonal) { //if using perspetive, map them to near plane for(int j=0;j<2;j++) { if (p.distance_to(points[j]) < 0 ) { @@ -1933,7 +2054,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp if (redraw) { //must redraw! - _light_instance_update_shadow(ins,camera,p_shadow_atlas,scenario,p_viewport_size); + _light_instance_update_shadow(ins,p_cam_transform,p_cam_projection,p_cam_orthogonal,p_shadow_atlas,scenario); } } @@ -1942,8 +2063,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp /* ENVIRONMENT */ RID environment; - if (camera->env.is_valid()) //camera has more environment priority - environment=camera->env; + if (p_force_environment.is_valid()) //camera has more environment priority + environment=p_force_environment; else if (scenario->environment.is_valid()) environment=scenario->environment; else @@ -1964,45 +2085,129 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp #endif /* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/ -#if 0 - // add lights + VSG::scene_render->render_scene(p_cam_transform, p_cam_projection,p_cam_orthogonal,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count+directional_light_count,reflection_probe_instance_cull_result,reflection_probe_cull_count,environment,p_shadow_atlas,scenario->reflection_atlas,p_reflection_probe,p_reflection_probe_pass); - { - List::Element *E=p_scenario->directional_lights.front(); +} - for(;E;E=E->next()) { - Instance *light = E->get().is_valid()?instance_owner.get(E->get()):NULL; +bool VisualServerScene::_render_probe_step(Instance* p_instance,int p_step) { - ERR_CONTINUE(!light); - if (!light->light_info->enabled) - continue; + InstanceReflectionProbeData *reflection_probe = static_cast(p_instance->base_data); + Scenario *scenario = p_instance->scenario; + ERR_FAIL_COND_V(!scenario,true); - rasterizer->add_light(light->light_info->instance); - light->light_info->last_add_pass=render_pass; + if (p_step==0) { + + if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance,scenario->reflection_atlas)) { + return true; //sorry, all full :( } + } - for (int i=0;i=0 && p_step<6) { - Instance *ins = light_cull_result[i]; - rasterizer->add_light(ins->light_info->instance); - ins->light_info->last_add_pass=render_pass; + static const Vector3 view_normals[6]={ + Vector3(-1, 0, 0), + Vector3(+1, 0, 0), + Vector3( 0,-1, 0), + Vector3( 0,+1, 0), + Vector3( 0, 0,-1), + Vector3( 0, 0,+1) + }; + + Vector3 extents = VSG::storage->reflection_probe_get_extents(p_instance->base); + Vector3 origin_offset = VSG::storage->reflection_probe_get_origin_offset(p_instance->base); + float max_distance = VSG::storage->reflection_probe_get_origin_max_distance(p_instance->base); + + + Vector3 edge = view_normals[p_step]*extents; + float distance = ABS(view_normals[p_step].dot(edge)-view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit + + max_distance = MAX(max_distance,distance); + + + //render cubemap side + CameraMatrix cm; + cm.set_perspective(90,1,0.01,max_distance); + + + static const Vector3 view_up[6]={ + Vector3( 0,-1, 0), + Vector3( 0,-1, 0), + Vector3( 0, 0,-1), + Vector3( 0, 0,+1), + Vector3( 0,-1, 0), + Vector3( 0,-1, 0) + }; + + Transform local_view; + local_view.set_look_at(origin_offset,origin_offset+view_normals[p_step],view_up[p_step]); + + Transform xform = p_instance->transform * local_view; + + RID shadow_atlas; + + if (VSG::storage->reflection_probe_renders_shadows(p_instance->base)) { + + shadow_atlas=scenario->reflection_probe_shadow_atlas; } + + _render_scene(xform,cm,false,RID(),VSG::storage->reflection_probe_get_cull_mask(p_instance->base),p_instance->scenario->self,shadow_atlas,reflection_probe->instance,p_step); + + } else { + //do roughness postprocess step until it belives it's done + return VSG::scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance); } - // add geometry -#endif + return false; +} - VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count+directional_light_count,environment,p_shadow_atlas); +void VisualServerScene::render_probes() { -} + SelfList *probe = reflection_probe_render_list.first(); + bool busy=false; + while(probe) { -void VisualServerScene::_update_dirty_instance(Instance *p_instance) { + SelfList *next=probe->next(); + RID base = probe->self()->owner->base; + switch(VSG::storage->reflection_probe_get_update_mode(base)) { + + case VS::REFLECTION_PROBE_UPDATE_ONCE: { + if (busy) //already rendering something + break; + + bool done = _render_probe_step(probe->self()->owner,probe->self()->render_step); + if (done) { + reflection_probe_render_list.remove(probe); + } else { + probe->self()->render_step++; + } + + busy=true; //do not render another one of this kind + } break; + case VS::REFLECTION_PROBE_UPDATE_ALWAYS: { + + int step=0; + bool done=false; + while(!done) { + done = _render_probe_step(probe->self()->owner,step); + step++; + } + + reflection_probe_render_list.remove(probe); + } break; + + } + + probe=next; + } +} + +void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (p_instance->update_aabb) _update_instance_aabb(p_instance); @@ -2114,7 +2319,8 @@ bool VisualServerScene::free(RID p_rid) { while(scenario->instances.first()) { instance_set_scenario(scenario->instances.first()->self()->self,RID()); } - + VSG::scene_render->free(scenario->reflection_probe_shadow_atlas); + VSG::scene_render->free(scenario->reflection_atlas); scenario_owner.free(p_rid); memdelete(scenario); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index e4f06fee6..0eaad45c9 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -16,8 +16,9 @@ public: MAX_INSTANCE_CULL=65536, MAX_LIGHTS_CULLED=4096, + MAX_REFLECTION_PROBES_CULLED=4096, MAX_ROOM_CULL=32, - MAX_EXTERIOR_PORTALS=128, + MAX_EXTERIOR_PORTALS=128, }; uint64_t render_pass; @@ -156,6 +157,9 @@ public: List directional_lights; RID environment; RID fallback_environment; + RID reflection_probe_shadow_atlas; + RID reflection_atlas; + SelfList::List instances; @@ -172,6 +176,7 @@ public: virtual void scenario_set_debug(RID p_scenario,VS::ScenarioDebugMode p_debug_mode); virtual void scenario_set_environment(RID p_scenario, RID p_environment); virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_size,int p_subdiv); /* INSTANCING API */ @@ -288,13 +293,43 @@ public: bool lighting_dirty; bool can_cast_shadows; + List reflection_probes; + bool reflection_dirty; + InstanceGeometryData() { lighting_dirty=false; + reflection_dirty=true; can_cast_shadows=true; } }; + struct InstanceReflectionProbeData : public InstanceBaseData { + + + Instance *owner; + + struct PairInfo { + List::Element *L; //light iterator in geometry + Instance *geometry; + }; + List geometries; + + + RID instance; + bool reflection_dirty; + SelfList update_list; + + int render_step; + + InstanceReflectionProbeData() : update_list(this) { + + reflection_dirty=true; + render_step=-1; + } + }; + + SelfList::List reflection_probe_render_list; struct InstanceLightData : public InstanceBaseData { @@ -325,6 +360,8 @@ public: Instance *light_cull_result[MAX_LIGHTS_CULLED]; RID light_instance_cull_result[MAX_LIGHTS_CULLED]; int light_cull_count; + RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED]; + int reflection_probe_cull_count; RID_Owner instance_owner; @@ -366,10 +403,15 @@ public: _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); - _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect); + _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance,const Transform p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_orthogonal,RID p_shadow_atlas,Scenario* p_scenario); - void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); + void _render_scene(const Transform p_cam_transform, const CameraMatrix& p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + + void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); + + bool _render_probe_step(Instance* p_instance,int p_step); + void render_probes(); bool free(RID p_rid); VisualServerScene(); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 18742aa21..fa2c461f3 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -520,26 +520,29 @@ void VisualServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_ bool VisualServerViewport::free(RID p_rid) { - Viewport * viewport = viewport_owner.getornull(p_rid); - if (!viewport) - return false; + if (viewport_owner.owns(p_rid)) { + Viewport * viewport = viewport_owner.getornull(p_rid); - VSG::storage->free( viewport->render_target ); - VSG::scene_render->free( viewport->shadow_atlas ); - while(viewport->canvas_map.front()) { - viewport_remove_canvas(p_rid,viewport->canvas_map.front()->key()); - } + VSG::storage->free( viewport->render_target ); + VSG::scene_render->free( viewport->shadow_atlas ); + + while(viewport->canvas_map.front()) { + viewport_remove_canvas(p_rid,viewport->canvas_map.front()->key()); + } - viewport_set_scenario(p_rid,RID()); - active_viewports.erase(viewport); + viewport_set_scenario(p_rid,RID()); + active_viewports.erase(viewport); + + viewport_owner.free(p_rid); + memdelete(viewport); - viewport_owner.free(p_rid); - memdelete(viewport); + return true; + } - return true; + return false; } diff --git a/servers/visual_server.h b/servers/visual_server.h index 148d090a0..5e318a4fe 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -127,8 +127,6 @@ public: virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable)=0; - virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const=0; - struct TextureInfo { RID texture; Size2 size; @@ -139,6 +137,10 @@ public: virtual void texture_debug_usage(List *r_info)=0; + /* SKYBOX API */ + + virtual RID skybox_create()=0; + virtual void skybox_set_texture(RID p_skybox,RID p_cube_map,int p_radiance_size)=0; /* SHADER API */ @@ -406,14 +408,23 @@ public: virtual RID reflection_probe_create()=0; + enum ReflectionProbeUpdateMode { + REFLECTION_PROBE_UPDATE_ONCE, + REFLECTION_PROBE_UPDATE_ALWAYS, + }; + + + virtual void reflection_probe_set_update_mode(RID p_probe, ReflectionProbeUpdateMode p_mode)=0; virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity)=0; - virtual void reflection_probe_set_clip(RID p_probe, float p_near, float p_far)=0; - virtual void reflection_probe_set_min_blend_distance(RID p_probe, float p_distance)=0; + virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color& p_color)=0; + virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy)=0; + virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib)=0; + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance)=0; virtual void reflection_probe_set_extents(RID p_probe, const Vector3& p_extents)=0; virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset)=0; - virtual void reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable)=0; - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution)=0; - virtual void reflection_probe_set_hide_skybox(RID p_probe, bool p_hide)=0; + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable)=0; virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers)=0; @@ -514,7 +525,7 @@ public: }; virtual void environment_set_background(RID p_env,EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox)=0; virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; @@ -563,6 +574,7 @@ public: virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode)=0; virtual void scenario_set_environment(RID p_scenario, RID p_environment)=0; + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_size,int p_subdiv)=0; virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment)=0; diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index cdd56bbac..a4a1aaedf 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -245,6 +245,7 @@ void EditorSpatialGizmo::add_handles(const Vector &p_handles, bool p_bi Array a; a.resize(VS::ARRAY_MAX); a[VS::ARRAY_VERTEX]=p_handles; + print_line("handles?: "+itos(p_handles.size())); DVector colors; { colors.resize(p_handles.size()); @@ -2238,6 +2239,164 @@ VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier* p_notifier) //////// +/// + + +String ReflectionProbeGizmo::get_handle_name(int p_idx) const { + + switch(p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + case 3: return "Origin X"; + case 4: return "Origin Y"; + case 5: return "Origin Z"; + } + + return ""; +} +Variant ReflectionProbeGizmo::get_handle_value(int p_idx) const{ + + return AABB(probe->get_extents(),probe->get_origin_offset()); +} +void ReflectionProbeGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){ + + Transform gt = probe->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + + if (p_idx<3) { + Vector3 extents = probe->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*16384)}; + + Vector3 axis; + axis[p_idx]=1.0; + + Vector3 ra,rb; + Geometry::get_closest_points_between_segments(Vector3(),axis*16384,sg[0],sg[1],ra,rb); + float d = ra[p_idx]; + if (d<0.001) + d=0.001; + + extents[p_idx]=d; + probe->set_extents(extents); + } else { + + p_idx-=3; + + Vector3 origin = probe->get_origin_offset(); + origin[p_idx]=0; + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*16384)}; + + Vector3 axis; + axis[p_idx]=1.0; + + Vector3 ra,rb; + Geometry::get_closest_points_between_segments(origin-axis*16384,origin+axis*16384,sg[0],sg[1],ra,rb); + float d = ra[p_idx]; + d+=0.25; + + origin[p_idx]=d; + probe->set_origin_offset(origin); + + } +} + +void ReflectionProbeGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){ + + AABB restore = p_restore; + + if (p_cancel) { + probe->set_extents(restore.pos); + probe->set_origin_offset(restore.size); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(probe,"set_extents",probe->get_extents()); + ur->add_do_method(probe,"set_origin_offset",probe->get_origin_offset()); + ur->add_undo_method(probe,"set_extents",restore.pos); + ur->add_undo_method(probe,"set_origin_offset",restore.size); + ur->commit_action(); + +} + +void ReflectionProbeGizmo::redraw(){ + + clear(); + + Vector lines; + Vector internal_lines; + Vector3 extents = probe->get_extents(); + + AABB aabb; + aabb.pos=-extents; + aabb.size=extents*2; + + for(int i=0;i<12;i++) { + Vector3 a,b; + aabb.get_edge(i,a,b); + lines.push_back(a); + lines.push_back(b); + } + + for(int i=0;i<8;i++) { + Vector3 ep = aabb.get_endpoint(i); + internal_lines.push_back(probe->get_origin_offset()); + internal_lines.push_back(ep); + + + } + + Vector handles; + + + for(int i=0;i<3;i++) { + + Vector3 ax; + ax[i]=aabb.pos[i]+aabb.size[i]; + handles.push_back(ax); + } + + for(int i=0;i<3;i++) { + + + Vector3 orig_handle=probe->get_origin_offset(); + orig_handle[i]-=0.25; + lines.push_back(orig_handle); + handles.push_back(orig_handle); + + orig_handle[i]+=0.5; + lines.push_back(orig_handle); + } + + add_lines(lines,SpatialEditorGizmos::singleton->reflection_probe_material); + add_lines(internal_lines,SpatialEditorGizmos::singleton->reflection_probe_material_internal); + //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); + add_collision_segments(lines); + add_handles(handles); + +} +ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe* p_probe){ + + probe=p_probe; + set_spatial_node(p_probe); +} + +//////// + + + void NavigationMeshSpatialGizmo::redraw() { @@ -2929,6 +3088,12 @@ Ref SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return misg; } + if (p_spatial->cast_to()) { + + Ref misg = memnew( ReflectionProbeGizmo(p_spatial->cast_to()) ); + return misg; + } + if (p_spatial->cast_to()) { Ref misg = memnew( VehicleWheelSpatialGizmo(p_spatial->cast_to()) ); @@ -3132,6 +3297,8 @@ SpatialEditorGizmos::SpatialEditorGizmos() { raycast_material = create_line_material(Color(1.0,0.8,0.6)); car_wheel_material = create_line_material(Color(0.6,0.8,1.0)); visibility_notifier_material = create_line_material(Color(1.0,0.5,1.0)); + reflection_probe_material = create_line_material(Color(0.5,1.0,0.7)); + reflection_probe_material_internal = create_line_material(Color(0.3,0.8,0.5,0.4)); joint_material = create_line_material(Color(0.6,0.8,1.0)); stream_player_icon = Ref( memnew( FixedSpatialMaterial )); diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h index 2c0033cdc..2cc1a7eab 100644 --- a/tools/editor/spatial_editor_gizmos.h +++ b/tools/editor/spatial_editor_gizmos.h @@ -45,6 +45,7 @@ #include "scene/3d/portal.h" #include "scene/3d/ray_cast.h" #include "scene/3d/navigation_mesh.h" +#include "scene/3d/reflection_probe.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/collision_polygon.h" @@ -307,6 +308,25 @@ public: }; +class ReflectionProbeGizmo : public EditorSpatialGizmo { + + OBJ_TYPE(ReflectionProbeGizmo ,EditorSpatialGizmo); + + + ReflectionProbe* probe; + +public: + + virtual String get_handle_name(int p_idx) const; + virtual Variant get_handle_value(int p_idx) const; + virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point); + virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false); + + void redraw(); + ReflectionProbeGizmo(ReflectionProbe* p_notifier=NULL); + +}; + class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { @@ -339,6 +359,7 @@ public: }; + class RayCastSpatialGizmo : public EditorSpatialGizmo { OBJ_TYPE(RayCastSpatialGizmo,EditorSpatialGizmo); @@ -473,6 +494,8 @@ public: Ref light_material_directional_icon; Ref camera_material; Ref skeleton_material; + Ref reflection_probe_material; + Ref reflection_probe_material_internal; Ref room_material; Ref portal_material; Ref raycast_material; -- cgit v1.2.3-70-g09d2 From 943d27f46ded993105928c4a46414aa16d84115e Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 22 Nov 2016 01:26:56 -0300 Subject: Instancing is working! (hooray) --- drivers/gles3/rasterizer_gles3.cpp | 1 + drivers/gles3/rasterizer_scene_gles3.cpp | 92 ++++ drivers/gles3/rasterizer_storage_gles3.cpp | 540 ++++++++++++++++++++--- drivers/gles3/rasterizer_storage_gles3.h | 42 +- drivers/gles3/shaders/scene.glsl | 26 +- scene/main/viewport.cpp | 16 - scene/resources/multimesh.cpp | 43 +- scene/resources/multimesh.h | 5 - servers/visual/rasterizer.h | 6 +- servers/visual/visual_server_raster.h | 5 +- servers/visual/visual_server_scene.cpp | 84 +++- servers/visual_server.cpp | 2 +- servers/visual_server.h | 6 +- tools/editor/plugins/multimesh_editor_plugin.cpp | 8 +- 14 files changed, 722 insertions(+), 154 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 63090e53a..84fa34931 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -124,6 +124,7 @@ void RasterizerGLES3::begin_frame(){ storage->frame.time[3]=Math::fmod(time_total,60); storage->frame.count++; + storage->update_dirty_multimeshes(); storage->update_dirty_skeletons(); storage->update_dirty_shaders(); storage->update_dirty_materials(); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index e0a3dbd36..54dc3b914 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1098,6 +1098,55 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) { glBindVertexArray(s->array_id); // everything is so easy nowadays } break; + + case VS::INSTANCE_MULTIMESH: { + + RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast(e->owner); + RasterizerStorageGLES3::Surface *s = static_cast(e->geometry); + glBindVertexArray(s->instancing_array_id); // use the instancing array ID + glBindBuffer(GL_ARRAY_BUFFER,multi_mesh->buffer); //modify the buffer + + int stride = (multi_mesh->xform_floats+multi_mesh->color_floats)*4; + glEnableVertexAttribArray(8); + glVertexAttribPointer(8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+0); + glVertexAttribDivisorARB(8,1); + glEnableVertexAttribArray(9); + glVertexAttribPointer(9,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+4*4); + glVertexAttribDivisorARB(9,1); + + int color_ofs; + + if (multi_mesh->transform_format==VS::MULTIMESH_TRANSFORM_3D) { + glEnableVertexAttribArray(10); + glVertexAttribPointer(10,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+8*4); + glVertexAttribDivisorARB(10,1); + color_ofs=12*4; + } else { + glDisableVertexAttribArray(10); + glVertexAttrib4f(10,0,0,1,0); + color_ofs=8*4; + } + + switch(multi_mesh->color_format) { + + case VS::MULTIMESH_COLOR_NONE: { + glDisableVertexAttribArray(11); + glVertexAttrib4f(11,1,1,1,1); + } break; + case VS::MULTIMESH_COLOR_8BIT: { + glEnableVertexAttribArray(11); + glVertexAttribPointer(11,4,GL_UNSIGNED_BYTE,GL_TRUE,stride,((uint8_t*)NULL)+color_ofs); + glVertexAttribDivisorARB(11,1); + + } break; + case VS::MULTIMESH_COLOR_FLOAT: { + glEnableVertexAttribArray(11); + glVertexAttribPointer(11,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+color_ofs); + glVertexAttribDivisorARB(11,1); + } break; + } + + } break; } } @@ -1133,6 +1182,25 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } } break; + case VS::INSTANCE_MULTIMESH: { + + RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast(e->owner); + RasterizerStorageGLES3::Surface *s = static_cast(e->geometry); + + int amount = MAX(multi_mesh->size,multi_mesh->visible_instances); + + if (s->index_array_len>0) { + + glDrawElementsInstancedARB(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0,amount); + + } else { + + glDrawArraysInstancedARB(gl_primitive[s->primitive],0,s->array_len,amount); + + } + + } break; + } } @@ -1481,6 +1549,11 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } } + if ((prev_base_type==VS::INSTANCE_MULTIMESH) != (e->instance->base_type==VS::INSTANCE_MULTIMESH)) { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING,e->instance->base_type==VS::INSTANCE_MULTIMESH); + rebind=true; + } + if (material!=prev_material || rebind) { rebind = _setup_material(material,p_alpha_pass); @@ -1519,6 +1592,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glFrontFace(GL_CW); glBindVertexArray(0); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); @@ -2414,6 +2488,24 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_ } break; case VS::INSTANCE_MULTIMESH: { + RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getptr(inst->base); + ERR_CONTINUE(!multi_mesh); + + if (multi_mesh->size==0 || multi_mesh->visible_instances==0) + continue; + + RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getptr(multi_mesh->mesh); + if (!mesh) + continue; //mesh not assigned + + int ssize = mesh->surfaces.size(); + + for (int i=0;isurfaces[i]; + _add_geometry(s,inst,multi_mesh,-1,p_shadow); + } + } break; case VS::INSTANCE_IMMEDIATE: { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index c2598e458..e5a0cded8 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2716,31 +2716,45 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P //generate arrays for faster state switching - glGenVertexArrays(1,&surface->array_id); - glBindVertexArray(surface->array_id); - glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); + for(int i=0;i<2;i++) { - for(int i=0;iarray_id); + glBindVertexArray(surface->array_id); + glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); + } else { + //for instancing draw (can be changed and no one cares) + glGenVertexArrays(1,&surface->instancing_array_id); + glBindVertexArray(surface->instancing_array_id); + glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); - if (!attribs[i].enabled) - continue; + } + + + for(int i=0;iindex_id) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); + } - if (surface->index_id) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); } - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER,0); //unbind - } { @@ -3068,14 +3082,14 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{ if (mesh->custom_aabb!=AABB()) return mesh->custom_aabb; -/* + Skeleton *sk=NULL; if (p_skeleton.is_valid()) sk=skeleton_owner.get(p_skeleton); -*/ + AABB aabb; - /* - if (sk && sk->bones.size()!=0) { + + if (sk && sk->size!=0) { for (int i=0;isurfaces.size();i++) { @@ -3088,21 +3102,67 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{ const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr(); const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr(); - int sbs = sk->bones.size(); + int sbs = sk->size; ERR_CONTINUE(bs>sbs); - Skeleton::Bone *skb = sk->bones.ptr(); + float *skb = sk->bones.ptr(); + + bool first=true; - for(int j=0;juse_2d) { + for(int j=0;jsurfaces.size();i++) { if (i==0) @@ -3125,9 +3185,9 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{ else aabb.merge_with(mesh->surfaces[i]->aabb); } -/* + } -*/ + return aabb; } @@ -3146,75 +3206,431 @@ void RasterizerStorageGLES3::mesh_clear(RID p_mesh){ RID RasterizerStorageGLES3::multimesh_create(){ - return RID(); + MultiMesh *multimesh = memnew( MultiMesh ); + return multimesh_owner.make_rid(multimesh); } -void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb){ +void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format){ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + + if (multimesh->size==p_instances && multimesh->transform_format==p_transform_format && multimesh->color_format==p_color_format) + return; + + if (multimesh->buffer) { + glDeleteBuffers(1,&multimesh->buffer); + multimesh->data.resize(0); + } + + multimesh->size=p_instances; + multimesh->transform_format=p_transform_format; + multimesh->color_format=p_color_format; + + if (multimesh->size) { + + if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) { + multimesh->xform_floats=8; + } else { + multimesh->xform_floats=12; + + } + + if (multimesh->color_format==VS::MULTIMESH_COLOR_NONE) { + multimesh->color_floats=0; + } else if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) { + multimesh->color_floats=1; + } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) { + multimesh->color_floats=4; + } + + int format_floats = multimesh->color_floats+multimesh->xform_floats; + multimesh->data.resize(format_floats*p_instances); + for(int i=0;itransform_format==VS::MULTIMESH_TRANSFORM_2D) { + multimesh->data[i+0]=1.0; + multimesh->data[i+1]=0.0; + multimesh->data[i+2]=0.0; + multimesh->data[i+3]=0.0; + multimesh->data[i+4]=0.0; + multimesh->data[i+5]=1.0; + multimesh->data[i+6]=0.0; + multimesh->data[i+7]=0.0; + color_from=8; + } else { + multimesh->data[i+0]=1.0; + multimesh->data[i+1]=0.0; + multimesh->data[i+2]=0.0; + multimesh->data[i+3]=0.0; + multimesh->data[i+4]=0.0; + multimesh->data[i+5]=1.0; + multimesh->data[i+6]=0.0; + multimesh->data[i+7]=0.0; + multimesh->data[i+8]=0.0; + multimesh->data[i+9]=0.0; + multimesh->data[i+10]=1.0; + multimesh->data[i+11]=0.0; + color_from=12; + } + + if (multimesh->color_format==VS::MULTIMESH_COLOR_NONE) { + //none + } else if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) { + + union { + uint32_t colu; + float colf; + } cu; + + cu.colu=0xFFFFFFFF; + multimesh->data[i+color_from+0]=cu.colf; + + } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) { + multimesh->data[i+color_from+0]=1.0; + multimesh->data[i+color_from+1]=1.0; + multimesh->data[i+color_from+2]=1.0; + multimesh->data[i+color_from+3]=1.0; + } + } + + glGenBuffers(1,&multimesh->buffer); + glBindBuffer(GL_ARRAY_BUFFER,multimesh->buffer); + glBufferData(GL_ARRAY_BUFFER,multimesh->data.size()*sizeof(float),NULL,GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER,0); + + } + + multimesh->dirty_data=true; + multimesh->dirty_aabb=true; + + if (!multimesh->update_list.in_list()) { + multimesh_update_list.add(&multimesh->update_list); + } } + int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const{ - return 0; + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh,0); + + return multimesh->size; } void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh,RID p_mesh){ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); -} -void RasterizerStorageGLES3::multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb){ + multimesh->mesh=p_mesh; + multimesh->dirty_aabb=true; + if (!multimesh->update_list.in_list()) { + multimesh_update_list.add(&multimesh->update_list); + } } -void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform){ +void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform){ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index,multimesh->size); + ERR_FAIL_COND(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D); + + int stride = multimesh->color_floats+multimesh->xform_floats; + float *dataptr=&multimesh->data[stride*p_index]; + + dataptr[ 0]=p_transform.basis.elements[0][0]; + dataptr[ 1]=p_transform.basis.elements[0][1]; + dataptr[ 2]=p_transform.basis.elements[0][2]; + dataptr[ 3]=p_transform.origin.x; + dataptr[ 4]=p_transform.basis.elements[1][0]; + dataptr[ 5]=p_transform.basis.elements[1][1]; + dataptr[ 6]=p_transform.basis.elements[1][2]; + dataptr[ 7]=p_transform.origin.y; + dataptr[ 8]=p_transform.basis.elements[2][0]; + dataptr[ 9]=p_transform.basis.elements[2][1]; + dataptr[10]=p_transform.basis.elements[2][2]; + dataptr[11]=p_transform.origin.z; + + multimesh->dirty_data=true; + multimesh->dirty_aabb=true; + + if (!multimesh->update_list.in_list()) { + multimesh_update_list.add(&multimesh->update_list); + } } + void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform){ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index,multimesh->size); + ERR_FAIL_COND(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_3D); + + int stride = multimesh->color_floats+multimesh->xform_floats; + float *dataptr=&multimesh->data[stride*p_index]; + + dataptr[ 0]=p_transform.elements[0][0]; + dataptr[ 1]=p_transform.elements[1][0]; + dataptr[ 2]=0; + dataptr[ 3]=p_transform.elements[2][0]; + dataptr[ 4]=p_transform.elements[0][1]; + dataptr[ 5]=p_transform.elements[1][1]; + dataptr[ 6]=0; + dataptr[ 7]=p_transform.elements[2][1]; + + multimesh->dirty_data=true; + multimesh->dirty_aabb=true; + if (!multimesh->update_list.in_list()) { + multimesh_update_list.add(&multimesh->update_list); + } } void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color){ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index,multimesh->size); + ERR_FAIL_COND(multimesh->color_format==VS::MULTIMESH_COLOR_NONE); + + int stride = multimesh->color_floats+multimesh->xform_floats; + float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats]; + + if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) { + union { + uint32_t colu; + float colf; + } cu; + + cu.colu=p_color.to_32(); + dataptr[ 0]=cu.colf; + + } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) { + dataptr[ 0]=p_color.r; + dataptr[ 1]=p_color.g; + dataptr[ 2]=p_color.b; + dataptr[ 3]=p_color.a; + } + + + multimesh->dirty_data=true; + multimesh->dirty_aabb=true; + if (!multimesh->update_list.in_list()) { + multimesh_update_list.add(&multimesh->update_list); + } } RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const{ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh,RID()); - return RID(); + return multimesh->mesh; } -AABB RasterizerStorageGLES3::multimesh_get_custom_aabb(RID p_multimesh) const{ - return AABB(); -} Transform RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh,int p_index) const{ - return Transform(); + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Transform()); + ERR_FAIL_INDEX_V(p_index,multimesh->size,Transform()); + ERR_FAIL_COND_V(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D,Transform()); + + int stride = multimesh->color_floats+multimesh->xform_floats; + float *dataptr=&multimesh->data[stride*p_index]; + + Transform xform; + + xform.basis.elements[0][0]=dataptr[ 0]; + xform.basis.elements[0][1]=dataptr[ 1]; + xform.basis.elements[0][2]=dataptr[ 2]; + xform.origin.x=dataptr[ 3]; + xform.basis.elements[1][0]=dataptr[ 4]; + xform.basis.elements[1][1]=dataptr[ 5]; + xform.basis.elements[1][2]=dataptr[ 6]; + xform.origin.y=dataptr[ 7]; + xform.basis.elements[2][0]=dataptr[ 8]; + xform.basis.elements[2][1]=dataptr[ 9]; + xform.basis.elements[2][2]=dataptr[10]; + xform.origin.z=dataptr[11]; + + return xform; } Matrix32 RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const{ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Matrix32()); + ERR_FAIL_INDEX_V(p_index,multimesh->size,Matrix32()); + ERR_FAIL_COND_V(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_3D,Matrix32()); + + int stride = multimesh->color_floats+multimesh->xform_floats; + float *dataptr=&multimesh->data[stride*p_index]; + + Matrix32 xform; + + xform.elements[0][0]=dataptr[ 0]; + xform.elements[1][0]=dataptr[ 1]; + xform.elements[2][0]=dataptr[ 3]; + xform.elements[0][1]=dataptr[ 4]; + xform.elements[1][1]=dataptr[ 5]; + xform.elements[2][1]=dataptr[ 7]; - return Matrix32(); + return xform; } + Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh,int p_index) const{ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh,Color()); + ERR_FAIL_INDEX_V(p_index,multimesh->size,Color()); + ERR_FAIL_COND_V(multimesh->color_format==VS::MULTIMESH_COLOR_NONE,Color()); + + int stride = multimesh->color_floats+multimesh->xform_floats; + float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats]; + + if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) { + union { + uint32_t colu; + float colf; + } cu; + + return Color::hex(cu.colu); + + } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) { + Color c; + c.r=dataptr[ 0]; + c.g=dataptr[ 1]; + c.b=dataptr[ 2]; + c.a=dataptr[ 3]; + + return c; + } + return Color(); + } void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh,int p_visible){ + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + multimesh->visible_instances=p_visible; } int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const{ - return 0; + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh,-1); + + return multimesh->visible_instances; } -AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_mesh) const{ +AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_multimesh) const{ - return AABB(); + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh,AABB()); + + const_cast(this)->update_dirty_multimeshes(); //update pending AABBs + + return multimesh->aabb; +} + +void RasterizerStorageGLES3::update_dirty_multimeshes() { + + while(multimesh_update_list.first()) { + + MultiMesh *multimesh = multimesh_update_list.first()->self(); + + if (multimesh->size && multimesh->dirty_data) { + + + glBindBuffer(GL_ARRAY_BUFFER,multimesh->buffer); + glBufferSubData(GL_ARRAY_BUFFER,0,multimesh->data.size()*sizeof(float),multimesh->data.ptr()); + glBindBuffer(GL_ARRAY_BUFFER,0); + + + } + + + + if (multimesh->size && multimesh->dirty_aabb) { + + AABB mesh_aabb; + + if (multimesh->mesh.is_valid()) { + mesh_aabb=mesh_get_aabb(multimesh->mesh,RID()); + } else { + mesh_aabb.size+=Vector3(0.001,0.001,0.001); + } + + int stride=multimesh->color_floats+multimesh->xform_floats; + int count = multimesh->data.size(); + float *data=multimesh->data.ptr(); + + AABB aabb; + + if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) { + + for(int i=0;iaabb=aabb; + } + multimesh->dirty_aabb=false; + multimesh->dirty_data=false; + + multimesh->instance_change_notify(); + + multimesh_update_list.remove(multimesh_update_list.first()); + } } /* IMMEDIATE API */ @@ -3957,6 +4373,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: inst = mesh_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_MULTIMESH: { + inst = multimesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_REFLECTION_PROBE: { inst = reflection_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -3988,6 +4408,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_MULTIMESH: { + inst = multimesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_REFLECTION_PROBE: { inst = reflection_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -4482,6 +4906,9 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return VS::INSTANCE_MESH; } + if (multimesh_owner.owns(p_rid)) { + return VS::INSTANCE_MULTIMESH; + } if (light_owner.owns(p_rid)) { return VS::INSTANCE_LIGHT; } @@ -4580,6 +5007,17 @@ bool RasterizerStorageGLES3::free(RID p_rid){ mesh_owner.free(p_rid); memdelete(mesh); + } else if (multimesh_owner.owns(p_rid)) { + + // delete the texture + MultiMesh *multimesh = multimesh_owner.get(p_rid); + + multimesh_allocate(p_rid,0,VS::MULTIMESH_TRANSFORM_2D,VS::MULTIMESH_COLOR_NONE); //frees multimesh + update_dirty_multimeshes(); + + multimesh_owner.free(p_rid); + memdelete(multimesh); + } else if (light_owner.owns(p_rid)) { // delete the texture diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b5eacacb4..c6712bd8e 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -482,6 +482,7 @@ public: uint32_t format; GLuint array_id; + GLuint instancing_array_id; GLuint vertex_id; GLuint index_id; @@ -591,20 +592,53 @@ public: /* MULTIMESH API */ + struct MultiMesh : public GeometryOwner { + RID mesh; + int size; + VS::MultimeshTransformFormat transform_format; + VS::MultimeshColorFormat color_format; + Vector data; + AABB aabb; + SelfList update_list; + GLuint buffer; + int visible_instances; + + int xform_floats; + int color_floats; + + bool dirty_aabb; + bool dirty_data; + + MultiMesh() : update_list(this) { + dirty_aabb=true; + dirty_data=true; + xform_floats=0; + color_floats=0; + visible_instances=-1; + size=0; + buffer=0; + transform_format=VS::MULTIMESH_TRANSFORM_2D; + color_format=VS::MULTIMESH_COLOR_NONE; + } + }; + + mutable RID_Owner multimesh_owner; + + SelfList::List multimesh_update_list; + + void update_dirty_multimeshes(); virtual RID multimesh_create(); - virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb=true); + virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format); virtual int multimesh_get_instance_count(RID p_multimesh) const; virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh); - virtual void multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb); virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform); virtual void multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform); virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color); virtual RID multimesh_get_mesh(RID p_multimesh) const; - virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const; virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const; virtual Matrix32 multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const; @@ -613,7 +647,7 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible); virtual int multimesh_get_visible_instances(RID p_multimesh) const; - virtual AABB multimesh_get_aabb(RID p_mesh) const; + virtual AABB multimesh_get_aabb(RID p_multimesh) const; /* IMMEDIATE API */ diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index f3dade9e5..c19853472 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -45,7 +45,7 @@ layout(location=6) in ivec4 bone_indices; // attrib:6 layout(location=7) in vec4 bone_weights; // attrib:7 #endif -#ifdef USE_ATTRIBUTE_INSTANCING +#ifdef USE_INSTANCING layout(location=8) in highp vec4 instance_xform0; layout(location=9) in highp vec4 instance_xform1; @@ -171,6 +171,10 @@ void main() { float binormalf = tangent_attrib.a; #endif +#if defined(ENABLE_COLOR_INTERP) + color_interp = color_attrib; +#endif + #ifdef USE_SKELETON @@ -191,6 +195,23 @@ void main() { #endif // USE_SKELETON1 +#ifdef USE_INSTANCING + + { + highp mat3x4 m=mat3x4(instance_xform0,instance_xform1,instance_xform2); + + vertex.xyz = vertex * m; + normal = vec4(normal,0.0) * m; +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) + tangent.xyz = vec4(tangent.xyz,0.0) * mn; +#endif + +#if defined(ENABLE_COLOR_INTERP) + color_interp*=instance_color; +#endif + } +#endif //USE_INSTANCING + #if !defined(SKIP_TRANSFORM_USED) vertex = modelview * vertex; @@ -207,9 +228,6 @@ void main() { -#if defined(ENABLE_COLOR_INTERP) - color_interp = color_attrib; -#endif #if defined(ENABLE_UV_INTERP) uv_interp = uv_attrib; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 0ca72eaa2..bd5eb0a4e 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -462,22 +462,6 @@ void Viewport::_notification(int p_what) { VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh,point_count); - if (point_count>0) { - AABB aabb; - - Transform t; - for(int i=0;imultimesh_instance_set_transform(contact_3d_debug_multimesh,i,t); - } - aabb.grow(aabb.get_longest_axis_size()*0.01); - VisualServer::get_singleton()->multimesh_set_custom_aabb(contact_3d_debug_multimesh,aabb); - } } diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index 0a005d8c5..8515cd28a 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -174,45 +174,13 @@ Color MultiMesh::get_instance_color(int p_instance) const { } -void MultiMesh::set_aabb(const AABB& p_aabb) { - aabb=p_aabb; - VisualServer::get_singleton()->multimesh_set_custom_aabb(multimesh,p_aabb); - - -} AABB MultiMesh::get_aabb() const { - return aabb; + return VisualServer::get_singleton()->multimesh_get_aabb(multimesh); } -void MultiMesh::generate_aabb() { - - - - ERR_EXPLAIN("Cannot generate AABB if mesh is null."); - ERR_FAIL_COND(mesh.is_null()); - - AABB base_aabb=mesh->get_aabb(); - - aabb=AABB(); - - int instance_count = get_instance_count(); - for(int i=0;imultimesh_create(); color_format=COLOR_NONE; - transform_format=TRANSFORM_NONE; + transform_format=TRANSFORM_2D; } MultiMesh::~MultiMesh() { diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h index be4ee38fc..5e28900c3 100644 --- a/scene/resources/multimesh.h +++ b/scene/resources/multimesh.h @@ -39,7 +39,6 @@ class MultiMesh : public Resource { public: enum TransformFormat { - TRANSFORM_NONE = VS::MULTIMESH_TRANSFORM_NONE, TRANSFORM_2D = VS::MULTIMESH_TRANSFORM_2D, TRANSFORM_3D = VS::MULTIMESH_TRANSFORM_3D }; @@ -50,7 +49,6 @@ public: COLOR_FLOAT = VS::MULTIMESH_COLOR_FLOAT, }; private: - AABB aabb; Ref mesh; RID multimesh; TransformFormat transform_format; @@ -87,11 +85,8 @@ public: void set_instance_color(int p_instance, const Color& p_color); Color get_instance_color(int p_instance) const; - void set_aabb(const AABB& p_aabb); virtual AABB get_aabb() const; - void generate_aabb(); - virtual RID get_rid() const; MultiMesh(); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0f70b036a..08d199572 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -261,17 +261,15 @@ public: virtual RID multimesh_create()=0; - virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb=true)=0; + virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format)=0; virtual int multimesh_get_instance_count(RID p_multimesh) const=0; virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh)=0; - virtual void multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb)=0; virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform)=0; virtual void multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform)=0; virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color)=0; virtual RID multimesh_get_mesh(RID p_multimesh) const=0; - virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const=0; virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const=0; virtual Matrix32 multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const=0; @@ -280,7 +278,7 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible)=0; virtual int multimesh_get_visible_instances(RID p_multimesh) const=0; - virtual AABB multimesh_get_aabb(RID p_mesh) const=0; + virtual AABB multimesh_get_aabb(RID p_multimesh) const=0; /* IMMEDIATE API */ diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 4e9110445..675e2d4ae 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -707,17 +707,16 @@ public: BIND0R(RID,multimesh_create) - BIND5(multimesh_allocate,RID,int,MultimeshTransformFormat,MultimeshColorFormat,bool) + BIND4(multimesh_allocate,RID,int,MultimeshTransformFormat,MultimeshColorFormat) BIND1RC(int,multimesh_get_instance_count,RID) BIND2(multimesh_set_mesh,RID,RID) - BIND2(multimesh_set_custom_aabb,RID,const AABB&) BIND3(multimesh_instance_set_transform,RID,int,const Transform&) BIND3(multimesh_instance_set_transform_2d,RID,int,const Matrix32& ) BIND3(multimesh_instance_set_color,RID,int,const Color&) BIND1RC(RID,multimesh_get_mesh,RID) - BIND1RC(AABB,multimesh_get_custom_aabb,RID) + BIND1RC(AABB,multimesh_get_aabb,RID) BIND2RC(Transform,multimesh_instance_get_transform,RID,int ) BIND2RC(Matrix32,multimesh_instance_get_transform_2d,RID,int) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 74d77c526..f25e5bc94 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -562,6 +562,11 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ InstanceGeometryData *geom = memnew( InstanceGeometryData ); instance->base_data=geom; } break; + case VS::INSTANCE_MULTIMESH: { + + InstanceGeometryData *geom = memnew( InstanceGeometryData ); + instance->base_data=geom; + } break; case VS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = memnew( InstanceReflectionProbeData ); @@ -764,8 +769,19 @@ void VisualServerScene::instance_attach_skeleton(RID p_instance,RID p_skeleton){ Instance *instance = instance_owner.get( p_instance ); ERR_FAIL_COND( !instance ); + if (instance->skeleton==p_skeleton) + return; + + if (instance->skeleton.is_valid()) { + VSG::storage->instance_remove_dependency(p_skeleton,instance); + } + instance->skeleton=p_skeleton; + if (instance->skeleton.is_valid()) { + VSG::storage->instance_add_dependency(p_skeleton,instance); + } + _instance_queue_update(instance,true); } @@ -1125,12 +1141,13 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { new_aabb = VSG::storage->mesh_get_aabb(p_instance->base,p_instance->skeleton); } break; -#if 0 + case VisualServer::INSTANCE_MULTIMESH: { - new_aabb = rasterizer->multimesh_get_aabb(p_instance->base); + new_aabb = VSG::storage->multimesh_get_aabb(p_instance->base); } break; +#if 0 case VisualServer::INSTANCE_IMMEDIATE: { new_aabb = rasterizer->immediate_get_aabb(p_instance->base); @@ -2238,39 +2255,64 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { can_cast_shadows=VSG::storage->material_casts_shadows(p_instance->material_override); } else { - RID mesh; - if (p_instance->base_type==VS::INSTANCE_MESH) { - mesh=p_instance->base; - } else if (p_instance->base_type==VS::INSTANCE_MULTIMESH) { - } + if (p_instance->base_type==VS::INSTANCE_MESH) { + RID mesh=p_instance->base; - if (mesh.is_valid()) { + if (mesh.is_valid()) { + bool cast_shadows=false; - bool cast_shadows=false; + for(int i=0;imaterials.size();i++) { - for(int i=0;imaterials.size();i++) { + RID mat = p_instance->materials[i].is_valid()?p_instance->materials[i]:VSG::storage->mesh_surface_get_material(mesh,i); - RID mat = p_instance->materials[i].is_valid()?p_instance->materials[i]:VSG::storage->mesh_surface_get_material(mesh,i); + if (!mat.is_valid()) { + cast_shadows=true; + break; + } - if (!mat.is_valid()) { - cast_shadows=true; - break; + if (VSG::storage->material_casts_shadows(mat)) { + cast_shadows=true; + break; + } } - if (VSG::storage->material_casts_shadows(mat)) { - cast_shadows=true; - break; + if (!cast_shadows) { + can_cast_shadows=false; } } - if (!cast_shadows) { - can_cast_shadows=false; + } else if (p_instance->base_type==VS::INSTANCE_MULTIMESH) { + RID mesh = VSG::storage->multimesh_get_mesh(p_instance->base); + if (mesh.is_valid()) { + bool cast_shadows=false; + + int sc = VSG::storage->mesh_get_surface_count(mesh); + for(int i=0;imesh_surface_get_material(mesh,i); + + if (!mat.is_valid()) { + cast_shadows=true; + break; + } + + if (VSG::storage->material_casts_shadows(mat)) { + cast_shadows=true; + break; + } + } + + if (!cast_shadows) { + can_cast_shadows=false; + } } } + + } if (can_cast_shadows!=geom->can_cast_shadows) { @@ -2335,9 +2377,9 @@ bool VisualServerScene::free(RID p_rid) { instance_set_scenario(p_rid,RID()); instance_set_base(p_rid,RID()); instance_geometry_set_material_override(p_rid,RID()); + instance_attach_skeleton(p_rid,RID()); - if (instance->skeleton.is_valid()) - instance_attach_skeleton(p_rid,RID()); + update_dirty_instances(); //in case something changed this instance_owner.free(p_rid); memdelete(instance); diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 267a87930..30d6b76b8 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1282,7 +1282,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector p for(int j=0;jget_val(); + multimesh->set_transform_format(MultiMesh::TRANSFORM_3D); + multimesh->set_color_format(MultiMesh::COLOR_NONE); multimesh->set_instance_count(instance_count); float _tilt_random = populate_tilt_random->get_val(); @@ -247,10 +249,10 @@ void MultiMeshEditor::_populate() { multimesh->set_instance_transform(i,xform); - multimesh->set_instance_color(i,Color(1,1,1,1)); + } - multimesh->generate_aabb(); + node->set_multimesh(multimesh); @@ -386,6 +388,7 @@ MultiMeshEditor::MultiMeshEditor() { populate_scale_random->set_min(0); populate_scale_random->set_max(1); populate_scale_random->set_val(0); + populate_scale_random->set_step(0.01); vbc->add_margin_child(TTR("Random Scale:"),populate_scale_random); @@ -393,6 +396,7 @@ MultiMeshEditor::MultiMeshEditor() { populate_scale->set_min(0.001); populate_scale->set_max(4096); populate_scale->set_val(1); + populate_scale->set_step(0.01); vbc->add_margin_child(TTR("Scale:"),populate_scale); -- cgit v1.2.3-70-g09d2 From 7cf8d75cf8c49d02a72eac1d5342808526fa54ef Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 23 Nov 2016 07:04:55 -0300 Subject: WIP immediates and proper buffers swapping --- drivers/gles3/rasterizer_gles3.cpp | 3 +- drivers/gles3/rasterizer_storage_gles3.cpp | 134 +++++++++++++++++++++++++++-- drivers/gles3/rasterizer_storage_gles3.h | 36 +++++++- drivers/gles3/shader_gles3.cpp | 3 +- servers/visual/rasterizer.h | 3 +- servers/visual/visual_server_raster.h | 1 - servers/visual/visual_server_scene.cpp | 25 ++++-- servers/visual_server.cpp | 4 + servers/visual_server.h | 2 +- 9 files changed, 185 insertions(+), 26 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index ebcedd5f0..904602870 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -276,8 +276,7 @@ void RasterizerGLES3::end_frame(){ canvas->draw_generic_textured_rect(Rect2(0,0,15,15),Rect2(0,0,1,1)); #endif - if (ContextGL::get_singleton()) - ContextGL::get_singleton()->swap_buffers(); + OS::get_singleton()->swap_buffers(); } void RasterizerGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 60cbbc902..a618953b8 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -3675,57 +3675,157 @@ void RasterizerStorageGLES3::update_dirty_multimeshes() { /* IMMEDIATE API */ -RID RasterizerStorageGLES3::immediate_create(){ - return RID(); +RID RasterizerStorageGLES3::immediate_create() { + + Immediate *im = memnew( Immediate ); + return immediate_owner.make_rid(im); + } -void RasterizerStorageGLES3::immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture){ + +void RasterizerStorageGLES3::immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture){ + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + + Immediate::Chunk ic; + ic.texture=p_texture; + ic.primitive=p_rimitive; + im->chunks.push_back(ic); + im->mask=0; + im->building=true; } void RasterizerStorageGLES3::immediate_vertex(RID p_immediate,const Vector3& p_vertex){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); -} -void RasterizerStorageGLES3::immediate_vertex_2d(RID p_immediate,const Vector3& p_vertex){ + Immediate::Chunk *c = &im->chunks.back()->get(); + + + if (c->vertices.empty() && im->chunks.size()==1) { + im->aabb.pos=p_vertex; + im->aabb.size=Vector3(); + } else { + im->aabb.expand_to(p_vertex); + } + + if (im->mask&VS::ARRAY_FORMAT_NORMAL) + c->normals.push_back(chunk_normal); + if (im->mask&VS::ARRAY_FORMAT_TANGENT) + c->tangents.push_back(chunk_tangent); + if (im->mask&VS::ARRAY_FORMAT_COLOR) + c->colors.push_back(chunk_color); + if (im->mask&VS::ARRAY_FORMAT_TEX_UV) + c->uvs.push_back(chunk_uv); + if (im->mask&VS::ARRAY_FORMAT_TEX_UV2) + c->uvs2.push_back(chunk_uv2); + im->mask|=VS::ARRAY_FORMAT_VERTEX; + c->vertices.push_back(p_vertex); } + + void RasterizerStorageGLES3::immediate_normal(RID p_immediate,const Vector3& p_normal){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_NORMAL; + chunk_normal=p_normal; } void RasterizerStorageGLES3::immediate_tangent(RID p_immediate,const Plane& p_tangent){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TANGENT; + chunk_tangent=p_tangent; } void RasterizerStorageGLES3::immediate_color(RID p_immediate,const Color& p_color){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_COLOR; + chunk_color=p_color; } void RasterizerStorageGLES3::immediate_uv(RID p_immediate,const Vector2& tex_uv){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TEX_UV; + chunk_uv=tex_uv; } void RasterizerStorageGLES3::immediate_uv2(RID p_immediate,const Vector2& tex_uv){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask|=VS::ARRAY_FORMAT_TEX_UV2; + chunk_uv2=tex_uv; } + void RasterizerStorageGLES3::immediate_end(RID p_immediate){ + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->building=false; + + im->instance_change_notify(); } -void RasterizerStorageGLES3::immediate_clear(RID p_immediate){ +void RasterizerStorageGLES3::immediate_clear(RID p_immediate) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + im->chunks.clear(); + im->instance_change_notify(); } -void RasterizerStorageGLES3::immediate_set_material(RID p_immediate,RID p_material){ +AABB RasterizerStorageGLES3::immediate_get_aabb(RID p_immediate) const { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,AABB()); + return im->aabb; } -RID RasterizerStorageGLES3::immediate_get_material(RID p_immediate) const{ - return RID(); +void RasterizerStorageGLES3::immediate_set_material(RID p_immediate,RID p_material) { + + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + im->material=p_material; + im->instance_material_change_notify(); + +} + +RID RasterizerStorageGLES3::immediate_get_material(RID p_immediate) const { + + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im,RID()); + return im->material; + } /* SKELETON API */ @@ -4417,6 +4517,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: inst = multimesh_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_IMMEDIATE: { + inst = immediate_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_REFLECTION_PROBE: { inst = reflection_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -4452,6 +4556,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce inst = multimesh_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_IMMEDIATE: { + inst = immediate_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_REFLECTION_PROBE: { inst = reflection_probe_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -4949,6 +5057,9 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { if (multimesh_owner.owns(p_rid)) { return VS::INSTANCE_MULTIMESH; } + if (immediate_owner.owns(p_rid)) { + return VS::INSTANCE_IMMEDIATE; + } if (light_owner.owns(p_rid)) { return VS::INSTANCE_LIGHT; } @@ -5057,7 +5168,12 @@ bool RasterizerStorageGLES3::free(RID p_rid){ multimesh_owner.free(p_rid); memdelete(multimesh); + } else if (immediate_owner.owns(p_rid)) { + + Immediate *immediate = immediate_owner.get(p_rid); + immediate_owner.free(p_rid); + memdelete(immediate); } else if (light_owner.owns(p_rid)) { // delete the texture diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index c6712bd8e..623962bf6 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -651,10 +651,41 @@ public: /* IMMEDIATE API */ + struct Immediate : public Geometry { + + struct Chunk { + + RID texture; + VS::PrimitiveType primitive; + Vector vertices; + Vector normals; + Vector tangents; + Vector colors; + Vector uvs; + Vector uvs2; + }; + + List chunks; + bool building; + int mask; + AABB aabb; + + Immediate() { type=GEOMETRY_IMMEDIATE; building=false;} + + }; + + Vector3 chunk_vertex; + Vector3 chunk_normal; + Plane chunk_tangent; + Color chunk_color; + Vector2 chunk_uv; + Vector2 chunk_uv2; + + mutable RID_Owner immediate_owner; + virtual RID immediate_create(); virtual void immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture=RID()); - virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex); - virtual void immediate_vertex_2d(RID p_immediate,const Vector3& p_vertex); + virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex); virtual void immediate_normal(RID p_immediate,const Vector3& p_normal); virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent); virtual void immediate_color(RID p_immediate,const Color& p_color); @@ -664,6 +695,7 @@ public: virtual void immediate_clear(RID p_immediate); virtual void immediate_set_material(RID p_immediate,RID p_material); virtual RID immediate_get_material(RID p_immediate) const; + virtual AABB immediate_get_aabb(RID p_immediate) const; /* SKELETON API */ diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index e906f9a79..78f35c493 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -222,9 +222,8 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() { Vector strings; #ifdef GLES_OVER_GL strings.push_back("#version 330\n"); - //strings.push_back("#version 300 es\n"); #else - strings.push_back("#version 300 es\n"); //ATI requieres this before anything + strings.push_back("#version 300 es\n"); #endif diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 08d199572..5f536b8fd 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -285,7 +285,6 @@ public: virtual RID immediate_create()=0; virtual void immediate_begin(RID p_immediate,VS::PrimitiveType p_rimitive,RID p_texture=RID())=0; virtual void immediate_vertex(RID p_immediate,const Vector3& p_vertex)=0; - virtual void immediate_vertex_2d(RID p_immediate,const Vector3& p_vertex)=0; virtual void immediate_normal(RID p_immediate,const Vector3& p_normal)=0; virtual void immediate_tangent(RID p_immediate,const Plane& p_tangent)=0; virtual void immediate_color(RID p_immediate,const Color& p_color)=0; @@ -295,6 +294,8 @@ public: virtual void immediate_clear(RID p_immediate)=0; virtual void immediate_set_material(RID p_immediate,RID p_material)=0; virtual RID immediate_get_material(RID p_immediate) const=0; + virtual AABB immediate_get_aabb(RID p_immediate) const=0; + /* SKELETON API */ diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 675e2d4ae..c3afadb39 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -731,7 +731,6 @@ public: BIND0R(RID,immediate_create) BIND3(immediate_begin,RID,PrimitiveType,RID) BIND2(immediate_vertex,RID,const Vector3&) - BIND2(immediate_vertex_2d,RID,const Vector3&) BIND2(immediate_normal,RID,const Vector3&) BIND2(immediate_tangent,RID,const Plane&) BIND2(immediate_color,RID,const Color&) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index f25e5bc94..2439eacd7 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -557,12 +557,9 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ instance->base_data=light; } break; - case VS::INSTANCE_MESH: { - - InstanceGeometryData *geom = memnew( InstanceGeometryData ); - instance->base_data=geom; - } break; - case VS::INSTANCE_MULTIMESH: { + case VS::INSTANCE_MESH: + case VS::INSTANCE_MULTIMESH: + case VS::INSTANCE_IMMEDIATE: { InstanceGeometryData *geom = memnew( InstanceGeometryData ); instance->base_data=geom; @@ -1147,13 +1144,14 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { new_aabb = VSG::storage->multimesh_get_aabb(p_instance->base); } break; -#if 0 case VisualServer::INSTANCE_IMMEDIATE: { - new_aabb = rasterizer->immediate_get_aabb(p_instance->base); + new_aabb = VSG::storage->immediate_get_aabb(p_instance->base); } break; +#if 0 + case VisualServer::INSTANCE_PARTICLES: { new_aabb = rasterizer->particles_get_aabb(p_instance->base); @@ -2309,6 +2307,17 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { can_cast_shadows=false; } } + } else if (p_instance->base_type==VS::INSTANCE_IMMEDIATE) { + + RID mat = VSG::storage->immediate_get_material(p_instance->base); + + if (!mat.is_valid() || VSG::storage->material_casts_shadows(mat)) { + can_cast_shadows=true; + } else { + can_cast_shadows=false; + } + + } diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 30d6b76b8..27b08c4c5 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1648,6 +1648,10 @@ void VisualServer::mesh_add_surface_from_planes( RID p_mesh, const DVector(e->geometry); - glBindVertexArray(s->array_id); // everything is so easy nowadays + + if (s->morph_targets.size() && e->instance->morph_values.size()) { + //blend shapes, use transform feedback + storage->mesh_render_blend_shapes(s,e->instance->morph_values.ptr()); + //rebind shader + state.scene_shader.bind(); + } else { + + glBindVertexArray(s->array_id); // everything is so easy nowadays + } } break; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index a618953b8..559f733e4 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2274,8 +2274,8 @@ void RasterizerStorageGLES3::_update_material(Material* material) { material->can_cast_shadow_cache=can_cast_shadow; material->is_animated_cache=is_animated; - for(Map::Element *E=material->instantiable_owners.front();E;E=E->next()) { - E->key()->instance_material_change_notify(); + for(Map::Element *E=material->geometry_owners.front();E;E=E->next()) { + E->key()->material_changed_notify(); } for(Map::Element *E=material->instance_owners.front();E;E=E->next()) { @@ -2379,32 +2379,32 @@ void RasterizerStorageGLES3::_update_material(Material* material) { } -void RasterizerStorageGLES3::_material_add_instantiable(RID p_material,Instantiable *p_instantiable) { +void RasterizerStorageGLES3::_material_add_geometry(RID p_material,Geometry *p_geometry) { Material * material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); - Map::Element *I = material->instantiable_owners.find(p_instantiable); + Map::Element *I = material->geometry_owners.find(p_geometry); if (I) { I->get()++; } else { - material->instantiable_owners[p_instantiable]=1; + material->geometry_owners[p_geometry]=1; } } -void RasterizerStorageGLES3::_material_remove_instantiable(RID p_material,Instantiable *p_instantiable) { +void RasterizerStorageGLES3::_material_remove_geometry(RID p_material,Geometry *p_geometry) { Material * material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); - Map::Element *I = material->instantiable_owners.find(p_instantiable); + Map::Element *I = material->geometry_owners.find(p_geometry); ERR_FAIL_COND(!I); I->get()--; if (I->get()==0) { - material->instantiable_owners.erase(I); + material->geometry_owners.erase(I); } } @@ -2446,18 +2446,15 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P bool has_morph = p_blend_shapes.size(); - Surface::Attrib attribs[VS::ARRAY_MAX],morph_attribs[VS::ARRAY_MAX]; + Surface::Attrib attribs[VS::ARRAY_MAX]; int stride=0; - int morph_stride=0; for(int i=0;iattribs[i]=attribs[i]; - surface->morph_attribs[i]=morph_attribs[i]; } { @@ -2763,12 +2701,11 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P glGenVertexArrays(1,&surface->array_id); glBindVertexArray(surface->array_id); glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); - } else { + } else if (i==1) { //for instancing draw (can be changed and no one cares) glGenVertexArrays(1,&surface->instancing_array_id); glBindVertexArray(surface->instancing_array_id); glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); - } @@ -2816,17 +2753,17 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P glBindVertexArray(mt.array_id); glBindBuffer(GL_ARRAY_BUFFER,mt.vertex_id); - for(int i=0;isurfaces[p_surface]->material.is_valid()) { - _material_remove_instantiable(mesh->surfaces[p_surface]->material,mesh); + _material_remove_geometry(mesh->surfaces[p_surface]->material,mesh->surfaces[p_surface]); } mesh->surfaces[p_surface]->material=p_material; if (mesh->surfaces[p_surface]->material.is_valid()) { - _material_add_instantiable(mesh->surfaces[p_surface]->material,mesh); + _material_add_geometry(mesh->surfaces[p_surface]->material,mesh->surfaces[p_surface]); } mesh->instance_material_change_notify(); @@ -3067,7 +3004,7 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ Surface *surface = mesh->surfaces[p_surface]; if (surface->material.is_valid()) { - _material_remove_instantiable(surface->material,mesh); + _material_remove_geometry(surface->material,mesh->surfaces[p_surface]); } glDeleteBuffers(1,&surface->vertex_id); @@ -3241,6 +3178,227 @@ void RasterizerStorageGLES3::mesh_clear(RID p_mesh){ } } +void RasterizerStorageGLES3::mesh_render_blend_shapes(Surface *s, float *p_weights) { + + glBindVertexArray(s->array_id); + + BlendShapeShaderGLES3::Conditionals cond[VS::ARRAY_MAX-1]={ + BlendShapeShaderGLES3::ENABLE_NORMAL, //will be ignored + BlendShapeShaderGLES3::ENABLE_NORMAL, + BlendShapeShaderGLES3::ENABLE_TANGENT, + BlendShapeShaderGLES3::ENABLE_COLOR, + BlendShapeShaderGLES3::ENABLE_UV, + BlendShapeShaderGLES3::ENABLE_UV2, + BlendShapeShaderGLES3::ENABLE_SKELETON, + BlendShapeShaderGLES3::ENABLE_SKELETON, + }; + + int stride=0; + + if (s->format&VS::ARRAY_FLAG_USE_2D_VERTICES) { + stride=2*4; + } else { + stride=3*4; + } + + static const int sizes[VS::ARRAY_MAX-1]={ + 3*4, + 3*4, + 4*4, + 4*4, + 2*4, + 2*4, + 4*4, + 4*4 + }; + + for(int i=1;iformat&(1<format&(1<morph_targets.size(); + + if (s->mesh->morph_target_mode==VS::MORPH_MODE_NORMALIZED) { + + for(int i=0;iformat&VS::ARRAY_FLAG_USE_2D_VERTICES); //use 2D vertices if needed + + shaders.blend_shapes.bind(); + + shaders.blend_shapes.set_uniform(BlendShapeShaderGLES3::BLEND_AMOUNT,base_weight); + glEnable(GL_RASTERIZER_DISCARD); + + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, resources.transform_feedback_buffers[0]); + glBeginTransformFeedback(GL_POINTS); + glDrawArrays(GL_POINTS,0,s->array_len); + glEndTransformFeedback(); + + + shaders.blend_shapes.set_conditional(BlendShapeShaderGLES3::ENABLE_BLEND,true); //first pass does not blend + shaders.blend_shapes.bind(); + + for(int ti=0;timorph_targets[ti].array_id); + glBindBuffer(GL_ARRAY_BUFFER, resources.transform_feedback_buffers[0]); + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, resources.transform_feedback_buffers[1]); + + shaders.blend_shapes.set_uniform(BlendShapeShaderGLES3::BLEND_AMOUNT,weight); + + int ofs=0; + for(int i=0;iformat&(1<format&VS::ARRAY_FLAG_USE_2D_VERTICES) { + glVertexAttribPointer(i+8,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=2*4; + } else { + glVertexAttribPointer(i+8,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=3*4; + } + } break; + case VS::ARRAY_NORMAL: { + glVertexAttribPointer(i+8,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=3*4; + } break; + case VS::ARRAY_TANGENT: { + glVertexAttribPointer(i+8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + case VS::ARRAY_COLOR: { + glVertexAttribPointer(i+8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + case VS::ARRAY_TEX_UV: { + glVertexAttribPointer(i+8,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=2*4; + + } break; + case VS::ARRAY_TEX_UV2: { + glVertexAttribPointer(i+8,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=2*4; + + } break; + case VS::ARRAY_BONES: { + glVertexAttribIPointer(i+8,4,GL_UNSIGNED_INT,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + case VS::ARRAY_WEIGHTS: { + glVertexAttribPointer(i+8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + } + + } else { + glDisableVertexAttribArray(i+8); + } + } + + glBeginTransformFeedback(GL_POINTS); + glDrawArrays(GL_POINTS,0,s->array_len); + glEndTransformFeedback(); + + + SWAP(resources.transform_feedback_buffers[0],resources.transform_feedback_buffers[1]); + + } + + glDisable(GL_RASTERIZER_DISCARD); + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0); + + + glBindVertexArray(resources.transform_feedback_array); + glBindBuffer(GL_ARRAY_BUFFER, resources.transform_feedback_buffers[0]); + + int ofs=0; + for(int i=0;iformat&(1<format&VS::ARRAY_FLAG_USE_2D_VERTICES) { + glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=2*4; + } else { + glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=3*4; + } + } break; + case VS::ARRAY_NORMAL: { + glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=3*4; + } break; + case VS::ARRAY_TANGENT: { + glVertexAttribPointer(i,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + case VS::ARRAY_COLOR: { + glVertexAttribPointer(i,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + case VS::ARRAY_TEX_UV: { + glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=2*4; + + } break; + case VS::ARRAY_TEX_UV2: { + glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=2*4; + + } break; + case VS::ARRAY_BONES: { + glVertexAttribIPointer(i,4,GL_UNSIGNED_INT,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + case VS::ARRAY_WEIGHTS: { + glVertexAttribPointer(i,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)0)+ofs); + ofs+=4*4; + + } break; + } + + } else { + glDisableVertexAttribArray(i); + } + } + + if (s->index_array_len) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,s->index_id); + } + +} + /* MULTIMESH API */ @@ -3896,7 +4054,6 @@ void RasterizerStorageGLES3::skeleton_allocate(RID p_skeleton,int p_bones,bool p skeleton_update_list.add(&skeleton->update_list); } - skeleton->instance_change_notify(); } @@ -4017,7 +4174,10 @@ void RasterizerStorageGLES3::update_dirty_skeletons() { glBufferSubData(GL_UNIFORM_BUFFER,0,skeleton->bones.size()*sizeof(float),skeleton->bones.ptr()); glBindBuffer(GL_UNIFORM_BUFFER, 0); } - skeleton->instance_change_notify(); + + for (Set::Element *E=skeleton->instances.front();E;E=E->next()) { + E->get()->base_changed(); + } skeleton_update_list.remove(skeleton_update_list.first()); } @@ -4505,6 +4665,23 @@ void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color } +void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + skeleton->instances.insert(p_instance); +} + +void RasterizerStorageGLES3::instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + skeleton->instances.erase(p_instance); +} + + void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance) { Instantiable *inst=NULL; @@ -4530,9 +4707,6 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: ERR_FAIL_COND(!inst); } break; default: { - if (skeleton_owner.owns(p_base)) { - inst=skeleton_owner.getornull(p_base); - } if (!inst) { ERR_FAIL(); } @@ -4550,7 +4724,6 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce case VS::INSTANCE_MESH: { inst = mesh_owner.getornull(p_base); ERR_FAIL_COND(!inst); - } break; case VS::INSTANCE_MULTIMESH: { inst = multimesh_owner.getornull(p_base); @@ -4569,9 +4742,7 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce ERR_FAIL_COND(!inst); } break; default: { - if (skeleton_owner.owns(p_base)) { - inst=skeleton_owner.getornull(p_base); - } + if (!inst) { ERR_FAIL(); } @@ -5134,6 +5305,26 @@ bool RasterizerStorageGLES3::free(RID p_rid){ glDeleteBuffers(1,&material->ubo_id); } + //remove from owners + for (Map::Element *E=material->geometry_owners.front();E;E=E->next()) { + + Geometry *g = E->key(); + g->material=RID(); + } + for (Map::Element *E=material->instance_owners.front();E;E=E->next()) { + RasterizerScene::InstanceBase*ins=E->key(); + if (ins->material_override==p_rid) { + ins->material_override=RID(); + } + + for(int i=0;imaterials.size();i++) { + if (ins->materials[i]==p_rid) { + ins->materials[i]=RID(); + } + } + + } + material_owner.free(p_rid); memdelete(material); @@ -5144,6 +5335,11 @@ bool RasterizerStorageGLES3::free(RID p_rid){ if (skeleton->update_list.in_list()) { skeleton_update_list.remove(&skeleton->update_list); } + + for (Set::Element *E=skeleton->instances.front();E;E=E->next()) { + E->get()->skeleton=RID(); + } + skeleton_allocate(p_rid,0,false); skeleton_owner.free(p_rid); memdelete(skeleton); @@ -5370,6 +5566,23 @@ void RasterizerStorageGLES3::initialize() { glBindBuffer(GL_ARRAY_BUFFER,0); //unbind } + + { + //transform feedback buffers + uint32_t xf_feedback_size = GLOBAL_DEF("rendering/gles3/blend_shape_max_buffer_size_kb",4096); + for(int i=0;i<2;i++) { + + glGenBuffers(1,&resources.transform_feedback_buffers[i]); + glBindBuffer(GL_ARRAY_BUFFER,resources.transform_feedback_buffers[i]); + glBufferData(GL_ARRAY_BUFFER,xf_feedback_size*1024,NULL,GL_STREAM_DRAW); + } + + shaders.blend_shapes.init();; + + glGenVertexArrays(1,&resources.transform_feedback_array); + + } + shaders.cubemap_filter.init(); glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 623962bf6..361e738af 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -6,6 +6,7 @@ #include "shader_gles3.h" #include "shaders/copy.glsl.h" #include "shaders/canvas.glsl.h" +#include "shaders/blend_shape.glsl.h" #include "shaders/cubemap_filter.glsl.h" #include "self_list.h" #include "shader_compiler_gles3.h" @@ -65,6 +66,8 @@ public: CubemapFilterShaderGLES3 cubemap_filter; + BlendShapeShaderGLES3 blend_shapes; + ShaderCompilerGLES3::IdentifierActions actions_canvas; ShaderCompilerGLES3::IdentifierActions actions_scene; } shaders; @@ -79,6 +82,9 @@ public: GLuint quadie; GLuint quadie_array; + GLuint transform_feedback_buffers[2]; + GLuint transform_feedback_array; + } resources; struct Info { @@ -133,8 +139,33 @@ public: } }; + struct GeometryOwner : public Instantiable { + + virtual ~GeometryOwner() {} + }; + struct Geometry : Instantiable { + + enum Type { + GEOMETRY_INVALID, + GEOMETRY_SURFACE, + GEOMETRY_IMMEDIATE, + GEOMETRY_MULTISURFACE, + }; + + + Type type; + RID material; + uint64_t last_pass; + uint32_t index; + virtual void material_changed_notify() {} + Geometry() { + last_pass=0; + index=0; + } + + }; @@ -384,7 +415,7 @@ public: uint32_t index; uint64_t last_pass; - Map instantiable_owners; + Map geometry_owners; Map instance_owners; bool can_cast_shadow_cache; @@ -404,8 +435,8 @@ public: mutable SelfList::List _material_dirty_list; void _material_make_dirty(Material *p_material) const; - void _material_add_instantiable(RID p_material,Instantiable *p_instantiable); - void _material_remove_instantiable(RID p_material, Instantiable *p_instantiable); + void _material_add_geometry(RID p_material,Geometry *p_instantiable); + void _material_remove_geometry(RID p_material, Geometry *p_instantiable); mutable RID_Owner material_owner; @@ -433,31 +464,9 @@ public: /* MESH API */ - struct Geometry : Instantiable { - - enum Type { - GEOMETRY_INVALID, - GEOMETRY_SURFACE, - GEOMETRY_IMMEDIATE, - GEOMETRY_MULTISURFACE, - }; - - Type type; - RID material; - uint64_t last_pass; - uint32_t index; - Geometry() { - last_pass=0; - index=0; - } - }; - struct GeometryOwner : public Instantiable { - - virtual ~GeometryOwner() {} - }; struct Mesh; struct Surface : public Geometry { @@ -475,7 +484,7 @@ public: }; Attrib attribs[VS::ARRAY_MAX]; - Attrib morph_attribs[VS::ARRAY_MAX]; + Mesh *mesh; @@ -512,6 +521,10 @@ public: bool active; + virtual void material_changed_notify() { + mesh->instance_material_change_notify(); + } + Surface() { array_byte_size=0; @@ -590,6 +603,8 @@ public: virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const; virtual void mesh_clear(RID p_mesh); + void mesh_render_blend_shapes(Surface *s, float *p_weights); + /* MULTIMESH API */ struct MultiMesh : public GeometryOwner { @@ -699,12 +714,13 @@ public: /* SKELETON API */ - struct Skeleton : Instantiable { + struct Skeleton : RID_Data { int size; bool use_2d; Vector bones; //4x3 or 4x2 depending on what is needed GLuint ubo; SelfList update_list; + Set instances; //instances using skeleton Skeleton() : update_list(this) { size=0; @@ -843,6 +859,8 @@ public: virtual void portal_set_disable_distance(RID p_portal, float p_distance); virtual void portal_set_disabled_color(RID p_portal, const Color& p_color); + virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance); + virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance); virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance); virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance); diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 78f35c493..d29927b13 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -502,6 +502,25 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() { glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name ); } + //if feedback exists, set it up + + if (feedback_count) { + Vector feedback; + for(int i=0;imesh_add_surface_from_arrays(mesh,(VisualServer::PrimitiveType)p_primitive, p_arrays,p_blend_shapes); + VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh,(VisualServer::PrimitiveType)p_primitive, p_arrays,p_blend_shapes,p_flags); surfaces.push_back(s); @@ -1024,7 +1024,7 @@ void Mesh::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_morph_target_mode","mode"),&Mesh::set_morph_target_mode); ObjectTypeDB::bind_method(_MD("get_morph_target_mode"),&Mesh::get_morph_target_mode); - ObjectTypeDB::bind_method(_MD("add_surface_from_arrays","primitive","arrays","blend_shapes"),&Mesh::add_surface_from_arrays,DEFVAL(Array())); + ObjectTypeDB::bind_method(_MD("add_surface_from_arrays","primitive","arrays","blend_shapes","compress_flags"),&Mesh::add_surface_from_arrays,DEFVAL(Array()),DEFVAL(ARRAY_COMPRESS_DEFAULT)); ObjectTypeDB::bind_method(_MD("get_surface_count"),&Mesh::get_surface_count); ObjectTypeDB::bind_method(_MD("surface_remove","surf_idx"),&Mesh::surface_remove); ObjectTypeDB::bind_method(_MD("surface_get_array_len","surf_idx"),&Mesh::surface_get_array_len); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 2b28f1187..b671d8c3b 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -77,6 +77,22 @@ public: ARRAY_FORMAT_WEIGHTS=1<& p_array,int p_vertex_count,const DVector& p_index_array,int p_index_count,const AABB& p_aabb,const Vector >& p_blend_shapes=Vector >(),const Vector& p_bone_aabbs=Vector()); Array surface_get_arrays(int p_surface) const; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 6f08d6922..8e6175fa5 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -355,7 +355,30 @@ Ref SurfaceTool::commit(const Ref& p_existing) { w=DVector::Write(); a[i]=array; } break; - case Mesh::ARRAY_FORMAT_BONES: + case Mesh::ARRAY_FORMAT_BONES: { + + + DVector array; + array.resize(varr_len*4); + DVector::Write w = array.write(); + + int idx=0; + for(List< Vertex >::Element *E=vertex_array.front();E;E=E->next(),idx+=4) { + + const Vertex &v=E->get(); + + ERR_CONTINUE( v.bones.size()!=4 ); + + for(int j=0;j<4;j++) { + w[idx+j]=v.bones[j]; + } + + } + + w=DVector::Write(); + a[i]=array; + + } break; case Mesh::ARRAY_FORMAT_WEIGHTS: { @@ -367,18 +390,11 @@ Ref SurfaceTool::commit(const Ref& p_existing) { for(List< Vertex >::Element *E=vertex_array.front();E;E=E->next(),idx+=4) { const Vertex &v=E->get(); + ERR_CONTINUE( v.weights.size()!=4 ); for(int j=0;j<4;j++) { - switch(i) { - case Mesh::ARRAY_WEIGHTS: { - ERR_CONTINUE( v.weights.size()!=4 ); - w[idx+j]=v.weights[j]; - } break; - case Mesh::ARRAY_BONES: { - ERR_CONTINUE( v.bones.size()!=4 ); - w[idx+j]=v.bones[j]; - } break; - } + + w[idx+j]=v.weights[j]; } } diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 5f536b8fd..21cf391af 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -380,7 +380,8 @@ public: virtual void portal_set_disable_distance(RID p_portal, float p_distance)=0; virtual void portal_set_disabled_color(RID p_portal, const Color& p_color)=0; - + virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance)=0; + virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance)=0; virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0; virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0; diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 2439eacd7..0f7dabcc1 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -738,13 +738,25 @@ void VisualServerScene::instance_attach_object_instance_ID(RID p_instance,Object } void VisualServerScene::instance_set_morph_target_weight(RID p_instance,int p_shape, float p_weight){ + Instance *instance = instance_owner.get( p_instance ); + ERR_FAIL_COND( !instance ); + + if (instance->update_item.in_list()) { + _update_dirty_instance(instance); + } + + ERR_FAIL_INDEX(p_shape,instance->morph_values.size()); + instance->morph_values[p_shape]=p_weight; } + void VisualServerScene::instance_set_surface_material(RID p_instance,int p_surface, RID p_material){ Instance *instance = instance_owner.get( p_instance ); ERR_FAIL_COND( !instance ); - _update_dirty_instance(instance); + if (instance->update_item.in_list()) { + _update_dirty_instance(instance); + } ERR_FAIL_INDEX(p_surface,instance->materials.size()); @@ -770,13 +782,13 @@ void VisualServerScene::instance_attach_skeleton(RID p_instance,RID p_skeleton){ return; if (instance->skeleton.is_valid()) { - VSG::storage->instance_remove_dependency(p_skeleton,instance); + VSG::storage->instance_remove_skeleton(p_skeleton,instance); } instance->skeleton=p_skeleton; if (instance->skeleton.is_valid()) { - VSG::storage->instance_add_dependency(p_skeleton,instance); + VSG::storage->instance_add_skeleton(p_skeleton,instance); } _instance_queue_update(instance,true); @@ -2227,6 +2239,7 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (p_instance->update_aabb) _update_instance_aabb(p_instance); + if (p_instance->update_materials) { if (p_instance->base_type==VS::INSTANCE_MESH) { @@ -2239,6 +2252,14 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { } } p_instance->materials.resize(new_mat_count); + + int new_morph_count = VSG::storage->mesh_get_morph_target_count(p_instance->base); + if (new_morph_count!=p_instance->morph_values.size()) { + p_instance->morph_values.resize(new_morph_count); + for(int i=0;imorph_values[i]=0; + } + } } if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 27b08c4c5..ac894f128 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -709,7 +709,7 @@ Error VisualServer::_surface_set_data(Array p_arrays,uint32_t p_format,uint32_t } break; case VS::ARRAY_BONES: { - ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::REAL_ARRAY, ERR_INVALID_PARAMETER ); + ERR_FAIL_COND_V( p_arrays[ai].get_type() != Variant::INT_ARRAY, ERR_INVALID_PARAMETER ); DVector array = p_arrays[ai]; @@ -912,7 +912,7 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh,PrimitiveType p_primi bsformat|=(1< noindex; AABB laabb; - Error err = _surface_set_data(p_blend_shapes[i],format&~ARRAY_FORMAT_INDEX,offsets,total_elem_size,vertex_array,array_len,noindex,0,laabb,bone_aabb); + Error err = _surface_set_data(p_blend_shapes[i],format&~ARRAY_FORMAT_INDEX,offsets,total_elem_size,vertex_array_shape,array_len,noindex,0,laabb,bone_aabb); aabb.merge_with(laabb); if (err) { ERR_EXPLAIN("Invalid blend shape array format for surface"); @@ -1194,9 +1194,9 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector p case VS::ARRAY_BONES: { if (p_format&ARRAY_FLAG_USE_16_BIT_BONES) { - elem_size=sizeof(uint32_t); - } else { elem_size=sizeof(uint16_t)*4; + } else { + elem_size=sizeof(uint32_t); } } break; @@ -1487,7 +1487,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector p DVector::Write w = arr.write(); for(int j=0;j& p_mesh,const Map& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector &bone_remap, const Collada::SkinControllerData *p_skin_data, const Collada::MorphControllerData *p_morph_data,Vector > p_morph_meshes=Vector >()); + Error _create_mesh_surfaces(bool p_optimize, Ref& p_mesh, const Map& p_material_map, const Collada::MeshData &meshdata, const Transform& p_local_xform, const Vector &bone_remap, const Collada::SkinControllerData *p_skin_data, const Collada::MorphControllerData *p_morph_data, Vector > p_morph_meshes=Vector >(), bool p_for_morph=false); Error load(const String& p_path, int p_flags, bool p_force_make_tangents=false); void _fix_param_animation_tracks(); void create_animation(int p_clip,bool p_make_tracks_in_all_bones); @@ -597,7 +597,7 @@ static void _generate_tangents_and_binormals(const DVector& p_indices,const } } -Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref& p_mesh,const Map& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector &bone_remap, const Collada::SkinControllerData *skin_controller, const Collada::MorphControllerData *p_morph_data,Vector > p_morph_meshes) { +Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref& p_mesh,const Map& p_material_map,const Collada::MeshData &meshdata,const Transform& p_local_xform,const Vector &bone_remap, const Collada::SkinControllerData *skin_controller, const Collada::MorphControllerData *p_morph_data,Vector > p_morph_meshes,bool p_for_morph) { bool local_xform_mirror=p_local_xform.basis.determinant() < 0; @@ -1072,7 +1072,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref& p_mesh,con DVector final_color_array; DVector final_uv_array; DVector final_uv2_array; - DVector final_bone_array; + DVector final_bone_array; DVector final_weight_array; uint32_t final_format=0; @@ -1223,12 +1223,12 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref& p_mesh,con if (has_weights) { DVector weightarray; - DVector bonearray; + DVector bonearray; weightarray.resize(vertex_array.size()*4); DVector::Write weightarrayw = weightarray.write(); bonearray.resize(vertex_array.size()*4); - DVector::Write bonearrayw = bonearray.write(); + DVector::Write bonearrayw = bonearray.write(); for(int k=0;k& p_mesh,con if (l& p_mesh,con } weightarrayw = DVector::Write(); - bonearrayw = DVector::Write(); + bonearrayw = DVector::Write(); final_weight_array = weightarray; final_bone_array = bonearray; @@ -1461,14 +1461,20 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref& p_mesh,con // print_line("want surface "+itos(mi)+" has "+itos(p_morph_meshes[mi]->get_surface_count())); Array a = p_morph_meshes[mi]->surface_get_arrays(surface); - a[Mesh::ARRAY_BONES]=Variant(); - a[Mesh::ARRAY_WEIGHTS]=Variant(); + //add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not) + + if (final_weight_array.size()) + a[Mesh::ARRAY_WEIGHTS]=final_weight_array; + if (final_bone_array.size()) + a[Mesh::ARRAY_BONES]=final_bone_array; + a[Mesh::ARRAY_INDEX]=Variant(); //a.resize(Mesh::ARRAY_MAX); //no need for index mr.push_back(a); } - p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,d,mr); + + p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,d,mr,p_for_morph?0:Mesh::ARRAY_COMPRESS_DEFAULT); if (material.is_valid()) { p_mesh->surface_set_material(surface, material); @@ -1692,7 +1698,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node) { if (collada.state.mesh_data_map.has(meshid)) { Ref mesh=Ref(memnew( Mesh )); const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid]; - Error err = _create_mesh_surfaces(false,mesh,ng->material_map,meshdata,apply_xform,bone_remap,skin,NULL); + Error err = _create_mesh_surfaces(false,mesh,ng->material_map,meshdata,apply_xform,bone_remap,skin,NULL,Vector >(),true); ERR_FAIL_COND_V(err,err); morphs.push_back(mesh); diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp index 3cd6d8336..d650725e2 100644 --- a/tools/editor/plugins/script_editor_plugin.cpp +++ b/tools/editor/plugins/script_editor_plugin.cpp @@ -1840,6 +1840,8 @@ void ScriptEditor::get_window_layout(Ref p_layout) { void ScriptEditor::_help_class_open(const String& p_class) { + if (p_class=="") + return; for(int i=0;iget_child_count();i++) { -- cgit v1.2.3-70-g09d2 From 27a46d78ec43b69a70a1d84c540353e3cb3b04c0 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 2 Dec 2016 22:23:16 -0300 Subject: Subsurface scattering material param is now working! --- drivers/gles3/rasterizer_scene_gles3.cpp | 91 +++++++++-- drivers/gles3/rasterizer_scene_gles3.h | 12 ++ drivers/gles3/rasterizer_storage_gles3.cpp | 21 ++- drivers/gles3/rasterizer_storage_gles3.h | 5 +- drivers/gles3/shader_compiler_gles3.cpp | 11 +- drivers/gles3/shader_compiler_gles3.h | 1 + drivers/gles3/shaders/SCsub | 2 + drivers/gles3/shaders/resolve.glsl | 12 +- drivers/gles3/shaders/scene.glsl | 42 +++++ drivers/gles3/shaders/screen_space_reflection.glsl | 7 +- drivers/gles3/shaders/subsurf_scattering.glsl | 172 +++++++++++++++++++++ scene/3d/light.cpp | 2 +- scene/resources/material.cpp | 37 +++-- scene/resources/material.h | 8 +- servers/visual/shader_types.cpp | 1 + servers/visual/visual_server_scene.cpp | 2 +- servers/visual_server.h | 1 + 17 files changed, 378 insertions(+), 49 deletions(-) create mode 100644 drivers/gles3/shaders/subsurf_scattering.glsl (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 16784246f..c4c7d4409 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1809,6 +1809,10 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g mirror=!mirror; } + if (m->shader->spatial.uses_sss) { + state.used_sss=true; + } + if (p_shadow) { if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) @@ -1827,6 +1831,7 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g } + RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); if (!e) @@ -2620,6 +2625,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_ current_geometry_index=0; current_material_index=0; + state.used_sss=false; //fill list @@ -2683,6 +2689,50 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c glDisable(GL_CULL_FACE); glDisable(GL_BLEND); + if (state.used_sss) {//sss enabled + //copy diffuse while performing sss + + state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_11_SAMPLES,subsurface_scatter_quality==SSS_QUALITY_LOW); + state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_17_SAMPLES,subsurface_scatter_quality==SSS_QUALITY_MEDIUM); + state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_25_SAMPLES,subsurface_scatter_quality==SSS_QUALITY_HIGH); + state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::ENABLE_FOLLOW_SURFACE,subsurface_scatter_follow_surface); + state.sss_shader.bind(); + state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::MAX_RADIUS,subsurface_scatter_size); + state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::FOVY,p_cam_projection.get_fov()); + state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::CAMERA_Z_NEAR,p_cam_projection.get_z_near()); + state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::CAMERA_Z_FAR,p_cam_projection.get_z_far()); + state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::DIR,Vector2(1,0)); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.motion_sss); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->fbo); //copy to front first + + _copy_screen(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->color); + state.sss_shader.set_uniform(SubsurfScatteringShaderGLES3::DIR,Vector2(0,1)); + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level + _copy_screen(); + + } else { + // just copy diffuse + storage->shaders.copy.bind(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse); + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level + _copy_screen(); + + } + + + if (env->ssr_enabled) { //blur diffuse into effect mipmaps using separatable convolution //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); @@ -2698,11 +2748,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE,Vector2(1.0/vp_w,1.0/vp_h)); state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD,float(i)); glActiveTexture(GL_TEXTURE0); - if (i==0) { - glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse); - } else { - glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger - } + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo); _copy_screen(); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL,false); @@ -2748,7 +2794,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse); glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.normal_sr); + glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.normal_rough); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->depth); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); @@ -2764,22 +2810,26 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env,const CameraMatrix &p_c } + //copy reflection over diffuse, resolving SSR if needed state.resolve_shader.set_conditional(ResolveShaderGLES3::USE_SSR,env->ssr_enabled); state.resolve_shader.bind(); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.diffuse); - glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->buffers.specular); if (env->ssr_enabled) { - glActiveTexture(GL_TEXTURE2); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->effects.mip_maps[1].color); } glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); - //glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->fbo); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE,GL_ONE); //use additive to accumulate one over the other + _copy_screen(); + glDisable(GL_BLEND); //end additive + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::SIMPLE_COPY,true); state.effect_blur_shader.bind(); state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD,float(0)); @@ -2839,6 +2889,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C bool use_mrt=true; + _fill_render_list(p_cull_result,p_cull_count,false); // @@ -2893,11 +2944,17 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C draw_buffers.push_back(GL_COLOR_ATTACHMENT0); draw_buffers.push_back(GL_COLOR_ATTACHMENT1); draw_buffers.push_back(GL_COLOR_ATTACHMENT2); + if (state.used_sss) { + draw_buffers.push_back(GL_COLOR_ATTACHMENT3); + } glDrawBuffers(draw_buffers.size(),draw_buffers.ptr()); Color black(0,0,0,0); glClearBufferfv(GL_COLOR,1,black.components); // specular glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough + if (state.used_sss) { + glClearBufferfv(GL_COLOR,3,black.components); // normal metal rough + } } else { @@ -3968,11 +4025,25 @@ void RasterizerSceneGLES3::initialize() { state.resolve_shader.init(); state.ssr_shader.init(); state.effect_blur_shader.init(); + state.sss_shader.init(); + + + { + GLOBAL_DEF("rendering/gles3/subsurface_scattering/quality",1); + Globals::get_singleton()->set_custom_property_info("rendering/gles3/subsurface_scattering/quality",PropertyInfo(Variant::INT,"rendering/gles3/subsurface_scattering/quality",PROPERTY_HINT_ENUM,"Low,Medium,High")); + GLOBAL_DEF("rendering/gles3/subsurface_scattering/max_size",1.0); + Globals::get_singleton()->set_custom_property_info("rendering/gles3/subsurface_scattering/max_size",PropertyInfo(Variant::INT,"rendering/gles3/subsurface_scattering/max_size",PROPERTY_HINT_RANGE,"0.01,8,0.01")); + GLOBAL_DEF("rendering/gles3/subsurface_scattering/follow_surface",false); + } + } void RasterizerSceneGLES3::iteration() { shadow_filter_mode=ShadowFilterMode(int(Globals::get_singleton()->get("rendering/gles3/shadow_filter_mode"))); + subsurface_scatter_follow_surface=Globals::get_singleton()->get("rendering/gles3/subsurface_scattering/follow_surface"); + subsurface_scatter_quality=SubSurfaceScatterQuality(int(Globals::get_singleton()->get("rendering/gles3/subsurface_scattering/quality"))); + subsurface_scatter_size=Globals::get_singleton()->get("rendering/gles3/subsurface_scattering/max_size"); } void RasterizerSceneGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 0b934085e..21711292a 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -7,6 +7,7 @@ #include "drivers/gles3/shaders/resolve.glsl.h" #include "drivers/gles3/shaders/screen_space_reflection.glsl.h" #include "drivers/gles3/shaders/effect_blur.glsl.h" +#include "drivers/gles3/shaders/subsurf_scattering.glsl.h" class RasterizerSceneGLES3 : public RasterizerScene { public: @@ -22,6 +23,15 @@ public: uint64_t shadow_atlas_realloc_tolerance_msec; + enum SubSurfaceScatterQuality { + SSS_QUALITY_LOW, + SSS_QUALITY_MEDIUM, + SSS_QUALITY_HIGH, + }; + + SubSurfaceScatterQuality subsurface_scatter_quality; + float subsurface_scatter_size; + bool subsurface_scatter_follow_surface; uint64_t render_pass; uint64_t scene_pass; @@ -51,6 +61,7 @@ public: ResolveShaderGLES3 resolve_shader; ScreenSpaceReflectionShaderGLES3 ssr_shader; EffectBlurShaderGLES3 effect_blur_shader; + SubsurfScatteringShaderGLES3 sss_shader; struct SceneDataUBO { @@ -118,6 +129,7 @@ public: int reflection_probe_count; bool cull_front; + bool used_sss; } state; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 01668e728..7b9a3f2af 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1456,6 +1456,7 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { p_shader->spatial.uses_alpha=false; p_shader->spatial.unshaded=false; p_shader->spatial.ontop=false; + p_shader->spatial.uses_sss=false; shaders.actions_scene.render_mode_values["blend_add"]=Pair(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_ADD); shaders.actions_scene.render_mode_values["blend_mix"]=Pair(&p_shader->spatial.blend_mode,Shader::Spatial::BLEND_MODE_MIX); @@ -1477,6 +1478,8 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha; shaders.actions_scene.usage_flag_pointers["VERTEX"]=&p_shader->spatial.uses_vertex; + shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"]=&p_shader->spatial.uses_sss; + actions=&shaders.actions_scene; actions->uniforms=&p_shader->uniforms; @@ -4771,7 +4774,8 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { glDeleteFramebuffers(1,&rt->buffers.alpha_fbo); glDeleteTextures(1,&rt->buffers.diffuse); glDeleteTextures(1,&rt->buffers.specular); - glDeleteTextures(1,&rt->buffers.normal_sr); + glDeleteTextures(1,&rt->buffers.normal_rough); + glDeleteTextures(1,&rt->buffers.motion_sss); rt->buffers.fbo=0; rt->buffers.alpha_fbo=0; } @@ -4923,14 +4927,23 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt){ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt->buffers.specular, 0); - glGenTextures(1, &rt->buffers.normal_sr); - glBindTexture(GL_TEXTURE_2D, rt->buffers.normal_sr); + glGenTextures(1, &rt->buffers.normal_rough); + glBindTexture(GL_TEXTURE_2D, rt->buffers.normal_rough); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->buffers.normal_sr, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, rt->buffers.normal_rough, 0); + + glGenTextures(1, &rt->buffers.motion_sss); + glBindTexture(GL_TEXTURE_2D, rt->buffers.motion_sss); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, rt->width, rt->height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, rt->buffers.motion_sss, 0); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 1eba8b42c..e6b89eb66 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -369,6 +369,7 @@ public: bool ontop; bool uses_vertex; bool uses_discard; + bool uses_sss; } spatial; @@ -886,8 +887,8 @@ public: GLuint alpha_fbo; //single buffer, just diffuse (for alpha pass) GLuint specular; GLuint diffuse; - GLuint normal_sr; - GLuint temporal; + GLuint normal_rough; + GLuint motion_sss; } buffers; struct Effects { diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index c54fc011e..5c7a72ab1 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -422,9 +422,9 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener used_name_defines.insert(vnode->name); } - if (p_actions.usage_flag_pointers.has(vnode->name) && !used_name_defines.has(vnode->name)) { + if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) { *p_actions.usage_flag_pointers[vnode->name]=true; - used_name_defines.insert(vnode->name); + used_flag_pointers.insert(vnode->name); } if (p_default_actions.renames.has(vnode->name)) @@ -670,6 +670,8 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"]="clearcoat_gloss"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"]="anisotropy"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"]="anisotropy_flow"; + actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"]="sss_spread"; + actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"]="sss_strength"; actions[VS::SHADER_SPATIAL].renames["AO"]="ao"; actions[VS::SHADER_SPATIAL].renames["EMISSION"]="emission"; actions[VS::SHADER_SPATIAL].renames["DISCARD"]="_discard"; @@ -692,6 +694,11 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"]="@NORMALMAP"; actions[VS::SHADER_SPATIAL].usage_defines["COLOR"]="#define ENABLE_COLOR_INTERP\n"; + actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"]="#define ENABLE_SSS_MOTION\n"; + + actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"]="sss_strength"; + + actions[VS::SHADER_SPATIAL].render_mode_defines["skip_transform"]="#define SKIP_TRANSFORM_USED\n"; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index 354952680..1beee66ad 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -58,6 +58,7 @@ private: StringName time_name; Set used_name_defines; + Set used_flag_pointers; Set used_rmode_defines; Set internal_functions; diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index 66a19eefd..b5797e78b 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -11,4 +11,6 @@ if env['BUILDERS'].has_key('GLES3_GLSL'): env.GLES3_GLSL('blend_shape.glsl'); env.GLES3_GLSL('screen_space_reflection.glsl'); env.GLES3_GLSL('effect_blur.glsl'); + env.GLES3_GLSL('subsurf_scattering.glsl'); + diff --git a/drivers/gles3/shaders/resolve.glsl b/drivers/gles3/shaders/resolve.glsl index 4ca629730..6acc71229 100644 --- a/drivers/gles3/shaders/resolve.glsl +++ b/drivers/gles3/shaders/resolve.glsl @@ -17,11 +17,8 @@ void main() { in vec2 uv_interp; -uniform sampler2D source_diffuse; //texunit:0 -uniform sampler2D source_specular; //texunit:1 - - -uniform sampler2D source_ssr_ssao; //texunit:2 +uniform sampler2D source_specular; //texunit:0 +uniform sampler2D source_ssr; //texunit:1 uniform float stuff; @@ -31,15 +28,14 @@ layout(location = 0) out vec4 frag_color; void main() { - vec4 diffuse = texture( source_diffuse, uv_interp ); vec4 specular = texture( source_specular, uv_interp ); #ifdef USE_SSR - vec4 ssr = textureLod(source_ssr_ssao,uv_interp,0.0); + vec4 ssr = textureLod(source_ssr,uv_interp,0.0); specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a); #endif - frag_color = vec4(diffuse.rgb,1.0)+vec4(specular.rgb,1.0); + frag_color = vec4(specular.rgb,1.0); } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 192042192..230544c1c 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -75,6 +75,7 @@ layout(std140) uniform SceneData { //ubo:0 vec2 directional_shadow_pixel_size; float reflection_multiplier; + float subsurface_scatter_width; }; @@ -385,6 +386,7 @@ layout(std140) uniform SceneData { vec2 directional_shadow_pixel_size; float reflection_multiplier; + float subsurface_scatter_width; }; @@ -479,6 +481,9 @@ uniform int reflection_count; layout(location=0) out vec4 diffuse_buffer; layout(location=1) out vec4 specular_buffer; layout(location=2) out vec4 normal_mr_buffer; +#if defined (ENABLE_SSS_MOTION) +layout(location=3) out uint motion_ssr_buffer; +#endif #else @@ -621,6 +626,35 @@ in highp float dp_clip; #endif +#if 0 +//need to save texture depth for this + +vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 pos, float distance) { + + float scale = 8.25 * (1.0 - translucency) / subsurface_scatter_width; + float d = scale * distance; + + /** + * Armed with the thickness, we can now calculate the color by means of the + * precalculated transmittance profile. + * (It can be precomputed into a texture, for maximum performance): + */ + float dd = -d * d; + vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); + + /** + * Using the profile, we finally approximate the transmitted lighting from + * the back of the object: + */ + return profile * clamp(0.3 + dot(light_vec, normal),0.0,1.0); +} +#endif + void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal,vec3 binormal, vec3 tangent, vec3 albedo, vec3 specular, float roughness, float rim, float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex; @@ -870,6 +904,10 @@ void main() { bool discard_=false; #endif +#if defined (ENABLE_SSS_MOTION) + float sss_strength=0.0; +#endif + { @@ -1194,6 +1232,10 @@ LIGHT_SHADER_CODE normal_mr_buffer=vec4(normalize(normal)*0.5+0.5,roughness); +#if defined (ENABLE_SSS_MOTION) + motion_ssr_buffer = uint(clamp(sqrt(sss_strength)*255.0,0.0,255))<<24; +#endif + #else diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl index 5b24013c0..ec4bdf86c 100644 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -23,7 +23,6 @@ in vec2 pos_interp; uniform sampler2D source_diffuse; //texunit:0 uniform sampler2D source_normal_roughness; //texunit:1 uniform sampler2D source_depth; //texunit:2 -uniform sampler2D source_diffuse_mipmaps; //texunit:3 uniform float camera_z_near; uniform float camera_z_far; @@ -295,11 +294,7 @@ void main() { vec4 sample_color; { - sample_color = textureLod(source_diffuse_mipmaps,sample_pos,max(1.0,mipmap)); - if (mipmap<1.0) { //we use another image as base to avoid copying all the screen unnecesarily - vec4 base_sample_color = textureLod(source_diffuse,sample_pos,0.0); - sample_color = mix(base_sample_color,sample_color,mipmap); - } + sample_color = textureLod(source_diffuse,sample_pos,mipmap); } //multiply by gloss diff --git a/drivers/gles3/shaders/subsurf_scattering.glsl b/drivers/gles3/shaders/subsurf_scattering.glsl new file mode 100644 index 000000000..89e618b66 --- /dev/null +++ b/drivers/gles3/shaders/subsurf_scattering.glsl @@ -0,0 +1,172 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; +layout(location=4) in vec2 uv_in; + +out vec2 uv_interp; + + +void main() { + + uv_interp = uv_in; + gl_Position = vertex_attrib; +} + +[fragment] + +//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this +#define QUALIFIER const + +#ifdef USE_25_SAMPLES + +const int kernel_size=25; +QUALIFIER vec4 kernel[25] = vec4[] ( + vec4(0.530605, 0.613514, 0.739601, 0.0), + vec4(0.000973794, 1.11862e-005, 9.43437e-007, -3.0), + vec4(0.00333804, 7.85443e-005, 1.2945e-005, -2.52083), + vec4(0.00500364, 0.00020094, 5.28848e-005, -2.08333), + vec4(0.00700976, 0.00049366, 0.000151938, -1.6875), + vec4(0.0094389, 0.00139119, 0.000416598, -1.33333), + vec4(0.0128496, 0.00356329, 0.00132016, -1.02083), + vec4(0.017924, 0.00711691, 0.00347194, -0.75), + vec4(0.0263642, 0.0119715, 0.00684598, -0.520833), + vec4(0.0410172, 0.0199899, 0.0118481, -0.333333), + vec4(0.0493588, 0.0367726, 0.0219485, -0.1875), + vec4(0.0402784, 0.0657244, 0.04631, -0.0833333), + vec4(0.0211412, 0.0459286, 0.0378196, -0.0208333), + vec4(0.0211412, 0.0459286, 0.0378196, 0.0208333), + vec4(0.0402784, 0.0657244, 0.04631, 0.0833333), + vec4(0.0493588, 0.0367726, 0.0219485, 0.1875), + vec4(0.0410172, 0.0199899, 0.0118481, 0.333333), + vec4(0.0263642, 0.0119715, 0.00684598, 0.520833), + vec4(0.017924, 0.00711691, 0.00347194, 0.75), + vec4(0.0128496, 0.00356329, 0.00132016, 1.02083), + vec4(0.0094389, 0.00139119, 0.000416598, 1.33333), + vec4(0.00700976, 0.00049366, 0.000151938, 1.6875), + vec4(0.00500364, 0.00020094, 5.28848e-005, 2.08333), + vec4(0.00333804, 7.85443e-005, 1.2945e-005, 2.52083), + vec4(0.000973794, 1.11862e-005, 9.43437e-007, 3.0) +); + +#endif //USE_25_SAMPLES + +#ifdef USE_17_SAMPLES + +const int kernel_size=17; + +QUALIFIER vec4 kernel[17] = vec4[]( + vec4(0.536343, 0.624624, 0.748867, 0.0), + vec4(0.00317394, 0.000134823, 3.77269e-005, -2.0), + vec4(0.0100386, 0.000914679, 0.000275702, -1.53125), + vec4(0.0144609, 0.00317269, 0.00106399, -1.125), + vec4(0.0216301, 0.00794618, 0.00376991, -0.78125), + vec4(0.0347317, 0.0151085, 0.00871983, -0.5), + vec4(0.0571056, 0.0287432, 0.0172844, -0.28125), + vec4(0.0582416, 0.0659959, 0.0411329, -0.125), + vec4(0.0324462, 0.0656718, 0.0532821, -0.03125), + vec4(0.0324462, 0.0656718, 0.0532821, 0.03125), + vec4(0.0582416, 0.0659959, 0.0411329, 0.125), + vec4(0.0571056, 0.0287432, 0.0172844, 0.28125), + vec4(0.0347317, 0.0151085, 0.00871983, 0.5), + vec4(0.0216301, 0.00794618, 0.00376991, 0.78125), + vec4(0.0144609, 0.00317269, 0.00106399, 1.125), + vec4(0.0100386, 0.000914679, 0.000275702, 1.53125), + vec4(0.00317394, 0.000134823, 3.77269e-005, 2.0) +); + +#endif //USE_17_SAMPLES + + +#ifdef USE_11_SAMPLES + +const int kernel_size=11; + +QUALIFIER vec4 kernel[11] = vec4[]( + vec4(0.560479, 0.669086, 0.784728, 0.0), + vec4(0.00471691, 0.000184771, 5.07566e-005, -2.0), + vec4(0.0192831, 0.00282018, 0.00084214, -1.28), + vec4(0.03639, 0.0130999, 0.00643685, -0.72), + vec4(0.0821904, 0.0358608, 0.0209261, -0.32), + vec4(0.0771802, 0.113491, 0.0793803, -0.08), + vec4(0.0771802, 0.113491, 0.0793803, 0.08), + vec4(0.0821904, 0.0358608, 0.0209261, 0.32), + vec4(0.03639, 0.0130999, 0.00643685, 0.72), + vec4(0.0192831, 0.00282018, 0.00084214, 1.28), + vec4(0.00471691, 0.000184771, 5.07565e-005, 2.0) +); + +#endif //USE_11_SAMPLES + + +uniform float max_radius; +uniform float fovy; +uniform float camera_z_far; +uniform float camera_z_near; +uniform vec2 dir; +in vec2 uv_interp; + +uniform sampler2D source_diffuse; //texunit:0 +uniform highp usampler2D source_motion_ss; //texunit:1 +uniform sampler2D source_depth; //texunit:2 + +layout(location = 0) out vec4 frag_color; + +void main() { + + float strength = float(texture(source_motion_ss,uv_interp).r>>24)*(1.0/255.0); + strength*=strength; //stored as sqrt + + // Fetch color of current pixel: + vec4 base_color = texture(source_diffuse, uv_interp); + + if (strength>0.0) { + + + // Fetch linear depth of current pixel: + float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0; + depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); + depth=-depth; + + + // Calculate the radius scale (1.0 for a unit plane sitting on the + // projection window): + float distance = 1.0 / tan(0.5 * fovy); + float scale = distance / -depth; //remember depth is negative by default in OpenGL + + // Calculate the final step to fetch the surrounding pixels: + vec2 step = max_radius * scale * dir; + step *= strength; // Modulate it using the alpha channel. + step *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3. + + // Accumulate the center sample: + vec3 color_accum = base_color.rgb; + color_accum *= kernel[0].rgb; + + // Accumulate the other samples: + for (int i = 1; i < kernel_size; i++) { + // Fetch color and depth for current sample: + vec2 offset = uv_interp + kernel[i].a * step; + vec3 color = texture(source_diffuse, offset).rgb; + +#ifdef ENABLE_FOLLOW_SURFACE + // If the difference in depth is huge, we lerp color back to "colorM": + float depth_cmp = texture(source_depth, offset).r *2.0 - 1.0; + depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near)); + depth_cmp=-depth_cmp; + + float s = clamp(300.0f * distance * + max_radius * abs(depth - depth_cmp),0.0,1.0); + color = mix(color, base_color.rgb, s); +#endif + + // Accumulate: + color_accum += kernel[i].rgb * color; + } + + frag_color = vec4(color_accum,base_color.a); //keep alpha (used for SSAO) + } else { + frag_color = base_color; + } +} + diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 49bffd3c2..7177e21e1 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -218,7 +218,7 @@ void Light::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_cull_mask"), _SCS("get_cull_mask")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow")); ADD_PROPERTY( PropertyInfo( Variant::COLOR, "shadow/color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_shadow_color"), _SCS("get_shadow_color")); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias",PROPERTY_HINT_RANGE,"-16,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/max_distance",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editor/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only")); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 99b7a130f..70afd6811 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -72,7 +72,7 @@ void FixedSpatialMaterial::init_shaders() { shader_names->clearcoat_gloss="clearcoat_gloss"; shader_names->anisotropy="anisotropy_ratio"; shader_names->height_scale="height_scale"; - shader_names->subsurface_scattering="subsurface_scattering"; + shader_names->subsurface_scattering_strength="subsurface_scattering_strength"; shader_names->refraction="refraction"; shader_names->refraction_roughness="refraction_roughness"; shader_names->point_size="point_size"; @@ -217,6 +217,14 @@ void FixedSpatialMaterial::_update_shader() { code+="uniform sampler2D texture_detail_mask : hint_white;\n"; } + if (features[FEATURE_SUBSURACE_SCATTERING]) { + + code+="uniform float subsurface_scattering_strength : hint_range(0,1);\n"; + code+="uniform sampler2D texture_subsurface_scattering : hint_white;\n"; + + } + + code+="\n\n"; code+="void vertex() {\n"; @@ -230,7 +238,7 @@ void FixedSpatialMaterial::_update_shader() { code+="\tPOINT_SIZE=point_size;\n"; } code+="\tUV=UV*uv1_scale+uv1_offset;\n"; - if (detail_blend_mode==DETAIL_UV_2) { + if (detail_uv==DETAIL_UV_2) { code+="\tUV2=UV2*uv2_scale+uv2_offset;\n"; } @@ -284,6 +292,12 @@ void FixedSpatialMaterial::_update_shader() { code+="\tAO = texture(texture_ambient_occlusion,UV).r;\n"; } + if (features[FEATURE_SUBSURACE_SCATTERING]) { + + code+="\tfloat sss_tex = texture(texture_subsurface_scattering,UV).r;\n"; + code+="\tSSS_STRENGTH=subsurface_scattering_strength*sss_tex;\n"; + } + if (features[FEATURE_DETAIL]) { String det_uv=detail_uv==DETAIL_UV_1?"UV":"UV2"; code+="\tvec4 detail_tex = texture(texture_detail_albedo,"+det_uv+");\n"; @@ -512,17 +526,18 @@ float FixedSpatialMaterial::get_height_scale() const{ return height_scale; } -void FixedSpatialMaterial::set_subsurface_scattering(float p_subsurface_scattering){ - subsurface_scattering=p_subsurface_scattering; - VS::get_singleton()->material_set_param(_get_material(),shader_names->subsurface_scattering,subsurface_scattering); +void FixedSpatialMaterial::set_subsurface_scattering_strength(float p_subsurface_scattering_strength){ + + subsurface_scattering_strength=p_subsurface_scattering_strength; + VS::get_singleton()->material_set_param(_get_material(),shader_names->subsurface_scattering_strength,subsurface_scattering_strength); } -float FixedSpatialMaterial::get_subsurface_scattering() const{ +float FixedSpatialMaterial::get_subsurface_scattering_strength() const{ - return subsurface_scattering; + return subsurface_scattering_strength; } void FixedSpatialMaterial::set_refraction(float p_refraction){ @@ -806,8 +821,8 @@ void FixedSpatialMaterial::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_height_scale","height_scale"),&FixedSpatialMaterial::set_height_scale); ObjectTypeDB::bind_method(_MD("get_height_scale"),&FixedSpatialMaterial::get_height_scale); - ObjectTypeDB::bind_method(_MD("set_subsurface_scattering","subsurface_scattering"),&FixedSpatialMaterial::set_subsurface_scattering); - ObjectTypeDB::bind_method(_MD("get_subsurface_scattering"),&FixedSpatialMaterial::get_subsurface_scattering); + ObjectTypeDB::bind_method(_MD("set_subsurface_scattering_strength","strength"),&FixedSpatialMaterial::set_subsurface_scattering_strength); + ObjectTypeDB::bind_method(_MD("get_subsurface_scattering_strength"),&FixedSpatialMaterial::get_subsurface_scattering_strength); ObjectTypeDB::bind_method(_MD("set_refraction","refraction"),&FixedSpatialMaterial::set_refraction); ObjectTypeDB::bind_method(_MD("get_refraction"),&FixedSpatialMaterial::get_refraction); @@ -912,7 +927,7 @@ void FixedSpatialMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"height/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_HEIGHT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"subsurf_scatter/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_SUBSURACE_SCATTERING); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"subsurf_scatter/amount",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_subsurface_scattering"),_SCS("get_subsurface_scattering")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"subsurf_scatter/strength",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_subsurface_scattering_strength"),_SCS("get_subsurface_scattering_strength")); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT,"subsurf_scatter/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"),TEXTURE_SUBSURFACE_SCATTERING); ADD_PROPERTYI(PropertyInfo(Variant::BOOL,"refraction/enabled"),_SCS("set_feature"),_SCS("get_feature"),FEATURE_REFRACTION); @@ -1011,7 +1026,7 @@ FixedSpatialMaterial::FixedSpatialMaterial() : element(this) { set_clearcoat_gloss(0.5); set_anisotropy(0); set_height_scale(1); - set_subsurface_scattering(0); + set_subsurface_scattering_strength(0); set_refraction(0); set_refraction_roughness(0); set_line_width(1); diff --git a/scene/resources/material.h b/scene/resources/material.h index 15c5910a9..9b80b6769 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -213,7 +213,7 @@ private: StringName clearcoat_gloss; StringName anisotropy; StringName height_scale; - StringName subsurface_scattering; + StringName subsurface_scattering_strength; StringName refraction; StringName refraction_roughness; StringName point_size; @@ -247,7 +247,7 @@ private: float clearcoat_gloss; float anisotropy; float height_scale; - float subsurface_scattering; + float subsurface_scattering_strength; float refraction; float refraction_roughness; float line_width; @@ -318,8 +318,8 @@ public: void set_height_scale(float p_height_scale); float get_height_scale() const; - void set_subsurface_scattering(float p_subsurface_scattering); - float get_subsurface_scattering() const; + void set_subsurface_scattering_strength(float p_strength); + float get_subsurface_scattering_strength() const; void set_refraction(float p_refraction); float get_refraction() const; diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index f79932902..4872135e2 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -66,6 +66,7 @@ ShaderTypes::ShaderTypes() shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["CLEARCOAT_GLOSS"]=ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ANISOTROPY"]=ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ANISOTROPY_FLOW"]=ShaderLanguage::TYPE_VEC2; + shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SSS_STRENGTH"]=ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["AO"]=ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["EMISSION"]=ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"]=ShaderLanguage::TYPE_FLOAT; diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 0f7dabcc1..6f7dac7f4 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1555,7 +1555,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,const float angle = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE); CameraMatrix cm; - cm.set_perspective( angle, 1.0, 0.01, radius ); + cm.set_perspective( angle*2.0, 1.0, 0.01, radius ); Vector planes = cm.get_projection_planes(p_instance->transform); diff --git a/servers/visual_server.h b/servers/visual_server.h index 4c9e04a78..9b1a9d81a 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -556,6 +556,7 @@ public: virtual void environment_set_adjustment(RID p_env,bool p_enable,float p_brightness,float p_contrast,float p_saturation,RID p_ramp)=0; virtual void environment_set_ssr(RID p_env,bool p_enable, int p_max_steps,float p_accel,float p_fade,float p_depth_tolerance,bool p_smooth,bool p_roughness)=0; + /* SCENARIO API */ -- cgit v1.2.3-70-g09d2 From 075fde7f26d6c3b02df5108065d1a9f979437bb8 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 20 Dec 2016 00:21:07 -0300 Subject: work in progress global illumination --- core/image.cpp | 22 +- drivers/gles3/rasterizer_scene_gles3.cpp | 85 +- drivers/gles3/rasterizer_scene_gles3.h | 26 +- drivers/gles3/rasterizer_storage_gles3.cpp | 317 +++- drivers/gles3/rasterizer_storage_gles3.h | 79 + drivers/gles3/shaders/scene.glsl | 135 +- scene/3d/baked_light_instance.cpp | 1722 +++++++++++++++++++- scene/3d/baked_light_instance.h | 122 +- scene/3d/gi_probe.cpp | 1248 ++++++++++++++ scene/3d/gi_probe.h | 174 ++ scene/3d/light.cpp | 34 +- scene/3d/light.h | 6 + scene/3d/visual_instance.cpp | 65 - scene/3d/visual_instance.h | 10 +- scene/register_scene_types.cpp | 5 +- scene/resources/baked_light.cpp | 574 ------- scene/resources/baked_light.h | 163 -- servers/visual/rasterizer.h | 45 +- servers/visual/visual_server_light_baker.cpp | 6 + servers/visual/visual_server_light_baker.h | 29 + servers/visual/visual_server_raster.cpp | 3 +- servers/visual/visual_server_raster.h | 30 +- servers/visual/visual_server_scene.cpp | 865 +++++++++- servers/visual/visual_server_scene.h | 162 +- servers/visual_server.h | 38 +- tools/editor/io_plugins/editor_import_collada.cpp | 17 +- .../io_plugins/editor_scene_import_plugin.cpp | 2 +- tools/editor/spatial_editor_gizmos.cpp | 170 +- tools/editor/spatial_editor_gizmos.h | 22 + 29 files changed, 5217 insertions(+), 959 deletions(-) create mode 100644 scene/3d/gi_probe.cpp create mode 100644 scene/3d/gi_probe.h create mode 100644 servers/visual/visual_server_light_baker.cpp create mode 100644 servers/visual/visual_server_light_baker.h (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/core/image.cpp b/core/image.cpp index 73a2ab801..0b63d9c52 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -390,16 +390,16 @@ void Image::convert( Format p_new_format ){ case FORMAT_R8|(FORMAT_RG8<<8): _convert<1,false,2,false,false,false>( width, height,rptr, wptr ); break; case FORMAT_R8|(FORMAT_RGB8<<8): _convert<1,false,3,false,false,false>( width, height,rptr, wptr ); break; case FORMAT_R8|(FORMAT_RGBA8<<8): _convert<1,false,3,true,false,false>( width, height,rptr, wptr ); break; - case FORMAT_RG8|(FORMAT_L8<<8): _convert<1,false,1,false,false,true>( width, height,rptr, wptr ); break; - case FORMAT_RG8|(FORMAT_LA8<<8): _convert<1,false,1,true,false,true>( width, height,rptr, wptr ); break; - case FORMAT_RG8|(FORMAT_R8<<8): _convert<1,false,1,false,false,false>( width, height,rptr, wptr ); break; - case FORMAT_RG8|(FORMAT_RGB8<<8): _convert<1,false,3,false,false,false>( width, height,rptr, wptr ); break; - case FORMAT_RG8|(FORMAT_RGBA8<<8): _convert<1,false,3,true,false,false>( width, height,rptr, wptr ); break; - case FORMAT_RGB8|(FORMAT_L8<<8): _convert<2,false,1,false,false,true>( width, height,rptr, wptr ); break; - case FORMAT_RGB8|(FORMAT_LA8<<8): _convert<2,false,1,true,false,true>( width, height,rptr, wptr ); break; - case FORMAT_RGB8|(FORMAT_R8<<8): _convert<2,false,1,false,false,false>( width, height,rptr, wptr ); break; - case FORMAT_RGB8|(FORMAT_RG8<<8): _convert<2,false,2,false,false,false>( width, height,rptr, wptr ); break; - case FORMAT_RGB8|(FORMAT_RGBA8<<8): _convert<2,false,3,true,false,false>( width, height,rptr, wptr ); break; + case FORMAT_RG8|(FORMAT_L8<<8): _convert<2,false,1,false,false,true>( width, height,rptr, wptr ); break; + case FORMAT_RG8|(FORMAT_LA8<<8): _convert<2,false,1,true,false,true>( width, height,rptr, wptr ); break; + case FORMAT_RG8|(FORMAT_R8<<8): _convert<2,false,1,false,false,false>( width, height,rptr, wptr ); break; + case FORMAT_RG8|(FORMAT_RGB8<<8): _convert<2,false,3,false,false,false>( width, height,rptr, wptr ); break; + case FORMAT_RG8|(FORMAT_RGBA8<<8): _convert<2,false,3,true,false,false>( width, height,rptr, wptr ); break; + case FORMAT_RGB8|(FORMAT_L8<<8): _convert<3,false,1,false,false,true>( width, height,rptr, wptr ); break; + case FORMAT_RGB8|(FORMAT_LA8<<8): _convert<3,false,1,true,false,true>( width, height,rptr, wptr ); break; + case FORMAT_RGB8|(FORMAT_R8<<8): _convert<3,false,1,false,false,false>( width, height,rptr, wptr ); break; + case FORMAT_RGB8|(FORMAT_RG8<<8): _convert<3,false,2,false,false,false>( width, height,rptr, wptr ); break; + case FORMAT_RGB8|(FORMAT_RGBA8<<8): _convert<3,false,3,true,false,false>( width, height,rptr, wptr ); break; case FORMAT_RGBA8|(FORMAT_L8<<8): _convert<3,true,1,false,false,true>( width, height,rptr, wptr ); break; case FORMAT_RGBA8|(FORMAT_LA8<<8): _convert<3,true,1,true,false,true>( width, height,rptr, wptr ); break; case FORMAT_RGBA8|(FORMAT_R8<<8): _convert<3,true,1,false,false,false>( width, height,rptr, wptr ); break; @@ -414,7 +414,7 @@ void Image::convert( Format p_new_format ){ bool gen_mipmaps=mipmaps; - mipmaps=false; +// mipmaps=false; *this=new_img; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 2c6c9dd9b..524e68373 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1010,6 +1010,48 @@ void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { light_instance->last_scene_pass=scene_pass; } + +////////////////////// + +RID RasterizerSceneGLES3::gi_probe_instance_create() { + + GIProbeInstance *gipi = memnew(GIProbeInstance); + + return gi_probe_instance_owner.make_rid(gipi); +} + +void RasterizerSceneGLES3::gi_probe_instance_set_light_data(RID p_probe,RID p_data) { + + GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe); + ERR_FAIL_COND(!gipi); + gipi->data=p_data; + if (p_data.is_valid()) { + RasterizerStorageGLES3::GIProbeData *gipd = storage->gi_probe_data_owner.getornull(p_data); + ERR_FAIL_COND(!gipd); + if (gipd) { + gipi->tex_cache=gipd->tex_id; + gipi->cell_size_cache.x=1.0/gipd->width; + gipi->cell_size_cache.y=1.0/gipd->height; + gipi->cell_size_cache.z=1.0/gipd->depth; + } + } +} +void RasterizerSceneGLES3::gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform) { + + GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe); + ERR_FAIL_COND(!gipi); + gipi->transform_to_data=p_xform; + +} + +void RasterizerSceneGLES3::gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds) { + + GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe); + ERR_FAIL_COND(!gipi); + gipi->bounds=p_bounds; + +} + //////////////////////////// //////////////////////////// //////////////////////////// @@ -1438,7 +1480,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } -void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) { +void RasterizerSceneGLES3::_setup_light(RenderList::Element *e,const Transform& p_view_transform) { int omni_indices[16]; int omni_count=0; @@ -1509,7 +1551,33 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) { glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::REFLECTION_INDICES),reflection_count,reflection_indices); } + int gi_probe_count = e->instance->gi_probe_instances.size(); + if (gi_probe_count) { + const RID * ridp = e->instance->gi_probe_instances.ptr(); + GIProbeInstance *gipi = gi_probe_instance_owner.getptr(ridp[0]); + + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-6); + glBindTexture(GL_TEXTURE_3D,gipi->tex_cache); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM1, gipi->transform_to_data * p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS1, gipi->bounds); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE1, gipi->cell_size_cache); + if (gi_probe_count>1) { + + GIProbeInstance *gipi2 = gi_probe_instance_owner.getptr(ridp[1]); + + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-7); + glBindTexture(GL_TEXTURE_3D,gipi2->tex_cache); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM2, gipi2->transform_to_data * p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS2, gipi2->bounds); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE2, gipi2->cell_size_cache); + + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, true ); + } else { + + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, false ); + } + } } @@ -1672,11 +1740,15 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,false); //state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); } else { + + state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,e->instance->gi_probe_instances.size()>0); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,!p_directional_add); state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false); @@ -1711,9 +1783,12 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } + + rebind=true; } + if (p_alpha_pass || p_directional_add) { int desired_blend_mode; if (p_directional_add) { @@ -1794,7 +1869,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } if (!(e->sort_key&RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) { - _setup_light(e); + _setup_light(e,p_view_transform); + } @@ -1837,6 +1913,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,false); } @@ -1950,6 +2027,10 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g copymem(oe,e,sizeof(RenderList::Element)); } + + if (e->instance->gi_probe_instances.size()) { + e->sort_key|=RenderList::SORT_KEY_GI_PROBES_FLAG; + } } //if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 78e8b3e47..5eb2be1cc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -526,6 +526,25 @@ public: virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass); virtual void light_instance_mark_visible(RID p_light_instance); + /* REFLECTION INSTANCE */ + + struct GIProbeInstance : public RID_Data { + RID data; + GLuint tex_cache; + Vector3 cell_size_cache; + Vector3 bounds; + Transform transform_to_data; + }; + + + + mutable RID_Owner gi_probe_instance_owner; + + virtual RID gi_probe_instance_create(); + virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data); + virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform); + virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds); + /* RENDER LIST */ struct RenderList { @@ -541,8 +560,9 @@ public: SORT_KEY_DEPTH_LAYER_SHIFT=60, SORT_KEY_UNSHADED_FLAG=uint64_t(1)<<59, SORT_KEY_NO_DIRECTIONAL_FLAG=uint64_t(1)<<58, - SORT_KEY_SHADING_SHIFT=58, - SORT_KEY_SHADING_MASK=3, + SORT_KEY_GI_PROBES_FLAG=uint64_t(1)<<57, + SORT_KEY_SHADING_SHIFT=57, + SORT_KEY_SHADING_MASK=7, SORT_KEY_MATERIAL_INDEX_SHIFT=40, SORT_KEY_GEOMETRY_INDEX_SHIFT=20, SORT_KEY_GEOMETRY_TYPE_SHIFT=15, @@ -669,7 +689,7 @@ public: _FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e); _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); - _FORCE_INLINE_ void _setup_light(RenderList::Element *e); + _FORCE_INLINE_ void _setup_light(RenderList::Element *e,const Transform& p_view_transform); void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, GLuint p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index cfa50f610..8262487f9 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1514,6 +1514,7 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { p_shader->valid=true; p_shader->version++; + } void RasterizerStorageGLES3::update_dirty_shaders() { @@ -3600,16 +3601,15 @@ void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh,int p_ ERR_FAIL_COND(multimesh->color_format==VS::MULTIMESH_COLOR_NONE); int stride = multimesh->color_floats+multimesh->xform_floats; - float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats]; + float *dataptr=&multimesh->data[stride*p_index+multimesh->xform_floats]; if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) { - union { - uint32_t colu; - float colf; - } cu; - cu.colu=p_color.to_32(); - dataptr[ 0]=cu.colf; + uint8_t *data8=(uint8_t*)dataptr; + data8[0]=CLAMP(p_color.r*255.0,0,255); + data8[1]=CLAMP(p_color.g*255.0,0,255); + data8[2]=CLAMP(p_color.b*255.0,0,255); + data8[3]=CLAMP(p_color.a*255.0,0,255); } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) { dataptr[ 0]=p_color.r; @@ -3701,7 +3701,7 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh,int p float colf; } cu; - return Color::hex(cu.colu); + return Color::hex(BSWAP32(cu.colu)); } else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) { Color c; @@ -4385,6 +4385,15 @@ float RasterizerStorageGLES3::light_get_param(RID p_light,VS::LightParam p_param return light->param[p_param]; } +Color RasterizerStorageGLES3::light_get_color(RID p_light) { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,Color()); + + return light->color; + +} + bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const { const Light * light = light_owner.getornull(p_light); @@ -4668,6 +4677,261 @@ void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color } +RID RasterizerStorageGLES3::gi_probe_create() { + + GIProbe *gip = memnew( GIProbe ); + + gip->data_width=0; + gip->data_height=0; + gip->data_depth=0; + gip->bounds=AABB(Vector3(),Vector3(1,1,1)); + gip->dynamic_range=1.0; + gip->version=1; + gip->cell_size=1.0; + + return gi_probe_owner.make_rid(gip); +} + +void RasterizerStorageGLES3::gi_probe_set_bounds(RID p_probe,const AABB& p_bounds){ + + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->bounds=p_bounds; + gip->version++; + gip->instance_change_notify(); +} +AABB RasterizerStorageGLES3::gi_probe_get_bounds(RID p_probe) const{ + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,AABB()); + + return gip->bounds; +} + +void RasterizerStorageGLES3::gi_probe_set_cell_size(RID p_probe,float p_size) { + + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->cell_size=p_size; + gip->version++; + gip->instance_change_notify(); +} + +float RasterizerStorageGLES3::gi_probe_get_cell_size(RID p_probe) const { + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,0); + + return gip->cell_size; + +} + +void RasterizerStorageGLES3::gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform) { + + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->to_cell=p_xform; +} + +Transform RasterizerStorageGLES3::gi_probe_get_to_cell_xform(RID p_probe) const { + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,Transform()); + + return gip->to_cell; + +} + + + +void RasterizerStorageGLES3::gi_probe_set_dynamic_data(RID p_probe,const DVector& p_data){ + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->dynamic_data=p_data; + gip->version++; + gip->instance_change_notify(); + +} +DVector RasterizerStorageGLES3::gi_probe_get_dynamic_data(RID p_probe) const{ + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,DVector()); + + return gip->dynamic_data; +} + +void RasterizerStorageGLES3::gi_probe_set_dynamic_range(RID p_probe,float p_range){ + + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->dynamic_range=p_range; + +} +float RasterizerStorageGLES3::gi_probe_get_dynamic_range(RID p_probe) const{ + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,0); + + return gip->dynamic_range; +} + + +void RasterizerStorageGLES3::gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth) { + + GIProbe *gip = gi_probe_owner.getornull(p_gi_probe); + ERR_FAIL_COND(!gip); + + if (gip->data.is_valid()) { + free(gip->data); + } + + gip->data=RID(); + //this is platform dependent + + gip->version++; + gip->instance_change_notify(); + +} +DVector RasterizerStorageGLES3::gi_probe_get_static_data(RID p_gi_probe) const { + + const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe); + ERR_FAIL_COND_V(!gip,DVector()); + + //platform dependent + return DVector(); +} +VS::GIProbeDataFormat RasterizerStorageGLES3::gi_probe_get_static_data_format(RID p_gi_probe) const { + + const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe); + ERR_FAIL_COND_V(!gip,VS::GI_PROBE_DATA_RGBA8); + + return gip->data_format; +} +int RasterizerStorageGLES3::gi_probe_get_static_data_width(RID p_probe) const { + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,0); + + return gip->data_width; +} +int RasterizerStorageGLES3::gi_probe_get_static_data_height(RID p_probe) const { + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,0); + return gip->data_height; +} +int RasterizerStorageGLES3::gi_probe_get_static_data_depth(RID p_probe) const { + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,0); + return gip->data_depth; +} + +RID RasterizerStorageGLES3::gi_probe_get_data(RID p_probe) { + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,RID()); + + return gip->data; +} + +uint32_t RasterizerStorageGLES3::gi_probe_get_version(RID p_probe) { + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,0); + + return gip->version; +} + +RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth) { + + GIProbeData *gipd = memnew( GIProbeData ); + + gipd->width=p_width; + gipd->height=p_height; + gipd->depth=p_depth; + + glActiveTexture(GL_TEXTURE0); + glGenTextures(1,&gipd->tex_id); + glBindTexture(GL_TEXTURE_3D,gipd->tex_id); + + int level=0; + + print_line("dyndata create"); + while(true) { + + Vector data; + data.resize(p_width*p_height*p_depth*4); + + + for(int i=0;i>=1; + p_height>>=1; + p_depth>>=1; + level++; + } + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, level); + + gipd->levels=level+1; + + return gi_probe_data_owner.make_rid(gipd); +} + +void RasterizerStorageGLES3::gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) { + + GIProbeData *gipd = gi_probe_data_owner.getornull(p_gi_probe_data); + ERR_FAIL_COND(!gipd); +/* + Vector data; + data.resize((gipd->width>>p_mipmap)*(gipd->height>>p_mipmap)*(gipd->depth>>p_mipmap)*4); + + for(int i=0;i<(gipd->width>>p_mipmap);i++) { + for(int j=0;j<(gipd->height>>p_mipmap);j++) { + for(int k=0;k<(gipd->depth>>p_mipmap);k++) { + + int ofs = (k*(gipd->height>>p_mipmap)*(gipd->width>>p_mipmap)) + j *(gipd->width>>p_mipmap) + i; + ofs*=4; + data[ofs+0]=i*0xFF/(gipd->width>>p_mipmap); + data[ofs+1]=j*0xFF/(gipd->height>>p_mipmap); + data[ofs+2]=k*0xFF/(gipd->depth>>p_mipmap); + data[ofs+3]=0xFF; + } + } + } +*/ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_3D,gipd->tex_id); + glTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,GL_RGBA,GL_UNSIGNED_BYTE,p_data); + //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data); + //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr()); + print_line("update rgba8 "+itos(p_mipmap)); +} + + + + void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); @@ -4709,6 +4973,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: inst = light_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_GI_PROBE: { + inst = gi_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; default: { if (!inst) { ERR_FAIL(); @@ -4744,6 +5012,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce inst = light_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_GI_PROBE: { + inst = gi_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; default: { if (!inst) { @@ -5395,19 +5667,27 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return VS::INSTANCE_MESH; } + if (multimesh_owner.owns(p_rid)) { return VS::INSTANCE_MULTIMESH; } + if (immediate_owner.owns(p_rid)) { return VS::INSTANCE_IMMEDIATE; } + if (light_owner.owns(p_rid)) { return VS::INSTANCE_LIGHT; } + if (reflection_probe_owner.owns(p_rid)) { return VS::INSTANCE_REFLECTION_PROBE; } + if (gi_probe_owner.owns(p_rid)) { + return VS::INSTANCE_GI_PROBE; + } + return VS::INSTANCE_NONE; } @@ -5561,6 +5841,27 @@ bool RasterizerStorageGLES3::free(RID p_rid){ reflection_probe_owner.free(p_rid); memdelete(reflection_probe); + } else if (gi_probe_owner.owns(p_rid)) { + + // delete the texture + GIProbe *gi_probe = gi_probe_owner.get(p_rid); + + if (gi_probe->data.is_valid()) { + free(gi_probe->data); + } + + gi_probe_owner.free(p_rid); + memdelete(gi_probe); + } else if (gi_probe_data_owner.owns(p_rid)) { + + // delete the texture + GIProbeData *gi_probe_data = gi_probe_data_owner.get(p_rid); + + print_line("dyndata delete"); + glDeleteTextures(1,&gi_probe_data->tex_id); + gi_probe_owner.free(p_rid); + memdelete(gi_probe_data); + } else if (canvas_occluder_owner.owns(p_rid)) { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 7802b2815..b81c3df78 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -799,6 +799,7 @@ public: virtual VS::LightType light_get_type(RID p_light) const; virtual float light_get_param(RID p_light,VS::LightParam p_param); + virtual Color light_get_color(RID p_light); virtual AABB light_get_aabb(RID p_light) const; virtual uint64_t light_get_version(RID p_light) const; @@ -868,6 +869,84 @@ public: virtual void portal_set_disable_distance(RID p_portal, float p_distance); virtual void portal_set_disabled_color(RID p_portal, const Color& p_color); + + + + + + + /* GI PROBE API */ + + struct GIProbe : public Instantiable { + + + AABB bounds; + Transform to_cell; + float cell_size; + + float dynamic_range; + + uint32_t version; + + DVector dynamic_data; + + RID data; + int data_width; + int data_height; + int data_depth; + VS::GIProbeDataFormat data_format; + + + }; + + mutable RID_Owner gi_probe_owner; + + virtual RID gi_probe_create(); + + virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds); + virtual AABB gi_probe_get_bounds(RID p_probe) const; + + virtual void gi_probe_set_cell_size(RID p_probe, float p_size); + virtual float gi_probe_get_cell_size(RID p_probe) const; + + virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform); + virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const; + + virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector& p_data); + virtual DVector gi_probe_get_dynamic_data(RID p_probe) const; + + virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range); + virtual float gi_probe_get_dynamic_range(RID p_probe) const; + + + virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth); + virtual DVector gi_probe_get_static_data(RID p_gi_probe) const; + virtual VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const; + virtual int gi_probe_get_static_data_width(RID p_probe) const; + virtual int gi_probe_get_static_data_height(RID p_probe) const; + virtual int gi_probe_get_static_data_depth(RID p_probe) const; + + virtual RID gi_probe_get_data(RID p_probe); //get data in case this is static + virtual uint32_t gi_probe_get_version(RID p_probe); + + struct GIProbeData : public RID_Data { + + int width; + int height; + int depth; + int levels; + GLuint tex_id; + + GIProbeData() { + } + }; + + mutable RID_Owner gi_probe_data_owner; + + virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth); + virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data); + + virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance); virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 61e9e37d2..bf561a7e4 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -838,6 +838,131 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta } } +#ifdef USE_GI_PROBES + +uniform mediump sampler3D gi_probe1; //texunit:-6 +uniform highp mat4 gi_probe_xform1; +uniform highp vec3 gi_probe_bounds1; +uniform highp vec3 gi_probe_cell_size1; + +uniform mediump sampler3D gi_probe2; //texunit:-7 +uniform highp mat4 gi_probe_xform2; +uniform highp vec3 gi_probe_bounds2; +uniform highp vec3 gi_probe_cell_size2; +uniform bool gi_probe2_enabled; + +vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance) { + + + float dist = dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0; + float alpha=0.0; + vec4 color = vec4(0.0); + + while(dist < max_distance && alpha < 0.95) { + float diameter = max(1.0, 2.0 * tan_half_angle * dist); + vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) ); + float a = (1.0 - alpha); + color.rgb += a * scolor.rgb; + alpha += a * scolor.a; + dist += diameter * 0.5; + } + + return color.rgb; +} + +void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, mat3 normal_mtx,vec3 ref_vec, float roughness, out vec4 out_spec, out vec4 out_diff) { + + + + vec3 probe_pos = (probe_xform * vec4(pos,1.0)).xyz; + vec3 ref_pos = (probe_xform * vec4(pos+ref_vec,1.0)).xyz; + + ref_vec = normalize(ref_pos - probe_pos); + +/* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0); + out_diff.a = 1.0; + return;*/ + //out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0); + //return; + + if (any(bvec2(any(lessThan(probe_pos,vec3(0.0))),any(greaterThan(probe_pos,bounds))))) + return; + + vec3 blendv = probe_pos/bounds * 2.0 - 1.0; + float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z)); + blend=1.0; + + //radiance + +#define MAX_CONE_DIRS 6 + vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] ( + vec3(0, 0, 1), + vec3(0.866025, 0, 0.5), + vec3(0.267617, 0.823639, 0.5), + vec3(-0.700629, 0.509037, 0.5), + vec3(-0.700629, -0.509037, 0.5), + vec3(0.267617, -0.823639, 0.5) + ); + + float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15); + + float max_distance = length(bounds); + vec3 light=vec3(0.0); + for(int i=0;i0.0) { + diff_accum.rgb/=diff_accum.a; + } + + if (spec_accum.a>0.0) { + spec_accum.rgb/=spec_accum.a; + } + + out_specular+=spec_accum.rgb; + out_ambient+=diff_accum.rgb; + +} + +#endif + + void main() { #ifdef RENDER_SHADOW_DUAL_PARABOLOID @@ -1161,21 +1286,27 @@ FRAGMENT_SHADER_CODE #endif //#USE_LIGHT_DIRECTIONAL +#ifdef USE_GI_PROBES + gi_probes_compute(vertex,normal,roughness,specular,specular_light,ambient_light); +#endif + #ifdef USE_FORWARD_LIGHTING highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0); highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0); + + for(int i=0;i0.0) { - specular_light=reflection_accum.rgb/reflection_accum.a; + specular_light+=reflection_accum.rgb/reflection_accum.a; } if (ambient_accum.a>0.0) { - ambient_light=ambient_accum.rgb/ambient_accum.a; + ambient_light+=ambient_accum.rgb/ambient_accum.a; } for(int i=0;imax) max=x1;\ + if(x2max) max=x2; + +static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox) +{ + int q; + Vector3 vmin,vmax; + for(q=0;q<=2;q++) + { + if(normal[q]>0.0f) + { + vmin[q]=-maxbox[q]; + vmax[q]=maxbox[q]; + } + else + { + vmin[q]=maxbox[q]; + vmax[q]=-maxbox[q]; + } + } + if(normal.dot(vmin)+d>0.0f) return false; + if(normal.dot(vmax)+d>=0.0f) return true; + + return false; +} + + +/*======================== X-tests ========================*/ +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a*v0.y - b*v0.z; \ + p2 = a*v2.y - b*v2.z; \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a*v0.y - b*v0.z; \ + p1 = a*v1.y - b*v1.z; \ + if(p0rad || max<-rad) return false; + +/*======================== Y-tests ========================*/ +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a*v0.x + b*v0.z; \ + p2 = -a*v2.x + b*v2.z; \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a*v0.x + b*v0.z; \ + p1 = -a*v1.x + b*v1.z; \ + if(p0rad || max<-rad) return false; + +/*======================== Z-tests ========================*/ + +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a*v1.x - b*v1.y; \ + p2 = a*v2.x - b*v2.y; \ + if(p2rad || max<-rad) return false; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a*v0.x - b*v0.y; \ + p1 = a*v1.x - b*v1.y; \ + if(p0rad || max<-rad) return false; + +static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) { + + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + Vector3 v0,v1,v2; + float min,max,d,p0,p1,p2,rad,fex,fey,fez; + Vector3 normal,e0,e1,e2; + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + + v0=triverts[0]-boxcenter; + v1=triverts[1]-boxcenter; + v2=triverts[2]-boxcenter; + + /* compute triangle edges */ + e0=v1-v0; /* tri edge 0 */ + e1=v2-v1; /* tri edge 1 */ + e2=v0-v2; /* tri edge 2 */ + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + fex = Math::abs(e0.x); + fey = Math::abs(e0.y); + fez = Math::abs(e0.z); + AXISTEST_X01(e0.z, e0.y, fez, fey); + AXISTEST_Y02(e0.z, e0.x, fez, fex); + AXISTEST_Z12(e0.y, e0.x, fey, fex); + + fex = Math::abs(e1.x); + fey = Math::abs(e1.y); + fez = Math::abs(e1.z); + AXISTEST_X01(e1.z, e1.y, fez, fey); + AXISTEST_Y02(e1.z, e1.x, fez, fex); + AXISTEST_Z0(e1.y, e1.x, fey, fex); + + fex = Math::abs(e2.x); + fey = Math::abs(e2.y); + fez = Math::abs(e2.z); + AXISTEST_X2(e2.z, e2.y, fez, fey); + AXISTEST_Y1(e2.z, e2.x, fez, fex); + AXISTEST_Z12(e2.y, e2.x, fey, fex); + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + /* test in X-direction */ + FINDMINMAX(v0.x,v1.x,v2.x,min,max); + if(min>boxhalfsize.x || max<-boxhalfsize.x) return false; + + /* test in Y-direction */ + FINDMINMAX(v0.y,v1.y,v2.y,min,max); + if(min>boxhalfsize.y || max<-boxhalfsize.y) return false; + + /* test in Z-direction */ + FINDMINMAX(v0.z,v1.z,v2.z,min,max); + if(min>boxhalfsize.z || max<-boxhalfsize.z) return false; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + normal=e0.cross(e1); + d=-normal.dot(v0); /* plane eq: normal.x+d=0 */ + if(!planeBoxOverlap(normal,d,boxhalfsize)) return false; + + return true; /* box and triangle overlaps */ +} + + +Vector BakedLight::_get_bake_texture(Image &p_image,const Color& p_color) { + + Vector ret; + + if (p_image.empty()) { + + ret.resize(bake_texture_size*bake_texture_size); + for(int i=0;i::Read r = p_image.get_data().read(); + ret.resize(bake_texture_size*bake_texture_size); + + for(int i=0;i p_material) { + + //this way of obtaining materials is inaccurate and also does not support some compressed formats very well + Ref mat = p_material; + + Ref material = mat; //hack for now + + if (material_cache.has(material)) { + return material_cache[material]; + } + + MaterialCache mc; + + if (mat.is_valid()) { + + + Ref albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO); + + Image img_albedo; + if (albedo_tex.is_valid()) { + + img_albedo = albedo_tex->get_data(); + } + + mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo()); + + Ref emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION); + + Color emission_col = mat->get_emission(); + emission_col.r*=mat->get_emission_energy(); + emission_col.g*=mat->get_emission_energy(); + emission_col.b*=mat->get_emission_energy(); + + Image img_emission; + + if (emission_tex.is_valid()) { + + img_emission = emission_tex->get_data(); + } + + mc.emission=_get_bake_texture(img_emission,emission_col); + + } else { + Image empty; + + mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7)); + mc.emission=_get_bake_texture(empty,Color(0,0,0)); + + + } + + material_cache[p_material]=mc; + return mc; + + +} + + + +static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) { + + if (p_pos.distance_squared_to(p_vtx[0])closest_dot) { + closest_axis=i; + closest_dot=dot; + } + } + + Vector3 axis; + axis[closest_axis]=1.0; + Vector3 t1; + t1[(closest_axis+1)%3]=1.0; + Vector3 t2; + t2[(closest_axis+2)%3]=1.0; + + t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width); + t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width); + + Color albedo_accum; + Color emission_accum; + float alpha=0.0; + + //map to a grid average in the best axis for this face + for(int i=0;iCMP_EPSILON) { + bake_cells_write[p_idx].used_sides|=(1<::Write(); + bake_cells.resize(1<=size || y<0 || y>=size || z<0 || z>=size) { + //neighbour is out, can't use it + bake_cells_write[p_idx].used_sides&=~(1<= ofs_x + half) { + child|=1; + ofs_x+=half; + } + if (y >= ofs_y + half) { + child|=2; + ofs_y+=half; + } + if (z >= ofs_z + half) { + child|=4; + ofs_z+=half; + } + + neighbour = bc->childs[child]; + if (neighbour==CHILD_EMPTY) { + break; + } + + half>>=1; + } + + if (neighbour!=CHILD_EMPTY) { + bake_cells_write[p_idx].used_sides&=~(1<> (p_level+1); + for(int i=0;i<8;i++) { + + uint32_t child = bake_cells_write[p_idx].childs[i]; + + if (child==CHILD_EMPTY) + continue; + + + int nx=p_x; + int ny=p_y; + int nz=p_z; + + if (i&1) + nx+=half; + if (i&2) + ny+=half; + if (i&4) + nz+=half; + + _fixup_plot(child,p_level+1,nx,ny,nz); + alpha_average+=bake_cells_write[child].alpha; + } + + bake_cells_write[p_idx].alpha=alpha_average/8.0; + bake_cells_write[p_idx].light[0]=0; + bake_cells_write[p_idx].light[1]=0; + bake_cells_write[p_idx].light[2]=0; + bake_cells_write[p_idx].albedo[0]=0; + bake_cells_write[p_idx].albedo[1]=0; + bake_cells_write[p_idx].albedo[2]=0; + + } + + //clean up light + bake_cells_write[p_idx].light_pass=0; + //find neighbours + + + +} + + +void BakedLight::_bake_add_mesh(const Transform& p_xform,Ref& p_mesh) { + + + for(int i=0;iget_surface_count();i++) { + + if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) + continue; //only triangles + + MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i)); + + Array a = p_mesh->surface_get_arrays(i); + + + DVector vertices = a[Mesh::ARRAY_VERTEX]; + DVector::Read vr=vertices.read(); + DVector uv = a[Mesh::ARRAY_TEX_UV]; + DVector::Read uvr; + DVector index = a[Mesh::ARRAY_INDEX]; + + bool read_uv=false; + + if (uv.size()) { + + uvr=uv.read(); + read_uv=true; + } + + if (index.size()) { + + int facecount = index.size()/3; + DVector::Read ir=index.read(); + + for(int j=0;j& p_mesh,bool &first) { + + for(int i=0;iget_surface_count();i++) { + + if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) + continue; //only triangles + + Array a = p_mesh->surface_get_arrays(i); + DVector vertices = a[Mesh::ARRAY_VERTEX]; + int vc = vertices.size(); + DVector::Read vr=vertices.read(); + + if (first) { + bounds.pos=p_xform.xform(vr[0]); + first=false; + } + + + for(int j=0;j::Element *E=geometries.front();E;E=E->next()) { + + print_line("aabb geom "+itos(count)+"/"+itos(geometries.size())); + + GeometryInstance *geom = E->get(); + + if (geom->cast_to()) { + + MeshInstance *mesh_instance = geom->cast_to(); + Ref mesh = mesh_instance->get_mesh(); + if (mesh.is_valid()) { + + _bake_add_to_aabb(geom->get_relative_transform(this),mesh,aabb_first); + } + } + count++; + } + + print_line("AABB: "+bounds); + ERR_FAIL_COND(aabb_first); + + bake_cells_write = bake_cells.write(); + count=0; + + for (Set::Element *E=geometries.front();E;E=E->next()) { + + GeometryInstance *geom = E->get(); + print_line("plot geom "+itos(count)+"/"+itos(geometries.size())); + + if (geom->cast_to()) { + + MeshInstance *mesh_instance = geom->cast_to(); + Ref mesh = mesh_instance->get_mesh(); + if (mesh.is_valid()) { + + _bake_add_mesh(geom->get_relative_transform(this),mesh); + } + } + + count++; + } + + + _fixup_plot(0, 0,0,0,0); + + + bake_cells_write=DVector::Write(); + + bake_cells.resize(bake_cells_used); + + + + print_line("total bake cells used: "+itos(bake_cells_used)); + for(int i=0;i=0 && light_pass!=bake_cells_write[idx].light_pass) { + //hit something, add or remove light to it + + Color albedo = Color(bake_cells_write[idx].albedo[0],bake_cells_write[idx].albedo[1],bake_cells_write[idx].albedo[2]); + bake_cells_write[idx].light[0]+=albedo.r*p_color.r*p_sign; + bake_cells_write[idx].light[1]+=albedo.g*p_color.g*p_sign; + bake_cells_write[idx].light[2]+=albedo.b*p_color.b*p_sign; + bake_cells_write[idx].light_pass=light_pass; + + } + + + } else { + + int half = cells_per_axis >> (p_level+1); + + //go down + for(int i=0;i<8;i++) { + + uint32_t child = bake_cells_write[p_idx].childs[i]; + + if (child==CHILD_EMPTY) + continue; + + int nx=p_x; + int ny=p_y; + int nz=p_z; + + if (i&1) + nx+=half; + if (i&2) + ny+=half; + if (i&4) + nz+=half; + + + _bake_directional(child,p_level+1,nx,ny,nz,p_dir,p_color,p_sign); + } + } +} + + + + +void BakedLight::_bake_light(Light* p_light) { + + if (p_light->cast_to()) { + + DirectionalLight * dl = p_light->cast_to(); + + Transform rel_xf = dl->get_relative_transform(this); + + Vector3 light_dir = -rel_xf.basis.get_axis(2); + + Color color = dl->get_color(); + float nrg = dl->get_param(Light::PARAM_ENERGY);; + color.r*=nrg; + color.g*=nrg; + color.b*=nrg; + + light_pass++; + _bake_directional(0,0,0,0,0,light_dir,color,1); + + } +} + + +void BakedLight::_upscale_light(int p_idx,int p_level) { + + + //go down + + float light_accum[3]={0,0,0}; + float alpha_accum=0; + + bool check_children = p_level < (cell_subdiv -2); + + for(int i=0;i<8;i++) { + + uint32_t child = bake_cells_write[p_idx].childs[i]; + + if (child==CHILD_EMPTY) + continue; + + if (check_children) { + _upscale_light(child,p_level+1); + } + + light_accum[0]+=bake_cells_write[child].light[0]; + light_accum[1]+=bake_cells_write[child].light[1]; + light_accum[2]+=bake_cells_write[child].light[2]; + alpha_accum+=bake_cells_write[child].alpha; + + } + + bake_cells_write[p_idx].light[0]=light_accum[0]/8.0; + bake_cells_write[p_idx].light[1]=light_accum[1]/8.0; + bake_cells_write[p_idx].light[2]=light_accum[2]/8.0; + bake_cells_write[p_idx].alpha=alpha_accum/8.0; + +} + + +void BakedLight::bake_lights() { + + ERR_FAIL_COND(bake_cells.size()==0); + + bake_cells_write = bake_cells.write(); + + for(Set::Element *E=lights.front();E;E=E->next()) { + + _bake_light(E->get()); + } + + + _upscale_light(0,0); + + bake_cells_write=DVector::Write(); + +} + + + +Color BakedLight::_cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle) { + + + Color color(0,0,0,0); + float tha = Math::tan(p_half_angle);//tan half angle + Vector3 from =(p_from-bounds.pos)/bounds.size; //convert to 0..1 + from/=cells_per_axis; //convert to voxels of size 1 + Vector3 dir = (p_dir/bounds.size).normalized(); + + float max_dist = Vector3(cells_per_axis,cells_per_axis,cells_per_axis).length(); + + float dist = 1.0; + // self occlusion in flat surfaces + + float alpha=0; + + + while(dist < max_dist && alpha < 0.95) { + +#if 0 + // smallest sample diameter possible is the voxel size + float diameter = MAX(1.0, 2.0 * tha * dist); + float lod = log2(diameter); + + Vector3 sample_pos = from + dist * dir; + + + Color samples_base[2][8]={{Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)}, + {Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)}}; + + float levelf = Math::fposmod(lod,1.0); + float fx = Math::fposmod(sample_pos.x,1.0); + float fy = Math::fposmod(sample_pos.y,1.0); + float fz = Math::fposmod(sample_pos.z,1.0); + + for(int l=0;l<2;l++){ + + int bx = Math::floor(sample_pos.x); + int by = Math::floor(sample_pos.y); + int bz = Math::floor(sample_pos.z); + + int lodn=int(Math::floor(lod))-l; + + bx>>=lodn; + by>>=lodn; + bz>>=lodn; + + int limit = MAX(0,cell_subdiv-lodn-1); + + for(int c=0;c<8;c++) { + + int x = bx; + int y = by; + int z = bz; + + if (c&1) { + x+=1; + } + if (c&2) { + y+=1; + } + if (c&4) { + z+=1; + } + + int ofs_x=0; + int ofs_y=0; + int ofs_z=0; + int size = cells_per_axis>>lodn; + int half=size/2; + + bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size; + + if (outside) + continue; + + + uint32_t cell=0; + + for(int i=0;i= ofs_x + half) { + child|=1; + ofs_x+=half; + } + if (y >= ofs_y + half) { + child|=2; + ofs_y+=half; + } + if (z >= ofs_z + half) { + child|=4; + ofs_z+=half; + } + + cell = bc->childs[child]; + if (cell==CHILD_EMPTY) + break; + + half>>=1; + } + + if (cell!=CHILD_EMPTY) { + + samples_base[l][c].r=bake_cells_write[cell].light[0]; + samples_base[l][c].g=bake_cells_write[cell].light[1]; + samples_base[l][c].b=bake_cells_write[cell].light[2]; + samples_base[l][c].a=bake_cells_write[cell].alpha; + } + + } + + + } + + Color m0x0 = samples_base[0][0].linear_interpolate(samples_base[0][1],fx); + Color m0x1 = samples_base[0][2].linear_interpolate(samples_base[0][3],fx); + Color m0y0 = m0x0.linear_interpolate(m0x1,fy); + m0x0 = samples_base[0][4].linear_interpolate(samples_base[0][5],fx); + m0x1 = samples_base[0][6].linear_interpolate(samples_base[0][7],fx); + Color m0y1 = m0x0.linear_interpolate(m0x1,fy); + Color m0z = m0y0.linear_interpolate(m0y1,fz); + + Color m1x0 = samples_base[1][0].linear_interpolate(samples_base[1][1],fx); + Color m1x1 = samples_base[1][2].linear_interpolate(samples_base[1][3],fx); + Color m1y0 = m1x0.linear_interpolate(m1x1,fy); + m1x0 = samples_base[1][4].linear_interpolate(samples_base[1][5],fx); + m1x1 = samples_base[1][6].linear_interpolate(samples_base[1][7],fx); + Color m1y1 = m1x0.linear_interpolate(m1x1,fy); + Color m1z = m1y0.linear_interpolate(m1y1,fz); + + Color m = m0z.linear_interpolate(m1z,levelf); +#else + float diameter = 1.0; + Vector3 sample_pos = from + dist * dir; + + Color m(0,0,0,0); + { + int x = Math::floor(sample_pos.x); + int y = Math::floor(sample_pos.y); + int z = Math::floor(sample_pos.z); + + int ofs_x=0; + int ofs_y=0; + int ofs_z=0; + int size = cells_per_axis; + int half=size/2; + + bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size; + + if (!outside) { + + + uint32_t cell=0; + + for(int i=0;i= ofs_x + half) { + child|=1; + ofs_x+=half; + } + if (y >= ofs_y + half) { + child|=2; + ofs_y+=half; + } + if (z >= ofs_z + half) { + child|=4; + ofs_z+=half; + } + + cell = bc->childs[child]; + if (cell==CHILD_EMPTY) + break; + + half>>=1; + } + + if (cell!=CHILD_EMPTY) { + + m.r=bake_cells_write[cell].light[0]; + m.g=bake_cells_write[cell].light[1]; + m.b=bake_cells_write[cell].light[2]; + m.a=bake_cells_write[cell].alpha; + } + } + } + +#endif + // front-to-back compositing + float a = (1.0 - alpha); + color.r += a * m.r; + color.g += a * m.g; + color.b += a * m.b; + alpha += a * m.a; + //occlusion += a * voxelColor.a; + //occlusion += (a * voxelColor.a) / (1.0 + 0.03 * diameter); + dist += diameter * 0.5; // smoother + //dist += diameter; // faster but misses more voxels + } + + return color; +} + + + +void BakedLight::_bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z) { + + + + + if (p_level==cell_subdiv-1) { + + const int NUM_CONES = 6; + Vector3 cone_directions[6] = { + Vector3(1, 0, 0), + Vector3(0.5, 0.866025, 0), + Vector3( 0.5, 0.267617, 0.823639), + Vector3( 0.5, -0.700629, 0.509037), + Vector3( 0.5, -0.700629, -0.509037), + Vector3( 0.5, 0.267617, -0.823639) + }; + float coneWeights[6] = {0.25, 0.15, 0.15, 0.15, 0.15, 0.15}; + + Vector3 pos = (Vector3(p_x,p_y,p_z)/float(cells_per_axis))*bounds.size+bounds.pos; + Vector3 voxel_size = bounds.size/float(cells_per_axis); + pos+=voxel_size*0.5; + + Color accum; + + bake_cells_write[p_idx].light[0]=0; + bake_cells_write[p_idx].light[1]=0; + bake_cells_write[p_idx].light[2]=0; + + int freepix=0; + for(int i=0;i<6;i++) { + + if (!(bake_cells_write[p_idx].used_sides&(1<> (p_level+1); + + //go down + for(int i=0;i<8;i++) { + + uint32_t child = bake_cells_write[p_idx].childs[i]; + + if (child==CHILD_EMPTY) + continue; + + int nx=p_x; + int ny=p_y; + int nz=p_z; + + if (i&1) + nx+=half; + if (i&2) + ny+=half; + if (i&4) + nz+=half; + + + _bake_radiance(child,p_level+1,nx,ny,nz); + } + } +} + +void BakedLight::bake_radiance() { + + ERR_FAIL_COND(bake_cells.size()==0); + + bake_cells_write = bake_cells.write(); + + _bake_radiance(0,0,0,0,0); + + bake_cells_write=DVector::Write(); -RID BakedLightInstance::get_baked_light_instance() const { +} +int BakedLight::_find_cell(int x,int y, int z) { + + + uint32_t cell=0; + + int ofs_x=0; + int ofs_y=0; + int ofs_z=0; + int size = cells_per_axis; + int half=size/2; + + if (x<0 || x>=size) + return -1; + if (y<0 || y>=size) + return -1; + if (z<0 || z>=size) + return -1; + + for(int i=0;i= ofs_x + half) { + child|=1; + ofs_x+=half; + } + if (y >= ofs_y + half) { + child|=2; + ofs_y+=half; + } + if (z >= ofs_z + half) { + child|=4; + ofs_z+=half; + } - if (baked_light.is_null()) - return RID(); - else - return get_instance(); + cell = bc->childs[child]; + if (cell==CHILD_EMPTY) + return -1; + + half>>=1; + } + + return cell; } -void BakedLightInstance::set_baked_light(const Ref& p_baked_light) { - baked_light=p_baked_light; +int BakedLight::_plot_ray(const Vector3& p_from, const Vector3& p_to) { + + Vector3 from = (p_from - bounds.pos) / bounds.size; + Vector3 to = (p_to - bounds.pos) / bounds.size; - RID base_rid; + int x1 = Math::floor(from.x*cells_per_axis); + int y1 = Math::floor(from.y*cells_per_axis); + int z1 = Math::floor(from.z*cells_per_axis); - if (baked_light.is_valid()) - base_rid=baked_light->get_rid(); - else - base_rid=RID(); + int x2 = Math::floor(to.x*cells_per_axis); + int y2 = Math::floor(to.y*cells_per_axis); + int z2 = Math::floor(to.z*cells_per_axis); - set_base(base_rid); - if (is_inside_world()) { + int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; + int point[3]; - emit_signal(SceneStringNames::get_singleton()->baked_light_changed); + point[0] = x1; + point[1] = y1; + point[2] = z1; + dx = x2 - x1; + dy = y2 - y1; + dz = z2 - z1; + x_inc = (dx < 0) ? -1 : 1; + l = ABS(dx); + y_inc = (dy < 0) ? -1 : 1; + m = ABS(dy); + z_inc = (dz < 0) ? -1 : 1; + n = ABS(dz); + dx2 = l << 1; + dy2 = m << 1; + dz2 = n << 1; -// for (List::Element *E=baked_geometry.front();E;E=E->next()) { -// VS::get_singleton()->instance_geometry_set_baked_light(E->get()->get_instance(),baked_light.is_valid()?get_instance():RID()); -// } + if ((l >= m) && (l >= n)) { + err_1 = dy2 - l; + err_2 = dz2 - l; + for (i = 0; i < l; i++) { + int cell = _find_cell(point[0],point[1],point[2]); + if (cell>=0) + return cell; + + if (err_1 > 0) { + point[1] += y_inc; + err_1 -= dx2; + } + if (err_2 > 0) { + point[2] += z_inc; + err_2 -= dx2; + } + err_1 += dy2; + err_2 += dz2; + point[0] += x_inc; + } + } else if ((m >= l) && (m >= n)) { + err_1 = dx2 - m; + err_2 = dz2 - m; + for (i = 0; i < m; i++) { + int cell = _find_cell(point[0],point[1],point[2]); + if (cell>=0) + return cell; + if (err_1 > 0) { + point[0] += x_inc; + err_1 -= dy2; + } + if (err_2 > 0) { + point[2] += z_inc; + err_2 -= dy2; + } + err_1 += dx2; + err_2 += dz2; + point[1] += y_inc; + } + } else { + err_1 = dy2 - n; + err_2 = dx2 - n; + for (i = 0; i < n; i++) { + int cell = _find_cell(point[0],point[1],point[2]); + if (cell>=0) + return cell; + + if (err_1 > 0) { + point[1] += y_inc; + err_1 -= dz2; + } + if (err_2 > 0) { + point[0] += x_inc; + err_2 -= dz2; + } + err_1 += dy2; + err_2 += dx2; + point[2] += z_inc; + } } + return _find_cell(point[0],point[1],point[2]); + +} - update_configuration_warning(); + +void BakedLight::set_cell_subdiv(int p_subdiv) { + + cell_subdiv=p_subdiv; + +// VS::get_singleton()->baked_light_set_subdivision(baked_light,p_subdiv); } -Ref BakedLightInstance::get_baked_light() const{ +int BakedLight::get_cell_subdiv() const { - return baked_light; + return cell_subdiv; } -AABB BakedLightInstance::get_aabb() const { + + +AABB BakedLight::get_aabb() const { return AABB(Vector3(0,0,0),Vector3(1,1,1)); } -DVector BakedLightInstance::get_faces(uint32_t p_usage_flags) const { +DVector BakedLight::get_faces(uint32_t p_usage_flags) const { return DVector(); } -String BakedLightInstance::get_configuration_warning() const { - if (get_baked_light().is_null()) { - return TTR("BakedLightInstance does not contain a BakedLight resource."); - } +String BakedLight::get_configuration_warning() const { return String(); } -void BakedLightInstance::_bind_methods() { +void BakedLight::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref &p_multimesh,int &idx) { + + + if (p_level==cell_subdiv-1) { + + Vector3 center = p_aabb.pos+p_aabb.size*0.5; + Transform xform; + xform.origin=center; + xform.basis.scale(p_aabb.size*0.5); + p_multimesh->set_instance_transform(idx,xform); + Color col; + switch(p_mode) { + case DEBUG_ALBEDO: { + col=Color(bake_cells_write[p_idx].albedo[0],bake_cells_write[p_idx].albedo[1],bake_cells_write[p_idx].albedo[2]); + } break; + case DEBUG_LIGHT: { + col=Color(bake_cells_write[p_idx].light[0],bake_cells_write[p_idx].light[1],bake_cells_write[p_idx].light[2]); + Color colr=Color(bake_cells_write[p_idx].radiance[0],bake_cells_write[p_idx].radiance[1],bake_cells_write[p_idx].radiance[2]); + col.r+=colr.r; + col.g+=colr.g; + col.b+=colr.b; + } break; + + } + p_multimesh->set_instance_color(idx,col); + + + idx++; + + } else { + + for(int i=0;i<8;i++) { + + if (bake_cells_write[p_idx].childs[i]==CHILD_EMPTY) + continue; + + AABB aabb=p_aabb; + aabb.size*=0.5; + + if (i&1) + aabb.pos.x+=aabb.size.x; + if (i&2) + aabb.pos.y+=aabb.size.y; + if (i&4) + aabb.pos.z+=aabb.size.z; + + _debug_mesh(bake_cells_write[p_idx].childs[i],p_level+1,aabb,p_mode,p_multimesh,idx); + } + + } + +} + + +void BakedLight::create_debug_mesh(DebugMode p_mode) { + + Ref mm; + mm.instance(); + + mm->set_transform_format(MultiMesh::TRANSFORM_3D); + mm->set_color_format(MultiMesh::COLOR_8BIT); + mm->set_instance_count(bake_cells_level_used[cell_subdiv-1]); + + Ref mesh; + mesh.instance(); + + + + { + Array arr; + arr.resize(Mesh::ARRAY_MAX); + + DVector vertices; + DVector colors; + + int vtx_idx=0; + #define ADD_VTX(m_idx);\ + vertices.push_back( face_points[m_idx] );\ + colors.push_back( Color(1,1,1,1) );\ + vtx_idx++;\ + + for (int i=0;i<6;i++) { + + + Vector3 face_points[4]; + + for (int j=0;j<4;j++) { + + float v[3]; + v[0]=1.0; + v[1]=1-2*((j>>1)&1); + v[2]=v[1]*(1-2*(j&1)); + + for (int k=0;k<3;k++) { + + if (i<3) + face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1); + else + face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1); + } + } + + //tri 1 + ADD_VTX(0); + ADD_VTX(1); + ADD_VTX(2); + //tri 2 + ADD_VTX(2); + ADD_VTX(3); + ADD_VTX(0); + + } + + + arr[Mesh::ARRAY_VERTEX]=vertices; + arr[Mesh::ARRAY_COLOR]=colors; + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr); + } + + { + Ref fsm; + fsm.instance(); + fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true); + fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); + fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + fsm->set_albedo(Color(1,1,1,1)); + + mesh->surface_set_material(0,fsm); + } + + mm->set_mesh(mesh); + + + bake_cells_write = bake_cells.write(); + + + + int idx=0; + _debug_mesh(0,0,bounds,p_mode,mm,idx); + + print_line("written: "+itos(idx)+" total: "+itos(bake_cells_level_used[cell_subdiv-1])); + + + MultiMeshInstance *mmi = memnew( MultiMeshInstance ); + mmi->set_multimesh(mm); + add_child(mmi); + if (get_tree()->get_edited_scene_root()==this){ + mmi->set_owner(this); + } else { + mmi->set_owner(get_owner()); + + } + +} + +void BakedLight::_debug_mesh_albedo() { + create_debug_mesh(DEBUG_ALBEDO); +} + +void BakedLight::_debug_mesh_light() { + create_debug_mesh(DEBUG_LIGHT); +} + + +void BakedLight::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_cell_subdiv","steps"),&BakedLight::set_cell_subdiv); + ObjectTypeDB::bind_method(_MD("get_cell_subdiv"),&BakedLight::get_cell_subdiv); + + ObjectTypeDB::bind_method(_MD("bake"),&BakedLight::bake); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + + ObjectTypeDB::bind_method(_MD("bake_lights"),&BakedLight::bake_lights); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_lights"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + + ObjectTypeDB::bind_method(_MD("bake_radiance"),&BakedLight::bake_radiance); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_radiance"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + + ObjectTypeDB::bind_method(_MD("debug_mesh_albedo"),&BakedLight::_debug_mesh_albedo); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_albedo"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + - ObjectTypeDB::bind_method(_MD("set_baked_light","baked_light"),&BakedLightInstance::set_baked_light); - ObjectTypeDB::bind_method(_MD("get_baked_light"),&BakedLightInstance::get_baked_light); - ObjectTypeDB::bind_method(_MD("get_baked_light_instance"),&BakedLightInstance::get_baked_light_instance); + ObjectTypeDB::bind_method(_MD("debug_mesh_light"),&BakedLight::_debug_mesh_light); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_light"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"baked_light",PROPERTY_HINT_RESOURCE_TYPE,"BakedLight"),_SCS("set_baked_light"),_SCS("get_baked_light")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"cell_subdiv"),_SCS("set_cell_subdiv"),_SCS("get_cell_subdiv")); ADD_SIGNAL( MethodInfo("baked_light_changed")); + } -BakedLightInstance::BakedLightInstance() { +BakedLight::BakedLight() { +// baked_light=VisualServer::get_singleton()->baked_light_create(); + VS::get_singleton()->instance_set_base(get_instance(),baked_light); + cell_subdiv=8; + bake_texture_size=128; + color_scan_cell_width=8; + light_pass=0; } -///////////////////////// +BakedLight::~BakedLight() { + + VS::get_singleton()->free(baked_light); +} + +///////////////////////// + +#if 0 void BakedLightSampler::set_param(Param p_param,float p_value) { ERR_FAIL_INDEX(p_param,PARAM_MAX); params[p_param]=p_value; diff --git a/scene/3d/baked_light_instance.h b/scene/3d/baked_light_instance.h index 15f04fea3..314e5f145 100644 --- a/scene/3d/baked_light_instance.h +++ b/scene/3d/baked_light_instance.h @@ -31,38 +31,142 @@ #include "scene/3d/visual_instance.h" #include "scene/resources/baked_light.h" +#include "scene/3d/multimesh_instance.h" + -#if 0 class BakedLightBaker; +class Light; + +class BakedLight : public VisualInstance { + OBJ_TYPE(BakedLight,VisualInstance); + +public: + enum DebugMode { + DEBUG_ALBEDO, + DEBUG_LIGHT + }; + +private: + RID baked_light; + int cell_subdiv; + AABB bounds; + int cells_per_axis; + + enum { + CHILD_EMPTY=0xFFFFFFFF, + }; + + + /* BAKE DATA */ + + struct BakeCell { + + uint32_t childs[8]; + float albedo[3]; //albedo in RGB24 + float light[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) + float radiance[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) + uint32_t used_sides; + float alpha; //used for upsampling + uint32_t light_pass; //used for baking light + + BakeCell() { + for(int i=0;i<8;i++) { + childs[i]=0xFFFFFFFF; + } + + for(int i=0;i<3;i++) { + light[i]=0; + albedo[i]=0; + radiance[i]=0; + } + alpha=0; + light_pass=0; + used_sides=0; + } + }; + + + int bake_texture_size; + int color_scan_cell_width; + + struct MaterialCache { + //128x128 textures + Vector albedo; + Vector emission; + }; + + Vector _get_bake_texture(Image &p_image, const Color &p_color); -class BakedLightInstance : public VisualInstance { - OBJ_TYPE(BakedLightInstance,VisualInstance); - Ref baked_light; + Map,MaterialCache> material_cache; + MaterialCache _get_material_cache(Ref p_material); + int bake_cells_alloc; + int bake_cells_used; + int zero_alphas; + Vector bake_cells_level_used; + DVector bake_cells; + DVector::Write bake_cells_write; + + + + void _plot_face(int p_idx,int p_level,const Vector3 *p_vtx,const Vector2* p_uv, const MaterialCache& p_material,const AABB& p_aabb); + void _fixup_plot(int p_idx, int p_level, int p_x, int p_y, int p_z); + void _bake_add_mesh(const Transform& p_xform,Ref& p_mesh); + void _bake_add_to_aabb(const Transform& p_xform,Ref& p_mesh,bool &first); + + void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref &p_multimesh,int &idx); + void _debug_mesh_albedo(); + void _debug_mesh_light(); + + + _FORCE_INLINE_ int _find_cell(int x,int y, int z); + int _plot_ray(const Vector3& p_from, const Vector3& p_to); + + uint32_t light_pass; + + + void _bake_directional(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3& p_dir,const Color& p_color,int p_sign); + void _upscale_light(int p_idx,int p_level); + void _bake_light(Light* p_light); + + Color _cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle); + void _bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z); + +friend class GeometryInstance; + + Set geometries; +friend class Light; + + Set lights; protected: static void _bind_methods(); public: + void set_cell_subdiv(int p_subdiv); + int get_cell_subdiv() const; + + void bake(); + void bake_lights(); + void bake_radiance(); - RID get_baked_light_instance() const; - void set_baked_light(const Ref& baked_light); - Ref get_baked_light() const; + void create_debug_mesh(DebugMode p_mode); virtual AABB get_aabb() const; virtual DVector get_faces(uint32_t p_usage_flags) const; String get_configuration_warning() const; - BakedLightInstance(); + BakedLight(); + ~BakedLight(); }; - +#if 0 class BakedLightSampler : public VisualInstance { OBJ_TYPE(BakedLightSampler,VisualInstance); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp new file mode 100644 index 000000000..ce360859d --- /dev/null +++ b/scene/3d/gi_probe.cpp @@ -0,0 +1,1248 @@ +#include "gi_probe.h" +#include "mesh_instance.h" + +enum DataFormat { + DATA_RGBA8, + DATA_DXT5, + DATA_ETC2_EAC, +}; + + +void GIProbeData::set_bounds(const AABB& p_bounds) { + + VS::get_singleton()->gi_probe_set_bounds(probe,p_bounds); +} + +AABB GIProbeData::get_bounds() const{ + + return VS::get_singleton()->gi_probe_get_bounds(probe); +} + +void GIProbeData::set_cell_size(float p_size) { + + VS::get_singleton()->gi_probe_set_cell_size(probe,p_size); + +} + +float GIProbeData::get_cell_size() const { + + return VS::get_singleton()->gi_probe_get_cell_size(probe); + +} + +void GIProbeData::set_to_cell_xform(const Transform& p_xform) { + + VS::get_singleton()->gi_probe_set_to_cell_xform(probe,p_xform); + +} + +Transform GIProbeData::get_to_cell_xform() const { + + return VS::get_singleton()->gi_probe_get_to_cell_xform(probe); + +} + + +void GIProbeData::set_dynamic_data(const DVector& p_data){ + + VS::get_singleton()->gi_probe_set_dynamic_data(probe,p_data); + +} +DVector GIProbeData::get_dynamic_data() const{ + + return VS::get_singleton()->gi_probe_get_dynamic_data(probe); +} + +void GIProbeData::set_dynamic_range(float p_range){ + + VS::get_singleton()->gi_probe_set_dynamic_range(probe,p_range); + +} +float GIProbeData::get_dynamic_range() const{ + + + return VS::get_singleton()->gi_probe_get_dynamic_range(probe); +} + +void GIProbeData::set_static_data(const DVector& p_data,DataFormat p_format,int p_width,int p_height,int p_depth){ + + VS::get_singleton()->gi_probe_set_static_data(probe,p_data,VS::GIProbeDataFormat(p_format),p_width,p_height,p_depth); + +} +DVector GIProbeData::get_static_data() const{ + + return VS::get_singleton()->gi_probe_get_static_data(probe); + +} +GIProbeData::DataFormat GIProbeData::get_static_data_format() const{ + + return GIProbeData::DataFormat(VS::get_singleton()->gi_probe_get_static_data_format(probe)); + +} +int GIProbeData::get_static_data_width() const{ + + return VS::get_singleton()->gi_probe_get_static_data_width(probe); + +} +int GIProbeData::get_static_data_height() const{ + + return VS::get_singleton()->gi_probe_get_static_data_height(probe); + +} +int GIProbeData::get_static_data_depth() const{ + + return VS::get_singleton()->gi_probe_get_static_data_depth(probe); + +} + +RID GIProbeData::get_rid() const { + + return probe; +} + +GIProbeData::GIProbeData() { + + probe=VS::get_singleton()->gi_probe_create(); +} + +GIProbeData::~GIProbeData() { + + VS::get_singleton()->free(probe); +} + + +////////////////////// +////////////////////// + + +void GIProbe::set_probe_data(const Ref& p_data) { + + if (p_data.is_valid()) { + VS::get_singleton()->instance_set_base(get_instance(),p_data->get_rid()); + } else { + VS::get_singleton()->instance_set_base(get_instance(),RID()); + } + + probe_data=p_data; +} + +Ref GIProbe::get_probe_data() const { + + return probe_data; +} + +void GIProbe::set_subdiv(Subdiv p_subdiv) { + + ERR_FAIL_INDEX(p_subdiv,SUBDIV_MAX); + subdiv=p_subdiv; + update_gizmo(); +} + +GIProbe::Subdiv GIProbe::get_subdiv() const { + + return subdiv; +} + +void GIProbe::set_extents(const Vector3& p_extents) { + + extents=p_extents; + update_gizmo(); +} + +Vector3 GIProbe::get_extents() const { + + return extents; +} + +void GIProbe::set_dynamic_range(float p_dynamic_range) { + + dynamic_range=p_dynamic_range; +} +float GIProbe::get_dynamic_range() const { + + return dynamic_range; +} + +#include "math.h" + +#define FINDMINMAX(x0,x1,x2,min,max) \ + min = max = x0; \ + if(x1max) max=x1;\ + if(x2max) max=x2; + +static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox) +{ + int q; + Vector3 vmin,vmax; + for(q=0;q<=2;q++) + { + if(normal[q]>0.0f) + { + vmin[q]=-maxbox[q]; + vmax[q]=maxbox[q]; + } + else + { + vmin[q]=maxbox[q]; + vmax[q]=-maxbox[q]; + } + } + if(normal.dot(vmin)+d>0.0f) return false; + if(normal.dot(vmax)+d>=0.0f) return true; + + return false; +} + + +/*======================== X-tests ========================*/ +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a*v0.y - b*v0.z; \ + p2 = a*v2.y - b*v2.z; \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a*v0.y - b*v0.z; \ + p1 = a*v1.y - b*v1.z; \ + if(p0rad || max<-rad) return false; + +/*======================== Y-tests ========================*/ +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a*v0.x + b*v0.z; \ + p2 = -a*v2.x + b*v2.z; \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a*v0.x + b*v0.z; \ + p1 = -a*v1.x + b*v1.z; \ + if(p0rad || max<-rad) return false; + +/*======================== Z-tests ========================*/ + +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a*v1.x - b*v1.y; \ + p2 = a*v2.x - b*v2.y; \ + if(p2rad || max<-rad) return false; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a*v0.x - b*v0.y; \ + p1 = a*v1.x - b*v1.y; \ + if(p0rad || max<-rad) return false; + +static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) { + + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + Vector3 v0,v1,v2; + float min,max,d,p0,p1,p2,rad,fex,fey,fez; + Vector3 normal,e0,e1,e2; + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + + v0=triverts[0]-boxcenter; + v1=triverts[1]-boxcenter; + v2=triverts[2]-boxcenter; + + /* compute triangle edges */ + e0=v1-v0; /* tri edge 0 */ + e1=v2-v1; /* tri edge 1 */ + e2=v0-v2; /* tri edge 2 */ + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + fex = Math::abs(e0.x); + fey = Math::abs(e0.y); + fez = Math::abs(e0.z); + AXISTEST_X01(e0.z, e0.y, fez, fey); + AXISTEST_Y02(e0.z, e0.x, fez, fex); + AXISTEST_Z12(e0.y, e0.x, fey, fex); + + fex = Math::abs(e1.x); + fey = Math::abs(e1.y); + fez = Math::abs(e1.z); + AXISTEST_X01(e1.z, e1.y, fez, fey); + AXISTEST_Y02(e1.z, e1.x, fez, fex); + AXISTEST_Z0(e1.y, e1.x, fey, fex); + + fex = Math::abs(e2.x); + fey = Math::abs(e2.y); + fez = Math::abs(e2.z); + AXISTEST_X2(e2.z, e2.y, fez, fey); + AXISTEST_Y1(e2.z, e2.x, fez, fex); + AXISTEST_Z12(e2.y, e2.x, fey, fex); + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + /* test in X-direction */ + FINDMINMAX(v0.x,v1.x,v2.x,min,max); + if(min>boxhalfsize.x || max<-boxhalfsize.x) return false; + + /* test in Y-direction */ + FINDMINMAX(v0.y,v1.y,v2.y,min,max); + if(min>boxhalfsize.y || max<-boxhalfsize.y) return false; + + /* test in Z-direction */ + FINDMINMAX(v0.z,v1.z,v2.z,min,max); + if(min>boxhalfsize.z || max<-boxhalfsize.z) return false; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + normal=e0.cross(e1); + d=-normal.dot(v0); /* plane eq: normal.x+d=0 */ + if(!planeBoxOverlap(normal,d,boxhalfsize)) return false; + + return true; /* box and triangle overlaps */ +} + + + +static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) { + + if (p_pos.distance_squared_to(p_vtx[0])cell_subdiv-1) { + //plot the face by guessing it's albedo and emission value + + //find best axis to map to, for scanning values + int closest_axis; + float closest_dot; + + Vector3 normal = Plane(p_vtx[0],p_vtx[1],p_vtx[2]).normal; + + for(int i=0;i<3;i++) { + + Vector3 axis; + axis[i]=1.0; + float dot=ABS(normal.dot(axis)); + if (i==0 || dot>closest_dot) { + closest_axis=i; + closest_dot=dot; + } + } + + Vector3 axis; + axis[closest_axis]=1.0; + Vector3 t1; + t1[(closest_axis+1)%3]=1.0; + Vector3 t2; + t2[(closest_axis+2)%3]=1.0; + + t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width); + t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width); + + Color albedo_accum; + Color emission_accum; + float alpha=0.0; + + //map to a grid average in the best axis for this face + for(int i=0;ibake_cells[p_idx].albedo[0]+=albedo_accum.r; + p_baker->bake_cells[p_idx].albedo[1]+=albedo_accum.g; + p_baker->bake_cells[p_idx].albedo[2]+=albedo_accum.b; + p_baker->bake_cells[p_idx].emission[0]+=emission_accum.r; + p_baker->bake_cells[p_idx].emission[1]+=emission_accum.g; + p_baker->bake_cells[p_idx].emission[2]+=emission_accum.b; + p_baker->bake_cells[p_idx].alpha+=alpha; + + static const Vector3 side_normals[6]={ + Vector3(-1, 0, 0), + Vector3( 1, 0, 0), + Vector3( 0,-1, 0), + Vector3( 0, 1, 0), + Vector3( 0, 0,-1), + Vector3( 0, 0, 1), + }; + + for(int i=0;i<6;i++) { + if (normal.dot(side_normals[i])>CMP_EPSILON) { + p_baker->bake_cells[p_idx].used_sides|=(1<cell_subdiv-1)) >> (p_level+1); + for(int i=0;i<8;i++) { + + AABB aabb=p_aabb; + aabb.size*=0.5; + + int nx=p_x; + int ny=p_y; + int nz=p_z; + + if (i&1) { + aabb.pos.x+=aabb.size.x; + nx+=half; + } + if (i&2) { + aabb.pos.y+=aabb.size.y; + ny+=half; + } + if (i&4) { + aabb.pos.z+=aabb.size.z; + nz+=half; + } + //make sure to not plot beyond limits + if (nx<0 || nx>=p_baker->axis_cell_size[0] || ny<0 || ny>=p_baker->axis_cell_size[1] || nz<0 || nz>=p_baker->axis_cell_size[2]) + continue; + + { + AABB test_aabb=aabb; + //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time + Vector3 qsize = test_aabb.size*0.5; //quarter size, for fast aabb test + + if (!fast_tri_box_overlap(test_aabb.pos+qsize,qsize,p_vtx)) { + //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) { + //does not fit in child, go on + continue; + } + + } + + if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) { + //sub cell must be created + + p_baker->bake_cells[p_idx].childs[i]=p_baker->bake_cells.size(); + p_baker->bake_cells.resize( p_baker->bake_cells.size() + 1); + + } + + + _plot_face(p_baker->bake_cells[p_idx].childs[i],p_level+1,nx,ny,nz,p_vtx,p_uv,p_material,aabb,p_baker); + } + } +} + + + +void GIProbe::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker) { + + + + if (p_level==p_baker->cell_subdiv-1) { + + p_baker->leaf_voxel_count++; + float alpha = p_baker->bake_cells[p_idx].alpha; + + p_baker->bake_cells[p_idx].albedo[0]/=alpha; + p_baker->bake_cells[p_idx].albedo[1]/=alpha; + p_baker->bake_cells[p_idx].albedo[2]/=alpha; + + //transfer emission to light + p_baker->bake_cells[p_idx].emission[0]/=alpha; + p_baker->bake_cells[p_idx].emission[1]/=alpha; + p_baker->bake_cells[p_idx].emission[2]/=alpha; + + p_baker->bake_cells[p_idx].alpha=1.0; + + //remove neighbours from used sides + + for(int n=0;n<6;n++) { + + int ofs[3]={0,0,0}; + + ofs[n/2]=(n&1)?1:-1; + + //convert to x,y,z on this level + int x=p_x; + int y=p_y; + int z=p_z; + + x+=ofs[0]; + y+=ofs[1]; + z+=ofs[2]; + + int ofs_x=0; + int ofs_y=0; + int ofs_z=0; + int size = 1<=size || y<0 || y>=size || z<0 || z>=size) { + //neighbour is out, can't use it + p_baker->bake_cells[p_idx].used_sides&=~(1<cell_subdiv-1;i++) { + + Baker::Cell *bc = &p_baker->bake_cells[neighbour]; + + int child = 0; + if (x >= ofs_x + half) { + child|=1; + ofs_x+=half; + } + if (y >= ofs_y + half) { + child|=2; + ofs_y+=half; + } + if (z >= ofs_z + half) { + child|=4; + ofs_z+=half; + } + + neighbour = bc->childs[child]; + if (neighbour==Baker::CHILD_EMPTY) { + break; + } + + half>>=1; + } + + if (neighbour!=Baker::CHILD_EMPTY) { + p_baker->bake_cells[p_idx].used_sides&=~(1<cell_subdiv-1)) >> (p_level+1); + for(int i=0;i<8;i++) { + + uint32_t child = p_baker->bake_cells[p_idx].childs[i]; + + if (child==Baker::CHILD_EMPTY) + continue; + + + int nx=p_x; + int ny=p_y; + int nz=p_z; + + if (i&1) + nx+=half; + if (i&2) + ny+=half; + if (i&4) + nz+=half; + + _fixup_plot(child,p_level+1,nx,ny,nz,p_baker); + alpha_average+=p_baker->bake_cells[child].alpha; + } + + p_baker->bake_cells[p_idx].alpha=alpha_average/8.0; + p_baker->bake_cells[p_idx].emission[0]=0; + p_baker->bake_cells[p_idx].emission[1]=0; + p_baker->bake_cells[p_idx].emission[2]=0; + p_baker->bake_cells[p_idx].albedo[0]=0; + p_baker->bake_cells[p_idx].albedo[1]=0; + p_baker->bake_cells[p_idx].albedo[2]=0; + + } + +} + + + +Vector GIProbe::_get_bake_texture(Image &p_image,const Color& p_color) { + + Vector ret; + + if (p_image.empty()) { + + ret.resize(bake_texture_size*bake_texture_size); + for(int i=0;i::Read r = p_image.get_data().read(); + ret.resize(bake_texture_size*bake_texture_size); + + for(int i=0;i p_material,Baker *p_baker) { + + //this way of obtaining materials is inaccurate and also does not support some compressed formats very well + Ref mat = p_material; + + Ref material = mat; //hack for now + + if (p_baker->material_cache.has(material)) { + return p_baker->material_cache[material]; + } + + Baker::MaterialCache mc; + + if (mat.is_valid()) { + + + Ref albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO); + + Image img_albedo; + if (albedo_tex.is_valid()) { + + img_albedo = albedo_tex->get_data(); + } + + mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo()); + + Ref emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION); + + Color emission_col = mat->get_emission(); + emission_col.r*=mat->get_emission_energy(); + emission_col.g*=mat->get_emission_energy(); + emission_col.b*=mat->get_emission_energy(); + + Image img_emission; + + if (emission_tex.is_valid()) { + + img_emission = emission_tex->get_data(); + } + + mc.emission=_get_bake_texture(img_emission,emission_col); + + } else { + Image empty; + + mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7)); + mc.emission=_get_bake_texture(empty,Color(0,0,0)); + + + } + + p_baker->material_cache[p_material]=mc; + return mc; + + +} + +void GIProbe::_plot_mesh(const Transform& p_xform, Ref& p_mesh, Baker *p_baker) { + + + for(int i=0;iget_surface_count();i++) { + + if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) + continue; //only triangles + + Baker::MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i),p_baker); + + Array a = p_mesh->surface_get_arrays(i); + + + DVector vertices = a[Mesh::ARRAY_VERTEX]; + DVector::Read vr=vertices.read(); + DVector uv = a[Mesh::ARRAY_TEX_UV]; + DVector::Read uvr; + DVector index = a[Mesh::ARRAY_INDEX]; + + bool read_uv=false; + + if (uv.size()) { + + uvr=uv.read(); + read_uv=true; + } + + if (index.size()) { + + int facecount = index.size()/3; + DVector::Read ir=index.read(); + + for(int j=0;jpo2_bounds,p_baker); + } + + + + } else { + + int facecount = vertices.size()/3; + + for(int j=0;jpo2_bounds,p_baker); + } + + } + } +} + + + +void GIProbe::_find_meshes(Node *p_at_node,Baker *p_baker){ + + MeshInstance *mi = p_at_node->cast_to(); + if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT)) { + Ref mesh = mi->get_mesh(); + if (mesh.is_valid()) { + + AABB aabb = mesh->get_aabb(); + + Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform(); + + if (AABB(-extents,extents*2).intersects(xf.xform(aabb))) { + Baker::PlotMesh pm; + pm.local_xform=xf; + pm.mesh=mesh; + p_baker->mesh_list.push_back(pm); + + } + } + } + + for(int i=0;iget_child_count();i++) { + + Node *child = p_at_node->get_child(i); + if (!child->get_owner()) + continue; //maybe a helper + + _find_meshes(child,p_baker); + + } +} + + + + +void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){ + + Baker baker; + + static const int subdiv_value[SUBDIV_MAX]={7,8,9,10}; + + baker.cell_subdiv=subdiv_value[subdiv]; + baker.bake_cells.resize(1); + + //find out the actual real bounds, power of 2, which gets the highest subdivision + baker.po2_bounds=AABB(-extents,extents*2.0); + int longest_axis = baker.po2_bounds.get_longest_axis_index(); + baker.axis_cell_size[longest_axis]=(1<<(baker.cell_subdiv-1)); + baker.leaf_voxel_count=0; + + for(int i=0;i<3;i++) { + + if (i==longest_axis) + continue; + + baker.axis_cell_size[i]=baker.axis_cell_size[longest_axis]; + float axis_size = baker.po2_bounds.size[longest_axis]; + + //shrink until fit subdiv + while (axis_size/2.0 >= baker.po2_bounds.size[i]) { + axis_size/=2.0; + baker.axis_cell_size[i]>>=1; + } + + baker.po2_bounds.size[i]=baker.po2_bounds.size[longest_axis]; + } + + + + Transform to_bounds; + to_bounds.basis.scale(Vector3(baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis])); + to_bounds.origin=baker.po2_bounds.pos; + + Transform to_grid; + to_grid.basis.scale(Vector3(baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis])); + + baker.to_cell_space = to_grid * to_bounds.affine_inverse(); + + + _find_meshes(p_from_node?p_from_node:get_parent(),&baker); + + + + int pmc=0; + + for(List::Element *E=baker.mesh_list.front();E;E=E->next()) { + + print_line("plotting mesh "+itos(pmc++)+"/"+itos(baker.mesh_list.size())); + + _plot_mesh(E->get().local_xform,E->get().mesh,&baker); + } + + _fixup_plot(0,0,0,0,0,&baker); + + //create the data for visual server + + DVector data; + + data.resize( 16+(8+1+1+1+1)*baker.bake_cells.size() ); //4 for header, rest for rest. + + { + DVector::Write w = data.write(); + + uint32_t * w32 = (uint32_t*)w.ptr(); + + w32[0]=0;//version + w32[1]=baker.cell_subdiv; //subdiv + w32[2]=baker.axis_cell_size[0]; + w32[3]=baker.axis_cell_size[1]; + w32[4]=baker.axis_cell_size[2]; + w32[5]=baker.bake_cells.size(); + w32[6]=baker.leaf_voxel_count; + + int ofs=16; + + for(int i=0;i0) { + e.normalize(); + l=CLAMP(l/8.0,0,1.0); + } + + uint32_t em=uint32_t(CLAMP(e[0]*255,0,255))<<24; + em|=uint32_t(CLAMP(e[1]*255,0,255))<<16; + em|=uint32_t(CLAMP(e[2]*255,0,255))<<8; + em|=uint32_t(CLAMP(l*255,0,255)); + + w32[ofs++]=em; + } + + w32[ofs++]=baker.bake_cells[i].used_sides; + w32[ofs++]=uint32_t(baker.bake_cells[i].alpha*65535.0); + + } + + } + + Ref probe_data; + probe_data.instance(); + probe_data->set_bounds(AABB(-extents,extents*2.0)); + probe_data->set_cell_size(baker.po2_bounds.size[longest_axis]/baker.axis_cell_size[longest_axis]); + probe_data->set_dynamic_data(data); + probe_data->set_to_cell_xform(baker.to_cell_space); + + set_probe_data(probe_data); + + + if (p_create_visual_debug) { + // _create_debug_mesh(&baker); + } + + + +} + + +void GIProbe::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref &p_multimesh,int &idx,Baker *p_baker) { + + + if (p_level==p_baker->cell_subdiv-1) { + + Vector3 center = p_aabb.pos+p_aabb.size*0.5; + Transform xform; + xform.origin=center; + xform.basis.scale(p_aabb.size*0.5); + p_multimesh->set_instance_transform(idx,xform); + Color col=Color(p_baker->bake_cells[p_idx].albedo[0],p_baker->bake_cells[p_idx].albedo[1],p_baker->bake_cells[p_idx].albedo[2]); + p_multimesh->set_instance_color(idx,col); + + idx++; + + } else { + + for(int i=0;i<8;i++) { + + if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) + continue; + + AABB aabb=p_aabb; + aabb.size*=0.5; + + if (i&1) + aabb.pos.x+=aabb.size.x; + if (i&2) + aabb.pos.y+=aabb.size.y; + if (i&4) + aabb.pos.z+=aabb.size.z; + + _debug_mesh(p_baker->bake_cells[p_idx].childs[i],p_level+1,aabb,p_multimesh,idx,p_baker); + } + + } + +} + + +void GIProbe::_create_debug_mesh(Baker *p_baker) { + + Ref mm; + mm.instance(); + + mm->set_transform_format(MultiMesh::TRANSFORM_3D); + mm->set_color_format(MultiMesh::COLOR_8BIT); + print_line("leaf voxels: "+itos(p_baker->leaf_voxel_count)); + mm->set_instance_count(p_baker->leaf_voxel_count); + + Ref mesh; + mesh.instance(); + + { + Array arr; + arr.resize(Mesh::ARRAY_MAX); + + DVector vertices; + DVector colors; + + int vtx_idx=0; + #define ADD_VTX(m_idx);\ + vertices.push_back( face_points[m_idx] );\ + colors.push_back( Color(1,1,1,1) );\ + vtx_idx++;\ + + for (int i=0;i<6;i++) { + + + Vector3 face_points[4]; + + for (int j=0;j<4;j++) { + + float v[3]; + v[0]=1.0; + v[1]=1-2*((j>>1)&1); + v[2]=v[1]*(1-2*(j&1)); + + for (int k=0;k<3;k++) { + + if (i<3) + face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1); + else + face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1); + } + } + + //tri 1 + ADD_VTX(0); + ADD_VTX(1); + ADD_VTX(2); + //tri 2 + ADD_VTX(2); + ADD_VTX(3); + ADD_VTX(0); + + } + + + arr[Mesh::ARRAY_VERTEX]=vertices; + arr[Mesh::ARRAY_COLOR]=colors; + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr); + } + + { + Ref fsm; + fsm.instance(); + fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true); + fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true); + fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true); + fsm->set_albedo(Color(1,1,1,1)); + + mesh->surface_set_material(0,fsm); + } + + mm->set_mesh(mesh); + + + int idx=0; + _debug_mesh(0,0,p_baker->po2_bounds,mm,idx,p_baker); + + MultiMeshInstance *mmi = memnew( MultiMeshInstance ); + mmi->set_multimesh(mm); + add_child(mmi); + if (get_tree()->get_edited_scene_root()==this){ + mmi->set_owner(this); + } else { + mmi->set_owner(get_owner()); + + } + +} + +void GIProbe::_debug_bake() { + + bake(NULL,true); +} + +AABB GIProbe::get_aabb() const { + + return AABB(-extents,extents*2); +} + +DVector GIProbe::get_faces(uint32_t p_usage_flags) const { + + return DVector(); +} + +void GIProbe::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_probe_data","data"),&GIProbe::set_probe_data); + ObjectTypeDB::bind_method(_MD("get_probe_data"),&GIProbe::get_probe_data); + + ObjectTypeDB::bind_method(_MD("set_subdiv","subdiv"),&GIProbe::set_subdiv); + ObjectTypeDB::bind_method(_MD("get_subdiv"),&GIProbe::get_subdiv); + + ObjectTypeDB::bind_method(_MD("set_extents","extents"),&GIProbe::set_extents); + ObjectTypeDB::bind_method(_MD("get_extents"),&GIProbe::get_extents); + + ObjectTypeDB::bind_method(_MD("set_dynamic_range","max"),&GIProbe::set_dynamic_range); + ObjectTypeDB::bind_method(_MD("get_dynamic_range"),&GIProbe::get_dynamic_range); + + ObjectTypeDB::bind_method(_MD("bake","from_node","create_visual_debug"),&GIProbe::bake,DEFVAL(Variant()),DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("debug_bake"),&GIProbe::_debug_bake); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"subdiv",PROPERTY_HINT_ENUM,"64,128,256,512"),_SCS("set_subdiv"),_SCS("get_subdiv")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"extents"),_SCS("set_extents"),_SCS("get_extents")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"dynamic_range",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"data",PROPERTY_HINT_RESOURCE_TYPE,"GIProbeData"),_SCS("set_probe_data"),_SCS("get_probe_data")); + + + BIND_CONSTANT( SUBDIV_64 ); + BIND_CONSTANT( SUBDIV_128 ); + BIND_CONSTANT( SUBDIV_256 ); + BIND_CONSTANT( SUBDIV_MAX ); + +} + +GIProbe::GIProbe() { + + subdiv=SUBDIV_128; + dynamic_range=1.0; + extents=Vector3(10,10,10); + color_scan_cell_width=4; + bake_texture_size=128; + + gi_probe = VS::get_singleton()->gi_probe_create(); + + +} + +GIProbe::~GIProbe() { + + +} diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h new file mode 100644 index 000000000..e2017acfc --- /dev/null +++ b/scene/3d/gi_probe.h @@ -0,0 +1,174 @@ +#ifndef GIPROBE_H +#define GIPROBE_H + +#include "scene/3d/visual_instance.h" +#include "multimesh_instance.h" + +class GIProbeData : public Resource { + + OBJ_TYPE(GIProbeData,Resource); + + RID probe; + +public: + + enum DataFormat { + DATA_RGBA8, + DATA_DXT5, + DATA_ETC2_EAC, + }; + + + void set_bounds(const AABB& p_bounds); + AABB get_bounds() const; + + void set_cell_size(float p_size); + float get_cell_size() const; + + void set_to_cell_xform(const Transform& p_xform); + Transform get_to_cell_xform() const; + + void set_dynamic_data(const DVector& p_data); + DVector get_dynamic_data() const; + + void set_dynamic_range(float p_range); + float get_dynamic_range() const; + + void set_static_data(const DVector& p_data,DataFormat p_format,int p_width,int p_height,int p_depth); + DVector get_static_data() const; + DataFormat get_static_data_format() const; + int get_static_data_width() const; + int get_static_data_height() const; + int get_static_data_depth() const; + + virtual RID get_rid() const; + + GIProbeData(); + ~GIProbeData(); +}; + +VARIANT_ENUM_CAST(GIProbeData::DataFormat); + +class GIProbe : public VisualInstance { + OBJ_TYPE(GIProbe,VisualInstance); +public: + enum Subdiv{ + SUBDIV_64, + SUBDIV_128, + SUBDIV_256, + SUBDIV_512, + SUBDIV_MAX + + }; +private: + + //stuff used for bake + struct Baker { + + enum { + CHILD_EMPTY=0xFFFFFFFF + }; + struct Cell { + + uint32_t childs[8]; + float albedo[3]; //albedo in RGB24 + float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) + uint32_t used_sides; + float alpha; //used for upsampling + + Cell() { + for(int i=0;i<8;i++) { + childs[i]=CHILD_EMPTY; + } + + for(int i=0;i<3;i++) { + emission[i]=0; + albedo[i]=0; + } + alpha=0; + used_sides=0; + } + }; + + Vector bake_cells; + int cell_subdiv; + + struct MaterialCache { + //128x128 textures + Vector albedo; + Vector emission; + }; + + + Vector _get_bake_texture(Image &p_image, const Color &p_color); + Map,MaterialCache> material_cache; + MaterialCache _get_material_cache(Ref p_material); + int leaf_voxel_count; + + + AABB po2_bounds; + int axis_cell_size[3]; + + struct PlotMesh { + Ref mesh; + Transform local_xform; + }; + + Transform to_cell_space; + + List mesh_list; + }; + + + Ref probe_data; + + RID gi_probe; + + Subdiv subdiv; + Vector3 extents; + float dynamic_range; + + int color_scan_cell_width; + int bake_texture_size; + + Vector _get_bake_texture(Image &p_image,const Color& p_color); + Baker::MaterialCache _get_material_cache(Ref p_material,Baker *p_baker); + void _plot_face(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const AABB &p_aabb,Baker *p_baker); + void _plot_mesh(const Transform& p_xform, Ref& p_mesh, Baker *p_baker); + void _find_meshes(Node *p_at_node,Baker *p_baker); + void _fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker); + + void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref &p_multimesh,int &idx,Baker *p_baker); + void _create_debug_mesh(Baker *p_baker); + + void _debug_bake(); + +protected: + + static void _bind_methods(); +public: + + void set_probe_data(const Ref& p_data); + Ref get_probe_data() const; + + void set_subdiv(Subdiv p_subdiv); + Subdiv get_subdiv() const; + + void set_extents(const Vector3& p_extents); + Vector3 get_extents() const; + + void set_dynamic_range(float p_dynamic_range); + float get_dynamic_range() const; + + void bake(Node *p_from_node=NULL,bool p_create_visual_debug=false); + + virtual AABB get_aabb() const; + virtual DVector get_faces(uint32_t p_usage_flags) const; + + GIProbe(); + ~GIProbe(); +}; + +VARIANT_ENUM_CAST(GIProbe::Subdiv) + +#endif // GIPROBE_H diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 7177e21e1..1566743e1 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -30,7 +30,7 @@ #include "globals.h" #include "scene/resources/surface_tool.h" - +#include "baked_light_instance.h" bool Light::_can_gizmo_scale() const { @@ -168,9 +168,37 @@ void Light::_update_visibility() { void Light::_notification(int p_what) { - if (p_what==NOTIFICATION_ENTER_TREE || p_what==NOTIFICATION_VISIBILITY_CHANGED) { + + if (p_what==NOTIFICATION_VISIBILITY_CHANGED) { + _update_visibility(); + + } + + if (p_what==NOTIFICATION_ENTER_TREE) { + _update_visibility(); + + Node *node = this; + + while(node) { + + baked_light=node->cast_to(); + if (baked_light) { + baked_light->lights.insert(this); + break; + } + + node=node->get_parent(); + } } + + if (p_what==NOTIFICATION_EXIT_TREE) { + + if (baked_light) { + baked_light->lights.erase(this); + } + } + } @@ -247,6 +275,8 @@ Light::Light(VisualServer::LightType p_type) { light=VisualServer::get_singleton()->light_create(p_type); VS::get_singleton()->instance_set_base(get_instance(),light); + baked_light=NULL; + editor_only=false; set_color(Color(1,1,1,1)); set_shadow(false); diff --git a/scene/3d/light.h b/scene/3d/light.h index fcf5ce90f..45adfc1de 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -37,6 +37,10 @@ /** @author Juan Linietsky */ + + +class BakedLight; + class Light : public VisualInstance { OBJ_TYPE( Light, VisualInstance ); @@ -72,6 +76,8 @@ private: VS::LightType type; bool editor_only; void _update_visibility(); + + BakedLight *baked_light; // bind helpers protected: diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 5bc332f8f..f5dbf7c53 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -31,7 +31,6 @@ #include "servers/visual_server.h" #include "room_instance.h" #include "scene/scene_string_names.h" -#include "baked_light_instance.h" #include "skeleton.h" AABB VisualInstance::get_transformed_aabb() const { @@ -227,7 +226,6 @@ void GeometryInstance::_notification(int p_what) { if (flags[FLAG_USE_BAKED_LIGHT]) { - _find_baked_light(); } _update_visibility(); @@ -236,11 +234,6 @@ void GeometryInstance::_notification(int p_what) { if (flags[FLAG_USE_BAKED_LIGHT]) { - if (baked_light_instance) { - // baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed); - // baked_light_instance=NULL; - } - _baked_light_changed(); } @@ -252,37 +245,6 @@ void GeometryInstance::_notification(int p_what) { } -void GeometryInstance::_baked_light_changed() { - - //if (!baked_light_instance) - // VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),RID()); -// else -// VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),baked_light_instance->get_baked_light_instance()); - -} - -void GeometryInstance::_find_baked_light() { -/* - Node *n=get_parent(); - while(n) { - - BakedLightInstance *bl=n->cast_to(); - if (bl) { - - baked_light_instance=bl; - baked_light_instance->connect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed); - _baked_light_changed(); - - return; - } - - n=n->get_parent(); - } - - _baked_light_changed(); - */ -} - void GeometryInstance::_update_visibility() { if (!is_inside_tree()) @@ -314,17 +276,6 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) { } if (p_flag==FLAG_USE_BAKED_LIGHT) { - /* if (is_inside_world()) { - if (!p_value) { - if (baked_light_instance) { - baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed); - baked_light_instance=NULL; - } - _baked_light_changed(); - } else { - _find_baked_light(); - } - }*/ } } @@ -357,17 +308,8 @@ GeometryInstance::ShadowCastingSetting GeometryInstance::get_cast_shadows_settin return shadow_casting_setting; } -void GeometryInstance::set_baked_light_texture_id(int p_id) { -// baked_light_texture_id=p_id; -// VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),baked_light_texture_id); -} - -int GeometryInstance::get_baked_light_texture_id() const{ - - return baked_light_texture_id; -} void GeometryInstance::set_extra_cull_margin(float p_margin) { @@ -405,15 +347,11 @@ void GeometryInstance::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_lod_min_distance"), &GeometryInstance::get_lod_min_distance); - ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id); - ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id); - ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin); ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin); ObjectTypeDB::bind_method(_MD("get_aabb"),&GeometryInstance::get_aabb); - ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "geometry/material_override",PROPERTY_HINT_RESOURCE_TYPE,"Material"), _SCS("set_material_override"), _SCS("get_material_override")); @@ -424,7 +362,6 @@ void GeometryInstance::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT); - ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id")); ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_distance"), _SCS("get_lod_min_distance")); ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_hysteresis",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_hysteresis"), _SCS("get_lod_min_hysteresis")); ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/max_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_max_distance"), _SCS("get_lod_max_distance")); @@ -461,8 +398,6 @@ GeometryInstance::GeometryInstance() { flags[FLAG_CAST_SHADOW]=true; shadow_casting_setting=SHADOW_CASTING_SETTING_ON; - baked_light_instance=NULL; - baked_light_texture_id=0; extra_cull_margin=0; // VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index b168bcbfe..5fd0830d3 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -79,7 +79,7 @@ public: }; -class BakedLightInstance; +class BakedLight; class GeometryInstance : public VisualInstance { @@ -114,12 +114,9 @@ private: float lod_max_distance; float lod_min_hysteresis; float lod_max_hysteresis; - void _find_baked_light(); - BakedLightInstance *baked_light_instance; - int baked_light_texture_id; + float extra_cull_margin; - void _baked_light_changed(); void _update_visibility(); protected: @@ -148,9 +145,6 @@ public: void set_material_override(const Ref& p_material); Ref get_material_override() const; - void set_baked_light_texture_id(int p_id); - int get_baked_light_texture_id() const; - void set_extra_cull_margin(float p_margin); float get_extra_cull_margin() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index d2b9def5c..1c2620ec9 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -205,6 +205,7 @@ #include "scene/3d/quad.h" #include "scene/3d/light.h" #include "scene/3d/reflection_probe.h" +#include "scene/3d/gi_probe.h" #include "scene/3d/particles.h" #include "scene/3d/portal.h" #include "scene/resources/environment.h" @@ -424,6 +425,8 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); //ObjectTypeDB::register_type(); @@ -455,7 +458,7 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); - //ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); //ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); diff --git a/scene/resources/baked_light.cpp b/scene/resources/baked_light.cpp index 38ed661cd..0d53eff7d 100644 --- a/scene/resources/baked_light.cpp +++ b/scene/resources/baked_light.cpp @@ -29,577 +29,3 @@ #include "baked_light.h" #include "servers/visual_server.h" -#if 0 - -void BakedLight::set_mode(Mode p_mode) { - - mode=p_mode; - VS::get_singleton()->baked_light_set_mode(baked_light,(VS::BakedLightMode(p_mode))); - -} - -BakedLight::Mode BakedLight::get_mode() const{ - - return mode; -} - -void BakedLight::set_octree(const DVector& p_octree) { - - VS::get_singleton()->baked_light_set_octree(baked_light,p_octree); -} - -DVector BakedLight::get_octree() const { - - return VS::get_singleton()->baked_light_get_octree(baked_light); -} - -void BakedLight::set_light(const DVector& p_light) { - - VS::get_singleton()->baked_light_set_light(baked_light,p_light); -} - -DVector BakedLight::get_light() const { - - return VS::get_singleton()->baked_light_get_light(baked_light); -} - - -void BakedLight::set_sampler_octree(const DVector& p_sampler_octree) { - - VS::get_singleton()->baked_light_set_sampler_octree(baked_light,p_sampler_octree); -} - -DVector BakedLight::get_sampler_octree() const { - - return VS::get_singleton()->baked_light_get_sampler_octree(baked_light); -} - - - - - -void BakedLight::add_lightmap(const Ref &p_texture,Size2 p_gen_size) { - - LightMap lm; - lm.texture=p_texture; - lm.gen_size=p_gen_size; - lightmaps.push_back(lm); - _update_lightmaps(); - _change_notify(); -} - -void BakedLight::set_lightmap_gen_size(int p_idx,const Size2& p_size){ - - ERR_FAIL_INDEX(p_idx,lightmaps.size()); - lightmaps[p_idx].gen_size=p_size; - _update_lightmaps(); -} -Size2 BakedLight::get_lightmap_gen_size(int p_idx) const{ - - ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Size2()); - return lightmaps[p_idx].gen_size; - -} -void BakedLight::set_lightmap_texture(int p_idx,const Ref &p_texture){ - - ERR_FAIL_INDEX(p_idx,lightmaps.size()); - lightmaps[p_idx].texture=p_texture; - _update_lightmaps(); - -} -Ref BakedLight::get_lightmap_texture(int p_idx) const{ - - ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Ref()); - return lightmaps[p_idx].texture; - -} -void BakedLight::erase_lightmap(int p_idx){ - - ERR_FAIL_INDEX(p_idx,lightmaps.size()); - lightmaps.remove(p_idx); - _update_lightmaps(); - _change_notify(); - -} -int BakedLight::get_lightmaps_count() const{ - - return lightmaps.size(); -} -void BakedLight::clear_lightmaps(){ - - lightmaps.clear(); - _update_lightmaps(); - _change_notify(); -} - - - -void BakedLight::_update_lightmaps() { - - VS::get_singleton()->baked_light_clear_lightmaps(baked_light); - for(int i=0;iget_rid(); - VS::get_singleton()->baked_light_add_lightmap(baked_light,tid,i); - } -} - - - -RID BakedLight::get_rid() const { - - return baked_light; -} - -Array BakedLight::_get_lightmap_data() const { - - Array ret; - ret.resize(lightmaps.size()*2); - - int idx=0; - for(int i=0;i tex = p_array[i+1]; -// ERR_CONTINUE(tex.is_null()); - LightMap lm; - lm.gen_size=size; - lm.texture=tex; - lightmaps.push_back(lm); - } - _update_lightmaps(); -} - - -void BakedLight::set_cell_subdivision(int p_subdiv) { - - cell_subdiv=p_subdiv; -} - -int BakedLight::get_cell_subdivision() const{ - - return cell_subdiv; -} - -void BakedLight::set_initial_lattice_subdiv(int p_size){ - - lattice_subdiv=p_size; -} -int BakedLight::get_initial_lattice_subdiv() const{ - - return lattice_subdiv; -} - -void BakedLight::set_plot_size(float p_size){ - - plot_size=p_size; -} -float BakedLight::get_plot_size() const{ - - return plot_size; -} - -void BakedLight::set_bounces(int p_size){ - - bounces=p_size; -} -int BakedLight::get_bounces() const{ - - return bounces; -} - -void BakedLight::set_cell_extra_margin(float p_margin) { - cell_extra_margin=p_margin; -} - -float BakedLight::get_cell_extra_margin() const { - - return cell_extra_margin; -} - -void BakedLight::set_edge_damp(float p_margin) { - edge_damp=p_margin; -} - -float BakedLight::get_edge_damp() const { - - return edge_damp; -} - - -void BakedLight::set_normal_damp(float p_margin) { - normal_damp=p_margin; -} - -float BakedLight::get_normal_damp() const { - - return normal_damp; -} - -void BakedLight::set_tint(float p_margin) { - tint=p_margin; -} - -float BakedLight::get_tint() const { - - return tint; -} - -void BakedLight::set_saturation(float p_margin) { - saturation=p_margin; -} - -float BakedLight::get_saturation() const { - - return saturation; -} - -void BakedLight::set_ao_radius(float p_ao_radius) { - ao_radius=p_ao_radius; -} - -float BakedLight::get_ao_radius() const { - return ao_radius; -} - -void BakedLight::set_ao_strength(float p_ao_strength) { - - ao_strength=p_ao_strength; -} - -float BakedLight::get_ao_strength() const { - - return ao_strength; -} - -void BakedLight::set_realtime_color_enabled(const bool p_realtime_color_enabled) { - - VS::get_singleton()->baked_light_set_realtime_color_enabled(baked_light, p_realtime_color_enabled); -} - -bool BakedLight::get_realtime_color_enabled() const { - - return VS::get_singleton()->baked_light_get_realtime_color_enabled(baked_light); -} - - -void BakedLight::set_realtime_color(const Color &p_realtime_color) { - - VS::get_singleton()->baked_light_set_realtime_color(baked_light, p_realtime_color); -} - -Color BakedLight::get_realtime_color() const { - - return VS::get_singleton()->baked_light_get_realtime_color(baked_light); -} - -void BakedLight::set_realtime_energy(const float p_realtime_energy) { - - VS::get_singleton()->baked_light_set_realtime_energy(baked_light, p_realtime_energy); -} - -float BakedLight::get_realtime_energy() const { - - return VS::get_singleton()->baked_light_get_realtime_energy(baked_light); -} - - - -void BakedLight::set_energy_multiplier(float p_multiplier){ - - energy_multiply=p_multiplier; -} -float BakedLight::get_energy_multiplier() const{ - - return energy_multiply; -} - -void BakedLight::set_gamma_adjust(float p_adjust){ - - gamma_adjust=p_adjust; -} -float BakedLight::get_gamma_adjust() const{ - - return gamma_adjust; -} - -void BakedLight::set_bake_flag(BakeFlags p_flags,bool p_enable){ - - flags[p_flags]=p_enable; -} -bool BakedLight::get_bake_flag(BakeFlags p_flags) const{ - - return flags[p_flags]; -} - -void BakedLight::set_format(Format p_format) { - - format=p_format; - VS::get_singleton()->baked_light_set_lightmap_multiplier(baked_light,format==FORMAT_HDR8?8.0:1.0); -} - -BakedLight::Format BakedLight::get_format() const{ - - return format; -} - -void BakedLight::set_transfer_lightmaps_only_to_uv2(bool p_enable) { - - transfer_only_uv2=p_enable; -} - -bool BakedLight::get_transfer_lightmaps_only_to_uv2() const{ - - return transfer_only_uv2; -} - - -bool BakedLight::_set(const StringName& p_name, const Variant& p_value) { - - String n = p_name; - if (!n.begins_with("lightmap")) - return false; - int idx = n.get_slicec('/',1).to_int(); - ERR_FAIL_COND_V(idx<0,false); - ERR_FAIL_COND_V(idx>lightmaps.size(),false); - - String what = n.get_slicec('/',2); - Ref tex; - Size2 gens; - - if (what=="texture") - tex=p_value; - else if (what=="gen_size") - gens=p_value; - - if (idx==lightmaps.size()) { - if (tex.is_valid() || gens!=Size2()) - add_lightmap(tex,gens); - } else { - if (tex.is_valid()) - set_lightmap_texture(idx,tex); - else if (gens!=Size2()) - set_lightmap_gen_size(idx,gens); - } - - - return true; -} - -bool BakedLight::_get(const StringName& p_name,Variant &r_ret) const{ - - String n = p_name; - if (!n.begins_with("lightmap")) - return false; - int idx = n.get_slicec('/',1).to_int(); - ERR_FAIL_COND_V(idx<0,false); - ERR_FAIL_COND_V(idx>lightmaps.size(),false); - - String what = n.get_slicec('/',2); - - if (what=="texture") { - if (idx==lightmaps.size()) - r_ret=Ref(); - else - r_ret=lightmaps[idx].texture; - - } else if (what=="gen_size") { - - if (idx==lightmaps.size()) - r_ret=Size2(); - else - r_ret=Size2(lightmaps[idx].gen_size); - } else - return false; - - return true; - - -} -void BakedLight::_get_property_list( List *p_list) const{ - - for(int i=0;i<=lightmaps.size();i++) { - - p_list->push_back(PropertyInfo(Variant::VECTOR2,"lightmaps/"+itos(i)+"/gen_size",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT,"lightmaps/"+itos(i)+"/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture",PROPERTY_USAGE_EDITOR)); - } -} - - -void BakedLight::_bind_methods(){ - - - ObjectTypeDB::bind_method(_MD("set_mode","mode"),&BakedLight::set_mode); - ObjectTypeDB::bind_method(_MD("get_mode"),&BakedLight::get_mode); - - ObjectTypeDB::bind_method(_MD("set_octree","octree"),&BakedLight::set_octree); - ObjectTypeDB::bind_method(_MD("get_octree"),&BakedLight::get_octree); - - ObjectTypeDB::bind_method(_MD("set_light","light"),&BakedLight::set_light); - ObjectTypeDB::bind_method(_MD("get_light"),&BakedLight::get_light); - - ObjectTypeDB::bind_method(_MD("set_sampler_octree","sampler_octree"),&BakedLight::set_sampler_octree); - ObjectTypeDB::bind_method(_MD("get_sampler_octree"),&BakedLight::get_sampler_octree); - - - ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","gen_size"),&BakedLight::add_lightmap); - ObjectTypeDB::bind_method(_MD("erase_lightmap","id"),&BakedLight::erase_lightmap); - ObjectTypeDB::bind_method(_MD("clear_lightmaps"),&BakedLight::clear_lightmaps); - - ObjectTypeDB::bind_method(_MD("_set_lightmap_data","lightmap_data"),&BakedLight::_set_lightmap_data); - ObjectTypeDB::bind_method(_MD("_get_lightmap_data"),&BakedLight::_get_lightmap_data); - - ObjectTypeDB::bind_method(_MD("set_cell_subdivision","cell_subdivision"),&BakedLight::set_cell_subdivision); - ObjectTypeDB::bind_method(_MD("get_cell_subdivision"),&BakedLight::get_cell_subdivision); - - ObjectTypeDB::bind_method(_MD("set_initial_lattice_subdiv","cell_subdivision"),&BakedLight::set_initial_lattice_subdiv); - ObjectTypeDB::bind_method(_MD("get_initial_lattice_subdiv","cell_subdivision"),&BakedLight::get_initial_lattice_subdiv); - - ObjectTypeDB::bind_method(_MD("set_plot_size","plot_size"),&BakedLight::set_plot_size); - ObjectTypeDB::bind_method(_MD("get_plot_size"),&BakedLight::get_plot_size); - - ObjectTypeDB::bind_method(_MD("set_bounces","bounces"),&BakedLight::set_bounces); - ObjectTypeDB::bind_method(_MD("get_bounces"),&BakedLight::get_bounces); - - ObjectTypeDB::bind_method(_MD("set_cell_extra_margin","cell_extra_margin"),&BakedLight::set_cell_extra_margin); - ObjectTypeDB::bind_method(_MD("get_cell_extra_margin"),&BakedLight::get_cell_extra_margin); - - ObjectTypeDB::bind_method(_MD("set_edge_damp","edge_damp"),&BakedLight::set_edge_damp); - ObjectTypeDB::bind_method(_MD("get_edge_damp"),&BakedLight::get_edge_damp); - - ObjectTypeDB::bind_method(_MD("set_normal_damp","normal_damp"),&BakedLight::set_normal_damp); - ObjectTypeDB::bind_method(_MD("get_normal_damp"),&BakedLight::get_normal_damp); - - ObjectTypeDB::bind_method(_MD("set_tint","tint"),&BakedLight::set_tint); - ObjectTypeDB::bind_method(_MD("get_tint"),&BakedLight::get_tint); - - ObjectTypeDB::bind_method(_MD("set_saturation","saturation"),&BakedLight::set_saturation); - ObjectTypeDB::bind_method(_MD("get_saturation"),&BakedLight::get_saturation); - - ObjectTypeDB::bind_method(_MD("set_ao_radius","ao_radius"),&BakedLight::set_ao_radius); - ObjectTypeDB::bind_method(_MD("get_ao_radius"),&BakedLight::get_ao_radius); - - ObjectTypeDB::bind_method(_MD("set_ao_strength","ao_strength"),&BakedLight::set_ao_strength); - ObjectTypeDB::bind_method(_MD("get_ao_strength"),&BakedLight::get_ao_strength); - - ObjectTypeDB::bind_method(_MD("set_realtime_color_enabled", "enabled"), &BakedLight::set_realtime_color_enabled); - ObjectTypeDB::bind_method(_MD("get_realtime_color_enabled"), &BakedLight::get_realtime_color_enabled); - - ObjectTypeDB::bind_method(_MD("set_realtime_color", "tint"), &BakedLight::set_realtime_color); - ObjectTypeDB::bind_method(_MD("get_realtime_color"), &BakedLight::get_realtime_color); - - ObjectTypeDB::bind_method(_MD("set_realtime_energy", "energy"), &BakedLight::set_realtime_energy); - ObjectTypeDB::bind_method(_MD("get_realtime_energy"), &BakedLight::get_realtime_energy); - - ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format); - ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format); - - ObjectTypeDB::bind_method(_MD("set_transfer_lightmaps_only_to_uv2","enable"),&BakedLight::set_transfer_lightmaps_only_to_uv2); - ObjectTypeDB::bind_method(_MD("get_transfer_lightmaps_only_to_uv2"),&BakedLight::get_transfer_lightmaps_only_to_uv2); - - - - - ObjectTypeDB::bind_method(_MD("set_energy_multiplier","energy_multiplier"),&BakedLight::set_energy_multiplier); - ObjectTypeDB::bind_method(_MD("get_energy_multiplier"),&BakedLight::get_energy_multiplier); - - ObjectTypeDB::bind_method(_MD("set_gamma_adjust","gamma_adjust"),&BakedLight::set_gamma_adjust); - ObjectTypeDB::bind_method(_MD("get_gamma_adjust"),&BakedLight::get_gamma_adjust); - - ObjectTypeDB::bind_method(_MD("set_bake_flag","flag","enabled"),&BakedLight::set_bake_flag); - ObjectTypeDB::bind_method(_MD("get_bake_flag","flag"),&BakedLight::get_bake_flag); - - ADD_PROPERTY( PropertyInfo(Variant::INT,"mode/mode",PROPERTY_HINT_ENUM,"Octree,Lightmaps"),_SCS("set_mode"),_SCS("get_mode")); - - ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/format",PROPERTY_HINT_ENUM,"RGB,HDR8,HDR16"),_SCS("set_format"),_SCS("get_format")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/cell_subdiv",PROPERTY_HINT_RANGE,"4,14,1"),_SCS("set_cell_subdivision"),_SCS("get_cell_subdivision")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/lattice_subdiv",PROPERTY_HINT_RANGE,"1,5,1"),_SCS("set_initial_lattice_subdiv"),_SCS("get_initial_lattice_subdiv")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/light_bounces",PROPERTY_HINT_RANGE,"0,3,1"),_SCS("set_bounces"),_SCS("get_bounces")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/plot_size",PROPERTY_HINT_RANGE,"1.0,16.0,0.01"),_SCS("set_plot_size"),_SCS("get_plot_size")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/energy_mult",PROPERTY_HINT_RANGE,"0.01,4096.0,0.01"),_SCS("set_energy_multiplier"),_SCS("get_energy_multiplier")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/gamma_adjust",PROPERTY_HINT_EXP_EASING),_SCS("set_gamma_adjust"),_SCS("get_gamma_adjust")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/saturation",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_saturation"),_SCS("get_saturation")); - ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/diffuse"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_DIFFUSE); - ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR); - ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT); - ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY); - ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/linear_color"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_LINEAR_COLOR); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"lightmap/use_only_uv2"),_SCS("set_transfer_lightmaps_only_to_uv2"),_SCS("get_transfer_lightmaps_only_to_uv2")); - - ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree")); - ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"light",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_light"),_SCS("get_light")); - ADD_PROPERTY( PropertyInfo(Variant::INT_ARRAY,"sampler_octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_sampler_octree"),_SCS("get_sampler_octree")); - ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/cell_margin",PROPERTY_HINT_RANGE,"0.01,0.8,0.01"),_SCS("set_cell_extra_margin"),_SCS("get_cell_extra_margin")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/edge_damp",PROPERTY_HINT_RANGE,"0.0,8.0,0.1"),_SCS("set_edge_damp"),_SCS("get_edge_damp")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/normal_damp",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_normal_damp"),_SCS("get_normal_damp")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/light_tint",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_tint"),_SCS("get_tint")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_radius",PROPERTY_HINT_RANGE,"0.0,16.0,0.01"),_SCS("set_ao_radius"),_SCS("get_ao_radius")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_strength",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_ao_strength"),_SCS("get_ao_strength")); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "realtime/enabled"), _SCS("set_realtime_color_enabled"), _SCS("get_realtime_color_enabled")); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "realtime/color", PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_realtime_color"), _SCS("get_realtime_color")); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "realtime/energy", PROPERTY_HINT_RANGE, "0.01,4096.0,0.01"), _SCS("set_realtime_energy"), _SCS("get_realtime_energy")); - - - BIND_CONSTANT( MODE_OCTREE ); - BIND_CONSTANT( MODE_LIGHTMAPS ); - - BIND_CONSTANT( BAKE_DIFFUSE ); - BIND_CONSTANT( BAKE_SPECULAR ); - BIND_CONSTANT( BAKE_TRANSLUCENT ); - BIND_CONSTANT( BAKE_CONSERVE_ENERGY ); - BIND_CONSTANT( BAKE_MAX ); - - -} - - -BakedLight::BakedLight() { - - cell_subdiv=8; - lattice_subdiv=4; - plot_size=2.5; - bounces=1; - energy_multiply=2.0; - gamma_adjust=0.7; - cell_extra_margin=0.05; - edge_damp=0.0; - normal_damp=0.0; - saturation=1; - tint=0.0; - ao_radius=2.5; - ao_strength=0.7; - format=FORMAT_RGB8; - transfer_only_uv2=false; - - - flags[BAKE_DIFFUSE]=true; - flags[BAKE_SPECULAR]=false; - flags[BAKE_TRANSLUCENT]=true; - flags[BAKE_CONSERVE_ENERGY]=false; - flags[BAKE_LINEAR_COLOR]=false; - - mode=MODE_OCTREE; - baked_light=VS::get_singleton()->baked_light_create(); -} - -BakedLight::~BakedLight() { - - VS::get_singleton()->free(baked_light); -} -#endif diff --git a/scene/resources/baked_light.h b/scene/resources/baked_light.h index 0eaa3df27..6a0742dd2 100644 --- a/scene/resources/baked_light.h +++ b/scene/resources/baked_light.h @@ -32,169 +32,6 @@ #include "resource.h" #include "scene/resources/texture.h" -#if 0 -class BakedLight : public Resource { - OBJ_TYPE( BakedLight, Resource); -public: - enum Mode { - MODE_OCTREE, - MODE_LIGHTMAPS - }; - - enum Format { - - FORMAT_RGB8, - FORMAT_HDR8, - FORMAT_HDR16 - }; - - enum BakeFlags { - BAKE_DIFFUSE, - BAKE_SPECULAR, - BAKE_TRANSLUCENT, - BAKE_CONSERVE_ENERGY, - BAKE_LINEAR_COLOR, - BAKE_MAX - }; - -private: - - RID baked_light; - Mode mode; - struct LightMap { - Size2i gen_size; - Ref texture; - }; - - - Vector< LightMap> lightmaps; - - //bake vars - int cell_subdiv; - int lattice_subdiv; - float plot_size; - float energy_multiply; - float gamma_adjust; - float cell_extra_margin; - float edge_damp; - float normal_damp; - float tint; - float ao_radius; - float ao_strength; - float saturation; - int bounces; - bool transfer_only_uv2; - Format format; - bool flags[BAKE_MAX]; - - - - void _update_lightmaps(); - - Array _get_lightmap_data() const; - void _set_lightmap_data(Array p_array); - -protected: - - bool _set(const StringName& p_name, const Variant& p_value); - bool _get(const StringName& p_name,Variant &r_ret) const; - void _get_property_list( List *p_list) const; - - static void _bind_methods(); - -public: - - void set_cell_subdivision(int p_subdiv); - int get_cell_subdivision() const; - - void set_initial_lattice_subdiv(int p_size); - int get_initial_lattice_subdiv() const; - - void set_plot_size(float p_size); - float get_plot_size() const; - - void set_bounces(int p_size); - int get_bounces() const; - - void set_energy_multiplier(float p_multiplier); - float get_energy_multiplier() const; - - void set_gamma_adjust(float p_adjust); - float get_gamma_adjust() const; - - void set_cell_extra_margin(float p_margin); - float get_cell_extra_margin() const; - - void set_edge_damp(float p_margin); - float get_edge_damp() const; - - void set_normal_damp(float p_margin); - float get_normal_damp() const; - - void set_tint(float p_margin); - float get_tint() const; - - void set_saturation(float p_saturation); - float get_saturation() const; - - void set_ao_radius(float p_ao_radius); - float get_ao_radius() const; - - void set_ao_strength(float p_ao_strength); - float get_ao_strength() const; - - void set_realtime_color_enabled(const bool p_enabled); - bool get_realtime_color_enabled() const; - - void set_realtime_color(const Color& p_realtime_color); - Color get_realtime_color() const; - - void set_realtime_energy(const float p_realtime_energy); - float get_realtime_energy() const; - - void set_bake_flag(BakeFlags p_flags,bool p_enable); - bool get_bake_flag(BakeFlags p_flags) const; - - void set_format(Format p_margin); - Format get_format() const; - - void set_transfer_lightmaps_only_to_uv2(bool p_enable); - bool get_transfer_lightmaps_only_to_uv2() const; - - void set_mode(Mode p_mode); - Mode get_mode() const; - - void set_octree(const DVector& p_octree); - DVector get_octree() const; - - void set_light(const DVector& p_light); - DVector get_light() const; - - void set_sampler_octree(const DVector& p_sampler_octree); - DVector get_sampler_octree() const; - - - - void add_lightmap(const Ref &p_texture,Size2 p_gen_size=Size2(256,256)); - void set_lightmap_gen_size(int p_idx,const Size2& p_size); - Size2 get_lightmap_gen_size(int p_idx) const; - void set_lightmap_texture(int p_idx,const Ref &p_texture); - Ref get_lightmap_texture(int p_idx) const; - void erase_lightmap(int p_idx); - int get_lightmaps_count() const; - void clear_lightmaps(); - - virtual RID get_rid() const; - - BakedLight(); - ~BakedLight(); -}; - - -VARIANT_ENUM_CAST(BakedLight::Format); -VARIANT_ENUM_CAST(BakedLight::Mode); -VARIANT_ENUM_CAST(BakedLight::BakeFlags); -#endif #endif // BAKED_LIGHT_H diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 228afffdb..79560f348 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -91,6 +91,7 @@ public: Vector materials; Vector light_instances; Vector reflection_probe_instances; + Vector gi_probe_instances; Vector morph_values; @@ -108,12 +109,14 @@ public: float depth; //used for sorting SelfList dependency_item; + InstanceBase *baked_light; //baked light to use + SelfList baked_light_item; virtual void base_removed()=0; virtual void base_changed()=0; virtual void base_material_changed()=0; - InstanceBase() : dependency_item(this) { + InstanceBase() : dependency_item(this), baked_light_item(this) { base_type=VS::INSTANCE_NONE; cast_shadows=VS::SHADOW_CASTING_SETTING_ON; @@ -123,6 +126,7 @@ public: billboard_y=false; depth_layer=0; layer_mask=1; + baked_light=NULL; } }; @@ -144,6 +148,11 @@ public: virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas)=0; virtual bool reflection_probe_instance_postprocess_step(RID p_instance)=0; + virtual RID gi_probe_instance_create()=0; + virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data)=0; + virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform)=0; + virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds)=0; + virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass)=0; virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count)=0; @@ -340,6 +349,7 @@ public: virtual VS::LightType light_get_type(RID p_light) const=0; virtual AABB light_get_aabb(RID p_light) const=0; virtual float light_get_param(RID p_light,VS::LightParam p_param)=0; + virtual Color light_get_color(RID p_light)=0; virtual uint64_t light_get_version(RID p_light) const=0; @@ -392,6 +402,39 @@ public: virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0; virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0; + /* GI PROBE API */ + + virtual RID gi_probe_create()=0; + + virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds)=0; + virtual AABB gi_probe_get_bounds(RID p_probe) const=0; + + virtual void gi_probe_set_cell_size(RID p_probe,float p_range)=0; + virtual float gi_probe_get_cell_size(RID p_probe) const=0; + + virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform)=0; + virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const=0; + + virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector& p_data)=0; + virtual DVector gi_probe_get_dynamic_data(RID p_probe) const=0; + + virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0; + virtual float gi_probe_get_dynamic_range(RID p_probe) const=0; + + + virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0; + virtual DVector gi_probe_get_static_data(RID p_gi_probe) const=0; + virtual VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0; + virtual int gi_probe_get_static_data_width(RID p_probe) const=0; + virtual int gi_probe_get_static_data_height(RID p_probe) const=0; + virtual int gi_probe_get_static_data_depth(RID p_probe) const=0; + + virtual RID gi_probe_get_data(RID p_probe)=0; //get data in case this is static + virtual uint32_t gi_probe_get_version(RID p_probe)=0; + + virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth)=0; + virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0; + /* RENDER TARGET */ enum RenderTargetFlags { diff --git a/servers/visual/visual_server_light_baker.cpp b/servers/visual/visual_server_light_baker.cpp new file mode 100644 index 000000000..4956d78ab --- /dev/null +++ b/servers/visual/visual_server_light_baker.cpp @@ -0,0 +1,6 @@ +#include "visual_server_light_baker.h" + +VisualServerLightBaker::VisualServerLightBaker() +{ + +} diff --git a/servers/visual/visual_server_light_baker.h b/servers/visual/visual_server_light_baker.h new file mode 100644 index 000000000..42f016f61 --- /dev/null +++ b/servers/visual/visual_server_light_baker.h @@ -0,0 +1,29 @@ +#ifndef VISUALSERVERLIGHTBAKER_H +#define VISUALSERVERLIGHTBAKER_H + +#include "servers/visual_server.h" + +class VisualServerLightBaker { +public: + + struct BakeCell { + + uint32_t cells[8]; + uint32_t neighbours[7]; //one unused + uint32_t albedo; //albedo in RGBE + uint32_t emission; //emissive light in RGBE + uint32_t light[4]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) + float alpha; //used for upsampling + uint32_t directional_pass; //used for baking directional + + }; + + + + + + + VisualServerLightBaker(); +}; + +#endif // VISUALSERVERLIGHTBAKER_H diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 6ba63a769..2fa45d179 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -90,9 +90,10 @@ void VisualServerRaster::draw(){ changes=0; + VSG::rasterizer->begin_frame(); + VSG::scene->update_dirty_instances(); //update scene stuff - VSG::rasterizer->begin_frame(); VSG::viewport->draw_viewports(); VSG::scene->render_probes(); //_draw_cursors_and_margins(); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 78b0e3cad..191330c66 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -803,12 +803,39 @@ public: BIND2(portal_set_disable_distance,RID , float ) BIND2(portal_set_disabled_color,RID , const Color& ) - /* CAMERA API */ + /* BAKED LIGHT API */ + + BIND0R(RID, gi_probe_create) + + BIND2(gi_probe_set_bounds,RID,const AABB&) + BIND1RC(AABB,gi_probe_get_bounds,RID) + + BIND2(gi_probe_set_cell_size,RID,float) + BIND1RC(float,gi_probe_get_cell_size,RID) + + BIND2(gi_probe_set_to_cell_xform,RID,const Transform&) + BIND1RC(Transform,gi_probe_get_to_cell_xform,RID) + + BIND2(gi_probe_set_dynamic_range,RID,float) + BIND1RC(float,gi_probe_get_dynamic_range,RID) + + BIND2(gi_probe_set_dynamic_data,RID,const DVector& ) + BIND1RC( DVector,gi_probe_get_dynamic_data,RID) + + BIND6(gi_probe_set_static_data,RID,const DVector&,GIProbeDataFormat,int,int,int) + BIND1RC(DVector,gi_probe_get_static_data,RID) + BIND1RC(GIProbeDataFormat,gi_probe_get_static_data_format,RID) + BIND1RC(int,gi_probe_get_static_data_width,RID) + BIND1RC(int,gi_probe_get_static_data_height,RID) + BIND1RC(int,gi_probe_get_static_data_depth,RID) + #undef BINDBASE //from now on, calls forwarded to this singleton #define BINDBASE VSG::scene + /* CAMERA API */ + BIND0R(RID, camera_create) BIND4(camera_set_perspective,RID,float, float , float ) @@ -936,7 +963,6 @@ public: BIND5(instance_geometry_set_draw_range,RID,float ,float ,float ,float ) BIND2(instance_geometry_set_as_instance_lod,RID,RID ) - #undef BINDBASE //from now on, calls forwarded to this singleton #define BINDBASE VSG::canvas diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 6f7dac7f4..62b3a2378 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1,9 +1,12 @@ #include "visual_server_scene.h" #include "visual_server_global.h" - +#include "os/os.h" /* CAMERA API */ + + + RID VisualServerScene::camera_create() { Camera * camera = memnew( Camera ); @@ -118,6 +121,28 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance geom->reflection_dirty=true; return E; //this element should make freeing faster + } else if (B->base_type==VS::INSTANCE_GI_PROBE && (1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceGIProbeData * gi_probe = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + + InstanceGIProbeData::PairInfo pinfo; + pinfo.geometry=A; + pinfo.L = geom->gi_probes.push_back(B); + + List::Element *E = gi_probe->geometries.push_back(pinfo); + + geom->gi_probes_dirty=true; + + return E; //this element should make freeing faster + + } else if (B->base_type==VS::INSTANCE_GI_PROBE && A->base_type==VS::INSTANCE_LIGHT) { + + InstanceGIProbeData * gi_probe = static_cast(B->base_data); + InstanceLightData * light = static_cast(A->base_data); + + return gi_probe->lights.insert(A); } @@ -134,14 +159,14 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance //attempt to conncet portal A (will go through B anyway) //this is a little hackish, but works fine in practice - } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) { + } else if (A->base_type==INSTANCE_GI_PROBE || B->base_type==INSTANCE_GI_PROBE) { - if (B->base_type==INSTANCE_BAKED_LIGHT) { + if (B->base_type==INSTANCE_GI_PROBE) { SWAP(A,B); } - ERR_FAIL_COND_V(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER,NULL); - B->baked_light_sampler_info->baked_lights.insert(A); + ERR_FAIL_COND_V(B->base_type!=INSTANCE_GI_PROBE_SAMPLER,NULL); + B->gi_probe_sampler_info->gi_probes.insert(A); } else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) { @@ -218,6 +243,28 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance geom->reflection_dirty=true; + } else if (B->base_type==VS::INSTANCE_GI_PROBE && (1<base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceGIProbeData * gi_probe = static_cast(B->base_data); + InstanceGeometryData * geom = static_cast(A->base_data); + + List::Element *E = reinterpret_cast::Element*>(udata); + + geom->gi_probes.erase(E->get().L); + gi_probe->geometries.erase(E); + + geom->gi_probes_dirty=true; + + + } else if (B->base_type==VS::INSTANCE_GI_PROBE && A->base_type==VS::INSTANCE_LIGHT) { + + InstanceGIProbeData * gi_probe = static_cast(B->base_data); + InstanceLightData * light = static_cast(A->base_data); + + + Set::Element *E = reinterpret_cast::Element*>(udata); + + gi_probe->lights.erase(E); } #if 0 if (A->base_type==INSTANCE_PORTAL) { @@ -232,14 +279,14 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance self->_portal_attempt_connect(A); self->_portal_attempt_connect(B); - } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) { + } else if (A->base_type==INSTANCE_GI_PROBE || B->base_type==INSTANCE_GI_PROBE) { - if (B->base_type==INSTANCE_BAKED_LIGHT) { + if (B->base_type==INSTANCE_GI_PROBE) { SWAP(A,B); } - ERR_FAIL_COND(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER); - B->baked_light_sampler_info->baked_lights.erase(A); + ERR_FAIL_COND(B->base_type!=INSTANCE_GI_PROBE_SAMPLER); + B->gi_probe_sampler_info->gi_probes.erase(A); } else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) { @@ -397,6 +444,25 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ reflection_probe_render_list.remove(&reflection_probe->update_list); } } break; + case VS::INSTANCE_GI_PROBE: { + + InstanceGIProbeData *gi_probe = static_cast(instance->base_data); + + while(gi_probe->dynamic.updating_stage==GI_UPDATE_STAGE_LIGHTING) { + //wait until bake is done if it's baking + OS::get_singleton()->delay_usec(1); + } + if (gi_probe->update_element.in_list()) { + gi_probe_update_list.remove(&gi_probe->update_element); + } + if (gi_probe->dynamic.probe_data.is_valid()) { + VSG::storage->free(gi_probe->dynamic.probe_data); + } + + VSG::scene_render->free(gi_probe->probe_instance); + + } break; + } if (instance->base_data) { @@ -455,20 +521,20 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ } - if (instance->baked_light_info) { + if (instance->gi_probe_info) { - while(instance->baked_light_info->owned_instances.size()) { + while(instance->gi_probe_info->owned_instances.size()) { - Instance *owned=instance->baked_light_info->owned_instances.front()->get(); - owned->baked_light=NULL; - owned->data.baked_light=NULL; - owned->data.baked_light_octree_xform=NULL; + Instance *owned=instance->gi_probe_info->owned_instances.front()->get(); + owned->gi_probe=NULL; + owned->data.gi_probe=NULL; + owned->data.gi_probe_octree_xform=NULL; owned->BLE=NULL; - instance->baked_light_info->owned_instances.pop_front(); + instance->gi_probe_info->owned_instances.pop_front(); } - memdelete(instance->baked_light_info); - instance->baked_light_info=NULL; + memdelete(instance->gi_probe_info); + instance->gi_probe_info=NULL; } @@ -517,18 +583,18 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ } - if (instance->baked_light_sampler_info) { + if (instance->gi_probe_sampler_info) { - while (instance->baked_light_sampler_info->owned_instances.size()) { + while (instance->gi_probe_sampler_info->owned_instances.size()) { - instance_geometry_set_baked_light_sampler(instance->baked_light_sampler_info->owned_instances.front()->get()->self,RID()); + instance_geometry_set_gi_probe_sampler(instance->gi_probe_sampler_info->owned_instances.front()->get()->self,RID()); } - if (instance->baked_light_sampler_info->sampled_light.is_valid()) { - rasterizer->free(instance->baked_light_sampler_info->sampled_light); + if (instance->gi_probe_sampler_info->sampled_light.is_valid()) { + rasterizer->free(instance->gi_probe_sampler_info->sampled_light); } - memdelete( instance->baked_light_sampler_info ); - instance->baked_light_sampler_info=NULL; + memdelete( instance->gi_probe_sampler_info ); + instance->gi_probe_sampler_info=NULL; } #endif @@ -572,6 +638,19 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ reflection_probe->instance=VSG::scene_render->reflection_probe_instance_create(p_base); } break; + case VS::INSTANCE_GI_PROBE: { + + InstanceGIProbeData *gi_probe = memnew( InstanceGIProbeData ); + instance->base_data=gi_probe; + gi_probe->owner=instance; + + if (scenario && !gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + + gi_probe->probe_instance=VSG::scene_render->gi_probe_instance_create(); + + } break; } @@ -615,20 +694,20 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ instance->base_type=INSTANCE_PORTAL; instance->portal_info = memnew(Instance::PortalInfo); instance->portal_info->portal=portal_owner.get(p_base); - } else if (baked_light_owner.owns(p_base)) { + } else if (gi_probe_owner.owns(p_base)) { - instance->base_type=INSTANCE_BAKED_LIGHT; - instance->baked_light_info=memnew(Instance::BakedLightInfo); - instance->baked_light_info->baked_light=baked_light_owner.get(p_base); + instance->base_type=INSTANCE_GI_PROBE; + instance->gi_probe_info=memnew(Instance::BakedLightInfo); + instance->gi_probe_info->gi_probe=gi_probe_owner.get(p_base); //instance->portal_info = memnew(Instance::PortalInfo); //instance->portal_info->portal=portal_owner.get(p_base); - } else if (baked_light_sampler_owner.owns(p_base)) { + } else if (gi_probe_sampler_owner.owns(p_base)) { - instance->base_type=INSTANCE_BAKED_LIGHT_SAMPLER; - instance->baked_light_sampler_info=memnew( Instance::BakedLightSamplerInfo); - instance->baked_light_sampler_info->sampler=baked_light_sampler_owner.get(p_base); + instance->base_type=INSTANCE_GI_PROBE_SAMPLER; + instance->gi_probe_sampler_info=memnew( Instance::BakedLightSamplerInfo); + instance->gi_probe_sampler_info->sampler=gi_probe_sampler_owner.get(p_base); //instance->portal_info = memnew(Instance::PortalInfo); //instance->portal_info->portal=portal_owner.get(p_base); @@ -676,6 +755,13 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){ InstanceReflectionProbeData *reflection_probe = static_cast(instance->base_data); VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); } break; + case VS::INSTANCE_GI_PROBE: { + + InstanceGIProbeData *gi_probe = static_cast(instance->base_data); + if (gi_probe->update_element.in_list()) { + gi_probe_update_list.remove(&gi_probe->update_element); + } + } break; } @@ -704,6 +790,13 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){ light->D = scenario->directional_lights.push_back(instance); } } break; + case VS::INSTANCE_GI_PROBE: { + + InstanceGIProbeData *gi_probe = static_cast(instance->base_data); + if (!gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + } break; } _instance_queue_update(instance,true,true); @@ -1006,13 +1099,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) { else if (p_instance->base_type == INSTANCE_ROOM) { p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse(); - } else if (p_instance->base_type == INSTANCE_BAKED_LIGHT) { + } else if (p_instance->base_type == INSTANCE_GI_PROBE) { Transform scale; - scale.basis.scale(p_instance->baked_light_info->baked_light->octree_aabb.size); - scale.origin=p_instance->baked_light_info->baked_light->octree_aabb.pos; + scale.basis.scale(p_instance->gi_probe_info->gi_probe->octree_aabb.size); + scale.origin=p_instance->gi_probe_info->gi_probe->octree_aabb.pos; //print_line("scale: "+scale); - p_instance->baked_light_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse(); + p_instance->gi_probe_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse(); } @@ -1077,6 +1170,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) { pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK:0; pairable=true; } + + if (p_instance->base_type == VS::INSTANCE_GI_PROBE) { + //lights and geometries + pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK|(1<base_type == VS::INSTANCE_PORTAL) { @@ -1085,9 +1185,9 @@ void VisualServerScene::_update_instance(Instance *p_instance) { pairable=true; } - if (p_instance->base_type == VS::INSTANCE_BAKED_LIGHT_SAMPLER) { + if (p_instance->base_type == VS::INSTANCE_GI_PROBE_SAMPLER) { - pairable_mask=(1<reflection_probe_get_aabb(p_instance->base); } break; + case VisualServer::INSTANCE_GI_PROBE: { + + new_aabb = VSG::storage->gi_probe_get_bounds(p_instance->base); + + } break; #if 0 case VisualServer::INSTANCE_ROOM: { @@ -1208,18 +1313,18 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { } } break; - case VisualServer::INSTANCE_BAKED_LIGHT: { + case VisualServer::INSTANCE_GI_PROBE: { - BakedLight *baked_light = baked_light_owner.get( p_instance->base ); - ERR_FAIL_COND(!baked_light); - new_aabb=baked_light->octree_aabb; + BakedLight *gi_probe = gi_probe_owner.get( p_instance->base ); + ERR_FAIL_COND(!gi_probe); + new_aabb=gi_probe->octree_aabb; } break; - case VisualServer::INSTANCE_BAKED_LIGHT_SAMPLER: { + case VisualServer::INSTANCE_GI_PROBE_SAMPLER: { - BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get( p_instance->base ); - ERR_FAIL_COND(!baked_light_sampler); - float radius = baked_light_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS]; + BakedLightSampler *gi_probe_sampler = gi_probe_sampler_owner.get( p_instance->base ); + ERR_FAIL_COND(!gi_probe_sampler); + float radius = gi_probe_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS]; new_aabb=AABB(Vector3(-radius,-radius,-radius),Vector3(radius*2,radius*2,radius*2)); @@ -1805,6 +1910,13 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came } } + } else if (ins->base_type==VS::INSTANCE_GI_PROBE && ins->visible) { + + InstanceGIProbeData * gi_probe = static_cast(ins->base_data); + if (!gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + } else if ((1<base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { keep=true; @@ -1865,10 +1977,10 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came if (max>cull_range.max) cull_range.max=max; - if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) { + if (ins->sampled_light && ins->sampled_light->gi_probe_sampler_info->last_pass!=render_pass) { if (light_samplers_culledsampled_light; - ins->sampled_light->baked_light_sampler_info->last_pass=render_pass; + ins->sampled_light->gi_probe_sampler_info->last_pass=render_pass; } } } @@ -1908,6 +2020,21 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came geom->reflection_dirty=false; } + if (geom->gi_probes_dirty) { + int l=0; + //only called when reflection probe AABB enter/exit this geometry + ins->gi_probe_instances.resize(geom->gi_probes.size()); + + for (List::Element *E=geom->gi_probes.front();E;E=E->next()) { + + InstanceGIProbeData * gi_probe = static_cast(E->get()->base_data); + + ins->gi_probe_instances[l++]=gi_probe->probe_instance; + } + + geom->gi_probes_dirty=false; + } + ins->depth = near_plane.distance_to(ins->transform.origin); ins->depth_layer=CLAMP(int(ins->depth*8/z_far),0,7); @@ -2117,7 +2244,7 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came } -bool VisualServerScene::_render_probe_step(Instance* p_instance,int p_step) { +bool VisualServerScene::_render_reflection_probe_step(Instance* p_instance,int p_step) { InstanceReflectionProbeData *reflection_probe = static_cast(p_instance->base_data); Scenario *scenario = p_instance->scenario; @@ -2188,18 +2315,539 @@ bool VisualServerScene::_render_probe_step(Instance* p_instance,int p_step) { return false; } +void VisualServerScene::_gi_probe_fill_local_data(int p_idx, int p_level, int p_x, int p_y, int p_z, const GIProbeDataCell* p_cell, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, Vector *prev_cell) { + + if (p_level==p_header->cell_subdiv-1) { + + Vector3 emission; + emission.x=(p_cell[p_idx].emission>>24)/255.0; + emission.y=((p_cell[p_idx].emission>>16)&0xFF)/255.0; + emission.z=((p_cell[p_idx].emission>>8)&0xFF)/255.0; + float l = (p_cell[p_idx].emission&0xFF)/255.0; + l*=8.0; + + emission*=l; + + p_local_data[p_idx].energy[0]=uint16_t(emission.x*1024); //go from 0 to 1024 for light + p_local_data[p_idx].energy[1]=uint16_t(emission.y*1024); //go from 0 to 1024 for light + p_local_data[p_idx].energy[2]=uint16_t(emission.z*1024); //go from 0 to 1024 for light + } else { + + p_local_data[p_idx].energy[0]=0; + p_local_data[p_idx].energy[1]=0; + p_local_data[p_idx].energy[2]=0; + + int half=(1<<(p_header->cell_subdiv-1))>>(p_level+1); + + for(int i=0;i<8;i++) { + + uint32_t child = p_cell[p_idx].children[i]; + + if (child==0xFFFFFFFF) + continue; + + int x = p_x; + int y = p_y; + int z = p_z; + + if (i&1) + x+=half; + if (i&2) + y+=half; + if (i&4) + z+=half; + + _gi_probe_fill_local_data(child,p_level+1,x,y,z,p_cell,p_header,p_local_data,prev_cell); + } + } + + //position for each part of the mipmaped texture + p_local_data[p_idx].pos[0]=p_x>>(p_header->cell_subdiv-p_level-1); + p_local_data[p_idx].pos[1]=p_y>>(p_header->cell_subdiv-p_level-1); + p_local_data[p_idx].pos[2]=p_z>>(p_header->cell_subdiv-p_level-1); + + prev_cell[p_level].push_back(p_idx); + +} + + +void VisualServerScene::_gi_probe_bake_threads(void* self) { + + VisualServerScene* vss = (VisualServerScene*)self; + vss->_gi_probe_bake_thread(); +} + +void VisualServerScene::_setup_gi_probe(Instance *p_instance) { + + + InstanceGIProbeData *probe = static_cast(p_instance->base_data); + + if (probe->dynamic.probe_data.is_valid()) { + VSG::storage->free(probe->dynamic.probe_data); + probe->dynamic.probe_data=RID(); + } + + probe->dynamic.light_data=VSG::storage->gi_probe_get_dynamic_data(p_instance->base); + + if (probe->dynamic.light_data.size()) { + //using dynamic data + DVector::Read r=probe->dynamic.light_data.read(); + + const GIProbeDataHeader *header = (GIProbeDataHeader *)r.ptr(); + + probe->dynamic.local_data.resize(header->cell_count); + + DVector::Write ldw = probe->dynamic.local_data.write(); + + const GIProbeDataCell *cells = (GIProbeDataCell*)&r[16]; + + probe->dynamic.level_cell_lists.resize(header->cell_subdiv); + + _gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr()); + + probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth); + + + probe->dynamic.mipmaps_3d.clear(); + + probe->dynamic.grid_size[0]=header->width; + probe->dynamic.grid_size[1]=header->height; + probe->dynamic.grid_size[2]=header->depth; + + for(int i=0;i<(int)header->cell_subdiv;i++) { + + uint32_t x = header->width >> i; + uint32_t y = header->height >> i; + uint32_t z = header->depth >> i; + + //create and clear mipmap + DVector mipmap; + mipmap.resize(x*y*z*4); + DVector::Write w = mipmap.write(); + zeromem(w.ptr(),x*y*z*4); + w = DVector::Write(); + + probe->dynamic.mipmaps_3d.push_back(mipmap); + + if (x<=1 || y<=1 || z<=1) + break; + } + + probe->dynamic.updating_stage=GI_UPDATE_STAGE_CHECK; + probe->invalid=false; + probe->dynamic.enabled=true; + + Transform cell_to_xform = VSG::storage->gi_probe_get_to_cell_xform(p_instance->base); + AABB bounds = VSG::storage->gi_probe_get_bounds(p_instance->base); + float cell_size = VSG::storage->gi_probe_get_cell_size(p_instance->base); + + probe->dynamic.light_to_cell_xform=cell_to_xform * p_instance->transform.affine_inverse(); + + VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,probe->dynamic.probe_data); + VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform); + + + + VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance,bounds.size/cell_size); + + + } else { + RID data = VSG::storage->gi_probe_get_data(p_instance->base); + + probe->dynamic.enabled=false; + probe->invalid=!data.is_valid(); + if (data.is_valid()) { + VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,data); + } + } + + probe->base_version=VSG::storage->gi_probe_get_version(p_instance->base); + +} + +void VisualServerScene::_gi_probe_bake_thread() { + + while(true) { + + probe_bake_sem->wait(); + if (probe_bake_thread_exit) { + break; + } + + Instance* to_bake=NULL; + + probe_bake_mutex->lock(); + + if (!probe_bake_list.empty()) { + to_bake=probe_bake_list.front()->get(); + probe_bake_list.pop_front(); + + } + probe_bake_mutex->unlock(); + + if (!to_bake) + continue; + + _bake_gi_probe(to_bake); + } +} + + + +uint32_t VisualServerScene::_gi_bake_find_cell(const GIProbeDataCell *cells,int x,int y, int z,int p_cell_subdiv) { + + + uint32_t cell=0; + + int ofs_x=0; + int ofs_y=0; + int ofs_z=0; + int size = 1<<(p_cell_subdiv-1); + int half=size/2; + + if (x<0 || x>=size) + return -1; + if (y<0 || y>=size) + return -1; + if (z<0 || z>=size) + return -1; + + for(int i=0;i= ofs_x + half) { + child|=1; + ofs_x+=half; + } + if (y >= ofs_y + half) { + child|=2; + ofs_y+=half; + } + if (z >= ofs_z + half) { + child|=4; + ofs_z+=half; + } + + cell = bc->children[child]; + if (cell==0xFFFFFFFF) + return 0xFFFFFFFF; + + half>>=1; + } + + return cell; + +} + +void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header,const GIProbeDataCell *cells,InstanceGIProbeData::LocalData *local_data,const uint32_t *leaves,int leaf_count, const InstanceGIProbeData::LightCache& light_cache,int sign) { + + + int light_r = int(light_cache.color.r * light_cache.energy * 1024.0)*sign; + int light_g = int(light_cache.color.g * light_cache.energy * 1024.0)*sign; + int light_b = int(light_cache.color.b * light_cache.energy * 1024.0)*sign; + + switch(light_cache.type) { + + case VS::LIGHT_DIRECTIONAL: { + + float limits[3]={float(header->width),float(header->height),float(header->depth)}; + Plane clip[3]; + int clip_planes=0; + float max_len = Vector3(limits[0],limits[1],limits[2]).length()*1.1; + + Vector3 light_axis = -light_cache.transform.basis.get_axis(2).normalized(); + + print_line("transform directional, axis: "+light_axis); + print_line("limits: "+Vector3(limits[0],limits[1],limits[2])); + + for(int i=0;i<3;i++) { + + if (ABS(light_axis[i])= unorm.y) && (unorm.x >= unorm.z) ) { + // x code + unorm = normal.x > 0.0 ? Vector3( 1.0, 0.0, 0.0 ) : Vector3( -1.0, 0.0, 0.0 ) ; + } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) { + // y code + unorm = normal.y > 0.0 ? Vector3( 0.0, 1.0, 0.0 ) : Vector3( 0.0, -1.0, 0.0 ) ; + } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) { + // z code + unorm = normal.z > 0.0 ? Vector3( 0.0, 0.0, 1.0 ) : Vector3( 0.0, 0.0, -1.0 ) ; + } else { + // oh-no we messed up code + // has to be + unorm = Vector3( 1.0, 0.0, 0.0 ); + } + + distance_adv = 1.0/normal.dot(unorm); + + } + + int success_count=0; + + uint64_t us = OS::get_singleton()->get_ticks_usec(); + + for(int i=0;ipos[0]+0.5,light->pos[1]+0.5,light->pos[2]+0.5); + + + Vector3 from = to - max_len * light_axis; + + for(int j=0;j-distance_adv) { //use this to avoid precision errors + + result = _gi_bake_find_cell(cells,int(floor(from.x)),int(floor(from.y)),int(floor(from.z)),header->cell_subdiv); + if (result!=0xFFFFFFFF) { + break; + } + + from+=light_axis*distance_adv; + distance-=distance_adv; + } + + if (result==idx) { + //cell hit itself! hooray! + light->energy[0]+=(uint32_t(light_r)*((cell->albedo>>16)&0xFF))>>8; + light->energy[1]+=(uint32_t(light_g)*((cell->albedo>>8)&0xFF))>>8; + light->energy[2]+=(uint32_t(light_b)*((cell->albedo)&0xFF))>>8; + success_count++; + } + } + print_line("BAKE TIME: "+rtos((OS::get_singleton()->get_ticks_usec()-us)/1000000.0)); + print_line("valid cells: "+itos(success_count)); + + + } break; + } +} + + +void VisualServerScene::_bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell* p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data) { + + //average light to upper level + p_local_data[p_idx].energy[0]=0; + p_local_data[p_idx].energy[1]=0; + p_local_data[p_idx].energy[2]=0; + + for(int i=0;i<8;i++) { + + uint32_t child = p_cells[p_idx].children[i]; + + if (child==0xFFFFFFFF) + continue; + + if (p_level+1 < (int)p_header->cell_subdiv-1) { + _bake_gi_downscale_light(child,p_level+1,p_cells,p_header,p_local_data); + } + + p_local_data[p_idx].energy[0]+=p_local_data[child].energy[0]; + p_local_data[p_idx].energy[1]+=p_local_data[child].energy[1]; + p_local_data[p_idx].energy[2]+=p_local_data[child].energy[2]; + + } + + //divide by eight for average + p_local_data[p_idx].energy[0]>>=3; + p_local_data[p_idx].energy[1]>>=3; + p_local_data[p_idx].energy[2]>>=3; + +} + + +void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { + + InstanceGIProbeData * probe_data = static_cast(p_gi_probe->base_data); + + DVector::Read r=probe_data->dynamic.light_data.read(); + + const GIProbeDataHeader *header = (const GIProbeDataHeader *)r.ptr(); + const GIProbeDataCell *cells = (const GIProbeDataCell*)&r[16]; + + int leaf_count = probe_data->dynamic.level_cell_lists[ header->cell_subdiv -1 ].size(); + const uint32_t *leaves = probe_data->dynamic.level_cell_lists[ header->cell_subdiv -1 ].ptr(); + + DVector::Write ldw = probe_data->dynamic.local_data.write(); + + InstanceGIProbeData::LocalData *local_data = ldw.ptr(); + + + //remove what must be removed + for (Map::Element *E=probe_data->dynamic.light_cache.front();E;E=E->next()) { + + RID rid = E->key(); + const InstanceGIProbeData::LightCache& lc = E->get(); + + if (!probe_data->dynamic.light_cache_changes.has(rid) || !(probe_data->dynamic.light_cache_changes[rid]==lc)) { + //erase light data + + _bake_gi_probe_light(header,cells,local_data,leaves,leaf_count,lc,-1); + } + + } + + //add what must be added + for (Map::Element *E=probe_data->dynamic.light_cache_changes.front();E;E=E->next()) { + + RID rid = E->key(); + const InstanceGIProbeData::LightCache& lc = E->get(); + + if (!probe_data->dynamic.light_cache.has(rid) || !(probe_data->dynamic.light_cache[rid]==lc)) { + //add light data + + _bake_gi_probe_light(header,cells,local_data,leaves,leaf_count,lc,1); + } + } + + SWAP(probe_data->dynamic.light_cache_changes,probe_data->dynamic.light_cache); + + //downscale to lower res levels + _bake_gi_downscale_light(0,0,cells,header,local_data); + + //plot result to 3D texture! + + for(int i=0;i<(int)header->cell_subdiv;i++) { + + int stage = header->cell_subdiv - i -1; + + if (stage >= probe_data->dynamic.mipmaps_3d.size()) + continue; //no mipmap for this one + + print_line("generating mipmap stage: "+itos(stage)); + int level_cell_count = probe_data->dynamic.level_cell_lists[ i ].size(); + const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[ i ].ptr(); + + DVector::Write lw = probe_data->dynamic.mipmaps_3d[stage].write(); + uint8_t *mipmapw = lw.ptr(); + + uint32_t sizes[3]={header->width>>stage,header->height>>stage,header->depth>>stage}; + + for(int j=0;j>2; + uint32_t g = local_data[idx].energy[1]>>2; + uint32_t b = local_data[idx].energy[2]>>2; + uint32_t a = cells[idx].alpha>>8; + + uint32_t mm_ofs = sizes[0]*sizes[1]*(local_data[idx].pos[2]) + sizes[0]*(local_data[idx].pos[1]) + (local_data[idx].pos[0]); + mm_ofs*=4; //for RGBA (4 bytes) + + mipmapw[mm_ofs+0]=uint8_t(CLAMP(r,0,255)); + mipmapw[mm_ofs+1]=uint8_t(CLAMP(g,0,255)); + mipmapw[mm_ofs+2]=uint8_t(CLAMP(b,0,255)); + mipmapw[mm_ofs+3]=uint8_t(CLAMP(a,0,255)); + + + } + } + + //send back to main thread to update un little chunks + probe_data->dynamic.updating_stage=GI_UPDATE_STAGE_UPLOADING; + +} + +bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) { + + InstanceGIProbeData * probe_data = static_cast(p_gi_probe->base_data); + + probe_data->dynamic.light_cache_changes.clear(); + + bool all_equal=true; + + + for (List::Element *E=p_gi_probe->scenario->directional_lights.front();E;E=E->next()) { + + InstanceGIProbeData::LightCache lc; + lc.type=VSG::storage->light_get_type(E->get()->base); + lc.color=VSG::storage->light_get_color(E->get()->base); + lc.energy=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ENERGY); + lc.radius=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_RANGE); + lc.attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ATTENUATION); + lc.spot_angle=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ANGLE); + lc.spot_attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ATTENUATION); + lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform; + + if (!probe_data->dynamic.light_cache.has(E->get()->self) || !(probe_data->dynamic.light_cache[E->get()->self]==lc)) { + all_equal=false; + } + + probe_data->dynamic.light_cache_changes[E->get()->self]=lc; + + } + + + for (Set::Element *E=probe_data->lights.front();E;E=E->next()) { + + InstanceGIProbeData::LightCache lc; + lc.type=VSG::storage->light_get_type(E->get()->base); + lc.color=VSG::storage->light_get_color(E->get()->base); + lc.energy=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ENERGY); + lc.radius=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_RANGE); + lc.attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ATTENUATION); + lc.spot_angle=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ANGLE); + lc.spot_attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ATTENUATION); + lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform; + + if (!probe_data->dynamic.light_cache.has(E->get()->self) || !(probe_data->dynamic.light_cache[E->get()->self]==lc)) { + all_equal=false; + } + + probe_data->dynamic.light_cache_changes[E->get()->self]=lc; + } + + //lighting changed from after to before, must do some updating + return !all_equal || probe_data->dynamic.light_cache_changes.size()!=probe_data->dynamic.light_cache.size(); + +} void VisualServerScene::render_probes() { + /* REFLECTION PROBES */ - SelfList *probe = reflection_probe_render_list.first(); + SelfList *ref_probe = reflection_probe_render_list.first(); bool busy=false; - while(probe) { + while(ref_probe) { - SelfList *next=probe->next(); - RID base = probe->self()->owner->base; + SelfList *next=ref_probe->next(); + RID base = ref_probe->self()->owner->base; switch(VSG::storage->reflection_probe_get_update_mode(base)) { @@ -2207,11 +2855,11 @@ void VisualServerScene::render_probes() { if (busy) //already rendering something break; - bool done = _render_probe_step(probe->self()->owner,probe->self()->render_step); + bool done = _render_reflection_probe_step(ref_probe->self()->owner,ref_probe->self()->render_step); if (done) { - reflection_probe_render_list.remove(probe); + reflection_probe_render_list.remove(ref_probe); } else { - probe->self()->render_step++; + ref_probe->self()->render_step++; } busy=true; //do not render another one of this kind @@ -2221,17 +2869,92 @@ void VisualServerScene::render_probes() { int step=0; bool done=false; while(!done) { - done = _render_probe_step(probe->self()->owner,step); + done = _render_reflection_probe_step(ref_probe->self()->owner,step); step++; } - reflection_probe_render_list.remove(probe); + reflection_probe_render_list.remove(ref_probe); } break; } - probe=next; + ref_probe=next; } + + /* GI PROBES */ + + SelfList *gi_probe = gi_probe_update_list.first(); + + while(gi_probe) { + + SelfList *next=gi_probe->next(); + + InstanceGIProbeData *probe = gi_probe->self(); + Instance *instance_probe = probe->owner; + + //check if probe must be setup, but don't do if on the lighting thread + + bool force_lighting=false; + + if (probe->invalid || (probe->dynamic.updating_stage==GI_UPDATE_STAGE_CHECK && probe->base_version!=VSG::storage->gi_probe_get_version(instance_probe->base))) { + + _setup_gi_probe(instance_probe); + force_lighting=true; + } + + if (probe->invalid==false && probe->dynamic.enabled) { + + switch(probe->dynamic.updating_stage) { + case GI_UPDATE_STAGE_CHECK: { + + if (_check_gi_probe(instance_probe) || force_lighting) { + //send to lighting thread + probe->dynamic.updating_stage=GI_UPDATE_STAGE_LIGHTING; + +#ifndef NO_THREADS + probe_bake_mutex->lock(); + probe_bake_list.push_back(instance_probe); + probe_bake_mutex->unlock(); + probe_bake_sem->post(); + +#else + + _bake_gi_probe(instance_probe); +#endif + + } + } break; + case GI_UPDATE_STAGE_LIGHTING: { + //do none, wait til done! + + } break; + case GI_UPDATE_STAGE_UPLOADING: { + + uint64_t us = OS::get_singleton()->get_ticks_usec(); + + for(int i=0;i<(int)probe->dynamic.mipmaps_3d.size();i++) { + + int mmsize = probe->dynamic.mipmaps_3d[i].size(); + DVector::Read r = probe->dynamic.mipmaps_3d[i].read(); + VSG::storage->gi_probe_dynamic_data_update_rgba8(probe->dynamic.probe_data,0,probe->dynamic.grid_size[2]>>i,i,r.ptr()); + } + + + probe->dynamic.updating_stage=GI_UPDATE_STAGE_CHECK; + +// print_line("UPLOAD TIME: "+rtos((OS::get_singleton()->get_ticks_usec()-us)/1000000.0)); + } break; + + } + } + //_update_gi_probe(gi_probe->self()->owner); + + + gi_probe=next; + } + + + } void VisualServerScene::_update_dirty_instance(Instance *p_instance) { @@ -2423,10 +3146,32 @@ bool VisualServerScene::free(RID p_rid) { VisualServerScene *VisualServerScene::singleton=NULL; + VisualServerScene::VisualServerScene() { +#ifndef NO_THREADS + probe_bake_sem = Semaphore::create(); + probe_bake_mutex = Mutex::create(); + probe_bake_thread = Thread::create(_gi_probe_bake_threads,this); + probe_bake_thread_exit=false; +#endif + render_pass=1; singleton=this; } + +VisualServerScene::~VisualServerScene() { + +#ifndef NO_THREADS + probe_bake_thread_exit=true; + Thread::wait_to_finish(probe_bake_thread); + memdelete(probe_bake_thread); + memdelete(probe_bake_sem); + memdelete(probe_bake_mutex); + +#endif + + +} diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 0eaad45c9..63cb1fd2b 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -7,6 +7,9 @@ #include "allocators.h" #include "octree.h" #include "self_list.h" +#include "os/thread.h" +#include "os/semaphore.h" +#include "semaphore.h" class VisualServerScene { public: @@ -69,6 +72,8 @@ public: #endif + /* CAMERA API */ + struct Camera : public RID_Data { enum Type { @@ -141,6 +146,7 @@ public: */ + /* SCENARIO API */ struct Instance; @@ -296,11 +302,15 @@ public: List reflection_probes; bool reflection_dirty; + List gi_probes; + bool gi_probes_dirty; + InstanceGeometryData() { lighting_dirty=false; reflection_dirty=true; can_cast_shadows=true; + gi_probes_dirty=true; } }; @@ -310,7 +320,7 @@ public: Instance *owner; struct PairInfo { - List::Element *L; //light iterator in geometry + List::Element *L; //reflection iterator in geometry Instance *geometry; }; List geometries; @@ -346,14 +356,112 @@ public: List geometries; + Instance *baked_light; + InstanceLightData() { shadow_dirty=true; D=NULL; last_version=0; + baked_light=NULL; } }; + struct InstanceGIProbeData : public InstanceBaseData { + + + Instance *owner; + + struct PairInfo { + List::Element *L; //gi probe iterator in geometry + Instance *geometry; + }; + + List geometries; + + Set lights; + + struct LightCache { + + VS::LightType type; + Transform transform; + Color color; + float energy; + float radius; + float attenuation; + float spot_angle; + float spot_attenuation; + + bool operator==(const LightCache& p_cache) { + + return (type==p_cache.type && + transform==p_cache.transform && + color==p_cache.color && + energy==p_cache.energy && + radius==p_cache.radius && + attenuation==p_cache.attenuation && + spot_angle==p_cache.spot_angle && + spot_attenuation==p_cache.spot_attenuation); + } + + LightCache() { + + type=VS::LIGHT_DIRECTIONAL; + energy=1.0; + radius=1.0; + attenuation=1.0; + spot_angle=1.0; + spot_attenuation=1.0; + + } + + }; + + struct LocalData { + uint16_t pos[3]; + uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights + }; + + + struct Dynamic { + + Map light_cache; + Map light_cache_changes; + DVector light_data; + DVector local_data; + Vector > level_cell_lists; + RID probe_data; + bool enabled; + + Vector< DVector > mipmaps_3d; + + int updating_stage; + + int grid_size[3]; + + Transform light_to_cell_xform; + + } dynamic; + + + RID probe_instance; + + + bool invalid; + uint32_t base_version; + + SelfList update_element; + + InstanceGIProbeData() : update_element(this) { + invalid=true; + base_version=0; + } + + }; + + + SelfList::List gi_probe_update_list; + Instance *instance_cull_result[MAX_INSTANCE_CULL]; Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps @@ -410,11 +518,61 @@ public: void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); - bool _render_probe_step(Instance* p_instance,int p_step); + //probes + struct GIProbeDataHeader { + + uint32_t version; + uint32_t cell_subdiv; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t cell_count; + uint32_t leaf_cell_count; + }; + + + struct GIProbeDataCell { + + uint32_t children[8]; + uint32_t albedo; + uint32_t emission; + uint32_t sides_used; + uint32_t alpha; + }; + + enum { + GI_UPDATE_STAGE_CHECK, + GI_UPDATE_STAGE_LIGHTING, + GI_UPDATE_STAGE_UPLOADING, + }; + + void _gi_probe_bake_thread(); + static void _gi_probe_bake_threads(void*); + + volatile bool probe_bake_thread_exit; + Thread *probe_bake_thread; + Semaphore *probe_bake_sem; + Mutex *probe_bake_mutex; + List probe_bake_list; + + bool _render_reflection_probe_step(Instance* p_instance,int p_step); + void _gi_probe_fill_local_data(int p_idx,int p_level,int p_x,int p_y,int p_z,const GIProbeDataCell* p_cell,const GIProbeDataHeader *p_header,InstanceGIProbeData::LocalData *p_local_data,Vector *prev_cell); + + _FORCE_INLINE_ uint32_t _gi_bake_find_cell(const GIProbeDataCell *cells,int x,int y, int z,int p_cell_subdiv); + void _bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell* p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data); + + void _bake_gi_probe_light(const GIProbeDataHeader *header,const GIProbeDataCell *cells,InstanceGIProbeData::LocalData *local_data,const uint32_t *leaves,int p_leaf_count, const InstanceGIProbeData::LightCache& light_cache,int p_sign); + void _bake_gi_probe(Instance *p_probe); + bool _check_gi_probe(Instance *p_gi_probe); + void _setup_gi_probe(Instance *p_instance); + void render_probes(); + + bool free(RID p_rid); VisualServerScene(); + ~VisualServerScene(); }; #endif // VISUALSERVERSCENE_H diff --git a/servers/visual_server.h b/servers/visual_server.h index 7558fbf81..6f2aa7395 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -445,7 +445,39 @@ public: virtual void portal_set_disable_distance(RID p_portal, float p_distance)=0; virtual void portal_set_disabled_color(RID p_portal, const Color& p_color)=0; - /* BAKED LIGHT API */ + /* GI PROBE API */ + + virtual RID gi_probe_create()=0; + + virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds)=0; + virtual AABB gi_probe_get_bounds(RID p_probe) const=0; + + virtual void gi_probe_set_cell_size(RID p_probe,float p_range)=0; + virtual float gi_probe_get_cell_size(RID p_probe) const=0; + + virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform)=0; + virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const=0; + + virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector& p_data)=0; + virtual DVector gi_probe_get_dynamic_data(RID p_probe) const=0; + + virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0; + virtual float gi_probe_get_dynamic_range(RID p_probe) const=0; + + enum GIProbeDataFormat { + GI_PROBE_DATA_RGBA8, + GI_PROBE_DATA_DXT5, + GI_PROBE_DATA_ETC2_EAC, + }; + + virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0; + virtual DVector gi_probe_get_static_data(RID p_gi_probe) const=0; + virtual GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0; + virtual int gi_probe_get_static_data_width(RID p_probe) const=0; + virtual int gi_probe_get_static_data_height(RID p_probe) const=0; + virtual int gi_probe_get_static_data_depth(RID p_probe) const=0; + + /* CAMERA API */ @@ -600,9 +632,9 @@ public: INSTANCE_REFLECTION_PROBE, INSTANCE_ROOM, INSTANCE_PORTAL, + INSTANCE_GI_PROBE, INSTANCE_MAX, - /*INSTANCE_BAKED_LIGHT, - INSTANCE_BAKED_LIGHT_SAMPLER,*/ + /*INSTANCE_BAKED_LIGHT_SAMPLER,*/ INSTANCE_GEOMETRY_MASK=(1< texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { -// material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,texture); + material->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,texture); + material->set_albedo(Color(1,1,1,1)); // material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1)); } else { missing_textures.push_back(texfile.get_file()); @@ -413,6 +414,8 @@ Error ColladaImport::_create_material(const String& p_target) { Ref texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { + material->set_texture(FixedSpatialMaterial::TEXTURE_SPECULAR,texture); + material->set_specular(Color(1,1,1,1)); // material->set_texture(FixedSpatialMaterial::PARAM_SPECULAR,texture); // material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1)); @@ -435,7 +438,9 @@ Error ColladaImport::_create_material(const String& p_target) { Ref texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { -// material->set_texture(FixedSpatialMaterial::PARAM_EMISSION,texture); + material->set_texture(FixedSpatialMaterial::TEXTURE_EMISSION,texture); + material->set_emission(Color(1,1,1,1)); + // material->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,Color(1,1,1,1)); }else { // missing_textures.push_back(texfile.get_file()); @@ -455,6 +460,8 @@ Error ColladaImport::_create_material(const String& p_target) { Ref texture = ResourceLoader::load(texfile,"Texture"); if (texture.is_valid()) { + material->set_texture(FixedSpatialMaterial::TEXTURE_NORMAL,texture); +// material->set_emission(Color(1,1,1,1)); // material->set_texture(FixedSpatialMaterial::PARAM_NORMAL,texture); }else { @@ -466,8 +473,10 @@ Error ColladaImport::_create_material(const String& p_target) { // material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR_EXP,effect.shininess); -// material->set_flag(Material::FLAG_DOUBLE_SIDED,effect.double_sided); -// material->set_flag(Material::FLAG_UNSHADED,effect.unshaded); + if (effect.double_sided) { + material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED); + } + material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,effect.unshaded); diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp index 41b245eb7..e3fb8986c 100644 --- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp @@ -1692,7 +1692,7 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map String str=name; int layer = str.substr(str.find("lm")+3,str.length()).to_int(); - mi->set_baked_light_texture_id(layer); + //mi->set_baked_light_texture_id(layer); } if (p_flags&SCENE_FLAG_CREATE_COLLISIONS && _teststr(name,"colonly")) { diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index a4a1aaedf..98b9a126d 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -2397,6 +2397,163 @@ ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe* p_probe){ +/// + + +String GIProbeGizmo::get_handle_name(int p_idx) const { + + switch(p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + } + + return ""; +} +Variant GIProbeGizmo::get_handle_value(int p_idx) const{ + + return probe->get_extents(); +} +void GIProbeGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){ + + Transform gt = probe->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + + Vector3 extents = probe->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*16384)}; + + Vector3 axis; + axis[p_idx]=1.0; + + Vector3 ra,rb; + Geometry::get_closest_points_between_segments(Vector3(),axis*16384,sg[0],sg[1],ra,rb); + float d = ra[p_idx]; + if (d<0.001) + d=0.001; + + extents[p_idx]=d; + probe->set_extents(extents); + +} + +void GIProbeGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){ + + Vector3 restore = p_restore; + + if (p_cancel) { + probe->set_extents(restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(probe,"set_extents",probe->get_extents()); + ur->add_undo_method(probe,"set_extents",restore); + ur->commit_action(); + +} + +void GIProbeGizmo::redraw(){ + + clear(); + + Vector lines; + Vector3 extents = probe->get_extents(); + + static const int subdivs[GIProbe::SUBDIV_MAX]={64,128,256,512}; + + AABB aabb = AABB(-extents,extents*2); + int subdiv = subdivs[probe->get_subdiv()]; + float cell_size = aabb.get_longest_axis_size()/subdiv; + + + for(int i=0;i<12;i++) { + Vector3 a,b; + aabb.get_edge(i,a,b); + lines.push_back(a); + lines.push_back(b); + } + + add_lines(lines,SpatialEditorGizmos::singleton->gi_probe_material); + add_collision_segments(lines); + + lines.clear(); + + for(int i=1;iaabb.size[j]) { + continue; + } + + Vector2 dir; + dir[j]=1.0; + Vector2 ta,tb; + int j_n1=(j+1)%3; + int j_n2=(j+2)%3; + ta[j_n1]=1.0; + tb[j_n2]=1.0; + + + for(int k=0;k<4;k++) { + + Vector3 from=aabb.pos,to=aabb.pos; + from[j]+= cell_size*i; + to[j]+=cell_size*i; + + if (k&1) { + to[j_n1]+=aabb.size[j_n1]; + } else { + + to[j_n2]+=aabb.size[j_n2]; + } + + if (k&2) { + from[j_n1]+=aabb.size[j_n1]; + from[j_n2]+=aabb.size[j_n2]; + } + + lines.push_back(from); + lines.push_back(to); + } + + } + + } + + add_lines(lines,SpatialEditorGizmos::singleton->reflection_probe_material_internal); + + Vector handles; + + + for(int i=0;i<3;i++) { + + Vector3 ax; + ax[i]=aabb.pos[i]+aabb.size[i]; + handles.push_back(ax); + } + + + add_handles(handles); + +} +GIProbeGizmo::GIProbeGizmo(GIProbe* p_probe){ + + probe=p_probe; + set_spatial_node(p_probe); +} + +//////// + void NavigationMeshSpatialGizmo::redraw() { @@ -3093,6 +3250,11 @@ Ref SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { Ref misg = memnew( ReflectionProbeGizmo(p_spatial->cast_to()) ); return misg; } + if (p_spatial->cast_to()) { + + Ref misg = memnew( GIProbeGizmo(p_spatial->cast_to()) ); + return misg; + } if (p_spatial->cast_to()) { @@ -3146,8 +3308,8 @@ Ref SpatialEditorGizmos::create_line_material(const Color& line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true); line_material->set_line_width(3.0); line_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true); - line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - line_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + //line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + //->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); line_material->set_albedo(p_base_color); return line_material; @@ -3298,7 +3460,9 @@ SpatialEditorGizmos::SpatialEditorGizmos() { car_wheel_material = create_line_material(Color(0.6,0.8,1.0)); visibility_notifier_material = create_line_material(Color(1.0,0.5,1.0)); reflection_probe_material = create_line_material(Color(0.5,1.0,0.7)); - reflection_probe_material_internal = create_line_material(Color(0.3,0.8,0.5,0.4)); + reflection_probe_material_internal = create_line_material(Color(0.3,0.8,0.5,0.15)); + gi_probe_material = create_line_material(Color(0.7,1.0,0.5)); + gi_probe_material_internal = create_line_material(Color(0.5,0.8,0.3,0.4)); joint_material = create_line_material(Color(0.6,0.8,1.0)); stream_player_icon = Ref( memnew( FixedSpatialMaterial )); diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h index 2cc1a7eab..eba143d32 100644 --- a/tools/editor/spatial_editor_gizmos.h +++ b/tools/editor/spatial_editor_gizmos.h @@ -46,6 +46,7 @@ #include "scene/3d/ray_cast.h" #include "scene/3d/navigation_mesh.h" #include "scene/3d/reflection_probe.h" +#include "scene/3d/gi_probe.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/collision_polygon.h" @@ -327,6 +328,25 @@ public: }; +class GIProbeGizmo : public EditorSpatialGizmo { + + OBJ_TYPE(GIProbeGizmo ,EditorSpatialGizmo); + + + GIProbe* probe; + +public: + + virtual String get_handle_name(int p_idx) const; + virtual Variant get_handle_value(int p_idx) const; + virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point); + virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false); + + void redraw(); + GIProbeGizmo(GIProbe* p_notifier=NULL); + +}; + class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { @@ -496,6 +516,8 @@ public: Ref skeleton_material; Ref reflection_probe_material; Ref reflection_probe_material_internal; + Ref gi_probe_material; + Ref gi_probe_material_internal; Ref room_material; Ref portal_material; Ref raycast_material; -- cgit v1.2.3-70-g09d2 From 37f558cd7b2308f6442f74c5265f12425d9887c8 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 21 Dec 2016 14:20:35 -0300 Subject: Some BRDF fixes --- core/ustring.cpp | 2 ++ drivers/gles3/rasterizer_gles3.cpp | 19 +++++++++++-- drivers/gles3/rasterizer_scene_gles3.cpp | 21 +++++++++++++- drivers/gles3/rasterizer_scene_gles3.h | 1 + drivers/gles3/rasterizer_storage_gles3.cpp | 13 +++++++-- drivers/gles3/rasterizer_storage_gles3.h | 6 ++++ drivers/gles3/shaders/scene.glsl | 44 ++++++++++++++++++++++-------- platform/x11/context_gl_x11.cpp | 2 +- servers/visual/visual_server_scene.cpp | 2 +- tools/editor/editor_initialize_ssl.cpp | 3 +- tools/editor/editor_resource_preview.cpp | 2 ++ 11 files changed, 95 insertions(+), 20 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/core/ustring.cpp b/core/ustring.cpp index 2e907381f..abda1f1a3 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -612,6 +612,8 @@ String String::get_slicec(CharType p_splitter, int p_slice) const { if (p_slice==count) { return substr(prev,i-prev); + } else if (c[i]==0) { + return String(); } else { count++; prev=i+1; diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 110436b9d..cb42790e6 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -130,9 +130,9 @@ void RasterizerGLES3::initialize() { ERR_PRINT("Error initializing GLAD"); } - glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); +// glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); // glDebugMessageCallbackARB(_gl_debug_print, NULL); - glEnable(_EXT_DEBUG_OUTPUT); +// glEnable(_EXT_DEBUG_OUTPUT); #endif @@ -169,6 +169,14 @@ void RasterizerGLES3::begin_frame(){ storage->update_dirty_skeletons(); storage->update_dirty_shaders(); storage->update_dirty_materials(); + + storage->info.render_object_count=0; + storage->info.render_material_switch_count=0; + storage->info.render_surface_switch_count=0; + storage->info.render_shader_rebind_count=0; + storage->info.render_vertices_count=0; + + scene->iteration(); @@ -277,6 +285,13 @@ void RasterizerGLES3::end_frame(){ canvas->draw_generic_textured_rect(Rect2(0,0,15,15),Rect2(0,0,1,1)); #endif OS::get_singleton()->swap_buffers(); + +/* print_line("objects: "+itos(storage->info.render_object_count)); + print_line("material chages: "+itos(storage->info.render_material_switch_count)); + print_line("surface changes: "+itos(storage->info.render_surface_switch_count)); + print_line("shader changes: "+itos(storage->info.render_shader_rebind_count)); + print_line("vertices: "+itos(storage->info.render_vertices_count)); +*/ } void RasterizerGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 65591de56..675b6f228 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1331,10 +1331,14 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0); + storage->info.render_vertices_count+=s->index_array_len; + } else { glDrawArrays(gl_primitive[s->primitive],0,s->array_len); + storage->info.render_vertices_count+=s->array_len; + } } break; @@ -1349,10 +1353,14 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glDrawElementsInstanced(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0,amount); + storage->info.render_vertices_count+=s->index_array_len * amount; + } else { glDrawArraysInstanced(gl_primitive[s->primitive],0,s->array_len,amount); + storage->info.render_vertices_count+=s->array_len * amount; + } } break; @@ -1379,6 +1387,8 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { int vertices = c.vertices.size(); uint32_t buf_ofs=0; + storage->info.render_vertices_count+=vertices; + if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) { const RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture); @@ -1704,6 +1714,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e bool first=true; + storage->info.render_object_count+=p_element_count; + for (int i=0;iinfo.render_material_switch_count++; + rebind = _setup_material(material,p_alpha_pass); -// _rinfo.mat_change_count++; + + if (rebind) { + storage->info.render_shader_rebind_count++; + } } if (!(e->sort_key&RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) { @@ -1877,6 +1894,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e if (prev_base_type != e->instance->base_type || prev_geometry!=e->geometry) { _setup_geometry(e); + storage->info.render_surface_switch_count++; + } _set_cull(e->sort_key&RenderList::SORT_KEY_MIRROR_FLAG,p_reverse_cull); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index ef1b7b8d3..ce869da13 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -148,6 +148,7 @@ public: } state; + /* SHADOW ATLAS API */ struct ShadowAtlas : public RID_Data { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index eca916854..9edc37fe3 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -826,15 +826,20 @@ Image RasterizerStorageGLES3::texture_get_data(RID p_texture,VS::CubeMapSide p_c DVector data; - int data_size = Image::get_image_data_size(texture->width,texture->height,texture->format,texture->mipmaps>1?-1:0); + int data_size = Image::get_image_data_size(texture->alloc_width,texture->alloc_height,texture->format,texture->mipmaps>1?-1:0); - data.resize(data_size); + data.resize(data_size*2); //add some memory at the end, just in case for buggy drivers DVector::Write wb = data.write(); glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target,texture->tex_id); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + + print_line("GET FORMAT: "+Image::get_format_name(texture->format)+" mipmaps: "+itos(texture->mipmaps)); + + for(int i=0;imipmaps;i++) { int ofs=0; @@ -848,7 +853,9 @@ Image RasterizerStorageGLES3::texture_get_data(RID p_texture,VS::CubeMapSide p_c glGetCompressedTexImage(texture->target,i,&wb[ofs]); } else { + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glGetTexImage(texture->target,i,texture->gl_format_cache,texture->gl_type_cache,&wb[ofs]); } } @@ -856,6 +863,8 @@ Image RasterizerStorageGLES3::texture_get_data(RID p_texture,VS::CubeMapSide p_c wb=DVector::Write(); + data.resize(data_size); + Image img(texture->alloc_width,texture->alloc_height,texture->mipmaps>1?true:false,texture->format,data); return img; diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b81c3df78..5d07d0be8 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -91,6 +91,12 @@ public: uint64_t texture_mem; + uint32_t render_object_count; + uint32_t render_material_switch_count; + uint32_t render_surface_switch_count; + uint32_t render_shader_rebind_count; + uint32_t render_vertices_count; + } info; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index bf561a7e4..c9de56be4 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -569,7 +569,7 @@ void light_compute(vec3 N, vec3 L,vec3 V,vec3 B, vec3 T,vec3 light_color,vec3 di float speci = dotNL * D * F * vis; - specular += speci * light_color * specular_color * specular_blob_intensity; + specular += speci * light_color /* specular_color*/ * specular_blob_intensity; #if defined(LIGHT_USE_CLEARCOAT) float Dr = GTR1(dotNH, mix(.1,.001,clearcoat_gloss)); @@ -780,7 +780,8 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw); highp vec4 reflection; - reflection.rgb = textureLod(reflection_atlas,splane.xy,roughness*5.0).rgb * ( brdf.x + brdf.y); + reflection.rgb = textureLod(reflection_atlas,splane.xy,roughness*5.0).rgb * brdf.x + brdf.y; + if (reflections[idx].params.z < 0.5) { reflection.rgb = mix(skybox,reflection.rgb,blend); } @@ -893,6 +894,7 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s blend=1.0; //radiance +#ifdef VCT_QUALITY_HIGH #define MAX_CONE_DIRS 6 vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] ( @@ -905,13 +907,28 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s ); float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15); + float cone_angle_tan = 0.577; +#else + +#define MAX_CONE_DIRS 4 + + vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] ( + vec3(0.707107, 0, 0.707107), + vec3(0, 0.707107, 0.707107), + vec3(-0.707107, 0, 0.707107), + vec3(0, -0.707107, 0.707107) + ); + + float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); + float cone_angle_tan = 0.98269; +#endif float max_distance = length(bounds); vec3 light=vec3(0.0); for(int i=0;idirectional_lights.size()); int directional_shadow_count=0; for (List::Element *E=scenario->directional_lights.front();E;E=E->next()) { diff --git a/tools/editor/editor_initialize_ssl.cpp b/tools/editor/editor_initialize_ssl.cpp index c0b55b302..968afba9d 100644 --- a/tools/editor/editor_initialize_ssl.cpp +++ b/tools/editor/editor_initialize_ssl.cpp @@ -35,10 +35,11 @@ void editor_initialize_certificates() { ByteArray data; - data.resize(_certs_uncompressed_size); + data.resize(_certs_uncompressed_size+1); { ByteArray::Write w = data.write(); Compression::decompress(w.ptr(),_certs_uncompressed_size,_certs_compressed,_certs_compressed_size,Compression::MODE_DEFLATE); + w[_certs_uncompressed_size]=0; //make sure it ends at zero } StreamPeerSSL::load_certs_from_memory(data); diff --git a/tools/editor/editor_resource_preview.cpp b/tools/editor/editor_resource_preview.cpp index 6afc3e2a3..46b81dc07 100644 --- a/tools/editor/editor_resource_preview.cpp +++ b/tools/editor/editor_resource_preview.cpp @@ -267,6 +267,8 @@ void EditorResourcePreview::_thread() { memdelete(f); } + cache_valid=false; + if (cache_valid) { texture = ResourceLoader::load(cache_base+".png","ImageTexture",true); -- cgit v1.2.3-70-g09d2 From f9603d82365823938129e68823a19739a3dd0b23 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 22 Dec 2016 10:00:15 -0300 Subject: can bake for omni and spotlight store normal when baking --- drivers/gles3/rasterizer_gles3.cpp | 6 +- drivers/gles3/rasterizer_scene_gles3.cpp | 39 +++--- drivers/gles3/rasterizer_scene_gles3.h | 3 +- drivers/gles3/rasterizer_storage_gles3.cpp | 41 +++++- drivers/gles3/rasterizer_storage_gles3.h | 13 +- drivers/gles3/shaders/scene.glsl | 29 +++- scene/3d/gi_probe.cpp | 129 ++++++++++++++++-- scene/3d/gi_probe.h | 27 +++- scene/main/viewport.cpp | 3 + servers/visual/rasterizer.h | 11 +- servers/visual/visual_server_raster.h | 10 +- servers/visual/visual_server_scene.cpp | 207 +++++++++++++++++++++++------ servers/visual/visual_server_scene.h | 4 +- servers/visual_server.h | 10 +- 14 files changed, 440 insertions(+), 92 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index cb42790e6..bf3b902c5 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -130,9 +130,9 @@ void RasterizerGLES3::initialize() { ERR_PRINT("Error initializing GLAD"); } -// glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); -// glDebugMessageCallbackARB(_gl_debug_print, NULL); -// glEnable(_EXT_DEBUG_OUTPUT); + glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + glDebugMessageCallbackARB(_gl_debug_print, NULL); + glEnable(_EXT_DEBUG_OUTPUT); #endif diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 675b6f228..1a63d451b 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -100,6 +100,8 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ shadow_atlas->depth=0; shadow_atlas->fbo=0; + + print_line("erasing atlas"); } for(int i=0;i<4;i++) { //clear subdivisions @@ -130,19 +132,18 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - //interpola nearest (though nvidia can improve this) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // Remove artifact on the edges of the shadowmap glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // We'll use a depth texture to store the depths in the shadow map - // Attach the depth texture to FBO depth attachment point glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_atlas->depth, 0); + + glViewport(0,0,shadow_atlas->size,shadow_atlas->size); + glClearDepth(0); + glClear(GL_DEPTH_BUFFER_BIT); + } } @@ -523,12 +524,19 @@ void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas,int p_size) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); + mmsize=reflection_atlas->size; for(int i=0;i<6;i++) { glGenFramebuffers(1, &reflection_atlas->fbo[i]); glBindFramebuffer(GL_FRAMEBUFFER, reflection_atlas->fbo[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, reflection_atlas->color, i); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); + glDisable(GL_SCISSOR_TEST); glViewport(0,0,mmsize,mmsize); glClearColor(0,0,0,0); @@ -538,8 +546,6 @@ void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas,int p_size) } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); } @@ -1020,11 +1026,12 @@ RID RasterizerSceneGLES3::gi_probe_instance_create() { return gi_probe_instance_owner.make_rid(gipi); } -void RasterizerSceneGLES3::gi_probe_instance_set_light_data(RID p_probe,RID p_data) { +void RasterizerSceneGLES3::gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) { GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND(!gipi); gipi->data=p_data; + gipi->probe=storage->gi_probe_owner.getornull(p_base); if (p_data.is_valid()) { RasterizerStorageGLES3::GIProbeData *gipd = storage->gi_probe_data_owner.getornull(p_data); ERR_FAIL_COND(!gipd); @@ -1571,6 +1578,8 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e,const Transform& glBindTexture(GL_TEXTURE_3D,gipi->tex_cache); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM1, gipi->transform_to_data * p_view_transform); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS1, gipi->bounds); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_MULTIPLIER1, gipi->probe?gipi->probe->dynamic_range*gipi->probe->energy:0.0); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BLEND_AMBIENT1, gipi->probe?!gipi->probe->interior:false); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE1, gipi->cell_size_cache); if (gi_probe_count>1) { @@ -1581,7 +1590,8 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e,const Transform& state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM2, gipi2->transform_to_data * p_view_transform); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS2, gipi2->bounds); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE2, gipi2->cell_size_cache); - + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_MULTIPLIER2, gipi2->probe?gipi2->probe->dynamic_range*gipi2->probe->energy:0.0); + state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BLEND_AMBIENT2, gipi2->probe?!gipi2->probe->interior:false); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, true ); } else { @@ -4209,7 +4219,6 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa fbo=shadow_atlas->fbo; vp_height=shadow_atlas->size; - uint32_t key = shadow_atlas->shadow_owners[p_light]; uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3; @@ -4299,24 +4308,22 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa render_list.sort_by_depth(false); //shadow is front to back for performance glDepthMask(true); - glColorMask(0,0,0,0); + glColorMask(1,1,1,1); glDisable(GL_BLEND); glDisable(GL_DITHER); glEnable(GL_DEPTH_TEST); - glBindFramebuffer(GL_FRAMEBUFFER,fbo); if (custom_vp_size) { glViewport(0,0,custom_vp_size,custom_vp_size); glScissor(0,0,custom_vp_size,custom_vp_size); + } else { glViewport(x,y,width,height); glScissor(x,y,width,height); } - //glViewport(x,vp_height-(height+y),width,height); - //glScissor(x,vp_height-(height+y),width,height); glEnable(GL_SCISSOR_TEST); glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); @@ -4331,7 +4338,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,true); - _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true,false,false); + _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,0,!flip_facing,false,true,false,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index ce869da13..31d9964ab 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -531,6 +531,7 @@ public: struct GIProbeInstance : public RID_Data { RID data; + RasterizerStorageGLES3::GIProbe *probe; GLuint tex_cache; Vector3 cell_size_cache; Vector3 bounds; @@ -542,7 +543,7 @@ public: mutable RID_Owner gi_probe_instance_owner; virtual RID gi_probe_instance_create(); - virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data); + virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_base,RID p_data); virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform); virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 9edc37fe3..fe8373b20 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -4695,6 +4695,8 @@ RID RasterizerStorageGLES3::gi_probe_create() { gip->data_depth=0; gip->bounds=AABB(Vector3(),Vector3(1,1,1)); gip->dynamic_range=1.0; + gip->energy=1.0; + gip->interior=false; gip->version=1; gip->cell_size=1.0; @@ -4773,7 +4775,7 @@ DVector RasterizerStorageGLES3::gi_probe_get_dynamic_data(RID p_probe) cons return gip->dynamic_data; } -void RasterizerStorageGLES3::gi_probe_set_dynamic_range(RID p_probe,float p_range){ +void RasterizerStorageGLES3::gi_probe_set_dynamic_range(RID p_probe,int p_range){ GIProbe *gip = gi_probe_owner.getornull(p_probe); ERR_FAIL_COND(!gip); @@ -4781,7 +4783,7 @@ void RasterizerStorageGLES3::gi_probe_set_dynamic_range(RID p_probe,float p_rang gip->dynamic_range=p_range; } -float RasterizerStorageGLES3::gi_probe_get_dynamic_range(RID p_probe) const{ +int RasterizerStorageGLES3::gi_probe_get_dynamic_range(RID p_probe) const{ const GIProbe *gip = gi_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!gip,0); @@ -4789,6 +4791,41 @@ float RasterizerStorageGLES3::gi_probe_get_dynamic_range(RID p_probe) const{ return gip->dynamic_range; } +void RasterizerStorageGLES3::gi_probe_set_energy(RID p_probe,float p_range){ + + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->energy=p_range; + +} + +void RasterizerStorageGLES3::gi_probe_set_interior(RID p_probe,bool p_enable) { + + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->interior=p_enable; + +} + +bool RasterizerStorageGLES3::gi_probe_is_interior(RID p_probe) const{ + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,false); + + return gip->interior; + +} + +float RasterizerStorageGLES3::gi_probe_get_energy(RID p_probe) const{ + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,0); + + return gip->energy; +} + void RasterizerStorageGLES3::gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth) { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 5d07d0be8..c51cd8d90 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -890,7 +890,9 @@ public: Transform to_cell; float cell_size; - float dynamic_range; + int dynamic_range; + float energy; + bool interior; uint32_t version; @@ -921,9 +923,14 @@ public: virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector& p_data); virtual DVector gi_probe_get_dynamic_data(RID p_probe) const; - virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range); - virtual float gi_probe_get_dynamic_range(RID p_probe) const; + virtual void gi_probe_set_dynamic_range(RID p_probe,int p_range); + virtual int gi_probe_get_dynamic_range(RID p_probe) const; + + virtual void gi_probe_set_energy(RID p_probe,float p_range); + virtual float gi_probe_get_energy(RID p_probe) const; + virtual void gi_probe_set_interior(RID p_probe,bool p_enable); + virtual bool gi_probe_is_interior(RID p_probe) const; virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth); virtual DVector gi_probe_get_static_data(RID p_gi_probe) const; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index c9de56be4..2dfbbd340 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -845,14 +845,18 @@ uniform mediump sampler3D gi_probe1; //texunit:-6 uniform highp mat4 gi_probe_xform1; uniform highp vec3 gi_probe_bounds1; uniform highp vec3 gi_probe_cell_size1; +uniform highp float gi_probe_multiplier1; +uniform bool gi_probe_blend_ambient1; uniform mediump sampler3D gi_probe2; //texunit:-7 uniform highp mat4 gi_probe_xform2; uniform highp vec3 gi_probe_bounds2; uniform highp vec3 gi_probe_cell_size2; +uniform highp float gi_probe_multiplier2; uniform bool gi_probe2_enabled; +uniform bool gi_probe_blend_ambient2; -vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance) { +vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, bool blend_ambient, vec3 direction, float tan_half_angle, float max_distance) { float dist = dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0; @@ -868,10 +872,12 @@ vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 direction, dist += diameter * 0.5; } + color.rgb = mix(color.rgb,mix(ambient,color.rgb,alpha),blend_ambient); + return color.rgb; } -void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, mat3 normal_mtx,vec3 ref_vec, float roughness, out vec4 out_spec, out vec4 out_diff) { +void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient,float multiplier, mat3 normal_mtx,vec3 ref_vec, float roughness, out vec4 out_spec, out vec4 out_diff) { @@ -928,15 +934,19 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s for(int i=0;i0.0) { diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index ce360859d..93d3e51a8 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -53,12 +53,35 @@ DVector GIProbeData::get_dynamic_data() const{ return VS::get_singleton()->gi_probe_get_dynamic_data(probe); } -void GIProbeData::set_dynamic_range(float p_range){ +void GIProbeData::set_dynamic_range(int p_range){ VS::get_singleton()->gi_probe_set_dynamic_range(probe,p_range); } -float GIProbeData::get_dynamic_range() const{ + +void GIProbeData::set_energy(float p_range) { + + VS::get_singleton()->gi_probe_set_energy(probe,p_range); +} + +float GIProbeData::get_energy() const{ + + return VS::get_singleton()->gi_probe_get_energy(probe); + +} + +void GIProbeData::set_interior(bool p_enable) { + + VS::get_singleton()->gi_probe_set_interior(probe,p_enable); + +} + +bool GIProbeData::is_interior() const{ + + return VS::get_singleton()->gi_probe_is_interior(probe); +} + +int GIProbeData::get_dynamic_range() const{ return VS::get_singleton()->gi_probe_get_dynamic_range(probe); @@ -154,15 +177,42 @@ Vector3 GIProbe::get_extents() const { return extents; } -void GIProbe::set_dynamic_range(float p_dynamic_range) { +void GIProbe::set_dynamic_range(int p_dynamic_range) { dynamic_range=p_dynamic_range; } -float GIProbe::get_dynamic_range() const { +int GIProbe::get_dynamic_range() const { return dynamic_range; } +void GIProbe::set_energy(float p_energy) { + + energy=p_energy; + if (probe_data.is_valid()) { + probe_data->set_energy(energy); + } +} +float GIProbe::get_energy() const { + + return energy; +} + +void GIProbe::set_interior(bool p_enable) { + + interior=p_enable; + if (probe_data.is_valid()) { + probe_data->set_interior(p_enable); + } +} + +bool GIProbe::is_interior() const { + + return interior; +} + + + #include "math.h" #define FINDMINMAX(x0,x1,x2,min,max) \ @@ -384,6 +434,8 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V Color albedo_accum; Color emission_accum; + Vector3 normal_accum; + float alpha=0.0; //map to a grid average in the best axis for this face @@ -441,6 +493,9 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V emission_accum.r+=p_material.emission[ofs].r; emission_accum.g+=p_material.emission[ofs].g; emission_accum.b+=p_material.emission[ofs].b; + + normal_accum+=normal; + alpha+=1.0; } @@ -471,6 +526,7 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V emission_accum.g=p_material.emission[ofs].g*alpha; emission_accum.b=p_material.emission[ofs].b*alpha; + normal_accum*=alpha; } else { @@ -486,6 +542,9 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V emission_accum.r*=accdiv; emission_accum.g*=accdiv; emission_accum.b*=accdiv; + + normal_accum*=accdiv; + } //put this temporarily here, corrected in a later step @@ -495,6 +554,9 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V p_baker->bake_cells[p_idx].emission[0]+=emission_accum.r; p_baker->bake_cells[p_idx].emission[1]+=emission_accum.g; p_baker->bake_cells[p_idx].emission[2]+=emission_accum.b; + p_baker->bake_cells[p_idx].normal[0]+=normal_accum.x; + p_baker->bake_cells[p_idx].normal[1]+=normal_accum.y; + p_baker->bake_cells[p_idx].normal[2]+=normal_accum.z; p_baker->bake_cells[p_idx].alpha+=alpha; static const Vector3 side_normals[6]={ @@ -506,11 +568,12 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V Vector3( 0, 0, 1), }; + /* for(int i=0;i<6;i++) { if (normal.dot(side_normals[i])>CMP_EPSILON) { p_baker->bake_cells[p_idx].used_sides|=(1<bake_cells[p_idx].emission[1]/=alpha; p_baker->bake_cells[p_idx].emission[2]/=alpha; + p_baker->bake_cells[p_idx].normal[0]/=alpha; + p_baker->bake_cells[p_idx].normal[1]/=alpha; + p_baker->bake_cells[p_idx].normal[2]/=alpha; + + Vector3 n(p_baker->bake_cells[p_idx].normal[0],p_baker->bake_cells[p_idx].normal[1],p_baker->bake_cells[p_idx].normal[2]); + if (n.length()<0.01) { + //too much fight over normal, zero it + p_baker->bake_cells[p_idx].normal[0]=0; + p_baker->bake_cells[p_idx].normal[1]=0; + p_baker->bake_cells[p_idx].normal[2]=0; + } else { + n.normalize(); + p_baker->bake_cells[p_idx].normal[0]=n.x; + p_baker->bake_cells[p_idx].normal[1]=n.y; + p_baker->bake_cells[p_idx].normal[2]=n.z; + } + + p_baker->bake_cells[p_idx].alpha=1.0; + /* //remove neighbours from used sides for(int n=0;n<6;n++) { @@ -653,6 +735,7 @@ void GIProbe::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker p_baker->bake_cells[p_idx].used_sides&=~(1<bake_cells[p_idx].emission[0]=0; p_baker->bake_cells[p_idx].emission[1]=0; p_baker->bake_cells[p_idx].emission[2]=0; + p_baker->bake_cells[p_idx].normal[0]=0; + p_baker->bake_cells[p_idx].normal[1]=0; + p_baker->bake_cells[p_idx].normal[2]=0; p_baker->bake_cells[p_idx].albedo[0]=0; p_baker->bake_cells[p_idx].albedo[1]=0; p_baker->bake_cells[p_idx].albedo[2]=0; @@ -1024,7 +1110,21 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){ w32[ofs++]=em; } - w32[ofs++]=baker.bake_cells[i].used_sides; + //w32[ofs++]=baker.bake_cells[i].used_sides; + { //normal + + Vector3 n(baker.bake_cells[i].normal[0],baker.bake_cells[i].normal[1],baker.bake_cells[i].normal[2]); + n=n*Vector3(0.5,0.5,0.5)+Vector3(0.5,0.5,0.5); + uint32_t norm=0; + + + norm|=uint32_t(CLAMP( n.x*255.0, 0, 255))<<16; + norm|=uint32_t(CLAMP( n.y*255.0, 0, 255))<<8; + norm|=uint32_t(CLAMP( n.z*255.0, 0, 255))<<0; + + w32[ofs++]=norm; + } + w32[ofs++]=uint32_t(baker.bake_cells[i].alpha*65535.0); } @@ -1036,6 +1136,9 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){ probe_data->set_bounds(AABB(-extents,extents*2.0)); probe_data->set_cell_size(baker.po2_bounds.size[longest_axis]/baker.axis_cell_size[longest_axis]); probe_data->set_dynamic_data(data); + probe_data->set_dynamic_range(dynamic_range); + probe_data->set_energy(energy); + probe_data->set_interior(interior); probe_data->set_to_cell_xform(baker.to_cell_space); set_probe_data(probe_data); @@ -1212,13 +1315,21 @@ void GIProbe::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_dynamic_range","max"),&GIProbe::set_dynamic_range); ObjectTypeDB::bind_method(_MD("get_dynamic_range"),&GIProbe::get_dynamic_range); + ObjectTypeDB::bind_method(_MD("set_energy","max"),&GIProbe::set_energy); + ObjectTypeDB::bind_method(_MD("get_energy"),&GIProbe::get_energy); + + ObjectTypeDB::bind_method(_MD("set_interior","enable"),&GIProbe::set_interior); + ObjectTypeDB::bind_method(_MD("is_interior"),&GIProbe::is_interior); + ObjectTypeDB::bind_method(_MD("bake","from_node","create_visual_debug"),&GIProbe::bake,DEFVAL(Variant()),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("debug_bake"),&GIProbe::_debug_bake); ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); ADD_PROPERTY( PropertyInfo(Variant::INT,"subdiv",PROPERTY_HINT_ENUM,"64,128,256,512"),_SCS("set_subdiv"),_SCS("get_subdiv")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"extents"),_SCS("set_extents"),_SCS("get_extents")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"dynamic_range",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_RANGE,"1,16,1"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_energy"),_SCS("get_energy")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"interior"),_SCS("set_interior"),_SCS("is_interior")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"data",PROPERTY_HINT_RESOURCE_TYPE,"GIProbeData"),_SCS("set_probe_data"),_SCS("get_probe_data")); @@ -1232,10 +1343,12 @@ void GIProbe::_bind_methods() { GIProbe::GIProbe() { subdiv=SUBDIV_128; - dynamic_range=1.0; + dynamic_range=4; + energy=1.0; extents=Vector3(10,10,10); color_scan_cell_width=4; bake_texture_size=128; + interior=false; gi_probe = VS::get_singleton()->gi_probe_create(); diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index e2017acfc..297672198 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -31,8 +31,14 @@ public: void set_dynamic_data(const DVector& p_data); DVector get_dynamic_data() const; - void set_dynamic_range(float p_range); - float get_dynamic_range() const; + void set_dynamic_range(int p_range); + int get_dynamic_range() const; + + void set_energy(float p_range); + float get_energy() const; + + void set_interior(bool p_enable); + bool is_interior() const; void set_static_data(const DVector& p_data,DataFormat p_format,int p_width,int p_height,int p_depth); DVector get_static_data() const; @@ -73,6 +79,7 @@ private: uint32_t childs[8]; float albedo[3]; //albedo in RGB24 float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) + float normal[3]; uint32_t used_sides; float alpha; //used for upsampling @@ -84,6 +91,7 @@ private: for(int i=0;i<3;i++) { emission[i]=0; albedo[i]=0; + normal[i]=0; } alpha=0; used_sides=0; @@ -126,7 +134,9 @@ private: Subdiv subdiv; Vector3 extents; - float dynamic_range; + int dynamic_range; + float energy; + bool interior; int color_scan_cell_width; int bake_texture_size; @@ -157,8 +167,15 @@ public: void set_extents(const Vector3& p_extents); Vector3 get_extents() const; - void set_dynamic_range(float p_dynamic_range); - float get_dynamic_range() const; + void set_dynamic_range(int p_dynamic_range); + int get_dynamic_range() const; + + void set_energy(float p_energy); + float get_energy() const; + + void set_interior(bool p_enable); + bool is_interior() const; + void bake(Node *p_from_node=NULL,bool p_create_visual_debug=false); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index bd5eb0a4e..728997e79 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1283,6 +1283,9 @@ bool Viewport::get_clear_on_new_frame() const{ void Viewport::set_shadow_atlas_size(int p_size) { + if (shadow_atlas_size==p_size) + return; + shadow_atlas_size=p_size; VS::get_singleton()->viewport_set_shadow_atlas_size(viewport,p_size); } diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 79560f348..f22b7e04f 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -149,7 +149,7 @@ public: virtual bool reflection_probe_instance_postprocess_step(RID p_instance)=0; virtual RID gi_probe_instance_create()=0; - virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data)=0; + virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_base,RID p_data)=0; virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform)=0; virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds)=0; @@ -418,9 +418,14 @@ public: virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector& p_data)=0; virtual DVector gi_probe_get_dynamic_data(RID p_probe) const=0; - virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0; - virtual float gi_probe_get_dynamic_range(RID p_probe) const=0; + virtual void gi_probe_set_dynamic_range(RID p_probe,int p_range)=0; + virtual int gi_probe_get_dynamic_range(RID p_probe) const=0; + virtual void gi_probe_set_energy(RID p_probe,float p_range)=0; + virtual float gi_probe_get_energy(RID p_probe) const=0; + + virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0; + virtual bool gi_probe_is_interior(RID p_probe) const=0; virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0; virtual DVector gi_probe_get_static_data(RID p_gi_probe) const=0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 191330c66..9dec587d1 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -816,8 +816,14 @@ public: BIND2(gi_probe_set_to_cell_xform,RID,const Transform&) BIND1RC(Transform,gi_probe_get_to_cell_xform,RID) - BIND2(gi_probe_set_dynamic_range,RID,float) - BIND1RC(float,gi_probe_get_dynamic_range,RID) + BIND2(gi_probe_set_dynamic_range,RID,int) + BIND1RC(int,gi_probe_get_dynamic_range,RID) + + BIND2(gi_probe_set_energy,RID,float) + BIND1RC(float,gi_probe_get_energy,RID) + + BIND2(gi_probe_set_interior,RID,bool) + BIND1RC(bool,gi_probe_is_interior,RID) BIND2(gi_probe_set_dynamic_data,RID,const DVector& ) BIND1RC( DVector,gi_probe_get_dynamic_data,RID) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 162647e42..d74f5265e 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1641,6 +1641,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,const } } + VSG::scene_render->light_instance_set_shadow_transform(light->instance,cm,xform,radius,0,i); VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,i,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count); } @@ -2203,10 +2204,10 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came } - bool redraw = VSG::scene_render->shadow_atlas_update_light(p_shadow_atlas,light->instance,coverage,light->last_version); if (redraw) { + print_line("redraw shadow"); //must redraw! _light_instance_update_shadow(ins,p_cam_transform,p_cam_projection,p_cam_orthogonal,p_shadow_atlas,scenario); } @@ -2407,6 +2408,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth); + probe->dynamic.bake_dynamic_range=VSG::storage->gi_probe_get_dynamic_range(p_instance->base); probe->dynamic.mipmaps_3d.clear(); @@ -2443,7 +2445,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { probe->dynamic.light_to_cell_xform=cell_to_xform * p_instance->transform.affine_inverse(); - VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,probe->dynamic.probe_data); + VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,probe->dynamic.probe_data); VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform); @@ -2457,7 +2459,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { probe->dynamic.enabled=false; probe->invalid=!data.is_valid(); if (data.is_valid()) { - VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,data); + VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,data); } } @@ -2541,6 +2543,30 @@ uint32_t VisualServerScene::_gi_bake_find_cell(const GIProbeDataCell *cells,int } +static float _get_normal_advance(const Vector3& p_normal ) { + + Vector3 normal = p_normal; + Vector3 unorm = normal.abs(); + + if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) { + // x code + unorm = normal.x > 0.0 ? Vector3( 1.0, 0.0, 0.0 ) : Vector3( -1.0, 0.0, 0.0 ) ; + } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) { + // y code + unorm = normal.y > 0.0 ? Vector3( 0.0, 1.0, 0.0 ) : Vector3( 0.0, -1.0, 0.0 ) ; + } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) { + // z code + unorm = normal.z > 0.0 ? Vector3( 0.0, 0.0, 1.0 ) : Vector3( 0.0, 0.0, -1.0 ) ; + } else { + // oh-no we messed up code + // has to be + unorm = Vector3( 1.0, 0.0, 0.0 ); + } + + return 1.0/normal.dot(unorm); + +} + void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header,const GIProbeDataCell *cells,InstanceGIProbeData::LocalData *local_data,const uint32_t *leaves,int leaf_count, const InstanceGIProbeData::LightCache& light_cache,int sign) { @@ -2548,20 +2574,20 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header,con int light_g = int(light_cache.color.g * light_cache.energy * 1024.0)*sign; int light_b = int(light_cache.color.b * light_cache.energy * 1024.0)*sign; + float limits[3]={float(header->width),float(header->height),float(header->depth)}; + Plane clip[3]; + int clip_planes=0; + + + switch(light_cache.type) { case VS::LIGHT_DIRECTIONAL: { - float limits[3]={float(header->width),float(header->height),float(header->depth)}; - Plane clip[3]; - int clip_planes=0; float max_len = Vector3(limits[0],limits[1],limits[2]).length()*1.1; Vector3 light_axis = -light_cache.transform.basis.get_axis(2).normalized(); - print_line("transform directional, axis: "+light_axis); - print_line("limits: "+Vector3(limits[0],limits[1],limits[2])); - for(int i=0;i<3;i++) { if (ABS(light_axis[i])= unorm.y) && (unorm.x >= unorm.z) ) { - // x code - unorm = normal.x > 0.0 ? Vector3( 1.0, 0.0, 0.0 ) : Vector3( -1.0, 0.0, 0.0 ) ; - } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) { - // y code - unorm = normal.y > 0.0 ? Vector3( 0.0, 1.0, 0.0 ) : Vector3( 0.0, -1.0, 0.0 ) ; - } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) { - // z code - unorm = normal.z > 0.0 ? Vector3( 0.0, 0.0, 1.0 ) : Vector3( 0.0, 0.0, -1.0 ) ; - } else { - // oh-no we messed up code - // has to be - unorm = Vector3( 1.0, 0.0, 0.0 ); - } - - distance_adv = 1.0/normal.dot(unorm); - - } + float distance_adv = _get_normal_advance(light_axis); int success_count=0; @@ -2614,7 +2618,18 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header,con InstanceGIProbeData::LocalData *light = &local_data[idx]; Vector3 to(light->pos[0]+0.5,light->pos[1]+0.5,light->pos[2]+0.5); + Vector3 norm ( + (((cells[idx].normal>>16)&0xFF)/255.0)*2.0-1.0, + (((cells[idx].normal>>8)&0xFF)/255.0)*2.0-1.0, + (((cells[idx].normal>>0)&0xFF)/255.0)*2.0-1.0 + ); + + float att = norm.dot(-light_axis); + if (att<0.001) { + //not lighting towards this + continue; + } Vector3 from = to - max_len * light_axis; @@ -2642,16 +2657,130 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header,con if (result==idx) { //cell hit itself! hooray! - light->energy[0]+=(uint32_t(light_r)*((cell->albedo>>16)&0xFF))>>8; - light->energy[1]+=(uint32_t(light_g)*((cell->albedo>>8)&0xFF))>>8; - light->energy[2]+=(uint32_t(light_b)*((cell->albedo)&0xFF))>>8; - success_count++; + light->energy[0]+=int32_t(light_r*att*((cell->albedo>>16)&0xFF)/255.0); + light->energy[1]+=int32_t(light_g*att*((cell->albedo>>8)&0xFF)/255.0); + light->energy[2]+=int32_t(light_b*att*((cell->albedo)&0xFF)/255.0); + success_count++; } } print_line("BAKE TIME: "+rtos((OS::get_singleton()->get_ticks_usec()-us)/1000000.0)); print_line("valid cells: "+itos(success_count)); + } break; + case VS::LIGHT_OMNI: + case VS::LIGHT_SPOT: { + + + uint64_t us = OS::get_singleton()->get_ticks_usec(); + + Vector3 light_pos = light_cache.transform.origin; + Vector3 spot_axis = -light_cache.transform.basis.get_axis(2).normalized(); + + + float local_radius = light_cache.radius * light_cache.transform.basis.get_axis(2).length(); + + for(int i=0;ipos[0]+0.5,light->pos[1]+0.5,light->pos[2]+0.5); + Vector3 norm ( + (((cells[idx].normal>>16)&0xFF)/255.0)*2.0-1.0, + (((cells[idx].normal>>8)&0xFF)/255.0)*2.0-1.0, + (((cells[idx].normal>>0)&0xFF)/255.0)*2.0-1.0 + ); + + Vector3 light_axis = (to - light_pos).normalized(); + float distance_adv = _get_normal_advance(light_axis); + + float att = norm.dot(-light_axis); + if (att<0.001) { + //not lighting towards this + continue; + } + + { + float d = light_pos.distance_to(to); + if (d+distance_adv > local_radius) + continue; // too far away + + float dt = CLAMP((d+distance_adv)/local_radius,0,1); + att*= pow(1.0-dt,light_cache.attenuation); + } + + + if (light_cache.type==VS::LIGHT_SPOT) { + + float angle = Math::rad2deg(acos(light_axis.dot(spot_axis))); + if (angle > light_cache.spot_angle) + continue; + + float d = CLAMP(angle/light_cache.spot_angle,1,0); + att*= pow(1.0-d,light_cache.spot_attenuation); + + } + + clip_planes=0; + + for(int c=0;c<3;c++) { + + if (ABS(light_axis[c])-distance_adv) { //use this to avoid precision errors + + result = _gi_bake_find_cell(cells,int(floor(from.x)),int(floor(from.y)),int(floor(from.z)),header->cell_subdiv); + if (result!=0xFFFFFFFF) { + break; + } + + from+=light_axis*distance_adv; + distance-=distance_adv; + } + + if (result==idx) { + //cell hit itself! hooray! + + light->energy[0]+=int32_t(light_r*att*((cell->albedo>>16)&0xFF)/255.0); + light->energy[1]+=int32_t(light_g*att*((cell->albedo>>8)&0xFF)/255.0); + light->energy[2]+=int32_t(light_b*att*((cell->albedo)&0xFF)/255.0); + + } + } + print_line("BAKE TIME: "+rtos((OS::get_singleton()->get_ticks_usec()-us)/1000000.0)); + + } break; } } @@ -2760,9 +2889,9 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { uint32_t idx = level_cells[j]; - uint32_t r = local_data[idx].energy[0]>>2; - uint32_t g = local_data[idx].energy[1]>>2; - uint32_t b = local_data[idx].energy[2]>>2; + uint32_t r = (uint32_t(local_data[idx].energy[0])/probe_data->dynamic.bake_dynamic_range)>>2; + uint32_t g = (uint32_t(local_data[idx].energy[1])/probe_data->dynamic.bake_dynamic_range)>>2; + uint32_t b = (uint32_t(local_data[idx].energy[2])/probe_data->dynamic.bake_dynamic_range)>>2; uint32_t a = cells[idx].alpha>>8; uint32_t mm_ofs = sizes[0]*sizes[1]*(local_data[idx].pos[2]) + sizes[0]*(local_data[idx].pos[1]) + (local_data[idx].pos[0]); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 894d3529a..418e8387b 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -432,6 +432,7 @@ public: Vector > level_cell_lists; RID probe_data; bool enabled; + int bake_dynamic_range; Vector< DVector > mipmaps_3d; @@ -536,7 +537,7 @@ public: uint32_t children[8]; uint32_t albedo; uint32_t emission; - uint32_t sides_used; + uint32_t normal; uint32_t alpha; }; @@ -560,7 +561,6 @@ public: _FORCE_INLINE_ uint32_t _gi_bake_find_cell(const GIProbeDataCell *cells,int x,int y, int z,int p_cell_subdiv); void _bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell* p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data); - void _bake_gi_probe_light(const GIProbeDataHeader *header,const GIProbeDataCell *cells,InstanceGIProbeData::LocalData *local_data,const uint32_t *leaves,int p_leaf_count, const InstanceGIProbeData::LightCache& light_cache,int p_sign); void _bake_gi_probe(Instance *p_probe); bool _check_gi_probe(Instance *p_gi_probe); diff --git a/servers/visual_server.h b/servers/visual_server.h index 6f2aa7395..20fe8e7d7 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -461,8 +461,14 @@ public: virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector& p_data)=0; virtual DVector gi_probe_get_dynamic_data(RID p_probe) const=0; - virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0; - virtual float gi_probe_get_dynamic_range(RID p_probe) const=0; + virtual void gi_probe_set_dynamic_range(RID p_probe,int p_range)=0; + virtual int gi_probe_get_dynamic_range(RID p_probe) const=0; + + virtual void gi_probe_set_energy(RID p_probe,float p_range)=0; + virtual float gi_probe_get_energy(RID p_probe) const=0; + + virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0; + virtual bool gi_probe_is_interior(RID p_probe) const=0; enum GIProbeDataFormat { GI_PROBE_DATA_RGBA8, -- cgit v1.2.3-70-g09d2 From 4e729f38e02274afc91319d8dc9d2dfea9e9438e Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 23 Dec 2016 00:37:38 -0300 Subject: baking now shows a proper button, and bakes can be saved. --- drivers/gles3/rasterizer_storage_gles3.cpp | 78 ++++----------------- drivers/gles3/rasterizer_storage_gles3.h | 20 ++---- scene/3d/gi_probe.cpp | 49 +++++++------- scene/3d/gi_probe.h | 17 ++--- servers/visual/rasterizer.h | 11 +-- servers/visual/visual_server_raster.h | 8 +-- servers/visual/visual_server_scene.cpp | 90 +++++++++++-------------- servers/visual_server.h | 16 +---- tools/editor/editor_node.cpp | 4 ++ tools/editor/plugins/gi_probe_editor_plugin.cpp | 58 ++++++++++++++++ tools/editor/plugins/gi_probe_editor_plugin.h | 37 ++++++++++ 11 files changed, 194 insertions(+), 194 deletions(-) create mode 100644 tools/editor/plugins/gi_probe_editor_plugin.cpp create mode 100644 tools/editor/plugins/gi_probe_editor_plugin.h (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index fe8373b20..24e6be588 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -645,6 +645,10 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture,const Image& p_image bool srgb; + if (config.keep_original_textures && !(texture->flags&VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { + texture->images[p_cube_side]=p_image; + } + Image img = _get_gl_image_and_format(p_image, p_image.get_format(),texture->flags,format,internal_format,type,compressed,srgb); if (config.shrink_textures_x2 && (p_image.has_mipmaps() || !p_image.is_compressed()) && !(texture->flags&VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { @@ -822,6 +826,9 @@ Image RasterizerStorageGLES3::texture_get_data(RID p_texture,VS::CubeMapSide p_c ERR_FAIL_COND_V(texture->data_size==0,Image()); ERR_FAIL_COND_V(texture->render_target,Image()); + if (!texture->images[p_cube_side].empty()) + return texture->images[p_cube_side]; + #ifdef GLES_OVER_GL DVector data; @@ -871,6 +878,7 @@ Image RasterizerStorageGLES3::texture_get_data(RID p_texture,VS::CubeMapSide p_c #else ERR_EXPLAIN("Sorry, It's not posible to obtain images back in OpenGL ES"); + return Image(); #endif } @@ -1047,6 +1055,11 @@ void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable config.shrink_textures_x2=p_enable; } +void RasterizerStorageGLES3::textures_keep_original(bool p_enable) { + + config.keep_original_textures=p_enable; +} + RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_resolution) const { Texture * texture = texture_owner.get(p_source); @@ -4690,9 +4703,6 @@ RID RasterizerStorageGLES3::gi_probe_create() { GIProbe *gip = memnew( GIProbe ); - gip->data_width=0; - gip->data_height=0; - gip->data_depth=0; gip->bounds=AABB(Vector3(),Vector3(1,1,1)); gip->dynamic_range=1.0; gip->energy=1.0; @@ -4827,64 +4837,6 @@ float RasterizerStorageGLES3::gi_probe_get_energy(RID p_probe) const{ } -void RasterizerStorageGLES3::gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth) { - - GIProbe *gip = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gip); - - if (gip->data.is_valid()) { - free(gip->data); - } - - gip->data=RID(); - //this is platform dependent - - gip->version++; - gip->instance_change_notify(); - -} -DVector RasterizerStorageGLES3::gi_probe_get_static_data(RID p_gi_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gip,DVector()); - - //platform dependent - return DVector(); -} -VS::GIProbeDataFormat RasterizerStorageGLES3::gi_probe_get_static_data_format(RID p_gi_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gip,VS::GI_PROBE_DATA_RGBA8); - - return gip->data_format; -} -int RasterizerStorageGLES3::gi_probe_get_static_data_width(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip,0); - - return gip->data_width; -} -int RasterizerStorageGLES3::gi_probe_get_static_data_height(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip,0); - return gip->data_height; -} -int RasterizerStorageGLES3::gi_probe_get_static_data_depth(RID p_probe) const { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip,0); - return gip->data_depth; -} - -RID RasterizerStorageGLES3::gi_probe_get_data(RID p_probe) { - - const GIProbe *gip = gi_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!gip,RID()); - - return gip->data; -} uint32_t RasterizerStorageGLES3::gi_probe_get_version(RID p_probe) { @@ -5892,9 +5844,6 @@ bool RasterizerStorageGLES3::free(RID p_rid){ // delete the texture GIProbe *gi_probe = gi_probe_owner.get(p_rid); - if (gi_probe->data.is_valid()) { - free(gi_probe->data); - } gi_probe_owner.free(p_rid); memdelete(gi_probe); @@ -6119,6 +6068,7 @@ void RasterizerStorageGLES3::initialize() { glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); frame.count=0; + config.keep_original_textures=false; } void RasterizerStorageGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index c51cd8d90..5a8246f03 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -56,6 +56,8 @@ public: int max_texture_size; Set extensions; + + bool keep_original_textures; } config; mutable struct Shaders { @@ -221,6 +223,8 @@ public: RenderTarget *render_target; + Image images[6]; + Texture() { using_srgb=false; @@ -272,6 +276,8 @@ public: virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const; + virtual void textures_keep_original(bool p_enable); + /* SKYBOX API */ struct SkyBox : public RID_Data { @@ -898,12 +904,6 @@ public: DVector dynamic_data; - RID data; - int data_width; - int data_height; - int data_depth; - VS::GIProbeDataFormat data_format; - }; @@ -932,14 +932,6 @@ public: virtual void gi_probe_set_interior(RID p_probe,bool p_enable); virtual bool gi_probe_is_interior(RID p_probe) const; - virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth); - virtual DVector gi_probe_get_static_data(RID p_gi_probe) const; - virtual VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const; - virtual int gi_probe_get_static_data_width(RID p_probe) const; - virtual int gi_probe_get_static_data_height(RID p_probe) const; - virtual int gi_probe_get_static_data_depth(RID p_probe) const; - - virtual RID gi_probe_get_data(RID p_probe); //get data in case this is static virtual uint32_t gi_probe_get_version(RID p_probe); struct GIProbeData : public RID_Data { diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 93d3e51a8..24ed12027 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -1,12 +1,6 @@ #include "gi_probe.h" #include "mesh_instance.h" -enum DataFormat { - DATA_RGBA8, - DATA_DXT5, - DATA_ETC2_EAC, -}; - void GIProbeData::set_bounds(const AABB& p_bounds) { @@ -87,40 +81,45 @@ int GIProbeData::get_dynamic_range() const{ return VS::get_singleton()->gi_probe_get_dynamic_range(probe); } -void GIProbeData::set_static_data(const DVector& p_data,DataFormat p_format,int p_width,int p_height,int p_depth){ - VS::get_singleton()->gi_probe_set_static_data(probe,p_data,VS::GIProbeDataFormat(p_format),p_width,p_height,p_depth); +RID GIProbeData::get_rid() const { + return probe; } -DVector GIProbeData::get_static_data() const{ - return VS::get_singleton()->gi_probe_get_static_data(probe); -} -GIProbeData::DataFormat GIProbeData::get_static_data_format() const{ +void GIProbeData::_bind_methods() { - return GIProbeData::DataFormat(VS::get_singleton()->gi_probe_get_static_data_format(probe)); + ObjectTypeDB::bind_method(_MD("set_bounds","bounds"),&GIProbeData::set_bounds); + ObjectTypeDB::bind_method(_MD("get_bounds"),&GIProbeData::get_bounds); -} -int GIProbeData::get_static_data_width() const{ + ObjectTypeDB::bind_method(_MD("set_cell_size","cell_size"),&GIProbeData::set_cell_size); + ObjectTypeDB::bind_method(_MD("get_cell_size"),&GIProbeData::get_cell_size); - return VS::get_singleton()->gi_probe_get_static_data_width(probe); + ObjectTypeDB::bind_method(_MD("set_to_cell_xform","to_cell_xform"),&GIProbeData::set_to_cell_xform); + ObjectTypeDB::bind_method(_MD("get_to_cell_xform"),&GIProbeData::get_to_cell_xform); -} -int GIProbeData::get_static_data_height() const{ + ObjectTypeDB::bind_method(_MD("set_dynamic_data","dynamic_data"),&GIProbeData::set_dynamic_data); + ObjectTypeDB::bind_method(_MD("get_dynamic_data"),&GIProbeData::get_dynamic_data); - return VS::get_singleton()->gi_probe_get_static_data_height(probe); + ObjectTypeDB::bind_method(_MD("set_dynamic_range","dynamic_range"),&GIProbeData::set_dynamic_range); + ObjectTypeDB::bind_method(_MD("get_dynamic_range"),&GIProbeData::get_dynamic_range); -} -int GIProbeData::get_static_data_depth() const{ + ObjectTypeDB::bind_method(_MD("set_energy","energy"),&GIProbeData::set_energy); + ObjectTypeDB::bind_method(_MD("get_energy"),&GIProbeData::get_energy); - return VS::get_singleton()->gi_probe_get_static_data_depth(probe); + ObjectTypeDB::bind_method(_MD("set_interior","interior"),&GIProbeData::set_interior); + ObjectTypeDB::bind_method(_MD("is_interior"),&GIProbeData::is_interior); -} + ADD_PROPERTY(PropertyInfo(Variant::_AABB,"bounds",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_bounds"),_SCS("get_bounds")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"cell_size",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_cell_size"),_SCS("get_cell_size")); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM,"to_cell_xform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_to_cell_xform"),_SCS("get_to_cell_xform")); -RID GIProbeData::get_rid() const { + ADD_PROPERTY(PropertyInfo(Variant::INT_ARRAY,"dynamic_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_dynamic_data"),_SCS("get_dynamic_data")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_energy"),_SCS("get_energy")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"interior",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_interior"),_SCS("is_interior")); - return probe; } GIProbeData::GIProbeData() { diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 297672198..aea01b536 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -10,13 +10,11 @@ class GIProbeData : public Resource { RID probe; +protected: + + static void _bind_methods(); public: - enum DataFormat { - DATA_RGBA8, - DATA_DXT5, - DATA_ETC2_EAC, - }; void set_bounds(const AABB& p_bounds); @@ -40,20 +38,13 @@ public: void set_interior(bool p_enable); bool is_interior() const; - void set_static_data(const DVector& p_data,DataFormat p_format,int p_width,int p_height,int p_depth); - DVector get_static_data() const; - DataFormat get_static_data_format() const; - int get_static_data_width() const; - int get_static_data_height() const; - int get_static_data_depth() const; - virtual RID get_rid() const; GIProbeData(); ~GIProbeData(); }; -VARIANT_ENUM_CAST(GIProbeData::DataFormat); + class GIProbe : public VisualInstance { OBJ_TYPE(GIProbe,VisualInstance); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index f22b7e04f..725a32590 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -193,6 +193,9 @@ public: virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const=0; + + virtual void textures_keep_original(bool p_enable)=0; + /* SKYBOX API */ virtual RID skybox_create()=0; @@ -427,14 +430,6 @@ public: virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0; virtual bool gi_probe_is_interior(RID p_probe) const=0; - virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0; - virtual DVector gi_probe_get_static_data(RID p_gi_probe) const=0; - virtual VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0; - virtual int gi_probe_get_static_data_width(RID p_probe) const=0; - virtual int gi_probe_get_static_data_height(RID p_probe) const=0; - virtual int gi_probe_get_static_data_depth(RID p_probe) const=0; - - virtual RID gi_probe_get_data(RID p_probe)=0; //get data in case this is static virtual uint32_t gi_probe_get_version(RID p_probe)=0; virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth)=0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 9dec587d1..fcfaf52e0 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -629,6 +629,8 @@ public: BIND1(texture_set_shrink_all_x2_on_set_data,bool) BIND1(texture_debug_usage,List*) + BIND1(textures_keep_original,bool) + /* SKYBOX API */ BIND0R(RID,skybox_create) @@ -828,12 +830,6 @@ public: BIND2(gi_probe_set_dynamic_data,RID,const DVector& ) BIND1RC( DVector,gi_probe_get_dynamic_data,RID) - BIND6(gi_probe_set_static_data,RID,const DVector&,GIProbeDataFormat,int,int,int) - BIND1RC(DVector,gi_probe_get_static_data,RID) - BIND1RC(GIProbeDataFormat,gi_probe_get_static_data_format,RID) - BIND1RC(int,gi_probe_get_static_data_width,RID) - BIND1RC(int,gi_probe_get_static_data_height,RID) - BIND1RC(int,gi_probe_get_static_data_depth,RID) #undef BINDBASE diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index d74f5265e..a7876d081 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2390,78 +2390,68 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { probe->dynamic.light_data=VSG::storage->gi_probe_get_dynamic_data(p_instance->base); - if (probe->dynamic.light_data.size()) { - //using dynamic data - DVector::Read r=probe->dynamic.light_data.read(); + if (probe->dynamic.light_data.size()==0) + return; + //using dynamic data + DVector::Read r=probe->dynamic.light_data.read(); - const GIProbeDataHeader *header = (GIProbeDataHeader *)r.ptr(); + const GIProbeDataHeader *header = (GIProbeDataHeader *)r.ptr(); - probe->dynamic.local_data.resize(header->cell_count); + probe->dynamic.local_data.resize(header->cell_count); - DVector::Write ldw = probe->dynamic.local_data.write(); + DVector::Write ldw = probe->dynamic.local_data.write(); - const GIProbeDataCell *cells = (GIProbeDataCell*)&r[16]; + const GIProbeDataCell *cells = (GIProbeDataCell*)&r[16]; - probe->dynamic.level_cell_lists.resize(header->cell_subdiv); + probe->dynamic.level_cell_lists.resize(header->cell_subdiv); - _gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr()); + _gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr()); - probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth); + probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth); - probe->dynamic.bake_dynamic_range=VSG::storage->gi_probe_get_dynamic_range(p_instance->base); + probe->dynamic.bake_dynamic_range=VSG::storage->gi_probe_get_dynamic_range(p_instance->base); - probe->dynamic.mipmaps_3d.clear(); + probe->dynamic.mipmaps_3d.clear(); - probe->dynamic.grid_size[0]=header->width; - probe->dynamic.grid_size[1]=header->height; - probe->dynamic.grid_size[2]=header->depth; + probe->dynamic.grid_size[0]=header->width; + probe->dynamic.grid_size[1]=header->height; + probe->dynamic.grid_size[2]=header->depth; - for(int i=0;i<(int)header->cell_subdiv;i++) { - - uint32_t x = header->width >> i; - uint32_t y = header->height >> i; - uint32_t z = header->depth >> i; - - //create and clear mipmap - DVector mipmap; - mipmap.resize(x*y*z*4); - DVector::Write w = mipmap.write(); - zeromem(w.ptr(),x*y*z*4); - w = DVector::Write(); - - probe->dynamic.mipmaps_3d.push_back(mipmap); + for(int i=0;i<(int)header->cell_subdiv;i++) { - if (x<=1 || y<=1 || z<=1) - break; - } + uint32_t x = header->width >> i; + uint32_t y = header->height >> i; + uint32_t z = header->depth >> i; - probe->dynamic.updating_stage=GI_UPDATE_STAGE_CHECK; - probe->invalid=false; - probe->dynamic.enabled=true; + //create and clear mipmap + DVector mipmap; + mipmap.resize(x*y*z*4); + DVector::Write w = mipmap.write(); + zeromem(w.ptr(),x*y*z*4); + w = DVector::Write(); - Transform cell_to_xform = VSG::storage->gi_probe_get_to_cell_xform(p_instance->base); - AABB bounds = VSG::storage->gi_probe_get_bounds(p_instance->base); - float cell_size = VSG::storage->gi_probe_get_cell_size(p_instance->base); + probe->dynamic.mipmaps_3d.push_back(mipmap); - probe->dynamic.light_to_cell_xform=cell_to_xform * p_instance->transform.affine_inverse(); + if (x<=1 || y<=1 || z<=1) + break; + } - VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,probe->dynamic.probe_data); - VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform); + probe->dynamic.updating_stage=GI_UPDATE_STAGE_CHECK; + probe->invalid=false; + probe->dynamic.enabled=true; + Transform cell_to_xform = VSG::storage->gi_probe_get_to_cell_xform(p_instance->base); + AABB bounds = VSG::storage->gi_probe_get_bounds(p_instance->base); + float cell_size = VSG::storage->gi_probe_get_cell_size(p_instance->base); + probe->dynamic.light_to_cell_xform=cell_to_xform * p_instance->transform.affine_inverse(); - VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance,bounds.size/cell_size); + VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,probe->dynamic.probe_data); + VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform); - } else { - RID data = VSG::storage->gi_probe_get_data(p_instance->base); - probe->dynamic.enabled=false; - probe->invalid=!data.is_valid(); - if (data.is_valid()) { - VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,data); - } - } + VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance,bounds.size/cell_size); probe->base_version=VSG::storage->gi_probe_get_version(p_instance->base); diff --git a/servers/visual_server.h b/servers/visual_server.h index 20fe8e7d7..ef7cbc03a 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -139,6 +139,8 @@ public: virtual void texture_debug_usage(List *r_info)=0; + virtual void textures_keep_original(bool p_enable)=0; + /* SKYBOX API */ virtual RID skybox_create()=0; @@ -470,20 +472,6 @@ public: virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0; virtual bool gi_probe_is_interior(RID p_probe) const=0; - enum GIProbeDataFormat { - GI_PROBE_DATA_RGBA8, - GI_PROBE_DATA_DXT5, - GI_PROBE_DATA_ETC2_EAC, - }; - - virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector& p_data,GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0; - virtual DVector gi_probe_get_static_data(RID p_gi_probe) const=0; - virtual GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0; - virtual int gi_probe_get_static_data_width(RID p_probe) const=0; - virtual int gi_probe_get_static_data_height(RID p_probe) const=0; - virtual int gi_probe_get_static_data_depth(RID p_probe) const=0; - - /* CAMERA API */ diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 99c2b468f..8ec10756c 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -99,6 +99,7 @@ #include "plugins/light_occluder_2d_editor_plugin.h" #include "plugins/color_ramp_editor_plugin.h" #include "plugins/collision_shape_2d_editor_plugin.h" +#include "plugins/gi_probe_editor_plugin.h" #include "main/input_default.h" // end #include "tools/editor/io_plugins/editor_texture_import_plugin.h" @@ -5361,6 +5362,8 @@ void EditorNode::_bind_methods() { EditorNode::EditorNode() { + VisualServer::get_singleton()->textures_keep_original(true); + EditorHelp::generate_doc(); //before any editor classes are crated SceneState::set_disable_placeholders(true); editor_initialize_certificates(); //for asset sharing @@ -6567,6 +6570,7 @@ EditorNode::EditorNode() { add_editor_plugin( memnew( SpriteFramesEditorPlugin(this) ) ); add_editor_plugin( memnew( TextureRegionEditorPlugin(this) ) ); add_editor_plugin( memnew( Particles2DEditorPlugin(this) ) ); + add_editor_plugin( memnew( GIProbeEditorPlugin(this) ) ); add_editor_plugin( memnew( Path2DEditorPlugin(this) ) ); // add_editor_plugin( memnew( PathEditorPlugin(this) ) ); //add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) ); diff --git a/tools/editor/plugins/gi_probe_editor_plugin.cpp b/tools/editor/plugins/gi_probe_editor_plugin.cpp new file mode 100644 index 000000000..5beee1d91 --- /dev/null +++ b/tools/editor/plugins/gi_probe_editor_plugin.cpp @@ -0,0 +1,58 @@ +#include "gi_probe_editor_plugin.h" + + +void GIProbeEditorPlugin::_bake() { + + if (gi_probe) { + gi_probe->bake(); + } +} + + +void GIProbeEditorPlugin::edit(Object *p_object) { + + GIProbe * s = p_object->cast_to(); + if (!s) + return; + + gi_probe=s; +} + +bool GIProbeEditorPlugin::handles(Object *p_object) const { + + return p_object->is_type("GIProbe"); +} + +void GIProbeEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) { + bake->show(); + } else { + + bake->hide(); + } + +} + +void GIProbeEditorPlugin::_bind_methods() { + + ObjectTypeDB::bind_method("_bake",&GIProbeEditorPlugin::_bake); +} + +GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { + + editor=p_node; + bake = memnew( Button ); + bake->set_text("Bake GI!"); + bake->set_icon(editor->get_gui_base()->get_icon("BakedLight","EditorIcons")); + bake->hide();; + bake->connect("pressed",this,"_bake"); + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU,bake); + gi_probe=NULL; +} + + +GIProbeEditorPlugin::~GIProbeEditorPlugin() { + + memdelete(bake); +} diff --git a/tools/editor/plugins/gi_probe_editor_plugin.h b/tools/editor/plugins/gi_probe_editor_plugin.h new file mode 100644 index 000000000..7db91beba --- /dev/null +++ b/tools/editor/plugins/gi_probe_editor_plugin.h @@ -0,0 +1,37 @@ +#ifndef GIPROBEEDITORPLUGIN_H +#define GIPROBEEDITORPLUGIN_H + +#include "tools/editor/editor_plugin.h" +#include "tools/editor/editor_node.h" +#include "scene/resources/material.h" +#include "scene/3d/gi_probe.h" + + + +class GIProbeEditorPlugin : public EditorPlugin { + + OBJ_TYPE( GIProbeEditorPlugin, EditorPlugin ); + + GIProbe *gi_probe; + + Button *bake; + EditorNode *editor; + + void _bake(); +protected: + + static void _bind_methods(); +public: + + virtual String get_name() const { return "GIProbe"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_node); + virtual bool handles(Object *p_node) const; + virtual void make_visible(bool p_visible); + + GIProbeEditorPlugin(EditorNode *p_node); + ~GIProbeEditorPlugin(); + +}; + +#endif // GIPROBEEDITORPLUGIN_H -- cgit v1.2.3-70-g09d2 From 0d4abf2aa3a336a8a04c83f0576c6b42783ba6e9 Mon Sep 17 00:00:00 2001 From: reduz Date: Sat, 24 Dec 2016 16:23:30 -0300 Subject: fixed a horrible bug on Windows AMD, scenes saved until now in this branch are no longer valid :( --- drivers/gles3/rasterizer_gles3.cpp | 8 +++++++- drivers/gles3/rasterizer_scene_gles3.cpp | 4 ++++ drivers/gles3/rasterizer_storage_gles3.cpp | 13 ++++++++----- drivers/gles3/shaders/scene.glsl | 2 +- platform/windows/context_gl_win.cpp | 2 +- scene/resources/mesh.cpp | 6 ++++-- servers/visual/visual_server_scene.cpp | 4 ++-- servers/visual_server.cpp | 17 +++++++++++++---- 8 files changed, 40 insertions(+), 16 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index bf3b902c5..ccc5c70c9 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -42,7 +42,13 @@ RasterizerScene *RasterizerGLES3::get_scene() { #define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 #define _EXT_DEBUG_OUTPUT 0x92E0 -static void _gl_debug_print(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam) +#ifdef WINDOWS_ENABLED +#define GLAPIENTRY APIENTRY +#else +#define GLAPIENTRY +#endif + +static void GLAPIENTRY _gl_debug_print(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam) { if (type==_EXT_DEBUG_TYPE_OTHER_ARB) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index d380d8d14..7fdd08a83 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1337,6 +1337,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { if (s->index_array_len>0) { + glDrawElements(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0); storage->info.render_vertices_count+=s->index_array_len; @@ -1349,6 +1350,9 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } + + + } break; case VS::INSTANCE_MULTIMESH: { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index ec71f6404..ffcd46280 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2481,6 +2481,8 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P for(int i=0;iindex_id); glBufferData(GL_ELEMENT_ARRAY_BUFFER,index_array_size,ir.ptr(),GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind + + } //generate arrays for faster state switching - for(int i=0;i<2;i++) { + for(int ai=0;ai<2;ai++) { - if (i==0) { + if (ai==0) { //for normal draw glGenVertexArrays(1,&surface->array_id); glBindVertexArray(surface->array_id); glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); - } else if (i==1) { + } else if (ai==1) { //for instancing draw (can be changed and no one cares) glGenVertexArrays(1,&surface->instancing_array_id); glBindVertexArray(surface->instancing_array_id); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 2dfbbd340..b0b278230 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -872,7 +872,7 @@ vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, b dist += diameter * 0.5; } - color.rgb = mix(color.rgb,mix(ambient,color.rgb,alpha),blend_ambient); + //color.rgb = mix(color.rgb,mix(ambient,color.rgb,alpha),blend_ambient); return color.rgb; } diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp index 57950d33c..fc6e33f40 100644 --- a/platform/windows/context_gl_win.cpp +++ b/platform/windows/context_gl_win.cpp @@ -165,7 +165,7 @@ Error ContextGL_Win::initialize() { WGL_CONTEXT_MAJOR_VERSION_ARB, 3,//we want a 3.3 context WGL_CONTEXT_MINOR_VERSION_ARB, 3, //and it shall be forward compatible so that we can only use up to date functionality - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB/*|WGL_CONTEXT_DEBUG_BIT_ARB*/, 0}; //zero indicates the end of the array PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; //pointer to the method diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index ec33bb53d..c454301e0 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -775,8 +775,10 @@ Ref Mesh::generate_triangle_mesh() const { DVector indices = a[ARRAY_INDEX]; DVector::Read ir = indices.read(); - for(int i=0;i p elem_size*=sizeof(float); } + if (elem_size==6) { + elem_size=8; + } + } break; case VS::ARRAY_NORMAL: { @@ -1207,7 +1216,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector p break; } /* determine wether using 16 or 32 bits indices */ - if (p_index_len>=(1<<16)) { + if (p_vertex_len>=(1<<16)) { elem_size=4; @@ -1505,7 +1514,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector p DVector arr; arr.resize(p_index_len); - if (p_index_len<(1<<16)) { + if (p_vertex_len<(1<<16)) { DVector::Write w = arr.write(); -- cgit v1.2.3-70-g09d2 From f4a56e7782526e5e20a4351c4c293a7b4f020acd Mon Sep 17 00:00:00 2001 From: reduz Date: Fri, 30 Dec 2016 08:35:54 -0300 Subject: begin work on new particle system --- drivers/gles3/rasterizer_storage_gles3.cpp | 194 ++++++++++++++-- drivers/gles3/rasterizer_storage_gles3.h | 86 +++++++- drivers/gles3/shaders/SCsub | 1 + drivers/gles3/shaders/particles.glsl | 114 ++++++++++ drivers/gles3/shaders/scene.glsl | 10 +- scene/2d/particles_2d.h | 1 - scene/3d/gi_probe.cpp | 11 +- scene/3d/gi_probe.h | 2 + servers/visual/rasterizer.h | 36 ++- servers/visual/visual_server_raster.h | 28 +++ servers/visual/visual_server_scene.cpp | 341 ++++++++++++++++++++++++++--- servers/visual/visual_server_scene.h | 11 +- servers/visual_server.h | 56 +++++ 13 files changed, 832 insertions(+), 59 deletions(-) create mode 100644 drivers/gles3/shaders/particles.glsl (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 698788316..3fc051354 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -4882,37 +4882,45 @@ uint32_t RasterizerStorageGLES3::gi_probe_get_version(RID p_probe) { return gip->version; } -RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth) { +RasterizerStorage::GIProbeCompression RasterizerStorageGLES3::gi_probe_get_dynamic_data_get_preferred_compression() const { + if (config.s3tc_supported) { + return GI_PROBE_S3TC; + } else { + return GI_PROBE_UNCOMPRESSED; + } +} + +RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) { GIProbeData *gipd = memnew( GIProbeData ); gipd->width=p_width; gipd->height=p_height; gipd->depth=p_depth; + gipd->compression=p_compression; glActiveTexture(GL_TEXTURE0); glGenTextures(1,&gipd->tex_id); glBindTexture(GL_TEXTURE_3D,gipd->tex_id); int level=0; + int min_size=1; + + if (gipd->compression==GI_PROBE_S3TC) { + min_size=4; + } print_line("dyndata create"); while(true) { - Vector data; - data.resize(p_width*p_height*p_depth*4); - - - for(int i=0;icompression==GI_PROBE_S3TC) { + int size = p_width * p_height * p_depth; + glCompressedTexImage3D(GL_TEXTURE_3D,level,_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT,p_width,p_height,p_depth,0, size,NULL); + } else { + glTexImage3D(GL_TEXTURE_3D,level,GL_RGBA8,p_width,p_height,p_depth,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); } - glTexImage3D(GL_TEXTURE_3D,level,GL_RGBA8,p_width,p_height,p_depth,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr()); - if (p_width<=1 || p_height<=1 || p_depth<=1) + if (p_width<=min_size || p_height<=min_size || p_depth<=min_size) break; p_width>>=1; p_height>>=1; @@ -4933,7 +4941,7 @@ RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width,int p_heigh return gi_probe_data_owner.make_rid(gipd); } -void RasterizerStorageGLES3::gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) { +void RasterizerStorageGLES3::gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) { GIProbeData *gipd = gi_probe_data_owner.getornull(p_gi_probe_data); ERR_FAIL_COND(!gipd); @@ -4957,14 +4965,168 @@ void RasterizerStorageGLES3::gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_d */ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_3D,gipd->tex_id); - glTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,GL_RGBA,GL_UNSIGNED_BYTE,p_data); + if (gipd->compression==GI_PROBE_S3TC) { + int size = (gipd->width>>p_mipmap) * (gipd->height>>p_mipmap) * p_slice_count; + glCompressedTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT,size, p_data); + } else { + glTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,GL_RGBA,GL_UNSIGNED_BYTE,p_data); + } //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data); //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr()); - print_line("update rgba8 "+itos(p_mipmap)); + +} + +/////// + + +RID RasterizerStorageGLES3::particles_create() { + + Particles *particles = memnew( Particles ); + + + return particles_owner.make_rid(particles); +} + +void RasterizerStorageGLES3::particles_set_emitting(RID p_particles,bool p_emitting) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->emitting=p_emitting; + +} +void RasterizerStorageGLES3::particles_set_amount(RID p_particles,int p_amount) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + +} +void RasterizerStorageGLES3::particles_set_lifetime(RID p_particles,float p_lifetime){ + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->lifetime=p_lifetime; +} +void RasterizerStorageGLES3::particles_set_pre_process_time(RID p_particles,float p_time) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->pre_process_time=p_time; + +} +void RasterizerStorageGLES3::particles_set_explosiveness_ratio(RID p_particles,float p_ratio) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->explosiveness=p_ratio; +} +void RasterizerStorageGLES3::particles_set_randomness_ratio(RID p_particles,float p_ratio) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->randomness=p_ratio; + +} +void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles,const AABB& p_aabb) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->custom_aabb=p_aabb; + } +void RasterizerStorageGLES3::particles_set_gravity(RID p_particles,const Vector3& p_gravity) { + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + particles->gravity=p_gravity; + +} +void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles,bool p_enable) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->use_local_coords=p_enable; +} +void RasterizerStorageGLES3::particles_set_process_material(RID p_particles,RID p_material) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->process_material=p_material; +} + +void RasterizerStorageGLES3::particles_set_emission_shape(RID p_particles, VS::ParticlesEmissionShape p_shape) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->emission_shape=p_shape; +} +void RasterizerStorageGLES3::particles_set_emission_sphere_radius(RID p_particles,float p_radius) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->emission_sphere_radius=p_radius; +} +void RasterizerStorageGLES3::particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->emission_box_extents=p_extents; +} +void RasterizerStorageGLES3::particles_set_emission_points(RID p_particles,const DVector& p_points) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->emission_points=p_points; +} + + +void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles,VS::ParticlesDrawOrder p_order) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->draw_order=p_order; +} + +void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles,int p_count) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + + particles->draw_passes.resize(p_count); +} +void RasterizerStorageGLES3::particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_pass,particles->draw_passes.size()); + p_pass,particles->draw_passes[p_pass].material=p_material; + +} +void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh) { + + Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND(!particles); + ERR_FAIL_INDEX(p_pass,particles->draw_passes.size()); + p_pass,particles->draw_passes[p_pass].mesh=p_mesh; + +} + +AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { + + const Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND_V(!particles,AABB()); + + return particles->computed_aabb; +} +//////// void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 5a8246f03..b0f980015 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -941,6 +941,7 @@ public: int depth; int levels; GLuint tex_id; + GIProbeCompression compression; GIProbeData() { } @@ -948,9 +949,90 @@ public: mutable RID_Owner gi_probe_data_owner; - virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth); - virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data); + virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const; + virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth,GIProbeCompression p_compression); + virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data); + /* PARTICLES */ + + struct Particles : public Instantiable { + + bool emitting; + int amount; + float lifetime; + float pre_process_time; + float explosiveness; + float randomness; + AABB custom_aabb; + Vector3 gravity; + bool use_local_coords; + RID process_material; + + VS::ParticlesEmissionShape emission_shape; + float emission_sphere_radius; + Vector3 emission_box_extents; + DVector emission_points; + GLuint emission_point_texture; + + VS::ParticlesDrawOrder draw_order; + struct DrawPass { + RID mesh; + RID material; + }; + + Vector draw_passes; + + AABB computed_aabb; + + Particles() { + emitting=false; + amount=0; + lifetime=1.0;; + pre_process_time=0.0; + explosiveness=0.0; + randomness=0.0; + use_local_coords=true; + + draw_order=VS::PARTICLES_DRAW_ORDER_INDEX; + emission_shape=VS::PARTICLES_EMSSION_POINT; + emission_sphere_radius=1.0; + float emission_sphere_radius; + emission_box_extents=Vector3(1,1,1); + emission_point_texture=0; + } + + }; + + mutable RID_Owner particles_owner; + + virtual RID particles_create(); + + virtual void particles_set_emitting(RID p_particles,bool p_emitting); + virtual void particles_set_amount(RID p_particles,int p_amount); + virtual void particles_set_lifetime(RID p_particles,float p_lifetime); + virtual void particles_set_pre_process_time(RID p_particles,float p_time); + virtual void particles_set_explosiveness_ratio(RID p_particles,float p_ratio); + virtual void particles_set_randomness_ratio(RID p_particles,float p_ratio); + virtual void particles_set_custom_aabb(RID p_particles,const AABB& p_aabb); + virtual void particles_set_gravity(RID p_particles,const Vector3& p_gravity); + virtual void particles_set_use_local_coordinates(RID p_particles,bool p_enable); + virtual void particles_set_process_material(RID p_particles,RID p_material); + + virtual void particles_set_emission_shape(RID p_particles,VS::ParticlesEmissionShape p_shape); + virtual void particles_set_emission_sphere_radius(RID p_particles,float p_radius); + virtual void particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents); + virtual void particles_set_emission_points(RID p_particles,const DVector& p_points); + + + virtual void particles_set_draw_order(RID p_particles,VS::ParticlesDrawOrder p_order); + + virtual void particles_set_draw_passes(RID p_particles,int p_count); + virtual void particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material); + virtual void particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh); + + virtual AABB particles_get_current_aabb(RID p_particles); + + /* INSTANCE */ virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance); virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance); diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index 272f9bb5e..f9baeae97 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -17,5 +17,6 @@ if env['BUILDERS'].has_key('GLES3_GLSL'): env.GLES3_GLSL('ssao_blur.glsl'); env.GLES3_GLSL('exposure.glsl'); env.GLES3_GLSL('tonemap.glsl'); + env.GLES3_GLSL('particles.glsl'); diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl new file mode 100644 index 000000000..fb6060957 --- /dev/null +++ b/drivers/gles3/shaders/particles.glsl @@ -0,0 +1,114 @@ +[vertex] + + + +layout(location=0) in highp vec4 pos_lifetime; +layout(location=1) in highp vec4 color; +layout(location=2) in highp vec4 velocity_seed; +layout(location=3) in highp vec4 rot_active; + + +struct Attractor { + + vec3 pos; + vec3 dir; + float radius; + float eat_radius; + float strength; + float attenuation; +}; + +#define MAX_ATTRACTORS 64 + +uniform mat4 origin; +uniform float system_phase; +uniform float prev_system_phase; +uniform float total_particles; +uniform float explosiveness; +uniform vec4 time; +uniform float delta; +uniform vec3 gravity; +uniform int attractor_count; +uniform Attractor attractors[MAX_ATTRACTORS]; + + +out highp vec4 out_pos_lifetime; //tfb: +out highp vec4 out_color; //tfb: +out highp vec4 out_velocity_seed; //tfb: +out highp vec4 out_rot_active; //tfb: + +void main() { + + bool apply_forces=true; + bool apply_velocity=true; + + float mass = 1.0; + + float restart_phase = float(gl_InstanceID)/total_particles; + restart_phase*= explosiveness; + bool restart=false; + + if (system_phase > prev_system_phase) { + restart = prev_system_phase < restart_phase && system_phase >= restart_phase; + } else { + restart = prev_system_phase < restart_phase || system_phase >= restart_phase; + } + + if (restart) { + out_rot_active.a=1.0; + } + + out_pos_lifetime=pos_lifetime; + out_color=color; + out_velocity_seed=velocity_seed; + out_rot_active=rot_active; + + if (out_rot_active.a) { + //execute shader + + } + + + if (apply_forces) { + + vec3 force = gravity; + for(int i=0;i0 && attractors[i].eat_radius > dist) { + rot_active.a=0.0; + } + + rel_vec = normalize(rel_vec); + + float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation); + + if (attractors[i].dir==vec3(0.0)) { + //towards center + force+=attractors[i].strength * rel_vec * attenuation * mass; + } else { + force+=attractors[i].strength * attractors[i].dir * attenuation *mass; + + } + } + + out_velocity_seed.xyz += force * delta; + } + + if (apply_velocity) { + + out_pos_lifetime.xyz += out_velocity_seed.xyz * delta; + } + +} + +[fragment] + + +void main() { + + +} diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index b0b278230..90c501ea3 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -899,8 +899,10 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z)); blend=1.0; + float max_distance = length(bounds); + //radiance -#ifdef VCT_QUALITY_HIGH +#ifndef VCT_QUALITY_HIGH #define MAX_CONE_DIRS 6 vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] ( @@ -914,6 +916,7 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15); float cone_angle_tan = 0.577; + float min_ref_tan = 0.0; #else #define MAX_CONE_DIRS 4 @@ -927,9 +930,10 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); float cone_angle_tan = 0.98269; + max_distance*=0.5; + float min_ref_tan = 0.2; #endif - float max_distance = length(bounds); vec3 light=vec3(0.0); for(int i=0;ibake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) { //sub cell must be created - p_baker->bake_cells[p_idx].childs[i]=p_baker->bake_cells.size(); + uint32_t child_idx = p_baker->bake_cells.size(); + p_baker->bake_cells[p_idx].childs[i]=child_idx; p_baker->bake_cells.resize( p_baker->bake_cells.size() + 1); + p_baker->bake_cells[child_idx].level=p_level+1; } @@ -1124,7 +1126,12 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){ w32[ofs++]=norm; } - w32[ofs++]=uint32_t(baker.bake_cells[i].alpha*65535.0); + { + uint16_t alpha = CLAMP(uint32_t(baker.bake_cells[i].alpha*65535.0),0,65535); + uint16_t level = baker.bake_cells[i].level; + + w32[ofs++] = (uint32_t(level)<<16)|uint32_t(alpha); + } } diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index aea01b536..ca882856c 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -73,6 +73,7 @@ private: float normal[3]; uint32_t used_sides; float alpha; //used for upsampling + int level; Cell() { for(int i=0;i<8;i++) { @@ -86,6 +87,7 @@ private: } alpha=0; used_sides=0; + level=0; } }; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 844504372..eda67f2ed 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -432,14 +432,44 @@ public: virtual uint32_t gi_probe_get_version(RID p_probe)=0; - enum GIProbeCompress { + enum GIProbeCompression { GI_PROBE_UNCOMPRESSED, GI_PROBE_S3TC, GI_PROBE_ETC2 }; - virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth)=0; - virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0; + virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const=0; + virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth,GIProbeCompression p_compression)=0; + virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0; + + /* PARTICLES */ + + virtual RID particles_create()=0; + + virtual void particles_set_emitting(RID p_particles,bool p_emitting)=0; + virtual void particles_set_amount(RID p_particles,int p_amount)=0; + virtual void particles_set_lifetime(RID p_particles,float p_lifetime)=0; + virtual void particles_set_pre_process_time(RID p_particles,float p_time)=0; + virtual void particles_set_explosiveness_ratio(RID p_particles,float p_ratio)=0; + virtual void particles_set_randomness_ratio(RID p_particles,float p_ratio)=0; + virtual void particles_set_custom_aabb(RID p_particles,const AABB& p_aabb)=0; + virtual void particles_set_gravity(RID p_particles,const Vector3& p_gravity)=0; + virtual void particles_set_use_local_coordinates(RID p_particles,bool p_enable)=0; + virtual void particles_set_process_material(RID p_particles,RID p_material)=0; + + virtual void particles_set_emission_shape(RID p_particles,VS::ParticlesEmissionShape p_shape)=0; + virtual void particles_set_emission_sphere_radius(RID p_particles,float p_radius)=0; + virtual void particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents)=0; + virtual void particles_set_emission_points(RID p_particles,const DVector& p_points)=0; + + + virtual void particles_set_draw_order(RID p_particles,VS::ParticlesDrawOrder p_order)=0; + + virtual void particles_set_draw_passes(RID p_particles,int p_count)=0; + virtual void particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material)=0; + virtual void particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh)=0; + + virtual AABB particles_get_current_aabb(RID p_particles)=0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index fcfaf52e0..5088dedb5 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -830,6 +830,34 @@ public: BIND2(gi_probe_set_dynamic_data,RID,const DVector& ) BIND1RC( DVector,gi_probe_get_dynamic_data,RID) + /* PARTICLES */ + + BIND0R(RID, particles_create) + + BIND2(particles_set_emitting,RID,bool) + BIND2(particles_set_amount,RID,int ) + BIND2(particles_set_lifetime,RID,float ) + BIND2(particles_set_pre_process_time,RID,float ) + BIND2(particles_set_explosiveness_ratio,RID,float ) + BIND2(particles_set_randomness_ratio,RID,float ) + BIND2(particles_set_custom_aabb,RID,const AABB& ) + BIND2(particles_set_gravity,RID,const Vector3& ) + BIND2(particles_set_use_local_coordinates,RID,bool ) + BIND2(particles_set_process_material,RID,RID ) + + BIND2(particles_set_emission_shape,RID,VS::ParticlesEmissionShape ) + BIND2(particles_set_emission_sphere_radius,RID,float ) + BIND2(particles_set_emission_box_extents,RID,const Vector3& ) + BIND2(particles_set_emission_points,RID,const DVector& ) + + + BIND2(particles_set_draw_order,RID,VS::ParticlesDrawOrder ) + + BIND2(particles_set_draw_passes,RID,int ) + BIND3(particles_set_draw_pass_material,RID,int , RID ) + BIND3(particles_set_draw_pass_mesh,RID,int , RID ) + + BIND1R(AABB,particles_get_current_aabb,RID); #undef BINDBASE diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index aa97b2ebd..deb391c77 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2391,7 +2391,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { probe->dynamic.light_data=VSG::storage->gi_probe_get_dynamic_data(p_instance->base); if (probe->dynamic.light_data.size()==0) - return; + return; //using dynamic data DVector::Read r=probe->dynamic.light_data.read(); @@ -2399,15 +2399,17 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { probe->dynamic.local_data.resize(header->cell_count); + int cell_count = probe->dynamic.local_data.size(); DVector::Write ldw = probe->dynamic.local_data.write(); - const GIProbeDataCell *cells = (GIProbeDataCell*)&r[16]; probe->dynamic.level_cell_lists.resize(header->cell_subdiv); _gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr()); - probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth); + probe->dynamic.compression = VSG::storage->gi_probe_get_dynamic_data_get_preferred_compression(); + + probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth,probe->dynamic.compression); probe->dynamic.bake_dynamic_range=VSG::storage->gi_probe_get_dynamic_range(p_instance->base); @@ -2417,6 +2419,14 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { probe->dynamic.grid_size[1]=header->height; probe->dynamic.grid_size[2]=header->depth; + int size_limit = 1; + int size_divisor = 1; + + if (probe->dynamic.compression==RasterizerStorage::GI_PROBE_S3TC) { + print_line("S3TC"); + size_limit=4; + size_divisor=4; + } for(int i=0;i<(int)header->cell_subdiv;i++) { uint32_t x = header->width >> i; @@ -2425,14 +2435,16 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { //create and clear mipmap DVector mipmap; - mipmap.resize(x*y*z*4); + int size = x*y*z*4; + size/=size_divisor; + mipmap.resize(size); DVector::Write w = mipmap.write(); - zeromem(w.ptr(),x*y*z*4); + zeromem(w.ptr(),size); w = DVector::Write(); probe->dynamic.mipmaps_3d.push_back(mipmap); - if (x<=1 || y<=1 || z<=1) + if (x<=size_limit || y<=size_limit || z<=size_limit) break; } @@ -2449,12 +2461,132 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,probe->dynamic.probe_data); VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform); - - VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance,bounds.size/cell_size); probe->base_version=VSG::storage->gi_probe_get_version(p_instance->base); + //if compression is S3TC, fill it up + if (probe->dynamic.compression==RasterizerStorage::GI_PROBE_S3TC) { + + //create all blocks + Vector > comp_blocks; + int mipmap_count = probe->dynamic.mipmaps_3d.size(); + comp_blocks.resize(mipmap_count); + + for(int i=0;i>16; + int mipmap = header->cell_subdiv - level -1; + if (mipmap >= mipmap_count) + continue;//uninteresting + + + int blockx = (ld.pos[0]>>2); + int blocky = (ld.pos[1]>>2); + int blockz = (ld.pos[2]); //compression is x/y only + + int blockw = (header->width >> mipmap) >> 2; + int blockh = (header->height >> mipmap) >> 2; + + //print_line("cell "+itos(i)+" level "+itos(level)+"mipmap: "+itos(mipmap)+" pos: "+Vector3(blockx,blocky,blockz)+" size "+Vector2(blockw,blockh)); + + uint32_t key = blockz * blockw*blockh + blocky * blockw + blockx; + + Map & cmap = comp_blocks[mipmap]; + + if (!cmap.has(key)) { + + InstanceGIProbeData::CompBlockS3TC k; + k.offset=key; //use offset as counter first + k.source_count=0; + cmap[key]=k; + } + + InstanceGIProbeData::CompBlockS3TC &k=cmap[key]; + ERR_CONTINUE(k.source_count==16); + k.sources[k.source_count++]=i; + } + + //fix the blocks, precomputing what is needed + probe->dynamic.mipmaps_s3tc.resize(mipmap_count); + + for(int i=0;idynamic.mipmaps_s3tc[i].resize(comp_blocks[i].size()); + DVector::Write w = probe->dynamic.mipmaps_s3tc[i].write(); + int block_idx=0; + + for (Map::Element *E=comp_blocks[i].front();E;E=E->next()) { + + InstanceGIProbeData::CompBlockS3TC k = E->get(); + + //PRECOMPUTE ALPHA + int max_alpha=-100000; + int min_alpha=k.source_count==16 ?100000 :0; //if the block is not completely full, minimum is always 0, (and those blocks will map to 1, which will be zero) + + uint8_t alpha_block[4][4]={ {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0} }; + + for(int j=0;j>8)&0xFF; + if (alphamax_alpha) + max_alpha=alpha; + //fill up alpha block + alpha_block[ldw[k.sources[j]].pos[0]%4][ldw[k.sources[j]].pos[1]%4]=alpha; + + } + + //use the first mode (8 adjustable levels) + k.alpha[0]=max_alpha; + k.alpha[1]=min_alpha; + + uint64_t alpha_bits=0; + + if (max_alpha!=min_alpha) { + + int idx=0; + + for(int y=0;y<4;y++) { + for(int x=0;x<4;x++) { + + //substract minimum + uint32_t a = uint32_t(alpha_block[x][y])-min_alpha; + //convert range to 3 bits + a =int((a * 7.0 / (max_alpha-min_alpha))+0.5); + a = CLAMP(a,0,7); //just to be sure + a = 7-a; //because range is inverted in this mode + if (a==0) { + //do none, remain + } else if (a==7) { + a=1; + } else { + a=a+1; + } + + alpha_bits|=uint64_t(a)<<(idx*3); + idx++; + } + } + } + + k.alpha[2]=(alpha_bits >> 0)&0xFF; + k.alpha[3]=(alpha_bits >> 8)&0xFF; + k.alpha[4]=(alpha_bits >> 16)&0xFF; + k.alpha[5]=(alpha_bits >> 24)&0xFF; + k.alpha[6]=(alpha_bits >> 32)&0xFF; + k.alpha[7]=(alpha_bits >> 40)&0xFF; + + w[block_idx++]=k; + + } + + } + } + } void VisualServerScene::_gi_probe_bake_thread() { @@ -2859,43 +2991,190 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { //plot result to 3D texture! - for(int i=0;i<(int)header->cell_subdiv;i++) { + if (probe_data->dynamic.compression==RasterizerStorage::GI_PROBE_UNCOMPRESSED) { + + for(int i=0;i<(int)header->cell_subdiv;i++) { + + int stage = header->cell_subdiv - i -1; + + if (stage >= probe_data->dynamic.mipmaps_3d.size()) + continue; //no mipmap for this one + + print_line("generating mipmap stage: "+itos(stage)); + int level_cell_count = probe_data->dynamic.level_cell_lists[ i ].size(); + const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[ i ].ptr(); - int stage = header->cell_subdiv - i -1; + DVector::Write lw = probe_data->dynamic.mipmaps_3d[stage].write(); + uint8_t *mipmapw = lw.ptr(); - if (stage >= probe_data->dynamic.mipmaps_3d.size()) - continue; //no mipmap for this one + uint32_t sizes[3]={header->width>>stage,header->height>>stage,header->depth>>stage}; - print_line("generating mipmap stage: "+itos(stage)); - int level_cell_count = probe_data->dynamic.level_cell_lists[ i ].size(); - const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[ i ].ptr(); + for(int j=0;j::Write lw = probe_data->dynamic.mipmaps_3d[stage].write(); - uint8_t *mipmapw = lw.ptr(); + uint32_t idx = level_cells[j]; - uint32_t sizes[3]={header->width>>stage,header->height>>stage,header->depth>>stage}; + uint32_t r = (uint32_t(local_data[idx].energy[0])/probe_data->dynamic.bake_dynamic_range)>>2; + uint32_t g = (uint32_t(local_data[idx].energy[1])/probe_data->dynamic.bake_dynamic_range)>>2; + uint32_t b = (uint32_t(local_data[idx].energy[2])/probe_data->dynamic.bake_dynamic_range)>>2; + uint32_t a = (cells[idx].level_alpha>>8)&0xFF; - for(int j=0;jdynamic.bake_dynamic_range)>>2; - uint32_t g = (uint32_t(local_data[idx].energy[1])/probe_data->dynamic.bake_dynamic_range)>>2; - uint32_t b = (uint32_t(local_data[idx].energy[2])/probe_data->dynamic.bake_dynamic_range)>>2; - uint32_t a = cells[idx].alpha>>8; - uint32_t mm_ofs = sizes[0]*sizes[1]*(local_data[idx].pos[2]) + sizes[0]*(local_data[idx].pos[1]) + (local_data[idx].pos[0]); - mm_ofs*=4; //for RGBA (4 bytes) + } + } + } else if (probe_data->dynamic.compression==RasterizerStorage::GI_PROBE_S3TC) { + + + int mipmap_count = probe_data->dynamic.mipmaps_3d.size(); + + for(int mmi=0;mmi::Write mmw = probe_data->dynamic.mipmaps_3d[mmi].write(); + int block_count = probe_data->dynamic.mipmaps_s3tc[mmi].size(); + DVector::Read mmr = probe_data->dynamic.mipmaps_s3tc[mmi].read(); + + for(int i=0;idynamic.bake_dynamic_range))/1024.0; + colors[j].y=(local_data[b.sources[j]].energy[1]/float(probe_data->dynamic.bake_dynamic_range))/1024.0; + colors[j].z=(local_data[b.sources[j]].energy[2]/float(probe_data->dynamic.bake_dynamic_range))/1024.0; + } + //super quick and dirty compression + //find 2 most futher apart + float distance=0; + Vector3 from,to; + + if (b.source_count==16) { + //all cells are used so, find minmax between them + int further_apart[2]={0,0}; + for(int j=0;jdistance) { + distance=d; + further_apart[0]=j; + further_apart[1]=k; + } + } + } + + from = colors[further_apart[0]]; + to = colors[further_apart[1]]; + + } else { + //if a block is missing, the priority is that this block remains black, + //otherwise the geometry will appear deformed + //correct shape wins over correct color in this case + //average all colors first + Vector3 average; + + for(int j=0;j color_0) { + SWAP(color_1,color_0); + SWAP(from,to); + //} - mipmapw[mm_ofs+0]=uint8_t(CLAMP(r,0,255)); - mipmapw[mm_ofs+1]=uint8_t(CLAMP(g,0,255)); - mipmapw[mm_ofs+2]=uint8_t(CLAMP(b,0,255)); - mipmapw[mm_ofs+3]=uint8_t(CLAMP(a,0,255)); + + if (distance>0) { + + Vector3 dir = (to-from).normalized(); + + + for(int j=0;j>8)&0xFF; + blockptr[10]=color_1&0xFF; + blockptr[11]=(color_1>>8)&0xFF; + blockptr[12]=encode&0xFF; + blockptr[13]=(encode>>8)&0xFF; + blockptr[14]=(encode>>16)&0xFF; + blockptr[15]=(encode>>24)&0xFF; + + } } + } + //send back to main thread to update un little chunks probe_data->dynamic.updating_stage=GI_UPDATE_STAGE_UPLOADING; @@ -3055,7 +3334,7 @@ void VisualServerScene::render_probes() { int mmsize = probe->dynamic.mipmaps_3d[i].size(); DVector::Read r = probe->dynamic.mipmaps_3d[i].read(); - VSG::storage->gi_probe_dynamic_data_update_rgba8(probe->dynamic.probe_data,0,probe->dynamic.grid_size[2]>>i,i,r.ptr()); + VSG::storage->gi_probe_dynamic_data_update(probe->dynamic.probe_data,0,probe->dynamic.grid_size[2]>>i,i,r.ptr()); } diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 418e8387b..aa498e275 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -422,6 +422,13 @@ public: uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights }; + struct CompBlockS3TC { + uint32_t offset; //offset in mipmap + uint32_t source_count; //sources + uint32_t sources[16]; //id for each source + uint8_t alpha[8]; //alpha block is pre-computed + }; + struct Dynamic { @@ -433,8 +440,10 @@ public: RID probe_data; bool enabled; int bake_dynamic_range; + RasterizerStorage::GIProbeCompression compression; Vector< DVector > mipmaps_3d; + Vector< DVector > mipmaps_s3tc; //for s3tc int updating_stage; @@ -538,7 +547,7 @@ public: uint32_t albedo; uint32_t emission; uint32_t normal; - uint32_t alpha; + uint32_t level_alpha; }; enum { diff --git a/servers/visual_server.h b/servers/visual_server.h index ef7cbc03a..33a408348 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -472,6 +472,53 @@ public: virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0; virtual bool gi_probe_is_interior(RID p_probe) const=0; + /* PARTICLES API */ + + virtual RID particles_create()=0; + + virtual void particles_set_emitting(RID p_particles,bool p_emitting)=0; + virtual void particles_set_amount(RID p_particles,int p_amount)=0; + virtual void particles_set_lifetime(RID p_particles,float p_lifetime)=0; + virtual void particles_set_pre_process_time(RID p_particles,float p_time)=0; + virtual void particles_set_explosiveness_ratio(RID p_particles,float p_ratio)=0; + virtual void particles_set_randomness_ratio(RID p_particles,float p_ratio)=0; + virtual void particles_set_custom_aabb(RID p_particles,const AABB& p_aabb)=0; + virtual void particles_set_gravity(RID p_particles,const Vector3& p_gravity)=0; + virtual void particles_set_use_local_coordinates(RID p_particles,bool p_enable)=0; + virtual void particles_set_process_material(RID p_particles,RID p_material)=0; + + enum ParticlesEmissionShape { + PARTICLES_EMSSION_POINT, + PARTICLES_EMSSION_SPHERE, + PARTICLES_EMSSION_BOX, + PARTICLES_EMSSION_POINTS, + PARTICLES_EMSSION_SEGMENTS, + }; + + virtual void particles_set_emission_shape(RID p_particles,ParticlesEmissionShape)=0; + virtual void particles_set_emission_sphere_radius(RID p_particles,float p_radius)=0; + virtual void particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents)=0; + virtual void particles_set_emission_points(RID p_particles,const DVector& p_points)=0; + + enum ParticlesDrawOrder { + PARTICLES_DRAW_ORDER_INDEX, + PARTICLES_DRAW_ORDER_LIFETIME, + PARTICLES_DRAW_ORDER_VIEW_DEPTH, + }; + + virtual void particles_set_draw_order(RID p_particles,ParticlesDrawOrder p_order)=0; + + enum ParticlesDrawPassMode { + PARTICLES_DRAW_PASS_MODE_QUAD, + PARTICLES_DRAW_PASS_MODE_MESH + }; + + + virtual void particles_set_draw_passes(RID p_particles,int p_count)=0; + virtual void particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material)=0; + virtual void particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh)=0; + + virtual AABB particles_get_current_aabb(RID p_particles)=0; /* CAMERA API */ @@ -483,7 +530,15 @@ public: virtual void camera_set_environment(RID p_camera,RID p_env)=0; virtual void camera_set_use_vertical_aspect(RID p_camera,bool p_enable)=0; +/* + enum ParticlesCollisionMode { + PARTICLES_COLLISION_NONE, + PARTICLES_COLLISION_TEXTURE, + PARTICLES_COLLISION_CUBEMAP, + }; + virtual void particles_set_collision(RID p_particles,ParticlesCollisionMode p_mode,const Transform&, p_xform,const RID p_depth_tex,const RID p_normal_tex)=0; +*/ /* VIEWPORT TARGET API */ virtual RID viewport_create()=0; @@ -622,6 +677,7 @@ public: INSTANCE_MESH, INSTANCE_MULTIMESH, INSTANCE_IMMEDIATE, + INSTANCE_PARTICLES, INSTANCE_LIGHT, INSTANCE_REFLECTION_PROBE, INSTANCE_ROOM, -- cgit v1.2.3-70-g09d2 From a62c99c4e4325ca0c015d731f2bcb9b07410bb65 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 31 Dec 2016 10:53:29 -0300 Subject: Some fixes and clean ups --- core/image.cpp | 2 +- drivers/gles3/rasterizer_scene_gles3.cpp | 53 ++++++++++++++++++++++++++---- drivers/gles3/rasterizer_storage_gles3.cpp | 19 +++++++++++ drivers/gles3/rasterizer_storage_gles3.h | 4 +++ drivers/gles3/shaders/scene.glsl | 28 ++++++++-------- scene/3d/gi_probe.cpp | 36 ++++++++++++++++++++ scene/3d/gi_probe.h | 6 ++++ servers/visual/rasterizer.h | 4 +++ servers/visual/visual_server_raster.h | 3 ++ servers/visual/visual_server_scene.cpp | 8 +++-- servers/visual_server.h | 3 ++ 11 files changed, 141 insertions(+), 25 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/core/image.cpp b/core/image.cpp index 0b63d9c52..fe5c067b0 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -404,7 +404,7 @@ void Image::convert( Format p_new_format ){ case FORMAT_RGBA8|(FORMAT_LA8<<8): _convert<3,true,1,true,false,true>( width, height,rptr, wptr ); break; case FORMAT_RGBA8|(FORMAT_R8<<8): _convert<3,true,1,false,false,false>( width, height,rptr, wptr ); break; case FORMAT_RGBA8|(FORMAT_RG8<<8): _convert<3,true,2,false,false,false>( width, height,rptr, wptr ); break; - case FORMAT_RGBA8|(FORMAT_RGB8<<8): _convert<3,true,3,true,false,false>( width, height,rptr, wptr ); break; + case FORMAT_RGBA8|(FORMAT_RGB8<<8): _convert<3,true,3,false,false,false>( width, height,rptr, wptr ); break; } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 7fdd08a83..1b080a121 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -3687,9 +3687,47 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C state.ubo_data.subsurface_scatter_width=subsurface_scatter_size; + state.ubo_data.shadow_z_offset=0; + state.ubo_data.shadow_slope_scale=0; + state.ubo_data.shadow_dual_paraboloid_render_side=0; + state.ubo_data.shadow_dual_paraboloid_render_zfar=0; _setup_environment(env,p_cam_projection,p_cam_transform); + bool fb_cleared=false; + + glDepthFunc(GL_LEQUAL); + + + if (storage->frame.current_rt && true) { + //pre z pass + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->fbo); + glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height); + + glColorMask(0,0,0,0); + + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + + + render_list.clear(); + _fill_render_list(p_cull_result,p_cull_count,true); + render_list.sort_by_depth(false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH,true); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,0,false,false,true,false,false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH,false); + + glColorMask(1,1,1,1); + + fb_cleared=true; + render_pass++; + } + + _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_shadow_atlas); _setup_reflections(p_reflection_probe_cull_result,p_reflection_probe_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_reflection_atlas,env); @@ -3778,9 +3816,10 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C } } - - glClearDepth(1.0); - glClear(GL_DEPTH_BUFFER_BIT); + if (!fb_cleared) { + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + } Color clear_color(0,0,0,0); @@ -4287,7 +4326,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa zfar=light->param[VS::LIGHT_PARAM_RANGE]; bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,true); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH_DUAL_PARABOLOID,true); } } else if (light->type==VS::LIGHT_SPOT) { @@ -4341,12 +4380,12 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa _setup_environment(NULL,light_projection,light_transform); - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,true); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH,true); _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,0,!flip_facing,false,true,false,false); - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false); - state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH,false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_DEPTH_DUAL_PARABOLOID,false); if (light->type==VS::LIGHT_OMNI && light->omni_shadow_mode==VS::LIGHT_OMNI_SHADOW_CUBE && p_pass==5) { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 3fc051354..2875c1f78 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -4743,6 +4743,7 @@ RID RasterizerStorageGLES3::gi_probe_create() { gip->dynamic_range=1.0; gip->energy=1.0; gip->interior=false; + gip->compress=false; gip->version=1; gip->cell_size=1.0; @@ -4864,6 +4865,24 @@ bool RasterizerStorageGLES3::gi_probe_is_interior(RID p_probe) const{ } + +void RasterizerStorageGLES3::gi_probe_set_compress(RID p_probe,bool p_enable) { + + GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!gip); + + gip->compress=p_enable; + +} + +bool RasterizerStorageGLES3::gi_probe_is_compressed(RID p_probe) const{ + + const GIProbe *gip = gi_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!gip,false); + + return gip->compress; + +} float RasterizerStorageGLES3::gi_probe_get_energy(RID p_probe) const{ const GIProbe *gip = gi_probe_owner.getornull(p_probe); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b0f980015..690a169ca 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -899,6 +899,7 @@ public: int dynamic_range; float energy; bool interior; + bool compress; uint32_t version; @@ -932,6 +933,9 @@ public: virtual void gi_probe_set_interior(RID p_probe,bool p_enable); virtual bool gi_probe_is_interior(RID p_probe) const; + virtual void gi_probe_set_compress(RID p_probe,bool p_enable); + virtual bool gi_probe_is_compressed(RID p_probe) const; + virtual uint32_t gi_probe_get_version(RID p_probe); struct GIProbeData : public RID_Data { diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 90c501ea3..c18a356a5 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -146,7 +146,7 @@ MATERIAL_UNIFORMS #endif -#ifdef RENDER_SHADOW_DUAL_PARABOLOID +#ifdef RENDER_DEPTH_DUAL_PARABOLOID out highp float dp_clip; @@ -253,10 +253,10 @@ VERTEX_SHADER_CODE binormal_interp = binormal; #endif -#ifdef RENDER_SHADOW +#ifdef RENDER_DEPTH -#ifdef RENDER_SHADOW_DUAL_PARABOLOID +#ifdef RENDER_DEPTH_DUAL_PARABOLOID vertex_interp.z*= shadow_dual_paraboloid_render_side; normal_interp.z*= shadow_dual_paraboloid_render_side; @@ -282,12 +282,12 @@ VERTEX_SHADER_CODE z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale; vertex_interp.z-=z_ofs; -#endif //RENDER_SHADOW_DUAL_PARABOLOID +#endif //RENDER_DEPTH_DUAL_PARABOLOID -#endif //RENDER_SHADOW +#endif //RENDER_DEPTH -#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_SHADOW_DUAL_PARABOLOID) +#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_DEPTH_DUAL_PARABOLOID) gl_Position = projection_matrix * vec4(vertex_interp,1.0); #else gl_Position = vertex; @@ -622,7 +622,7 @@ float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 p } -#ifdef RENDER_SHADOW_DUAL_PARABOLOID +#ifdef RENDER_DEPTH_DUAL_PARABOLOID in highp float dp_clip; @@ -861,20 +861,20 @@ vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, b float dist = dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0; float alpha=0.0; - vec4 color = vec4(0.0); + vec3 color = vec3(0.0); while(dist < max_distance && alpha < 0.95) { float diameter = max(1.0, 2.0 * tan_half_angle * dist); vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) ); float a = (1.0 - alpha); - color.rgb += a * scolor.rgb; + color += scolor.rgb * a; alpha += a * scolor.a; dist += diameter * 0.5; } //color.rgb = mix(color.rgb,mix(ambient,color.rgb,alpha),blend_ambient); - return color.rgb; + return color; } void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient,float multiplier, mat3 normal_mtx,vec3 ref_vec, float roughness, out vec4 out_spec, out vec4 out_diff) { @@ -1004,7 +1004,7 @@ void gi_probes_compute(vec3 pos, vec3 normal, float roughness, vec3 specular, in void main() { -#ifdef RENDER_SHADOW_DUAL_PARABOLOID +#ifdef RENDER_DEPTH_DUAL_PARABOLOID if (dp_clip>0.0) discard; @@ -1128,7 +1128,7 @@ FRAGMENT_SHADER_CODE vec3 eye_vec = -normalize( vertex_interp ); -#ifndef RENDER_SHADOW +#ifndef RENDER_DEPTH float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; @@ -1370,7 +1370,7 @@ LIGHT_SHADER_CODE } #endif -#ifdef RENDER_SHADOW +#ifdef RENDER_DEPTH //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else @@ -1424,7 +1424,7 @@ LIGHT_SHADER_CODE -#endif //RENDER_SHADOW +#endif //RENDER_DEPTH } diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index de2d9c1b9..f8d8213b8 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -75,6 +75,19 @@ bool GIProbeData::is_interior() const{ return VS::get_singleton()->gi_probe_is_interior(probe); } + +bool GIProbeData::is_compressed() const{ + + return VS::get_singleton()->gi_probe_is_compressed(probe); +} + + +void GIProbeData::set_compress(bool p_enable) { + + VS::get_singleton()->gi_probe_set_compress(probe,p_enable); + +} + int GIProbeData::get_dynamic_range() const{ @@ -111,6 +124,9 @@ void GIProbeData::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_interior","interior"),&GIProbeData::set_interior); ObjectTypeDB::bind_method(_MD("is_interior"),&GIProbeData::is_interior); + ObjectTypeDB::bind_method(_MD("set_compress","compress"),&GIProbeData::set_compress); + ObjectTypeDB::bind_method(_MD("is_compressed"),&GIProbeData::is_compressed); + ADD_PROPERTY(PropertyInfo(Variant::_AABB,"bounds",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_bounds"),_SCS("get_bounds")); ADD_PROPERTY(PropertyInfo(Variant::REAL,"cell_size",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_cell_size"),_SCS("get_cell_size")); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM,"to_cell_xform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_to_cell_xform"),_SCS("get_to_cell_xform")); @@ -119,6 +135,7 @@ void GIProbeData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); ADD_PROPERTY(PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_energy"),_SCS("get_energy")); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"interior",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_interior"),_SCS("is_interior")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"compress",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_compress"),_SCS("is_compressed")); } @@ -211,6 +228,19 @@ bool GIProbe::is_interior() const { } +void GIProbe::set_compress(bool p_enable) { + + compress=p_enable; + if (probe_data.is_valid()) { + probe_data->set_compress(p_enable); + } +} + +bool GIProbe::is_compressed() const { + + return compress; +} + #include "math.h" @@ -1145,6 +1175,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){ probe_data->set_dynamic_range(dynamic_range); probe_data->set_energy(energy); probe_data->set_interior(interior); + probe_data->set_compress(compress); probe_data->set_to_cell_xform(baker.to_cell_space); set_probe_data(probe_data); @@ -1327,6 +1358,9 @@ void GIProbe::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_interior","enable"),&GIProbe::set_interior); ObjectTypeDB::bind_method(_MD("is_interior"),&GIProbe::is_interior); + ObjectTypeDB::bind_method(_MD("set_compress","enable"),&GIProbe::set_compress); + ObjectTypeDB::bind_method(_MD("is_compressed"),&GIProbe::is_compressed); + ObjectTypeDB::bind_method(_MD("bake","from_node","create_visual_debug"),&GIProbe::bake,DEFVAL(Variant()),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("debug_bake"),&GIProbe::_debug_bake); ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); @@ -1336,6 +1370,7 @@ void GIProbe::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_RANGE,"1,16,1"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_energy"),_SCS("get_energy")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"interior"),_SCS("set_interior"),_SCS("is_interior")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"compress"),_SCS("set_compress"),_SCS("is_compressed")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"data",PROPERTY_HINT_RESOURCE_TYPE,"GIProbeData"),_SCS("set_probe_data"),_SCS("get_probe_data")); @@ -1355,6 +1390,7 @@ GIProbe::GIProbe() { color_scan_cell_width=4; bake_texture_size=128; interior=false; + compress=false; gi_probe = VS::get_singleton()->gi_probe_create(); diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index ca882856c..59747761b 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -38,6 +38,9 @@ public: void set_interior(bool p_enable); bool is_interior() const; + void set_compress(bool p_enable); + bool is_compressed() const; + virtual RID get_rid() const; GIProbeData(); @@ -130,6 +133,7 @@ private: int dynamic_range; float energy; bool interior; + bool compress; int color_scan_cell_width; int bake_texture_size; @@ -169,6 +173,8 @@ public: void set_interior(bool p_enable); bool is_interior() const; + void set_compress(bool p_enable); + bool is_compressed() const; void bake(Node *p_from_node=NULL,bool p_create_visual_debug=false); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index eda67f2ed..745298552 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -430,6 +430,9 @@ public: virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0; virtual bool gi_probe_is_interior(RID p_probe) const=0; + virtual void gi_probe_set_compress(RID p_probe,bool p_enable)=0; + virtual bool gi_probe_is_compressed(RID p_probe) const=0; + virtual uint32_t gi_probe_get_version(RID p_probe)=0; enum GIProbeCompression { @@ -442,6 +445,7 @@ public: virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth,GIProbeCompression p_compression)=0; virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0; + /* PARTICLES */ virtual RID particles_create()=0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 5088dedb5..e67c140b2 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -827,6 +827,9 @@ public: BIND2(gi_probe_set_interior,RID,bool) BIND1RC(bool,gi_probe_is_interior,RID) + BIND2(gi_probe_set_compress,RID,bool) + BIND1RC(bool,gi_probe_is_compressed,RID) + BIND2(gi_probe_set_dynamic_data,RID,const DVector& ) BIND1RC( DVector,gi_probe_get_dynamic_data,RID) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index deb391c77..6b170d379 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2407,7 +2407,9 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { _gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr()); - probe->dynamic.compression = VSG::storage->gi_probe_get_dynamic_data_get_preferred_compression(); + bool compress = VSG::storage->gi_probe_is_compressed(p_instance->base); + + probe->dynamic.compression = compress ? VSG::storage->gi_probe_get_dynamic_data_get_preferred_compression() : RasterizerStorage::GI_PROBE_UNCOMPRESSED; probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth,probe->dynamic.compression); @@ -3112,10 +3114,10 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { color_1 |= CLAMP(int(to.y*63),0,63)<<5; color_1 |= CLAMP(int(to.z*31),0,31); - //if (color_1 > color_0) { + if (color_1 > color_0) { SWAP(color_1,color_0); SWAP(from,to); - //} + } if (distance>0) { diff --git a/servers/visual_server.h b/servers/visual_server.h index 33a408348..f4848ff34 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -472,6 +472,9 @@ public: virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0; virtual bool gi_probe_is_interior(RID p_probe) const=0; + virtual void gi_probe_set_compress(RID p_probe,bool p_enable)=0; + virtual bool gi_probe_is_compressed(RID p_probe) const=0; + /* PARTICLES API */ virtual RID particles_create()=0; -- cgit v1.2.3-70-g09d2 From 2820b2d82b2ed747011e37c543aefc6d4d4edee9 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 2 Jan 2017 14:09:42 -0300 Subject: fix stupid bug in light downscaling for GI Probe --- servers/visual/visual_server_scene.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'servers/visual/visual_server_scene.cpp') diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 6b170d379..91694c3e1 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2917,6 +2917,8 @@ void VisualServerScene::_bake_gi_downscale_light(int p_idx, int p_level, const G p_local_data[p_idx].energy[1]=0; p_local_data[p_idx].energy[2]=0; + int divisor=0; + for(int i=0;i<8;i++) { uint32_t child = p_cells[p_idx].children[i]; @@ -2931,13 +2933,14 @@ void VisualServerScene::_bake_gi_downscale_light(int p_idx, int p_level, const G p_local_data[p_idx].energy[0]+=p_local_data[child].energy[0]; p_local_data[p_idx].energy[1]+=p_local_data[child].energy[1]; p_local_data[p_idx].energy[2]+=p_local_data[child].energy[2]; + divisor++; } //divide by eight for average - p_local_data[p_idx].energy[0]>>=3; - p_local_data[p_idx].energy[1]>>=3; - p_local_data[p_idx].energy[2]>>=3; + p_local_data[p_idx].energy[0]/=divisor; + p_local_data[p_idx].energy[1]/=divisor; + p_local_data[p_idx].energy[2]/=divisor; } -- cgit v1.2.3-70-g09d2