aboutsummaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
authorJuan Linietsky2016-11-09 23:55:06 -0300
committerJuan Linietsky2016-11-09 23:55:06 -0300
commitcacf9ebb7fd8df8845daca9da2fe55456cc179aa (patch)
tree5881cb42ace5001916e9d1843f5a7acbc35332a6 /servers
parent6b2a27bbe5fa112365fc88b9b4678a61293bcb53 (diff)
downloadgodot-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.h37
-rw-r--r--servers/visual/shader_types.cpp2
-rw-r--r--servers/visual/visual_server_raster.h10
-rw-r--r--servers/visual/visual_server_scene.cpp638
-rw-r--r--servers/visual/visual_server_scene.h19
-rw-r--r--servers/visual/visual_server_viewport.cpp27
-rw-r--r--servers/visual/visual_server_viewport.h7
-rw-r--r--servers/visual_server.cpp450
-rw-r--r--servers/visual_server.h28
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 */