summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/baked_light_instance.cpp1724
-rw-r--r--scene/3d/baked_light_instance.h123
-rw-r--r--scene/3d/camera.cpp107
-rw-r--r--scene/3d/camera.h6
-rw-r--r--scene/3d/gi_probe.cpp1403
-rw-r--r--scene/3d/gi_probe.h190
-rw-r--r--scene/3d/light.cpp646
-rw-r--r--scene/3d/light.h161
-rw-r--r--scene/3d/navigation_mesh.cpp2
-rw-r--r--scene/3d/particles.cpp12
-rw-r--r--scene/3d/particles.h3
-rw-r--r--scene/3d/portal.cpp44
-rw-r--r--scene/3d/portal.h2
-rw-r--r--scene/3d/position_3d.cpp31
-rw-r--r--scene/3d/position_3d.h1
-rw-r--r--scene/3d/quad.cpp2
-rw-r--r--scene/3d/reflection_probe.cpp266
-rw-r--r--scene/3d/reflection_probe.h92
-rw-r--r--scene/3d/room_instance.cpp77
-rw-r--r--scene/3d/room_instance.h5
-rw-r--r--scene/3d/skeleton.cpp47
-rw-r--r--scene/3d/skeleton.h1
-rw-r--r--scene/3d/spatial_player.cpp140
-rw-r--r--scene/3d/spatial_player.h2
-rw-r--r--scene/3d/visual_instance.cpp147
-rw-r--r--scene/3d/visual_instance.h32
26 files changed, 4141 insertions, 1125 deletions
diff --git a/scene/3d/baked_light_instance.cpp b/scene/3d/baked_light_instance.cpp
index ed1984db26..051256deb4 100644
--- a/scene/3d/baked_light_instance.cpp
+++ b/scene/3d/baked_light_instance.cpp
@@ -28,82 +28,1737 @@
/*************************************************************************/
#include "baked_light_instance.h"
#include "scene/scene_string_names.h"
+#include "mesh_instance.h"
+#include "light.h"
+#include "math.h"
+#define FINDMINMAX(x0,x1,x2,min,max) \
+ min = max = x0; \
+ if(x1<min) min=x1;\
+ if(x1>max) max=x1;\
+ if(x2<min) min=x2;\
+ if(x2>max) max=x2;
-RID BakedLightInstance::get_baked_light_instance() const {
+static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox)
+{
+ int q;
+ Vector3 vmin,vmax;
+ for(q=0;q<=2;q++)
+ {
+ if(normal[q]>0.0f)
+ {
+ vmin[q]=-maxbox[q];
+ vmax[q]=maxbox[q];
+ }
+ else
+ {
+ vmin[q]=maxbox[q];
+ vmax[q]=-maxbox[q];
+ }
+ }
+ if(normal.dot(vmin)+d>0.0f) return false;
+ if(normal.dot(vmax)+d>=0.0f) return true;
- if (baked_light.is_null())
- return RID();
- else
- return get_instance();
+ return false;
+}
+
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p2 = a*v2.y - b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_X2(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p1 = a*v1.y - b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p2 = -a*v2.x + b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Y1(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p1 = -a*v1.x + b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb) \
+ p1 = a*v1.x - b*v1.y; \
+ p2 = a*v2.x - b*v2.y; \
+ if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Z0(a, b, fa, fb) \
+ p0 = a*v0.x - b*v0.y; \
+ p1 = a*v1.x - b*v1.y; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) {
+
+ /* use separating axis theorem to test overlap between triangle and box */
+ /* need to test for overlap in these directions: */
+ /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+ /* we do not even need to test these) */
+ /* 2) normal of the triangle */
+ /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
+ /* this gives 3x3=9 more tests */
+ Vector3 v0,v1,v2;
+ float min,max,d,p0,p1,p2,rad,fex,fey,fez;
+ Vector3 normal,e0,e1,e2;
+
+ /* This is the fastest branch on Sun */
+ /* move everything so that the boxcenter is in (0,0,0) */
+
+ v0=triverts[0]-boxcenter;
+ v1=triverts[1]-boxcenter;
+ v2=triverts[2]-boxcenter;
+
+ /* compute triangle edges */
+ e0=v1-v0; /* tri edge 0 */
+ e1=v2-v1; /* tri edge 1 */
+ e2=v0-v2; /* tri edge 2 */
+
+ /* Bullet 3: */
+ /* test the 9 tests first (this was faster) */
+ fex = Math::abs(e0.x);
+ fey = Math::abs(e0.y);
+ fez = Math::abs(e0.z);
+ AXISTEST_X01(e0.z, e0.y, fez, fey);
+ AXISTEST_Y02(e0.z, e0.x, fez, fex);
+ AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+ fex = Math::abs(e1.x);
+ fey = Math::abs(e1.y);
+ fez = Math::abs(e1.z);
+ AXISTEST_X01(e1.z, e1.y, fez, fey);
+ AXISTEST_Y02(e1.z, e1.x, fez, fex);
+ AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+ fex = Math::abs(e2.x);
+ fey = Math::abs(e2.y);
+ fez = Math::abs(e2.z);
+ AXISTEST_X2(e2.z, e2.y, fez, fey);
+ AXISTEST_Y1(e2.z, e2.x, fez, fex);
+ AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+ /* Bullet 1: */
+ /* first test overlap in the {x,y,z}-directions */
+ /* find min, max of the triangle each direction, and test for overlap in */
+ /* that direction -- this is equivalent to testing a minimal AABB around */
+ /* the triangle against the AABB */
+
+ /* test in X-direction */
+ FINDMINMAX(v0.x,v1.x,v2.x,min,max);
+ if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
+
+ /* test in Y-direction */
+ FINDMINMAX(v0.y,v1.y,v2.y,min,max);
+ if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
+
+ /* test in Z-direction */
+ FINDMINMAX(v0.z,v1.z,v2.z,min,max);
+ if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
+
+ /* Bullet 2: */
+ /* test if the box intersects the plane of the triangle */
+ /* compute plane equation of triangle: normal*x+d=0 */
+ normal=e0.cross(e1);
+ d=-normal.dot(v0); /* plane eq: normal.x+d=0 */
+ if(!planeBoxOverlap(normal,d,boxhalfsize)) return false;
+
+ return true; /* box and triangle overlaps */
+}
+
+
+Vector<Color> BakedLight::_get_bake_texture(Image &p_image,const Color& p_color) {
+
+ Vector<Color> ret;
+
+ if (p_image.empty()) {
+
+ ret.resize(bake_texture_size*bake_texture_size);
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ ret[i]=p_color;
+ }
+
+ return ret;
+ }
+
+ p_image.convert(Image::FORMAT_RGBA8);
+ p_image.resize(bake_texture_size,bake_texture_size,Image::INTERPOLATE_CUBIC);
+
+
+ DVector<uint8_t>::Read r = p_image.get_data().read();
+ ret.resize(bake_texture_size*bake_texture_size);
+
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ Color c;
+ c.r = r[i*4+0]/255.0;
+ c.g = r[i*4+1]/255.0;
+ c.b = r[i*4+2]/255.0;
+ c.a = r[i*4+3]/255.0;
+ ret[i]=c;
+
+ }
+
+ return ret;
+}
+
+
+BakedLight::MaterialCache BakedLight::_get_material_cache(Ref<Material> p_material) {
+
+ //this way of obtaining materials is inaccurate and also does not support some compressed formats very well
+ Ref<FixedSpatialMaterial> mat = p_material;
+
+ Ref<Material> material = mat; //hack for now
+
+ if (material_cache.has(material)) {
+ return material_cache[material];
+ }
+
+ MaterialCache mc;
+
+ if (mat.is_valid()) {
+
+
+ Ref<ImageTexture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+
+ Image img_albedo;
+ if (albedo_tex.is_valid()) {
+
+ img_albedo = albedo_tex->get_data();
+ }
+
+ mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo());
+
+ Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+
+ Color emission_col = mat->get_emission();
+ emission_col.r*=mat->get_emission_energy();
+ emission_col.g*=mat->get_emission_energy();
+ emission_col.b*=mat->get_emission_energy();
+
+ Image img_emission;
+
+ if (emission_tex.is_valid()) {
+
+ img_emission = emission_tex->get_data();
+ }
+
+ mc.emission=_get_bake_texture(img_emission,emission_col);
+
+ } else {
+ Image empty;
+
+ mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7));
+ mc.emission=_get_bake_texture(empty,Color(0,0,0));
+
+
+ }
+
+ material_cache[p_material]=mc;
+ return mc;
+
+
+}
+
+
+
+static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) {
+
+ if (p_pos.distance_squared_to(p_vtx[0])<CMP_EPSILON2)
+ return p_uv[0];
+ if (p_pos.distance_squared_to(p_vtx[1])<CMP_EPSILON2)
+ return p_uv[1];
+ if (p_pos.distance_squared_to(p_vtx[2])<CMP_EPSILON2)
+ return p_uv[2];
+
+ Vector3 v0 = p_vtx[1] - p_vtx[0];
+ Vector3 v1 = p_vtx[2] - p_vtx[0];
+ Vector3 v2 = p_pos - p_vtx[0];
+
+ float d00 = v0.dot( v0);
+ float d01 = v0.dot( v1);
+ float d11 = v1.dot( v1);
+ float d20 = v2.dot( v0);
+ float d21 = v2.dot( v1);
+ float denom = (d00 * d11 - d01 * d01);
+ if (denom==0)
+ return p_uv[0];
+ float v = (d11 * d20 - d01 * d21) / denom;
+ float w = (d00 * d21 - d01 * d20) / denom;
+ float u = 1.0f - v - w;
+
+ return p_uv[0]*u + p_uv[1]*v + p_uv[2]*w;
+}
+
+void BakedLight::_plot_face(int p_idx, int p_level, const Vector3 *p_vtx, const Vector2* p_uv, const MaterialCache& p_material, const AABB &p_aabb) {
+
+
+
+ if (p_level==cell_subdiv-1) {
+ //plot the face by guessing it's albedo and emission value
+
+ //find best axis to map to, for scanning values
+ int closest_axis;
+ float closest_dot;
+
+ Vector3 normal = Plane(p_vtx[0],p_vtx[1],p_vtx[2]).normal;
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 axis;
+ axis[i]=1.0;
+ float dot=ABS(normal.dot(axis));
+ if (i==0 || dot>closest_dot) {
+ closest_axis=i;
+ closest_dot=dot;
+ }
+ }
+
+ Vector3 axis;
+ axis[closest_axis]=1.0;
+ Vector3 t1;
+ t1[(closest_axis+1)%3]=1.0;
+ Vector3 t2;
+ t2[(closest_axis+2)%3]=1.0;
+
+ t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width);
+ t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width);
+
+ Color albedo_accum;
+ Color emission_accum;
+ float alpha=0.0;
+
+ //map to a grid average in the best axis for this face
+ for(int i=0;i<color_scan_cell_width;i++) {
+
+ Vector3 ofs_i=float(i)*t1;
+
+ for(int j=0;j<color_scan_cell_width;j++) {
+
+ Vector3 ofs_j=float(j)*t2;
+
+ Vector3 from = p_aabb.pos+ofs_i+ofs_j;
+ Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
+ Vector3 half = (to-from)*0.5;
+
+ //is in this cell?
+ if (!fast_tri_box_overlap(from+half,half,p_vtx)) {
+ continue; //face does not span this cell
+ }
+
+ //go from -size to +size*2 to avoid skipping collisions
+ Vector3 ray_from = from + (t1+t2)*0.5 - axis * p_aabb.size[closest_axis];
+ Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis]*2;
+
+ Vector3 intersection;
+
+ if (!Geometry::ray_intersects_triangle(ray_from,ray_to,p_vtx[0],p_vtx[1],p_vtx[2],&intersection)) {
+ //no intersect? look in edges
+
+ float closest_dist=1e20;
+ for(int j=0;j<3;j++) {
+ Vector3 c;
+ Vector3 inters;
+ Geometry::get_closest_points_between_segments(p_vtx[j],p_vtx[(j+1)%3],ray_from,ray_to,inters,c);
+ float d=c.distance_to(intersection);
+ if (j==0 || d<closest_dist) {
+ closest_dist=d;
+ intersection=inters;
+ }
+ }
+ }
+
+ Vector2 uv = get_uv(intersection,p_vtx,p_uv);
+
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+ albedo_accum.r+=p_material.albedo[ofs].r;
+ albedo_accum.g+=p_material.albedo[ofs].g;
+ albedo_accum.b+=p_material.albedo[ofs].b;
+ albedo_accum.a+=p_material.albedo[ofs].a;
+
+ emission_accum.r+=p_material.emission[ofs].r;
+ emission_accum.g+=p_material.emission[ofs].g;
+ emission_accum.b+=p_material.emission[ofs].b;
+ alpha+=1.0;
+
+ }
+ }
+
+
+ if (alpha==0) {
+ //could not in any way get texture information.. so use closest point to center
+
+ Face3 f( p_vtx[0],p_vtx[1],p_vtx[2]);
+ Vector3 inters = f.get_closest_point_to(p_aabb.pos+p_aabb.size*0.5);
+
+ Vector2 uv = get_uv(inters,p_vtx,p_uv);
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+
+ alpha = 1.0/(color_scan_cell_width*color_scan_cell_width);
+
+ albedo_accum.r=p_material.albedo[ofs].r*alpha;
+ albedo_accum.g=p_material.albedo[ofs].g*alpha;
+ albedo_accum.b=p_material.albedo[ofs].b*alpha;
+ albedo_accum.a=p_material.albedo[ofs].a*alpha;
+
+ emission_accum.r=p_material.emission[ofs].r*alpha;
+ emission_accum.g=p_material.emission[ofs].g*alpha;
+ emission_accum.b=p_material.emission[ofs].b*alpha;
+
+
+ zero_alphas++;
+ } else {
+
+ float accdiv = 1.0/(color_scan_cell_width*color_scan_cell_width);
+ alpha*=accdiv;
+
+ albedo_accum.r*=accdiv;
+ albedo_accum.g*=accdiv;
+ albedo_accum.b*=accdiv;
+ albedo_accum.a*=accdiv;
+
+ emission_accum.r*=accdiv;
+ emission_accum.g*=accdiv;
+ emission_accum.b*=accdiv;
+ }
+
+ //put this temporarily here, corrected in a later step
+ bake_cells_write[p_idx].albedo[0]+=albedo_accum.r;
+ bake_cells_write[p_idx].albedo[1]+=albedo_accum.g;
+ bake_cells_write[p_idx].albedo[2]+=albedo_accum.b;
+ bake_cells_write[p_idx].light[0]+=emission_accum.r;
+ bake_cells_write[p_idx].light[1]+=emission_accum.g;
+ bake_cells_write[p_idx].light[2]+=emission_accum.b;
+ bake_cells_write[p_idx].alpha+=alpha;
+
+ static const Vector3 side_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),
+ };
+
+ for(int i=0;i<6;i++) {
+ if (normal.dot(side_normals[i])>CMP_EPSILON) {
+ bake_cells_write[p_idx].used_sides|=(1<<i);
+ }
+ }
+
+
+ } else {
+ //go down
+ for(int i=0;i<8;i++) {
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ if (i&1)
+ aabb.pos.x+=aabb.size.x;
+ if (i&2)
+ aabb.pos.y+=aabb.size.y;
+ if (i&4)
+ aabb.pos.z+=aabb.size.z;
+
+ {
+ AABB test_aabb=aabb;
+ //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
+ Vector3 qsize = test_aabb.size*0.5; //quarter size, for fast aabb test
+
+ if (!fast_tri_box_overlap(test_aabb.pos+qsize,qsize,p_vtx)) {
+ //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
+ //does not fit in child, go on
+ continue;
+ }
+
+ }
+
+ if (bake_cells_write[p_idx].childs[i]==CHILD_EMPTY) {
+ //sub cell must be created
+
+ if (bake_cells_used==(1<<bake_cells_alloc)) {
+ //exhausted cells, creating more space
+ bake_cells_alloc++;
+ bake_cells_write=DVector<BakeCell>::Write();
+ bake_cells.resize(1<<bake_cells_alloc);
+ bake_cells_write=bake_cells.write();
+ }
+
+ bake_cells_write[p_idx].childs[i]=bake_cells_used;
+ bake_cells_level_used[p_level+1]++;
+ bake_cells_used++;
+
+
+ }
+
+
+ _plot_face(bake_cells_write[p_idx].childs[i],p_level+1,p_vtx,p_uv,p_material,aabb);
+ }
+ }
+}
+
+
+
+void BakedLight::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z) {
+
+
+
+ if (p_level==cell_subdiv-1) {
+
+
+ float alpha = bake_cells_write[p_idx].alpha;
+
+ bake_cells_write[p_idx].albedo[0]/=alpha;
+ bake_cells_write[p_idx].albedo[1]/=alpha;
+ bake_cells_write[p_idx].albedo[2]/=alpha;
+
+ //transfer emission to light
+ bake_cells_write[p_idx].light[0]/=alpha;
+ bake_cells_write[p_idx].light[1]/=alpha;
+ bake_cells_write[p_idx].light[2]/=alpha;
+
+ bake_cells_write[p_idx].alpha=1.0;
+
+ //remove neighbours from used sides
+
+ for(int n=0;n<6;n++) {
+
+ int ofs[3]={0,0,0};
+
+ ofs[n/2]=(n&1)?1:-1;
+
+ //convert to x,y,z on this level
+ int x=p_x;
+ int y=p_y;
+ int z=p_z;
+
+ x+=ofs[0];
+ y+=ofs[1];
+ z+=ofs[2];
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = 1<<p_level;
+ int half=size/2;
+
+
+ if (x<0 || x>=size || y<0 || y>=size || z<0 || z>=size) {
+ //neighbour is out, can't use it
+ bake_cells_write[p_idx].used_sides&=~(1<<uint32_t(n));
+ continue;
+ }
+
+ uint32_t neighbour=0;
+
+ for(int i=0;i<cell_subdiv-1;i++) {
+
+ BakeCell *bc = &bake_cells_write[neighbour];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ neighbour = bc->childs[child];
+ if (neighbour==CHILD_EMPTY) {
+ break;
+ }
+
+ half>>=1;
+ }
+
+ if (neighbour!=CHILD_EMPTY) {
+ bake_cells_write[p_idx].used_sides&=~(1<<uint32_t(n));
+ }
+ }
+ } else {
+
+
+ //go down
+
+ float alpha_average=0;
+ int half = cells_per_axis >> (p_level+1);
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+ _fixup_plot(child,p_level+1,nx,ny,nz);
+ alpha_average+=bake_cells_write[child].alpha;
+ }
+
+ bake_cells_write[p_idx].alpha=alpha_average/8.0;
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+ bake_cells_write[p_idx].albedo[0]=0;
+ bake_cells_write[p_idx].albedo[1]=0;
+ bake_cells_write[p_idx].albedo[2]=0;
+
+ }
+
+ //clean up light
+ bake_cells_write[p_idx].light_pass=0;
+ //find neighbours
+
+
+
+}
+
+
+void BakedLight::_bake_add_mesh(const Transform& p_xform,Ref<Mesh>& p_mesh) {
+
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue; //only triangles
+
+ MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i));
+
+ Array a = p_mesh->surface_get_arrays(i);
+
+
+ DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ DVector<Vector3>::Read vr=vertices.read();
+ DVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
+ DVector<Vector2>::Read uvr;
+ DVector<int> index = a[Mesh::ARRAY_INDEX];
+
+ bool read_uv=false;
+
+ if (uv.size()) {
+
+ uvr=uv.read();
+ read_uv=true;
+ }
+
+ if (index.size()) {
+
+ int facecount = index.size()/3;
+ DVector<int>::Read ir=index.read();
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[ir[j*3+k]]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[ir[j*3+k]];
+ }
+ }
+
+ //plot face
+ _plot_face(0,0,vtxs,uvs,material,bounds);
+ }
+
+
+
+ } else {
+
+ int facecount = vertices.size()/3;
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[j*3+k]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[j*3+k];
+ }
+ }
+
+ //plot face
+ _plot_face(0,0,vtxs,uvs,material,bounds);
+ }
+
+ }
+ }
+}
+
+
+
+void BakedLight::_bake_add_to_aabb(const Transform& p_xform,Ref<Mesh>& p_mesh,bool &first) {
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue; //only triangles
+
+ Array a = p_mesh->surface_get_arrays(i);
+ DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ int vc = vertices.size();
+ DVector<Vector3>::Read vr=vertices.read();
+
+ if (first) {
+ bounds.pos=p_xform.xform(vr[0]);
+ first=false;
+ }
+
+
+ for(int j=0;j<vc;j++) {
+ bounds.expand_to(p_xform.xform(vr[j]));
+ }
+ }
+}
+
+void BakedLight::bake() {
+
+
+ bake_cells_alloc=16;
+ bake_cells.resize(1<<bake_cells_alloc);
+ bake_cells_used=1;
+ cells_per_axis=(1<<(cell_subdiv-1));
+ zero_alphas=0;
+
+ bool aabb_first=true;
+ print_line("Generating AABB");
+
+ bake_cells_level_used.resize(cell_subdiv);
+ for(int i=0;i<cell_subdiv;i++) {
+ bake_cells_level_used[i]=0;
+ }
+
+ int count=0;
+ for (Set<GeometryInstance*>::Element *E=geometries.front();E;E=E->next()) {
+
+ print_line("aabb geom "+itos(count)+"/"+itos(geometries.size()));
+
+ GeometryInstance *geom = E->get();
+
+ if (geom->cast_to<MeshInstance>()) {
+
+ MeshInstance *mesh_instance = geom->cast_to<MeshInstance>();
+ Ref<Mesh> mesh = mesh_instance->get_mesh();
+ if (mesh.is_valid()) {
+
+ _bake_add_to_aabb(geom->get_relative_transform(this),mesh,aabb_first);
+ }
+ }
+ count++;
+ }
+
+ print_line("AABB: "+bounds);
+ ERR_FAIL_COND(aabb_first);
+
+ bake_cells_write = bake_cells.write();
+ count=0;
+
+ for (Set<GeometryInstance*>::Element *E=geometries.front();E;E=E->next()) {
+
+ GeometryInstance *geom = E->get();
+ print_line("plot geom "+itos(count)+"/"+itos(geometries.size()));
+
+ if (geom->cast_to<MeshInstance>()) {
+
+ MeshInstance *mesh_instance = geom->cast_to<MeshInstance>();
+ Ref<Mesh> mesh = mesh_instance->get_mesh();
+ if (mesh.is_valid()) {
+
+ _bake_add_mesh(geom->get_relative_transform(this),mesh);
+ }
+ }
+
+ count++;
+ }
+
+
+ _fixup_plot(0, 0,0,0,0);
+
+
+ bake_cells_write=DVector<BakeCell>::Write();
+
+ bake_cells.resize(bake_cells_used);
+
+
+
+ print_line("total bake cells used: "+itos(bake_cells_used));
+ for(int i=0;i<cell_subdiv;i++) {
+ print_line("level "+itos(i)+": "+itos(bake_cells_level_used[i]));
+ }
+ print_line("zero alphas: "+itos(zero_alphas));
+
+
+
+}
+
+
+
+void BakedLight::_bake_directional(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3& p_dir,const Color& p_color,int p_sign) {
+
+
+
+
+ if (p_level==cell_subdiv-1) {
+
+ Vector3 end;
+ end.x = float(p_x+0.5) / cells_per_axis;
+ end.y = float(p_y+0.5) / cells_per_axis;
+ end.z = float(p_z+0.5) / cells_per_axis;
+
+ end = bounds.pos + bounds.size*end;
+
+ float max_ray_len = (bounds.size).length()*1.2;
+ Vector3 begin = end + max_ray_len*-p_dir;
+
+ //clip begin
+
+ for(int i=0;i<3;i++) {
+
+ if (ABS(p_dir[i])<CMP_EPSILON) {
+ continue; // parallel to axis, don't clip
+ }
+
+ Plane p;
+ p.normal[i]=1.0;
+ p.d=bounds.pos[i];
+ if (p_dir[i]<0) {
+ p.d+=bounds.size[i];
+ }
+
+ Vector3 inters;
+ if (p.intersects_segment(end,begin,&inters)) {
+ begin=inters;
+ }
+
+ }
+
+
+ int idx = _plot_ray(begin,end);
+
+ if (idx>=0 && light_pass!=bake_cells_write[idx].light_pass) {
+ //hit something, add or remove light to it
+
+ Color albedo = Color(bake_cells_write[idx].albedo[0],bake_cells_write[idx].albedo[1],bake_cells_write[idx].albedo[2]);
+ bake_cells_write[idx].light[0]+=albedo.r*p_color.r*p_sign;
+ bake_cells_write[idx].light[1]+=albedo.g*p_color.g*p_sign;
+ bake_cells_write[idx].light[2]+=albedo.b*p_color.b*p_sign;
+ bake_cells_write[idx].light_pass=light_pass;
+
+ }
+
+
+ } else {
+
+ int half = cells_per_axis >> (p_level+1);
+
+ //go down
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+
+ _bake_directional(child,p_level+1,nx,ny,nz,p_dir,p_color,p_sign);
+ }
+ }
+}
+
+
+
+
+void BakedLight::_bake_light(Light* p_light) {
+
+ if (p_light->cast_to<DirectionalLight>()) {
+
+ DirectionalLight * dl = p_light->cast_to<DirectionalLight>();
+
+ Transform rel_xf = dl->get_relative_transform(this);
+
+ Vector3 light_dir = -rel_xf.basis.get_axis(2);
+
+ Color color = dl->get_color();
+ float nrg = dl->get_param(Light::PARAM_ENERGY);;
+ color.r*=nrg;
+ color.g*=nrg;
+ color.b*=nrg;
+
+ light_pass++;
+ _bake_directional(0,0,0,0,0,light_dir,color,1);
+
+ }
+}
+
+
+void BakedLight::_upscale_light(int p_idx,int p_level) {
+
+
+ //go down
+
+ float light_accum[3]={0,0,0};
+ float alpha_accum=0;
+
+ bool check_children = p_level < (cell_subdiv -2);
+
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+ if (check_children) {
+ _upscale_light(child,p_level+1);
+ }
+
+ light_accum[0]+=bake_cells_write[child].light[0];
+ light_accum[1]+=bake_cells_write[child].light[1];
+ light_accum[2]+=bake_cells_write[child].light[2];
+ alpha_accum+=bake_cells_write[child].alpha;
+
+ }
+
+ bake_cells_write[p_idx].light[0]=light_accum[0]/8.0;
+ bake_cells_write[p_idx].light[1]=light_accum[1]/8.0;
+ bake_cells_write[p_idx].light[2]=light_accum[2]/8.0;
+ bake_cells_write[p_idx].alpha=alpha_accum/8.0;
+
+}
+
+
+void BakedLight::bake_lights() {
+
+ ERR_FAIL_COND(bake_cells.size()==0);
+
+ bake_cells_write = bake_cells.write();
+
+ for(Set<Light*>::Element *E=lights.front();E;E=E->next()) {
+
+ _bake_light(E->get());
+ }
+
+
+ _upscale_light(0,0);
+
+ bake_cells_write=DVector<BakeCell>::Write();
+
+}
+
+
+
+Color BakedLight::_cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle) {
+
+
+ Color color(0,0,0,0);
+ float tha = Math::tan(p_half_angle);//tan half angle
+ Vector3 from =(p_from-bounds.pos)/bounds.size; //convert to 0..1
+ from/=cells_per_axis; //convert to voxels of size 1
+ Vector3 dir = (p_dir/bounds.size).normalized();
+
+ float max_dist = Vector3(cells_per_axis,cells_per_axis,cells_per_axis).length();
+
+ float dist = 1.0;
+ // self occlusion in flat surfaces
+
+ float alpha=0;
+
+
+ while(dist < max_dist && alpha < 0.95) {
+
+#if 0
+ // smallest sample diameter possible is the voxel size
+ float diameter = MAX(1.0, 2.0 * tha * dist);
+ float lod = log2(diameter);
+
+ Vector3 sample_pos = from + dist * dir;
+
+
+ Color samples_base[2][8]={{Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)},
+ {Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)}};
+
+ float levelf = Math::fposmod(lod,1.0);
+ float fx = Math::fposmod(sample_pos.x,1.0);
+ float fy = Math::fposmod(sample_pos.y,1.0);
+ float fz = Math::fposmod(sample_pos.z,1.0);
+
+ for(int l=0;l<2;l++){
+
+ int bx = Math::floor(sample_pos.x);
+ int by = Math::floor(sample_pos.y);
+ int bz = Math::floor(sample_pos.z);
+
+ int lodn=int(Math::floor(lod))-l;
+
+ bx>>=lodn;
+ by>>=lodn;
+ bz>>=lodn;
+
+ int limit = MAX(0,cell_subdiv-lodn-1);
+
+ for(int c=0;c<8;c++) {
+
+ int x = bx;
+ int y = by;
+ int z = bz;
+
+ if (c&1) {
+ x+=1;
+ }
+ if (c&2) {
+ y+=1;
+ }
+ if (c&4) {
+ z+=1;
+ }
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = cells_per_axis>>lodn;
+ int half=size/2;
+
+ bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size;
+
+ if (outside)
+ continue;
+
+
+ uint32_t cell=0;
+
+ for(int i=0;i<limit;i++) {
+
+ BakeCell *bc = &bake_cells_write[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ cell = bc->childs[child];
+ if (cell==CHILD_EMPTY)
+ break;
+
+ half>>=1;
+ }
+
+ if (cell!=CHILD_EMPTY) {
+
+ samples_base[l][c].r=bake_cells_write[cell].light[0];
+ samples_base[l][c].g=bake_cells_write[cell].light[1];
+ samples_base[l][c].b=bake_cells_write[cell].light[2];
+ samples_base[l][c].a=bake_cells_write[cell].alpha;
+ }
+
+ }
+
+
+ }
+
+ Color m0x0 = samples_base[0][0].linear_interpolate(samples_base[0][1],fx);
+ Color m0x1 = samples_base[0][2].linear_interpolate(samples_base[0][3],fx);
+ Color m0y0 = m0x0.linear_interpolate(m0x1,fy);
+ m0x0 = samples_base[0][4].linear_interpolate(samples_base[0][5],fx);
+ m0x1 = samples_base[0][6].linear_interpolate(samples_base[0][7],fx);
+ Color m0y1 = m0x0.linear_interpolate(m0x1,fy);
+ Color m0z = m0y0.linear_interpolate(m0y1,fz);
+
+ Color m1x0 = samples_base[1][0].linear_interpolate(samples_base[1][1],fx);
+ Color m1x1 = samples_base[1][2].linear_interpolate(samples_base[1][3],fx);
+ Color m1y0 = m1x0.linear_interpolate(m1x1,fy);
+ m1x0 = samples_base[1][4].linear_interpolate(samples_base[1][5],fx);
+ m1x1 = samples_base[1][6].linear_interpolate(samples_base[1][7],fx);
+ Color m1y1 = m1x0.linear_interpolate(m1x1,fy);
+ Color m1z = m1y0.linear_interpolate(m1y1,fz);
+
+ Color m = m0z.linear_interpolate(m1z,levelf);
+#else
+ float diameter = 1.0;
+ Vector3 sample_pos = from + dist * dir;
+
+ Color m(0,0,0,0);
+ {
+ int x = Math::floor(sample_pos.x);
+ int y = Math::floor(sample_pos.y);
+ int z = Math::floor(sample_pos.z);
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = cells_per_axis;
+ int half=size/2;
+
+ bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size;
+
+ if (!outside) {
+
+
+ uint32_t cell=0;
+
+ for(int i=0;i<cell_subdiv-1;i++) {
+
+ BakeCell *bc = &bake_cells_write[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ cell = bc->childs[child];
+ if (cell==CHILD_EMPTY)
+ break;
+
+ half>>=1;
+ }
+
+ if (cell!=CHILD_EMPTY) {
+
+ m.r=bake_cells_write[cell].light[0];
+ m.g=bake_cells_write[cell].light[1];
+ m.b=bake_cells_write[cell].light[2];
+ m.a=bake_cells_write[cell].alpha;
+ }
+ }
+ }
+
+#endif
+ // front-to-back compositing
+ float a = (1.0 - alpha);
+ color.r += a * m.r;
+ color.g += a * m.g;
+ color.b += a * m.b;
+ alpha += a * m.a;
+ //occlusion += a * voxelColor.a;
+ //occlusion += (a * voxelColor.a) / (1.0 + 0.03 * diameter);
+ dist += diameter * 0.5; // smoother
+ //dist += diameter; // faster but misses more voxels
+ }
+
+ return color;
+}
+
+
+
+void BakedLight::_bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z) {
+
+
+
+
+ if (p_level==cell_subdiv-1) {
+
+ const int NUM_CONES = 6;
+ Vector3 cone_directions[6] = {
+ Vector3(1, 0, 0),
+ Vector3(0.5, 0.866025, 0),
+ Vector3( 0.5, 0.267617, 0.823639),
+ Vector3( 0.5, -0.700629, 0.509037),
+ Vector3( 0.5, -0.700629, -0.509037),
+ Vector3( 0.5, 0.267617, -0.823639)
+ };
+ float coneWeights[6] = {0.25, 0.15, 0.15, 0.15, 0.15, 0.15};
+
+ Vector3 pos = (Vector3(p_x,p_y,p_z)/float(cells_per_axis))*bounds.size+bounds.pos;
+ Vector3 voxel_size = bounds.size/float(cells_per_axis);
+ pos+=voxel_size*0.5;
+
+ Color accum;
+
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+
+ int freepix=0;
+ for(int i=0;i<6;i++) {
+
+ if (!(bake_cells_write[p_idx].used_sides&(1<<i)))
+ continue;
+
+ if ((i&1)==0)
+ bake_cells_write[p_idx].light[i/2]=1.0;
+ freepix++;
+ continue;
+
+ int ofs = i/2;
+
+ Vector3 dir;
+ if ((i&1)==0)
+ dir[ofs]=1.0;
+ else
+ dir[ofs]=-1.0;
+
+ for(int j=0;j<1;j++) {
+
+
+ Vector3 cone_dir;
+ cone_dir.x = cone_directions[j][(ofs+0)%3];
+ cone_dir.y = cone_directions[j][(ofs+1)%3];
+ cone_dir.z = cone_directions[j][(ofs+2)%3];
+
+ cone_dir[ofs]*=dir[ofs];
+
+ Color res = _cone_trace(pos+dir*voxel_size,cone_dir,Math::deg2rad(29.9849));
+ accum.r+=res.r;//*coneWeights[j];
+ accum.g+=res.g;//*coneWeights[j];
+ accum.b+=res.b;//*coneWeights[j];
+ }
+
+
+ }
+#if 0
+ if (freepix==0) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+ }
+
+ if (freepix==1) {
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+ }
+
+ if (freepix==2) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=1;
+ bake_cells_write[p_idx].light[2]=0;
+ }
+
+ if (freepix==3) {
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[1]=1;
+ bake_cells_write[p_idx].light[2]=0;
+ }
+
+ if (freepix==4) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=1;
+ }
+
+ if (freepix==5) {
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=1;
+ }
+
+ if (freepix==6) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[0]=1;
+ }
+#endif
+ //bake_cells_write[p_idx].radiance[0]=accum.r;
+ //bake_cells_write[p_idx].radiance[1]=accum.g;
+ //bake_cells_write[p_idx].radiance[2]=accum.b;
+
+
+ } else {
+
+ int half = cells_per_axis >> (p_level+1);
+
+ //go down
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+
+ _bake_radiance(child,p_level+1,nx,ny,nz);
+ }
+ }
}
-void BakedLightInstance::set_baked_light(const Ref<BakedLight>& p_baked_light) {
+void BakedLight::bake_radiance() {
+
+ ERR_FAIL_COND(bake_cells.size()==0);
- baked_light=p_baked_light;
+ bake_cells_write = bake_cells.write();
+
+ _bake_radiance(0,0,0,0,0);
+
+ bake_cells_write=DVector<BakeCell>::Write();
+
+}
+int BakedLight::_find_cell(int x,int y, int z) {
- RID base_rid;
- if (baked_light.is_valid())
- base_rid=baked_light->get_rid();
- else
- base_rid=RID();
+ uint32_t cell=0;
- set_base(base_rid);
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = cells_per_axis;
+ int half=size/2;
- if (is_inside_world()) {
+ if (x<0 || x>=size)
+ return -1;
+ if (y<0 || y>=size)
+ return -1;
+ if (z<0 || z>=size)
+ return -1;
- emit_signal(SceneStringNames::get_singleton()->baked_light_changed);
+ for(int i=0;i<cell_subdiv-1;i++) {
-// for (List<Node*>::Element *E=baked_geometry.front();E;E=E->next()) {
-// VS::get_singleton()->instance_geometry_set_baked_light(E->get()->get_instance(),baked_light.is_valid()?get_instance():RID());
-// }
+ BakeCell *bc = &bake_cells_write[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ cell = bc->childs[child];
+ if (cell==CHILD_EMPTY)
+ return -1;
+
+ half>>=1;
}
- update_configuration_warning();
+ return cell;
+
}
-Ref<BakedLight> BakedLightInstance::get_baked_light() const{
- return baked_light;
+int BakedLight::_plot_ray(const Vector3& p_from, const Vector3& p_to) {
+
+ Vector3 from = (p_from - bounds.pos) / bounds.size;
+ Vector3 to = (p_to - bounds.pos) / bounds.size;
+
+ int x1 = Math::floor(from.x*cells_per_axis);
+ int y1 = Math::floor(from.y*cells_per_axis);
+ int z1 = Math::floor(from.z*cells_per_axis);
+
+ int x2 = Math::floor(to.x*cells_per_axis);
+ int y2 = Math::floor(to.y*cells_per_axis);
+ int z2 = Math::floor(to.z*cells_per_axis);
+
+
+ int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+ int point[3];
+
+ point[0] = x1;
+ point[1] = y1;
+ point[2] = z1;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = z2 - z1;
+ x_inc = (dx < 0) ? -1 : 1;
+ l = ABS(dx);
+ y_inc = (dy < 0) ? -1 : 1;
+ m = ABS(dy);
+ z_inc = (dz < 0) ? -1 : 1;
+ n = ABS(dz);
+ dx2 = l << 1;
+ dy2 = m << 1;
+ dz2 = n << 1;
+
+ if ((l >= m) && (l >= n)) {
+ err_1 = dy2 - l;
+ err_2 = dz2 - l;
+ for (i = 0; i < l; i++) {
+ int cell = _find_cell(point[0],point[1],point[2]);
+ if (cell>=0)
+ return cell;
+
+ if (err_1 > 0) {
+ point[1] += y_inc;
+ err_1 -= dx2;
+ }
+ if (err_2 > 0) {
+ point[2] += z_inc;
+ err_2 -= dx2;
+ }
+ err_1 += dy2;
+ err_2 += dz2;
+ point[0] += x_inc;
+ }
+ } else if ((m >= l) && (m >= n)) {
+ err_1 = dx2 - m;
+ err_2 = dz2 - m;
+ for (i = 0; i < m; i++) {
+ int cell = _find_cell(point[0],point[1],point[2]);
+ if (cell>=0)
+ return cell;
+ if (err_1 > 0) {
+ point[0] += x_inc;
+ err_1 -= dy2;
+ }
+ if (err_2 > 0) {
+ point[2] += z_inc;
+ err_2 -= dy2;
+ }
+ err_1 += dx2;
+ err_2 += dz2;
+ point[1] += y_inc;
+ }
+ } else {
+ err_1 = dy2 - n;
+ err_2 = dx2 - n;
+ for (i = 0; i < n; i++) {
+ int cell = _find_cell(point[0],point[1],point[2]);
+ if (cell>=0)
+ return cell;
+
+ if (err_1 > 0) {
+ point[1] += y_inc;
+ err_1 -= dz2;
+ }
+ if (err_2 > 0) {
+ point[0] += x_inc;
+ err_2 -= dz2;
+ }
+ err_1 += dy2;
+ err_2 += dx2;
+ point[2] += z_inc;
+ }
+ }
+ return _find_cell(point[0],point[1],point[2]);
+
}
-AABB BakedLightInstance::get_aabb() const {
+
+void BakedLight::set_cell_subdiv(int p_subdiv) {
+
+ cell_subdiv=p_subdiv;
+
+// VS::get_singleton()->baked_light_set_subdivision(baked_light,p_subdiv);
+}
+
+int BakedLight::get_cell_subdiv() const {
+
+ return cell_subdiv;
+}
+
+
+
+AABB BakedLight::get_aabb() const {
return AABB(Vector3(0,0,0),Vector3(1,1,1));
}
-DVector<Face3> BakedLightInstance::get_faces(uint32_t p_usage_flags) const {
+DVector<Face3> BakedLight::get_faces(uint32_t p_usage_flags) const {
return DVector<Face3>();
}
-String BakedLightInstance::get_configuration_warning() const {
- if (get_baked_light().is_null()) {
- return TTR("BakedLightInstance does not contain a BakedLight resource.");
- }
+String BakedLight::get_configuration_warning() const {
return String();
}
-void BakedLightInstance::_bind_methods() {
+void BakedLight::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref<MultiMesh> &p_multimesh,int &idx) {
+
+
+ if (p_level==cell_subdiv-1) {
+
+ Vector3 center = p_aabb.pos+p_aabb.size*0.5;
+ Transform xform;
+ xform.origin=center;
+ xform.basis.scale(p_aabb.size*0.5);
+ p_multimesh->set_instance_transform(idx,xform);
+ Color col;
+ switch(p_mode) {
+ case DEBUG_ALBEDO: {
+ col=Color(bake_cells_write[p_idx].albedo[0],bake_cells_write[p_idx].albedo[1],bake_cells_write[p_idx].albedo[2]);
+ } break;
+ case DEBUG_LIGHT: {
+ col=Color(bake_cells_write[p_idx].light[0],bake_cells_write[p_idx].light[1],bake_cells_write[p_idx].light[2]);
+ Color colr=Color(bake_cells_write[p_idx].radiance[0],bake_cells_write[p_idx].radiance[1],bake_cells_write[p_idx].radiance[2]);
+ col.r+=colr.r;
+ col.g+=colr.g;
+ col.b+=colr.b;
+ } break;
+
+ }
+ p_multimesh->set_instance_color(idx,col);
+
+
+ idx++;
+
+ } else {
- ObjectTypeDB::bind_method(_MD("set_baked_light","baked_light"),&BakedLightInstance::set_baked_light);
- ObjectTypeDB::bind_method(_MD("get_baked_light"),&BakedLightInstance::get_baked_light);
- ObjectTypeDB::bind_method(_MD("get_baked_light_instance"),&BakedLightInstance::get_baked_light_instance);
+ for(int i=0;i<8;i++) {
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"baked_light",PROPERTY_HINT_RESOURCE_TYPE,"BakedLight"),_SCS("set_baked_light"),_SCS("get_baked_light"));
+ if (bake_cells_write[p_idx].childs[i]==CHILD_EMPTY)
+ continue;
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ if (i&1)
+ aabb.pos.x+=aabb.size.x;
+ if (i&2)
+ aabb.pos.y+=aabb.size.y;
+ if (i&4)
+ aabb.pos.z+=aabb.size.z;
+
+ _debug_mesh(bake_cells_write[p_idx].childs[i],p_level+1,aabb,p_mode,p_multimesh,idx);
+ }
+
+ }
+
+}
+
+
+void BakedLight::create_debug_mesh(DebugMode p_mode) {
+
+ Ref<MultiMesh> mm;
+ mm.instance();
+
+ mm->set_transform_format(MultiMesh::TRANSFORM_3D);
+ mm->set_color_format(MultiMesh::COLOR_8BIT);
+ mm->set_instance_count(bake_cells_level_used[cell_subdiv-1]);
+
+ Ref<Mesh> mesh;
+ mesh.instance();
+
+
+
+ {
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+
+ DVector<Vector3> vertices;
+ DVector<Color> colors;
+
+ int vtx_idx=0;
+ #define ADD_VTX(m_idx);\
+ vertices.push_back( face_points[m_idx] );\
+ colors.push_back( Color(1,1,1,1) );\
+ vtx_idx++;\
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ }
+
+ //tri 1
+ ADD_VTX(0);
+ ADD_VTX(1);
+ ADD_VTX(2);
+ //tri 2
+ ADD_VTX(2);
+ ADD_VTX(3);
+ ADD_VTX(0);
+
+ }
+
+
+ arr[Mesh::ARRAY_VERTEX]=vertices;
+ arr[Mesh::ARRAY_COLOR]=colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
+ }
+
+ {
+ Ref<FixedSpatialMaterial> fsm;
+ fsm.instance();
+ fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
+ fsm->set_albedo(Color(1,1,1,1));
+
+ mesh->surface_set_material(0,fsm);
+ }
+
+ mm->set_mesh(mesh);
+
+
+ bake_cells_write = bake_cells.write();
+
+
+
+ int idx=0;
+ _debug_mesh(0,0,bounds,p_mode,mm,idx);
+
+ print_line("written: "+itos(idx)+" total: "+itos(bake_cells_level_used[cell_subdiv-1]));
+
+
+ MultiMeshInstance *mmi = memnew( MultiMeshInstance );
+ mmi->set_multimesh(mm);
+ add_child(mmi);
+ if (get_tree()->get_edited_scene_root()==this){
+ mmi->set_owner(this);
+ } else {
+ mmi->set_owner(get_owner());
+
+ }
+
+}
+
+void BakedLight::_debug_mesh_albedo() {
+ create_debug_mesh(DEBUG_ALBEDO);
+}
+
+void BakedLight::_debug_mesh_light() {
+ create_debug_mesh(DEBUG_LIGHT);
+}
+
+
+void BakedLight::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_cell_subdiv","steps"),&BakedLight::set_cell_subdiv);
+ ObjectTypeDB::bind_method(_MD("get_cell_subdiv"),&BakedLight::get_cell_subdiv);
+
+ ObjectTypeDB::bind_method(_MD("bake"),&BakedLight::bake);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ObjectTypeDB::bind_method(_MD("bake_lights"),&BakedLight::bake_lights);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_lights"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ObjectTypeDB::bind_method(_MD("bake_radiance"),&BakedLight::bake_radiance);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_radiance"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ObjectTypeDB::bind_method(_MD("debug_mesh_albedo"),&BakedLight::_debug_mesh_albedo);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_albedo"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+
+ ObjectTypeDB::bind_method(_MD("debug_mesh_light"),&BakedLight::_debug_mesh_light);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_light"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"cell_subdiv"),_SCS("set_cell_subdiv"),_SCS("get_cell_subdiv"));
ADD_SIGNAL( MethodInfo("baked_light_changed"));
+
}
-BakedLightInstance::BakedLightInstance() {
+BakedLight::BakedLight() {
+// baked_light=VisualServer::get_singleton()->baked_light_create();
+ VS::get_singleton()->instance_set_base(get_instance(),baked_light);
+ cell_subdiv=8;
+ bake_texture_size=128;
+ color_scan_cell_width=8;
+ light_pass=0;
}
-/////////////////////////
+BakedLight::~BakedLight() {
+
+ VS::get_singleton()->free(baked_light);
+}
+
+/////////////////////////
+
+#if 0
void BakedLightSampler::set_param(Param p_param,float p_value) {
ERR_FAIL_INDEX(p_param,PARAM_MAX);
params[p_param]=p_value;
@@ -179,3 +1834,4 @@ BakedLightSampler::~BakedLightSampler(){
VS::get_singleton()->free(base);
}
+#endif
diff --git a/scene/3d/baked_light_instance.h b/scene/3d/baked_light_instance.h
index a31b0b0dab..4913eae908 100644
--- a/scene/3d/baked_light_instance.h
+++ b/scene/3d/baked_light_instance.h
@@ -31,37 +31,142 @@
#include "scene/3d/visual_instance.h"
#include "scene/resources/baked_light.h"
+#include "scene/3d/multimesh_instance.h"
+
class BakedLightBaker;
+class Light;
+
+class BakedLight : public VisualInstance {
+ OBJ_TYPE(BakedLight,VisualInstance);
+
+public:
+ enum DebugMode {
+ DEBUG_ALBEDO,
+ DEBUG_LIGHT
+ };
+
+private:
+ RID baked_light;
+ int cell_subdiv;
+ AABB bounds;
+ int cells_per_axis;
+
+ enum {
+ CHILD_EMPTY=0xFFFFFFFF,
+ };
+
+
+ /* BAKE DATA */
+
+ struct BakeCell {
+
+ uint32_t childs[8];
+ float albedo[3]; //albedo in RGB24
+ float light[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+ float radiance[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+ uint32_t used_sides;
+ float alpha; //used for upsampling
+ uint32_t light_pass; //used for baking light
+
+ BakeCell() {
+ for(int i=0;i<8;i++) {
+ childs[i]=0xFFFFFFFF;
+ }
+
+ for(int i=0;i<3;i++) {
+ light[i]=0;
+ albedo[i]=0;
+ radiance[i]=0;
+ }
+ alpha=0;
+ light_pass=0;
+ used_sides=0;
+ }
+ };
+
+
+ int bake_texture_size;
+ int color_scan_cell_width;
+
+ struct MaterialCache {
+ //128x128 textures
+ Vector<Color> albedo;
+ Vector<Color> emission;
+ };
+
+ Vector<Color> _get_bake_texture(Image &p_image, const Color &p_color);
-class BakedLightInstance : public VisualInstance {
- OBJ_TYPE(BakedLightInstance,VisualInstance);
- Ref<BakedLight> baked_light;
+ Map<Ref<Material>,MaterialCache> material_cache;
+ MaterialCache _get_material_cache(Ref<Material> p_material);
+ int bake_cells_alloc;
+ int bake_cells_used;
+ int zero_alphas;
+ Vector<int> bake_cells_level_used;
+ DVector<BakeCell> bake_cells;
+ DVector<BakeCell>::Write bake_cells_write;
+
+
+
+ void _plot_face(int p_idx,int p_level,const Vector3 *p_vtx,const Vector2* p_uv, const MaterialCache& p_material,const AABB& p_aabb);
+ void _fixup_plot(int p_idx, int p_level, int p_x, int p_y, int p_z);
+ void _bake_add_mesh(const Transform& p_xform,Ref<Mesh>& p_mesh);
+ void _bake_add_to_aabb(const Transform& p_xform,Ref<Mesh>& p_mesh,bool &first);
+
+ void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref<MultiMesh> &p_multimesh,int &idx);
+ void _debug_mesh_albedo();
+ void _debug_mesh_light();
+
+
+ _FORCE_INLINE_ int _find_cell(int x,int y, int z);
+ int _plot_ray(const Vector3& p_from, const Vector3& p_to);
+
+ uint32_t light_pass;
+
+
+ void _bake_directional(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3& p_dir,const Color& p_color,int p_sign);
+ void _upscale_light(int p_idx,int p_level);
+ void _bake_light(Light* p_light);
+
+ Color _cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle);
+ void _bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z);
+
+friend class GeometryInstance;
+
+ Set<GeometryInstance*> geometries;
+friend class Light;
+
+ Set<Light*> lights;
protected:
static void _bind_methods();
public:
+ void set_cell_subdiv(int p_subdiv);
+ int get_cell_subdiv() const;
+
+ void bake();
+ void bake_lights();
+ void bake_radiance();
- RID get_baked_light_instance() const;
- void set_baked_light(const Ref<BakedLight>& baked_light);
- Ref<BakedLight> get_baked_light() const;
+ void create_debug_mesh(DebugMode p_mode);
virtual AABB get_aabb() const;
virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
String get_configuration_warning() const;
- BakedLightInstance();
+ BakedLight();
+ ~BakedLight();
};
-
+#if 0
class BakedLightSampler : public VisualInstance {
OBJ_TYPE(BakedLightSampler,VisualInstance);
@@ -101,5 +206,5 @@ public:
VARIANT_ENUM_CAST( BakedLightSampler::Param );
-
+#endif
#endif // BAKED_LIGHT_H
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 56e16ee309..a9a5ea7371 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -96,8 +96,8 @@ bool Camera::_set(const StringName& p_name, const Variant& p_value) {
} else {
clear_current();
}
- } else if (p_name=="visible_layers") {
- set_visible_layers(p_value);
+ } else if (p_name=="cull_mask") {
+ set_cull_mask(p_value);
} else if (p_name=="environment") {
set_environment(p_value);
} else
@@ -130,8 +130,8 @@ bool Camera::_get(const StringName& p_name,Variant &r_ret) const {
} else {
r_ret=is_current();
}
- } else if (p_name=="visible_layers") {
- r_ret=get_visible_layers();
+ } else if (p_name=="cull_mask") {
+ r_ret=get_cull_mask();
} else if (p_name=="h_offset") {
r_ret=get_h_offset();
} else if (p_name=="v_offset") {
@@ -176,7 +176,7 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const {
p_list->push_back( PropertyInfo( Variant::REAL, "far" , PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01") );
p_list->push_back( PropertyInfo( Variant::INT, "keep_aspect",PROPERTY_HINT_ENUM,"Keep Width,Keep Height") );
p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) );
- p_list->push_back( PropertyInfo( Variant::INT, "visible_layers",PROPERTY_HINT_ALL_FLAGS ) );
+ p_list->push_back( PropertyInfo( Variant::INT, "cull_mask",PROPERTY_HINT_ALL_FLAGS ) );
p_list->push_back( PropertyInfo( Variant::OBJECT, "environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment" ) );
p_list->push_back( PropertyInfo( Variant::REAL, "h_offset" ) );
p_list->push_back( PropertyInfo( Variant::REAL, "v_offset" ) );
@@ -342,91 +342,6 @@ bool Camera::_can_gizmo_scale() const {
}
-RES Camera::_get_gizmo_geometry() const {
-
-
- Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
-
- Ref<FixedMaterial> mat( memnew( FixedMaterial ));
-
- mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(1.0,0.5,1.0,0.5) );
- mat->set_line_width(4);
- mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- mat->set_flag(Material::FLAG_UNSHADED,true);
- //mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-
- surface_tool->begin(Mesh::PRIMITIVE_LINES);
- surface_tool->set_material(mat);
-
- switch(mode) {
-
- case PROJECTION_PERSPECTIVE: {
-
-
-
- Vector3 side=Vector3( Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)) );
- Vector3 nside=side;
- nside.x=-nside.x;
- Vector3 up=Vector3(0,side.x,0);
-
-
-#define ADD_TRIANGLE( m_a, m_b, m_c)\
-{\
- surface_tool->add_vertex(m_a);\
- surface_tool->add_vertex(m_b);\
- surface_tool->add_vertex(m_b);\
- surface_tool->add_vertex(m_c);\
- surface_tool->add_vertex(m_c);\
- surface_tool->add_vertex(m_a);\
-}
-
- ADD_TRIANGLE( Vector3(), side+up, side-up );
- ADD_TRIANGLE( Vector3(), nside+up, nside-up );
- ADD_TRIANGLE( Vector3(), side+up, nside+up );
- ADD_TRIANGLE( Vector3(), side-up, nside-up );
-
- side.x*=0.25;
- nside.x*=0.25;
- Vector3 tup( 0, up.y*3/2,side.z);
- ADD_TRIANGLE( tup, side+up, nside+up );
-
- } break;
- case PROJECTION_ORTHOGONAL: {
-
-#define ADD_QUAD( m_a, m_b, m_c, m_d)\
-{\
- surface_tool->add_vertex(m_a);\
- surface_tool->add_vertex(m_b);\
- surface_tool->add_vertex(m_b);\
- surface_tool->add_vertex(m_c);\
- surface_tool->add_vertex(m_c);\
- surface_tool->add_vertex(m_d);\
- surface_tool->add_vertex(m_d);\
- surface_tool->add_vertex(m_a);\
-}
-
- float hsize=size*0.5;
- Vector3 right(hsize,0,0);
- Vector3 up(0,hsize,0);
- Vector3 back(0,0,-1.0);
- Vector3 front(0,0,0);
-
- ADD_QUAD( -up-right,-up+right,up+right,up-right);
- ADD_QUAD( -up-right+back,-up+right+back,up+right+back,up-right+back);
- ADD_QUAD( up+right,up+right+back,up-right+back,up-right);
- ADD_QUAD( -up+right,-up+right+back,-up-right+back,-up-right);
-
- right.x*=0.25;
- Vector3 tup( 0, up.y*3/2,back.z );
- ADD_TRIANGLE( tup, right+up+back, -right+up+back );
-
- } break;
-
- }
-
- return surface_tool->commit();
-
-}
Vector3 Camera::project_ray_normal(const Point2& p_pos) const {
@@ -652,8 +567,8 @@ void Camera::_bind_methods() {
ObjectTypeDB::bind_method( _MD("get_h_offset"),&Camera::get_h_offset );
ObjectTypeDB::bind_method( _MD("set_v_offset","ofs"),&Camera::set_v_offset );
ObjectTypeDB::bind_method( _MD("get_v_offset"),&Camera::get_v_offset );
- ObjectTypeDB::bind_method( _MD("set_visible_layers","mask"),&Camera::set_visible_layers );
- ObjectTypeDB::bind_method( _MD("get_visible_layers"),&Camera::get_visible_layers );
+ ObjectTypeDB::bind_method( _MD("set_cull_mask","mask"),&Camera::set_cull_mask );
+ ObjectTypeDB::bind_method( _MD("get_cull_mask"),&Camera::get_cull_mask );
ObjectTypeDB::bind_method( _MD("set_environment","env:Environment"),&Camera::set_environment );
ObjectTypeDB::bind_method( _MD("get_environment:Environment"),&Camera::get_environment );
ObjectTypeDB::bind_method( _MD("set_keep_aspect_mode","mode"),&Camera::set_keep_aspect_mode );
@@ -694,13 +609,13 @@ Camera::Projection Camera::get_projection() const {
return mode;
}
-void Camera::set_visible_layers(uint32_t p_layers) {
+void Camera::set_cull_mask(uint32_t p_layers) {
layers=p_layers;
- VisualServer::get_singleton()->camera_set_visible_layers(camera,layers);
+ VisualServer::get_singleton()->camera_set_cull_mask(camera,layers);
}
-uint32_t Camera::get_visible_layers() const{
+uint32_t Camera::get_cull_mask() const{
return layers;
}
@@ -761,7 +676,7 @@ Camera::Camera() {
layers=0xfffff;
v_offset=0;
h_offset=0;
- VisualServer::get_singleton()->camera_set_visible_layers(camera,layers);
+ VisualServer::get_singleton()->camera_set_cull_mask(camera,layers);
//active=false;
}
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 554990997e..409cc29401 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -75,7 +75,7 @@ private:
Ref<Environment> environment;
virtual bool _can_gizmo_scale() const;
- virtual RES _get_gizmo_geometry() const;
+
//void _camera_make_current(Node *p_camera);
@@ -126,8 +126,8 @@ public:
bool is_position_behind(const Vector3& p_pos) const;
Vector3 project_position(const Point2& p_point) const;
- void set_visible_layers(uint32_t p_layers);
- uint32_t get_visible_layers() const;
+ void set_cull_mask(uint32_t p_layers);
+ uint32_t get_cull_mask() const;
Vector<Plane> get_frustum() const;
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
new file mode 100644
index 0000000000..f8d8213b82
--- /dev/null
+++ b/scene/3d/gi_probe.cpp
@@ -0,0 +1,1403 @@
+#include "gi_probe.h"
+#include "mesh_instance.h"
+
+
+void GIProbeData::set_bounds(const AABB& p_bounds) {
+
+ VS::get_singleton()->gi_probe_set_bounds(probe,p_bounds);
+}
+
+AABB GIProbeData::get_bounds() const{
+
+ return VS::get_singleton()->gi_probe_get_bounds(probe);
+}
+
+void GIProbeData::set_cell_size(float p_size) {
+
+ VS::get_singleton()->gi_probe_set_cell_size(probe,p_size);
+
+}
+
+float GIProbeData::get_cell_size() const {
+
+ return VS::get_singleton()->gi_probe_get_cell_size(probe);
+
+}
+
+void GIProbeData::set_to_cell_xform(const Transform& p_xform) {
+
+ VS::get_singleton()->gi_probe_set_to_cell_xform(probe,p_xform);
+
+}
+
+Transform GIProbeData::get_to_cell_xform() const {
+
+ return VS::get_singleton()->gi_probe_get_to_cell_xform(probe);
+
+}
+
+
+void GIProbeData::set_dynamic_data(const DVector<int>& p_data){
+
+ VS::get_singleton()->gi_probe_set_dynamic_data(probe,p_data);
+
+}
+DVector<int> GIProbeData::get_dynamic_data() const{
+
+ return VS::get_singleton()->gi_probe_get_dynamic_data(probe);
+}
+
+void GIProbeData::set_dynamic_range(int p_range){
+
+ VS::get_singleton()->gi_probe_set_dynamic_range(probe,p_range);
+
+}
+
+void GIProbeData::set_energy(float p_range) {
+
+ VS::get_singleton()->gi_probe_set_energy(probe,p_range);
+}
+
+float GIProbeData::get_energy() const{
+
+ return VS::get_singleton()->gi_probe_get_energy(probe);
+
+}
+
+void GIProbeData::set_interior(bool p_enable) {
+
+ VS::get_singleton()->gi_probe_set_interior(probe,p_enable);
+
+}
+
+bool GIProbeData::is_interior() const{
+
+ return VS::get_singleton()->gi_probe_is_interior(probe);
+}
+
+
+bool GIProbeData::is_compressed() const{
+
+ return VS::get_singleton()->gi_probe_is_compressed(probe);
+}
+
+
+void GIProbeData::set_compress(bool p_enable) {
+
+ VS::get_singleton()->gi_probe_set_compress(probe,p_enable);
+
+}
+
+int GIProbeData::get_dynamic_range() const{
+
+
+ return VS::get_singleton()->gi_probe_get_dynamic_range(probe);
+}
+
+
+RID GIProbeData::get_rid() const {
+
+ return probe;
+}
+
+
+void GIProbeData::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_bounds","bounds"),&GIProbeData::set_bounds);
+ ObjectTypeDB::bind_method(_MD("get_bounds"),&GIProbeData::get_bounds);
+
+ ObjectTypeDB::bind_method(_MD("set_cell_size","cell_size"),&GIProbeData::set_cell_size);
+ ObjectTypeDB::bind_method(_MD("get_cell_size"),&GIProbeData::get_cell_size);
+
+ ObjectTypeDB::bind_method(_MD("set_to_cell_xform","to_cell_xform"),&GIProbeData::set_to_cell_xform);
+ ObjectTypeDB::bind_method(_MD("get_to_cell_xform"),&GIProbeData::get_to_cell_xform);
+
+ ObjectTypeDB::bind_method(_MD("set_dynamic_data","dynamic_data"),&GIProbeData::set_dynamic_data);
+ ObjectTypeDB::bind_method(_MD("get_dynamic_data"),&GIProbeData::get_dynamic_data);
+
+ ObjectTypeDB::bind_method(_MD("set_dynamic_range","dynamic_range"),&GIProbeData::set_dynamic_range);
+ ObjectTypeDB::bind_method(_MD("get_dynamic_range"),&GIProbeData::get_dynamic_range);
+
+ ObjectTypeDB::bind_method(_MD("set_energy","energy"),&GIProbeData::set_energy);
+ ObjectTypeDB::bind_method(_MD("get_energy"),&GIProbeData::get_energy);
+
+ ObjectTypeDB::bind_method(_MD("set_interior","interior"),&GIProbeData::set_interior);
+ ObjectTypeDB::bind_method(_MD("is_interior"),&GIProbeData::is_interior);
+
+ ObjectTypeDB::bind_method(_MD("set_compress","compress"),&GIProbeData::set_compress);
+ ObjectTypeDB::bind_method(_MD("is_compressed"),&GIProbeData::is_compressed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::_AABB,"bounds",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_bounds"),_SCS("get_bounds"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"cell_size",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_cell_size"),_SCS("get_cell_size"));
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM,"to_cell_xform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_to_cell_xform"),_SCS("get_to_cell_xform"));
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT_ARRAY,"dynamic_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_dynamic_data"),_SCS("get_dynamic_data"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_dynamic_range"),_SCS("get_dynamic_range"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_energy"),_SCS("get_energy"));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"interior",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_interior"),_SCS("is_interior"));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"compress",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_compress"),_SCS("is_compressed"));
+
+}
+
+GIProbeData::GIProbeData() {
+
+ probe=VS::get_singleton()->gi_probe_create();
+}
+
+GIProbeData::~GIProbeData() {
+
+ VS::get_singleton()->free(probe);
+}
+
+
+//////////////////////
+//////////////////////
+
+
+void GIProbe::set_probe_data(const Ref<GIProbeData>& p_data) {
+
+ if (p_data.is_valid()) {
+ VS::get_singleton()->instance_set_base(get_instance(),p_data->get_rid());
+ } else {
+ VS::get_singleton()->instance_set_base(get_instance(),RID());
+ }
+
+ probe_data=p_data;
+}
+
+Ref<GIProbeData> GIProbe::get_probe_data() const {
+
+ return probe_data;
+}
+
+void GIProbe::set_subdiv(Subdiv p_subdiv) {
+
+ ERR_FAIL_INDEX(p_subdiv,SUBDIV_MAX);
+ subdiv=p_subdiv;
+ update_gizmo();
+}
+
+GIProbe::Subdiv GIProbe::get_subdiv() const {
+
+ return subdiv;
+}
+
+void GIProbe::set_extents(const Vector3& p_extents) {
+
+ extents=p_extents;
+ update_gizmo();
+}
+
+Vector3 GIProbe::get_extents() const {
+
+ return extents;
+}
+
+void GIProbe::set_dynamic_range(int p_dynamic_range) {
+
+ dynamic_range=p_dynamic_range;
+}
+int GIProbe::get_dynamic_range() const {
+
+ return dynamic_range;
+}
+
+void GIProbe::set_energy(float p_energy) {
+
+ energy=p_energy;
+ if (probe_data.is_valid()) {
+ probe_data->set_energy(energy);
+ }
+}
+float GIProbe::get_energy() const {
+
+ return energy;
+}
+
+void GIProbe::set_interior(bool p_enable) {
+
+ interior=p_enable;
+ if (probe_data.is_valid()) {
+ probe_data->set_interior(p_enable);
+ }
+}
+
+bool GIProbe::is_interior() const {
+
+ return interior;
+}
+
+
+void GIProbe::set_compress(bool p_enable) {
+
+ compress=p_enable;
+ if (probe_data.is_valid()) {
+ probe_data->set_compress(p_enable);
+ }
+}
+
+bool GIProbe::is_compressed() const {
+
+ return compress;
+}
+
+
+#include "math.h"
+
+#define FINDMINMAX(x0,x1,x2,min,max) \
+ min = max = x0; \
+ if(x1<min) min=x1;\
+ if(x1>max) max=x1;\
+ if(x2<min) min=x2;\
+ if(x2>max) max=x2;
+
+static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox)
+{
+ int q;
+ Vector3 vmin,vmax;
+ for(q=0;q<=2;q++)
+ {
+ if(normal[q]>0.0f)
+ {
+ vmin[q]=-maxbox[q];
+ vmax[q]=maxbox[q];
+ }
+ else
+ {
+ vmin[q]=maxbox[q];
+ vmax[q]=-maxbox[q];
+ }
+ }
+ if(normal.dot(vmin)+d>0.0f) return false;
+ if(normal.dot(vmax)+d>=0.0f) return true;
+
+ return false;
+}
+
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p2 = a*v2.y - b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_X2(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p1 = a*v1.y - b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p2 = -a*v2.x + b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Y1(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p1 = -a*v1.x + b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb) \
+ p1 = a*v1.x - b*v1.y; \
+ p2 = a*v2.x - b*v2.y; \
+ if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Z0(a, b, fa, fb) \
+ p0 = a*v0.x - b*v0.y; \
+ p1 = a*v1.x - b*v1.y; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) {
+
+ /* use separating axis theorem to test overlap between triangle and box */
+ /* need to test for overlap in these directions: */
+ /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+ /* we do not even need to test these) */
+ /* 2) normal of the triangle */
+ /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
+ /* this gives 3x3=9 more tests */
+ Vector3 v0,v1,v2;
+ float min,max,d,p0,p1,p2,rad,fex,fey,fez;
+ Vector3 normal,e0,e1,e2;
+
+ /* This is the fastest branch on Sun */
+ /* move everything so that the boxcenter is in (0,0,0) */
+
+ v0=triverts[0]-boxcenter;
+ v1=triverts[1]-boxcenter;
+ v2=triverts[2]-boxcenter;
+
+ /* compute triangle edges */
+ e0=v1-v0; /* tri edge 0 */
+ e1=v2-v1; /* tri edge 1 */
+ e2=v0-v2; /* tri edge 2 */
+
+ /* Bullet 3: */
+ /* test the 9 tests first (this was faster) */
+ fex = Math::abs(e0.x);
+ fey = Math::abs(e0.y);
+ fez = Math::abs(e0.z);
+ AXISTEST_X01(e0.z, e0.y, fez, fey);
+ AXISTEST_Y02(e0.z, e0.x, fez, fex);
+ AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+ fex = Math::abs(e1.x);
+ fey = Math::abs(e1.y);
+ fez = Math::abs(e1.z);
+ AXISTEST_X01(e1.z, e1.y, fez, fey);
+ AXISTEST_Y02(e1.z, e1.x, fez, fex);
+ AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+ fex = Math::abs(e2.x);
+ fey = Math::abs(e2.y);
+ fez = Math::abs(e2.z);
+ AXISTEST_X2(e2.z, e2.y, fez, fey);
+ AXISTEST_Y1(e2.z, e2.x, fez, fex);
+ AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+ /* Bullet 1: */
+ /* first test overlap in the {x,y,z}-directions */
+ /* find min, max of the triangle each direction, and test for overlap in */
+ /* that direction -- this is equivalent to testing a minimal AABB around */
+ /* the triangle against the AABB */
+
+ /* test in X-direction */
+ FINDMINMAX(v0.x,v1.x,v2.x,min,max);
+ if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
+
+ /* test in Y-direction */
+ FINDMINMAX(v0.y,v1.y,v2.y,min,max);
+ if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
+
+ /* test in Z-direction */
+ FINDMINMAX(v0.z,v1.z,v2.z,min,max);
+ if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
+
+ /* Bullet 2: */
+ /* test if the box intersects the plane of the triangle */
+ /* compute plane equation of triangle: normal*x+d=0 */
+ normal=e0.cross(e1);
+ d=-normal.dot(v0); /* plane eq: normal.x+d=0 */
+ if(!planeBoxOverlap(normal,d,boxhalfsize)) return false;
+
+ return true; /* box and triangle overlaps */
+}
+
+
+
+static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) {
+
+ if (p_pos.distance_squared_to(p_vtx[0])<CMP_EPSILON2)
+ return p_uv[0];
+ if (p_pos.distance_squared_to(p_vtx[1])<CMP_EPSILON2)
+ return p_uv[1];
+ if (p_pos.distance_squared_to(p_vtx[2])<CMP_EPSILON2)
+ return p_uv[2];
+
+ Vector3 v0 = p_vtx[1] - p_vtx[0];
+ Vector3 v1 = p_vtx[2] - p_vtx[0];
+ Vector3 v2 = p_pos - p_vtx[0];
+
+ float d00 = v0.dot( v0);
+ float d01 = v0.dot( v1);
+ float d11 = v1.dot( v1);
+ float d20 = v2.dot( v0);
+ float d21 = v2.dot( v1);
+ float denom = (d00 * d11 - d01 * d01);
+ if (denom==0)
+ return p_uv[0];
+ float v = (d11 * d20 - d01 * d21) / denom;
+ float w = (d00 * d21 - d01 * d20) / denom;
+ float u = 1.0f - v - w;
+
+ return p_uv[0]*u + p_uv[1]*v + p_uv[2]*w;
+}
+
+void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const AABB &p_aabb,Baker *p_baker) {
+
+
+
+ if (p_level==p_baker->cell_subdiv-1) {
+ //plot the face by guessing it's albedo and emission value
+
+ //find best axis to map to, for scanning values
+ int closest_axis;
+ float closest_dot;
+
+ Vector3 normal = Plane(p_vtx[0],p_vtx[1],p_vtx[2]).normal;
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 axis;
+ axis[i]=1.0;
+ float dot=ABS(normal.dot(axis));
+ if (i==0 || dot>closest_dot) {
+ closest_axis=i;
+ closest_dot=dot;
+ }
+ }
+
+ Vector3 axis;
+ axis[closest_axis]=1.0;
+ Vector3 t1;
+ t1[(closest_axis+1)%3]=1.0;
+ Vector3 t2;
+ t2[(closest_axis+2)%3]=1.0;
+
+ t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width);
+ t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width);
+
+ Color albedo_accum;
+ Color emission_accum;
+ Vector3 normal_accum;
+
+ float alpha=0.0;
+
+ //map to a grid average in the best axis for this face
+ for(int i=0;i<color_scan_cell_width;i++) {
+
+ Vector3 ofs_i=float(i)*t1;
+
+ for(int j=0;j<color_scan_cell_width;j++) {
+
+ Vector3 ofs_j=float(j)*t2;
+
+ Vector3 from = p_aabb.pos+ofs_i+ofs_j;
+ Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
+ Vector3 half = (to-from)*0.5;
+
+ //is in this cell?
+ if (!fast_tri_box_overlap(from+half,half,p_vtx)) {
+ continue; //face does not span this cell
+ }
+
+ //go from -size to +size*2 to avoid skipping collisions
+ Vector3 ray_from = from + (t1+t2)*0.5 - axis * p_aabb.size[closest_axis];
+ Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis]*2;
+
+ Vector3 intersection;
+
+ if (!Geometry::ray_intersects_triangle(ray_from,ray_to,p_vtx[0],p_vtx[1],p_vtx[2],&intersection)) {
+ //no intersect? look in edges
+
+ float closest_dist=1e20;
+ for(int j=0;j<3;j++) {
+ Vector3 c;
+ Vector3 inters;
+ Geometry::get_closest_points_between_segments(p_vtx[j],p_vtx[(j+1)%3],ray_from,ray_to,inters,c);
+ float d=c.distance_to(intersection);
+ if (j==0 || d<closest_dist) {
+ closest_dist=d;
+ intersection=inters;
+ }
+ }
+ }
+
+ Vector2 uv = get_uv(intersection,p_vtx,p_uv);
+
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+ albedo_accum.r+=p_material.albedo[ofs].r;
+ albedo_accum.g+=p_material.albedo[ofs].g;
+ albedo_accum.b+=p_material.albedo[ofs].b;
+ albedo_accum.a+=p_material.albedo[ofs].a;
+
+ emission_accum.r+=p_material.emission[ofs].r;
+ emission_accum.g+=p_material.emission[ofs].g;
+ emission_accum.b+=p_material.emission[ofs].b;
+
+ normal_accum+=normal;
+
+ alpha+=1.0;
+
+ }
+ }
+
+
+ if (alpha==0) {
+ //could not in any way get texture information.. so use closest point to center
+
+ Face3 f( p_vtx[0],p_vtx[1],p_vtx[2]);
+ Vector3 inters = f.get_closest_point_to(p_aabb.pos+p_aabb.size*0.5);
+
+ Vector2 uv = get_uv(inters,p_vtx,p_uv);
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+
+ alpha = 1.0/(color_scan_cell_width*color_scan_cell_width);
+
+ albedo_accum.r=p_material.albedo[ofs].r*alpha;
+ albedo_accum.g=p_material.albedo[ofs].g*alpha;
+ albedo_accum.b=p_material.albedo[ofs].b*alpha;
+ albedo_accum.a=p_material.albedo[ofs].a*alpha;
+
+ emission_accum.r=p_material.emission[ofs].r*alpha;
+ emission_accum.g=p_material.emission[ofs].g*alpha;
+ emission_accum.b=p_material.emission[ofs].b*alpha;
+
+ normal_accum*=alpha;
+
+
+ } else {
+
+ float accdiv = 1.0/(color_scan_cell_width*color_scan_cell_width);
+ alpha*=accdiv;
+
+ albedo_accum.r*=accdiv;
+ albedo_accum.g*=accdiv;
+ albedo_accum.b*=accdiv;
+ albedo_accum.a*=accdiv;
+
+ emission_accum.r*=accdiv;
+ emission_accum.g*=accdiv;
+ emission_accum.b*=accdiv;
+
+ normal_accum*=accdiv;
+
+ }
+
+ //put this temporarily here, corrected in a later step
+ p_baker->bake_cells[p_idx].albedo[0]+=albedo_accum.r;
+ p_baker->bake_cells[p_idx].albedo[1]+=albedo_accum.g;
+ p_baker->bake_cells[p_idx].albedo[2]+=albedo_accum.b;
+ p_baker->bake_cells[p_idx].emission[0]+=emission_accum.r;
+ p_baker->bake_cells[p_idx].emission[1]+=emission_accum.g;
+ p_baker->bake_cells[p_idx].emission[2]+=emission_accum.b;
+ p_baker->bake_cells[p_idx].normal[0]+=normal_accum.x;
+ p_baker->bake_cells[p_idx].normal[1]+=normal_accum.y;
+ p_baker->bake_cells[p_idx].normal[2]+=normal_accum.z;
+ p_baker->bake_cells[p_idx].alpha+=alpha;
+
+ static const Vector3 side_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),
+ };
+
+ /*
+ for(int i=0;i<6;i++) {
+ if (normal.dot(side_normals[i])>CMP_EPSILON) {
+ p_baker->bake_cells[p_idx].used_sides|=(1<<i);
+ }
+ }*/
+
+
+ } else {
+ //go down
+
+ int half = (1<<(p_baker->cell_subdiv-1)) >> (p_level+1);
+ for(int i=0;i<8;i++) {
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1) {
+ aabb.pos.x+=aabb.size.x;
+ nx+=half;
+ }
+ if (i&2) {
+ aabb.pos.y+=aabb.size.y;
+ ny+=half;
+ }
+ if (i&4) {
+ aabb.pos.z+=aabb.size.z;
+ nz+=half;
+ }
+ //make sure to not plot beyond limits
+ if (nx<0 || nx>=p_baker->axis_cell_size[0] || ny<0 || ny>=p_baker->axis_cell_size[1] || nz<0 || nz>=p_baker->axis_cell_size[2])
+ continue;
+
+ {
+ AABB test_aabb=aabb;
+ //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
+ Vector3 qsize = test_aabb.size*0.5; //quarter size, for fast aabb test
+
+ if (!fast_tri_box_overlap(test_aabb.pos+qsize,qsize,p_vtx)) {
+ //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
+ //does not fit in child, go on
+ continue;
+ }
+
+ }
+
+ if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) {
+ //sub cell must be created
+
+ 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[child_idx].level=p_level+1;
+
+ }
+
+
+ _plot_face(p_baker->bake_cells[p_idx].childs[i],p_level+1,nx,ny,nz,p_vtx,p_uv,p_material,aabb,p_baker);
+ }
+ }
+}
+
+
+
+void GIProbe::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker) {
+
+
+
+ if (p_level==p_baker->cell_subdiv-1) {
+
+ p_baker->leaf_voxel_count++;
+ float alpha = p_baker->bake_cells[p_idx].alpha;
+
+ p_baker->bake_cells[p_idx].albedo[0]/=alpha;
+ p_baker->bake_cells[p_idx].albedo[1]/=alpha;
+ p_baker->bake_cells[p_idx].albedo[2]/=alpha;
+
+ //transfer emission to light
+ p_baker->bake_cells[p_idx].emission[0]/=alpha;
+ p_baker->bake_cells[p_idx].emission[1]/=alpha;
+ p_baker->bake_cells[p_idx].emission[2]/=alpha;
+
+ p_baker->bake_cells[p_idx].normal[0]/=alpha;
+ p_baker->bake_cells[p_idx].normal[1]/=alpha;
+ p_baker->bake_cells[p_idx].normal[2]/=alpha;
+
+ Vector3 n(p_baker->bake_cells[p_idx].normal[0],p_baker->bake_cells[p_idx].normal[1],p_baker->bake_cells[p_idx].normal[2]);
+ if (n.length()<0.01) {
+ //too much fight over normal, zero it
+ p_baker->bake_cells[p_idx].normal[0]=0;
+ p_baker->bake_cells[p_idx].normal[1]=0;
+ p_baker->bake_cells[p_idx].normal[2]=0;
+ } else {
+ n.normalize();
+ p_baker->bake_cells[p_idx].normal[0]=n.x;
+ p_baker->bake_cells[p_idx].normal[1]=n.y;
+ p_baker->bake_cells[p_idx].normal[2]=n.z;
+ }
+
+
+ p_baker->bake_cells[p_idx].alpha=1.0;
+
+ /*
+ //remove neighbours from used sides
+
+ for(int n=0;n<6;n++) {
+
+ int ofs[3]={0,0,0};
+
+ ofs[n/2]=(n&1)?1:-1;
+
+ //convert to x,y,z on this level
+ int x=p_x;
+ int y=p_y;
+ int z=p_z;
+
+ x+=ofs[0];
+ y+=ofs[1];
+ z+=ofs[2];
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = 1<<p_level;
+ int half=size/2;
+
+
+ if (x<0 || x>=size || y<0 || y>=size || z<0 || z>=size) {
+ //neighbour is out, can't use it
+ p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n));
+ continue;
+ }
+
+ uint32_t neighbour=0;
+
+ for(int i=0;i<p_baker->cell_subdiv-1;i++) {
+
+ Baker::Cell *bc = &p_baker->bake_cells[neighbour];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ neighbour = bc->childs[child];
+ if (neighbour==Baker::CHILD_EMPTY) {
+ break;
+ }
+
+ half>>=1;
+ }
+
+ if (neighbour!=Baker::CHILD_EMPTY) {
+ p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n));
+ }
+ }
+ */
+ } else {
+
+
+ //go down
+
+ float alpha_average=0;
+ int half = (1<<(p_baker->cell_subdiv-1)) >> (p_level+1);
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = p_baker->bake_cells[p_idx].childs[i];
+
+ if (child==Baker::CHILD_EMPTY)
+ continue;
+
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+ _fixup_plot(child,p_level+1,nx,ny,nz,p_baker);
+ alpha_average+=p_baker->bake_cells[child].alpha;
+ }
+
+ p_baker->bake_cells[p_idx].alpha=alpha_average/8.0;
+ p_baker->bake_cells[p_idx].emission[0]=0;
+ p_baker->bake_cells[p_idx].emission[1]=0;
+ p_baker->bake_cells[p_idx].emission[2]=0;
+ p_baker->bake_cells[p_idx].normal[0]=0;
+ p_baker->bake_cells[p_idx].normal[1]=0;
+ p_baker->bake_cells[p_idx].normal[2]=0;
+ p_baker->bake_cells[p_idx].albedo[0]=0;
+ p_baker->bake_cells[p_idx].albedo[1]=0;
+ p_baker->bake_cells[p_idx].albedo[2]=0;
+
+ }
+
+}
+
+
+
+Vector<Color> GIProbe::_get_bake_texture(Image &p_image,const Color& p_color) {
+
+ Vector<Color> ret;
+
+ if (p_image.empty()) {
+
+ ret.resize(bake_texture_size*bake_texture_size);
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ ret[i]=p_color;
+ }
+
+ return ret;
+ }
+
+ p_image.convert(Image::FORMAT_RGBA8);
+ p_image.resize(bake_texture_size,bake_texture_size,Image::INTERPOLATE_CUBIC);
+
+
+ DVector<uint8_t>::Read r = p_image.get_data().read();
+ ret.resize(bake_texture_size*bake_texture_size);
+
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ Color c;
+ c.r = r[i*4+0]/255.0;
+ c.g = r[i*4+1]/255.0;
+ c.b = r[i*4+2]/255.0;
+ c.a = r[i*4+3]/255.0;
+ ret[i]=c;
+
+ }
+
+ return ret;
+}
+
+
+GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_material,Baker *p_baker) {
+
+ //this way of obtaining materials is inaccurate and also does not support some compressed formats very well
+ Ref<FixedSpatialMaterial> mat = p_material;
+
+ Ref<Material> material = mat; //hack for now
+
+ if (p_baker->material_cache.has(material)) {
+ return p_baker->material_cache[material];
+ }
+
+ Baker::MaterialCache mc;
+
+ if (mat.is_valid()) {
+
+
+ Ref<ImageTexture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+
+ Image img_albedo;
+ if (albedo_tex.is_valid()) {
+
+ img_albedo = albedo_tex->get_data();
+ }
+
+ mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo());
+
+ Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+
+ Color emission_col = mat->get_emission();
+ emission_col.r*=mat->get_emission_energy();
+ emission_col.g*=mat->get_emission_energy();
+ emission_col.b*=mat->get_emission_energy();
+
+ Image img_emission;
+
+ if (emission_tex.is_valid()) {
+
+ img_emission = emission_tex->get_data();
+ }
+
+ mc.emission=_get_bake_texture(img_emission,emission_col);
+
+ } else {
+ Image empty;
+
+ mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7));
+ mc.emission=_get_bake_texture(empty,Color(0,0,0));
+
+
+ }
+
+ p_baker->material_cache[p_material]=mc;
+ return mc;
+
+
+}
+
+void GIProbe::_plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker) {
+
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue; //only triangles
+
+ Baker::MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i),p_baker);
+
+ Array a = p_mesh->surface_get_arrays(i);
+
+
+ DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ DVector<Vector3>::Read vr=vertices.read();
+ DVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
+ DVector<Vector2>::Read uvr;
+ DVector<int> index = a[Mesh::ARRAY_INDEX];
+
+ bool read_uv=false;
+
+ if (uv.size()) {
+
+ uvr=uv.read();
+ read_uv=true;
+ }
+
+ if (index.size()) {
+
+ int facecount = index.size()/3;
+ DVector<int>::Read ir=index.read();
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[ir[j*3+k]]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[ir[j*3+k]];
+ }
+ }
+
+ //test against original bounds
+ if (!fast_tri_box_overlap(-extents,extents*2,vtxs))
+ continue;
+ //plot
+ _plot_face(0,0,0,0,0,vtxs,uvs,material,p_baker->po2_bounds,p_baker);
+ }
+
+
+
+ } else {
+
+ int facecount = vertices.size()/3;
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[j*3+k]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[j*3+k];
+ }
+ }
+
+ //test against original bounds
+ if (!fast_tri_box_overlap(-extents,extents*2,vtxs))
+ continue;
+ //plot face
+ _plot_face(0,0,0,0,0,vtxs,uvs,material,p_baker->po2_bounds,p_baker);
+ }
+
+ }
+ }
+}
+
+
+
+void GIProbe::_find_meshes(Node *p_at_node,Baker *p_baker){
+
+ MeshInstance *mi = p_at_node->cast_to<MeshInstance>();
+ if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT)) {
+ Ref<Mesh> mesh = mi->get_mesh();
+ if (mesh.is_valid()) {
+
+ AABB aabb = mesh->get_aabb();
+
+ Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();
+
+ if (AABB(-extents,extents*2).intersects(xf.xform(aabb))) {
+ Baker::PlotMesh pm;
+ pm.local_xform=xf;
+ pm.mesh=mesh;
+ p_baker->mesh_list.push_back(pm);
+
+ }
+ }
+ }
+
+ for(int i=0;i<p_at_node->get_child_count();i++) {
+
+ Node *child = p_at_node->get_child(i);
+ if (!child->get_owner())
+ continue; //maybe a helper
+
+ _find_meshes(child,p_baker);
+
+ }
+}
+
+
+
+
+void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){
+
+ Baker baker;
+
+ static const int subdiv_value[SUBDIV_MAX]={7,8,9,10};
+
+ baker.cell_subdiv=subdiv_value[subdiv];
+ baker.bake_cells.resize(1);
+
+ //find out the actual real bounds, power of 2, which gets the highest subdivision
+ baker.po2_bounds=AABB(-extents,extents*2.0);
+ int longest_axis = baker.po2_bounds.get_longest_axis_index();
+ baker.axis_cell_size[longest_axis]=(1<<(baker.cell_subdiv-1));
+ baker.leaf_voxel_count=0;
+
+ for(int i=0;i<3;i++) {
+
+ if (i==longest_axis)
+ continue;
+
+ baker.axis_cell_size[i]=baker.axis_cell_size[longest_axis];
+ float axis_size = baker.po2_bounds.size[longest_axis];
+
+ //shrink until fit subdiv
+ while (axis_size/2.0 >= baker.po2_bounds.size[i]) {
+ axis_size/=2.0;
+ baker.axis_cell_size[i]>>=1;
+ }
+
+ baker.po2_bounds.size[i]=baker.po2_bounds.size[longest_axis];
+ }
+
+
+
+ Transform to_bounds;
+ to_bounds.basis.scale(Vector3(baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis]));
+ to_bounds.origin=baker.po2_bounds.pos;
+
+ Transform to_grid;
+ to_grid.basis.scale(Vector3(baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis]));
+
+ baker.to_cell_space = to_grid * to_bounds.affine_inverse();
+
+
+ _find_meshes(p_from_node?p_from_node:get_parent(),&baker);
+
+
+
+ int pmc=0;
+
+ for(List<Baker::PlotMesh>::Element *E=baker.mesh_list.front();E;E=E->next()) {
+
+ print_line("plotting mesh "+itos(pmc++)+"/"+itos(baker.mesh_list.size()));
+
+ _plot_mesh(E->get().local_xform,E->get().mesh,&baker);
+ }
+
+ _fixup_plot(0,0,0,0,0,&baker);
+
+ //create the data for visual server
+
+ DVector<int> data;
+
+ data.resize( 16+(8+1+1+1+1)*baker.bake_cells.size() ); //4 for header, rest for rest.
+
+ {
+ DVector<int>::Write w = data.write();
+
+ uint32_t * w32 = (uint32_t*)w.ptr();
+
+ w32[0]=0;//version
+ w32[1]=baker.cell_subdiv; //subdiv
+ w32[2]=baker.axis_cell_size[0];
+ w32[3]=baker.axis_cell_size[1];
+ w32[4]=baker.axis_cell_size[2];
+ w32[5]=baker.bake_cells.size();
+ w32[6]=baker.leaf_voxel_count;
+
+ int ofs=16;
+
+ for(int i=0;i<baker.bake_cells.size();i++) {
+
+ for(int j=0;j<8;j++) {
+ w32[ofs++]=baker.bake_cells[i].childs[j];
+ }
+
+ { //albedo
+ uint32_t rgba=uint32_t(CLAMP(baker.bake_cells[i].albedo[0]*255.0,0,255))<<16;
+ rgba|=uint32_t(CLAMP(baker.bake_cells[i].albedo[1]*255.0,0,255))<<8;
+ rgba|=uint32_t(CLAMP(baker.bake_cells[i].albedo[2]*255.0,0,255))<<0;
+
+ w32[ofs++]=rgba;
+
+
+ }
+ { //emission
+
+ Vector3 e(baker.bake_cells[i].emission[0],baker.bake_cells[i].emission[1],baker.bake_cells[i].emission[2]);
+ float l = e.length();
+ if (l>0) {
+ e.normalize();
+ l=CLAMP(l/8.0,0,1.0);
+ }
+
+ uint32_t em=uint32_t(CLAMP(e[0]*255,0,255))<<24;
+ em|=uint32_t(CLAMP(e[1]*255,0,255))<<16;
+ em|=uint32_t(CLAMP(e[2]*255,0,255))<<8;
+ em|=uint32_t(CLAMP(l*255,0,255));
+
+ w32[ofs++]=em;
+ }
+
+ //w32[ofs++]=baker.bake_cells[i].used_sides;
+ { //normal
+
+ Vector3 n(baker.bake_cells[i].normal[0],baker.bake_cells[i].normal[1],baker.bake_cells[i].normal[2]);
+ n=n*Vector3(0.5,0.5,0.5)+Vector3(0.5,0.5,0.5);
+ uint32_t norm=0;
+
+
+ norm|=uint32_t(CLAMP( n.x*255.0, 0, 255))<<16;
+ norm|=uint32_t(CLAMP( n.y*255.0, 0, 255))<<8;
+ norm|=uint32_t(CLAMP( n.z*255.0, 0, 255))<<0;
+
+ w32[ofs++]=norm;
+ }
+
+ {
+ 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);
+ }
+
+ }
+
+ }
+
+ Ref<GIProbeData> probe_data;
+ probe_data.instance();
+ probe_data->set_bounds(AABB(-extents,extents*2.0));
+ probe_data->set_cell_size(baker.po2_bounds.size[longest_axis]/baker.axis_cell_size[longest_axis]);
+ probe_data->set_dynamic_data(data);
+ probe_data->set_dynamic_range(dynamic_range);
+ probe_data->set_energy(energy);
+ probe_data->set_interior(interior);
+ probe_data->set_compress(compress);
+ probe_data->set_to_cell_xform(baker.to_cell_space);
+
+ set_probe_data(probe_data);
+
+
+ if (p_create_visual_debug) {
+ // _create_debug_mesh(&baker);
+ }
+
+
+
+}
+
+
+void GIProbe::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref<MultiMesh> &p_multimesh,int &idx,Baker *p_baker) {
+
+
+ if (p_level==p_baker->cell_subdiv-1) {
+
+ Vector3 center = p_aabb.pos+p_aabb.size*0.5;
+ Transform xform;
+ xform.origin=center;
+ xform.basis.scale(p_aabb.size*0.5);
+ p_multimesh->set_instance_transform(idx,xform);
+ Color col=Color(p_baker->bake_cells[p_idx].albedo[0],p_baker->bake_cells[p_idx].albedo[1],p_baker->bake_cells[p_idx].albedo[2]);
+ p_multimesh->set_instance_color(idx,col);
+
+ idx++;
+
+ } else {
+
+ for(int i=0;i<8;i++) {
+
+ if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY)
+ continue;
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ if (i&1)
+ aabb.pos.x+=aabb.size.x;
+ if (i&2)
+ aabb.pos.y+=aabb.size.y;
+ if (i&4)
+ aabb.pos.z+=aabb.size.z;
+
+ _debug_mesh(p_baker->bake_cells[p_idx].childs[i],p_level+1,aabb,p_multimesh,idx,p_baker);
+ }
+
+ }
+
+}
+
+
+void GIProbe::_create_debug_mesh(Baker *p_baker) {
+
+ Ref<MultiMesh> mm;
+ mm.instance();
+
+ mm->set_transform_format(MultiMesh::TRANSFORM_3D);
+ mm->set_color_format(MultiMesh::COLOR_8BIT);
+ print_line("leaf voxels: "+itos(p_baker->leaf_voxel_count));
+ mm->set_instance_count(p_baker->leaf_voxel_count);
+
+ Ref<Mesh> mesh;
+ mesh.instance();
+
+ {
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+
+ DVector<Vector3> vertices;
+ DVector<Color> colors;
+
+ int vtx_idx=0;
+ #define ADD_VTX(m_idx);\
+ vertices.push_back( face_points[m_idx] );\
+ colors.push_back( Color(1,1,1,1) );\
+ vtx_idx++;\
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ }
+
+ //tri 1
+ ADD_VTX(0);
+ ADD_VTX(1);
+ ADD_VTX(2);
+ //tri 2
+ ADD_VTX(2);
+ ADD_VTX(3);
+ ADD_VTX(0);
+
+ }
+
+
+ arr[Mesh::ARRAY_VERTEX]=vertices;
+ arr[Mesh::ARRAY_COLOR]=colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
+ }
+
+ {
+ Ref<FixedSpatialMaterial> fsm;
+ fsm.instance();
+ fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
+ fsm->set_albedo(Color(1,1,1,1));
+
+ mesh->surface_set_material(0,fsm);
+ }
+
+ mm->set_mesh(mesh);
+
+
+ int idx=0;
+ _debug_mesh(0,0,p_baker->po2_bounds,mm,idx,p_baker);
+
+ MultiMeshInstance *mmi = memnew( MultiMeshInstance );
+ mmi->set_multimesh(mm);
+ add_child(mmi);
+ if (get_tree()->get_edited_scene_root()==this){
+ mmi->set_owner(this);
+ } else {
+ mmi->set_owner(get_owner());
+
+ }
+
+}
+
+void GIProbe::_debug_bake() {
+
+ bake(NULL,true);
+}
+
+AABB GIProbe::get_aabb() const {
+
+ return AABB(-extents,extents*2);
+}
+
+DVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
+
+ return DVector<Face3>();
+}
+
+void GIProbe::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_probe_data","data"),&GIProbe::set_probe_data);
+ ObjectTypeDB::bind_method(_MD("get_probe_data"),&GIProbe::get_probe_data);
+
+ ObjectTypeDB::bind_method(_MD("set_subdiv","subdiv"),&GIProbe::set_subdiv);
+ ObjectTypeDB::bind_method(_MD("get_subdiv"),&GIProbe::get_subdiv);
+
+ ObjectTypeDB::bind_method(_MD("set_extents","extents"),&GIProbe::set_extents);
+ ObjectTypeDB::bind_method(_MD("get_extents"),&GIProbe::get_extents);
+
+ ObjectTypeDB::bind_method(_MD("set_dynamic_range","max"),&GIProbe::set_dynamic_range);
+ ObjectTypeDB::bind_method(_MD("get_dynamic_range"),&GIProbe::get_dynamic_range);
+
+ ObjectTypeDB::bind_method(_MD("set_energy","max"),&GIProbe::set_energy);
+ ObjectTypeDB::bind_method(_MD("get_energy"),&GIProbe::get_energy);
+
+ ObjectTypeDB::bind_method(_MD("set_interior","enable"),&GIProbe::set_interior);
+ ObjectTypeDB::bind_method(_MD("is_interior"),&GIProbe::is_interior);
+
+ ObjectTypeDB::bind_method(_MD("set_compress","enable"),&GIProbe::set_compress);
+ ObjectTypeDB::bind_method(_MD("is_compressed"),&GIProbe::is_compressed);
+
+ ObjectTypeDB::bind_method(_MD("bake","from_node","create_visual_debug"),&GIProbe::bake,DEFVAL(Variant()),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("debug_bake"),&GIProbe::_debug_bake);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"subdiv",PROPERTY_HINT_ENUM,"64,128,256,512"),_SCS("set_subdiv"),_SCS("get_subdiv"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"extents"),_SCS("set_extents"),_SCS("get_extents"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"dynamic_range",PROPERTY_HINT_RANGE,"1,16,1"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_energy"),_SCS("get_energy"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"interior"),_SCS("set_interior"),_SCS("is_interior"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"compress"),_SCS("set_compress"),_SCS("is_compressed"));
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"data",PROPERTY_HINT_RESOURCE_TYPE,"GIProbeData"),_SCS("set_probe_data"),_SCS("get_probe_data"));
+
+
+ BIND_CONSTANT( SUBDIV_64 );
+ BIND_CONSTANT( SUBDIV_128 );
+ BIND_CONSTANT( SUBDIV_256 );
+ BIND_CONSTANT( SUBDIV_MAX );
+
+}
+
+GIProbe::GIProbe() {
+
+ subdiv=SUBDIV_128;
+ dynamic_range=4;
+ energy=1.0;
+ extents=Vector3(10,10,10);
+ color_scan_cell_width=4;
+ bake_texture_size=128;
+ interior=false;
+ compress=false;
+
+ gi_probe = VS::get_singleton()->gi_probe_create();
+
+
+}
+
+GIProbe::~GIProbe() {
+
+
+}
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
new file mode 100644
index 0000000000..59747761b8
--- /dev/null
+++ b/scene/3d/gi_probe.h
@@ -0,0 +1,190 @@
+#ifndef GIPROBE_H
+#define GIPROBE_H
+
+#include "scene/3d/visual_instance.h"
+#include "multimesh_instance.h"
+
+class GIProbeData : public Resource {
+
+ OBJ_TYPE(GIProbeData,Resource);
+
+ RID probe;
+
+protected:
+
+ static void _bind_methods();
+public:
+
+
+
+ void set_bounds(const AABB& p_bounds);
+ AABB get_bounds() const;
+
+ void set_cell_size(float p_size);
+ float get_cell_size() const;
+
+ void set_to_cell_xform(const Transform& p_xform);
+ Transform get_to_cell_xform() const;
+
+ void set_dynamic_data(const DVector<int>& p_data);
+ DVector<int> get_dynamic_data() const;
+
+ void set_dynamic_range(int p_range);
+ int get_dynamic_range() const;
+
+ void set_energy(float p_range);
+ float get_energy() const;
+
+ void set_interior(bool p_enable);
+ bool is_interior() const;
+
+ void set_compress(bool p_enable);
+ bool is_compressed() const;
+
+ virtual RID get_rid() const;
+
+ GIProbeData();
+ ~GIProbeData();
+};
+
+
+
+class GIProbe : public VisualInstance {
+ OBJ_TYPE(GIProbe,VisualInstance);
+public:
+ enum Subdiv{
+ SUBDIV_64,
+ SUBDIV_128,
+ SUBDIV_256,
+ SUBDIV_512,
+ SUBDIV_MAX
+
+ };
+private:
+
+ //stuff used for bake
+ struct Baker {
+
+ enum {
+ CHILD_EMPTY=0xFFFFFFFF
+ };
+ struct Cell {
+
+ uint32_t childs[8];
+ float albedo[3]; //albedo in RGB24
+ float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+ float normal[3];
+ uint32_t used_sides;
+ float alpha; //used for upsampling
+ int level;
+
+ Cell() {
+ for(int i=0;i<8;i++) {
+ childs[i]=CHILD_EMPTY;
+ }
+
+ for(int i=0;i<3;i++) {
+ emission[i]=0;
+ albedo[i]=0;
+ normal[i]=0;
+ }
+ alpha=0;
+ used_sides=0;
+ level=0;
+ }
+ };
+
+ Vector<Cell> bake_cells;
+ int cell_subdiv;
+
+ struct MaterialCache {
+ //128x128 textures
+ Vector<Color> albedo;
+ Vector<Color> emission;
+ };
+
+
+ Vector<Color> _get_bake_texture(Image &p_image, const Color &p_color);
+ Map<Ref<Material>,MaterialCache> material_cache;
+ MaterialCache _get_material_cache(Ref<Material> p_material);
+ int leaf_voxel_count;
+
+
+ AABB po2_bounds;
+ int axis_cell_size[3];
+
+ struct PlotMesh {
+ Ref<Mesh> mesh;
+ Transform local_xform;
+ };
+
+ Transform to_cell_space;
+
+ List<PlotMesh> mesh_list;
+ };
+
+
+ Ref<GIProbeData> probe_data;
+
+ RID gi_probe;
+
+ Subdiv subdiv;
+ Vector3 extents;
+ int dynamic_range;
+ float energy;
+ bool interior;
+ bool compress;
+
+ int color_scan_cell_width;
+ int bake_texture_size;
+
+ Vector<Color> _get_bake_texture(Image &p_image,const Color& p_color);
+ Baker::MaterialCache _get_material_cache(Ref<Material> p_material,Baker *p_baker);
+ void _plot_face(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const AABB &p_aabb,Baker *p_baker);
+ void _plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker);
+ void _find_meshes(Node *p_at_node,Baker *p_baker);
+ void _fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker);
+
+ void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref<MultiMesh> &p_multimesh,int &idx,Baker *p_baker);
+ void _create_debug_mesh(Baker *p_baker);
+
+ void _debug_bake();
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ void set_probe_data(const Ref<GIProbeData>& p_data);
+ Ref<GIProbeData> get_probe_data() const;
+
+ void set_subdiv(Subdiv p_subdiv);
+ Subdiv get_subdiv() const;
+
+ void set_extents(const Vector3& p_extents);
+ Vector3 get_extents() const;
+
+ void set_dynamic_range(int p_dynamic_range);
+ int get_dynamic_range() const;
+
+ void set_energy(float p_energy);
+ float get_energy() const;
+
+ void set_interior(bool p_enable);
+ bool is_interior() const;
+
+ void set_compress(bool p_enable);
+ bool is_compressed() const;
+
+ void bake(Node *p_from_node=NULL,bool p_create_visual_debug=false);
+
+ virtual AABB get_aabb() const;
+ virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ GIProbe();
+ ~GIProbe();
+};
+
+VARIANT_ENUM_CAST(GIProbe::Subdiv)
+
+#endif // GIPROBE_H
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index d9e153c4f5..7a0db6c174 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -30,310 +30,105 @@
#include "globals.h"
#include "scene/resources/surface_tool.h"
+#include "baked_light_instance.h"
-static const char* _light_param_names[VS::LIGHT_PARAM_MAX]={
- "params/spot_attenuation",
- "params/spot_angle",
- "params/radius",
- "params/energy",
- "params/attenuation",
- "shadow/darkening",
- "shadow/z_offset",
- "shadow/z_slope_scale",
- "shadow/esm_multiplier",
- "shadow/blur_passes"
-};
-
-void Light::set_parameter(Parameter p_param, float p_value) {
+bool Light::_can_gizmo_scale() const {
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- vars[p_param]=p_value;
- VisualServer::get_singleton()->light_set_param(light,(VisualServer::LightParam)p_param,p_value);
- if (p_param==PARAM_RADIUS || p_param==PARAM_SPOT_ANGLE)
- update_gizmo();
- _change_notify(_light_param_names[p_param]);
-// _change_notify(_param_names[p_param]);
+ return false;
}
-float Light::get_parameter(Parameter p_param) const {
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return vars[p_param];
+void Light::set_param(Param p_param, float p_value) {
-}
-
-void Light::set_color(LightColor p_color, const Color& p_value) {
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ param[p_param]=p_value;
- ERR_FAIL_INDEX(p_color, 3);
- colors[p_color]=p_value;
- VisualServer::get_singleton()->light_set_color(light,(VisualServer::LightColor)p_color,p_value);
- //_change_notify(_color_names[p_color]);
+ VS::get_singleton()->light_set_param(light,VS::LightParam(p_param),p_value);
-}
-Color Light::get_color(LightColor p_color) const {
+ if (p_param==PARAM_SPOT_ANGLE || p_param==PARAM_RANGE) {
+ update_gizmo();;
+ }
- ERR_FAIL_INDEX_V(p_color, 3, Color());
- return colors[p_color];
}
+float Light::get_param(Param p_param) const{
-void Light::set_project_shadows(bool p_enabled) {
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return param[p_param];
- shadows=p_enabled;
- VisualServer::get_singleton()->light_set_shadow(light, p_enabled);
- _change_notify("shadow");
}
-bool Light::has_project_shadows() const {
- return shadows;
-}
+void Light::set_shadow(bool p_enable){
-void Light::set_projector(const Ref<Texture>& p_projector) {
+ shadow=p_enable;
+ VS::get_singleton()->light_set_shadow(light,p_enable);
- projector=p_projector;
- VisualServer::get_singleton()->light_set_projector(light, projector.is_null()?RID():projector->get_rid());
}
+bool Light::has_shadow() const{
-Ref<Texture> Light::get_projector() const {
-
- return projector;
+ return shadow;
}
+void Light::set_negative(bool p_enable){
-bool Light::_can_gizmo_scale() const {
-
- return false;
+ negative=p_enable;
+ VS::get_singleton()->light_set_negative(light,p_enable);
}
+bool Light::is_negative() const{
-
-static void _make_sphere(int p_lats, int p_lons, float p_radius, Ref<SurfaceTool> p_tool) {
-
-
- p_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- for(int i = 1; i <= p_lats; i++) {
- double lat0 = Math_PI * (-0.5 + (double) (i - 1) / p_lats);
- double z0 = Math::sin(lat0);
- double zr0 = Math::cos(lat0);
-
- double lat1 = Math_PI * (-0.5 + (double) i / p_lats);
- double z1 = Math::sin(lat1);
- double zr1 = Math::cos(lat1);
-
- for(int j = p_lons; j >= 1; j--) {
-
- double lng0 = 2 * Math_PI * (double) (j - 1) / p_lons;
- double x0 = Math::cos(lng0);
- double y0 = Math::sin(lng0);
-
- double lng1 = 2 * Math_PI * (double) (j) / p_lons;
- double x1 = Math::cos(lng1);
- double y1 = Math::sin(lng1);
-
-
- Vector3 v[4]={
- Vector3(x1 * zr0, z0, y1 *zr0),
- Vector3(x1 * zr1, z1, y1 *zr1),
- Vector3(x0 * zr1, z1, y0 *zr1),
- Vector3(x0 * zr0, z0, y0 *zr0)
- };
-
-#define ADD_POINT(m_idx) \
- p_tool->add_normal(v[m_idx]);\
- p_tool->add_vertex(v[m_idx]*p_radius);
-
- ADD_POINT(0);
- ADD_POINT(1);
- ADD_POINT(2);
-
- ADD_POINT(2);
- ADD_POINT(3);
- ADD_POINT(0);
- }
- }
-
+ return negative;
}
-RES Light::_get_gizmo_geometry() const {
-
-
- Ref<FixedMaterial> mat_area( memnew( FixedMaterial ));
-
- mat_area->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.7,0.6,0.0,0.05) );
- mat_area->set_parameter( FixedMaterial::PARAM_EMISSION,Color(0.7,0.7,0.7) );
- mat_area->set_blend_mode( Material::BLEND_MODE_ADD );
- mat_area->set_flag(Material::FLAG_DOUBLE_SIDED,true);
-// mat_area->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-
- Ref<FixedMaterial> mat_light( memnew( FixedMaterial ));
-
- mat_light->set_parameter( FixedMaterial::PARAM_DIFFUSE, Color(1.0,1.0,0.8,0.9) );
- mat_light->set_flag(Material::FLAG_UNSHADED,true);
-
- Ref< Mesh > mesh;
-
- Ref<SurfaceTool> surftool( memnew( SurfaceTool ));
-
- switch(type) {
-
- case VisualServer::LIGHT_DIRECTIONAL: {
-
-
- mat_area->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.9,0.8,0.1,0.8) );
- mat_area->set_blend_mode( Material::BLEND_MODE_MIX);
- mat_area->set_flag(Material::FLAG_DOUBLE_SIDED,false);
- mat_area->set_flag(Material::FLAG_UNSHADED,true);
-
- _make_sphere( 5,5,0.6, surftool );
- surftool->set_material(mat_light);
- mesh=surftool->commit(mesh);
-
- // float radius=1;
-
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- const int arrow_points=5;
- Vector3 arrow[arrow_points]={
- Vector3(0,0,2),
- Vector3(1,1,2),
- Vector3(1,1,-1),
- Vector3(2,2,-1),
- Vector3(0,0,-3)
- };
-
- int arrow_sides=4;
+void Light::set_cull_mask(uint32_t p_cull_mask){
+ cull_mask=p_cull_mask;
+ VS::get_singleton()->light_set_cull_mask(light,p_cull_mask);
- for(int i = 0; i < arrow_sides ; i++) {
-
-
- Matrix3 ma(Vector3(0,0,1),Math_PI*2*float(i)/arrow_sides);
- Matrix3 mb(Vector3(0,0,1),Math_PI*2*float(i+1)/arrow_sides);
-
-
- for(int j=0;j<arrow_points-1;j++) {
-
- Vector3 points[4]={
- ma.xform(arrow[j]),
- mb.xform(arrow[j]),
- mb.xform(arrow[j+1]),
- ma.xform(arrow[j+1]),
- };
-
- Vector3 n = Plane(points[0],points[1],points[2]).normal;
-
- surftool->add_normal(n);
- surftool->add_vertex(points[0]);
- surftool->add_normal(n);
- surftool->add_vertex(points[1]);
- surftool->add_normal(n);
- surftool->add_vertex(points[2]);
-
- surftool->add_normal(n);
- surftool->add_vertex(points[0]);
- surftool->add_normal(n);
- surftool->add_vertex(points[2]);
- surftool->add_normal(n);
- surftool->add_vertex(points[3]);
-
-
- }
-
-
- }
-
- surftool->set_material(mat_area);
- mesh=surftool->commit(mesh);
-
-
-
- } break;
- case VisualServer::LIGHT_OMNI: {
-
-
- _make_sphere( 20,20,vars[PARAM_RADIUS], surftool );
- surftool->set_material(mat_area);
- mesh=surftool->commit(mesh);
- _make_sphere(5,5, 0.1, surftool );
- surftool->set_material(mat_light);
- mesh=surftool->commit(mesh);
- } break;
-
- case VisualServer::LIGHT_SPOT: {
-
- _make_sphere( 5,5,0.1, surftool );
- surftool->set_material(mat_light);
- mesh=surftool->commit(mesh);
-
- // make cone
- int points=24;
- float len=vars[PARAM_RADIUS];
- float size=Math::tan(Math::deg2rad(vars[PARAM_SPOT_ANGLE]))*len;
-
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- for(int i = 0; i < points; i++) {
-
- float x0=Math::sin(i * Math_PI * 2 / points);
- float y0=Math::cos(i * Math_PI * 2 / points);
- float x1=Math::sin((i+1) * Math_PI * 2 / points);
- float y1=Math::cos((i+1) * Math_PI * 2 / points);
-
- Vector3 v1=Vector3(x0*size,y0*size,-len).normalized()*len;
- Vector3 v2=Vector3(x1*size,y1*size,-len).normalized()*len;
-
- Vector3 v3=Vector3(0,0,0);
- Vector3 v4=Vector3(0,0,v1.z);
-
- Vector3 n = Plane(v1,v2,v3).normal;
-
-
- surftool->add_normal(n);
- surftool->add_vertex(v1);
- surftool->add_normal(n);
- surftool->add_vertex(v2);
- surftool->add_normal(n);
- surftool->add_vertex(v3);
+}
+uint32_t Light::get_cull_mask() const{
- n=Vector3(0,0,-1);
+ return cull_mask;
+}
- surftool->add_normal(n);
- surftool->add_vertex(v1);
- surftool->add_normal(n);
- surftool->add_vertex(v2);
- surftool->add_normal(n);
- surftool->add_vertex(v4);
+void Light::set_color(const Color& p_color){
+ color=p_color;
+ VS::get_singleton()->light_set_color(light,p_color);
+}
+Color Light::get_color() const{
- }
+ return color;
+}
- surftool->set_material(mat_area);
- mesh=surftool->commit(mesh);
+void Light::set_shadow_color(const Color& p_shadow_color){
+ shadow_color=p_shadow_color;
+ VS::get_singleton()->light_set_shadow_color(light,p_shadow_color);
+}
- } break;
- }
+Color Light::get_shadow_color() const{
- return mesh;
+ return shadow_color;
}
AABB Light::get_aabb() const {
+
if (type==VisualServer::LIGHT_DIRECTIONAL) {
return AABB( Vector3(-1,-1,-1), Vector3(2, 2, 2 ) );
} else if (type==VisualServer::LIGHT_OMNI) {
- return AABB( Vector3(-1,-1,-1) * vars[PARAM_RADIUS], Vector3(2, 2, 2 ) * vars[PARAM_RADIUS]);
+ return AABB( Vector3(-1,-1,-1) * param[PARAM_RANGE], Vector3(2, 2, 2 ) * param[PARAM_RANGE]);
} else if (type==VisualServer::LIGHT_SPOT) {
- float len=vars[PARAM_RADIUS];
- float size=Math::tan(Math::deg2rad(vars[PARAM_SPOT_ANGLE]))*len;
+ float len=param[PARAM_RANGE];
+ float size=Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE]))*len;
return AABB( Vector3( -size,-size,-len ), Vector3( size*2, size*2, len ) );
}
@@ -346,89 +141,6 @@ DVector<Face3> Light::get_faces(uint32_t p_usage_flags) const {
}
-void Light::set_operator(Operator p_op) {
- ERR_FAIL_INDEX(p_op,2);
- op=p_op;
- VisualServer::get_singleton()->light_set_operator(light,VS::LightOp(op));
-
-}
-
-void Light::set_bake_mode(BakeMode p_bake_mode) {
-
- bake_mode=p_bake_mode;
-}
-
-Light::BakeMode Light::get_bake_mode() const {
-
- return bake_mode;
-}
-
-
-Light::Operator Light::get_operator() const {
-
- return op;
-}
-
-void Light::approximate_opengl_attenuation(float p_constant, float p_linear, float p_quadratic,float p_radius_treshold) {
-
- //this is horrible and must never be used
-
- float a = p_quadratic * p_radius_treshold;
- float b = p_linear * p_radius_treshold;
- float c = p_constant * p_radius_treshold -1;
-
- float radius=10000;
-
- if(a == 0) { // solve linear
- float d = Math::abs(-c/b);
- if(d<radius)
- radius=d;
-
-
- } else { // solve quadratic
- // now ad^2 + bd + c = 0, solve quadratic equation:
-
- float denominator = 2*a;
-
- if(denominator != 0) {
-
-
- float root = b*b - 4*a*c;
-
- if(root >=0) {
-
- root = sqrt(root);
-
- float solution1 = fabs( (-b + root) / denominator);
- float solution2 = fabs( (-b - root) / denominator);
-
- if(solution1 > radius)
- solution1 = radius;
-
- if(solution2 > radius)
- solution2 = radius;
-
- radius = (solution1 > solution2 ? solution1 : solution2);
- }
- }
- }
-
- float energy=1.0;
-
- /*if (p_constant>0)
- energy=1.0/p_constant; //energy is this
- else
- energy=8.0; // some high number..
-*/
-
- if (radius==10000)
- radius=100; //bug?
-
- set_parameter(PARAM_RADIUS,radius);
- set_parameter(PARAM_ENERGY,energy);
-
-}
-
void Light::_update_visibility() {
@@ -436,7 +148,7 @@ void Light::_update_visibility() {
return;
-bool editor_ok=true;
+ bool editor_ok=true;
#ifdef TOOLS_ENABLED
if (editor_only) {
@@ -452,7 +164,7 @@ bool editor_ok=true;
}
#endif
- VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible() && enabled && editor_ok);
+ //VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible() && editor_ok);
_change_notify("geometry/visible");
}
@@ -460,22 +172,40 @@ bool editor_ok=true;
void Light::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_TREE || p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
_update_visibility();
+
}
-}
-void Light::set_enabled(bool p_enabled) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+ _update_visibility();
- enabled=p_enabled;
- _update_visibility();
-}
+ Node *node = this;
+
+ while(node) {
+
+ baked_light=node->cast_to<BakedLight>();
+ if (baked_light) {
+ baked_light->lights.insert(this);
+ break;
+ }
+
+ node=node->get_parent();
+ }
+ }
-bool Light::is_enabled() const{
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+ if (baked_light) {
+ baked_light->lights.erase(this);
+ }
+ }
- return enabled;
}
+
void Light::set_editor_only(bool p_editor_only) {
editor_only=p_editor_only;
@@ -490,68 +220,54 @@ bool Light::is_editor_only() const{
void Light::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("set_parameter","variable","value"), &Light::set_parameter );
- ObjectTypeDB::bind_method(_MD("get_parameter","variable"), &Light::get_parameter );
- ObjectTypeDB::bind_method(_MD("set_color","color","value"), &Light::set_color );
- ObjectTypeDB::bind_method(_MD("get_color","color"), &Light::get_color );
- ObjectTypeDB::bind_method(_MD("set_project_shadows","enable"), &Light::set_project_shadows );
- ObjectTypeDB::bind_method(_MD("has_project_shadows"), &Light::has_project_shadows );
- ObjectTypeDB::bind_method(_MD("set_projector","projector:Texture"), &Light::set_projector );
- ObjectTypeDB::bind_method(_MD("get_projector:Texture"), &Light::get_projector );
- ObjectTypeDB::bind_method(_MD("set_operator","operator"), &Light::set_operator );
- ObjectTypeDB::bind_method(_MD("get_operator"), &Light::get_operator );
- ObjectTypeDB::bind_method(_MD("set_bake_mode","bake_mode"), &Light::set_bake_mode );
- ObjectTypeDB::bind_method(_MD("get_bake_mode"), &Light::get_bake_mode );
- ObjectTypeDB::bind_method(_MD("set_enabled","enabled"), &Light::set_enabled );
- ObjectTypeDB::bind_method(_MD("is_enabled"), &Light::is_enabled );
+
ObjectTypeDB::bind_method(_MD("set_editor_only","editor_only"), &Light::set_editor_only );
ObjectTypeDB::bind_method(_MD("is_editor_only"), &Light::is_editor_only );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/enabled"), _SCS("set_enabled"), _SCS("is_enabled"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Indirect+Shadows,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY );
- /*
- if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) {
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"));
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_RANGE, "0,8,0.01"));
- }
+ ObjectTypeDB::bind_method(_MD("set_param","param","value"), &Light::set_param );
+ ObjectTypeDB::bind_method(_MD("get_param","param"), &Light::get_param );
+
+ ObjectTypeDB::bind_method(_MD("set_shadow","enabled"), &Light::set_shadow );
+ ObjectTypeDB::bind_method(_MD("has_shadow"), &Light::has_shadow );
- if (type == VisualServer::LIGHT_SPOT) {
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/spot_angle", PROPERTY_HINT_RANGE, "0.01,90.0,0.01"));
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_RANGE, "0,8,0.01"));
+ ObjectTypeDB::bind_method(_MD("set_negative","enabled"), &Light::set_negative );
+ ObjectTypeDB::bind_method(_MD("is_negative"), &Light::is_negative );
- }*/
+ ObjectTypeDB::bind_method(_MD("set_cull_mask","cull_mask"), &Light::set_cull_mask );
+ ObjectTypeDB::bind_method(_MD("get_cull_mask"), &Light::get_cull_mask );
- ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/diffuse"), _SCS("set_color"), _SCS("get_color"),COLOR_DIFFUSE);
- ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/specular"), _SCS("set_color"), _SCS("get_color"),COLOR_SPECULAR);
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/shadow"), _SCS("set_project_shadows"), _SCS("has_project_shadows"));
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_offset", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_OFFSET);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_slope_scale", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_SLOPE_SCALE);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/esm_multiplier", PROPERTY_HINT_RANGE, "1.0,512.0,0.1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_ESM_MULTIPLIER);
- ADD_PROPERTYI( PropertyInfo( Variant::INT, "shadow/blur_passes", PROPERTY_HINT_RANGE, "0,4,1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_BLUR_PASSES);
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "projector",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_projector"), _SCS("get_projector"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "operator",PROPERTY_HINT_ENUM,"Add,Sub"), _SCS("set_operator"), _SCS("get_operator"));
+ ObjectTypeDB::bind_method(_MD("set_color","color"), &Light::set_color );
+ ObjectTypeDB::bind_method(_MD("get_color"), &Light::get_color );
+ ObjectTypeDB::bind_method(_MD("set_shadow_color","shadow_color"), &Light::set_shadow_color );
+ ObjectTypeDB::bind_method(_MD("get_shadow_color"), &Light::get_shadow_color );
+
+ ADD_PROPERTY( PropertyInfo( Variant::COLOR, "light/color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_color"), _SCS("get_color"));
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/energy",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_ENERGY);
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "light/negative"), _SCS("set_negative"), _SCS("is_negative"));
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "light/specular",PROPERTY_HINT_RANGE,"0,1,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SPECULAR);
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "light/cull_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_cull_mask"), _SCS("get_cull_mask"));
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/enabled"), _SCS("set_shadow"), _SCS("has_shadow"));
+ ADD_PROPERTY( PropertyInfo( Variant::COLOR, "shadow/color",PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_shadow_color"), _SCS("get_shadow_color"));
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/bias",PROPERTY_HINT_RANGE,"-16,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/max_distance",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_MAX_DISTANCE);
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editor/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only"));
- BIND_CONSTANT( PARAM_RADIUS );
BIND_CONSTANT( PARAM_ENERGY );
+ BIND_CONSTANT( PARAM_SPECULAR );
+ BIND_CONSTANT( PARAM_RANGE );
BIND_CONSTANT( PARAM_ATTENUATION );
BIND_CONSTANT( PARAM_SPOT_ANGLE );
BIND_CONSTANT( PARAM_SPOT_ATTENUATION );
- BIND_CONSTANT( PARAM_SHADOW_DARKENING );
- BIND_CONSTANT( PARAM_SHADOW_Z_OFFSET );
-
-
- BIND_CONSTANT( COLOR_DIFFUSE );
- BIND_CONSTANT( COLOR_SPECULAR );
-
- BIND_CONSTANT( BAKE_MODE_DISABLED );
- BIND_CONSTANT( BAKE_MODE_INDIRECT );
- BIND_CONSTANT( BAKE_MODE_INDIRECT_AND_SHADOWS );
- BIND_CONSTANT( BAKE_MODE_FULL );
+ BIND_CONSTANT( PARAM_SHADOW_MAX_DISTANCE );
+ 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_NORMAL_BIAS );
+ BIND_CONSTANT( PARAM_SHADOW_BIAS );
+ BIND_CONSTANT( PARAM_SHADOW_BIAS_SPLIT_SCALE );
+ BIND_CONSTANT( PARAM_MAX );
}
@@ -561,28 +277,29 @@ Light::Light(VisualServer::LightType p_type) {
type=p_type;
light=VisualServer::get_singleton()->light_create(p_type);
+ VS::get_singleton()->instance_set_base(get_instance(),light);
+
+ baked_light=NULL;
- set_parameter(PARAM_SPOT_ATTENUATION,1.0);
- set_parameter(PARAM_SPOT_ANGLE,30.0);
- set_parameter(PARAM_RADIUS,2.0);
- set_parameter(PARAM_ENERGY,1.0);
- set_parameter(PARAM_ATTENUATION,1.0);
- set_parameter(PARAM_SHADOW_DARKENING,0.0);
- set_parameter(PARAM_SHADOW_Z_OFFSET,0.05);
- set_parameter(PARAM_SHADOW_Z_SLOPE_SCALE,0);
- set_parameter(PARAM_SHADOW_ESM_MULTIPLIER,60);
- set_parameter(PARAM_SHADOW_BLUR_PASSES,1);
-
-
- set_color( COLOR_DIFFUSE, Color(1,1,1));
- set_color( COLOR_SPECULAR, Color(1,1,1));
-
- op=OPERATOR_ADD;
- set_project_shadows( false );
- set_base(light);
- enabled=true;
editor_only=false;
- bake_mode=BAKE_MODE_DISABLED;
+ set_color(Color(1,1,1,1));
+ set_shadow(false);
+ set_negative(false);
+ set_cull_mask(0xFFFFFFFF);
+
+ set_param(PARAM_ENERGY,1);
+ set_param(PARAM_SPECULAR,0.5);
+ set_param(PARAM_RANGE,5);
+ set_param(PARAM_ATTENUATION,1);
+ set_param(PARAM_SPOT_ANGLE,45);
+ set_param(PARAM_SPOT_ATTENUATION,1);
+ set_param(PARAM_SHADOW_MAX_DISTANCE,0);
+ 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_NORMAL_BIAS,0.1);
+ set_param(PARAM_SHADOW_BIAS,0.1);
+ set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE,0.1);
}
@@ -596,83 +313,116 @@ Light::Light() {
Light::~Light() {
+ VS::get_singleton()->instance_set_base(get_instance(),RID());
+
if (light.is_valid())
VisualServer::get_singleton()->free(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);
-
+ VS::get_singleton()->light_directional_set_shadow_mode(light,VS::LightDirectionalShadowMode(p_mode));
}
-DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const{
+DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const {
return shadow_mode;
}
-void DirectionalLight::set_shadow_param(ShadowParam p_param, float p_value) {
+void DirectionalLight::set_blend_splits(bool p_enable) {
- ERR_FAIL_INDEX(p_param,3);
- shadow_param[p_param]=p_value;
- VS::get_singleton()->light_directional_set_shadow_param(light,VS::LightDirectionalShadowParam(p_param),p_value);
+ blend_splits=p_enable;
+ VS::get_singleton()->light_directional_set_blend_splits(light,p_enable);
}
-float DirectionalLight::get_shadow_param(ShadowParam p_param) const {
- ERR_FAIL_INDEX_V(p_param,3,0);
- return shadow_param[p_param];
+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);
- ObjectTypeDB::bind_method(_MD("set_shadow_param","param","value"),&DirectionalLight::set_shadow_param);
- ObjectTypeDB::bind_method(_MD("get_shadow_param","param"),&DirectionalLight::get_shadow_param);
+ ObjectTypeDB::bind_method( _MD("set_shadow_mode","mode"),&DirectionalLight::set_shadow_mode);
+ ObjectTypeDB::bind_method( _MD("get_shadow_mode"),&DirectionalLight::get_shadow_mode);
- ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/mode",PROPERTY_HINT_ENUM,"Orthogonal,Perspective,PSSM 2 Splits,PSSM 4 Splits"),_SCS("set_shadow_mode"),_SCS("get_shadow_mode"));
- ADD_PROPERTYI( PropertyInfo(Variant::REAL,"shadow/max_distance",PROPERTY_HINT_EXP_RANGE,"0.00,99999,0.01"),_SCS("set_shadow_param"),_SCS("get_shadow_param"), SHADOW_PARAM_MAX_DISTANCE);
- ADD_PROPERTYI( PropertyInfo(Variant::REAL,"shadow/split_weight",PROPERTY_HINT_RANGE,"0.01,1.0,0.01"),_SCS("set_shadow_param"),_SCS("get_shadow_param"), SHADOW_PARAM_PSSM_SPLIT_WEIGHT);
- ADD_PROPERTYI( PropertyInfo(Variant::REAL,"shadow/zoffset_scale",PROPERTY_HINT_RANGE,"0.01,1024.0,0.01"),_SCS("set_shadow_param"),_SCS("get_shadow_param"), SHADOW_PARAM_PSSM_ZOFFSET_SCALE);
+ 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_shadow/split_1",PROPERTY_HINT_RANGE,"0,1,0.001"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_1_OFFSET);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/split_2",PROPERTY_HINT_RANGE,"0,1,0.001"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_2_OFFSET);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/split_3",PROPERTY_HINT_RANGE,"0,1,0.001"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_SPLIT_3_OFFSET);
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "directional_shadow/blend_splits"), _SCS("set_blend_splits"), _SCS("is_blend_splits_enabled"));
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/normal_bias",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_NORMAL_BIAS);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "directional_shadow/bias_split_scale",PROPERTY_HINT_RANGE,"0,16,0.01"), _SCS("set_param"), _SCS("get_param"), PARAM_SHADOW_BIAS_SPLIT_SCALE);
BIND_CONSTANT( SHADOW_ORTHOGONAL );
- BIND_CONSTANT( SHADOW_PERSPECTIVE );
BIND_CONSTANT( SHADOW_PARALLEL_2_SPLITS );
BIND_CONSTANT( SHADOW_PARALLEL_4_SPLITS );
- BIND_CONSTANT( SHADOW_PARAM_MAX_DISTANCE );
- BIND_CONSTANT( SHADOW_PARAM_PSSM_SPLIT_WEIGHT );
- BIND_CONSTANT( SHADOW_PARAM_PSSM_ZOFFSET_SCALE );
}
DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL ) {
- shadow_mode=SHADOW_ORTHOGONAL;
- shadow_param[SHADOW_PARAM_MAX_DISTANCE]=0;
- shadow_param[SHADOW_PARAM_PSSM_SPLIT_WEIGHT]=0.5;
- shadow_param[SHADOW_PARAM_PSSM_ZOFFSET_SCALE]=2.0;
+ 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, "params/radius", PROPERTY_HINT_EXP_RANGE, "0.2,4096,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_RADIUS );
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), 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",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "omni/attenuation",PROPERTY_HINT_EXP_EASING), _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"));
}
-void SpotLight::_bind_methods() {
+OmniLight::OmniLight() : Light( VisualServer::LIGHT_OMNI ) {
+
+ set_shadow_mode(SHADOW_DUAL_PARABOLOID);
+ set_shadow_detail(SHADOW_DETAIL_HORIZONTAL);
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/radius", PROPERTY_HINT_EXP_RANGE, "0.2,4096,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_RADIUS );
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION );
+}
+
+void SpotLight::_bind_methods() {
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_angle", PROPERTY_HINT_RANGE, "0.01,89.9,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPOT_ANGLE );
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_EXP_EASING, "spot_attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPOT_ATTENUATION );
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/range",PROPERTY_HINT_RANGE,"0,65536,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_RANGE);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/attenuation",PROPERTY_HINT_EXP_EASING), _SCS("set_param"), _SCS("get_param"), PARAM_ATTENUATION);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_angle",PROPERTY_HINT_RANGE,"0,180,0.1"), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ANGLE);
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "spot/spot_attenuation",PROPERTY_HINT_EXP_EASING), _SCS("set_param"), _SCS("get_param"), PARAM_SPOT_ATTENUATION);
}
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 43ac7be350..6818e4f014 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -37,6 +37,10 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
+
+
+class BakedLight;
+
class Light : public VisualInstance {
OBJ_TYPE( Light, VisualInstance );
@@ -44,58 +48,36 @@ class Light : public VisualInstance {
public:
- enum Parameter {
- PARAM_RADIUS=VisualServer::LIGHT_PARAM_RADIUS,
- PARAM_ENERGY=VisualServer::LIGHT_PARAM_ENERGY,
- PARAM_ATTENUATION=VisualServer::LIGHT_PARAM_ATTENUATION,
- PARAM_SPOT_ANGLE=VisualServer::LIGHT_PARAM_SPOT_ANGLE,
- PARAM_SPOT_ATTENUATION=VisualServer::LIGHT_PARAM_SPOT_ATTENUATION,
- PARAM_SHADOW_DARKENING=VisualServer::LIGHT_PARAM_SHADOW_DARKENING,
- PARAM_SHADOW_Z_OFFSET=VisualServer::LIGHT_PARAM_SHADOW_Z_OFFSET,
- PARAM_SHADOW_Z_SLOPE_SCALE=VisualServer::LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE,
- PARAM_SHADOW_ESM_MULTIPLIER=VisualServer::LIGHT_PARAM_SHADOW_ESM_MULTIPLIER,
- PARAM_SHADOW_BLUR_PASSES=VisualServer::LIGHT_PARAM_SHADOW_BLUR_PASSES,
- PARAM_MAX=VisualServer::LIGHT_PARAM_MAX
- };
-
-
- enum LightColor {
-
- COLOR_DIFFUSE=VisualServer::LIGHT_COLOR_DIFFUSE,
- COLOR_SPECULAR=VisualServer::LIGHT_COLOR_SPECULAR
- };
-
- enum BakeMode {
-
- BAKE_MODE_DISABLED,
- BAKE_MODE_INDIRECT,
- BAKE_MODE_INDIRECT_AND_SHADOWS,
- BAKE_MODE_FULL
-
+ enum Param {
+ 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_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
};
-
- enum Operator {
-
- OPERATOR_ADD,
- OPERATOR_SUB
- };
private:
-
- Ref<Texture> projector;
- float vars[PARAM_MAX];
- Color colors[3];
-
-
- BakeMode bake_mode;
- VisualServer::LightType type;
- bool shadows;
- bool enabled;
+ Color color;
+ float param[PARAM_MAX];
+ Color shadow_color;
+ bool shadow;
+ bool negative;
+ uint32_t cull_mask;
+ VS::LightType type;
bool editor_only;
- Operator op;
-
void _update_visibility();
+
+ BakedLight *baked_light;
// bind helpers
protected:
@@ -103,8 +85,7 @@ protected:
RID light;
virtual bool _can_gizmo_scale() const;
- virtual RES _get_gizmo_geometry() const;
-
+
static void _bind_methods();
void _notification(int p_what);
@@ -114,44 +95,37 @@ public:
VS::LightType get_light_type() const { return type; }
- void set_parameter(Parameter p_var, float p_value);
- float get_parameter(Parameter p_var) const;
+ void set_editor_only(bool p_editor_only);
+ bool is_editor_only() const;
- void set_color(LightColor p_color,const Color& p_value);
- Color get_color(LightColor p_color) const;
+ void set_param(Param p_param, float p_value);
+ float get_param(Param p_param) const;
- void set_project_shadows(bool p_enabled);
- bool has_project_shadows() const;
+ void set_shadow(bool p_enable);
+ bool has_shadow() const;
- void set_projector(const Ref<Texture>& p_projector);
- Ref<Texture> get_projector() const;
+ void set_negative(bool p_enable);
+ bool is_negative() const;
- void set_operator(Operator p_op);
- Operator get_operator() const;
+ void set_cull_mask(uint32_t p_cull_mask);
+ uint32_t get_cull_mask() const;
- void set_bake_mode(BakeMode p_bake_mode);
- BakeMode get_bake_mode() const;
+ void set_color(const Color& p_color);
+ Color get_color() const;
- void set_enabled(bool p_enabled);
- bool is_enabled() const;
+ void set_shadow_color(const Color& p_shadow_color);
+ Color get_shadow_color() const;
- void set_editor_only(bool p_editor_only);
- bool is_editor_only() const;
virtual AABB get_aabb() const;
virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
- void approximate_opengl_attenuation(float p_constant, float p_linear, float p_quadratic, float p_radius_treshold=0.5);
-
Light();
~Light();
};
-VARIANT_ENUM_CAST( Light::Parameter );
-VARIANT_ENUM_CAST( Light::LightColor );
-VARIANT_ENUM_CAST( Light::Operator );
-VARIANT_ENUM_CAST( Light::BakeMode);
+VARIANT_ENUM_CAST(Light::Param);
class DirectionalLight : public Light {
@@ -162,19 +136,15 @@ public:
enum ShadowMode {
SHADOW_ORTHOGONAL,
- SHADOW_PERSPECTIVE,
SHADOW_PARALLEL_2_SPLITS,
SHADOW_PARALLEL_4_SPLITS
};
- enum ShadowParam {
- SHADOW_PARAM_MAX_DISTANCE,
- SHADOW_PARAM_PSSM_SPLIT_WEIGHT,
- SHADOW_PARAM_PSSM_ZOFFSET_SCALE
- };
private:
+
+ bool blend_splits;
ShadowMode shadow_mode;
- float shadow_param[3];
+
protected:
static void _bind_methods();
public:
@@ -182,30 +152,51 @@ public:
void set_shadow_mode(ShadowMode p_mode);
ShadowMode get_shadow_mode() const;
- void set_shadow_max_distance(float p_distance);
- float get_shadow_max_distance() const;
- void set_shadow_param(ShadowParam p_param, float p_value);
- float get_shadow_param(ShadowParam p_param) const;
+ void set_blend_splits(bool p_enable);
+ bool is_blend_splits_enabled() const;
DirectionalLight();
};
-VARIANT_ENUM_CAST( DirectionalLight::ShadowMode );
-VARIANT_ENUM_CAST( DirectionalLight::ShadowParam );
-
+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 ) { set_parameter(PARAM_SHADOW_Z_OFFSET,0.001);}
+ void set_shadow_detail(ShadowDetail p_detail);
+ ShadowDetail get_shadow_detail() const;
+
+ OmniLight();
};
+VARIANT_ENUM_CAST(OmniLight::ShadowMode)
+VARIANT_ENUM_CAST(OmniLight::ShadowDetail)
+
class SpotLight : public Light {
OBJ_TYPE( SpotLight, Light );
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 25f675ac0c..dfa8e5901f 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -201,7 +201,7 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
arr.resize(Mesh::ARRAY_MAX);
arr[Mesh::ARRAY_VERTEX]=varr;
- debug_mesh->add_surface(Mesh::PRIMITIVE_LINES,arr);
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES,arr);
return debug_mesh;
}
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index c700fed575..289dec534b 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -30,6 +30,7 @@
#include "servers/visual_server.h"
#include "scene/resources/surface_tool.h"
+#if 0
/*
static const char* _var_names[Particles::VAR_MAX]={
"vars/lifetime",
@@ -318,10 +319,10 @@ RES Particles::_get_gizmo_geometry() const {
Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
- Ref<FixedMaterial> mat( memnew( FixedMaterial ));
+ Ref<FixedSpatialMaterial> mat( memnew( FixedSpatialMaterial ));
- mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.2) );
- mat->set_parameter( FixedMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) );
+ mat->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.2) );
+ mat->set_parameter( FixedSpatialMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) );
mat->set_blend_mode( Material::BLEND_MODE_ADD );
mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
// mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
@@ -381,9 +382,9 @@ RES Particles::_get_gizmo_geometry() const {
Ref<Mesh> mesh = surface_tool->commit();
- Ref<FixedMaterial> mat_aabb( memnew( FixedMaterial ));
+ Ref<FixedSpatialMaterial> mat_aabb( memnew( FixedSpatialMaterial ));
- mat_aabb->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.9,0.7) );
+ mat_aabb->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.9,0.7) );
mat_aabb->set_line_width(3);
mat_aabb->set_flag( Material::FLAG_UNSHADED, true );
@@ -557,3 +558,4 @@ Particles::~Particles() {
VisualServer::get_singleton()->free(particles);
}
+#endif
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
index 21e975138c..7b42f5f26a 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -37,7 +37,7 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
-
+#if 0
class Particles : public GeometryInstance {
public:
@@ -163,3 +163,4 @@ public:
VARIANT_ENUM_CAST( Particles::Variable );
#endif
+#endif
diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp
index 0630e6a1de..421cfcc787 100644
--- a/scene/3d/portal.cpp
+++ b/scene/3d/portal.cpp
@@ -96,45 +96,6 @@ void Portal::_get_property_list( List<PropertyInfo> *p_list) const {
}
-RES Portal::_get_gizmo_geometry() const {
-
- Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
-
- Ref<FixedMaterial> mat( memnew( FixedMaterial ));
-
- mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(1.0,0.8,0.8,0.7) );
- mat->set_line_width(4);
- mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- mat->set_flag(Material::FLAG_UNSHADED,true);
-// mat->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER,true);
-
- surface_tool->begin(Mesh::PRIMITIVE_LINES);
- surface_tool->set_material(mat);
-
- Vector<Point2> shape = get_shape();
-
- Vector2 center;
- for (int i=0;i<shape.size();i++) {
-
- int n=(i+1)%shape.size();
- Vector<Vector3> points;
- surface_tool->add_vertex( Vector3( shape[i].x, shape[i].y,0 ));
- surface_tool->add_vertex( Vector3( shape[n].x, shape[n].y,0 ));
- center+=shape[i];
-
- }
-
- if (shape.size()>0) {
-
- center/=shape.size();
- Vector<Vector3> points;
- surface_tool->add_vertex( Vector3( center.x, center.y,0 ));
- surface_tool->add_vertex( Vector3( center.x, center.y,1.0 ));
- }
-
- return surface_tool->commit();
-}
-
AABB Portal::get_aabb() const {
@@ -178,18 +139,19 @@ void Portal::set_shape(const Vector<Point2>& p_shape) {
VisualServer::get_singleton()->portal_set_shape(portal, p_shape);
+ shape=p_shape;
update_gizmo();
}
Vector<Point2> Portal::get_shape() const {
- return VisualServer::get_singleton()->portal_get_shape(portal);
+ return shape;
}
void Portal::set_connect_range(float p_range) {
connect_range=p_range;
- VisualServer::get_singleton()->portal_set_connect_range(portal,p_range);
+ //VisualServer::get_singleton()->portal_set_connect_range(portal,p_range);
}
float Portal::get_connect_range() const {
diff --git a/scene/3d/portal.h b/scene/3d/portal.h
index 9443ffca99..e69e973146 100644
--- a/scene/3d/portal.h
+++ b/scene/3d/portal.h
@@ -47,6 +47,7 @@ class Portal : public VisualInstance {
OBJ_TYPE(Portal, VisualInstance);
RID portal;
+ Vector<Point2> shape;
bool enabled;
float disable_distance;
@@ -55,7 +56,6 @@ class Portal : public VisualInstance {
AABB aabb;
- virtual RES _get_gizmo_geometry() const;
protected:
diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp
index c08d2609b1..e7403053b2 100644
--- a/scene/3d/position_3d.cpp
+++ b/scene/3d/position_3d.cpp
@@ -29,37 +29,6 @@
#include "position_3d.h"
#include "scene/resources/mesh.h"
-RES Position3D::_get_gizmo_geometry() const {
-
-
- Ref<Mesh> mesh = memnew( Mesh );
-
- DVector<Vector3> cursor_points;
- DVector<Color> cursor_colors;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));
- cursor_points.push_back(Vector3(0,0,+cs));
- cursor_points.push_back(Vector3(0,0,-cs));
- cursor_colors.push_back(Color(1,0.5,0.5,1));
- cursor_colors.push_back(Color(1,0.5,0.5,1));
- cursor_colors.push_back(Color(0.5,1,0.5,1));
- cursor_colors.push_back(Color(0.5,1,0.5,1));
- cursor_colors.push_back(Color(0.5,0.5,1,1));
- cursor_colors.push_back(Color(0.5,0.5,1,1));
-
- Ref<FixedMaterial> mat = memnew( FixedMaterial );
- mat->set_flag(Material::FLAG_UNSHADED,true);
- mat->set_line_width(3);
- Array d;
- d[Mesh::ARRAY_VERTEX]=cursor_points;
- d[Mesh::ARRAY_COLOR]=cursor_colors;
- mesh->add_surface(Mesh::PRIMITIVE_LINES,d);
- mesh->surface_set_material(0,mat);
- return mesh;
-}
Position3D::Position3D()
{
diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h
index 1c2afe9ee6..47f71845f0 100644
--- a/scene/3d/position_3d.h
+++ b/scene/3d/position_3d.h
@@ -35,7 +35,6 @@ class Position3D : public Spatial {
OBJ_TYPE(Position3D,Spatial);
- virtual RES _get_gizmo_geometry() const;
public:
diff --git a/scene/3d/quad.cpp b/scene/3d/quad.cpp
index 519757ba04..2d433fbb8c 100644
--- a/scene/3d/quad.cpp
+++ b/scene/3d/quad.cpp
@@ -120,7 +120,7 @@ void Quad::_update() {
} else {
configured=true;
}
- VS::get_singleton()->mesh_add_surface(mesh,VS::PRIMITIVE_TRIANGLES,arr);
+ VS::get_singleton()->mesh_add_surface_from_arrays(mesh,VS::PRIMITIVE_TRIANGLES,arr);
pending_update=false;
}
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
new file mode 100644
index 0000000000..09082b0f28
--- /dev/null
+++ b/scene/3d/reflection_probe.cpp
@@ -0,0 +1,266 @@
+#include "reflection_probe.h"
+
+
+void ReflectionProbe::set_intensity(float p_intensity) {
+
+ intensity=p_intensity;
+ VS::get_singleton()->reflection_probe_set_intensity(probe,p_intensity);
+}
+
+float ReflectionProbe::get_intensity() const{
+
+ return intensity;
+}
+
+
+void ReflectionProbe::set_interior_ambient(Color p_ambient) {
+
+ interior_ambient=p_ambient;
+ VS::get_singleton()->reflection_probe_set_interior_ambient(probe,p_ambient);
+}
+
+void ReflectionProbe::set_interior_ambient_energy(float p_energy) {
+ interior_ambient_energy=p_energy;
+ VS::get_singleton()->reflection_probe_set_interior_ambient_energy(probe,p_energy);
+}
+
+float ReflectionProbe::get_interior_ambient_energy() const{
+ return interior_ambient_energy;
+}
+
+
+Color ReflectionProbe::get_interior_ambient() const{
+
+ return interior_ambient;
+}
+
+void ReflectionProbe::set_interior_ambient_probe_contribution(float p_contribution) {
+
+ interior_ambient_probe_contribution=p_contribution;
+ VS::get_singleton()->reflection_probe_set_interior_ambient_probe_contribution(probe,p_contribution);
+}
+
+float ReflectionProbe::get_interior_ambient_probe_contribution() const{
+
+ return interior_ambient_probe_contribution;
+}
+
+
+void ReflectionProbe::set_max_distance(float p_distance){
+
+ max_distance=p_distance;
+ VS::get_singleton()->reflection_probe_set_max_distance(probe,p_distance);
+}
+float ReflectionProbe::get_max_distance() const{
+
+ return max_distance;
+}
+
+
+void ReflectionProbe::set_extents(const Vector3& p_extents){
+
+ extents=p_extents;
+
+ for(int i=0;i<3;i++) {
+ if (extents[i]<0.01) {
+ extents[i]=0.01;
+ }
+
+ if (extents[i]-0.01<ABS(origin_offset[i])) {
+ origin_offset[i]=SGN(origin_offset[i])*(extents[i]-0.01);
+ _change_notify("origin_offset");
+ }
+ }
+
+ VS::get_singleton()->reflection_probe_set_extents(probe,extents);
+ VS::get_singleton()->reflection_probe_set_origin_offset(probe,origin_offset);
+ _change_notify("extents");
+ update_gizmo();
+
+}
+Vector3 ReflectionProbe::get_extents() const{
+
+ return extents;
+}
+
+void ReflectionProbe::set_origin_offset(const Vector3& p_extents){
+
+ origin_offset=p_extents;
+
+ for(int i=0;i<3;i++) {
+
+ if (extents[i]-0.01<ABS(origin_offset[i])) {
+ origin_offset[i]=SGN(origin_offset[i])*(extents[i]-0.01);
+
+ }
+ }
+ VS::get_singleton()->reflection_probe_set_extents(probe,extents);
+ VS::get_singleton()->reflection_probe_set_origin_offset(probe,origin_offset);
+
+ _change_notify("origin_offset");
+ update_gizmo();
+}
+Vector3 ReflectionProbe::get_origin_offset() const{
+
+ return origin_offset;
+}
+
+void ReflectionProbe::set_enable_box_projection(bool p_enable){
+
+ box_projection=p_enable;
+ VS::get_singleton()->reflection_probe_set_enable_box_projection(probe,p_enable);
+
+}
+bool ReflectionProbe::is_box_projection_enabled() const{
+
+ return box_projection;
+}
+
+
+void ReflectionProbe::set_as_interior(bool p_enable) {
+
+ interior=p_enable;
+ VS::get_singleton()->reflection_probe_set_as_interior(probe,interior);
+ _change_notify();
+
+}
+
+bool ReflectionProbe::is_set_as_interior() const {
+
+ return interior;
+}
+
+
+
+void ReflectionProbe::set_enable_shadows(bool p_enable) {
+
+ enable_shadows=p_enable;
+ VS::get_singleton()->reflection_probe_set_enable_shadows(probe,p_enable);
+}
+bool ReflectionProbe::are_shadows_enabled() const {
+
+ return enable_shadows;
+}
+
+void ReflectionProbe::set_cull_mask(uint32_t p_layers) {
+
+ cull_mask=p_layers;
+ VS::get_singleton()->reflection_probe_set_enable_shadows(probe,p_layers);
+}
+uint32_t ReflectionProbe::get_cull_mask() const {
+
+ return cull_mask;
+}
+
+void ReflectionProbe::set_update_mode(UpdateMode p_mode) {
+ update_mode=p_mode;
+ VS::get_singleton()->reflection_probe_set_update_mode(probe,VS::ReflectionProbeUpdateMode(p_mode));
+}
+
+ReflectionProbe::UpdateMode ReflectionProbe::get_update_mode() const {
+ return update_mode;
+}
+
+
+AABB ReflectionProbe::get_aabb() const {
+
+ AABB aabb;
+ aabb.pos=-origin_offset;
+ aabb.size=origin_offset+extents;
+ return aabb;
+}
+DVector<Face3> ReflectionProbe::get_faces(uint32_t p_usage_flags) const {
+
+ return DVector<Face3>();
+}
+
+void ReflectionProbe::_validate_property(PropertyInfo& property) const {
+
+ if (property.name=="interior/ambient_color" || property.name=="interior/ambient_energy" || property.name=="interior/ambient_contrib") {
+ if (!interior) {
+ property.usage=PROPERTY_USAGE_NOEDITOR;
+ }
+ }
+}
+
+void ReflectionProbe::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_intensity","intensity"),&ReflectionProbe::set_intensity);
+ ObjectTypeDB::bind_method(_MD("get_intensity"),&ReflectionProbe::get_intensity);
+
+ ObjectTypeDB::bind_method(_MD("set_interior_ambient","ambient"),&ReflectionProbe::set_interior_ambient);
+ ObjectTypeDB::bind_method(_MD("get_interior_ambient"),&ReflectionProbe::get_interior_ambient);
+
+ ObjectTypeDB::bind_method(_MD("set_interior_ambient_energy","ambient_energy"),&ReflectionProbe::set_interior_ambient_energy);
+ ObjectTypeDB::bind_method(_MD("get_interior_ambient_energy"),&ReflectionProbe::get_interior_ambient_energy);
+
+ ObjectTypeDB::bind_method(_MD("set_interior_ambient_probe_contribution","ambient_probe_contribution"),&ReflectionProbe::set_interior_ambient_probe_contribution);
+ ObjectTypeDB::bind_method(_MD("get_interior_ambient_probe_contribution"),&ReflectionProbe::get_interior_ambient_probe_contribution);
+
+ ObjectTypeDB::bind_method(_MD("set_max_distance","max_distance"),&ReflectionProbe::set_max_distance);
+ ObjectTypeDB::bind_method(_MD("get_max_distance"),&ReflectionProbe::get_max_distance);
+
+ ObjectTypeDB::bind_method(_MD("set_extents","extents"),&ReflectionProbe::set_extents);
+ ObjectTypeDB::bind_method(_MD("get_extents"),&ReflectionProbe::get_extents);
+
+ ObjectTypeDB::bind_method(_MD("set_origin_offset","origin_offset"),&ReflectionProbe::set_origin_offset);
+ ObjectTypeDB::bind_method(_MD("get_origin_offset"),&ReflectionProbe::get_origin_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_as_interior","enable"),&ReflectionProbe::set_as_interior);
+ ObjectTypeDB::bind_method(_MD("is_set_as_interior"),&ReflectionProbe::is_set_as_interior);
+
+ ObjectTypeDB::bind_method(_MD("set_enable_box_projection","enable"),&ReflectionProbe::set_enable_box_projection);
+ ObjectTypeDB::bind_method(_MD("is_box_projection_enabled"),&ReflectionProbe::is_box_projection_enabled);
+
+
+ ObjectTypeDB::bind_method(_MD("set_enable_shadows","enable"),&ReflectionProbe::set_enable_shadows);
+ ObjectTypeDB::bind_method(_MD("are_shadows_enabled"),&ReflectionProbe::are_shadows_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_cull_mask","layers"),&ReflectionProbe::set_cull_mask);
+ ObjectTypeDB::bind_method(_MD("get_cull_mask"),&ReflectionProbe::get_cull_mask);
+
+ ObjectTypeDB::bind_method(_MD("set_update_mode","mode"),&ReflectionProbe::set_update_mode);
+ ObjectTypeDB::bind_method(_MD("get_update_mode"),&ReflectionProbe::get_update_mode);
+
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"update_mode",PROPERTY_HINT_ENUM,"Once,Always"),_SCS("set_update_mode"),_SCS("get_update_mode"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"intensity",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_intensity"),_SCS("get_intensity"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"max_distance",PROPERTY_HINT_RANGE,"0,16384,0.1"),_SCS("set_max_distance"),_SCS("get_max_distance"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"extents"),_SCS("set_extents"),_SCS("get_extents"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"origin_offset"),_SCS("set_origin_offset"),_SCS("get_origin_offset"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"box_projection"),_SCS("set_enable_box_projection"),_SCS("is_box_projection_enabled"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enable_shadows"),_SCS("set_enable_shadows"),_SCS("are_shadows_enabled"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_cull_mask"),_SCS("get_cull_mask"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"interior/enable"),_SCS("set_as_interior"),_SCS("is_set_as_interior"));
+ ADD_PROPERTY( PropertyInfo(Variant::COLOR,"interior/ambient_color",PROPERTY_HINT_COLOR_NO_ALPHA),_SCS("set_interior_ambient"),_SCS("get_interior_ambient"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"interior/ambient_energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_interior_ambient_energy"),_SCS("get_interior_ambient_energy"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"interior/ambient_contrib",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_interior_ambient_probe_contribution"),_SCS("get_interior_ambient_probe_contribution"));
+
+
+ BIND_CONSTANT( UPDATE_ONCE );
+ BIND_CONSTANT( UPDATE_ALWAYS );
+
+}
+
+ReflectionProbe::ReflectionProbe() {
+
+ intensity=1.0;
+ interior_ambient=Color(0,0,0);
+ interior_ambient_probe_contribution=0;
+ interior_ambient_energy=1.0;
+ max_distance=0;
+ extents=Vector3(1,1,1);
+ origin_offset=Vector3(0,0,0);
+ box_projection=false;
+ interior=false;
+ enable_shadows=false;
+ cull_mask=(1<<20)-1;
+ update_mode=UPDATE_ONCE;
+
+ probe=VisualServer::get_singleton()->reflection_probe_create();
+ VS::get_singleton()->instance_set_base(get_instance(),probe);
+}
+
+ReflectionProbe::~ReflectionProbe() {
+
+ VS::get_singleton()->free(probe);
+}
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
new file mode 100644
index 0000000000..5ea41a91c9
--- /dev/null
+++ b/scene/3d/reflection_probe.h
@@ -0,0 +1,92 @@
+#ifndef REFLECTIONPROBE_H
+#define REFLECTIONPROBE_H
+
+#include "scene/3d/visual_instance.h"
+#include "scene/resources/texture.h"
+#include "scene/resources/sky_box.h"
+#include "servers/visual_server.h"
+
+class ReflectionProbe : public VisualInstance {
+ OBJ_TYPE(ReflectionProbe,VisualInstance);
+
+public:
+
+ enum UpdateMode {
+ UPDATE_ONCE,
+ UPDATE_ALWAYS,
+ };
+
+
+private:
+
+ RID probe;
+ float intensity;
+ float max_distance;
+ Vector3 extents;
+ Vector3 origin_offset;
+ bool box_projection;
+ bool enable_shadows;
+ bool interior;
+ Color interior_ambient;
+ float interior_ambient_energy;
+ float interior_ambient_probe_contribution;
+
+ uint32_t cull_mask;
+ UpdateMode update_mode;
+
+protected:
+
+ static void _bind_methods();
+ void _validate_property(PropertyInfo& property) const;
+
+public:
+
+ void set_intensity(float p_intensity);
+ float get_intensity() const;
+
+ void set_interior_ambient(Color p_ambient);
+ Color get_interior_ambient() const;
+
+ void set_interior_ambient_energy(float p_energy);
+ float get_interior_ambient_energy() const;
+
+ void set_interior_ambient_probe_contribution(float p_contribution);
+ float get_interior_ambient_probe_contribution() const;
+
+ void set_max_distance(float p_distance);
+ float get_max_distance() const;
+
+ void set_extents(const Vector3& p_extents);
+ Vector3 get_extents() const;
+
+ void set_origin_offset(const Vector3& p_extents);
+ Vector3 get_origin_offset() const;
+
+ void set_as_interior(bool p_enable);
+ bool is_set_as_interior() const;
+
+ void set_enable_box_projection(bool p_enable);
+ bool is_box_projection_enabled() const;
+
+ void set_enable_shadows(bool p_enable);
+ bool are_shadows_enabled() const;
+
+ void set_cull_mask(uint32_t p_layers);
+ uint32_t get_cull_mask() const;
+
+ void set_update_mode(UpdateMode p_mode);
+ UpdateMode get_update_mode() const;
+
+ virtual AABB get_aabb() const;
+ virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+
+
+ ReflectionProbe();
+ ~ReflectionProbe();
+};
+
+
+VARIANT_ENUM_CAST( ReflectionProbe::UpdateMode );
+
+#endif // REFLECTIONPROBE_H
diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp
index 3b4eb0b522..ea3200622e 100644
--- a/scene/3d/room_instance.cpp
+++ b/scene/3d/room_instance.cpp
@@ -75,50 +75,6 @@ void Room::_notification(int p_what) {
}
-RES Room::_get_gizmo_geometry() const {
-
- DVector<Face3> faces;
- if (!room.is_null())
- faces=room->get_geometry_hint();
-
- int count=faces.size();
- if (count==0)
- return RES();
-
- DVector<Face3>::Read facesr=faces.read();
-
- const Face3* facesptr=facesr.ptr();
-
- DVector<Vector3> points;
-
- Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
-
- Ref<FixedMaterial> mat( memnew( FixedMaterial ));
-
- mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.2,0.8,0.9,0.3) );
- mat->set_line_width(4);
- mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- mat->set_flag(Material::FLAG_UNSHADED,true);
-// mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-
- surface_tool->begin(Mesh::PRIMITIVE_LINES);
- surface_tool->set_material(mat);
-
- for (int i=0;i<count;i++) {
-
- surface_tool->add_vertex(facesptr[i].vertex[0]);
- surface_tool->add_vertex(facesptr[i].vertex[1]);
-
- surface_tool->add_vertex(facesptr[i].vertex[1]);
- surface_tool->add_vertex(facesptr[i].vertex[2]);
-
- surface_tool->add_vertex(facesptr[i].vertex[2]);
- surface_tool->add_vertex(facesptr[i].vertex[0]);
-
- }
-
- return surface_tool->commit();
-}
@@ -127,8 +83,9 @@ AABB Room::get_aabb() const {
if (room.is_null())
return AABB();
- return room->get_bounds().get_aabb();
+ return AABB();
}
+
DVector<Face3> Room::get_faces(uint32_t p_usage_flags) const {
return DVector<Face3>();
@@ -154,9 +111,6 @@ void Room::set_room( const Ref<RoomBounds>& p_room ) {
propagate_notification(NOTIFICATION_AREA_CHANGED);
update_gizmo();
- if (room.is_valid())
- SpatialSoundServer::get_singleton()->room_set_bounds(sound_room,room->get_bounds());
-
}
@@ -202,32 +156,6 @@ void Room::_parse_node_faces(DVector<Face3> &all_faces,const Node *p_node) const
}
-void Room::compute_room_from_subtree() {
-
-
- DVector<Face3> all_faces;
- _parse_node_faces(all_faces,this);
-
-
- if (all_faces.size()==0)
- return;
- float error;
- DVector<Face3> wrapped_faces = Geometry::wrap_geometry(all_faces,&error);
-
-
- if (wrapped_faces.size()==0)
- return;
-
- BSP_Tree tree(wrapped_faces,error);
-
- Ref<RoomBounds> room( memnew( RoomBounds ) );
- room->set_bounds(tree);
- room->set_geometry_hint(wrapped_faces);
-
- set_room(room);
-
-}
-
void Room::set_simulate_acoustics(bool p_enable) {
@@ -268,7 +196,6 @@ void Room::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_room","room:Room"),&Room::set_room );
ObjectTypeDB::bind_method(_MD("get_room:Room"),&Room::get_room );
- ObjectTypeDB::bind_method(_MD("compute_room_from_subtree"),&Room::compute_room_from_subtree);
diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h
index d0c7dd1268..b40665b498 100644
--- a/scene/3d/room_instance.h
+++ b/scene/3d/room_instance.h
@@ -45,6 +45,8 @@
*/
+
+
class Room : public VisualInstance {
OBJ_TYPE( Room, VisualInstance );
@@ -65,7 +67,7 @@ private:
void _bounds_changed();
- virtual RES _get_gizmo_geometry() const;
+
protected:
@@ -89,7 +91,6 @@ public:
void set_simulate_acoustics(bool p_enable);
bool is_simulating_acoustics() const;
- void compute_room_from_subtree();
RID get_sound_room() const;
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index 6ca954190f..dfc58dc4c3 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -163,7 +163,7 @@ void Skeleton::_notification(int p_what) {
Bone *bonesptr=&bones[0];
int len=bones.size();
- vs->skeleton_resize( skeleton, len ); // if same size, nothin really happens
+ vs->skeleton_allocate( skeleton, len ); // if same size, nothin really happens
// pose changed, rebuild cache of inverses
if (rest_global_inverse_dirty) {
@@ -513,51 +513,6 @@ void Skeleton::_make_dirty() {
}
-RES Skeleton::_get_gizmo_geometry() const {
-
- if (!GLOBAL_DEF("debug/draw_skeleton", true))
- return RES();
-
- if (bones.size()==0)
- return RES();
-
- Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
-
- Ref<FixedMaterial> mat( memnew( FixedMaterial ));
-
- mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.6,1.0,0.3,0.1) );
- mat->set_line_width(4);
- mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- mat->set_flag(Material::FLAG_UNSHADED,true);
- mat->set_flag(Material::FLAG_ONTOP,true);
-// mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-
- surface_tool->begin(Mesh::PRIMITIVE_LINES);
- surface_tool->set_material(mat);
-
-
- const Bone *bonesptr=&bones[0];
- int len=bones.size();
-
- for (int i=0;i<len;i++) {
-
- const Bone &b=bonesptr[i];
-
- Transform t;
- if (b.parent<0)
- continue;
-
- Vector3 v1=(bonesptr[b.parent].pose_global * bonesptr[b.parent].rest_global_inverse).xform(bonesptr[b.parent].rest_global_inverse.affine_inverse().origin);
- Vector3 v2=(b.pose_global * b.rest_global_inverse).xform(b.rest_global_inverse.affine_inverse().origin);
-
- surface_tool->add_vertex(v1);
- surface_tool->add_vertex(v2);
-
- }
-
- return surface_tool->commit();
-
-}
void Skeleton::localize_rests() {
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index ddecafd12c..37810e5466 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -84,7 +84,6 @@ class Skeleton : public Spatial {
return bound;
}
- virtual RES _get_gizmo_geometry() const;
protected:
diff --git a/scene/3d/spatial_player.cpp b/scene/3d/spatial_player.cpp
index 2bd94aac79..017f17226f 100644
--- a/scene/3d/spatial_player.cpp
+++ b/scene/3d/spatial_player.cpp
@@ -88,146 +88,6 @@ bool SpatialPlayer::_can_gizmo_scale() const {
return false;
}
-RES SpatialPlayer::_get_gizmo_geometry() const {
-
- Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
-
- Ref<FixedMaterial> mat( memnew( FixedMaterial ));
-
- mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.05) );
- mat->set_parameter( FixedMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) );
- mat->set_blend_mode( Material::BLEND_MODE_ADD );
- mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
-// mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true);
-
-
- surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
- surface_tool->set_material(mat);
-
- int sides=16;
- int sections=24;
-
-// float len=1;
- float deg=Math::deg2rad(params[PARAM_EMISSION_CONE_DEGREES]);
- if (deg==180)
- deg=179.5;
-
- Vector3 to=Vector3(0,0,-1);
-
- for(int j=0;j<sections;j++) {
-
- Vector3 p1=Matrix3(Vector3(1,0,0),deg*j/sections).xform(to);
- Vector3 p2=Matrix3(Vector3(1,0,0),deg*(j+1)/sections).xform(to);
-
- for(int i=0;i<sides;i++) {
-
- Vector3 p1r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p1);
- Vector3 p1s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p1);
- Vector3 p2s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p2);
- Vector3 p2r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p2);
-
- surface_tool->add_normal(p1r.normalized());
- surface_tool->add_vertex(p1r);
- surface_tool->add_normal(p1s.normalized());
- surface_tool->add_vertex(p1s);
- surface_tool->add_normal(p2s.normalized());
- surface_tool->add_vertex(p2s);
-
- surface_tool->add_normal(p1r.normalized());
- surface_tool->add_vertex(p1r);
- surface_tool->add_normal(p2s.normalized());
- surface_tool->add_vertex(p2s);
- surface_tool->add_normal(p2r.normalized());
- surface_tool->add_vertex(p2r);
-
- if (j==sections-1) {
-
- surface_tool->add_normal(p2r.normalized());
- surface_tool->add_vertex(p2r);
- surface_tool->add_normal(p2s.normalized());
- surface_tool->add_vertex(p2s);
- surface_tool->add_normal(Vector3(0,0,1));
- surface_tool->add_vertex(Vector3());
- }
- }
- }
-
-
- Ref<Mesh> mesh = surface_tool->commit();
-
- Ref<FixedMaterial> mat_speaker( memnew( FixedMaterial ));
-
- mat_speaker->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.3,0.3,0.6) );
- mat_speaker->set_parameter( FixedMaterial::PARAM_SPECULAR,Color(0.5,0.5,0.6) );
- //mat_speaker->set_blend_mode( Material::BLEND_MODE_MIX);
- //mat_speaker->set_flag(Material::FLAG_DOUBLE_SIDED,false);
- //mat_speaker->set_flag(Material::FLAG_UNSHADED,true);
-
- surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
- surface_tool->set_material(mat_speaker);
-
-// float radius=1;
-
-
- const int speaker_points=8;
- Vector3 speaker[speaker_points]={
- Vector3(0,0,1)*0.15,
- Vector3(1,1,1)*0.15,
- Vector3(1,1,0)*0.15,
- Vector3(2,2,-1)*0.15,
- Vector3(1,1,-1)*0.15,
- Vector3(0.8,0.8,-1.2)*0.15,
- Vector3(0.5,0.5,-1.4)*0.15,
- Vector3(0.0,0.0,-1.6)*0.15
- };
-
- int speaker_sides=10;
-
-
- for(int i = 0; i < speaker_sides ; i++) {
-
-
- Matrix3 ma(Vector3(0,0,1),Math_PI*2*float(i)/speaker_sides);
- Matrix3 mb(Vector3(0,0,1),Math_PI*2*float(i+1)/speaker_sides);
-
-
- for(int j=0;j<speaker_points-1;j++) {
-
- Vector3 points[4]={
- ma.xform(speaker[j]),
- mb.xform(speaker[j]),
- mb.xform(speaker[j+1]),
- ma.xform(speaker[j+1]),
- };
-
- Vector3 n = -Plane(points[0],points[1],points[2]).normal;
-
- surface_tool->add_normal(n);
- surface_tool->add_vertex(points[0]);
- surface_tool->add_normal(n);
- surface_tool->add_vertex(points[2]);
- surface_tool->add_normal(n);
- surface_tool->add_vertex(points[1]);
-
- surface_tool->add_normal(n);
- surface_tool->add_vertex(points[0]);
- surface_tool->add_normal(n);
- surface_tool->add_vertex(points[3]);
- surface_tool->add_normal(n);
- surface_tool->add_vertex(points[2]);
-
-
- }
-
-
- }
-
-
- return surface_tool->commit(mesh);
-
-}
-
-
void SpatialPlayer::_bind_methods() {
diff --git a/scene/3d/spatial_player.h b/scene/3d/spatial_player.h
index 258bf5e411..73a19eee4d 100644
--- a/scene/3d/spatial_player.h
+++ b/scene/3d/spatial_player.h
@@ -60,7 +60,7 @@ private:
RID source_rid;
virtual bool _can_gizmo_scale() const;
- virtual RES _get_gizmo_geometry() const;
+
protected:
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 155fe96ba7..5386680200 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -31,7 +31,6 @@
#include "servers/visual_server.h"
#include "room_instance.h"
#include "scene/scene_string_names.h"
-#include "baked_light_instance.h"
#include "skeleton.h"
AABB VisualInstance::get_transformed_aabb() const {
@@ -52,7 +51,7 @@ void VisualInstance::_notification(int p_what) {
Room *room=NULL;
bool is_geom = cast_to<GeometryInstance>();
- while(parent) {
+ /* while(parent) {
room = parent->cast_to<Room>();
if (room)
@@ -64,7 +63,7 @@ void VisualInstance::_notification(int p_what) {
}
parent=parent->get_parent_spatial();
- }
+ }*/
@@ -92,7 +91,7 @@ void VisualInstance::_notification(int p_what) {
VisualServer::get_singleton()->instance_set_scenario( instance, RID() );
VisualServer::get_singleton()->instance_set_room(instance,RID());
VisualServer::get_singleton()->instance_attach_skeleton( instance, RID() );
- VS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() );
+ // VS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() );
} break;
@@ -172,89 +171,78 @@ Ref<Material> GeometryInstance::get_material_override() const{
-void GeometryInstance::set_draw_range_begin(float p_dist){
+void GeometryInstance::set_lod_min_distance(float p_dist){
- draw_begin=p_dist;
- VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),draw_begin,draw_end);
+ lod_min_distance=p_dist;
+ VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),lod_min_distance,lod_max_distance,lod_min_hysteresis,lod_max_hysteresis);
}
-float GeometryInstance::get_draw_range_begin() const{
+float GeometryInstance::get_lod_min_distance() const{
- return draw_begin;
+ return lod_min_distance;
}
-void GeometryInstance::set_draw_range_end(float p_dist) {
+void GeometryInstance::set_lod_max_distance(float p_dist) {
- draw_end=p_dist;
- VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),draw_begin,draw_end);
+ lod_max_distance=p_dist;
+ VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),lod_min_distance,lod_max_distance,lod_min_hysteresis,lod_max_hysteresis);
}
-float GeometryInstance::get_draw_range_end() const {
+float GeometryInstance::get_lod_max_distance() const {
- return draw_end;
+ return lod_max_distance;
}
-void GeometryInstance::_notification(int p_what) {
+void GeometryInstance::set_lod_min_hysteresis(float p_dist){
- if (p_what==NOTIFICATION_ENTER_WORLD) {
+ lod_min_hysteresis=p_dist;
+ VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),lod_min_distance,lod_max_distance,lod_min_hysteresis,lod_max_hysteresis);
+}
- if (flags[FLAG_USE_BAKED_LIGHT]) {
+float GeometryInstance::get_lod_min_hysteresis() const{
- _find_baked_light();
- }
+ return lod_min_hysteresis;
+}
- _update_visibility();
- } else if (p_what==NOTIFICATION_EXIT_WORLD) {
+void GeometryInstance::set_lod_max_hysteresis(float p_dist) {
- if (flags[FLAG_USE_BAKED_LIGHT]) {
+ lod_max_hysteresis=p_dist;
+ VS::get_singleton()->instance_geometry_set_draw_range(get_instance(),lod_min_distance,lod_max_distance,lod_min_hysteresis,lod_max_hysteresis);
- if (baked_light_instance) {
- baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
- baked_light_instance=NULL;
- }
- _baked_light_changed();
+}
- }
+float GeometryInstance::get_lod_max_hysteresis() const {
- } if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
-
- _update_visibility();
- }
+ return lod_max_hysteresis;
+}
-}
+void GeometryInstance::_notification(int p_what) {
-void GeometryInstance::_baked_light_changed() {
+ if (p_what==NOTIFICATION_ENTER_WORLD) {
- if (!baked_light_instance)
- VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),RID());
- else
- VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),baked_light_instance->get_baked_light_instance());
+ if (flags[FLAG_USE_BAKED_LIGHT]) {
-}
+ }
-void GeometryInstance::_find_baked_light() {
+ _update_visibility();
- Node *n=get_parent();
- while(n) {
+ } else if (p_what==NOTIFICATION_EXIT_WORLD) {
- BakedLightInstance *bl=n->cast_to<BakedLightInstance>();
- if (bl) {
+ if (flags[FLAG_USE_BAKED_LIGHT]) {
- baked_light_instance=bl;
- baked_light_instance->connect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
- _baked_light_changed();
- return;
}
- n=n->get_parent();
+ } if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ _update_visibility();
}
- _baked_light_changed();
+
}
void GeometryInstance::_update_visibility() {
@@ -288,17 +276,6 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
}
if (p_flag==FLAG_USE_BAKED_LIGHT) {
- if (is_inside_world()) {
- if (!p_value) {
- if (baked_light_instance) {
- baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
- baked_light_instance=NULL;
- }
- _baked_light_changed();
- } else {
- _find_baked_light();
- }
- }
}
}
@@ -331,17 +308,8 @@ GeometryInstance::ShadowCastingSetting GeometryInstance::get_cast_shadows_settin
return shadow_casting_setting;
}
-void GeometryInstance::set_baked_light_texture_id(int p_id) {
-
- baked_light_texture_id=p_id;
- VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),baked_light_texture_id);
-
-}
-int GeometryInstance::get_baked_light_texture_id() const{
- return baked_light_texture_id;
-}
void GeometryInstance::set_extra_cull_margin(float p_margin) {
@@ -366,41 +334,43 @@ void GeometryInstance::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance::set_cast_shadows_setting);
ObjectTypeDB::bind_method(_MD("get_cast_shadows_setting"), &GeometryInstance::get_cast_shadows_setting);
- ObjectTypeDB::bind_method(_MD("set_draw_range_begin","mode"), &GeometryInstance::set_draw_range_begin);
- ObjectTypeDB::bind_method(_MD("get_draw_range_begin"), &GeometryInstance::get_draw_range_begin);
+ ObjectTypeDB::bind_method(_MD("set_lod_max_hysteresis","mode"), &GeometryInstance::set_lod_max_hysteresis);
+ ObjectTypeDB::bind_method(_MD("get_lod_max_hysteresis"), &GeometryInstance::get_lod_max_hysteresis);
+
+ ObjectTypeDB::bind_method(_MD("set_lod_max_distance","mode"), &GeometryInstance::set_lod_max_distance);
+ ObjectTypeDB::bind_method(_MD("get_lod_max_distance"), &GeometryInstance::get_lod_max_distance);
+
+ ObjectTypeDB::bind_method(_MD("set_lod_min_hysteresis","mode"), &GeometryInstance::set_lod_min_hysteresis);
+ ObjectTypeDB::bind_method(_MD("get_lod_min_hysteresis"), &GeometryInstance::get_lod_min_hysteresis);
- ObjectTypeDB::bind_method(_MD("set_draw_range_end","mode"), &GeometryInstance::set_draw_range_end);
- ObjectTypeDB::bind_method(_MD("get_draw_range_end"), &GeometryInstance::get_draw_range_end);
+ ObjectTypeDB::bind_method(_MD("set_lod_min_distance","mode"), &GeometryInstance::set_lod_min_distance);
+ ObjectTypeDB::bind_method(_MD("get_lod_min_distance"), &GeometryInstance::get_lod_min_distance);
- ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id);
- ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id);
ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin);
ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
ObjectTypeDB::bind_method(_MD("get_aabb"),&GeometryInstance::get_aabb);
- ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "geometry/material_override",PROPERTY_HINT_RESOURCE_TYPE,"Material"), _SCS("set_material_override"), _SCS("get_material_override"));
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), _SCS("set_cast_shadows_setting"), _SCS("get_cast_shadows_setting"));
- ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/receive_shadows"), _SCS("set_flag"), _SCS("get_flag"),FLAG_RECEIVE_SHADOWS);
- ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_begin",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_begin"), _SCS("get_draw_range_begin"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_end",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_end"), _SCS("get_draw_range_end"));
ADD_PROPERTY( PropertyInfo( Variant::REAL, "geometry/extra_cull_margin",PROPERTY_HINT_RANGE,"0,16384,0"), _SCS("set_extra_cull_margin"), _SCS("get_extra_cull_margin"));
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
- ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_distance"), _SCS("get_lod_min_distance"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_hysteresis",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_hysteresis"), _SCS("get_lod_min_hysteresis"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/max_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_max_distance"), _SCS("get_lod_max_distance"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/max_hysteresis",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_max_hysteresis"), _SCS("get_lod_max_hysteresis"));
// ADD_SIGNAL( MethodInfo("visibility_changed"));
BIND_CONSTANT(FLAG_VISIBLE );
BIND_CONSTANT(FLAG_CAST_SHADOW );
- BIND_CONSTANT(FLAG_RECEIVE_SHADOWS );
BIND_CONSTANT(FLAG_BILLBOARD );
BIND_CONSTANT(FLAG_BILLBOARD_FIX_Y );
BIND_CONSTANT(FLAG_DEPH_SCALE );
@@ -415,20 +385,21 @@ void GeometryInstance::_bind_methods() {
}
GeometryInstance::GeometryInstance() {
- draw_begin=0;
- draw_end=0;
+ lod_min_distance=0;
+ lod_max_distance=0;
+ lod_min_hysteresis=0;
+ lod_max_hysteresis=0;
+
for(int i=0;i<FLAG_MAX;i++) {
flags[i]=false;
}
flags[FLAG_VISIBLE]=true;
flags[FLAG_CAST_SHADOW]=true;
- flags[FLAG_RECEIVE_SHADOWS]=true;
+
shadow_casting_setting=SHADOW_CASTING_SETTING_ON;
- baked_light_instance=NULL;
- baked_light_texture_id=0;
extra_cull_margin=0;
- VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
+// VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
}
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 1670c4679a..5fa2eeeeda 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -79,7 +79,7 @@ public:
};
-class BakedLightInstance;
+class BakedLight;
class GeometryInstance : public VisualInstance {
@@ -89,7 +89,6 @@ public:
enum Flags {
FLAG_VISIBLE=VS::INSTANCE_FLAG_VISIBLE,
FLAG_CAST_SHADOW=VS::INSTANCE_FLAG_CAST_SHADOW,
- FLAG_RECEIVE_SHADOWS=VS::INSTANCE_FLAG_RECEIVE_SHADOWS,
FLAG_BILLBOARD=VS::INSTANCE_FLAG_BILLBOARD,
FLAG_BILLBOARD_FIX_Y=VS::INSTANCE_FLAG_BILLBOARD_FIX_Y,
FLAG_DEPH_SCALE=VS::INSTANCE_FLAG_DEPH_SCALE,
@@ -98,6 +97,7 @@ public:
FLAG_MAX=VS::INSTANCE_FLAG_MAX,
};
+
enum ShadowCastingSetting {
SHADOW_CASTING_SETTING_OFF=VS::SHADOW_CASTING_SETTING_OFF,
SHADOW_CASTING_SETTING_ON = VS::SHADOW_CASTING_SETTING_ON,
@@ -110,14 +110,13 @@ private:
bool flags[FLAG_MAX];
ShadowCastingSetting shadow_casting_setting;
Ref<Material> material_override;
- float draw_begin;
- float draw_end;
- void _find_baked_light();
- BakedLightInstance *baked_light_instance;
- int baked_light_texture_id;
+ float lod_min_distance;
+ float lod_max_distance;
+ float lod_min_hysteresis;
+ float lod_max_hysteresis;
+
float extra_cull_margin;
- void _baked_light_changed();
void _update_visibility();
protected:
@@ -131,18 +130,21 @@ public:
void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting);
ShadowCastingSetting get_cast_shadows_setting() const;
- void set_draw_range_begin(float p_dist);
- float get_draw_range_begin() const;
+ void set_lod_min_distance(float p_dist);
+ float get_lod_min_distance() const;
+
+ void set_lod_max_distance(float p_dist);
+ float get_lod_max_distance() const;
- void set_draw_range_end(float p_dist);
- float get_draw_range_end() const;
+ void set_lod_min_hysteresis(float p_dist);
+ float get_lod_min_hysteresis() const;
+
+ void set_lod_max_hysteresis(float p_dist);
+ float get_lod_max_hysteresis() const;
void set_material_override(const Ref<Material>& p_material);
Ref<Material> get_material_override() const;
- void set_baked_light_texture_id(int p_id);
- int get_baked_light_texture_id() const;
-
void set_extra_cull_margin(float p_margin);
float get_extra_cull_margin() const;