begin work on new particle system
This commit is contained in:
parent
289bc881aa
commit
f4a56e7782
|
@ -4882,37 +4882,45 @@ uint32_t RasterizerStorageGLES3::gi_probe_get_version(RID p_probe) {
|
||||||
return gip->version;
|
return gip->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth) {
|
RasterizerStorage::GIProbeCompression RasterizerStorageGLES3::gi_probe_get_dynamic_data_get_preferred_compression() const {
|
||||||
|
if (config.s3tc_supported) {
|
||||||
|
return GI_PROBE_S3TC;
|
||||||
|
} else {
|
||||||
|
return GI_PROBE_UNCOMPRESSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) {
|
||||||
|
|
||||||
GIProbeData *gipd = memnew( GIProbeData );
|
GIProbeData *gipd = memnew( GIProbeData );
|
||||||
|
|
||||||
gipd->width=p_width;
|
gipd->width=p_width;
|
||||||
gipd->height=p_height;
|
gipd->height=p_height;
|
||||||
gipd->depth=p_depth;
|
gipd->depth=p_depth;
|
||||||
|
gipd->compression=p_compression;
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glGenTextures(1,&gipd->tex_id);
|
glGenTextures(1,&gipd->tex_id);
|
||||||
glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
|
glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
|
||||||
|
|
||||||
int level=0;
|
int level=0;
|
||||||
|
int min_size=1;
|
||||||
|
|
||||||
|
if (gipd->compression==GI_PROBE_S3TC) {
|
||||||
|
min_size=4;
|
||||||
|
}
|
||||||
|
|
||||||
print_line("dyndata create");
|
print_line("dyndata create");
|
||||||
while(true) {
|
while(true) {
|
||||||
|
|
||||||
Vector<uint8_t> data;
|
if (gipd->compression==GI_PROBE_S3TC) {
|
||||||
data.resize(p_width*p_height*p_depth*4);
|
int size = p_width * p_height * p_depth;
|
||||||
|
glCompressedTexImage3D(GL_TEXTURE_3D,level,_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT,p_width,p_height,p_depth,0, size,NULL);
|
||||||
|
} else {
|
||||||
for(int i=0;i<data.size();i+=4) {
|
glTexImage3D(GL_TEXTURE_3D,level,GL_RGBA8,p_width,p_height,p_depth,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
|
||||||
|
|
||||||
data[i+0]=0xFF;
|
|
||||||
data[i+1]=0x00;
|
|
||||||
data[i+2]=0xFF;
|
|
||||||
data[i+3]=0xFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexImage3D(GL_TEXTURE_3D,level,GL_RGBA8,p_width,p_height,p_depth,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr());
|
if (p_width<=min_size || p_height<=min_size || p_depth<=min_size)
|
||||||
if (p_width<=1 || p_height<=1 || p_depth<=1)
|
|
||||||
break;
|
break;
|
||||||
p_width>>=1;
|
p_width>>=1;
|
||||||
p_height>>=1;
|
p_height>>=1;
|
||||||
|
@ -4933,7 +4941,7 @@ RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width,int p_heigh
|
||||||
return gi_probe_data_owner.make_rid(gipd);
|
return gi_probe_data_owner.make_rid(gipd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerStorageGLES3::gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {
|
void RasterizerStorageGLES3::gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {
|
||||||
|
|
||||||
GIProbeData *gipd = gi_probe_data_owner.getornull(p_gi_probe_data);
|
GIProbeData *gipd = gi_probe_data_owner.getornull(p_gi_probe_data);
|
||||||
ERR_FAIL_COND(!gipd);
|
ERR_FAIL_COND(!gipd);
|
||||||
|
@ -4957,14 +4965,168 @@ void RasterizerStorageGLES3::gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_d
|
||||||
*/
|
*/
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
|
glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
|
||||||
glTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
|
if (gipd->compression==GI_PROBE_S3TC) {
|
||||||
|
int size = (gipd->width>>p_mipmap) * (gipd->height>>p_mipmap) * p_slice_count;
|
||||||
|
glCompressedTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT,size, p_data);
|
||||||
|
} else {
|
||||||
|
glTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
|
||||||
|
}
|
||||||
//glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
|
//glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
|
||||||
//glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr());
|
//glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr());
|
||||||
print_line("update rgba8 "+itos(p_mipmap));
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////
|
||||||
|
|
||||||
|
|
||||||
|
RID RasterizerStorageGLES3::particles_create() {
|
||||||
|
|
||||||
|
Particles *particles = memnew( Particles );
|
||||||
|
|
||||||
|
|
||||||
|
return particles_owner.make_rid(particles);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES3::particles_set_emitting(RID p_particles,bool p_emitting) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
particles->emitting=p_emitting;
|
||||||
|
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_amount(RID p_particles,int p_amount) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_lifetime(RID p_particles,float p_lifetime){
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
particles->lifetime=p_lifetime;
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_pre_process_time(RID p_particles,float p_time) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
particles->pre_process_time=p_time;
|
||||||
|
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_explosiveness_ratio(RID p_particles,float p_ratio) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
particles->explosiveness=p_ratio;
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_randomness_ratio(RID p_particles,float p_ratio) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
particles->randomness=p_ratio;
|
||||||
|
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles,const AABB& p_aabb) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
particles->custom_aabb=p_aabb;
|
||||||
|
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_gravity(RID p_particles,const Vector3& p_gravity) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->gravity=p_gravity;
|
||||||
|
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles,bool p_enable) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->use_local_coords=p_enable;
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_process_material(RID p_particles,RID p_material) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->process_material=p_material;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES3::particles_set_emission_shape(RID p_particles, VS::ParticlesEmissionShape p_shape) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->emission_shape=p_shape;
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_emission_sphere_radius(RID p_particles,float p_radius) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->emission_sphere_radius=p_radius;
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->emission_box_extents=p_extents;
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_emission_points(RID p_particles,const DVector<Vector3>& p_points) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->emission_points=p_points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles,VS::ParticlesDrawOrder p_order) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->draw_order=p_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles,int p_count) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
|
||||||
|
particles->draw_passes.resize(p_count);
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
ERR_FAIL_INDEX(p_pass,particles->draw_passes.size());
|
||||||
|
p_pass,particles->draw_passes[p_pass].material=p_material;
|
||||||
|
|
||||||
|
}
|
||||||
|
void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh) {
|
||||||
|
|
||||||
|
Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND(!particles);
|
||||||
|
ERR_FAIL_INDEX(p_pass,particles->draw_passes.size());
|
||||||
|
p_pass,particles->draw_passes[p_pass].mesh=p_mesh;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) {
|
||||||
|
|
||||||
|
const Particles *particles = particles_owner.getornull(p_particles);
|
||||||
|
ERR_FAIL_COND_V(!particles,AABB());
|
||||||
|
|
||||||
|
return particles->computed_aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////
|
||||||
|
|
||||||
void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) {
|
void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) {
|
||||||
|
|
||||||
|
|
|
@ -941,6 +941,7 @@ public:
|
||||||
int depth;
|
int depth;
|
||||||
int levels;
|
int levels;
|
||||||
GLuint tex_id;
|
GLuint tex_id;
|
||||||
|
GIProbeCompression compression;
|
||||||
|
|
||||||
GIProbeData() {
|
GIProbeData() {
|
||||||
}
|
}
|
||||||
|
@ -948,9 +949,90 @@ public:
|
||||||
|
|
||||||
mutable RID_Owner<GIProbeData> gi_probe_data_owner;
|
mutable RID_Owner<GIProbeData> gi_probe_data_owner;
|
||||||
|
|
||||||
virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth);
|
virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const;
|
||||||
virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data);
|
virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth,GIProbeCompression p_compression);
|
||||||
|
virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data);
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
struct Particles : public Instantiable {
|
||||||
|
|
||||||
|
bool emitting;
|
||||||
|
int amount;
|
||||||
|
float lifetime;
|
||||||
|
float pre_process_time;
|
||||||
|
float explosiveness;
|
||||||
|
float randomness;
|
||||||
|
AABB custom_aabb;
|
||||||
|
Vector3 gravity;
|
||||||
|
bool use_local_coords;
|
||||||
|
RID process_material;
|
||||||
|
|
||||||
|
VS::ParticlesEmissionShape emission_shape;
|
||||||
|
float emission_sphere_radius;
|
||||||
|
Vector3 emission_box_extents;
|
||||||
|
DVector<Vector3> emission_points;
|
||||||
|
GLuint emission_point_texture;
|
||||||
|
|
||||||
|
VS::ParticlesDrawOrder draw_order;
|
||||||
|
struct DrawPass {
|
||||||
|
RID mesh;
|
||||||
|
RID material;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<DrawPass> draw_passes;
|
||||||
|
|
||||||
|
AABB computed_aabb;
|
||||||
|
|
||||||
|
Particles() {
|
||||||
|
emitting=false;
|
||||||
|
amount=0;
|
||||||
|
lifetime=1.0;;
|
||||||
|
pre_process_time=0.0;
|
||||||
|
explosiveness=0.0;
|
||||||
|
randomness=0.0;
|
||||||
|
use_local_coords=true;
|
||||||
|
|
||||||
|
draw_order=VS::PARTICLES_DRAW_ORDER_INDEX;
|
||||||
|
emission_shape=VS::PARTICLES_EMSSION_POINT;
|
||||||
|
emission_sphere_radius=1.0;
|
||||||
|
float emission_sphere_radius;
|
||||||
|
emission_box_extents=Vector3(1,1,1);
|
||||||
|
emission_point_texture=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
mutable RID_Owner<Particles> particles_owner;
|
||||||
|
|
||||||
|
virtual RID particles_create();
|
||||||
|
|
||||||
|
virtual void particles_set_emitting(RID p_particles,bool p_emitting);
|
||||||
|
virtual void particles_set_amount(RID p_particles,int p_amount);
|
||||||
|
virtual void particles_set_lifetime(RID p_particles,float p_lifetime);
|
||||||
|
virtual void particles_set_pre_process_time(RID p_particles,float p_time);
|
||||||
|
virtual void particles_set_explosiveness_ratio(RID p_particles,float p_ratio);
|
||||||
|
virtual void particles_set_randomness_ratio(RID p_particles,float p_ratio);
|
||||||
|
virtual void particles_set_custom_aabb(RID p_particles,const AABB& p_aabb);
|
||||||
|
virtual void particles_set_gravity(RID p_particles,const Vector3& p_gravity);
|
||||||
|
virtual void particles_set_use_local_coordinates(RID p_particles,bool p_enable);
|
||||||
|
virtual void particles_set_process_material(RID p_particles,RID p_material);
|
||||||
|
|
||||||
|
virtual void particles_set_emission_shape(RID p_particles,VS::ParticlesEmissionShape p_shape);
|
||||||
|
virtual void particles_set_emission_sphere_radius(RID p_particles,float p_radius);
|
||||||
|
virtual void particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents);
|
||||||
|
virtual void particles_set_emission_points(RID p_particles,const DVector<Vector3>& p_points);
|
||||||
|
|
||||||
|
|
||||||
|
virtual void particles_set_draw_order(RID p_particles,VS::ParticlesDrawOrder p_order);
|
||||||
|
|
||||||
|
virtual void particles_set_draw_passes(RID p_particles,int p_count);
|
||||||
|
virtual void particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material);
|
||||||
|
virtual void particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh);
|
||||||
|
|
||||||
|
virtual AABB particles_get_current_aabb(RID p_particles);
|
||||||
|
|
||||||
|
/* INSTANCE */
|
||||||
|
|
||||||
virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
|
virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
|
||||||
virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
|
virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
|
||||||
|
|
|
@ -17,5 +17,6 @@ if env['BUILDERS'].has_key('GLES3_GLSL'):
|
||||||
env.GLES3_GLSL('ssao_blur.glsl');
|
env.GLES3_GLSL('ssao_blur.glsl');
|
||||||
env.GLES3_GLSL('exposure.glsl');
|
env.GLES3_GLSL('exposure.glsl');
|
||||||
env.GLES3_GLSL('tonemap.glsl');
|
env.GLES3_GLSL('tonemap.glsl');
|
||||||
|
env.GLES3_GLSL('particles.glsl');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
[vertex]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
layout(location=0) in highp vec4 pos_lifetime;
|
||||||
|
layout(location=1) in highp vec4 color;
|
||||||
|
layout(location=2) in highp vec4 velocity_seed;
|
||||||
|
layout(location=3) in highp vec4 rot_active;
|
||||||
|
|
||||||
|
|
||||||
|
struct Attractor {
|
||||||
|
|
||||||
|
vec3 pos;
|
||||||
|
vec3 dir;
|
||||||
|
float radius;
|
||||||
|
float eat_radius;
|
||||||
|
float strength;
|
||||||
|
float attenuation;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_ATTRACTORS 64
|
||||||
|
|
||||||
|
uniform mat4 origin;
|
||||||
|
uniform float system_phase;
|
||||||
|
uniform float prev_system_phase;
|
||||||
|
uniform float total_particles;
|
||||||
|
uniform float explosiveness;
|
||||||
|
uniform vec4 time;
|
||||||
|
uniform float delta;
|
||||||
|
uniform vec3 gravity;
|
||||||
|
uniform int attractor_count;
|
||||||
|
uniform Attractor attractors[MAX_ATTRACTORS];
|
||||||
|
|
||||||
|
|
||||||
|
out highp vec4 out_pos_lifetime; //tfb:
|
||||||
|
out highp vec4 out_color; //tfb:
|
||||||
|
out highp vec4 out_velocity_seed; //tfb:
|
||||||
|
out highp vec4 out_rot_active; //tfb:
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
bool apply_forces=true;
|
||||||
|
bool apply_velocity=true;
|
||||||
|
|
||||||
|
float mass = 1.0;
|
||||||
|
|
||||||
|
float restart_phase = float(gl_InstanceID)/total_particles;
|
||||||
|
restart_phase*= explosiveness;
|
||||||
|
bool restart=false;
|
||||||
|
|
||||||
|
if (system_phase > prev_system_phase) {
|
||||||
|
restart = prev_system_phase < restart_phase && system_phase >= restart_phase;
|
||||||
|
} else {
|
||||||
|
restart = prev_system_phase < restart_phase || system_phase >= restart_phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restart) {
|
||||||
|
out_rot_active.a=1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_pos_lifetime=pos_lifetime;
|
||||||
|
out_color=color;
|
||||||
|
out_velocity_seed=velocity_seed;
|
||||||
|
out_rot_active=rot_active;
|
||||||
|
|
||||||
|
if (out_rot_active.a) {
|
||||||
|
//execute shader
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (apply_forces) {
|
||||||
|
|
||||||
|
vec3 force = gravity;
|
||||||
|
for(int i=0;i<attractor_count;i++) {
|
||||||
|
|
||||||
|
vec3 rel_vec = out_pos_lifetime.xyz - attractors[i].pos;
|
||||||
|
float dist = rel_vec.length();
|
||||||
|
if (attractors[i].radius < dist)
|
||||||
|
continue;
|
||||||
|
if (attractors[i].eat_radius>0 && attractors[i].eat_radius > dist) {
|
||||||
|
rot_active.a=0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rel_vec = normalize(rel_vec);
|
||||||
|
|
||||||
|
float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation);
|
||||||
|
|
||||||
|
if (attractors[i].dir==vec3(0.0)) {
|
||||||
|
//towards center
|
||||||
|
force+=attractors[i].strength * rel_vec * attenuation * mass;
|
||||||
|
} else {
|
||||||
|
force+=attractors[i].strength * attractors[i].dir * attenuation *mass;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out_velocity_seed.xyz += force * delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apply_velocity) {
|
||||||
|
|
||||||
|
out_pos_lifetime.xyz += out_velocity_seed.xyz * delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[fragment]
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -899,8 +899,10 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s
|
||||||
float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z));
|
float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z));
|
||||||
blend=1.0;
|
blend=1.0;
|
||||||
|
|
||||||
|
float max_distance = length(bounds);
|
||||||
|
|
||||||
//radiance
|
//radiance
|
||||||
#ifdef VCT_QUALITY_HIGH
|
#ifndef VCT_QUALITY_HIGH
|
||||||
|
|
||||||
#define MAX_CONE_DIRS 6
|
#define MAX_CONE_DIRS 6
|
||||||
vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
|
vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
|
||||||
|
@ -914,6 +916,7 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s
|
||||||
|
|
||||||
float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
|
float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
|
||||||
float cone_angle_tan = 0.577;
|
float cone_angle_tan = 0.577;
|
||||||
|
float min_ref_tan = 0.0;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define MAX_CONE_DIRS 4
|
#define MAX_CONE_DIRS 4
|
||||||
|
@ -927,9 +930,10 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s
|
||||||
|
|
||||||
float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
|
float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
|
||||||
float cone_angle_tan = 0.98269;
|
float cone_angle_tan = 0.98269;
|
||||||
|
max_distance*=0.5;
|
||||||
|
float min_ref_tan = 0.2;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
float max_distance = length(bounds);
|
|
||||||
vec3 light=vec3(0.0);
|
vec3 light=vec3(0.0);
|
||||||
for(int i=0;i<MAX_CONE_DIRS;i++) {
|
for(int i=0;i<MAX_CONE_DIRS;i++) {
|
||||||
|
|
||||||
|
@ -944,7 +948,7 @@ void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_s
|
||||||
|
|
||||||
//irradiance
|
//irradiance
|
||||||
|
|
||||||
vec3 irr_light = voxel_cone_trace(probe,cell_size,probe_pos,environment,blend_ambient,ref_vec,tan(roughness * 0.5 * M_PI) ,max_distance);
|
vec3 irr_light = voxel_cone_trace(probe,cell_size,probe_pos,environment,blend_ambient,ref_vec,max(min_ref_tan,tan(roughness * 0.5 * M_PI)) ,max_distance);
|
||||||
|
|
||||||
irr_light *= multiplier;
|
irr_light *= multiplier;
|
||||||
//irr_light=vec3(0.0);
|
//irr_light=vec3(0.0);
|
||||||
|
|
|
@ -117,7 +117,6 @@ private:
|
||||||
float randomness[PARAM_MAX];
|
float randomness[PARAM_MAX];
|
||||||
|
|
||||||
struct Particle {
|
struct Particle {
|
||||||
|
|
||||||
bool active;
|
bool active;
|
||||||
Point2 pos;
|
Point2 pos;
|
||||||
Vector2 velocity;
|
Vector2 velocity;
|
||||||
|
|
|
@ -620,8 +620,10 @@ void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const V
|
||||||
if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) {
|
if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) {
|
||||||
//sub cell must be created
|
//sub cell must be created
|
||||||
|
|
||||||
p_baker->bake_cells[p_idx].childs[i]=p_baker->bake_cells.size();
|
uint32_t child_idx = p_baker->bake_cells.size();
|
||||||
|
p_baker->bake_cells[p_idx].childs[i]=child_idx;
|
||||||
p_baker->bake_cells.resize( p_baker->bake_cells.size() + 1);
|
p_baker->bake_cells.resize( p_baker->bake_cells.size() + 1);
|
||||||
|
p_baker->bake_cells[child_idx].level=p_level+1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,7 +1126,12 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){
|
||||||
w32[ofs++]=norm;
|
w32[ofs++]=norm;
|
||||||
}
|
}
|
||||||
|
|
||||||
w32[ofs++]=uint32_t(baker.bake_cells[i].alpha*65535.0);
|
{
|
||||||
|
uint16_t alpha = CLAMP(uint32_t(baker.bake_cells[i].alpha*65535.0),0,65535);
|
||||||
|
uint16_t level = baker.bake_cells[i].level;
|
||||||
|
|
||||||
|
w32[ofs++] = (uint32_t(level)<<16)|uint32_t(alpha);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ private:
|
||||||
float normal[3];
|
float normal[3];
|
||||||
uint32_t used_sides;
|
uint32_t used_sides;
|
||||||
float alpha; //used for upsampling
|
float alpha; //used for upsampling
|
||||||
|
int level;
|
||||||
|
|
||||||
Cell() {
|
Cell() {
|
||||||
for(int i=0;i<8;i++) {
|
for(int i=0;i<8;i++) {
|
||||||
|
@ -86,6 +87,7 @@ private:
|
||||||
}
|
}
|
||||||
alpha=0;
|
alpha=0;
|
||||||
used_sides=0;
|
used_sides=0;
|
||||||
|
level=0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -432,14 +432,44 @@ public:
|
||||||
|
|
||||||
virtual uint32_t gi_probe_get_version(RID p_probe)=0;
|
virtual uint32_t gi_probe_get_version(RID p_probe)=0;
|
||||||
|
|
||||||
enum GIProbeCompress {
|
enum GIProbeCompression {
|
||||||
GI_PROBE_UNCOMPRESSED,
|
GI_PROBE_UNCOMPRESSED,
|
||||||
GI_PROBE_S3TC,
|
GI_PROBE_S3TC,
|
||||||
GI_PROBE_ETC2
|
GI_PROBE_ETC2
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth)=0;
|
virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const=0;
|
||||||
virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0;
|
virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth,GIProbeCompression p_compression)=0;
|
||||||
|
virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0;
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
virtual RID particles_create()=0;
|
||||||
|
|
||||||
|
virtual void particles_set_emitting(RID p_particles,bool p_emitting)=0;
|
||||||
|
virtual void particles_set_amount(RID p_particles,int p_amount)=0;
|
||||||
|
virtual void particles_set_lifetime(RID p_particles,float p_lifetime)=0;
|
||||||
|
virtual void particles_set_pre_process_time(RID p_particles,float p_time)=0;
|
||||||
|
virtual void particles_set_explosiveness_ratio(RID p_particles,float p_ratio)=0;
|
||||||
|
virtual void particles_set_randomness_ratio(RID p_particles,float p_ratio)=0;
|
||||||
|
virtual void particles_set_custom_aabb(RID p_particles,const AABB& p_aabb)=0;
|
||||||
|
virtual void particles_set_gravity(RID p_particles,const Vector3& p_gravity)=0;
|
||||||
|
virtual void particles_set_use_local_coordinates(RID p_particles,bool p_enable)=0;
|
||||||
|
virtual void particles_set_process_material(RID p_particles,RID p_material)=0;
|
||||||
|
|
||||||
|
virtual void particles_set_emission_shape(RID p_particles,VS::ParticlesEmissionShape p_shape)=0;
|
||||||
|
virtual void particles_set_emission_sphere_radius(RID p_particles,float p_radius)=0;
|
||||||
|
virtual void particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents)=0;
|
||||||
|
virtual void particles_set_emission_points(RID p_particles,const DVector<Vector3>& p_points)=0;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void particles_set_draw_order(RID p_particles,VS::ParticlesDrawOrder p_order)=0;
|
||||||
|
|
||||||
|
virtual void particles_set_draw_passes(RID p_particles,int p_count)=0;
|
||||||
|
virtual void particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material)=0;
|
||||||
|
virtual void particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh)=0;
|
||||||
|
|
||||||
|
virtual AABB particles_get_current_aabb(RID p_particles)=0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -830,6 +830,34 @@ public:
|
||||||
BIND2(gi_probe_set_dynamic_data,RID,const DVector<int>& )
|
BIND2(gi_probe_set_dynamic_data,RID,const DVector<int>& )
|
||||||
BIND1RC( DVector<int>,gi_probe_get_dynamic_data,RID)
|
BIND1RC( DVector<int>,gi_probe_get_dynamic_data,RID)
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
BIND0R(RID, particles_create)
|
||||||
|
|
||||||
|
BIND2(particles_set_emitting,RID,bool)
|
||||||
|
BIND2(particles_set_amount,RID,int )
|
||||||
|
BIND2(particles_set_lifetime,RID,float )
|
||||||
|
BIND2(particles_set_pre_process_time,RID,float )
|
||||||
|
BIND2(particles_set_explosiveness_ratio,RID,float )
|
||||||
|
BIND2(particles_set_randomness_ratio,RID,float )
|
||||||
|
BIND2(particles_set_custom_aabb,RID,const AABB& )
|
||||||
|
BIND2(particles_set_gravity,RID,const Vector3& )
|
||||||
|
BIND2(particles_set_use_local_coordinates,RID,bool )
|
||||||
|
BIND2(particles_set_process_material,RID,RID )
|
||||||
|
|
||||||
|
BIND2(particles_set_emission_shape,RID,VS::ParticlesEmissionShape )
|
||||||
|
BIND2(particles_set_emission_sphere_radius,RID,float )
|
||||||
|
BIND2(particles_set_emission_box_extents,RID,const Vector3& )
|
||||||
|
BIND2(particles_set_emission_points,RID,const DVector<Vector3>& )
|
||||||
|
|
||||||
|
|
||||||
|
BIND2(particles_set_draw_order,RID,VS::ParticlesDrawOrder )
|
||||||
|
|
||||||
|
BIND2(particles_set_draw_passes,RID,int )
|
||||||
|
BIND3(particles_set_draw_pass_material,RID,int , RID )
|
||||||
|
BIND3(particles_set_draw_pass_mesh,RID,int , RID )
|
||||||
|
|
||||||
|
BIND1R(AABB,particles_get_current_aabb,RID);
|
||||||
|
|
||||||
|
|
||||||
#undef BINDBASE
|
#undef BINDBASE
|
||||||
|
|
|
@ -2391,7 +2391,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
|
||||||
probe->dynamic.light_data=VSG::storage->gi_probe_get_dynamic_data(p_instance->base);
|
probe->dynamic.light_data=VSG::storage->gi_probe_get_dynamic_data(p_instance->base);
|
||||||
|
|
||||||
if (probe->dynamic.light_data.size()==0)
|
if (probe->dynamic.light_data.size()==0)
|
||||||
return;
|
return;
|
||||||
//using dynamic data
|
//using dynamic data
|
||||||
DVector<int>::Read r=probe->dynamic.light_data.read();
|
DVector<int>::Read r=probe->dynamic.light_data.read();
|
||||||
|
|
||||||
|
@ -2399,15 +2399,17 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
|
||||||
|
|
||||||
probe->dynamic.local_data.resize(header->cell_count);
|
probe->dynamic.local_data.resize(header->cell_count);
|
||||||
|
|
||||||
|
int cell_count = probe->dynamic.local_data.size();
|
||||||
DVector<InstanceGIProbeData::LocalData>::Write ldw = probe->dynamic.local_data.write();
|
DVector<InstanceGIProbeData::LocalData>::Write ldw = probe->dynamic.local_data.write();
|
||||||
|
|
||||||
const GIProbeDataCell *cells = (GIProbeDataCell*)&r[16];
|
const GIProbeDataCell *cells = (GIProbeDataCell*)&r[16];
|
||||||
|
|
||||||
probe->dynamic.level_cell_lists.resize(header->cell_subdiv);
|
probe->dynamic.level_cell_lists.resize(header->cell_subdiv);
|
||||||
|
|
||||||
_gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr());
|
_gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr());
|
||||||
|
|
||||||
probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth);
|
probe->dynamic.compression = VSG::storage->gi_probe_get_dynamic_data_get_preferred_compression();
|
||||||
|
|
||||||
|
probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth,probe->dynamic.compression);
|
||||||
|
|
||||||
probe->dynamic.bake_dynamic_range=VSG::storage->gi_probe_get_dynamic_range(p_instance->base);
|
probe->dynamic.bake_dynamic_range=VSG::storage->gi_probe_get_dynamic_range(p_instance->base);
|
||||||
|
|
||||||
|
@ -2417,6 +2419,14 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
|
||||||
probe->dynamic.grid_size[1]=header->height;
|
probe->dynamic.grid_size[1]=header->height;
|
||||||
probe->dynamic.grid_size[2]=header->depth;
|
probe->dynamic.grid_size[2]=header->depth;
|
||||||
|
|
||||||
|
int size_limit = 1;
|
||||||
|
int size_divisor = 1;
|
||||||
|
|
||||||
|
if (probe->dynamic.compression==RasterizerStorage::GI_PROBE_S3TC) {
|
||||||
|
print_line("S3TC");
|
||||||
|
size_limit=4;
|
||||||
|
size_divisor=4;
|
||||||
|
}
|
||||||
for(int i=0;i<(int)header->cell_subdiv;i++) {
|
for(int i=0;i<(int)header->cell_subdiv;i++) {
|
||||||
|
|
||||||
uint32_t x = header->width >> i;
|
uint32_t x = header->width >> i;
|
||||||
|
@ -2425,14 +2435,16 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
|
||||||
|
|
||||||
//create and clear mipmap
|
//create and clear mipmap
|
||||||
DVector<uint8_t> mipmap;
|
DVector<uint8_t> mipmap;
|
||||||
mipmap.resize(x*y*z*4);
|
int size = x*y*z*4;
|
||||||
|
size/=size_divisor;
|
||||||
|
mipmap.resize(size);
|
||||||
DVector<uint8_t>::Write w = mipmap.write();
|
DVector<uint8_t>::Write w = mipmap.write();
|
||||||
zeromem(w.ptr(),x*y*z*4);
|
zeromem(w.ptr(),size);
|
||||||
w = DVector<uint8_t>::Write();
|
w = DVector<uint8_t>::Write();
|
||||||
|
|
||||||
probe->dynamic.mipmaps_3d.push_back(mipmap);
|
probe->dynamic.mipmaps_3d.push_back(mipmap);
|
||||||
|
|
||||||
if (x<=1 || y<=1 || z<=1)
|
if (x<=size_limit || y<=size_limit || z<=size_limit)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2449,12 +2461,132 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
|
||||||
VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,probe->dynamic.probe_data);
|
VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,p_instance->base,probe->dynamic.probe_data);
|
||||||
VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform);
|
VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance,bounds.size/cell_size);
|
VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance,bounds.size/cell_size);
|
||||||
|
|
||||||
probe->base_version=VSG::storage->gi_probe_get_version(p_instance->base);
|
probe->base_version=VSG::storage->gi_probe_get_version(p_instance->base);
|
||||||
|
|
||||||
|
//if compression is S3TC, fill it up
|
||||||
|
if (probe->dynamic.compression==RasterizerStorage::GI_PROBE_S3TC) {
|
||||||
|
|
||||||
|
//create all blocks
|
||||||
|
Vector<Map<uint32_t,InstanceGIProbeData::CompBlockS3TC> > comp_blocks;
|
||||||
|
int mipmap_count = probe->dynamic.mipmaps_3d.size();
|
||||||
|
comp_blocks.resize(mipmap_count);
|
||||||
|
|
||||||
|
for(int i=0;i<cell_count;i++) {
|
||||||
|
|
||||||
|
const GIProbeDataCell &c = cells[i];
|
||||||
|
const InstanceGIProbeData::LocalData &ld = ldw[i];
|
||||||
|
int level = c.level_alpha>>16;
|
||||||
|
int mipmap = header->cell_subdiv - level -1;
|
||||||
|
if (mipmap >= mipmap_count)
|
||||||
|
continue;//uninteresting
|
||||||
|
|
||||||
|
|
||||||
|
int blockx = (ld.pos[0]>>2);
|
||||||
|
int blocky = (ld.pos[1]>>2);
|
||||||
|
int blockz = (ld.pos[2]); //compression is x/y only
|
||||||
|
|
||||||
|
int blockw = (header->width >> mipmap) >> 2;
|
||||||
|
int blockh = (header->height >> mipmap) >> 2;
|
||||||
|
|
||||||
|
//print_line("cell "+itos(i)+" level "+itos(level)+"mipmap: "+itos(mipmap)+" pos: "+Vector3(blockx,blocky,blockz)+" size "+Vector2(blockw,blockh));
|
||||||
|
|
||||||
|
uint32_t key = blockz * blockw*blockh + blocky * blockw + blockx;
|
||||||
|
|
||||||
|
Map<uint32_t,InstanceGIProbeData::CompBlockS3TC> & cmap = comp_blocks[mipmap];
|
||||||
|
|
||||||
|
if (!cmap.has(key)) {
|
||||||
|
|
||||||
|
InstanceGIProbeData::CompBlockS3TC k;
|
||||||
|
k.offset=key; //use offset as counter first
|
||||||
|
k.source_count=0;
|
||||||
|
cmap[key]=k;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceGIProbeData::CompBlockS3TC &k=cmap[key];
|
||||||
|
ERR_CONTINUE(k.source_count==16);
|
||||||
|
k.sources[k.source_count++]=i;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fix the blocks, precomputing what is needed
|
||||||
|
probe->dynamic.mipmaps_s3tc.resize(mipmap_count);
|
||||||
|
|
||||||
|
for(int i=0;i<mipmap_count;i++) {
|
||||||
|
print_line("S3TC level: "+itos(i)+" blocks: "+itos(comp_blocks[i].size()));
|
||||||
|
probe->dynamic.mipmaps_s3tc[i].resize(comp_blocks[i].size());
|
||||||
|
DVector<InstanceGIProbeData::CompBlockS3TC>::Write w = probe->dynamic.mipmaps_s3tc[i].write();
|
||||||
|
int block_idx=0;
|
||||||
|
|
||||||
|
for (Map<uint32_t,InstanceGIProbeData::CompBlockS3TC>::Element *E=comp_blocks[i].front();E;E=E->next()) {
|
||||||
|
|
||||||
|
InstanceGIProbeData::CompBlockS3TC k = E->get();
|
||||||
|
|
||||||
|
//PRECOMPUTE ALPHA
|
||||||
|
int max_alpha=-100000;
|
||||||
|
int min_alpha=k.source_count==16 ?100000 :0; //if the block is not completely full, minimum is always 0, (and those blocks will map to 1, which will be zero)
|
||||||
|
|
||||||
|
uint8_t alpha_block[4][4]={ {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0} };
|
||||||
|
|
||||||
|
for(int j=0;j<k.source_count;j++) {
|
||||||
|
|
||||||
|
int alpha = (cells[k.sources[j]].level_alpha>>8)&0xFF;
|
||||||
|
if (alpha<min_alpha)
|
||||||
|
min_alpha=alpha;
|
||||||
|
if (alpha>max_alpha)
|
||||||
|
max_alpha=alpha;
|
||||||
|
//fill up alpha block
|
||||||
|
alpha_block[ldw[k.sources[j]].pos[0]%4][ldw[k.sources[j]].pos[1]%4]=alpha;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//use the first mode (8 adjustable levels)
|
||||||
|
k.alpha[0]=max_alpha;
|
||||||
|
k.alpha[1]=min_alpha;
|
||||||
|
|
||||||
|
uint64_t alpha_bits=0;
|
||||||
|
|
||||||
|
if (max_alpha!=min_alpha) {
|
||||||
|
|
||||||
|
int idx=0;
|
||||||
|
|
||||||
|
for(int y=0;y<4;y++) {
|
||||||
|
for(int x=0;x<4;x++) {
|
||||||
|
|
||||||
|
//substract minimum
|
||||||
|
uint32_t a = uint32_t(alpha_block[x][y])-min_alpha;
|
||||||
|
//convert range to 3 bits
|
||||||
|
a =int((a * 7.0 / (max_alpha-min_alpha))+0.5);
|
||||||
|
a = CLAMP(a,0,7); //just to be sure
|
||||||
|
a = 7-a; //because range is inverted in this mode
|
||||||
|
if (a==0) {
|
||||||
|
//do none, remain
|
||||||
|
} else if (a==7) {
|
||||||
|
a=1;
|
||||||
|
} else {
|
||||||
|
a=a+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
alpha_bits|=uint64_t(a)<<(idx*3);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k.alpha[2]=(alpha_bits >> 0)&0xFF;
|
||||||
|
k.alpha[3]=(alpha_bits >> 8)&0xFF;
|
||||||
|
k.alpha[4]=(alpha_bits >> 16)&0xFF;
|
||||||
|
k.alpha[5]=(alpha_bits >> 24)&0xFF;
|
||||||
|
k.alpha[6]=(alpha_bits >> 32)&0xFF;
|
||||||
|
k.alpha[7]=(alpha_bits >> 40)&0xFF;
|
||||||
|
|
||||||
|
w[block_idx++]=k;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::_gi_probe_bake_thread() {
|
void VisualServerScene::_gi_probe_bake_thread() {
|
||||||
|
@ -2859,43 +2991,190 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) {
|
||||||
|
|
||||||
//plot result to 3D texture!
|
//plot result to 3D texture!
|
||||||
|
|
||||||
for(int i=0;i<(int)header->cell_subdiv;i++) {
|
if (probe_data->dynamic.compression==RasterizerStorage::GI_PROBE_UNCOMPRESSED) {
|
||||||
|
|
||||||
int stage = header->cell_subdiv - i -1;
|
for(int i=0;i<(int)header->cell_subdiv;i++) {
|
||||||
|
|
||||||
if (stage >= probe_data->dynamic.mipmaps_3d.size())
|
int stage = header->cell_subdiv - i -1;
|
||||||
continue; //no mipmap for this one
|
|
||||||
|
|
||||||
print_line("generating mipmap stage: "+itos(stage));
|
if (stage >= probe_data->dynamic.mipmaps_3d.size())
|
||||||
int level_cell_count = probe_data->dynamic.level_cell_lists[ i ].size();
|
continue; //no mipmap for this one
|
||||||
const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[ i ].ptr();
|
|
||||||
|
|
||||||
DVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d[stage].write();
|
print_line("generating mipmap stage: "+itos(stage));
|
||||||
uint8_t *mipmapw = lw.ptr();
|
int level_cell_count = probe_data->dynamic.level_cell_lists[ i ].size();
|
||||||
|
const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[ i ].ptr();
|
||||||
|
|
||||||
uint32_t sizes[3]={header->width>>stage,header->height>>stage,header->depth>>stage};
|
DVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d[stage].write();
|
||||||
|
uint8_t *mipmapw = lw.ptr();
|
||||||
|
|
||||||
for(int j=0;j<level_cell_count;j++) {
|
uint32_t sizes[3]={header->width>>stage,header->height>>stage,header->depth>>stage};
|
||||||
|
|
||||||
uint32_t idx = level_cells[j];
|
for(int j=0;j<level_cell_count;j++) {
|
||||||
|
|
||||||
uint32_t r = (uint32_t(local_data[idx].energy[0])/probe_data->dynamic.bake_dynamic_range)>>2;
|
uint32_t idx = level_cells[j];
|
||||||
uint32_t g = (uint32_t(local_data[idx].energy[1])/probe_data->dynamic.bake_dynamic_range)>>2;
|
|
||||||
uint32_t b = (uint32_t(local_data[idx].energy[2])/probe_data->dynamic.bake_dynamic_range)>>2;
|
|
||||||
uint32_t a = cells[idx].alpha>>8;
|
|
||||||
|
|
||||||
uint32_t mm_ofs = sizes[0]*sizes[1]*(local_data[idx].pos[2]) + sizes[0]*(local_data[idx].pos[1]) + (local_data[idx].pos[0]);
|
uint32_t r = (uint32_t(local_data[idx].energy[0])/probe_data->dynamic.bake_dynamic_range)>>2;
|
||||||
mm_ofs*=4; //for RGBA (4 bytes)
|
uint32_t g = (uint32_t(local_data[idx].energy[1])/probe_data->dynamic.bake_dynamic_range)>>2;
|
||||||
|
uint32_t b = (uint32_t(local_data[idx].energy[2])/probe_data->dynamic.bake_dynamic_range)>>2;
|
||||||
|
uint32_t a = (cells[idx].level_alpha>>8)&0xFF;
|
||||||
|
|
||||||
mipmapw[mm_ofs+0]=uint8_t(CLAMP(r,0,255));
|
uint32_t mm_ofs = sizes[0]*sizes[1]*(local_data[idx].pos[2]) + sizes[0]*(local_data[idx].pos[1]) + (local_data[idx].pos[0]);
|
||||||
mipmapw[mm_ofs+1]=uint8_t(CLAMP(g,0,255));
|
mm_ofs*=4; //for RGBA (4 bytes)
|
||||||
mipmapw[mm_ofs+2]=uint8_t(CLAMP(b,0,255));
|
|
||||||
mipmapw[mm_ofs+3]=uint8_t(CLAMP(a,0,255));
|
mipmapw[mm_ofs+0]=uint8_t(CLAMP(r,0,255));
|
||||||
|
mipmapw[mm_ofs+1]=uint8_t(CLAMP(g,0,255));
|
||||||
|
mipmapw[mm_ofs+2]=uint8_t(CLAMP(b,0,255));
|
||||||
|
mipmapw[mm_ofs+3]=uint8_t(CLAMP(a,0,255));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (probe_data->dynamic.compression==RasterizerStorage::GI_PROBE_S3TC) {
|
||||||
|
|
||||||
|
|
||||||
|
int mipmap_count = probe_data->dynamic.mipmaps_3d.size();
|
||||||
|
|
||||||
|
for(int mmi=0;mmi<mipmap_count;mmi++) {
|
||||||
|
|
||||||
|
DVector<uint8_t>::Write mmw = probe_data->dynamic.mipmaps_3d[mmi].write();
|
||||||
|
int block_count = probe_data->dynamic.mipmaps_s3tc[mmi].size();
|
||||||
|
DVector<InstanceGIProbeData::CompBlockS3TC>::Read mmr = probe_data->dynamic.mipmaps_s3tc[mmi].read();
|
||||||
|
|
||||||
|
for(int i=0;i<block_count;i++) {
|
||||||
|
|
||||||
|
const InstanceGIProbeData::CompBlockS3TC& b = mmr[i];
|
||||||
|
|
||||||
|
uint8_t *blockptr = &mmw[b.offset*16];
|
||||||
|
copymem(blockptr,b.alpha,8); //copy alpha part, which is precomputed
|
||||||
|
|
||||||
|
Vector3 colors[16];
|
||||||
|
|
||||||
|
for(int j=0;j<b.source_count;j++) {
|
||||||
|
|
||||||
|
colors[j].x=(local_data[b.sources[j]].energy[0]/float(probe_data->dynamic.bake_dynamic_range))/1024.0;
|
||||||
|
colors[j].y=(local_data[b.sources[j]].energy[1]/float(probe_data->dynamic.bake_dynamic_range))/1024.0;
|
||||||
|
colors[j].z=(local_data[b.sources[j]].energy[2]/float(probe_data->dynamic.bake_dynamic_range))/1024.0;
|
||||||
|
}
|
||||||
|
//super quick and dirty compression
|
||||||
|
//find 2 most futher apart
|
||||||
|
float distance=0;
|
||||||
|
Vector3 from,to;
|
||||||
|
|
||||||
|
if (b.source_count==16) {
|
||||||
|
//all cells are used so, find minmax between them
|
||||||
|
int further_apart[2]={0,0};
|
||||||
|
for(int j=0;j<b.source_count;j++) {
|
||||||
|
for(int k=j+1;k<b.source_count;k++) {
|
||||||
|
float d = colors[j].distance_squared_to(colors[k]);
|
||||||
|
if (d>distance) {
|
||||||
|
distance=d;
|
||||||
|
further_apart[0]=j;
|
||||||
|
further_apart[1]=k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from = colors[further_apart[0]];
|
||||||
|
to = colors[further_apart[1]];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//if a block is missing, the priority is that this block remains black,
|
||||||
|
//otherwise the geometry will appear deformed
|
||||||
|
//correct shape wins over correct color in this case
|
||||||
|
//average all colors first
|
||||||
|
Vector3 average;
|
||||||
|
|
||||||
|
for(int j=0;j<b.source_count;j++) {
|
||||||
|
average+=colors[j];
|
||||||
|
}
|
||||||
|
average.normalize();
|
||||||
|
//find max distance in normal from average
|
||||||
|
for(int j=0;j<b.source_count;j++) {
|
||||||
|
float d = average.dot(colors[j]);
|
||||||
|
distance=MAX(d,distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
from = Vector3(); //from black
|
||||||
|
to = average * distance;
|
||||||
|
//find max distance
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int indices[16];
|
||||||
|
uint16_t color_0=0;
|
||||||
|
color_0 = CLAMP(int(from.x*31),0,31)<<11;
|
||||||
|
color_0 |= CLAMP(int(from.y*63),0,63)<<5;
|
||||||
|
color_0 |= CLAMP(int(from.z*31),0,31);
|
||||||
|
|
||||||
|
uint16_t color_1=0;
|
||||||
|
color_1 = CLAMP(int(to.x*31),0,31)<<11;
|
||||||
|
color_1 |= CLAMP(int(to.y*63),0,63)<<5;
|
||||||
|
color_1 |= CLAMP(int(to.z*31),0,31);
|
||||||
|
|
||||||
|
//if (color_1 > color_0) {
|
||||||
|
SWAP(color_1,color_0);
|
||||||
|
SWAP(from,to);
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
if (distance>0) {
|
||||||
|
|
||||||
|
Vector3 dir = (to-from).normalized();
|
||||||
|
|
||||||
|
|
||||||
|
for(int j=0;j<b.source_count;j++) {
|
||||||
|
|
||||||
|
float d = (colors[j]-from).dot(dir) / distance;
|
||||||
|
indices[j]=int(d*3+0.5);
|
||||||
|
|
||||||
|
static const int index_swap[4]={0,3,1,2};
|
||||||
|
|
||||||
|
indices[j]=index_swap[CLAMP(indices[j],0,3)];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int j=0;j<b.source_count;j++) {
|
||||||
|
indices[j]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//by default, 1 is black, otherwise it will be overriden by source
|
||||||
|
|
||||||
|
uint32_t index_block[16]={1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1 };
|
||||||
|
|
||||||
|
for(int j=0;j<b.source_count;j++) {
|
||||||
|
|
||||||
|
int x=local_data[b.sources[j]].pos[0]%4;
|
||||||
|
int y=local_data[b.sources[j]].pos[1]%4;
|
||||||
|
|
||||||
|
index_block[y*4+x]=indices[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t encode=0;
|
||||||
|
|
||||||
|
for(int j=0;j<16;j++) {
|
||||||
|
encode|=index_block[j]<<(j*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
blockptr[8]=color_0&0xFF;
|
||||||
|
blockptr[9]=(color_0>>8)&0xFF;
|
||||||
|
blockptr[10]=color_1&0xFF;
|
||||||
|
blockptr[11]=(color_1>>8)&0xFF;
|
||||||
|
blockptr[12]=encode&0xFF;
|
||||||
|
blockptr[13]=(encode>>8)&0xFF;
|
||||||
|
blockptr[14]=(encode>>16)&0xFF;
|
||||||
|
blockptr[15]=(encode>>24)&0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//send back to main thread to update un little chunks
|
//send back to main thread to update un little chunks
|
||||||
probe_data->dynamic.updating_stage=GI_UPDATE_STAGE_UPLOADING;
|
probe_data->dynamic.updating_stage=GI_UPDATE_STAGE_UPLOADING;
|
||||||
|
|
||||||
|
@ -3055,7 +3334,7 @@ void VisualServerScene::render_probes() {
|
||||||
|
|
||||||
int mmsize = probe->dynamic.mipmaps_3d[i].size();
|
int mmsize = probe->dynamic.mipmaps_3d[i].size();
|
||||||
DVector<uint8_t>::Read r = probe->dynamic.mipmaps_3d[i].read();
|
DVector<uint8_t>::Read r = probe->dynamic.mipmaps_3d[i].read();
|
||||||
VSG::storage->gi_probe_dynamic_data_update_rgba8(probe->dynamic.probe_data,0,probe->dynamic.grid_size[2]>>i,i,r.ptr());
|
VSG::storage->gi_probe_dynamic_data_update(probe->dynamic.probe_data,0,probe->dynamic.grid_size[2]>>i,i,r.ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -422,6 +422,13 @@ public:
|
||||||
uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights
|
uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CompBlockS3TC {
|
||||||
|
uint32_t offset; //offset in mipmap
|
||||||
|
uint32_t source_count; //sources
|
||||||
|
uint32_t sources[16]; //id for each source
|
||||||
|
uint8_t alpha[8]; //alpha block is pre-computed
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Dynamic {
|
struct Dynamic {
|
||||||
|
|
||||||
|
@ -433,8 +440,10 @@ public:
|
||||||
RID probe_data;
|
RID probe_data;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
int bake_dynamic_range;
|
int bake_dynamic_range;
|
||||||
|
RasterizerStorage::GIProbeCompression compression;
|
||||||
|
|
||||||
Vector< DVector<uint8_t> > mipmaps_3d;
|
Vector< DVector<uint8_t> > mipmaps_3d;
|
||||||
|
Vector< DVector<CompBlockS3TC> > mipmaps_s3tc; //for s3tc
|
||||||
|
|
||||||
int updating_stage;
|
int updating_stage;
|
||||||
|
|
||||||
|
@ -538,7 +547,7 @@ public:
|
||||||
uint32_t albedo;
|
uint32_t albedo;
|
||||||
uint32_t emission;
|
uint32_t emission;
|
||||||
uint32_t normal;
|
uint32_t normal;
|
||||||
uint32_t alpha;
|
uint32_t level_alpha;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -472,6 +472,53 @@ public:
|
||||||
virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0;
|
virtual void gi_probe_set_interior(RID p_probe,bool p_enable)=0;
|
||||||
virtual bool gi_probe_is_interior(RID p_probe) const=0;
|
virtual bool gi_probe_is_interior(RID p_probe) const=0;
|
||||||
|
|
||||||
|
/* PARTICLES API */
|
||||||
|
|
||||||
|
virtual RID particles_create()=0;
|
||||||
|
|
||||||
|
virtual void particles_set_emitting(RID p_particles,bool p_emitting)=0;
|
||||||
|
virtual void particles_set_amount(RID p_particles,int p_amount)=0;
|
||||||
|
virtual void particles_set_lifetime(RID p_particles,float p_lifetime)=0;
|
||||||
|
virtual void particles_set_pre_process_time(RID p_particles,float p_time)=0;
|
||||||
|
virtual void particles_set_explosiveness_ratio(RID p_particles,float p_ratio)=0;
|
||||||
|
virtual void particles_set_randomness_ratio(RID p_particles,float p_ratio)=0;
|
||||||
|
virtual void particles_set_custom_aabb(RID p_particles,const AABB& p_aabb)=0;
|
||||||
|
virtual void particles_set_gravity(RID p_particles,const Vector3& p_gravity)=0;
|
||||||
|
virtual void particles_set_use_local_coordinates(RID p_particles,bool p_enable)=0;
|
||||||
|
virtual void particles_set_process_material(RID p_particles,RID p_material)=0;
|
||||||
|
|
||||||
|
enum ParticlesEmissionShape {
|
||||||
|
PARTICLES_EMSSION_POINT,
|
||||||
|
PARTICLES_EMSSION_SPHERE,
|
||||||
|
PARTICLES_EMSSION_BOX,
|
||||||
|
PARTICLES_EMSSION_POINTS,
|
||||||
|
PARTICLES_EMSSION_SEGMENTS,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void particles_set_emission_shape(RID p_particles,ParticlesEmissionShape)=0;
|
||||||
|
virtual void particles_set_emission_sphere_radius(RID p_particles,float p_radius)=0;
|
||||||
|
virtual void particles_set_emission_box_extents(RID p_particles,const Vector3& p_extents)=0;
|
||||||
|
virtual void particles_set_emission_points(RID p_particles,const DVector<Vector3>& p_points)=0;
|
||||||
|
|
||||||
|
enum ParticlesDrawOrder {
|
||||||
|
PARTICLES_DRAW_ORDER_INDEX,
|
||||||
|
PARTICLES_DRAW_ORDER_LIFETIME,
|
||||||
|
PARTICLES_DRAW_ORDER_VIEW_DEPTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void particles_set_draw_order(RID p_particles,ParticlesDrawOrder p_order)=0;
|
||||||
|
|
||||||
|
enum ParticlesDrawPassMode {
|
||||||
|
PARTICLES_DRAW_PASS_MODE_QUAD,
|
||||||
|
PARTICLES_DRAW_PASS_MODE_MESH
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
virtual void particles_set_draw_passes(RID p_particles,int p_count)=0;
|
||||||
|
virtual void particles_set_draw_pass_material(RID p_particles,int p_pass, RID p_material)=0;
|
||||||
|
virtual void particles_set_draw_pass_mesh(RID p_particles,int p_pass, RID p_mesh)=0;
|
||||||
|
|
||||||
|
virtual AABB particles_get_current_aabb(RID p_particles)=0;
|
||||||
|
|
||||||
/* CAMERA API */
|
/* CAMERA API */
|
||||||
|
|
||||||
|
@ -483,7 +530,15 @@ public:
|
||||||
virtual void camera_set_environment(RID p_camera,RID p_env)=0;
|
virtual void camera_set_environment(RID p_camera,RID p_env)=0;
|
||||||
virtual void camera_set_use_vertical_aspect(RID p_camera,bool p_enable)=0;
|
virtual void camera_set_use_vertical_aspect(RID p_camera,bool p_enable)=0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
enum ParticlesCollisionMode {
|
||||||
|
PARTICLES_COLLISION_NONE,
|
||||||
|
PARTICLES_COLLISION_TEXTURE,
|
||||||
|
PARTICLES_COLLISION_CUBEMAP,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void particles_set_collision(RID p_particles,ParticlesCollisionMode p_mode,const Transform&, p_xform,const RID p_depth_tex,const RID p_normal_tex)=0;
|
||||||
|
*/
|
||||||
/* VIEWPORT TARGET API */
|
/* VIEWPORT TARGET API */
|
||||||
|
|
||||||
virtual RID viewport_create()=0;
|
virtual RID viewport_create()=0;
|
||||||
|
@ -622,6 +677,7 @@ public:
|
||||||
INSTANCE_MESH,
|
INSTANCE_MESH,
|
||||||
INSTANCE_MULTIMESH,
|
INSTANCE_MULTIMESH,
|
||||||
INSTANCE_IMMEDIATE,
|
INSTANCE_IMMEDIATE,
|
||||||
|
INSTANCE_PARTICLES,
|
||||||
INSTANCE_LIGHT,
|
INSTANCE_LIGHT,
|
||||||
INSTANCE_REFLECTION_PROBE,
|
INSTANCE_REFLECTION_PROBE,
|
||||||
INSTANCE_ROOM,
|
INSTANCE_ROOM,
|
||||||
|
|
Loading…
Reference in New Issue