virtual void Execute() { CDB::COLLIDER DB; DB.ray_options (CDB::OPT_ONLYFIRST); xr_vector<R_Light> Lights = g_lights; Fvector P,D,PLP; D.set (0,1,0); float coeff = 0.5f*g_params.fPatchSize/float(LIGHT_Count); LSelection Selected; float LperN = float(g_lights.size()); for (u32 i=Nstart; i<Nend; i++) { vertex& N = g_nodes[i]; // select lights Selected.clear(); for (u32 L=0; L<Lights.size(); L++) { R_Light& R = g_lights[L]; if (R.type==LT_DIRECT) Selected.push_back(&R); else { float dist = N.Pos.distance_to(R.position); if (dist-g_params.fPatchSize < R.range) Selected.push_back(&R); } } LperN = 0.9f*LperN + 0.1f*float(Selected.size()); // lighting itself float amount=0; for (int x=-LIGHT_Count; x<=LIGHT_Count; x++) { P.x = N.Pos.x + coeff*float(x); for (int z=-LIGHT_Count; z<=LIGHT_Count; z++) { // compute position P.z = N.Pos.z + coeff*float(z); P.y = N.Pos.y; N.Plane.intersectRayPoint(P,D,PLP); // "project" position P.y = PLP.y; // light point amount += LightPoint(DB,P,N.Plane.n,Selected); } } // calculation of luminocity N.LightLevel = amount/float(LIGHT_Total); thProgress = float(i-Nstart)/float(Nend-Nstart); } }
virtual void Execute () { CDB::COLLIDER DB; DB.ray_options (0); u32 counter = 0; for (;; counter++) { u32 id = VLT.get(); if (id==VLT_END) break; Vertex* V = g_vertices[id]; R_ASSERT (V); // Get transluency factor float v_trans = 0.f; BOOL bVertexLight= FALSE; u32 L_flags = 0; for (u32 f=0; f<V->adjacent.size(); f++) { Face* F = V->adjacent [f]; v_trans += F->Shader().vert_translucency; if (F->Shader().flags.bLIGHT_Vertex) bVertexLight = TRUE; } v_trans /= float(V->adjacent.size()); // if (bVertexLight) { base_color_c vC, old; V->C._get (old); LightPoint (&DB, RCAST_Model, vC, V->P, V->N, pBuild->L_static, (b_nosun?LP_dont_sun:0)|LP_dont_hemi, 0); vC._tmp_ = v_trans; vC.mul (.5f); vC.hemi = old.hemi; // preserve pre-calculated hemisphere V->C._set (vC); g_trans_register (V); } thProgress = float(counter) / float(g_vertices.size()); } }
void CDeflector::L_Direct_Edge (CDB::COLLIDER* DB, base_lighting* LightsSelected, Fvector2& p1, Fvector2& p2, Fvector& v1, Fvector& v2, Fvector& N, float texel_size, Face* skip) { Fvector vdir; vdir.sub (v2,v1); lm_layer& lm = layer; Fvector2 size; size.x = p2.x-p1.x; size.y = p2.y-p1.y; int du = iCeil(_abs(size.x)/texel_size); int dv = iCeil(_abs(size.y)/texel_size); int steps = _max(du,dv); if (steps<=0) return; for (int I=0; I<=steps; I++) { float time = float(I)/float(steps); Fvector2 uv; uv.x = size.x*time+p1.x; uv.y = size.y*time+p1.y; int _x = iFloor(uv.x*float(lm.width)); int _y = iFloor(uv.y*float(lm.height)); if ((_x<0)||(_x>=(int)lm.width)) continue; if ((_y<0)||(_y>=(int)lm.height)) continue; if (lm.marker[_y*lm.width+_x]) continue; // ok - perform lighting base_color_c C; Fvector P; P.mad(v1,vdir,time); LightPoint (DB, RCAST_Model, C, P, N, *LightsSelected, (b_norgb?LP_dont_rgb:0)|(b_nosun?LP_dont_sun:0)|LP_DEFAULT, skip); //. C.mul (.5f); lm.surface [_y*lm.width+_x]._set (C); lm.marker [_y*lm.width+_x] = 255; } }
void CDeflector::L_Direct (CDB::COLLIDER* DB, base_lighting* LightsSelected, HASH& H) { R_ASSERT (DB); R_ASSERT (LightsSelected); lm_layer& lm = layer; // Setup variables Fvector2 dim,half; dim.set (float(lm.width),float(lm.height)); half.set (.5f/dim.x,.5f/dim.y); // Jitter data Fvector2 JS; JS.set (.4999f/dim.x, .4999f/dim.y); u32 Jcount; Fvector2* Jitter; Jitter_Select(Jitter, Jcount); // Lighting itself DB->ray_options (0); for (u32 V=0; V<lm.height; V++) { for (u32 U=0; U<lm.width; U++) { u32 Fcount = 0; base_color_c C; try { for (u32 J=0; J<Jcount; J++) { // LUMEL space Fvector2 P; P.x = float(U)/dim.x + half.x + Jitter[J].x * JS.x; P.y = float(V)/dim.y + half.y + Jitter[J].y * JS.y; xr_vector<UVtri*>& space = H.query(P.x,P.y); // World space Fvector wP,wN,B; for (UVtri** it=&*space.begin(); it!=&*space.end(); it++) { if ((*it)->isInside(P,B)) { // We found triangle and have barycentric coords Face *F = (*it)->owner; Vertex *V1 = F->v[0]; Vertex *V2 = F->v[1]; Vertex *V3 = F->v[2]; wP.from_bary(V1->P,V2->P,V3->P,B); //. не нужно использовать if (F->Shader().flags.bLIGHT_Sharp) { wN.set(F->N); } // else { wN.from_bary(V1->N,V2->N,V3->N,B); exact_normalize (wN); wN.add (F->N); exact_normalize (wN); } try { LightPoint (DB, RCAST_Model, C, wP, wN, *LightsSelected, (b_norgb?LP_dont_rgb:0)|(b_nosun?LP_dont_sun:0)|LP_UseFaceDisable, F); //. Fcount += 1; } catch (...) { clMsg("* ERROR (CDB). Recovered. "); } break; } } } } catch (...) { clMsg("* ERROR (Light). Recovered. "); } if (Fcount) { C.scale (Fcount); C.mul (.5f); lm.surface [V*lm.width+U]._set(C); lm.marker [V*lm.width+U] = 255; } else { lm.surface [V*lm.width+U]._set(C); // 0-0-0-0-0 lm.marker [V*lm.width+U] = 0; } } } // *** Render Edges float texel_size = (1.f/float(_max(lm.width,lm.height)))/8.f; for (u32 t=0; t<UVpolys.size(); t++) { UVtri& T = UVpolys[t]; Face* F = T.owner; R_ASSERT (F); try { L_Direct_Edge (DB,LightsSelected, T.uv[0], T.uv[1], F->v[0]->P, F->v[1]->P, F->N, texel_size,F); L_Direct_Edge (DB,LightsSelected, T.uv[1], T.uv[2], F->v[1]->P, F->v[2]->P, F->N, texel_size,F); L_Direct_Edge (DB,LightsSelected, T.uv[2], T.uv[0], F->v[2]->P, F->v[0]->P, F->N, texel_size,F); } catch (...) { clMsg("* ERROR (Edge). Recovered. "); } } }
/* // Iterate on edges - select with maximum error int callback_edge_error (Face* F) { float max_err = -1; int max_id = -1; for (u32 e=0; e<3; e++) { Vertex *V1,*V2; F->EdgeVerts (e,&V1,&V2); float len = V1->P.distance_to (V2->P); // len if (len<aht_min_edge) continue; if (len>max_err) { max_err = len; max_id = e; } } if (max_id<0) return max_id; // There should be an edge larger than "min_edge" base_color_c c1; F->v[0]->C._get(c1); base_color_c c2; F->v[1]->C._get(c2); base_color_c c3; F->v[2]->C._get(c3); bool b1 = fsimilar (c1.hemi,c2.hemi,aht_min_err); bool b2 = fsimilar (c2.hemi,c3.hemi,aht_min_err); bool b3 = fsimilar (c3.hemi,c1.hemi,aht_min_err); if (b1 && b2 && b3) return -1; // don't touch flat-shaded triangle else return max_id; // tesselate longest edge } void callback_vertex_hemi (Vertex* V) { // calc vertex attributes CDB::COLLIDER DB; DB.ray_options (0); base_color_c vC; LightPoint (&DB, RCAST_Model, vC, V->P, V->N, pBuild->L_static, LP_dont_rgb+LP_dont_sun,0); V->C._set (vC); } int smfVertex (Vertex* V) { return 1 + (std::lower_bound(g_vertices.begin(),g_vertices.end(),V)-g_vertices.begin()); } void GSaveAsSMF (LPCSTR fname) { IWriter* W = FS.w_open (fname); string256 tmp; // vertices std::sort (g_vertices.begin(),g_vertices.end()); for (u32 v_idx=0; v_idx<g_vertices.size(); v_idx++){ Fvector v = g_vertices[v_idx]->P; sprintf (tmp,"v %f %f %f",v.x,v.y,-v.z); W->w_string (tmp); } // transfer faces for (u32 f_idx=0; f_idx<g_faces.size(); f_idx++){ Face* t = g_faces [f_idx]; sprintf (tmp,"f %d %d %d", smfVertex(t->v[0]), smfVertex(t->v[2]), smfVertex(t->v[1]) ); W->w_string (tmp); } // colors W->w_string ("bind c vertex"); for (u32 v_idx=0; v_idx<g_vertices.size(); v_idx++){ base_color_c c; g_vertices[v_idx]->C._get(c); float h = c.hemi/2.f; sprintf (tmp,"c %f %f %f",h,h,h); W->w_string (tmp); } FS.w_close (W); } */ void CBuild::xrPhase_AdaptiveHT () { CDB::COLLIDER DB; DB.ray_options (0); Status ("Tesselating..."); if (1) { for (u32 fit=0; fit<lc_global_data()->g_faces().size(); fit++) { // clear split flag from all faces + calculate normals lc_global_data()->g_faces()[fit]->flags.bSplitted = false; lc_global_data()->g_faces()[fit]->flags.bLocked = true; lc_global_data()->g_faces()[fit]->CalcNormal (); } u_Tesselate (callback_edge_longest,0,0); // tesselate } // Tesselate + calculate Status ("Precalculating..."); { mem_Compact (); // Build model FPU::m64r (); BuildRapid (FALSE); // Prepare FPU::m64r (); Status ("Precalculating : base hemisphere ..."); mem_Compact (); Light_prepare (); // calc approximate normals for vertices + base lighting for (u32 vit=0; vit<lc_global_data()->g_vertices().size(); vit++) { base_color_c vC; Vertex* V = lc_global_data()->g_vertices()[vit]; V->normalFromAdj (); LightPoint (&DB, lc_global_data()->RCAST_Model(), vC, V->P, V->N, pBuild->L_static(), LP_dont_rgb+LP_dont_sun,0); vC.mul (0.5f); V->C._set (vC); } } ////////////////////////////////////////////////////////////////////////// /* Status ("Adaptive tesselation..."); { for (u32 fit=0; fit<g_faces.size(); fit++) { // clear split flag from all faces + calculate normals g_faces[fit]->flags.bSplitted = false; g_faces[fit]->flags.bLocked = true; } u_Tesselate (callback_edge_error,0,callback_vertex_hemi); // tesselate } */ ////////////////////////////////////////////////////////////////////////// Status ("Gathering lighting information..."); u_SmoothVertColors (5); ////////////////////////////////////////////////////////////////////////// /* Status ("Exporting to SMF..."); { string_path fn; GSaveAsSMF (strconcat(fn,pBuild->path,"hemi_source.smf")); } */ }
//----------------------------------------------------------------------- void xrMU_Model::calc_lighting (xr_vector<base_color>& dest, const Fmatrix& xform, CDB::MODEL* MDL, base_lighting& lights, u32 flags) { // trans-map typedef xr_multimap<float,v_vertices> mapVert; typedef mapVert::iterator mapVertIt; mapVert g_trans; u32 I; // trans-epsilons const float eps = EPS_L; const float eps2 = 2.f*eps; // calc pure rotation matrix Fmatrix Rxform,tmp,R; R.set (xform ); R.translate_over (0,0,0 ); tmp.transpose (R ); Rxform.invert (tmp ); // Perform lighting CDB::COLLIDER DB; DB.ray_options (0); // Disable faces if needed /* BOOL bDisableFaces = flags&LP_UseFaceDisable; if (bDisableFaces) for (I=0; I<m_faces.size(); I++) m_faces[I]->flags.bDisableShadowCast = true; */ // Perform lighting for (I = 0; I<m_vertices.size(); I++) { _vertex* V = m_vertices[I]; // Get ambient factor float v_amb = 0.f; float v_trans = 0.f; for (u32 f=0; f<V->m_adjacents.size(); f++) { _face* F = V->m_adjacents[f]; v_amb += F->Shader().vert_ambient; v_trans += F->Shader().vert_translucency; } v_amb /= float(V->m_adjacents.size()); v_trans /= float(V->m_adjacents.size()); float v_inv = 1.f-v_amb; base_color_c vC; Fvector vP,vN; xform.transform_tiny (vP,V->P); Rxform.transform_dir (vN,V->N); exact_normalize (vN); // multi-sample const int n_samples = (g_params().m_quality==ebqDraft)?1:6; for (u32 sample=0; sample<(u32)n_samples; sample++) { float a = 0.2f * float(sample) / float(n_samples); Fvector P,N; N.random_dir (vN,deg2rad(30.f)); P.mad (vP,N,a); LightPoint (&DB, MDL, vC, P, N, lights, flags, 0); } vC.scale (n_samples); vC._tmp_ = v_trans; if (flags&LP_dont_hemi) ; else vC.hemi += v_amb; V->C._set (vC); // Search const float key = V->P.x; mapVertIt it = g_trans.lower_bound (key); mapVertIt it2 = it; // Decrement to the start and inc to end while (it!=g_trans.begin() && ((it->first+eps2)>key)) it--; while (it2!=g_trans.end() && ((it2->first-eps2)<key)) it2++; if (it2!=g_trans.end()) it2++; // Search BOOL found = FALSE; for (; it!=it2; it++) { v_vertices& VL = it->second; _vertex* Front = VL.front(); R_ASSERT (Front); if (Front->P.similar(V->P,eps)) { found = TRUE; VL.push_back (V); } } // Register if (!found) { mapVertIt ins = g_trans.insert(mk_pair(key,v_vertices())); ins->second.reserve (32); ins->second.push_back (V); } } // Enable faces if needed /* if (bDisableFaces) for (I=0; I<m_faces.size(); I++) m_faces[I]->flags.bDisableShadowCast = true; */ // Process all groups for (mapVertIt it=g_trans.begin(); it!=g_trans.end(); it++) { // Unique v_vertices& VL = it->second; std::sort (VL.begin(),VL.end()); VL.erase (std::unique(VL.begin(),VL.end()),VL.end()); // Calc summary color base_color_c C; for (int v=0; v<int(VL.size()); v++) { base_color_c vC; VL[v]->C._get (vC); C.max (vC); } // Calculate final vertex color for (u32 v=0; v<int(VL.size()); v++) { base_color_c vC; VL[v]->C._get (vC); // trans-level float level = vC._tmp_; // base_color_c R; R.lerp (vC,C,level); R.max (vC); R.mul (.5f); VL[v]->C._set (R); } } // Transfer colors to destination dest.resize (m_vertices.size()); for (I = 0; I<m_vertices.size(); I++) { Fvector ptPos = m_vertices[I]->P; base_color ptColor = m_vertices[I]->C; dest[I] = ptColor; } }