summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2016-11-09 23:55:06 -0300
committerJuan Linietsky <reduzio@gmail.com>2016-11-09 23:55:06 -0300
commitcacf9ebb7fd8df8845daca9da2fe55456cc179aa (patch)
tree5881cb42ace5001916e9d1843f5a7acbc35332a6
parent6b2a27bbe5fa112365fc88b9b4678a61293bcb53 (diff)
all light types and shadows are working, pending a lot of clean-up
-rw-r--r--core/math/camera_matrix.cpp22
-rw-r--r--core/math/camera_matrix.h2
-rw-r--r--core/math/math_funcs.h2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp1043
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h74
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp324
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h101
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp15
-rw-r--r--drivers/gles3/shader_compiler_gles3.h7
-rw-r--r--drivers/gles3/shaders/SCsub1
-rw-r--r--drivers/gles3/shaders/cube_to_dp.glsl79
-rw-r--r--drivers/gles3/shaders/scene.glsl341
-rw-r--r--main/main.cpp23
-rw-r--r--scene/3d/light.cpp91
-rw-r--r--scene/3d/light.h71
-rw-r--r--scene/3d/navigation_mesh.cpp2
-rw-r--r--scene/main/scene_main_loop.cpp2
-rw-r--r--scene/main/viewport.cpp61
-rw-r--r--scene/main/viewport.h24
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/mesh.cpp102
-rw-r--r--scene/resources/mesh.h4
-rw-r--r--scene/resources/mesh_data_tool.cpp2
-rw-r--r--scene/resources/shape.cpp2
-rw-r--r--scene/resources/surface_tool.cpp2
-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
-rw-r--r--tools/editor/io_plugins/editor_import_collada.cpp2
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.cpp14
-rw-r--r--tools/editor/spatial_editor_gizmos.cpp12
38 files changed, 3235 insertions, 412 deletions
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index f7dd8839b8..3e3cd1af4f 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -495,6 +495,28 @@ void CameraMatrix::set_light_bias() {
}
+void CameraMatrix::set_light_atlas_rect(const Rect2& p_rect) {
+
+ float *m=&matrix[0][0];
+
+ m[0]=p_rect.size.width,
+ m[1]=0.0,
+ m[2]=0.0,
+ m[3]=0.0,
+ m[4]=0.0,
+ m[5]=p_rect.size.height,
+ m[6]=0.0,
+ m[7]=0.0,
+ m[8]=0.0,
+ m[9]=0.0,
+ m[10]=1.0,
+ m[11]=0.0,
+ m[12]=p_rect.pos.x,
+ m[13]=p_rect.pos.y,
+ m[14]=0.0,
+ m[15]=1.0;
+}
+
CameraMatrix::operator String() const {
String str;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index d192b1fef1..bf8cf3592e 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -30,6 +30,7 @@
#define CAMERA_MATRIX_H
#include "transform.h"
+#include "math_2d.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -53,6 +54,7 @@ struct CameraMatrix {
void set_identity();
void set_zero();
void set_light_bias();
+ void set_light_atlas_rect(const Rect2& p_rect);
void set_perspective(float p_fovy_degrees, float p_aspect, float p_z_near, float p_z_far,bool p_flip_fov=false);
void set_orthogonal(float p_left, float p_right, float p_bottom, float p_top, float p_znear, float p_zfar);
void set_orthogonal(float p_size, float p_aspect, float p_znear, float p_zfar,bool p_flip_fov=false);
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index c8ced0b306..9d7e881c65 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -208,7 +208,7 @@ public:
}
}
- static _FORCE_INLINE_ float halfptr_to_float(uint16_t *h) {
+ static _FORCE_INLINE_ float halfptr_to_float(const uint16_t *h) {
union {
uint32_t u32;
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index c10c5fee65..c455d4bd11 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -824,8 +824,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
bool prev_distance_field=false;
-
-
while(p_item_list) {
Item *ci=p_item_list;
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 93dc01d473..287801b597 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1,8 +1,18 @@
#include "rasterizer_scene_gles3.h"
#include "globals.h"
#include "os/os.h"
+#include "rasterizer_canvas_gles3.h"
+static const GLenum _cube_side_enum[6]={
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+
+};
static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) {
@@ -78,6 +88,9 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
ERR_FAIL_COND(!shadow_atlas);
ERR_FAIL_COND(p_size<0);
+
+ p_size = nearest_power_of_2(p_size);
+
if (p_size==shadow_atlas->size)
return;
@@ -104,7 +117,7 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){
//clear owners
shadow_atlas->shadow_owners.clear();
- shadow_atlas->size=nearest_power_of_2(p_size);
+ shadow_atlas->size=p_size;
if (shadow_atlas->size) {
glGenFramebuffers(1, &shadow_atlas->fbo);
@@ -188,7 +201,7 @@ void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas,int
swaps=0;
for(int i=0;i<3;i++) {
- if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision > shadow_atlas->quadrants[shadow_atlas->size_order[i+1]].subdivision) {
+ if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i+1]].subdivision) {
SWAP(shadow_atlas->size_order[i],shadow_atlas->size_order[i+1]);
swaps++;
}
@@ -260,20 +273,22 @@ bool RasterizerSceneGLES3::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,i
}
-uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version){
+bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version){
+
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
- ERR_FAIL_COND_V(!shadow_atlas,ShadowAtlas::SHADOW_INVALID);
+ ERR_FAIL_COND_V(!shadow_atlas,false);
LightInstance *li = light_instance_owner.getornull(p_light_intance);
- ERR_FAIL_COND_V(!li,ShadowAtlas::SHADOW_INVALID);
+ ERR_FAIL_COND_V(!li,false);
if (shadow_atlas->size==0 || shadow_atlas->smallest_subdiv==0) {
- return ShadowAtlas::SHADOW_INVALID;
+ return false;
}
uint32_t quad_size = shadow_atlas->size>>1;
- int desired_fit = MAX(quad_size/shadow_atlas->smallest_subdiv,nearest_power_of_2(quad_size*p_coverage));
+ int desired_fit = MIN(quad_size/shadow_atlas->smallest_subdiv,nearest_power_of_2(quad_size*p_coverage));
+
int valid_quadrants[4];
int valid_quadrant_count=0;
@@ -300,8 +315,7 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh
}
}
-
- ERR_FAIL_COND_V(valid_quadrant_count==0,ShadowAtlas::SHADOW_INVALID);
+ ERR_FAIL_COND_V(valid_quadrant_count==0,false);
uint64_t tick = OS::get_singleton()->get_ticks_msec();
@@ -317,13 +331,12 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh
bool should_realloc=shadow_atlas->quadrants[q].subdivision!=best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick-tick > shadow_atlas_realloc_tolerance_msec);
bool should_redraw=shadow_atlas->quadrants[q].shadows[s].version!=p_light_version;
+
+
if (!should_realloc) {
+ shadow_atlas->quadrants[q].shadows[s].version=p_light_version;
//already existing, see if it should redraw or it's just OK
- if (should_redraw) {
- key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT;
- }
-
- return key;
+ return should_redraw;
}
int new_quadrant,new_shadow;
@@ -339,6 +352,10 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh
sli->shadow_atlases.erase(p_atlas);
}
+ //erase previous
+ shadow_atlas->quadrants[q].shadows[s].version=0;
+ shadow_atlas->quadrants[q].shadows[s].owner=RID();
+
sh->owner=p_light_intance;
sh->alloc_tick=tick;
sh->version=p_light_version;
@@ -349,19 +366,16 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh
//update it in map
shadow_atlas->shadow_owners[p_light_intance]=key;
//make it dirty, as it should redraw anyway
- key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT;
-
- return key;
+ return true;
}
//no better place for this shadow found, keep current
//already existing, see if it should redraw or it's just OK
- if (should_redraw) {
- key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT;
- }
- return key;
+ shadow_atlas->quadrants[q].shadows[s].version=p_light_version;
+
+ return should_redraw;
}
int new_quadrant,new_shadow;
@@ -387,20 +401,49 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh
//update it in map
shadow_atlas->shadow_owners[p_light_intance]=key;
//make it dirty, as it should redraw anyway
- key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT;
- return key;
+ return true;
}
//no place to allocate this light, apologies
- return ShadowAtlas::SHADOW_INVALID;
+ return false;
}
+void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) {
+
+ directional_shadow.light_count=p_count;
+ directional_shadow.current_light=0;
+}
+
+int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) {
+
+ ERR_FAIL_COND_V(directional_shadow.light_count==0,0);
+
+ int shadow_size;
+
+ if (directional_shadow.light_count==1) {
+ shadow_size = directional_shadow.size;
+ } else {
+ shadow_size = directional_shadow.size/2; //more than 4 not supported anyway
+ }
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_intance);
+ ERR_FAIL_COND_V(!light_instance,0);
+
+ switch(light_instance->light_ptr->directional_shadow_mode) {
+ case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: break; //none
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: shadow_size/=2; break;
+ }
+
+ return shadow_size;
+
+}
/* ENVIRONMENT API */
@@ -511,6 +554,7 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
light_instance->last_pass=0;
light_instance->last_scene_pass=0;
+ light_instance->last_scene_shadow_pass=0;
light_instance->light=p_light;
light_instance->light_ptr=storage->light_owner.getornull(p_light);
@@ -520,10 +564,11 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInstance::LightDataUBO), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
-
ERR_FAIL_COND_V(!light_instance->light_ptr,RID());
- return light_instance_owner.make_rid(light_instance);
+ light_instance->self=light_instance_owner.make_rid(light_instance);
+
+ return light_instance->self;
}
void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,const Transform& p_transform){
@@ -534,6 +579,25 @@ void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,con
light_instance->transform=p_transform;
}
+void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ if (light_instance->light_ptr->type!=VS::LIGHT_DIRECTIONAL) {
+ p_pass=0;
+ }
+
+ ERR_FAIL_INDEX(p_pass,4);
+
+ light_instance->shadow_transform[p_pass].camera=p_projection;
+ light_instance->shadow_transform[p_pass].transform=p_transform;
+ light_instance->shadow_transform[p_pass].far=p_far;
+ light_instance->shadow_transform[p_pass].split=p_split;
+
+}
+
+
void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) {
LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
@@ -542,7 +606,6 @@ void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) {
light_instance->last_scene_pass=scene_pass;
}
-
////////////////////////////
////////////////////////////
////////////////////////////
@@ -757,9 +820,10 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
void RasterizerSceneGLES3::_setup_light(LightInstance *p_light) {
-
glBindBufferBase(GL_UNIFORM_BUFFER,3,p_light->light_ubo); //bind light uniform
}
+
+
void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection) {
if (p_instance->billboard || p_instance->billboard_y || p_instance->depth_scale) {
@@ -815,7 +879,22 @@ void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance,const Trans
}
}
-void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass) {
+void RasterizerSceneGLES3::_set_cull(bool p_front,bool p_reverse_cull) {
+
+ bool front = p_front;
+ if (p_reverse_cull)
+ front=!front;
+
+ if (front!=state.cull_front) {
+
+ glCullFace(front?GL_FRONT:GL_BACK);
+ state.cull_front=front;
+ }
+}
+
+
+
+void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow) {
if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) {
//p_reverse_cull=!p_reverse_cull;
@@ -824,25 +903,30 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
glFrontFace(GL_CW);
}
- bool shadow=false;
-
glBindBufferBase(GL_UNIFORM_BUFFER,0,state.scene_ubo); //bind globals ubo
- glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info
- glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1);
- glBindTexture(GL_TEXTURE_2D,state.brdf_texture);
+ if (!p_shadow) {
+ glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info
+ glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1);
+ glBindTexture(GL_TEXTURE_2D,state.brdf_texture);
- if (p_base_env) {
- glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2);
- glBindTexture(p_base_env->target,p_base_env->tex_id);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true);
+ if (p_base_env) {
+ glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2);
+ glBindTexture(p_base_env->target,p_base_env->tex_id);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true);
+ } else {
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false);
+
+ }
} else {
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false);
}
+ state.cull_front=false;
+ glCullFace(GL_BACK);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false);
@@ -875,28 +959,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
bool additive=false;
- if (!shadow) {
-#if 0
- if (texscreen_used && !texscreen_copied && material->shader_cache && material->shader_cache->valid && material->shader_cache->has_texscreen) {
- texscreen_copied=true;
- _copy_to_texscreen();
-
- //force reset state
- prev_material=NULL;
- prev_light=0x777E;
- prev_geometry_cmp=NULL;
- prev_light_type=0xEF;
- prev_skeleton =NULL;
- prev_sort_flags=0xFF;
- prev_morph_values=NULL;
- prev_receive_shadows_state=-1;
- glEnable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
+ if (!p_shadow) {
- }
-#endif
if (light_type!=prev_light_type /* || receive_shadows_state!=prev_receive_shadows_state*/) {
if (material->shader->spatial.unshaded/* || current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) {
@@ -905,27 +969,38 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false);
state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false);
+
//state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true);
} else {
state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,light_type!=0xF);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,light_type==VS::LIGHT_DIRECTIONAL);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,light_type==VS::LIGHT_OMNI);
- state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,light_type==VS::LIGHT_SPOT);
- /*
- if (receive_shadows_state==1) {
- state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,(light_type&0x8));
- state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,(light_type&0x10));
- state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,(light_type&0x20));
- }
- else {
- state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,false);
- state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,false);
- state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,(light_type&3)==VS::LIGHT_DIRECTIONAL);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,(light_type&0xF)==VS::LIGHT_OMNI);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,(light_type&0xF)==VS::LIGHT_SPOT);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false);
+
+ if ((light_type&3)==VS::LIGHT_DIRECTIONAL) {
+
+ if (light_instances[light_index]->light_ptr->shadow) {
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,true);
+
+ switch(light_instances[light_index]->light_ptr->directional_shadow_mode) {
+ case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: break; //none
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,true); break;
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,true); break;
+ }
+ }
}
- state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false);
- */
+
+
}
rebind=true;
@@ -1007,14 +1082,16 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
current_blend_mode=desired_blend_mode;
}
- }
- if (light_index!=prev_light_index) {
- if (light_index!=0xFFFF) { //not unshaded
- _setup_light(light_instances[light_index]);
+ if (light_index!=prev_light_index) {
+ if (light_index!=0xFFFF) { //not unshaded
+ _setup_light(light_instances[light_index]);
+ }
}
+
}
+
if (material!=prev_material || rebind) {
rebind = _setup_material(material,p_alpha_pass);
@@ -1027,20 +1104,17 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
_setup_geometry(e);
}
- if (rebind || prev_additive!=additive) {
+ if (!p_shadow && (rebind || prev_additive!=additive)) {
state.scene_shader.set_uniform(SceneShaderGLES3::NO_AMBIENT_LIGHT, additive);
}
-// _set_cull(e->mirror,p_reverse_cull);
+ _set_cull(e->sort_key&RenderList::SORT_KEY_MIRROR_FLAG,p_reverse_cull);
state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror?-1.0:1.0);
_setup_transform(e->instance,p_view_transform,p_projection);
-
-// _render(e->geometry, material, skeleton,e->owner,e->instance->transform);
-
_render_geometry(e);
prev_material=material;
@@ -1052,15 +1126,26 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
}
- //print_line("shaderchanges: "+itos(p_alpha_pass)+": "+itos(_rinfo.shader_change_count));
glFrontFace(GL_CW);
glBindVertexArray(0);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false);
+
}
-void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material) {
+
+void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow) {
RasterizerStorageGLES3::Material *m=NULL;
RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override :(p_material>=0?p_instance->materials[p_material]:p_geometry->material);
@@ -1096,57 +1181,29 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g
bool has_alpha = has_base_alpha || has_blend_alpha;
bool shadow = false;
-#if 0
- if (shadow) {
+ bool mirror = p_instance->mirror;
- if (has_blend_alpha || (has_base_alpha && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA))
+ if (m->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) {
+ mirror=!mirror;
+ }
+
+ if (p_shadow) {
+
+ if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))
return; //bye
- if (!m->shader_cache || (!m->shader_cache->writes_vertex && !m->shader_cache->uses_discard && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA)) {
+ if (!m->shader->spatial.uses_vertex && !m->shader->spatial.uses_discard && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
//shader does not use discard and does not write a vertex position, use generic material
if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED)
- m = shadow_mat_double_sided_ptr;
+ m = storage->material_owner.getptr(default_material_twosided);
else
- m = shadow_mat_ptr;
- if (m->last_pass!=frame) {
-
- if (m->shader.is_valid()) {
-
- m->shader_cache=shader_owner.get(m->shader);
- if (m->shader_cache) {
-
-
- if (!m->shader_cache->valid)
- m->shader_cache=NULL;
- } else {
- m->shader=RID();
- }
-
- } else {
- m->shader_cache=NULL;
- }
-
- m->last_pass=frame;
- }
+ m = storage->material_owner.getptr(default_material);
}
- render_list = &opaque_render_list;
- /* notyet
- if (!m->shader_cache || m->shader_cache->can_zpass)
- render_list = &alpha_render_list;
- } else {
- render_list = &opaque_render_list;
- }*/
-
- } else {
- if (has_alpha) {
- render_list = &alpha_render_list;
- } else {
- render_list = &opaque_render_list;
+ has_alpha=false;
- }
}
-#endif
+
RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element();
@@ -1161,50 +1218,49 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g
e->additive_ptr=&e->additive;
e->sort_key=0;
-
if (e->geometry->last_pass!=render_pass) {
e->geometry->last_pass=render_pass;
e->geometry->index=current_geometry_index++;
}
+
e->sort_key|=uint64_t(e->geometry->index)<<RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT;
e->sort_key|=uint64_t(e->instance->base_type)<<RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT;
- if (e->material->last_pass!=render_pass) {
- e->material->last_pass=render_pass;
- e->material->index=current_material_index++;
- }
+ if (!p_shadow) {
- e->sort_key|=uint64_t(e->material->index)<<RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT;
- e->sort_key|=uint64_t(e->instance->depth_layer)<<RenderList::SORT_KEY_DEPTH_LAYER_SHIFT;
- //if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE)
- // e->sort_flags|=RenderList::SORT_FLAG_INSTANCING;
+ if (e->material->last_pass!=render_pass) {
+ e->material->last_pass=render_pass;
+ e->material->index=current_material_index++;
+ }
- bool mirror = e->instance->mirror;
+ e->sort_key|=uint64_t(e->material->index)<<RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT;
+ e->sort_key|=uint64_t(e->instance->depth_layer)<<RenderList::SORT_KEY_DEPTH_LAYER_SHIFT;
- if (m->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) {
- mirror=!mirror;
- }
+ if (!has_blend_alpha && has_alpha && m->shader->spatial.depth_draw_mode==RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
- if (mirror) {
- e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG;
- }
+ //if nothing exists, add this element as opaque too
+ RenderList::Element *oe = render_list.add_element();
- //e->light_type=0xFF; // no lights!
+ if (!oe)
+ return;
- if (!shadow && !has_blend_alpha && has_alpha && m->shader->spatial.depth_draw_mode==RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
+ copymem(oe,e,sizeof(RenderList::Element));
+ oe->additive_ptr=&oe->additive;
+ }
+ }
- //if nothing exists, add this element as opaque too
- RenderList::Element *oe = render_list.add_element();
+ //if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE)
+ // e->sort_flags|=RenderList::SORT_FLAG_INSTANCING;
- if (!oe)
- return;
- copymem(oe,e,sizeof(RenderList::Element));
- oe->additive_ptr=&oe->additive;
+ if (mirror) {
+ e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG;
}
+ //e->light_type=0xFF; // no lights!
+
@@ -1246,7 +1302,12 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g
ec->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK;
ec->sort_key|=uint64_t(directional_light_instances[i]->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT;
- ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT;
+ ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; //this is zero byt whathever
+
+ if (directional_light_instances[i]->light_ptr->shadow) {
+ //add proper flags for directional shadow mode
+ ec->sort_key|=uint64_t(directional_light_instances[i]->light_ptr->directional_shadow_mode+1) << (RenderList::SORT_KEY_LIGHT_TYPE_SHIFT+2);
+ }
lit=true;
}
@@ -1302,7 +1363,7 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g
}
-void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) {
+void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) {
RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox);
@@ -1382,7 +1443,7 @@ void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection,
}
-void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_cam_projection,const Transform& p_cam_transform) {
+void RasterizerSceneGLES3::_setup_environment(Environment *env,const CameraMatrix& p_cam_projection,const Transform& p_cam_transform) {
//store camera into ubo
@@ -1444,6 +1505,20 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_c
}
+ {
+ //directional shadow
+
+ state.ubo_data.shadow_directional_pixel_size[0]=1.0/directional_shadow.size;
+ state.ubo_data.shadow_directional_pixel_size[1]=1.0/directional_shadow.size;
+
+ glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-4);
+ glBindTexture(GL_TEXTURE_2D,directional_shadow.depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
+ }
+
+
+
glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo);
glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(State::SceneDataUBO), &state.ubo_data);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
@@ -1459,13 +1534,14 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_c
}
-void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection) {
+void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection,RID p_shadow_atlas) {
+
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
directional_light_instance_count=0;
light_instance_count=0;
- Vector<float> lpercent;
-
for(int i=0;i<p_light_cull_count;i++) {
ERR_BREAK( i>=RenderList::MAX_LIGHTS );
@@ -1502,23 +1578,90 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu
li->light_ubo_data.light_params[2]=0;
li->light_ubo_data.light_params[3]=0;
+ if (li->light_ptr->shadow) {
+ int shadow_count=0;
+ switch(li->light_ptr->directional_shadow_mode) {
+ case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
+ shadow_count=1;
+ } break;
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
+ shadow_count=2;
+ } break;
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
+ shadow_count=4;
+ } break;
-#if 0
- if (li->light_ptr->shadow_enabled) {
- CameraMatrix bias;
- bias.set_light_bias();
+ }
+
+ for(int j=0;j<shadow_count;j++) {
+
+
+ uint32_t x=li->directional_rect.pos.x;
+ uint32_t y=li->directional_rect.pos.y;
+ uint32_t width=li->directional_rect.size.x;
+ uint32_t height=li->directional_rect.size.y;
+
+
+
+ if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+
+
+ width/=2;
+ height/=2;
+
+ if (j==0) {
+
+ } else if (j==1) {
+ x+=width;
+ } else if (j==2) {
+ y+=height;
+ } else if (j==3) {
+ x+=width;
+ y+=height;
+
+ }
+
+
+
+ } else if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
- int passes=light_instance_get_shadow_passes(p_light_instance);
+ height/=2;
+
+ if (j==0) {
+
+ } else {
+ y+=height;
+ }
+
+ }
+
+ li->light_ubo_data.shadow_split_offsets[j]=1.0/li->shadow_transform[j].split;
+
+ Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse();
+
+ CameraMatrix bias;
+ bias.set_light_bias();
+ CameraMatrix rectm;
+ Rect2 atlas_rect = Rect2(float(x)/directional_shadow.size,float(y)/directional_shadow.size,float(width)/directional_shadow.size,float(height)/directional_shadow.size);
+ rectm.set_light_atlas_rect(atlas_rect);
+
+// print_line("atlas rect: "+atlas_rect);
+
+ CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview;
+
+ store_camera(shadow_mtx,&li->light_ubo_data.shadow_matrix1[16*j]);
+
+ li->light_ubo_data.light_clamp[0]=atlas_rect.pos.x;
+ li->light_ubo_data.light_clamp[1]=atlas_rect.pos.y;
+ li->light_ubo_data.light_clamp[2]=atlas_rect.size.x;
+ li->light_ubo_data.light_clamp[3]=atlas_rect.size.y;
- for(int i=0;i<passes;i++) {
- Transform modelview=Transform(camera_transform_inverse * li->custom_transform[i]).inverse();
- li->shadow_projection[i] = bias * li->custom_projection[i] * modelview;
}
- lights_use_shadow=true;
+
}
-#endif
+
} break;
case VS::LIGHT_OMNI: {
@@ -1542,29 +1685,57 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu
li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
li->light_ubo_data.light_params[0]=0;
- li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
- li->light_ubo_data.light_params[2]=0;
+ li->light_ubo_data.light_params[1]=0;
+ li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
li->light_ubo_data.light_params[3]=0;
-#if 0
- Transform ai = p_camera_inverse_transform.affine_inverse();
- float zn = p_camera_projection.get_z_near();
- Plane p (ai.origin + ai.basis.get_axis(2) * -zn, -ai.basis.get_axis(2) );
+ if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) {
+ // fill in the shadow information
- Vector3 point1 = li->transform.origin;
- Vector3 point2 = li->transform.origin+p_camera_inverse_transform.affine_inverse().basis.get_axis(1).normalized()*li->light_ptr->param[VS::LIGHT_PARAM_RANGE];
+ uint32_t key = shadow_atlas->shadow_owners[li->self];
- p.intersects_segment(ai.origin,point1,&point1);
- p.intersects_segment(ai.origin,point2,&point2);
- float r = point1.distance_to(point2);
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_CONTINUE(shadow>=shadow_atlas->quadrants[quadrant].shadows.size());
+
+ uint32_t atlas_size = shadow_atlas->size;
+ uint32_t quadrant_size = atlas_size>>1;
+
+ uint32_t x=(quadrant&1)*quadrant_size;
+ uint32_t y=(quadrant>>1)*quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ uint32_t width=shadow_size;
+ uint32_t height=shadow_size;
+
+
+ if (li->light_ptr->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+
+ height/=2;
+ } else {
+ width/=2;
+
+ }
+
+ Transform proj = (p_camera_inverse_transform * li->transform).inverse();
+
+ store_transform(proj,li->light_ubo_data.shadow_matrix1);
+
+ li->light_ubo_data.light_params[3]=1.0; //means it has shadow
+ li->light_ubo_data.light_clamp[0]=float(x)/atlas_size;
+ li->light_ubo_data.light_clamp[1]=float(y)/atlas_size;
+ li->light_ubo_data.light_clamp[2]=float(width)/atlas_size;
+ li->light_ubo_data.light_clamp[3]=float(height)/atlas_size;
+
+ }
- float vp_w,vp_h;
- p_camera_projection.get_viewport_size(vp_w,vp_h);
- lpercent.push_back(r*2/((vp_h+vp_w)*0.5));
-#endif
#if 0
if (li->light_ptr->shadow_enabled) {
@@ -1596,10 +1767,54 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu
li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
li->light_ubo_data.light_params[0]=li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION];
- li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
- li->light_ubo_data.light_params[2]=0;
+ li->light_ubo_data.light_params[1]=Math::cos(Math::deg2rad(li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]));
+ li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
li->light_ubo_data.light_params[3]=0;
+ if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) {
+ // fill in the shadow information
+
+ uint32_t key = shadow_atlas->shadow_owners[li->self];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_CONTINUE(shadow>=shadow_atlas->quadrants[quadrant].shadows.size());
+
+ uint32_t atlas_size = shadow_atlas->size;
+ uint32_t quadrant_size = atlas_size>>1;
+
+ uint32_t x=(quadrant&1)*quadrant_size;
+ uint32_t y=(quadrant>>1)*quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ uint32_t width=shadow_size;
+ uint32_t height=shadow_size;
+
+ Rect2 rect(float(x)/atlas_size,float(y)/atlas_size,float(width)/atlas_size,float(height)/atlas_size);
+
+ li->light_ubo_data.light_params[3]=1.0; //means it has shadow
+ li->light_ubo_data.light_clamp[0]=rect.pos.x;
+ li->light_ubo_data.light_clamp[1]=rect.pos.y;
+ li->light_ubo_data.light_clamp[2]=rect.size.x;
+ li->light_ubo_data.light_clamp[3]=rect.size.y;
+
+ Transform modelview = (p_camera_inverse_transform * li->transform).inverse();
+
+ CameraMatrix bias;
+ bias.set_light_bias();
+ CameraMatrix rectm;
+ rectm.set_light_atlas_rect(rect);
+
+ CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[0].camera * modelview;
+
+ store_camera(shadow_mtx,li->light_ubo_data.shadow_matrix1);
+
+
+ }
#if 0
if (li->light_ptr->shadow_enabled) {
CameraMatrix bias;
@@ -1679,24 +1894,39 @@ void RasterizerSceneGLES3::_copy_to_front_buffer(Environment *env) {
}
-void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){
+void RasterizerSceneGLES3::_copy_texture_to_front_buffer(GLuint p_texture) {
- //first of all, make a new render pass
- render_pass++;
+ //copy to front buffer
+ glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo);
- //fill up ubo
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1,1,1,1);
- Environment *env = environment_owner.getornull(p_environment);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D,p_texture);
- _setup_environment(env,p_cam_projection,p_cam_transform);
+ glViewport(0,0,storage->frame.current_rt->width*0.5,storage->frame.current_rt->height*0.5);
- _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,true);
+ storage->shaders.copy.bind();
- render_list.clear();
+ _copy_screen();
- current_material_index=0;
+ //turn off everything used
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB,false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,false);
- bool use_mrt=false;
+
+}
+
+void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow){
+
+ current_geometry_index=0;
+ current_material_index=0;
//fill list
@@ -1716,7 +1946,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM
int mat_idx = inst->materials[i].is_valid() ? i : -1;
RasterizerStorageGLES3::Surface *s = mesh->surfaces[i];
- _add_geometry(s,inst,NULL,mat_idx);
+ _add_geometry(s,inst,NULL,mat_idx,p_shadow);
}
//mesh->last_pass=frame;
@@ -1731,7 +1961,39 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM
}
}
+}
+
+
+void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas){
+
+ //first of all, make a new render pass
+ render_pass++;
+
+ //fill up ubo
+
+ Environment *env = environment_owner.getornull(p_environment);
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+
+ if (shadow_atlas && shadow_atlas->size) {
+ glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-3);
+ glBindTexture(GL_TEXTURE_2D,shadow_atlas->depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
+ state.ubo_data.shadow_atlas_pixel_size[0]=1.0/shadow_atlas->size;
+ state.ubo_data.shadow_atlas_pixel_size[1]=1.0/shadow_atlas->size;
+ }
+
+ _setup_environment(env,p_cam_projection,p_cam_transform);
+
+ _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_shadow_atlas);
+
+ render_list.clear();
+
+ bool use_mrt=false;
+
+
+ _fill_render_list(p_cull_result,p_cull_count,false);
//
@@ -1742,6 +2004,8 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM
RasterizerStorageGLES3::Texture* env_radiance_tex=NULL;
+ glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height);
+
if (use_mrt) {
glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo);
@@ -1811,7 +2075,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false);
+ _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false);
@@ -1843,11 +2107,34 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM
render_list.sort_by_depth(true);
- _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true);
+ _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false);
_copy_to_front_buffer(env);
+/* if (shadow_atlas) {
+
+ //_copy_texture_to_front_buffer(shadow_atlas->depth);
+ storage->canvas->canvas_begin();
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D,shadow_atlas->depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1));
+
+ }
+*/
+ if (directional_shadow.fbo) {
+
+ //_copy_texture_to_front_buffer(shadow_atlas->depth);
+ storage->canvas->canvas_begin();
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D,directional_shadow.depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1));
+
+ }
+
+
#if 0
if (use_fb) {
@@ -1994,6 +2281,294 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM
#endif
}
+void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count) {
+
+ render_pass++;
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light);
+ ERR_FAIL_COND(!light_instance);
+ RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light);
+ ERR_FAIL_COND(!light);
+
+ uint32_t x,y,width,height,vp_height;
+
+
+ float dp_direction=0.0;
+ float zfar=0;
+ bool flip_facing=false;
+ int custom_vp_size=0;
+ GLuint fbo;
+ int current_cubemap=-1;
+ float bias=0;
+ float normal_bias=0;
+
+ CameraMatrix light_projection;
+ Transform light_transform;
+
+
+ if (light->type==VS::LIGHT_DIRECTIONAL) {
+ //set pssm stuff
+ if (light_instance->last_scene_shadow_pass!=scene_pass) {
+ //assign rect if unassigned
+ light_instance->light_directional_index = directional_shadow.current_light;
+ light_instance->last_scene_shadow_pass=scene_pass;
+ directional_shadow.current_light++;
+
+ if (directional_shadow.light_count==1) {
+ light_instance->directional_rect=Rect2(0,0,directional_shadow.size,directional_shadow.size);
+ } else if (directional_shadow.light_count==2) {
+ light_instance->directional_rect=Rect2(0,0,directional_shadow.size,directional_shadow.size/2);
+ if (light_instance->light_directional_index==1) {
+ light_instance->directional_rect.pos.x+=light_instance->directional_rect.size.x;
+ }
+ } else { //3 and 4
+ light_instance->directional_rect=Rect2(0,0,directional_shadow.size/2,directional_shadow.size/2);
+ if (light_instance->light_directional_index&1) {
+ light_instance->directional_rect.pos.x+=light_instance->directional_rect.size.x;
+ }
+ if (light_instance->light_directional_index/2) {
+ light_instance->directional_rect.pos.y+=light_instance->directional_rect.size.y;
+ }
+ }
+ }
+
+ light_projection=light_instance->shadow_transform[p_pass].camera;
+ light_transform=light_instance->shadow_transform[p_pass].transform;
+
+ x=light_instance->directional_rect.pos.x;
+ y=light_instance->directional_rect.pos.y;
+ width=light_instance->directional_rect.size.x;
+ height=light_instance->directional_rect.size.y;
+
+
+
+ if (light->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+
+
+ width/=2;
+ height/=2;
+
+ if (p_pass==0) {
+
+ } else if (p_pass==1) {
+ x+=width;
+ } else if (p_pass==2) {
+ y+=height;
+ } else if (p_pass==3) {
+ x+=width;
+ y+=height;
+
+ }
+
+
+
+ } else if (light->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+
+ height/=2;
+
+ if (p_pass==0) {
+
+ } else {
+ y+=height;
+ }
+
+ }
+
+ zfar=light->param[VS::LIGHT_PARAM_RANGE];
+ bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS];
+ normal_bias=light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS];
+ fbo=directional_shadow.fbo;
+ vp_height=directional_shadow.size;
+
+ } else {
+ //set from shadow atlas
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light));
+
+ fbo=shadow_atlas->fbo;
+ vp_height=shadow_atlas->size;
+
+
+ uint32_t key = shadow_atlas->shadow_owners[p_light];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_FAIL_INDEX(shadow,shadow_atlas->quadrants[quadrant].shadows.size());
+
+ uint32_t quadrant_size = shadow_atlas->size>>1;
+
+ x=(quadrant&1)*quadrant_size;
+ y=(quadrant>>1)*quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ width=shadow_size;
+ height=shadow_size;
+
+ if (light->type==VS::LIGHT_OMNI) {
+
+
+ if (light->omni_shadow_mode==VS::LIGHT_OMNI_SHADOW_CUBE) {
+
+ int cubemap_index=shadow_cubemaps.size()-1;
+
+ for(int i=shadow_cubemaps.size()-1;i>=0;i--) {
+ //find appropriate cubemap to render to
+ if (shadow_cubemaps[i].size>shadow_size*2)
+ break;
+
+ cubemap_index=i;
+ }
+
+ fbo=shadow_cubemaps[cubemap_index].fbo_id[p_pass];
+ light_projection=light_instance->shadow_transform[0].camera;
+ light_transform=light_instance->shadow_transform[0].transform;
+ custom_vp_size=shadow_cubemaps[cubemap_index].size;
+ zfar=light->param[VS::LIGHT_PARAM_RANGE];
+
+ current_cubemap=cubemap_index;
+
+
+ } else {
+
+ light_projection=light_instance->shadow_transform[0].camera;
+ light_transform=light_instance->shadow_transform[0].transform;
+
+ if (light->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+
+ height/=2;
+ y+=p_pass*height;
+ } else {
+ width/=2;
+ x+=p_pass*width;
+
+ }
+
+ dp_direction = p_pass==0?1.0:-1.0;
+ flip_facing = (p_pass == 1);
+ zfar=light->param[VS::LIGHT_PARAM_RANGE];
+ bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS];
+
+ state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,true);
+ }
+
+ } else if (light->type==VS::LIGHT_SPOT) {
+
+ light_projection=light_instance->shadow_transform[0].camera;
+ light_transform=light_instance->shadow_transform[0].transform;
+
+ dp_direction = 1.0;
+ flip_facing = false;
+ zfar=light->param[VS::LIGHT_PARAM_RANGE];
+ bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS];
+ normal_bias=light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS];
+ }
+
+ }
+
+ //todo hacer que se redibuje cuando corresponde
+
+
+ render_list.clear();
+ _fill_render_list(p_cull_result,p_cull_count,true);
+
+ render_list.sort_by_depth(false); //shadow is front to back for performance
+
+ glDepthMask(true);
+ glColorMask(0,0,0,0);
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glEnable(GL_DEPTH_TEST);
+
+ glBindFramebuffer(GL_FRAMEBUFFER,fbo);
+
+ if (custom_vp_size) {
+ glViewport(0,0,custom_vp_size,custom_vp_size);
+ glScissor(0,0,custom_vp_size,custom_vp_size);
+
+ } else {
+ glViewport(x,y,width,height);
+ glScissor(x,y,width,height);
+ }
+
+ //glViewport(x,vp_height-(height+y),width,height);
+ //glScissor(x,vp_height-(height+y),width,height);
+ glEnable(GL_SCISSOR_TEST);
+ glClearDepth(1.0);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glDisable(GL_SCISSOR_TEST);
+
+ state.ubo_data.shadow_z_offset=bias;
+ state.ubo_data.shadow_slope_scale=normal_bias;
+ state.ubo_data.shadow_dual_paraboloid_render_side=dp_direction;
+ state.ubo_data.shadow_dual_paraboloid_render_zfar=zfar;
+
+ _setup_environment(NULL,light_projection,light_transform);
+
+ state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,true);
+
+ _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true);
+
+ state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false);
+
+
+ if (light->type==VS::LIGHT_OMNI && light->omni_shadow_mode==VS::LIGHT_OMNI_SHADOW_CUBE && p_pass==5) {
+ //convert the chosen cubemap to dual paraboloid!
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+
+ glBindFramebuffer(GL_FRAMEBUFFER,shadow_atlas->fbo);
+ state.cube_to_dp_shader.bind();
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP,shadow_cubemaps[current_cubemap].cubemap);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ glDisable(GL_CULL_FACE);
+
+ for(int i=0;i<2;i++) {
+
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FLIP,i==1);
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_NEAR,light_projection.get_z_near());
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FAR,light_projection.get_z_far());
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::BIAS,light->param[VS::LIGHT_PARAM_SHADOW_BIAS]);
+
+ uint32_t local_width=width,local_height=height;
+ uint32_t local_x=x,local_y=y;
+ if (light->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+
+ local_height/=2;
+ local_y+=i*local_height;
+ } else {
+ local_width/=2;
+ local_x+=i*local_width;
+ }
+
+ glViewport(local_x,local_y,local_width,local_height);
+ glScissor(local_x,local_y,local_width,local_height);
+ glEnable(GL_SCISSOR_TEST);
+ glClearDepth(1.0);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glDisable(GL_SCISSOR_TEST);
+ //glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+
+ _copy_screen();
+
+ }
+
+ }
+
+ glColorMask(1,1,1,1);
+
+
+}
+
void RasterizerSceneGLES3::set_scene_pass(uint64_t p_pass) {
scene_pass=p_pass;
}
@@ -2169,6 +2744,12 @@ void RasterizerSceneGLES3::initialize() {
default_material = storage->material_create();
storage->material_set_shader(default_material,default_shader);
+ default_shader_twosided = storage->shader_create(VS::SHADER_SPATIAL);
+ default_material_twosided = storage->material_create();
+ storage->shader_set_code(default_shader_twosided,"render_mode cull_disabled;\n");
+ storage->material_set_shader(default_material_twosided,default_shader_twosided);
+
+
glGenBuffers(1, &state.scene_ubo);
glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo);
glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.scene_ubo, GL_DYNAMIC_DRAW);
@@ -2208,9 +2789,77 @@ void RasterizerSceneGLES3::initialize() {
glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
}
render_list.init();
+ state.cube_to_dp_shader.init();
_generate_brdf();
shadow_atlas_realloc_tolerance_msec=500;
+
+
+
+
+
+ int max_shadow_cubemap_sampler_size=512;
+
+ int cube_size = max_shadow_cubemap_sampler_size;
+
+ glActiveTexture(GL_TEXTURE0);
+
+ while(cube_size>=32) {
+
+ ShadowCubeMap cube;
+ cube.size=cube_size;
+
+ glGenTextures(1,&cube.cubemap);
+ glBindTexture(GL_TEXTURE_CUBE_MAP,cube.cubemap);
+ //gen cubemap first
+ for(int i=0;i<6;i++) {
+
+ glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube.size, cube.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+ }
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ // Remove artifact on the edges of the shadowmap
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+
+ //gen renderbuffers second, because it needs a complete cubemap
+ for(int i=0;i<6;i++) {
+
+ glGenFramebuffers(1, &cube.fbo_id[i]);
+ glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo_id[i]);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,_cube_side_enum[i], cube.cubemap, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE);
+ }
+
+ shadow_cubemaps.push_back(cube);
+
+ cube_size>>=1;
+ }
+
+ {
+ //directional light shadow
+ directional_shadow.light_count=0;
+ directional_shadow.size=nearest_power_of_2(GLOBAL_DEF("renderer/directional_shadow_size",2048));
+ glGenFramebuffers(1,&directional_shadow.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER,directional_shadow.fbo);
+ glGenTextures(1,&directional_shadow.depth);
+ glBindTexture(GL_TEXTURE_2D,directional_shadow.depth);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D, directional_shadow.depth, 0);
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status!=GL_FRAMEBUFFER_COMPLETE) {
+ ERR_PRINT("Directional shadow framebuffer status invalid");
+ }
+ }
}
void RasterizerSceneGLES3::finalize(){
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 9df6315e45..d7beebbcf6 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -3,6 +3,7 @@
#include "rasterizer_storage_gles3.h"
#include "drivers/gles3/shaders/scene.glsl.h"
+#include "drivers/gles3/shaders/cube_to_dp.glsl.h"
class RasterizerSceneGLES3 : public RasterizerScene {
public:
@@ -16,10 +17,13 @@ public:
uint32_t current_geometry_index;
RID default_material;
+ RID default_material_twosided;
RID default_shader;
+ RID default_shader_twosided;
RasterizerStorageGLES3 *storage;
+
struct State {
@@ -29,6 +33,7 @@ public:
int current_depth_draw;
SceneShaderGLES3 scene_shader;
+ CubeToDpShaderGLES3 cube_to_dp_shader;
struct SceneDataUBO {
@@ -41,6 +46,12 @@ public:
float bg_color[4];
float ambient_energy;
float bg_energy;
+ float shadow_z_offset;
+ float shadow_slope_scale;
+ float shadow_dual_paraboloid_render_zfar;
+ float shadow_dual_paraboloid_render_side;
+ float shadow_atlas_pixel_size[2];
+ float shadow_directional_pixel_size[2];
} ubo_data;
@@ -62,7 +73,7 @@ public:
GLuint skybox_verts;
GLuint skybox_array;
-
+ bool cull_front;
} state;
@@ -71,7 +82,6 @@ public:
struct ShadowAtlas : public RID_Data {
enum {
- SHADOW_INDEX_DIRTY_BIT=(1<<31),
QUADRANT_SHIFT=27,
SHADOW_INDEX_MASK=(1<<QUADRANT_SHIFT)-1,
SHADOW_INVALID=0xFFFFFFFF
@@ -111,13 +121,35 @@ public:
Map<RID,uint32_t> shadow_owners;
};
+ struct ShadowCubeMap {
+
+ GLuint fbo_id[6];
+ GLuint cubemap;
+ int size;
+ };
+
+ Vector<ShadowCubeMap> shadow_cubemaps;
+
RID_Owner<ShadowAtlas> shadow_atlas_owner;
RID shadow_atlas_create();
void shadow_atlas_set_size(RID p_atlas,int p_size);
void shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision);
bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
- uint32_t shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version);
+ bool shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version);
+
+
+ struct DirectionalShadow {
+ GLuint fbo;
+ GLuint depth;
+ int light_count;
+ int size;
+ int current_light;
+ } directional_shadow;
+
+ virtual int get_directional_light_shadow_size(RID p_light_intance);
+ virtual void set_directional_shadow_count(int p_count);
+
/* ENVIRONMENT API */
@@ -174,12 +206,12 @@ public:
struct LightInstance : public RID_Data {
- struct SplitInfo {
+ struct ShadowTransform {
CameraMatrix camera;
Transform transform;
- float near;
float far;
+ float split;
};
struct LightDataUBO {
@@ -188,6 +220,7 @@ public:
float light_direction_attenuation[4];
float light_color_energy[4];
float light_params[4]; //cone attenuation, specular, shadow darkening,
+ float light_clamp[4]; //cone attenuation, specular, shadow darkening,
float shadow_split_offsets[4];
float shadow_matrix1[16];
float shadow_matrix2[16];
@@ -197,13 +230,11 @@ public:
} light_ubo_data;
- SplitInfo split_info[4];
+ ShadowTransform shadow_transform[4];
+ RID self;
RID light;
RasterizerStorageGLES3::Light *light_ptr;
-
- CameraMatrix shadow_matrix[4];
-
Transform transform;
Vector3 light_vector;
@@ -214,12 +245,17 @@ public:
uint64_t shadow_pass;
uint64_t last_scene_pass;
+ uint64_t last_scene_shadow_pass;
uint64_t last_pass;
uint16_t light_index;
+ uint16_t light_directional_index;
+
+ uint32_t current_shadow_atlas_key;
Vector2 dp;
- CameraMatrix shadow_projection[4];
+ Rect2 directional_rect;
+
Set<RID> shadow_atlases; //shadow atlases where this light is registered
@@ -231,6 +267,7 @@ public:
virtual RID light_instance_create(RID p_light);
virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform);
+ virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass);
virtual void light_instance_mark_visible(RID p_light_instance);
/* RENDER LIST */
@@ -371,26 +408,31 @@ public:
RenderList render_list;
+ _FORCE_INLINE_ void _set_cull(bool p_front,bool p_reverse_cull);
+
_FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass);
_FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection);
_FORCE_INLINE_ void _setup_geometry(RenderList::Element *e);
_FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
_FORCE_INLINE_ void _setup_light(LightInstance *p_light);
- void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass);
+ void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow);
- _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material);
+ _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow);
- void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale);
+ void _draw_skybox(RID p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale);
- void _setup_environment(Environment *env,CameraMatrix& p_cam_projection, const Transform& p_cam_transform);
- void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform,const CameraMatrix& p_camera_projection);
+ void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform& p_cam_transform);
+ void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_shadow_atlas);
void _copy_screen();
void _copy_to_front_buffer(Environment *env);
+ void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug
- virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment);
+ void _fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow);
+ virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas);
+ virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count);
virtual bool free(RID p_rid);
void _generate_brdf();
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 4b2c607297..b988781e14 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -1290,12 +1290,13 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
shaders.actions_scene.render_mode_values["cull_front"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_FRONT);
shaders.actions_scene.render_mode_values["cull_back"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_BACK);
- shaders.actions_scene.render_mode_values["cull_disable"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED);
+ shaders.actions_scene.render_mode_values["cull_disabled"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED);
shaders.actions_scene.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded;
shaders.actions_scene.render_mode_flags["ontop"]=&p_shader->spatial.ontop;
shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha;
+ shaders.actions_scene.usage_flag_pointers["VERTEX"]=&p_shader->spatial.uses_vertex;
actions=&shaders.actions_scene;
actions->uniforms=&p_shader->uniforms;
@@ -1318,6 +1319,9 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
p_shader->texture_count=gen_code.texture_uniforms.size();
p_shader->texture_hints=gen_code.texture_hints;
+ p_shader->uses_vertex_time=gen_code.uses_vertex_time;
+ p_shader->uses_fragment_time=gen_code.uses_fragment_time;
+
//all materials using this shader will have to be invalidated, unfortunately
for (SelfList<Material>* E = p_shader->materials.first();E;E=E->next() ) {
@@ -1535,6 +1539,57 @@ void RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_wid
}
+bool RasterizerStorageGLES3::material_is_animated(RID p_material) {
+
+ Material *material = material_owner.get( p_material );
+ ERR_FAIL_COND_V(!material,false);
+ if (material->dirty_list.in_list()) {
+ _update_material(material);
+ }
+
+ return material->is_animated_cache;
+
+}
+bool RasterizerStorageGLES3::material_casts_shadows(RID p_material) {
+
+ Material *material = material_owner.get( p_material );
+ ERR_FAIL_COND_V(!material,false);
+ if (material->dirty_list.in_list()) {
+ _update_material(material);
+ }
+
+ return material->can_cast_shadow_cache;
+}
+
+void RasterizerStorageGLES3::material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+
+ Material *material = material_owner.get( p_material );
+ ERR_FAIL_COND(!material);
+
+ Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.find(p_instance);
+ if (E) {
+ E->get()++;
+ } else {
+ material->instance_owners[p_instance]=1;
+ }
+}
+
+void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+
+ Material *material = material_owner.get( p_material );
+ ERR_FAIL_COND(!material);
+
+ Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.find(p_instance);
+ ERR_FAIL_COND(!E);
+ E->get()--;
+
+ if (E->get()==0) {
+ material->instance_owners.erase(E);
+ }
+}
+
+
+
_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant& value, uint8_t *data,bool p_linear_color) {
switch(type) {
case ShaderLanguage::TYPE_BOOL: {
@@ -2011,6 +2066,48 @@ void RasterizerStorageGLES3::_update_material(Material* material) {
if (material->dirty_list.in_list())
_material_dirty_list.remove( &material->dirty_list );
+
+ if (material->shader && material->shader->dirty_list.in_list()) {
+ _update_shader(material->shader);
+ }
+ //update caches
+
+ {
+ bool can_cast_shadow = false;
+ bool is_animated = false;
+
+ if (material->shader && material->shader->mode==VS::SHADER_SPATIAL) {
+ if (!material->shader->spatial.uses_alpha && material->shader->spatial.blend_mode==Shader::Spatial::BLEND_MODE_MIX) {
+ can_cast_shadow=true;
+ }
+
+ if (material->shader->spatial.uses_discard && material->shader->uses_fragment_time) {
+ is_animated=true;
+ }
+
+ if (material->shader->spatial.uses_vertex && material->shader->uses_vertex_time) {
+ is_animated=true;
+ }
+
+ }
+
+ if (can_cast_shadow!=material->can_cast_shadow_cache || is_animated!=material->is_animated_cache) {
+ material->can_cast_shadow_cache=can_cast_shadow;
+ material->is_animated_cache=is_animated;
+
+ for(Map<Instantiable*,int>::Element *E=material->instantiable_owners.front();E;E=E->next()) {
+ E->key()->instance_material_change_notify();
+ }
+
+ for(Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.front();E;E=E->next()) {
+ E->key()->base_material_changed();
+ }
+
+ }
+
+ }
+
+
//clear ubo if it needs to be cleared
if (material->ubo_size) {
@@ -2102,6 +2199,36 @@ void RasterizerStorageGLES3::_update_material(Material* material) {
}
+void RasterizerStorageGLES3::_material_add_instantiable(RID p_material,Instantiable *p_instantiable) {
+
+ Material * material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable);
+
+ if (I) {
+ I->get()++;
+ } else {
+ material->instantiable_owners[p_instantiable]=1;
+ }
+
+}
+
+void RasterizerStorageGLES3::_material_remove_instantiable(RID p_material,Instantiable *p_instantiable) {
+
+ Material * material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable);
+ ERR_FAIL_COND(!I);
+
+ I->get()--;
+ if (I->get()==0) {
+ material->instantiable_owners.erase(I);
+ }
+}
+
+
void RasterizerStorageGLES3::update_dirty_materials() {
while( _material_dirty_list.first() ) {
@@ -2406,6 +2533,8 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
surface->active=true;
surface->array_len=p_vertex_count;
surface->index_array_len=p_index_count;
+ surface->array_byte_size=p_array.size();
+ surface->index_array_byte_size=p_index_array.size();
surface->primitive=p_primitive;
surface->mesh=mesh;
surface->format=p_format;
@@ -2556,8 +2685,22 @@ void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface
ERR_FAIL_COND(!mesh);
ERR_FAIL_INDEX(p_surface,mesh->surfaces.size());
+ if (mesh->surfaces[p_surface]->material==p_material)
+ return;
+
+ if (mesh->surfaces[p_surface]->material.is_valid()) {
+ _material_remove_instantiable(mesh->surfaces[p_surface]->material,mesh);
+ }
+
mesh->surfaces[p_surface]->material=p_material;
+ if (mesh->surfaces[p_surface]->material.is_valid()) {
+ _material_add_instantiable(mesh->surfaces[p_surface]->material,mesh);
+ }
+
+ mesh->instance_material_change_notify();
+
+
}
RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const{
@@ -2595,17 +2738,17 @@ DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int
Surface *surface = mesh->surfaces[p_surface];
glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
- void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_len,GL_MAP_READ_BIT);
+ void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_byte_size,GL_MAP_READ_BIT);
ERR_FAIL_COND_V(!data,DVector<uint8_t>());
DVector<uint8_t> ret;
- ret.resize(surface->array_len);
+ ret.resize(surface->array_byte_size);
{
DVector<uint8_t>::Write w = ret.write();
- copymem(w.ptr(),data,surface->array_len);
+ copymem(w.ptr(),data,surface->array_byte_size);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
@@ -2622,18 +2765,18 @@ DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh
ERR_FAIL_COND_V(surface->index_array_len==0,DVector<uint8_t>());
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->vertex_id);
- void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_len,GL_MAP_READ_BIT);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+ void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_byte_size,GL_MAP_READ_BIT);
ERR_FAIL_COND_V(!data,DVector<uint8_t>());
DVector<uint8_t> ret;
- ret.resize(surface->index_array_len);
+ ret.resize(surface->index_array_byte_size);
{
DVector<uint8_t>::Write w = ret.write();
- copymem(w.ptr(),data,surface->index_array_len);
+ copymem(w.ptr(),data,surface->index_array_byte_size);
}
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
@@ -2662,6 +2805,59 @@ VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_
return mesh->surfaces[p_surface]->primitive;
}
+AABB RasterizerStorageGLES3::mesh_surface_get_aabb(RID p_mesh, int p_surface) const {
+
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,AABB());
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),AABB());
+
+ return mesh->surfaces[p_surface]->aabb;
+
+
+}
+Vector<DVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const{
+
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,Vector<DVector<uint8_t> >());
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector<DVector<uint8_t> >());
+
+ Vector<DVector<uint8_t> > bsarr;
+
+ for(int i=0;i<mesh->surfaces[p_surface]->morph_targets.size();i++) {
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh->surfaces[p_surface]->morph_targets[i].vertex_id);
+ void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,mesh->surfaces[p_surface]->array_byte_size,GL_MAP_READ_BIT);
+
+ ERR_FAIL_COND_V(!data,Vector<DVector<uint8_t> >());
+
+ DVector<uint8_t> ret;
+ ret.resize(mesh->surfaces[p_surface]->array_byte_size);
+
+ {
+
+ DVector<uint8_t>::Write w = ret.write();
+ copymem(w.ptr(),data,mesh->surfaces[p_surface]->array_byte_size);
+ }
+
+ bsarr.push_back(ret);
+
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+ }
+
+ return bsarr;
+
+}
+Vector<AABB> RasterizerStorageGLES3::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const{
+
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh,Vector<AABB >());
+ ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector<AABB >());
+
+ return mesh->surfaces[p_surface]->skeleton_bone_aabb;
+
+}
+
+
void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
Mesh *mesh = mesh_owner.getornull(p_mesh);
@@ -2670,6 +2866,10 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
Surface *surface = mesh->surfaces[p_surface];
+ if (surface->material.is_valid()) {
+ _material_remove_instantiable(surface->material,mesh);
+ }
+
glDeleteBuffers(1,&surface->vertex_id);
if (surface->index_id) {
glDeleteBuffers(1,&surface->index_id);
@@ -2683,6 +2883,8 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){
glDeleteVertexArrays(1,&surface->morph_targets[i].array_id);
}
+ mesh->instance_material_change_notify();
+
memdelete(surface);
mesh->surfaces.remove(p_surface);
@@ -2971,7 +3173,6 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){
light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET]=0.1;
light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET]=0.3;
light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET]=0.6;
- light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET]=1.0;
light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]=0.1;
light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]=0.1;
@@ -2981,6 +3182,10 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){
light->negative=false;
light->cull_mask=0xFFFFFFFF;
light->directional_shadow_mode=VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+ light->omni_shadow_mode=VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+ light->omni_shadow_detail=VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL;
+
+ light->version=0;
return light_owner.make_rid(light);
}
@@ -2998,9 +3203,23 @@ void RasterizerStorageGLES3::light_set_param(RID p_light,VS::LightParam p_param,
ERR_FAIL_COND(!light);
ERR_FAIL_INDEX(p_param,VS::LIGHT_PARAM_MAX);
- if (p_param==VS::LIGHT_PARAM_RANGE || p_param==VS::LIGHT_PARAM_SPOT_ANGLE) {
- light->instance_change_notify();
+ switch(p_param) {
+ case VS::LIGHT_PARAM_RANGE:
+ case VS::LIGHT_PARAM_SPOT_ANGLE:
+ case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE:
+ case VS::LIGHT_PARAM_SHADOW_DARKNESS:
+ case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET:
+ case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
+ case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
+ case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
+ case VS::LIGHT_PARAM_SHADOW_BIAS:
+ case VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE: {
+
+ light->version++;
+ light->instance_change_notify();
+ } break;
}
+
light->param[p_param]=p_value;
}
void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){
@@ -3009,6 +3228,10 @@ void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){
ERR_FAIL_COND(!light);
light->shadow=p_enabled;
+ light->version++;
+ light->instance_change_notify();
+
+
}
void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){
@@ -3021,9 +3244,8 @@ void RasterizerStorageGLES3::light_set_attenuation_texure(RID p_light,RID p_text
Light * light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
-
-
}
+
void RasterizerStorageGLES3::light_set_negative(RID p_light,bool p_enable){
Light * light = light_owner.getornull(p_light);
@@ -3037,6 +3259,10 @@ void RasterizerStorageGLES3::light_set_cull_mask(RID p_light,uint32_t p_mask){
ERR_FAIL_COND(!light);
light->cull_mask=p_mask;
+
+ light->version++;
+ light->instance_change_notify();
+
}
void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){
@@ -3045,22 +3271,92 @@ void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){
}
+void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) {
+
+ Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->omni_shadow_mode=p_mode;
+
+ light->version++;
+ light->instance_change_notify();
+
+
+}
+
+VS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) {
+
+ const Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI_SHADOW_CUBE);
+
+ return light->omni_shadow_mode;
+}
+
+
+void RasterizerStorageGLES3::light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail) {
+
+ Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->omni_shadow_detail=p_detail;
+ light->version++;
+ light->instance_change_notify();
+}
+
void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode){
Light * light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
+ light->directional_shadow_mode=p_mode;
+ light->version++;
+ light->instance_change_notify();
+
+}
+
+VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) {
+
+ const Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+
+ return light->directional_shadow_mode;
}
+
VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const {
const Light * light = light_owner.getornull(p_light);
ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL);
- return VS::LIGHT_DIRECTIONAL;
+ return light->type;
}
+float RasterizerStorageGLES3::light_get_param(RID p_light,VS::LightParam p_param) {
+
+ const Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL);
+
+ return light->param[p_param];
+}
+
+bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const {
+
+ const Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL);
+
+ return light->shadow;
+}
+
+uint64_t RasterizerStorageGLES3::light_get_version(RID p_light) const {
+
+ const Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light,0);
+
+ return light->version;
+}
+
+
AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const {
const Light * light = light_owner.getornull(p_light);
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index b12c2d93b6..f8b34d6a16 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -99,6 +99,38 @@ public:
+ struct Instantiable : public RID_Data {
+
+ SelfList<RasterizerScene::InstanceBase>::List instance_list;
+
+ _FORCE_INLINE_ void instance_change_notify() {
+
+ SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
+ while(instances) {
+
+ instances->self()->base_changed();
+ instances=instances->next();
+ }
+ }
+
+ _FORCE_INLINE_ void instance_material_change_notify() {
+
+ SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
+ while(instances) {
+
+ instances->self()->base_material_changed();
+ instances=instances->next();
+ }
+ }
+
+ Instantiable() { }
+ virtual ~Instantiable() {
+
+ while(instance_list.first()) {
+ instance_list.first()->self()->base_removed();
+ }
+ }
+ };
@@ -282,9 +314,14 @@ public:
bool uses_alpha;
bool unshaded;
bool ontop;
+ bool uses_vertex;
+ bool uses_discard;
} spatial;
+ bool uses_vertex_time;
+ bool uses_fragment_time;
+
Shader() : dirty_list(this) {
shader=NULL;
@@ -315,6 +352,8 @@ public:
void update_dirty_shaders();
+
+
/* COMMON MATERIAL API */
struct Material : public RID_Data {
@@ -331,7 +370,15 @@ public:
uint32_t index;
uint64_t last_pass;
+ Map<Instantiable*,int> instantiable_owners;
+ Map<RasterizerScene::InstanceBase*,int> instance_owners;
+
+ bool can_cast_shadow_cache;
+ bool is_animated_cache;
+
Material() : list(this), dirty_list(this) {
+ can_cast_shadow_cache=false;
+ is_animated_cache=false;
shader=NULL;
line_width=1.0;
ubo_id=0;
@@ -343,6 +390,8 @@ public:
mutable SelfList<Material>::List _material_dirty_list;
void _material_make_dirty(Material *p_material) const;
+ void _material_add_instantiable(RID p_material,Instantiable *p_instantiable);
+ void _material_remove_instantiable(RID p_material, Instantiable *p_instantiable);
mutable RID_Owner<Material> material_owner;
@@ -357,34 +406,18 @@ public:
virtual void material_set_line_width(RID p_material, float p_width);
+ virtual bool material_is_animated(RID p_material);
+ virtual bool material_casts_shadows(RID p_material);
+
+ virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance);
+ virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance);
+
void _update_material(Material* material);
void update_dirty_materials();
/* MESH API */
- struct Instantiable : public RID_Data {
-
- SelfList<RasterizerScene::InstanceBase>::List instance_list;
-
- _FORCE_INLINE_ void instance_change_notify() {
-
- SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
- while(instances) {
-
- instances->self()->base_changed();
- instances=instances->next();
- }
- }
-
- Instantiable() { }
- virtual ~Instantiable() {
-
- while(instance_list.first()) {
- instance_list.first()->self()->base_removed();
- }
- }
- };
struct Geometry : Instantiable {
@@ -455,7 +488,8 @@ public:
int index_array_len;
int max_bone;
- int array_bytes;
+ int array_byte_size;
+ int index_array_byte_size;
VS::PrimitiveType primitive;
@@ -464,7 +498,8 @@ public:
Surface() {
- array_bytes=0;
+ array_byte_size=0;
+ index_array_byte_size=0;
mesh=NULL;
format=0;
array_id=0;
@@ -526,6 +561,10 @@ public:
virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const;
virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
+ virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const;
+ virtual Vector<DVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const;
+ virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const;
+
virtual void mesh_remove_surface(RID p_mesh, int p_surface);
virtual int mesh_get_surface_count(RID p_mesh) const;
@@ -598,7 +637,10 @@ public:
bool shadow;
bool negative;
uint32_t cull_mask;
+ VS::LightOmniShadowMode omni_shadow_mode;
+ VS::LightOmniShadowDetail omni_shadow_detail;
VS::LightDirectionalShadowMode directional_shadow_mode;
+ uint64_t version;
};
mutable RID_Owner<Light> light_owner;
@@ -614,11 +656,22 @@ public:
virtual void light_set_cull_mask(RID p_light,uint32_t p_mask);
virtual void light_set_shader(RID p_light,RID p_shader);
+ virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode);
+
+ virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail);
virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode);
+ virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
+ virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
+
+ virtual bool light_has_shadow(RID p_light) const;
virtual VS::LightType light_get_type(RID p_light) const;
+ virtual float light_get_param(RID p_light,VS::LightParam p_param);
+
virtual AABB light_get_aabb(RID p_light) const;
+ virtual uint64_t light_get_version(RID p_light) const;
+
/* PROBE API */
virtual RID reflection_probe_create();
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index 0dff53bfb9..dce52ecd93 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -330,6 +330,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
SL::FunctionNode *fnode=pnode->functions[i].function;
+ current_func_name=fnode->name;
if (fnode->name=="vertex") {
@@ -401,6 +402,14 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
else
code=_mkid(vnode->name);
+ if (vnode->name==time_name) {
+ if (current_func_name==vertex_name) {
+ r_gen_code.uses_vertex_time=true;
+ }
+ if (current_func_name==fragment_name) {
+ r_gen_code.uses_fragment_time=true;
+ }
+ }
} break;
case SL::Node::TYPE_CONSTANT: {
@@ -536,6 +545,8 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String& p_code,
r_gen_code.fragment=String();
r_gen_code.fragment_global=String();
r_gen_code.light=String();
+ r_gen_code.uses_fragment_time=false;
+ r_gen_code.uses_vertex_time=false;
@@ -645,7 +656,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
-
+ vertex_name="vertex";
+ fragment_name="fragment";
+ time_name="TIME";
diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h
index dcea82d773..3549526808 100644
--- a/drivers/gles3/shader_compiler_gles3.h
+++ b/drivers/gles3/shader_compiler_gles3.h
@@ -32,6 +32,9 @@ public:
String fragment;
String light;
+ bool uses_fragment_time;
+ bool uses_vertex_time;
+
};
private:
@@ -49,6 +52,10 @@ private:
String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions& p_actions, const DefaultIdentifierActions& p_default_actions);
+ StringName current_func_name;
+ StringName vertex_name;
+ StringName fragment_name;
+ StringName time_name;
Set<StringName> used_name_defines;
Set<StringName> used_rmode_defines;
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index afffe10316..44d325b091 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -6,4 +6,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'):
env.GLES3_GLSL('canvas_shadow.glsl');
env.GLES3_GLSL('scene.glsl');
env.GLES3_GLSL('cubemap_filter.glsl');
+ env.GLES3_GLSL('cube_to_dp.glsl');
diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl
new file mode 100644
index 0000000000..5ffc78c0b9
--- /dev/null
+++ b/drivers/gles3/shaders/cube_to_dp.glsl
@@ -0,0 +1,79 @@
+[vertex]
+
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+out vec2 uv_interp;
+
+void main() {
+
+ uv_interp = uv_in;
+ gl_Position = vertex_attrib;
+}
+
+[fragment]
+
+
+uniform highp samplerCube source_cube; //texunit:0
+in vec2 uv_interp;
+
+uniform bool z_flip;
+uniform highp float z_far;
+uniform highp float z_near;
+uniform highp float bias;
+
+void main() {
+
+ highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 );
+/*
+ if(z_flip) {
+ normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ } else {
+ normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ }
+*/
+
+ //normal.z = sqrt(1.0-dot(normal.xy,normal.xy));
+ //normal.xy*=1.0+normal.z;
+
+ normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ normal = normalize(normal);
+
+/*
+ normal.z=0.5;
+ normal=normalize(normal);
+*/
+ if (!z_flip) {
+ normal.z=-normal.z;
+ }
+
+ //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 ));
+ float depth = texture(source_cube,normal).r;
+
+ // absolute values for direction cosines, bigger value equals closer to basis axis
+ vec3 unorm = abs(normal);
+
+ if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) {
+ // x code
+ unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ;
+ } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) {
+ // y code
+ unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ;
+ } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) {
+ // z code
+ unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ;
+ } else {
+ // oh-no we messed up code
+ // has to be
+ unorm = vec3( 1.0, 0.0, 0.0 );
+ }
+
+ float depth_fix = 1.0 / dot(normal,unorm);
+
+
+ depth = 2.0 * depth - 1.0;
+ float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near));
+ gl_FragDepth = (linear_depth*depth_fix+bias) / z_far;
+}
+
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 60ac015a17..de1591e8ff 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1,7 +1,6 @@
[vertex]
-#define ENABLE_UV_INTERP
/*
from VisualServer:
@@ -56,6 +55,15 @@ layout(std140) uniform SceneData { //ubo:0
highp vec4 bg_color;
float ambient_energy;
float bg_energy;
+
+ float shadow_z_offset;
+ float shadow_z_slope_scale;
+ float shadow_dual_paraboloid_render_zfar;
+ float shadow_dual_paraboloid_render_side;
+
+ vec2 shadow_atlas_pixel_size;
+ vec2 directional_shadow_pixel_size;
+
};
uniform highp mat4 world_transform;
@@ -68,6 +76,7 @@ layout(std140) uniform LightData { //ubo:3
mediump vec4 light_direction_attenuation;
mediump vec4 light_color_energy;
mediump vec4 light_params; //cone attenuation, specular, shadow darkening,
+ mediump vec4 light_clamp;
mediump vec4 shadow_split_offsets;
highp mat4 shadow_matrix1;
highp mat4 shadow_matrix2;
@@ -75,19 +84,6 @@ layout(std140) uniform LightData { //ubo:3
highp mat4 shadow_matrix4;
};
-#ifdef USE_FORWARD_1_SHADOW_MAP
-out mediump vec4 forward_shadow_pos1;
-#endif
-
-#ifdef USE_FORWARD_2_SHADOW_MAP
-out mediump vec4 forward_shadow_pos2;
-#endif
-
-#ifdef USE_FORWARD_4_SHADOW_MAP
-out mediump vec4 forward_shadow_pos3;
-out mediump vec4 forward_shadow_pos4;
-#endif
-
#endif
/* Varyings */
@@ -120,13 +116,6 @@ varying vec4 position_interp;
#endif
-#ifdef USE_SHADOW_PASS
-
-uniform highp float shadow_z_offset;
-uniform highp float shadow_z_slope_scale;
-
-#endif
-
VERTEX_SHADER_GLOBALS
@@ -141,6 +130,11 @@ MATERIAL_UNIFORMS
#endif
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+out highp float dp_clip;
+
+#endif
void main() {
@@ -206,24 +200,49 @@ VERTEX_SHADER_CODE
}
+ vertex_interp = vertex.xyz;
+ normal_interp = normal;
+
+#if defined(ENABLE_TANGENT_INTERP)
+ tangent_interp = tangent;
+ binormal_interp = binormal;
+#endif
+
+#ifdef RENDER_SHADOW
+
+
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+ vertex_interp.z*= shadow_dual_paraboloid_render_side;
+ normal_interp.z*= shadow_dual_paraboloid_render_side;
-#ifdef USE_SHADOW_PASS
+ dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
+
+ //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges
+
+ highp vec3 vtx = vertex_interp+normalize(vertex_interp)*shadow_z_offset;
+ highp float distance = length(vtx);
+ vtx = normalize(vtx);
+ vtx.xy/=1.0-vtx.z;
+ vtx.z=(distance/shadow_dual_paraboloid_render_zfar);
+ vtx.z=vtx.z * 2.0 - 1.0;
+
+ vertex.xyz=vtx;
+ vertex.w=1.0;
+
+
+#else
float z_ofs = shadow_z_offset;
z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale;
vertex_interp.z-=z_ofs;
-#endif
+#endif //RENDER_SHADOW_DUAL_PARABOLOID
- vertex_interp = vertex.xyz;
- normal_interp = normal;
+#endif //RENDER_SHADOW
-#if defined(ENABLE_TANGENT_INTERP)
- tangent_interp = tangent;
- binormal_interp = binormal;
-#endif
-#if !defined(SKIP_TRANSFORM_USED)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_SHADOW_DUAL_PARABOLOID)
gl_Position = projection_matrix * vec4(vertex_interp,1.0);
#else
gl_Position = vertex;
@@ -239,11 +258,6 @@ VERTEX_SHADER_CODE
#define M_PI 3.14159265359
-
-#define ENABLE_UV_INTERP
-//hack to use uv if no uv present so it works with lightmap
-
-
/* Varyings */
#if defined(ENABLE_COLOR_INTERP)
@@ -318,6 +332,15 @@ layout(std140) uniform SceneData {
highp vec4 bg_color;
float ambient_energy;
float bg_energy;
+
+ float shadow_z_offset;
+ float shadow_z_slope_scale;
+ float shadow_dual_paraboloid_render_zfar;
+ float shadow_dual_paraboloid_render_side;
+
+ vec2 shadow_atlas_pixel_size;
+ vec2 directional_shadow_pixel_size;
+
};
@@ -328,7 +351,8 @@ layout(std140) uniform LightData {
highp vec4 light_pos_inv_radius;
mediump vec4 light_direction_attenuation;
mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, specular, shadow darkening,
+ mediump vec4 light_params; //cone attenuation, specular, shadow darkening, shadow enabled
+ mediump vec4 light_clamp;
mediump vec4 shadow_split_offsets;
highp mat4 shadow_matrix1;
highp mat4 shadow_matrix2;
@@ -336,20 +360,12 @@ layout(std140) uniform LightData {
highp mat4 shadow_matrix4;
};
-#ifdef USE_FORWARD_1_SHADOW_MAP
-in mediump vec4 forward_shadow_pos1;
#endif
-#ifdef USE_FORWARD_2_SHADOW_MAP
-in mediump vec4 forward_shadow_pos2;
-#endif
-#ifdef USE_FORWARD_4_SHADOW_MAP
-in mediump vec4 forward_shadow_pos3;
-in mediump vec4 forward_shadow_pos4;
-#endif
+uniform highp sampler2DShadow directional_shadow; //texunit:-4
+uniform highp sampler2DShadow shadow_atlas; //texunit:-3
-#endif
#ifdef USE_MULTIPLE_RENDER_TARGETS
@@ -408,10 +424,27 @@ void light_compute(vec3 normal, vec3 light_vec,vec3 eye_vec,vec3 diffuse_color,
}
+float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) {
+
+ return textureProj(shadow,vec4(pos,depth,1.0));
+}
+
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+in highp float dp_clip;
+
+#endif
+
void main() {
+#ifdef RENDER_SHADOW_DUAL_PARABOLOID
+
+ if (dp_clip>0.0)
+ discard;
+#endif
+
//lay out everything, whathever is unused is optimized away anyway
- vec3 vertex = vertex_interp;
+ highp vec3 vertex = vertex_interp;
vec3 albedo = vec3(0.8,0.8,0.8);
vec3 specular = vec3(0.2,0.2,0.2);
float roughness = 1.0;
@@ -528,27 +561,216 @@ FRAGMENT_SHADER_CODE
#endif
-#ifdef USE_FORWARD_LIGHTING
-
#ifdef USE_FORWARD_DIRECTIONAL
- light_compute(normal,light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,1.0,diffuse_light,specular_light);
+ float light_attenuation=1.0;
+
+#ifdef LIGHT_DIRECTIONAL_SHADOW
+
+ if (gl_FragCoord.w > shadow_split_offsets.w) {
+
+ vec3 pssm_coord;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+ float pssm_blend;
+ vec3 pssm_coord2;
+ bool use_blend=true;
+ vec3 light_pssm_split_inv = 1.0/shadow_split_offsets.xyz;
+ float w_inv = 1.0/gl_FragCoord.w;
#endif
+
+#ifdef LIGHT_USE_PSSM4
+
+
+ if (gl_FragCoord.w > shadow_split_offsets.y) {
+
+ if (gl_FragCoord.w > shadow_split_offsets.x) {
+
+ highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+ ambient_light=vec3(1.0,0.4,0.4);
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+
+ splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv);
+#endif
+
+ } else {
+
+ highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+ ambient_light=vec3(0.4,1.0,0.4);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ splane=(shadow_matrix3 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv);
+#endif
+
+ }
+ } else {
+
+
+ if (gl_FragCoord.w > shadow_split_offsets.z) {
+
+ highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+ ambient_light=vec3(0.4,0.4,1.0);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ splane=(shadow_matrix4 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv);
+#endif
+
+ } else {
+ highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+ diffuse_light*=vec3(1.0,0.4,1.0);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ use_blend=false;
+
+#endif
+
+ }
+ }
+
+#endif //LIGHT_USE_PSSM4
+
+#ifdef LIGHT_USE_PSSM2
+
+ if (gl_FragCoord.w > shadow_split_offsets.x) {
+
+ highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+
+ splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord2=splane.xyz/splane.w;
+ pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv);
+#endif
+
+ } else {
+ highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+#if defined(LIGHT_USE_PSSM_BLEND)
+ use_blend=false;
+
+#endif
+
+ }
+
+#endif //LIGHT_USE_PSSM2
+
+#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
+ { //regular orthogonal
+ highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+ pssm_coord=splane.xyz/splane.w;
+ }
+#endif
+
+
+ //one one sample
+ light_attenuation=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp);
+
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ if (use_blend) {
+ float light_attenuation2=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp);
+ light_attenuation=mix(light_attenuation,light_attenuation2,pssm_blend);
+ }
+#endif
+
+ }
+
+#endif //LIGHT_DIRECTIONAL_SHADOW
+
+ light_compute(normal,-light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light);
+
+
+#endif //USE_FORWARD_DIRECTIONAL
+
+
#ifdef USE_FORWARD_OMNI
vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex;
float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w;
float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w );
+
+ if (light_params.w>0.5) {
+ //there is a shadowmap
+
+ highp vec3 splane=(shadow_matrix1 * vec4(vertex,1.0)).xyz;
+ float shadow_len=length(splane);
+ splane=normalize(splane);
+ vec4 clamp_rect=light_clamp;
+
+ if (splane.z>=0.0) {
+
+ splane.z+=1.0;
+
+ clamp_rect.y+=clamp_rect.w;
+
+ } else {
+
+ splane.z=1.0 - splane.z;
+
+ //if (clamp_rect.z<clamp_rect.w) {
+ // clamp_rect.x+=clamp_rect.z;
+ //} else {
+ // clamp_rect.y+=clamp_rect.w;
+ //}
+
+ }
+
+ splane.xy/=splane.z;
+ splane.xy=splane.xy * 0.5 + 0.5;
+ splane.z = shadow_len * light_pos_inv_radius.w;
+
+ splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw;
+
+ light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect);
+ }
+
light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light);
-#endif
+
+#endif //USE_FORWARD_OMNI
#ifdef USE_FORWARD_SPOT
-#endif
+ vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex;
+ float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w;
+ float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w );
+ vec3 spot_dir = light_direction_attenuation.xyz;
+ float spot_cutoff=light_params.y;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff);
+ float rim = (1.0 - scos) / (1.0 - spot_cutoff);
+ light_attenuation *= 1.0 - pow( rim, light_params.x);
+
+ if (light_params.w>0.5) {
+ //there is a shadowmap
+
+ highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
+ splane.xyz/=splane.w;
+ // splane.xy=splane.xy*0.5+0.5;
+
+ //splane.xy=light_clamp.xy+splane.xy*light_clamp.zw;
+ light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,light_clamp);
+
+ }
+
+ light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light);
+
+#endif //USE_FORWARD_SPOT
-#endif
#if defined(USE_LIGHT_SHADER_CODE)
@@ -560,6 +782,11 @@ LIGHT_SHADER_CODE
}
#endif
+#ifdef RENDER_SHADOW
+//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
+#else
+
+
#ifdef USE_MULTIPLE_RENDER_TARGETS
//approximate ambient scale for SSAO, since we will lack full ambient
@@ -574,13 +801,17 @@ LIGHT_SHADER_CODE
#else
+
#ifdef SHADELESS
frag_color=vec4(albedo,alpha);
#else
frag_color=vec4(ambient_light+diffuse_light+specular_light,alpha);
-#endif
+#endif //SHADELESS
+
+#endif //USE_MULTIPLE_RENDER_TARGETS
+
+#endif //RENDER_SHADOW
-#endif
}
diff --git a/main/main.cpp b/main/main.cpp
index 912e8adf4f..bd4af2e79a 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1296,6 +1296,17 @@ bool Main::start() {
appname = TranslationServer::get_singleton()->translate(appname);
OS::get_singleton()->set_window_title(appname);
+ int shadow_atlas_size = GLOBAL_DEF("rendering/shadow_atlas/size",2048);
+ int shadow_atlas_q0_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2);
+ int shadow_atlas_q1_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2);
+ int shadow_atlas_q2_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3);
+ int shadow_atlas_q3_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4);
+
+ sml->get_root()->set_shadow_atlas_size(shadow_atlas_size);
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q0_subdiv));
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q1_subdiv));
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q2_subdiv));
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q3_subdiv));
} else {
GLOBAL_DEF("display/stretch_mode","disabled");
@@ -1304,7 +1315,17 @@ bool Main::start() {
Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height"));
sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true));
-
+ GLOBAL_DEF("rendering/shadow_atlas/size",2048);
+ Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/size",PropertyInfo(Variant::INT,"rendering/shadow_atlas/size",PROPERTY_HINT_RANGE,"256,16384"));
+
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2);
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2);
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3);
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4);
+ Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_0_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_0_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_1_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_1_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_2_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_2_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ Globals::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_3_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_3_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
}
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 88ba7b3731..cfc829078d 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -202,7 +202,7 @@ void Light::_bind_methods() {
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "light/negative"), _SCS("set_negative"), _SCS("is_negative"));
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/specular"), _SCS("set_param"), _SCS("get_param"), PARAM_SPECULAR);
ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask"), _SCS("set_cull_mask"), _SCS("get_cull_mask"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow"));
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow"));
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkness"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_DARKNESS);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/normal_bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS);
@@ -222,7 +222,6 @@ void Light::_bind_methods() {
BIND_CONSTANT( PARAM_SHADOW_SPLIT_1_OFFSET );
BIND_CONSTANT( PARAM_SHADOW_SPLIT_2_OFFSET );
BIND_CONSTANT( PARAM_SHADOW_SPLIT_3_OFFSET );
- BIND_CONSTANT( PARAM_SHADOW_SPLIT_4_OFFSET );
BIND_CONSTANT( PARAM_SHADOW_NORMAL_BIAS );
BIND_CONSTANT( PARAM_SHADOW_BIAS );
BIND_CONSTANT( PARAM_SHADOW_BIAS_SPLIT_SCALE );
@@ -255,7 +254,6 @@ Light::Light(VisualServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_1_OFFSET,0.1);
set_param(PARAM_SHADOW_SPLIT_2_OFFSET,0.2);
set_param(PARAM_SHADOW_SPLIT_3_OFFSET,0.5);
- set_param(PARAM_SHADOW_SPLIT_4_OFFSET,1.0);
set_param(PARAM_SHADOW_NORMAL_BIAS,0.1);
set_param(PARAM_SHADOW_BIAS,0.1);
set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE,0.1);
@@ -279,36 +277,107 @@ Light::~Light() {
}
/////////////////////////////////////////
+void DirectionalLight::set_shadow_mode(ShadowMode p_mode) {
+
+ shadow_mode=p_mode;
+ VS::get_singleton()->light_directional_set_shadow_mode(light,VS::LightDirectionalShadowMode(p_mode));
+}
+
+DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const {
+
+ return shadow_mode;
+}
+
+void DirectionalLight::set_blend_splits(bool p_enable) {
+
+ blend_splits=p_enable;
+}
+
+bool DirectionalLight::is_blend_splits_enabled() const {
+
+ return blend_splits;
+}
+
void DirectionalLight::_bind_methods() {
+ ObjectTypeDB::bind_method( _MD("set_shadow_mode","mode"),&DirectionalLight::set_shadow_mode);
+ ObjectTypeDB::bind_method( _MD("get_shadow_mode"),&DirectionalLight::get_shadow_mode);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "pssm/split_4"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_4_OFFSET);
+ ObjectTypeDB::bind_method( _MD("set_blend_splits","enabled"),&DirectionalLight::set_blend_splits);
+ ObjectTypeDB::bind_method( _MD("is_blend_splits_enabled"),&DirectionalLight::is_blend_splits_enabled);
+
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "directional/shadow_mode",PROPERTY_HINT_ENUM,"Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode"));
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_2"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional/split_3"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET);
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "directional/blend_splits"), _SCS("set_blend_splits"), _SCS("is_blend_splits_enabled"));
+
+ BIND_CONSTANT( SHADOW_ORTHOGONAL );
+ BIND_CONSTANT( SHADOW_PARALLEL_2_SPLITS );
+ BIND_CONSTANT( SHADOW_PARALLEL_4_SPLITS );
}
DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL ) {
+ set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
+ blend_splits=false;
+}
+void OmniLight::set_shadow_mode(ShadowMode p_mode) {
+ shadow_mode=p_mode;
+ VS::get_singleton()->light_omni_set_shadow_mode(light,VS::LightOmniShadowMode(p_mode));
}
+OmniLight::ShadowMode OmniLight::get_shadow_mode() const{
+
+ return shadow_mode;
+}
+
+void OmniLight::set_shadow_detail(ShadowDetail p_detail){
+
+ shadow_detail=p_detail;
+ VS::get_singleton()->light_omni_set_shadow_detail(light,VS::LightOmniShadowDetail(p_detail));
+}
+OmniLight::ShadowDetail OmniLight::get_shadow_detail() const{
+
+ return shadow_detail;
+}
+
+
+
void OmniLight::_bind_methods() {
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION);
+ ObjectTypeDB::bind_method( _MD("set_shadow_mode","mode"),&OmniLight::set_shadow_mode);
+ ObjectTypeDB::bind_method( _MD("get_shadow_mode"),&OmniLight::get_shadow_mode);
+
+ ObjectTypeDB::bind_method( _MD("set_shadow_detail","detail"),&OmniLight::set_shadow_detail);
+ ObjectTypeDB::bind_method( _MD("get_shadow_detail"),&OmniLight::get_shadow_detail);
+
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION);
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_mode",PROPERTY_HINT_ENUM,"Dual Paraboloid,Cube"), _SCS("set_shadow_mode"), _SCS("get_shadow_mode"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "omni/shadow_detail",PROPERTY_HINT_ENUM,"Vertical,Horizontal"), _SCS("set_shadow_detail"), _SCS("get_shadow_detail"));
+
+}
+
+OmniLight::OmniLight() : Light( VisualServer::LIGHT_OMNI ) {
+
+ set_shadow_mode(SHADOW_DUAL_PARABOLOID);
+ set_shadow_detail(SHADOW_DETAIL_HORIZONTAL);
}
void SpotLight::_bind_methods() {
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/range"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_angle"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_attenuation"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION);
}
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 7da2d8e7ca..da28542817 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -45,22 +45,21 @@ class Light : public VisualInstance {
public:
enum Param {
- PARAM_ENERGY,
- PARAM_SPECULAR,
- PARAM_RANGE,
- PARAM_ATTENUATION,
- PARAM_SPOT_ANGLE,
- PARAM_SPOT_ATTENUATION,
- PARAM_SHADOW_MAX_DISTANCE,
- PARAM_SHADOW_DARKNESS,
- PARAM_SHADOW_SPLIT_1_OFFSET,
- PARAM_SHADOW_SPLIT_2_OFFSET,
- PARAM_SHADOW_SPLIT_3_OFFSET,
- PARAM_SHADOW_SPLIT_4_OFFSET,
- PARAM_SHADOW_NORMAL_BIAS,
- PARAM_SHADOW_BIAS,
- PARAM_SHADOW_BIAS_SPLIT_SCALE,
- PARAM_MAX
+ PARAM_ENERGY = VS::LIGHT_PARAM_ENERGY,
+ PARAM_SPECULAR = VS::LIGHT_PARAM_SPECULAR,
+ PARAM_RANGE = VS::LIGHT_PARAM_RANGE,
+ PARAM_ATTENUATION = VS::LIGHT_PARAM_ATTENUATION,
+ PARAM_SPOT_ANGLE = VS::LIGHT_PARAM_SPOT_ANGLE,
+ PARAM_SPOT_ATTENUATION = VS::LIGHT_PARAM_SPOT_ATTENUATION,
+ PARAM_SHADOW_MAX_DISTANCE = VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE,
+ PARAM_SHADOW_DARKNESS = VS::LIGHT_PARAM_SHADOW_DARKNESS,
+ PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
+ PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
+ PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
+ PARAM_SHADOW_NORMAL_BIAS = VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
+ PARAM_SHADOW_BIAS = VS::LIGHT_PARAM_SHADOW_BIAS,
+ PARAM_SHADOW_BIAS_SPLIT_SCALE = VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,
+ PARAM_MAX = VS::LIGHT_PARAM_MAX
};
private:
@@ -126,31 +125,69 @@ class DirectionalLight : public Light {
public:
+ enum ShadowMode {
+ SHADOW_ORTHOGONAL,
+ SHADOW_PARALLEL_2_SPLITS,
+ SHADOW_PARALLEL_4_SPLITS
+ };
private:
+ bool blend_splits;
+ ShadowMode shadow_mode;
protected:
static void _bind_methods();
public:
+ void set_shadow_mode(ShadowMode p_mode);
+ ShadowMode get_shadow_mode() const;
+
+ void set_blend_splits(bool p_enable);
+ bool is_blend_splits_enabled() const;
DirectionalLight();
};
+VARIANT_ENUM_CAST(DirectionalLight::ShadowMode)
class OmniLight : public Light {
OBJ_TYPE( OmniLight, Light );
+public:
+ // omni light
+ enum ShadowMode {
+ SHADOW_DUAL_PARABOLOID,
+ SHADOW_CUBE,
+ };
+
+ // omni light
+ enum ShadowDetail {
+ SHADOW_DETAIL_VERTICAL,
+ SHADOW_DETAIL_HORIZONTAL
+ };
+
+private:
+
+ ShadowMode shadow_mode;
+ ShadowDetail shadow_detail;
protected:
static void _bind_methods();
public:
+ void set_shadow_mode(ShadowMode p_mode);
+ ShadowMode get_shadow_mode() const;
- OmniLight() : Light( VisualServer::LIGHT_OMNI ) { }
+ void set_shadow_detail(ShadowDetail p_detail);
+ ShadowDetail get_shadow_detail() const;
+
+ OmniLight();
};
+VARIANT_ENUM_CAST(OmniLight::ShadowMode)
+VARIANT_ENUM_CAST(OmniLight::ShadowDetail)
+
class SpotLight : public Light {
OBJ_TYPE( SpotLight, Light );
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 386a0fab57..5e1bda3436 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -201,7 +201,7 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
arr.resize(Mesh::ARRAY_MAX);
arr[Mesh::ARRAY_VERTEX]=varr;
- debug_mesh->add_surface(Mesh::PRIMITIVE_LINES,arr);
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,arr);
return debug_mesh;
}
diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp
index cfc6753378..ef619244d0 100644
--- a/scene/main/scene_main_loop.cpp
+++ b/scene/main/scene_main_loop.cpp
@@ -845,7 +845,7 @@ Ref<Mesh> SceneTree::get_debug_contact_mesh() {
arr[Mesh::ARRAY_INDEX]=indices;
- debug_contact_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr);
+ debug_contact_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
debug_contact_mesh->surface_set_material(0,mat);
return debug_contact_mesh;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 35f72c5ce7..0ca72eaa2a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1297,6 +1297,39 @@ bool Viewport::get_clear_on_new_frame() const{
return clear_on_new_frame;
}
+void Viewport::set_shadow_atlas_size(int p_size) {
+
+ shadow_atlas_size=p_size;
+ VS::get_singleton()->viewport_set_shadow_atlas_size(viewport,p_size);
+}
+
+int Viewport::get_shadow_atlas_size() const{
+
+ return shadow_atlas_size;
+}
+
+void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant,ShadowAtlasQuadrantSubdiv p_subdiv){
+
+
+ ERR_FAIL_INDEX(p_quadrant,4);
+ ERR_FAIL_INDEX(p_subdiv,SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
+
+ if (shadow_atlas_quadrant_subdiv[p_quadrant]==p_subdiv)
+ return;
+
+ shadow_atlas_quadrant_subdiv[p_quadrant]=p_subdiv;
+ static const int subdiv[SHADOW_ATLAS_QUADRANT_SUBDIV_MAX]={0,1,4,16,64,256,1024};
+
+ VS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport,p_quadrant,subdiv[p_subdiv]);
+
+}
+Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const{
+
+ ERR_FAIL_INDEX_V(p_quadrant,4,SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
+ return shadow_atlas_quadrant_subdiv[p_quadrant];
+}
+
+
void Viewport::clear() {
//clear=true;
@@ -2661,6 +2694,12 @@ void Viewport::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip);
ObjectTypeDB::bind_method(_MD("_gui_remove_focus"), &Viewport::_gui_remove_focus);
+ ObjectTypeDB::bind_method(_MD("set_shadow_atlas_size","size"), &Viewport::set_shadow_atlas_size);
+ ObjectTypeDB::bind_method(_MD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size);
+
+ ObjectTypeDB::bind_method(_MD("set_shadow_atlas_quadrant_subdiv","quadrant","subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv);
+ ObjectTypeDB::bind_method(_MD("get_shadow_atlas_quadrant_subdiv","quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv);
+
ADD_PROPERTY( PropertyInfo(Variant::RECT2,"size"), _SCS("set_size"), _SCS("get_size") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"own_world"), _SCS("set_use_own_world"), _SCS("is_using_own_world") );
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world",PROPERTY_HINT_RESOURCE_TYPE,"World"), _SCS("set_world"), _SCS("get_world") );
@@ -2674,6 +2713,11 @@ void Viewport::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"physics/object_picking"), _SCS("set_physics_object_picking"), _SCS("get_physics_object_picking") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gui/disable_input"), _SCS("set_disable_input"), _SCS("is_input_disabled") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"3d/disable_3d"), _SCS("set_disable_3d"), _SCS("is_3d_disabled") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow_atlas/size"), _SCS("set_shadow_atlas_size"), _SCS("get_shadow_atlas_size") );
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_0",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),0 );
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_1",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),1 );
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_2",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),2 );
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"shadow_atlas/quad_3",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), _SCS("set_shadow_atlas_quadrant_subdiv"), _SCS("get_shadow_atlas_quadrant_subdiv"),3 );
ADD_SIGNAL(MethodInfo("size_changed"));
@@ -2682,6 +2726,14 @@ void Viewport::_bind_methods() {
BIND_CONSTANT( UPDATE_WHEN_VISIBLE );
BIND_CONSTANT( UPDATE_ALWAYS );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_1 );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_4 );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_16 );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_64 );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_256 );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_1024 );
+ BIND_CONSTANT( SHADOW_ATLAS_QUADRANT_SUBDIV_MAX );
}
@@ -2719,6 +2771,15 @@ Viewport::Viewport() {
physics_object_over=0;
physics_last_mousepos=Vector2(1e20,1e20);
+ shadow_atlas_size=0;
+ for(int i=0;i<4;i++) {
+ shadow_atlas_quadrant_subdiv[0]=SHADOW_ATLAS_QUADRANT_SUBDIV_MAX;
+ }
+ set_shadow_atlas_quadrant_subdiv(0,SHADOW_ATLAS_QUADRANT_SUBDIV_4);
+ set_shadow_atlas_quadrant_subdiv(1,SHADOW_ATLAS_QUADRANT_SUBDIV_4);
+ set_shadow_atlas_quadrant_subdiv(2,SHADOW_ATLAS_QUADRANT_SUBDIV_16);
+ set_shadow_atlas_quadrant_subdiv(3,SHADOW_ATLAS_QUADRANT_SUBDIV_64);
+
String id=itos(get_instance_ID());
input_group = "_vp_input"+id;
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index c5d61469dd..462ecff93e 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -86,6 +86,18 @@ public:
UPDATE_ALWAYS
};
+ enum ShadowAtlasQuadrantSubdiv {
+ SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED,
+ SHADOW_ATLAS_QUADRANT_SUBDIV_1,
+ SHADOW_ATLAS_QUADRANT_SUBDIV_4,
+ SHADOW_ATLAS_QUADRANT_SUBDIV_16,
+ SHADOW_ATLAS_QUADRANT_SUBDIV_64,
+ SHADOW_ATLAS_QUADRANT_SUBDIV_256,
+ SHADOW_ATLAS_QUADRANT_SUBDIV_1024,
+ SHADOW_ATLAS_QUADRANT_SUBDIV_MAX,
+
+ };
+
private:
friend class ViewportTexture;
@@ -120,8 +132,6 @@ friend class ViewportTexture;
RID contact_3d_debug_multimesh;
RID contact_3d_debug_instance;
-
-
bool size_override;
bool size_override_stretch;
Size2 size_override_size;
@@ -175,6 +185,9 @@ friend class ViewportTexture;
RID texture_rid;
Ref<ViewportTexture> texture;
+ int shadow_atlas_size;
+ ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4];
+
struct GUI {
// info used when this is a window
@@ -347,6 +360,11 @@ public:
UpdateMode get_update_mode() const;
Ref<ViewportTexture> get_texture() const;
+ void set_shadow_atlas_size(int p_size);
+ int get_shadow_atlas_size() const;
+
+ void set_shadow_atlas_quadrant_subdiv(int p_quadrant,ShadowAtlasQuadrantSubdiv p_subdiv);
+ ShadowAtlasQuadrantSubdiv get_shadow_atlas_quadrant_subdiv(int p_quadrant) const;
Vector2 get_camera_coords(const Vector2& p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
@@ -393,4 +411,6 @@ public:
};
VARIANT_ENUM_CAST(Viewport::UpdateMode);
+VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv);
+
#endif
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 3c7b0fbe6c..cb55f4f030 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -152,7 +152,7 @@ void FixedSpatialMaterial::_update_shader() {
switch(cull_mode) {
case CULL_BACK: code+=",cull_back"; break;
case CULL_FRONT: code+=",cull_front"; break;
- case CULL_DISABLED: code+=",cull_disable"; break;
+ case CULL_DISABLED: code+=",cull_disabled"; break;
}
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 132ec54e48..e737c5c37e 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -125,11 +125,61 @@ bool Mesh::_set(const StringName& p_name, const Variant& p_value) {
//create
Dictionary d=p_value;
ERR_FAIL_COND_V(!d.has("primitive"),false);
- ERR_FAIL_COND_V(!d.has("arrays"),false);
- ERR_FAIL_COND_V(!d.has("morph_arrays"),false);
+
+ if (d.has("arrays")) {
+ //old format
+ ERR_FAIL_COND_V(!d.has("morph_arrays"),false);
+ add_surface_from_arrays(PrimitiveType(int(d["primitive"])),d["arrays"],d["morph_arrays"]);
+
+ } else if (d.has("array_data")) {
+
+ DVector<uint8_t> array_data = d["array_data"];
+ DVector<uint8_t> array_index_data;
+ if (d.has("array_index_data"))
+ array_index_data=d["array_index_data"];
+
+ ERR_FAIL_COND_V(!d.has("format"),false);
+ uint32_t format = d["format"];
+
+ ERR_FAIL_COND_V(!d.has("primitive"),false);
+ uint32_t primitive = d["primitive"];
+
+ ERR_FAIL_COND_V(!d.has("vertex_count"),false);
+ int vertex_count = d["vertex_count"];
+
+ int index_count=0;
+ if (d.has("index_count"))
+ index_count=d["index_count"];
+
+ Vector< DVector<uint8_t> > morphs;
+
+ if (d.has("morph_data")) {
+ Array morph_data=d["morph_data"];
+ for(int i=0;i<morph_data.size();i++) {
+ DVector<uint8_t> morph = morph_data[i];
+ morphs.push_back(morph_data[i]);
+ }
+ }
+
+ ERR_FAIL_COND_V(!d.has("aabb"),false);
+ AABB aabb = d["aabb"];
+
+ Vector<AABB> bone_aabb;
+ if (d.has("bone_aabb")) {
+ Array baabb = d["bone_aabb"];
+ bone_aabb.resize(baabb.size());
+
+ for(int i=0;i<baabb.size();i++) {
+ bone_aabb[i]=baabb[i];
+ }
+ }
+
+ add_surface(format,PrimitiveType(primitive),array_data,vertex_count,array_index_data,index_count,aabb,morphs,bone_aabb);
+ } else {
+ ERR_FAIL_V(false);
+ }
- add_surface(PrimitiveType(int(d["primitive"])),d["arrays"],d["morph_arrays"]);
if (d.has("material")) {
surface_set_material(idx,d["material"]);
@@ -185,9 +235,31 @@ bool Mesh::_get(const StringName& p_name,Variant &r_ret) const {
ERR_FAIL_INDEX_V(idx,surfaces.size(),false);
Dictionary d;
- d["primitive"]=surface_get_primitive_type(idx);
- d["arrays"]=surface_get_arrays(idx);
- d["morph_arrays"]=surface_get_morph_arrays(idx);
+
+ d["array_data"]=VS::get_singleton()->mesh_surface_get_array(mesh,idx);
+ d["vertex_count"]=VS::get_singleton()->mesh_surface_get_array_len(mesh,idx);
+ d["array_index_data"]=VS::get_singleton()->mesh_surface_get_index_array(mesh,idx);
+ d["index_count"]=VS::get_singleton()->mesh_surface_get_array_index_len(mesh,idx);
+ d["primitive"]=VS::get_singleton()->mesh_surface_get_primitive_type(mesh,idx);
+ d["format"]=VS::get_singleton()->mesh_surface_get_format(mesh,idx);
+ d["aabb"]=VS::get_singleton()->mesh_surface_get_aabb(mesh,idx);
+
+ Vector<AABB> skel_aabb = VS::get_singleton()->mesh_surface_get_skeleton_aabb(mesh,idx);
+ Array arr;
+ for(int i=0;i<skel_aabb.size();i++) {
+ arr[i]=skel_aabb[i];
+ }
+ d["skeleton_aabb"]=arr;
+
+ Vector< DVector<uint8_t> > morph_data = VS::get_singleton()->mesh_surface_get_blend_shapes(mesh,idx);
+
+ Array md;
+ for(int i=0;i<morph_data.size();i++) {
+ md.push_back(morph_data[i]);
+ }
+
+ d["morph_data"]=md;
+
Ref<Material> m = surface_get_material(idx);
if (m.is_valid())
d["material"]=m;
@@ -234,7 +306,17 @@ void Mesh::_recompute_aabb() {
}
-void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes) {
+void Mesh::add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes,const Vector<AABB>& p_bone_aabbs) {
+
+ Surface s;
+ s.aabb=p_aabb;
+ surfaces.push_back(s);
+
+ VisualServer::get_singleton()->mesh_add_surface(mesh,p_format,(VS::PrimitiveType)p_primitive,p_array,p_vertex_count,p_index_array,p_index_count,p_aabb,p_blend_shapes,p_bone_aabbs);
+
+}
+
+void Mesh::add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes) {
ERR_FAIL_COND(p_arrays.size()!=ARRAY_MAX);
@@ -279,8 +361,7 @@ void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Arr
Array Mesh::surface_get_arrays(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface,surfaces.size(),Array());
- //return VisualServer::get_singleton()->mesh_get_surface_arrays(mesh,p_surface);
- return Array();
+ return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh,p_surface);
}
Array Mesh::surface_get_morph_arrays(int p_surface) const {
@@ -929,7 +1010,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
Ref<Mesh> newmesh = memnew( Mesh );
- newmesh->add_surface(PRIMITIVE_TRIANGLES,arrays);
+ newmesh->add_surface_from_arrays(PRIMITIVE_TRIANGLES,arrays);
return newmesh;
}
@@ -943,6 +1024,7 @@ void Mesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_morph_target_mode","mode"),&Mesh::set_morph_target_mode);
ObjectTypeDB::bind_method(_MD("get_morph_target_mode"),&Mesh::get_morph_target_mode);
+ ObjectTypeDB::bind_method(_MD("add_surface_from_arrays","primitive","arrays","blend_shapes"),&Mesh::add_surface_from_arrays,DEFVAL(Array()));
ObjectTypeDB::bind_method(_MD("get_surface_count"),&Mesh::get_surface_count);
ObjectTypeDB::bind_method(_MD("surface_remove","surf_idx"),&Mesh::surface_remove);
ObjectTypeDB::bind_method(_MD("surface_get_array_len","surf_idx"),&Mesh::surface_get_array_len);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index e329c353a0..2b28f1187e 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -122,7 +122,9 @@ protected:
public:
- void add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array());
+ void add_surface_from_arrays(PrimitiveType p_primitive,const Array& p_arrays,const Array& p_blend_shapes=Array());
+ void add_surface(uint32_t p_format,PrimitiveType p_primitive,const DVector<uint8_t>& p_array,int p_vertex_count,const DVector<uint8_t>& p_index_array,int p_index_count,const AABB& p_aabb,const Vector<DVector<uint8_t> >& p_blend_shapes=Vector<DVector<uint8_t> >(),const Vector<AABB>& p_bone_aabbs=Vector<AABB>());
+
Array surface_get_arrays(int p_surface) const;
virtual Array surface_get_morph_arrays(int p_surface) const;
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index fb0fc2a247..758d78e513 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -328,7 +328,7 @@ Error MeshDataTool::commit_to_surface(const Ref<Mesh>& p_mesh) {
Ref<Mesh> ncmesh=p_mesh;
int sc = ncmesh->get_surface_count();
- ncmesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr);
+ ncmesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
ncmesh->surface_set_material(sc,material);
return OK;
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index a71e414f61..778764a832 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -77,7 +77,7 @@ Ref<Mesh> Shape::get_debug_mesh() {
SceneTree *st=OS::get_singleton()->get_main_loop()->cast_to<SceneTree>();
- debug_mesh_cache->add_surface(Mesh::PRIMITIVE_LINES,arr);
+ debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,arr);
if (st) {
debug_mesh_cache->surface_set_material(0,st->get_debug_collision_material());
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index e1769d099b..6f08d69221 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -410,7 +410,7 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) {
}
- mesh->add_surface(primitive,a);
+ mesh->add_surface_from_arrays(primitive,a);
if (material.is_valid())
mesh->surface_set_material(surface,material);
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index feaac38acb..d87cc0fd8c 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 8c54ef11fb..8a0818c299 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 6c7048bd62..7810cc9018 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 e7900bdcc9..e36e31e191 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 10a159f27a..1b62583dcf 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 583b42bfc1..18742aa21d 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 cba33a3b2d..a9b8fe4e94 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 95636d2bc7..953448db52 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 78769c17f7..c2d7aaecef 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 */
diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp
index e8207c9575..fa9e372eb3 100644
--- a/tools/editor/io_plugins/editor_import_collada.cpp
+++ b/tools/editor/io_plugins/editor_import_collada.cpp
@@ -1468,7 +1468,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
mr.push_back(a);
}
- p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,d,mr);
+ p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,d,mr);
if (material.is_valid()) {
p_mesh->surface_set_material(surface, material);
diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp
index 13c69692c7..e5e8668df6 100644
--- a/tools/editor/plugins/spatial_editor_plugin.cpp
+++ b/tools/editor/plugins/spatial_editor_plugin.cpp
@@ -1823,6 +1823,19 @@ void SpatialEditorViewport::_notification(int p_what) {
surface->update();
}
+
+ int shadowmap_size = Globals::get_singleton()->get("rendering/shadow_atlas/size");
+ int atlas_q0 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_0_subdiv");
+ int atlas_q1 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_1_subdiv");
+ int atlas_q2 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_2_subdiv");
+ int atlas_q3 = Globals::get_singleton()->get("rendering/shadow_atlas/quadrant_3_subdiv");
+
+ viewport->set_shadow_atlas_size(shadowmap_size);
+ viewport->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
+ viewport->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
+ viewport->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
+ viewport->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
+
}
if (p_what==NOTIFICATION_ENTER_TREE) {
@@ -2354,6 +2367,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
c->set_area_as_parent_rect();
viewport = memnew( Viewport );
viewport->set_disable_input(true);
+
c->add_child(viewport);
surface = memnew( Control );
add_child(surface);
diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp
index b1accac762..cdd56bbac5 100644
--- a/tools/editor/spatial_editor_gizmos.cpp
+++ b/tools/editor/spatial_editor_gizmos.cpp
@@ -133,7 +133,7 @@ void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mat
a[Mesh::ARRAY_COLOR]=color;
- mesh->add_surface(Mesh::PRIMITIVE_LINES,a);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,a);
mesh->surface_set_material(0,p_material);
if (p_billboard) {
@@ -182,7 +182,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material>& p_material,
a.resize(Mesh::ARRAY_MAX);
a[Mesh::ARRAY_VERTEX]=vs;
a[Mesh::ARRAY_TEX_UV]=uv;
- mesh->add_surface(Mesh::PRIMITIVE_TRIANGLE_FAN,a);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_FAN,a);
mesh->surface_set_material(0,p_material);
if (true) {
@@ -259,7 +259,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi
}
a[VS::ARRAY_COLOR]=colors;
- mesh->add_surface(Mesh::PRIMITIVE_POINTS,a);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS,a);
mesh->surface_set_material(0,SpatialEditorGizmos::singleton->handle2_material);
if (p_billboard) {
@@ -2321,7 +2321,7 @@ void NavigationMeshSpatialGizmo::redraw() {
Array a;
a.resize(Mesh::ARRAY_MAX);
a[0]=tmeshfaces;
- m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
+ m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,a);
m->surface_set_material(0,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_solid_material:SpatialEditorGizmos::singleton->navmesh_solid_material_disabled);
add_mesh(m);
add_collision_segments(lines);
@@ -3090,7 +3090,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
d.resize(VS::ARRAY_MAX);
d[Mesh::ARRAY_VERTEX]=cursor_points;
d[Mesh::ARRAY_COLOR]=cursor_colors;
- pos3d_mesh->add_surface(Mesh::PRIMITIVE_LINES,d);
+ pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,d);
pos3d_mesh->surface_set_material(0,mat);
}
@@ -3114,7 +3114,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
d.resize(VS::ARRAY_MAX);
d[Mesh::ARRAY_VERTEX] = cursor_points;
d[Mesh::ARRAY_COLOR] = cursor_colors;
- listener_line_mesh->add_surface(Mesh::PRIMITIVE_LINES, d);
+ listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
listener_line_mesh->surface_set_material(0, mat);
}