diff options
| author | Juan Linietsky | 2016-11-09 23:55:06 -0300 |
|---|---|---|
| committer | Juan Linietsky | 2016-11-09 23:55:06 -0300 |
| commit | cacf9ebb7fd8df8845daca9da2fe55456cc179aa (patch) | |
| tree | 5881cb42ace5001916e9d1843f5a7acbc35332a6 /servers | |
| parent | 6b2a27bbe5fa112365fc88b9b4678a61293bcb53 (diff) | |
| download | godot-cacf9ebb7fd8df8845daca9da2fe55456cc179aa.tar.gz godot-cacf9ebb7fd8df8845daca9da2fe55456cc179aa.tar.zst godot-cacf9ebb7fd8df8845daca9da2fe55456cc179aa.zip | |
all light types and shadows are working, pending a lot of clean-up
Diffstat (limited to 'servers')
| -rw-r--r-- | servers/visual/rasterizer.h | 37 | ||||
| -rw-r--r-- | servers/visual/shader_types.cpp | 2 | ||||
| -rw-r--r-- | servers/visual/visual_server_raster.h | 10 | ||||
| -rw-r--r-- | servers/visual/visual_server_scene.cpp | 638 | ||||
| -rw-r--r-- | servers/visual/visual_server_scene.h | 19 | ||||
| -rw-r--r-- | servers/visual/visual_server_viewport.cpp | 27 | ||||
| -rw-r--r-- | servers/visual/visual_server_viewport.h | 7 | ||||
| -rw-r--r-- | servers/visual_server.cpp | 450 | ||||
| -rw-r--r-- | servers/visual_server.h | 28 |
9 files changed, 1171 insertions, 47 deletions
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<DVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const=0; + virtual Vector<AABB> 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<DVector<uint8_t> >,mesh_surface_get_blend_shapes,RID,int) + BIND2RC(Vector<AABB>,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<InstanceLightData::PairInfo>::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;i<instance->materials.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<InstanceLightData*>(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<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) { InstanceGeometryData *geom = static_cast<InstanceGeometryData*>(p_instance->base_data); - //make sure lights are updated + //make sure lights are updated if it casts shadow - for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) { - InstanceLightData *light = static_cast<InstanceLightData*>(E->get()->base_data); - light->shadow_sirty=true; + if (geom->can_cast_shadows) { + for (List<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) { + InstanceLightData *light = static_cast<InstanceLightData*>(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<InstanceLightData*>(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;i<splits;i++) { + distances[i+1]=p_camera->znear+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;i<splits;i++) { + + // 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: { + + + 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_x<x_min) + x_min=d_x; + if (j==0 || d_x>x_max) + x_max=d_x; + + if (j==0 || d_y<y_min) + y_min=d_y; + if (j==0 || d_y>y_max) + y_max=d_y; + + if (j==0 || d_z<z_min) + z_min=d_z; + if (j==0 || d_z>z_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<Plane> 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;j<cull_count;j++) { + + float min,max; + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(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<Plane> 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;j<cull_count;j++) { + + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(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<Plane> 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;j<cull_count;j++) { + + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(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<Plane> 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;j<cull_count;j++) { + + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1<<instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData*>(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<<ins->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<Instance*>::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<directional_shadow_count;i++) { + + _light_instance_update_shadow(lights_with_shadow[i],camera,p_shadow_atlas,scenario,p_viewport_size); } } -#if 0 - { //this should eventually change to - //assign shadows by distance to camera - SortArray<Instance*,_InstanceLightsort> sorter; - sorter.sort(light_cull_result,light_cull_count); + + { //setup shadow maps + + //SortArray<Instance*,_InstanceLightsort> sorter; + //sorter.sort(light_cull_result,light_cull_count); for (int i=0;i<light_cull_count;i++) { Instance *ins = light_cull_result[i]; - if (!rasterizer->light_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<InstanceLightData*>(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<<p_instance->base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceGeometryData *geom = static_cast<InstanceGeometryData*>(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;i<p_instance->materials.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<Instance*>::Element *E=geom->lighting.front();E;E=E->next()) { + InstanceLightData *light = static_cast<InstanceLightData*>(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<Instance> 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<Instance*> 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<Instance*>::Element *D; // directional light in scenario - bool shadow_sirty; + bool shadow_dirty; List<PairInfo> 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<uint8_t> p_vertex_data,int p_vertex_len,DVector<uint8_t> p_index_data,int p_index_len) const { + + + uint32_t offsets[ARRAY_MAX]; + + int total_elem_size=0; + + for (int i=0;i<VS::ARRAY_MAX;i++) { + + + offsets[i]=0; //reset + + if (!(p_format&(1<<i))) // no array + continue; + + + int elem_size=0; + + switch(i) { + + case VS::ARRAY_VERTEX: { + + + if (p_format&ARRAY_FLAG_USE_2D_VERTICES) { + elem_size=2; + } else { + elem_size=3; + } + + if (p_format&ARRAY_COMPRESS_VERTEX) { + elem_size*=sizeof(int16_t); + } else { + elem_size*=sizeof(float); + } + + } break; + case VS::ARRAY_NORMAL: { + + if (p_format&ARRAY_COMPRESS_NORMAL) { + elem_size=sizeof(uint32_t); + } else { + elem_size=sizeof(float)*3; + } + + } break; + + case VS::ARRAY_TANGENT: { + if (p_format&ARRAY_COMPRESS_TANGENT) { + elem_size=sizeof(uint32_t); + } else { + elem_size=sizeof(float)*4; + } + + } break; + case VS::ARRAY_COLOR: { + + if (p_format&ARRAY_COMPRESS_COLOR) { + elem_size=sizeof(uint32_t); + } else { + elem_size=sizeof(float)*4; + } + } break; + case VS::ARRAY_TEX_UV: { + if (p_format&ARRAY_COMPRESS_TEX_UV) { + elem_size=sizeof(uint32_t); + } else { + elem_size=sizeof(float)*2; + } + + } break; + + case VS::ARRAY_TEX_UV2: { + if (p_format&ARRAY_COMPRESS_TEX_UV2) { + elem_size=sizeof(uint32_t); + } else { + elem_size=sizeof(float)*2; + } + + } break; + case VS::ARRAY_WEIGHTS: { + + if (p_format&ARRAY_COMPRESS_WEIGHTS) { + elem_size=sizeof(uint16_t)*4; + } else { + elem_size=sizeof(float)*4; + } + + } break; + 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; + } + + } break; + case VS::ARRAY_INDEX: { + + if (p_index_len<=0) { + ERR_PRINT("index_array_len==NO_INDEX_ARRAY"); + break; + } + /* determine wether using 16 or 32 bits indices */ + if (p_index_len>=(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<uint8_t>::Read r = p_vertex_data.read(); + + for(int i=0;i<VS::ARRAY_MAX;i++) { + + if (!(p_format&(1<<i))) + continue; + + + switch(i) { + + case VS::ARRAY_VERTEX: { + + + if (p_format&ARRAY_FLAG_USE_2D_VERTICES) { + + DVector<Vector2> arr_2d; + arr_2d.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_VERTEX) { + + DVector<Vector2>::Write w = arr_2d.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector2(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1])); + } + } else { + + DVector<Vector2>::Write w = arr_2d.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector2(v[0],v[1]); + } + } + + ret[i]=arr_2d; + } else { + + DVector<Vector3> arr_3d; + arr_3d.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_VERTEX) { + + DVector<Vector3>::Write w = arr_3d.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector3(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1]),Math::halfptr_to_float(&v[1])); + } + } else { + + DVector<Vector3>::Write w = arr_3d.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector3(v[0],v[1],v[2]); + } + } + + ret[i]=arr_3d; + } + + + } break; + case VS::ARRAY_NORMAL: { + DVector<Vector3> arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_NORMAL) { + + DVector<Vector3>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint8_t *v = (const uint8_t*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector3( float(v[0]/255.0)*2.0-1.0, float(v[1]/255.0)*2.0-1.0, float(v[2]/255.0)*2.0-1.0 ); + } + } else { + DVector<Vector3>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector3(v[0],v[1],v[2]); + } + } + + ret[i]=arr; + + } break; + + case VS::ARRAY_TANGENT: { + DVector<float> arr; + arr.resize(p_vertex_len*4); + if (p_format&ARRAY_COMPRESS_TANGENT) { + DVector<float>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint8_t *v = (const uint8_t*)&r[j*total_elem_size+offsets[i]]; + for(int k=0;k<4;k++) { + w[j*4+k]=float(v[k]/255.0)*2.0-1.0; + } + } + } else { + + DVector<float>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + for(int k=0;k<4;k++) { + w[j*4+k]=v[k]; + } + } + + } + + ret[i]=arr; + + } break; + case VS::ARRAY_COLOR: { + + DVector<Color> arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_COLOR) { + + DVector<Color>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint8_t *v = (const uint8_t*)&r[j*total_elem_size+offsets[i]]; + w[j]=Color( float(v[0]/255.0)*2.0-1.0, float(v[1]/255.0)*2.0-1.0, float(v[2]/255.0)*2.0-1.0, float(v[3]/255.0)*2.0-1.0 ); + } + } else { + DVector<Color>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + w[j]=Color(v[0],v[1],v[2],v[3]); + } + } + + ret[i]=arr; + } break; + case VS::ARRAY_TEX_UV: { + + DVector<Vector2> arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_TEX_UV) { + + DVector<Vector2>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector2(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1])); + } + } else { + + DVector<Vector2>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector2(v[0],v[1]); + } + } + + ret[i]=arr; + } break; + + case VS::ARRAY_TEX_UV2: { + DVector<Vector2> arr; + arr.resize(p_vertex_len); + + if (p_format&ARRAY_COMPRESS_TEX_UV2) { + + DVector<Vector2>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector2(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1])); + } + } else { + + DVector<Vector2>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + w[j]=Vector2(v[0],v[1]); + } + } + + ret[i]=arr; + + } break; + case VS::ARRAY_WEIGHTS: { + + DVector<float> arr; + arr.resize(p_vertex_len*4); + if (p_format&ARRAY_COMPRESS_WEIGHTS) { + DVector<float>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]]; + for(int k=0;k<4;k++) { + w[j*4+k]=float(v[k]/65535.0)*2.0-1.0; + } + } + } else { + + DVector<float>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + const float *v = (const float*)&r[j*total_elem_size+offsets[i]]; + for(int k=0;k<4;k++) { + w[j*4+k]=v[k]; + } + } + + } + + ret[i]=arr; + + } break; + case VS::ARRAY_BONES: { + + DVector<int> arr; + arr.resize(p_vertex_len*4); + if (p_format&ARRAY_FLAG_USE_16_BIT_BONES) { + + DVector<int>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + + const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]]; + for(int k=0;k<4;k++) { + w[j*4+k]=v[k]; + } + } + } else { + + DVector<int>::Write w = arr.write(); + + for(int j=0;j<p_vertex_len;j++) { + const int *v = (const int*)&r[j*total_elem_size+offsets[i]]; + for(int k=0;k<4;k++) { + w[j*4+k]=v[k]; + } + } + + } + + ret[i]=arr; + + } break; + case VS::ARRAY_INDEX: { + /* determine wether using 16 or 32 bits indices */ + + DVector<uint8_t>::Read ir = p_index_data.read(); + + DVector<int> arr; + arr.resize(p_index_len); + if (p_index_len<(1<<16)) { + + DVector<int>::Write w = arr.write(); + + for(int j=0;j<p_index_len;j++) { + + const uint16_t *v = (const uint16_t*)&ir[j*2]; + w[j]=*v; + } + } else { + + DVector<int>::Write w = arr.write(); + + for(int j=0;j<p_index_len;j++) { + const int *v = (const int*)&ir[j*4]; + w[j]=*v; + } + + } + ret[i]=arr; + } break; + default: { + ERR_FAIL_V( ret ); + } + } + } + + return ret; +} + +Array VisualServer::mesh_surface_get_arrays(RID p_mesh,int p_surface) const { + + DVector<uint8_t> 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<uint8_t> 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<String> _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<float>& p_margins, const Color& p_modulate=Color(1,1,1)); + Array _get_array_from_surface(uint32_t p_format,DVector<uint8_t> p_vertex_data,int p_vertex_len,DVector<uint8_t> p_index_data,int p_index_len) const; + protected: RID _make_test_cube(); void _free_internal_rids(); @@ -258,10 +260,15 @@ public: virtual DVector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const=0; virtual DVector<uint8_t> 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<DVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const=0; + virtual Vector<AABB> 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 */ |
