mirror of
https://github.com/godotengine/godot.git
synced 2024-11-27 09:16:35 +08:00
all light types and shadows are working, pending a lot of clean-up
This commit is contained in:
parent
6b2a27bbe5
commit
cacf9ebb7f
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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";
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
||||
|
79
drivers/gles3/shaders/cube_to_dp.glsl
Normal file
79
drivers/gles3/shaders/cube_to_dp.glsl
Normal file
@ -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;
|
||||
}
|
||||
|
@ -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,15 +200,6 @@ VERTEX_SHADER_CODE
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_SHADOW_PASS
|
||||
|
||||
float z_ofs = shadow_z_offset;
|
||||
z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale;
|
||||
vertex_interp.z-=z_ofs;
|
||||
#endif
|
||||
|
||||
|
||||
vertex_interp = vertex.xyz;
|
||||
normal_interp = normal;
|
||||
|
||||
@ -223,7 +208,41 @@ VERTEX_SHADER_CODE
|
||||
binormal_interp = binormal;
|
||||
#endif
|
||||
|
||||
#if !defined(SKIP_TRANSFORM_USED)
|
||||
#ifdef RENDER_SHADOW
|
||||
|
||||
|
||||
#ifdef RENDER_SHADOW_DUAL_PARABOLOID
|
||||
|
||||
vertex_interp.z*= shadow_dual_paraboloid_render_side;
|
||||
normal_interp.z*= shadow_dual_paraboloid_render_side;
|
||||
|
||||
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 //RENDER_SHADOW_DUAL_PARABOLOID
|
||||
|
||||
#endif //RENDER_SHADOW
|
||||
|
||||
|
||||
#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
|
||||
|
||||
}
|
||||
|
||||
|
@ -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"));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user