//========================================================================== // // Sets up the texture coordinates for one light to be rendered // //========================================================================== bool GLWall::PrepareLight(texcoord * tcs, ADynamicLight * light) { float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; Vector nearPt, up, right; float scale; p.Init(vtx,4); if (!p.ValidNormal()) { return false; } if (!gl_SetupLight(p, light, nearPt, up, right, scale, Colormap.colormap, true, !!(flags&GLWF_FOGGY))) { return false; } if (tcs != NULL) { Vector t1; int outcnt[4]={0,0,0,0}; for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; // quick check whether the light touches this polygon if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } // The light doesn't touch this polygon if (outcnt[0]==4 || outcnt[1]==4 || outcnt[2]==4 || outcnt[3]==4) return false; } draw_dlight++; return true; }
void GLWall::SetupLights() { // check for wall types which cannot have dynamic lights on them (portal types never get here so they don't need to be checked.) switch (type) { case RENDERWALL_FOGBOUNDARY: case RENDERWALL_MIRRORSURFACE: case RENDERWALL_COLOR: case RENDERWALL_COLORLAYER: return; } float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Init(vtx,4); if (!p.ValidNormal()) { return; } FLightNode *node; if (seg->sidedef == NULL) { node = NULL; } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { node = seg->sidedef->lighthead; } else if (sub) { // Polobject segs cannot be checked per sidedef so use the subsector instead. node = sub->lighthead; } else node = NULL; // Iterate through all dynamic lights which touch this wall and render them while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; Vector fn, pos; float x = FIXED2FLOAT(node->lightsource->X()); float y = FIXED2FLOAT(node->lightsource->Y()); float z = FIXED2FLOAT(node->lightsource->Z()); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (node->lightsource->GetRadius() * gl_lights_size); float scale = 1.0f / ((2.f * radius) - dist); if (radius > 0.f && dist < radius) { Vector nearPt, up, right; pos.Set(x,z,y); fn=p.Normal(); fn.GetRightUp(right, up); Vector tmpVec = fn * dist; nearPt = pos + tmpVec; Vector t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(p, node->lightsource, true, false, lightdata); } } } node = node->nextLight; } dynlightindex = GLRenderer->mLights->UploadLights(lightdata); }
void GLWall::SetupLights() { float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Init(vtx,4); if (!p.ValidNormal()) { return; } for(int i=0;i<2;i++) { FLightNode *node; if (!seg->bPolySeg) { // Iterate through all dynamic lights which touch this wall and render them if (seg->sidedef) { node = seg->sidedef->lighthead[i]; } else node = NULL; } else if (sub) { // To avoid constant rechecking for polyobjects use the subsector's lightlist instead node = sub->lighthead[i]; } else node = NULL; while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; Vector fn, pos; float x = FIXED2FLOAT(node->lightsource->x); float y = FIXED2FLOAT(node->lightsource->y); float z = FIXED2FLOAT(node->lightsource->z); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (node->lightsource->GetRadius() * gl_lights_size); float scale = 1.0f / ((2.f * radius) - dist); if (radius > 0.f && dist < radius) { Vector nearPt, up, right; pos.Set(x,z,y); fn=p.Normal(); fn.GetRightUp(right, up); Vector tmpVec = fn * dist; nearPt = pos + tmpVec; Vector t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(p, node->lightsource, Colormap.colormap, true, false, lightdata); } } } node = node->nextLight; } } int numlights[3]; lightdata.Combine(numlights, gl.MaxLights()); if (numlights[2] > 0) { draw_dlight+=numlights[2]/2; gl_RenderState.EnableLight(true); gl_RenderState.SetLights(numlights, &lightdata.arrays[0][0]); } }
void PointCloud::calcNormals ( float radius, unsigned int kNN, unsigned int maxTries ) { // cerr << "Begin calcNormals " << endl << flush; KdTree3Df kd; kd.IndexedData(begin(), end()); kd.Build(); GfxTL::LimitedHeap< GfxTL::NN< float > > nn; KdTree3Df::NearestNeighborsAuxData< value_type > nnAux; //GfxTL::AssumeUniqueLimitedHeap< GfxTL::NN< float > > nn; MiscLib::NoShrinkVector< float > weights; vector<int> stats(91, 0); #ifdef PCA_NORMALS GfxTL::Plane< GfxTL::Vector3Df > plane; #endif for ( unsigned int i = 0; i < size(); i ++ ) { //kd.PointsInBall(at(i), radius, &nn); //if(nn.size() > kNN) //{ // std::sort(nn.begin(), nn.end()); // nn.resize(kNN); //} kd.NearestNeighbors(at(i), kNN, &nn, &nnAux); unsigned int num = (unsigned int)nn.size(); //if(i%1000 == 0) // cerr << num << " "; if ( num > kNN ) num = kNN; at(i).normal = Vec3f(0,0,0); if ( num < 8 ) { continue; } #ifdef PCA_NORMALS weights.resize(nn.size()); if(nn.front().sqrDist > 0) { float h = nn.front().sqrDist / 2; for(unsigned int i = 0; i < nn.size(); ++i) weights[i] = std::exp(-nn[i].sqrDist / h); } else std::fill(weights.begin(), weights.end(), 1.f); plane.Fit(GfxTL::IndexIterate(nn.begin(), begin()), GfxTL::IndexIterate(nn.end(), begin()), weights.begin()); at(i).normal = Vec3f(plane.Normal().Data()); #endif #ifdef LMS_NORMALS float score, bestScore = -1.f; for (unsigned int tries = 0; tries < maxTries; tries++) { //choose candidate int i0, i1, i2; i0 = rand() % num; do i1 = rand() % num; while (i1 == i0); do i2 = rand() % num; while (i2 == i0 || i2 == i1); Plane plane; if(!plane.Init(at(nn[i0]), at(nn[i1]), at(nn[i2]))) continue; //evaluate metric float *dist = new float[num]; for (unsigned int j = 0; j < num; j++) { dist[j] = plane.getDistance(at(nn[j])); } // sort(dist, dist+num); // score = dist[num/2]; // evaluate median score = quick_select(dist, num); // evaluate median delete[] dist; if (score < bestScore || bestScore < 0.f) { if ( tries > maxTries/2 ) { // let us see how good the first half of candidates are... int index = std::floor(180/M_PI*std::acos(std::min(1.f, abs(plane.getNormal().dot(at(i).normal))))); stats[index]++; } at(i).normal = plane.getNormal(); bestScore = score; } } #endif } //cerr << "End calcNormals " << endl << flush; //copy(stats.begin(), stats.end(), ostream_iterator<int>(cerr, " ")); }