#include "baked_light_baker.h" #include #include #include "io/marshalls.h" #include "tools/editor/editor_node.h" BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref& p_tex) { if (!tex_map.has(p_tex)) { Ref imgtex=p_tex; if (imgtex.is_null()) return NULL; Image image=imgtex->get_data(); if (image.empty()) return NULL; if (image.get_format()!=Image::FORMAT_RGBA) { if (image.get_format()>Image::FORMAT_INDEXED_ALPHA) { Error err = image.decompress(); if (err) return NULL; } if (image.get_format()!=Image::FORMAT_RGBA) image.convert(Image::FORMAT_RGBA); } DVector dvt=image.get_data(); DVector::Read r=dvt.read(); MeshTexture mt; mt.tex_w=image.get_width(); mt.tex_h=image.get_height(); int len = image.get_width()*image.get_height()*4; mt.tex.resize(len); copymem(mt.tex.ptr(),r.ptr(),len); textures.push_back(mt); tex_map[p_tex]=&textures.back()->get(); } return tex_map[p_tex]; } void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform) { for(int i=0;iget_surface_count();i++) { if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES) continue; Ref mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i); MeshMaterial *matptr=NULL; if (mat.is_valid()) { if (!mat_map.has(mat)) { MeshMaterial mm; Ref fm = mat; if (fm.is_valid()) { //fixed route mm.diffuse.color=fm->get_parameter(FixedMaterial::PARAM_DIFFUSE); mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_DIFFUSE)); mm.specular.color=fm->get_parameter(FixedMaterial::PARAM_SPECULAR); mm.specular.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_SPECULAR)); } else { mm.diffuse.color=Color(1,1,1,1); mm.diffuse.tex=NULL; mm.specular.color=Color(0,0,0,1); mm.specular.tex=NULL; } materials.push_back(mm); mat_map[mat]=&materials.back()->get(); } matptr=mat_map[mat]; } int facecount=0; if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { facecount=p_mesh->surface_get_array_index_len(i); } else { facecount=p_mesh->surface_get_array_len(i); } ERR_CONTINUE((facecount==0 || (facecount%3)!=0)); facecount/=3; int tbase=triangles.size(); triangles.resize(facecount+tbase); Array a = p_mesh->surface_get_arrays(i); DVector vertices = a[Mesh::ARRAY_VERTEX]; DVector::Read vr=vertices.read(); DVector uv; DVector::Read uvr; DVector normal; DVector::Read normalr; bool read_uv=false; bool read_normal=false; if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV) { uv=a[Mesh::ARRAY_TEX_UV]; uvr=uv.read(); read_uv=true; } if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_NORMAL) { normal=a[Mesh::ARRAY_NORMAL]; normalr=normal.read(); read_normal=true; } Matrix3 normal_xform = p_xform.basis.inverse().transposed(); if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) { DVector indices = a[Mesh::ARRAY_INDEX]; DVector::Read ir = indices.read(); for(int i=0;icast_to()) { MeshInstance *meshi=p_node->cast_to(); Ref mesh=meshi->get_mesh(); if (mesh.is_valid()) { _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform()); } } else if (p_node->cast_to()) { Light *dl=p_node->cast_to(); if (dl->get_bake_mode()!=Light::BAKE_MODE_DISABLED) { LightData dirl; dirl.type=VS::LightType(dl->get_light_type()); dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE); dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR); dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY); dirl.pos=dl->get_global_transform().origin; dirl.up=dl->get_global_transform().basis.get_axis(1).normalized(); dirl.left=dl->get_global_transform().basis.get_axis(0).normalized(); dirl.dir=-dl->get_global_transform().basis.get_axis(2).normalized(); dirl.spot_angle=dl->get_parameter(DirectionalLight::PARAM_SPOT_ANGLE); dirl.spot_attenuation=dl->get_parameter(DirectionalLight::PARAM_SPOT_ATTENUATION); dirl.attenuation=dl->get_parameter(DirectionalLight::PARAM_ATTENUATION); dirl.radius=dl->get_parameter(DirectionalLight::PARAM_RADIUS); dirl.bake_direct=dl->get_bake_mode()==Light::BAKE_MODE_FULL; dirl.rays_thrown=0; lights.push_back(dirl); } } else if (p_node->cast_to()){ Spatial *sp = p_node->cast_to(); Array arr = p_node->call("_get_baked_light_meshes"); for(int i=0;i mesh=arr[i+1]; _add_mesh(mesh,Ref(),base_inv * (sp->get_global_transform() * xform)); } } for(int i=0;iget_child_count();i++) { _parse_geometry(p_node->get_child(i)); } } void BakedLightBaker::_fix_lights() { total_light_area=0; for(int i=0;iup_max) up_max=up_d; if (up_dleft_max) left_max=left_d; if (left_ddir_max) dir_max=dir_d; if (dir_dmax_depth) { max_depth=p_depth; } if (p_size==1) { return p_children[0]; } else if (p_size==0) { return NULL; } AABB aabb; aabb=p_children[0]->aabb; for(int i=1;iaabb); } int li=aabb.get_longest_axis_index(); switch(li) { case Vector3::AXIS_X: { SortArray sort_x; sort_x.nth_element(0,p_size,p_size/2,p_children); //sort_x.sort(&p_bb[p_from],p_size); } break; case Vector3::AXIS_Y: { SortArray sort_y; sort_y.nth_element(0,p_size,p_size/2,p_children); //sort_y.sort(&p_bb[p_from],p_size); } break; case Vector3::AXIS_Z: { SortArray sort_z; sort_z.nth_element(0,p_size,p_size/2,p_children); //sort_z.sort(&p_bb[p_from],p_size); } break; } BVH* left = _parse_bvh(p_children,p_size/2,p_depth+1,max_depth); BVH* right = _parse_bvh(&p_children[p_size/2],p_size-p_size/2,p_depth+1,max_depth); BVH *_new = memnew(BVH); _new->aabb=aabb; _new->center=aabb.pos+aabb.size*0.5; _new->children[0]=left; _new->children[1]=right; _new->leaf=NULL; return _new; } void BakedLightBaker::_make_bvh() { Vector bases; bases.resize(triangles.size()); int max_depth=0; for(int i=0;ileaf=&triangles[i]; bases[i]->aabb.pos=triangles[i].vertices[0]; bases[i]->aabb.expand_to(triangles[i].vertices[1]); bases[i]->aabb.expand_to(triangles[i].vertices[2]); triangles[i].aabb=bases[i]->aabb; bases[i]->center=bases[i]->aabb.pos+bases[i]->aabb.size*0.5; } bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth); ray_stack = memnew_arr(uint32_t,max_depth); bvh_stack = memnew_arr(BVH*,max_depth); } void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_depth) { uint32_t *stack=octant_stack; uint32_t *ptr_stack=octantptr_stack; Octant *octants=octant_pool.ptr(); stack[0]=0; ptr_stack[0]=0; int stack_pos=0; while(true) { Octant *octant=&octants[ptr_stack[stack_pos]]; if (stack[stack_pos]<8) { int i = stack[stack_pos]; stack[stack_pos]++; //fit_aabb=fit_aabb.grow(bvh->aabb.size.x*0.0001); int child_idx =octant->children[i]; bool encloses; if (!child_idx) { AABB aabb=octant->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.grow_by(cell_size*octree_extra_margin); if (!aabb.intersects(p_triangle->aabb)) continue; encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb); if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb)) continue; } else { Octant *child=&octants[child_idx]; AABB aabb=child->aabb; aabb.grow_by(cell_size*octree_extra_margin); if (!aabb.intersects(p_triangle->aabb)) continue; encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb); if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb)) continue; } if (encloses) stack[stack_pos]=8; // quick and dirty opt if (!child_idx) { if (octant_pool_size==octant_pool.size()) { octant_pool.resize(octant_pool_size+OCTANT_POOL_CHUNK); octants=octant_pool.ptr(); octant=&octants[ptr_stack[stack_pos]]; } child_idx=octant_pool_size++; octant->children[i]=child_idx; Octant *child=&octants[child_idx]; child->aabb=octant->aabb; child->texture_x=0; child->texture_y=0; child->aabb.size*=0.5; if (i&1) child->aabb.pos.x+=child->aabb.size.x; if (i&2) child->aabb.pos.y+=child->aabb.size.y; if (i&4) child->aabb.pos.z+=child->aabb.size.z; if (stack_pos==octree_depth-1) { child->leaf=true; child->offset[0]=child->aabb.pos.x+child->aabb.size.x*0.5; child->offset[1]=child->aabb.pos.y+child->aabb.size.y*0.5; child->offset[2]=child->aabb.pos.z+child->aabb.size.z*0.5; child->next_leaf=leaf_list; for(int ci=0;ci<8;ci++) { child->normal_accum[ci][0]=0; child->normal_accum[ci][1]=0; child->normal_accum[ci][2]=0; } child->bake_neighbour=0; child->first_neighbour=true; leaf_list=child_idx; cell_count++; int lz = lights.size(); child->light = memnew_arr(OctantLight,lz); for(int li=0;lilight[li].accum[ci][0]=0; child->light[li].accum[ci][1]=0; child->light[li].accum[ci][2]=0; } } child->parent=ptr_stack[stack_pos]; } else { child->leaf=false; for(int j=0;j<8;j++) { child->children[j]=0; } } } if (!octants[child_idx].leaf) { stack_pos++; stack[stack_pos]=0; ptr_stack[stack_pos]=child_idx; } else { Octant *child=&octants[child_idx]; Vector3 n = Plane(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).normal; for(int ci=0;ci<8;ci++) { Vector3 pos = child->aabb.pos; if (ci&1) pos.x+=child->aabb.size.x; if (ci&2) pos.y+=child->aabb.size.y; if (ci&4) pos.z+=child->aabb.size.z; pos.x=floor((pos.x+cell_size*0.5)/cell_size); pos.y=floor((pos.y+cell_size*0.5)/cell_size); pos.z=floor((pos.z+cell_size*0.5)/cell_size); Map::Element *E=endpoint_normal.find(pos); if (!E) { endpoint_normal[pos]=n; } else { E->get()+=n; } } } } else { stack_pos--; if (stack_pos<0) break; } } } void BakedLightBaker::_make_octree() { AABB base = bvh->aabb; float lal=base.get_longest_axis_size(); //must be square because we want square blocks base.size.x=lal; base.size.y=lal; base.size.z=lal; base.grow_by(lal*0.001); //for precision octree_aabb=base; cell_size=base.size.x; for(int i=0;ileaf=false; root->aabb=octree_aabb; root->parent=-1; for(int i=0;i<8;i++) root->children[i]=0; EditorProgress ep("bake_octree","Parsing "+itos(triangles.size())+" Triangles:",triangles.size()); for(int i=0;iaabb.pos; if (ci&1) pos.x+=oct->aabb.size.x; if (ci&2) pos.y+=oct->aabb.size.y; if (ci&4) pos.z+=oct->aabb.size.z; pos.x=floor((pos.x+cell_size*0.5)/cell_size); pos.y=floor((pos.y+cell_size*0.5)/cell_size); pos.z=floor((pos.z+cell_size*0.5)/cell_size); Map::Element *E=endpoint_normal.find(pos); if (!E) { //? print_line("lolwut?"); } else { Vector3 n = E->get().normalized(); oct->normal_accum[ci][0]=n.x; oct->normal_accum[ci][1]=n.y; oct->normal_accum[ci][2]=n.z; } } oct_idx=oct->next_leaf; } } } void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light, const Plane& p_plane) { //stackless version uint32_t *stack=octant_stack; uint32_t *ptr_stack=octantptr_stack; Octant *octants=octant_pool.ptr(); stack[0]=0; ptr_stack[0]=0; int stack_pos=0; while(true) { Octant &octant=octants[ptr_stack[stack_pos]]; if (octant.leaf) { //if (p_plane.normal.dot(octant.aabb.get_support(p_plane.normal)) < p_plane.d-CMP_EPSILON) { //octants behind are no go float r=cell_size*plot_size; for(int i=0;i<8;i++) { Vector3 pos=octant.aabb.pos; if (i&1) pos.x+=octant.aabb.size.x; if (i&2) pos.y+=octant.aabb.size.y; if (i&4) pos.z+=octant.aabb.size.z; float d = p_plot_pos.distance_to(pos); if (d<=r) { float intensity = 1.0 - (d/r)*(d/r); //not gauss but.. float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]))); intensity*=pow(damp,edge_damp); //intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size); octant.light[p_light_index].accum[i][0]+=p_light.r*intensity; octant.light[p_light_index].accum[i][1]+=p_light.g*intensity; octant.light[p_light_index].accum[i][2]+=p_light.b*intensity; } } stack_pos--; } else if (stack[stack_pos]<8) { int i = stack[stack_pos]; stack[stack_pos]++; if (!octant.children[i]) { continue; } Octant &child=octants[octant.children[i]]; if (!child.aabb.intersects(p_plot_aabb)) continue; if (child.aabb.encloses(p_plot_aabb)) { stack[stack_pos]=8; //don't test the rest } stack_pos++; stack[stack_pos]=0; ptr_stack[stack_pos]=octant.children[i]; } else { stack_pos--; if (stack_pos<0) break; } } } float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce) { uint32_t* stack = ray_stack; BVH **bstack = bvh_stack; enum { TEST_AABB_BIT=0, VISIT_LEFT_BIT=1, VISIT_RIGHT_BIT=2, VISIT_DONE_BIT=3, }; Vector3 n = (p_end-p_begin); float len=n.length(); if (len==0) return 0; n/=len; real_t d=1e10; bool inters=false; Vector3 r_normal; Vector3 r_point; Vector3 end=p_end; Triangle *triangle=NULL; //for(int i=0;ivertices[0],b.leaf->vertices[1],b.leaf->vertices[2]); Vector3 res; if (f3.intersects_segment(p_begin,end,&res)) { float nd = n.dot(res); if (ndget_uv_and_normal(r_point,uv,r_normal); } else { } if (n.dot(r_normal)>0) r_normal=-r_normal; //ok... Color diffuse_at_point(0.8,0.8,0.8); Color specular_at_point(0.0,0.0,0.0); float dist = p_begin.distance_to(r_point); AABB aabb; aabb.pos=r_point; aabb.pos-=Vector3(1,1,1)*cell_size*plot_size; aabb.size=Vector3(2,2,2)*cell_size*plot_size; Color res_light=p_light; float att=1.0; float dp=(1.0-normal_damp)*n.dot(-r_normal)+normal_damp; if (p_att_curve) { p_att_pos+=dist; int cpos = Math::fast_ftoi((p_att_pos/p_att_curve_len)*ATTENUATION_CURVE_LEN); cpos=CLAMP(cpos,0,ATTENUATION_CURVE_LEN-1); att=p_att_curve[cpos]; } res_light.r*=dp; res_light.g*=dp; res_light.b*=dp; //light is plotted before multiplication with diffuse, this way //the multiplication can happen with more detail in the shader float ret=1e6; if (p_bounces>0) { p_rest-=dist; if (p_restmaterial) { //triangle->get_uv(r_point); diffuse_at_point=triangle->material->diffuse.get_color(uv); specular_at_point=triangle->material->specular.get_color(uv); } diffuse_at_point.r=res_light.r*diffuse_at_point.r; diffuse_at_point.g=res_light.g*diffuse_at_point.g; diffuse_at_point.b=res_light.b*diffuse_at_point.b; specular_at_point.r=res_light.r*specular_at_point.r; specular_at_point.g=res_light.g*specular_at_point.g; specular_at_point.b=res_light.b*specular_at_point.b; if (use_diffuse && (diffuse_at_point.r>CMP_EPSILON || diffuse_at_point.g>CMP_EPSILON || diffuse_at_point.b>CMP_EPSILON)) { //diffuse bounce Vector3 c1=r_normal.cross(n).normalized(); Vector3 c2=r_normal.cross(c1).normalized(); double r1 = double(rand())/RAND_MAX; double r2 = double(rand())/RAND_MAX; double r3 = double(rand())/RAND_MAX; #if 0 Vector3 next = - ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*(r3-0.5))).normalized()*0.5 + r_normal*0.5; if (next==Vector3()) next=r_normal; Vector3 rn=next.normalized(); #else Vector3 rn = ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*r3*0.5)).normalized(); #endif ret=_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1); } if (use_specular && (specular_at_point.r>CMP_EPSILON || specular_at_point.g>CMP_EPSILON || specular_at_point.b>CMP_EPSILON)) { //specular bounce //Vector3 c1=r_normal.cross(n).normalized(); //Vector3 c2=r_normal.cross(c1).normalized(); Vector3 rn = n - r_normal *r_normal.dot(n) * 2.0; _throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1); } } //specular later // _plot_light_point(r_point,octree,octree_aabb,p_light); Color plot_light=res_light; plot_light.r*=att; plot_light.g*=att; plot_light.b*=att; if (!p_first_bounce) { float r = plot_size * cell_size; if (ret octant_hashing; octant_hashing.resize(octant_pool_size); Vector hash_table; int hash_table_size=Math::larger_prime(16384); hash_table.resize(hash_table_size); uint32_t*hashptr = hash_table.ptr(); OctantHash*octhashptr = octant_hashing.ptr(); for(int i=0;iaabb.pos - octree_aabb.pos; //make sure is always positive base=int((pos.x+cell_size*0.5)/cell_size); base<<=16; base|=int((pos.y+cell_size*0.5)/cell_size); base<<=16; base|=int((pos.z+cell_size*0.5)/cell_size); uint32_t hash = HashMapHahserDefault::hash(base); uint32_t idx = hash % hash_table_size; octhashptr[oct_idx].next=hashptr[idx]; octhashptr[oct_idx].hash=hash; octhashptr[oct_idx].value=base; hashptr[idx]=oct_idx; oct_idx=oct->next_leaf; } //step 2 find neighbours oct_idx=leaf_list; int neighbours=0; while(oct_idx) { BakedLightBaker::Octant *oct = &octants[oct_idx]; Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive pos.x+=cell_size; uint64_t base=0; base=int((pos.x+cell_size*0.5)/cell_size); base<<=16; base|=int((pos.y+cell_size*0.5)/cell_size); base<<=16; base|=int((pos.z+cell_size*0.5)/cell_size); uint32_t hash = HashMapHahserDefault::hash(base); uint32_t idx = hash % hash_table_size; uint32_t bucket = hashptr[idx]; while(bucket) { if (octhashptr[bucket].value==base) { oct->bake_neighbour=bucket; octants[bucket].first_neighbour=false; neighbours++; break; } bucket = octhashptr[bucket].next; } oct_idx=oct->next_leaf; } print_line("octant with neighbour: "+itos(neighbours)); } //ok let's try to just create a texture { int otex_w=(1<texture_x=0; oct->texture_y=0; oct_idx=oct->next_leaf; } oct_idx=leaf_list; print_line("begin at row "+itos(row)); int longest_line_reused=0; int col=0; int processed=0; while(oct_idx) { BakedLightBaker::Octant *oct = &octants[oct_idx]; if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) { //was not processed uint32_t current_idx=oct_idx; int reused=0; while(current_idx) { BakedLightBaker::Octant *o = &octants[current_idx]; if (col+1 >= otex_w) { col=0; row+=4; } o->texture_x=col; o->texture_y=row; processed++; if (o->bake_neighbour) { reused++; } col+=o->bake_neighbour ? 1 : 2; //reuse neighbour current_idx=o->bake_neighbour; } if (reused>longest_line_reused) { longest_line_reused=reused; } } oct_idx=oct->next_leaf; } print_line("processed "+itos(processed)); print_line("longest reused: "+itos(longest_line_reused)); col=0; row+=4; print_line("end at row "+itos(row)); //put octree, no need for recursion, just loop backwards. int regular_octants=0; for(int i=octant_pool_size-1;i>=0;i--) { BakedLightBaker::Octant *oct = &octants[i]; if (oct->leaf) //ignore leaf continue; if (oct->aabb.size.x>lattice_cell_size.x*1.1) { //bigger than latice, skip oct->texture_x=0; oct->texture_y=0; } else if (oct->aabb.size.x>lattice_cell_size.x*0.8) { //this is the initial lattice Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive int x = int((pos.x+lattice_cell_size.x*0.5)/lattice_cell_size.x); int y = int((pos.y+lattice_cell_size.y*0.5)/lattice_cell_size.y); int z = int((pos.z+lattice_cell_size.z*0.5)/lattice_cell_size.z); //bug net ERR_FAIL_INDEX(x,(1<texture_x=ofs%otex_w; oct->texture_y=(ofs/otex_w)*4+4; */ oct->texture_x=(x+(1<texture_y=4+y*4; //print_line("pos: "+itos(x)+","+itos(y)+","+itos(z)+" - ofs"+itos(oct->texture_x)+","+itos(oct->texture_y)); } else { //an everyday regular octant if (col+2 > otex_w) { col=0; row+=4; } oct->texture_x=col; oct->texture_y=row; col+=2; regular_octants++; } } print_line("octants end at row "+itos(row)+" totalling"+itos(regular_octants)); //ok evaluation. if (otex_w<=2048 && row>2048) { //too big upwards, try bigger texture otex_w*=2; continue; } else { baked_octree_texture_w=otex_w; baked_octree_texture_h=row+4; break; } } } baked_octree_texture_h=nearest_power_of_2(baked_octree_texture_h); print_line("RESULT! "+itos(baked_octree_texture_w)+","+itos(baked_octree_texture_h)); } double BakedLightBaker::get_normalization(int p_light_idx) const { double nrg=0; const LightData &dl=lights[p_light_idx]; double cell_area = cell_size*cell_size;; //nrg+= /*dl.energy */ (dl.rays_thrown * cell_area / dl.area); nrg=dl.rays_thrown * cell_area; nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel nrg*=dl.constant; //nrg*=5; print_line("CS: "+rtos(cell_size)); return nrg; } void BakedLightBaker::throw_rays(int p_amount) { for(int i=0;i &p_light, Node* p_node) { if (baking) return; cell_count=0; base_inv=p_node->cast_to()->get_global_transform().affine_inverse(); EditorProgress ep("bake","Light Baker Setup:",5); baked_light=p_light; lattice_size=baked_light->get_initial_lattice_subdiv(); octree_depth=baked_light->get_cell_subdivision(); plot_size=baked_light->get_plot_size(); max_bounces=baked_light->get_bounces(); use_diffuse=baked_light->get_bake_flag(BakedLight::BAKE_DIFFUSE); use_specular=baked_light->get_bake_flag(BakedLight::BAKE_SPECULAR); use_translucency=baked_light->get_bake_flag(BakedLight::BAKE_TRANSLUCENT); edge_damp=baked_light->get_edge_damp(); normal_damp=baked_light->get_normal_damp(); octree_extra_margin=baked_light->get_cell_extra_margin(); ep.step("Parsing Geometry",0); _parse_geometry(p_node); mat_map.clear(); tex_map.clear(); print_line("\ttotal triangles: "+itos(triangles.size())); ep.step("Fixing Lights",1); _fix_lights(); ep.step("Making BVH",2); _make_bvh(); ep.step("Creating Light Octree",3); _make_octree(); ep.step("Creating Octree Texture",4); _make_octree_texture(); baking=true; _start_thread(); } void BakedLightBaker::update_octree_image(DVector &p_image) { int len = baked_octree_texture_w*baked_octree_texture_h*4; p_image.resize(len); DVector::Write w = p_image.write(); zeromem(w.ptr(),len); float gamma = baked_light->get_gamma_adjust(); float mult = baked_light->get_energy_multiplier(); for(int i=0;iget_format()==BakedLight::FORMAT_HDR8) multiplier=8; encode_uint32(baked_octree_texture_w,&w[0]); encode_uint32(baked_octree_texture_h,&w[4]); encode_uint32(0,&w[8]); encode_float(1< norm_arr; norm_arr.resize(lights.size()); for(int i=0;i>8; iptr[1]=choct.texture_x&0xFF; iptr[2]=choct.texture_y>>8; iptr[3]=choct.texture_y&0xFF; } } } } void BakedLightBaker::_free_bvh(BVH* p_bvh) { if (!p_bvh->leaf) { if (p_bvh->children[0]) _free_bvh(p_bvh->children[0]); if (p_bvh->children[1]) _free_bvh(p_bvh->children[1]); } memdelete(p_bvh); } bool BakedLightBaker::is_baking() { return baking; } void BakedLightBaker::set_pause(bool p_pause){ if (paused==p_pause) return; paused=p_pause; if (paused) { _stop_thread(); } else { _start_thread(); } } bool BakedLightBaker::is_paused() { return paused; } void BakedLightBaker::_bake_thread_func(void *arg) { BakedLightBaker *ble = (BakedLightBaker*)arg; ble->rays_at_snap_time=ble->total_rays; ble->snap_time=OS::get_singleton()->get_ticks_usec(); while(!ble->bake_thread_exit) { ble->throw_rays(1000); uint64_t t=OS::get_singleton()->get_ticks_usec(); if (t-ble->snap_time>1000000) { double time = (t-ble->snap_time)/1000000.0; int rays=ble->total_rays-ble->rays_at_snap_time; ble->rays_sec=int(rays/time); ble->snap_time=OS::get_singleton()->get_ticks_usec(); ble->rays_at_snap_time=ble->total_rays; } } } void BakedLightBaker::_start_thread() { if (thread!=NULL) return; bake_thread_exit=false; thread=Thread::create(_bake_thread_func,this); } void BakedLightBaker::_stop_thread() { if (thread==NULL) return; bake_thread_exit=true; Thread::wait_to_finish(thread); thread=NULL; } void BakedLightBaker::clear() { _stop_thread(); if (bvh) _free_bvh(bvh); if (ray_stack) memdelete_arr(ray_stack); if (octant_stack) memdelete_arr(octant_stack); if (octantptr_stack) memdelete_arr(octantptr_stack); if (bvh_stack) memdelete_arr(bvh_stack); for(int i=0;i(); total_rays=0; } BakedLightBaker::BakedLightBaker() { octree_depth=9; lattice_size=4; octant_pool.clear(); octant_pool_size=0; bvh=NULL; leaf_list=0; cell_count=0; ray_stack=NULL; bvh_stack=NULL; octant_stack=NULL; octantptr_stack=NULL; plot_size=2.5; max_bounces=2; materials.clear(); baked_octree_texture_w=0; baked_octree_texture_h=0; paused=false; baking=false; thread=NULL; bake_thread_exit=false; rays_at_snap_time=0; snap_time=0; rays_sec=0; total_rays=0; } BakedLightBaker::~BakedLightBaker() { clear(); }