You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
573 lines
16 KiB
573 lines
16 KiB
/**************************************************************************** |
|
* VCGLib o o * |
|
* Visual and Computer Graphics Library o o * |
|
* _ O _ * |
|
* Copyright(C) 2004-2016 \/)\/ * |
|
* Visual Computing Lab /\/| * |
|
* ISTI - Italian National Research Council | * |
|
* \ * |
|
* All rights reserved. * |
|
* * |
|
* This program is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published by * |
|
* the Free Software Foundation; either version 2 of the License, or * |
|
* (at your option) any later version. * |
|
* * |
|
* This program is distributed in the hope that it will be useful, * |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * |
|
* for more details. * |
|
* * |
|
****************************************************************************/ |
|
/**************************************************************************** |
|
History |
|
|
|
$Log: not supported by cvs2svn $ |
|
Revision 1.9 2005/11/12 06:47:18 cignoni |
|
Added Enhancement, removed type warnings, |
|
started to refactor code in order to remove the unnecessary generality of the class. |
|
|
|
Revision 1.8 2004/09/28 09:45:17 cignoni |
|
Added MapFalseColor |
|
|
|
Revision 1.7 2004/09/16 14:23:57 ponchio |
|
fixed gcc template compatibility issues. |
|
|
|
Revision 1.6 2004/09/10 14:02:20 cignoni |
|
Added Cone directions |
|
|
|
Revision 1.5 2004/09/09 22:59:21 cignoni |
|
Removed many small warnings |
|
|
|
Revision 1.4 2004/09/09 22:37:48 cignoni |
|
Integrated lost modifications... |
|
|
|
Revision 1.3 2004/09/09 14:35:54 ponchio |
|
Various changes for gcc compatibility |
|
|
|
Revision 1.2 2004/07/11 22:13:30 cignoni |
|
Added GPL comments |
|
|
|
|
|
****************************************************************************/ |
|
|
|
#ifndef __VCG_MESH_VISIBILITY |
|
#define __VCG_MESH_VISIBILITY |
|
|
|
#include <stdlib.h> |
|
|
|
#include <bitset> |
|
#include <vcg/math/matrix44.h> |
|
#include <wrap/gl/math.h> |
|
#include "simplepic.h" |
|
#include <vcg/math/gen_normal.h> |
|
|
|
namespace vcg { |
|
// Base Class che definisce le varie interfaccie; |
|
template <class MESH_TYPE, int MAXVIS=2048> class VisShader |
|
{ |
|
public : |
|
enum {VisMax=MAXVIS}; |
|
VisShader(MESH_TYPE &me):m(me) |
|
{ |
|
CullFlag= false; |
|
IsClosedFlag = false; |
|
ZTWIST=1e-3; |
|
SplitNum=1; |
|
|
|
CameraViewing=false; |
|
} |
|
|
|
typedef Point3<typename MESH_TYPE::ScalarType> Point3x; |
|
|
|
typedef typename MESH_TYPE::CoordType CoordType; |
|
typedef typename MESH_TYPE::ScalarType ScalarType; |
|
typedef typename MESH_TYPE::VertexType VertexType; |
|
typedef typename MESH_TYPE::VertexPointer VertexPointer; |
|
typedef typename MESH_TYPE::VertexIterator VertexIterator; |
|
typedef typename MESH_TYPE::FaceIterator FaceIterator; |
|
typedef typename MESH_TYPE::FaceType FaceType; |
|
typedef Matrix44<ScalarType> Matrix44x; |
|
typedef Box3<ScalarType> Box3x; |
|
|
|
// The Basic Data the mesh and its wrapper; |
|
MESH_TYPE &m; |
|
|
|
std::vector<MESH_TYPE *> OMV; // Occluder Mesh Vector; |
|
|
|
// la visibilita' e' in float, per ogni entita' |
|
// 1 significa che e' totalmente visibile per una data direzione. |
|
|
|
std::vector<float> VV; |
|
std::vector< Point3x > VN; // Vettore delle normali che ho usato per calcolare la mask e i float in W; |
|
|
|
// User defined parameters and flags |
|
bool IsClosedFlag; |
|
float ZTWIST; |
|
bool CullFlag; // Enable the frustum culling. Useful when the splitting value is larger than 2 |
|
int SplitNum; |
|
protected: |
|
bool CameraViewing; |
|
//Camera<ScalarType> Cam; |
|
public: |
|
|
|
/********************************************************/ |
|
// Generic functions with Specialized code for every subclass |
|
virtual void MapVisibility(float Gamma=1, float LowPass=0, float HighPass=1,float Scale=1.0)=0; |
|
//virtual void ApplyLightingEnvironment(std::vector<float> &W, float Gamma); |
|
|
|
virtual int GLAccumPixel( std::vector<int> &PixSeen)=0; |
|
|
|
virtual bool ReadVisibility(const char * /*filename*/){assert( 0); return false;} |
|
virtual bool WriteVisibility(const char * /*filename*/){assert( 0); return false;} |
|
|
|
/********************************************************/ |
|
// Generic functions with same code for every subclass |
|
|
|
void Clear() { |
|
fill(VV.begin(),VV.end(),0); } |
|
|
|
void InitGL() |
|
{ |
|
glPushAttrib(GL_COLOR_BUFFER_BIT ); |
|
::glClearColor (1.0, 1.0, 1.0, 0.0); |
|
glMatrixMode (GL_PROJECTION); |
|
glPushMatrix(); |
|
glMatrixMode (GL_MODELVIEW); |
|
glPushMatrix(); |
|
} |
|
|
|
void RestoreGL() |
|
{ |
|
glMatrixMode (GL_PROJECTION); |
|
glPopMatrix(); |
|
glMatrixMode (GL_MODELVIEW); |
|
glPopMatrix(); |
|
glPopAttrib(); |
|
} |
|
|
|
|
|
/* |
|
Funzione principale di conversione in visibilita' |
|
Dati i due vettori PixSeen e PixNotSeen che indicano per ogni entita' (vertice o faccia) |
|
quanti sono, rispettivamente, i pixel visibili e occlusi, |
|
questa funzione calcola un valore float per ogni entita' che indica quanto e' visibile lungo una data direzione camera |
|
== 1 significa completamente visibile |
|
== 0 significa completamente occluso. |
|
|
|
*/ |
|
void AddPixelCount(std::vector<float> &_VV, const std::vector<int> &PixSeen) |
|
{ |
|
assert(_VV.size()==PixSeen.size()); |
|
for(unsigned int i=0;i<PixSeen.size();++i) |
|
if(PixSeen[i]>0) _VV[i]+= 1; |
|
} |
|
|
|
|
|
//void SetVisibilityMask(std::vector< std::bitset<MAXVIS> > &_VM, const std::vector<int> &PixSeen, const int dir) |
|
// { |
|
// assert(_VM.size()==PixSeen.size()); |
|
// for(int i=0;i<PixSeen.size();++i) |
|
// if(PixSeen[i]>0) _VM[i][dir]=true; |
|
// } |
|
|
|
/******************************* |
|
Funzioni ad alto livello che computano le Visibility Mask per varie distribuzioni di direzioni |
|
|
|
|
|
*******************************/ |
|
|
|
// Funzione Generica |
|
// Calcola l'occlusion in base all'insieme VN di direzioni. |
|
|
|
void Compute( CallBack *cb) |
|
{ |
|
//cb(buf.format("Start to compute %i dir\n",VN.size())); |
|
InitGL(); |
|
int t00=clock(); |
|
VV.resize(m.vert.size()); |
|
std::vector<int> PixSeen(VV.size(),0); |
|
int TotRay=0,HitRay=0; |
|
for(unsigned int i=0;i<VN.size();++i) |
|
{ |
|
int t0=clock(); |
|
fill(PixSeen.begin(),PixSeen.end(),0); |
|
int added=SplittedRendering(VN[i], PixSeen,cb); |
|
AddPixelCount(VV,PixSeen); |
|
int t1=clock(); |
|
HitRay+=added; |
|
TotRay+=VV.size(); |
|
printf("%3i/%i : %i msec -- TotRays %i, HitRays %i, ray/sec %3.1fk \n ",i,VN.size(),t1-t0,TotRay,HitRay,float(TotRay)/(clock()-t00)); |
|
} |
|
|
|
printf("Tot Time %i msec TotRays %i, HitRays %i, ray/sec %3.1fk \n ",clock()-t00,TotRay,HitRay,float(TotRay)/(clock()-t00)); |
|
RestoreGL(); |
|
} |
|
|
|
void ComputeHalf(int nn, Point3x &dir, CallBack *cb) |
|
{ |
|
std::string buf; |
|
|
|
VN.clear(); |
|
std::vector<Point3x> nvt; |
|
assert(0 && "This is only my guess (to compile). (Ponchio)"); |
|
assert(0 && "Was: GenNormal(nn*2, nvt);"); |
|
GenNormal<ScalarType>::Uniform(nn*2,nvt); |
|
for(int i=0;i<nvt.size();++i) |
|
if(dir*nvt[i]>0) VN.push_back(nvt[i]); |
|
|
|
printf("Asked %i normal, got %i normals\n",nn,VN.size()); |
|
Compute(cb); |
|
} |
|
|
|
void ComputeUniformCone(int nn, std::vector<Point3x> &vv, ScalarType AngleRad, Point3x &ConeDir, CallBack *cb) |
|
{ |
|
VN.clear(); |
|
GenNormal<ScalarType>::UniformCone(nn,VN,AngleRad,ConeDir); |
|
typename std::vector<Point3x>::iterator vi; |
|
for(vi=VN.begin();vi!=VN.end();++vi) |
|
vv.push_back(*vi); |
|
|
|
char buf[256]; |
|
sprintf(buf,"Asked %i normal, got %i normals\n",nn,VN.size()); |
|
cb(buf); |
|
Compute(cb); |
|
} |
|
void ComputeUniform(int nn, std::vector<Point3x> &vv, CallBack *cb) |
|
{ |
|
VN.clear(); |
|
GenNormal<ScalarType>::Uniform(nn,VN); |
|
typename std::vector<Point3x>::iterator vi; |
|
for(vi=VN.begin();vi!=VN.end();++vi) |
|
vv.push_back(*vi); |
|
|
|
char buf[256]; |
|
sprintf(buf,"Asked %i normal, got %i normals\n",nn,VN.size()); |
|
cb(buf); |
|
Compute(cb); |
|
} |
|
|
|
void ComputeSingle(Point3x &dir, std::vector<Point3x> &vv,CallBack *cb) |
|
{ |
|
VN.clear(); |
|
VN.push_back(dir); |
|
vv.push_back(dir); |
|
printf("Computing one direction (%f %f %f)\n",dir[0],dir[1],dir[2]); |
|
Compute(cb); |
|
} |
|
|
|
/**********************************************************/ |
|
|
|
int SplittedRendering(Point3x &ViewDir, std::vector<int> &PixSeen, CallBack *cb=DummyCallBack) |
|
{ |
|
int tt=0; |
|
int i,j; |
|
for(i=0;i<SplitNum;++i) |
|
for(j=0;j<SplitNum;++j){ |
|
SetupOrthoViewMatrix(ViewDir, i,j,SplitNum); |
|
tt+=GLAccumPixel(PixSeen); |
|
} |
|
return tt; |
|
} |
|
|
|
// Compute a rotation matrix that bring Axis parallel to Z. |
|
void GenMatrix(Matrix44d &a, Point3d Axis, double angle) |
|
{ |
|
const double eps=1e-3; |
|
Point3d RotAx = Axis ^ Point3d(0,0,1); |
|
double RotAngle = Angle(Axis,Point3d(0,0,1)); |
|
|
|
if(math::Abs(RotAx.Norm())<eps) { // in questo caso Axis e' collineare con l'asse z |
|
RotAx=Axis ^ Point3d(0,1,0); |
|
double RotAngle = Angle(Axis,Point3d(0,1,0)); |
|
} |
|
|
|
//printf("Rotating around (%5.3f %5.3f %5.3f) %5.3f\n",RotAx[0],RotAx[1],RotAx[2],RotAngle); |
|
RotAx.Normalize(); |
|
a.SetRotate(RotAngle,RotAx); |
|
//Matrix44d rr; |
|
//rr.SetRotate(-angle, Point3d(0,0,1)); |
|
//a=rr*a; |
|
} |
|
|
|
|
|
// Genera la matrice di proj e model nel caso di un rendering ortogonale. |
|
// subx e suby indicano la sottoparte che si vuole |
|
void SetupOrthoViewMatrix(Point3x &ViewDir, int subx, int suby,int LocSplit) |
|
{ |
|
glMatrixMode (GL_PROJECTION); |
|
glLoadIdentity (); |
|
float dlt=2.0f/LocSplit; |
|
|
|
glOrtho(-1+subx*dlt, -1+(subx+1)*dlt, -1+suby*dlt, -1+(suby+1)*dlt,-2,2); |
|
glMatrixMode (GL_MODELVIEW); |
|
glLoadIdentity (); |
|
Matrix44d rot; |
|
Point3d qq; qq.Import(ViewDir); |
|
GenMatrix(rot,qq,0); |
|
glMultMatrix(rot); |
|
double d=2.0/m.bbox.Diag(); |
|
glScalef(d,d,d); |
|
glTranslate(-m.bbox.Center()); |
|
} |
|
|
|
void ComputeSingleDirection(Point3x BaseDir, std::vector<int> &PixSeen, CallBack *cb=DummyCallBack) |
|
{ |
|
int t0=clock(); |
|
std::string buf; |
|
|
|
int added=SplittedRendering(BaseDir, PixSeen,cb); |
|
int t1=clock(); |
|
printf("ComputeSingleDir %i msec\n",t1-t0); |
|
} |
|
|
|
void ComputeAverageVisibilityDirection() |
|
{ |
|
int i,j; |
|
VD.resize(VM.size()); |
|
for(j=0;j<VM.size();++j) |
|
{ |
|
Point3x &nn=VD[j]; |
|
nn=Point3x(0,0,0); |
|
bitset<VisMax> &msk=VM[j]; |
|
for(i=0;i<VN.size();++i) |
|
if(msk[i]) nn+=VN[i]; |
|
} |
|
for(j=0;j<VM.size();++j) |
|
VD[j].Normalize(); |
|
|
|
} |
|
|
|
// calcola un LightingEnvironment direzionale, cioe'un vettore di pesi per l'insieme di normali |
|
// corrente tale che |
|
// mette a 1 tutti i vettori che sono entro un angolo DegAngle1 |
|
// a 0 tutti quelli oltre DegAngle2 e |
|
// sfuma linearmente nel mezzo. |
|
void DirectionalLightingEnvironment(std::vector<float> &LE, Point3x dir, ScalarType DegAngle1, ScalarType DegAngle2) |
|
{ |
|
LE.clear(); |
|
LE.resize(VN.size(),0); |
|
int i; |
|
for(i=0;i<VN.size();++i) |
|
{ |
|
ScalarType a=ToDeg(Angle(dir,VN[i])); |
|
if(a<DegAngle1) { LE[i]=1; continue; } |
|
if(a>DegAngle2) { LE[i]=0; continue; } |
|
LE[i] = 1.0-(a-DegAngle1)/(DegAngle2-DegAngle1); |
|
|
|
} |
|
// last step normalize the weights; |
|
ScalarType sum=0; |
|
for(i=0;i<VN.size();++i) |
|
sum+=LE[i]; |
|
for(i=0;i<VN.size();++i) |
|
LE[i]/=sum; |
|
} |
|
|
|
|
|
}; |
|
/***************************************************************************/ |
|
/***************************************************************************/ |
|
/***************************************************************************/ |
|
|
|
template <class MESH_TYPE> class VertexVisShader : public VisShader<MESH_TYPE> |
|
{ |
|
public : |
|
|
|
// Function Members |
|
VertexVisShader(MESH_TYPE &me):VisShader<MESH_TYPE>(me) |
|
{ |
|
// la mesh DEVE avere colore per vertice |
|
if(! HasPerVertexColor(m)) assert(0); |
|
} |
|
|
|
void Init() { VV.resize(m.vert.size()); } |
|
void Compute(int nn); |
|
|
|
void DrawFill (MESH_TYPE &mm) |
|
{ |
|
static GLuint dl=0; |
|
if(mm.face.empty()) |
|
{ AMesh::VertexIterator vi; |
|
glBegin(GL_POINTS); |
|
for(vi=mm.vert.begin();vi!=mm.vert.end();++vi) |
|
{ |
|
if(ColorFlag) glColor((*vi).C()); |
|
glVertex((*vi).P()); |
|
} |
|
glEnd(); |
|
} |
|
else |
|
{ |
|
glBegin(GL_TRIANGLES); |
|
FaceIterator fi; |
|
for(fi=mm.face.begin();fi!=mm.face.end();++fi) |
|
{ |
|
glVertex((*fi).V(0)->P()); |
|
glVertex((*fi).V(1)->P()); |
|
glVertex((*fi).V(2)->P()); |
|
} |
|
glEnd(); |
|
} |
|
} |
|
|
|
/***************************************************************************/ |
|
|
|
//VertexVisibility |
|
// Funzione Principale restituisce per ogni entita' quanti px si vedono o no. |
|
|
|
int GLAccumPixel( std::vector<int> &PixSeen) |
|
{ |
|
SimplePic<float> snapZ; |
|
SimplePic<Color4b> snapC; |
|
|
|
glClearColor(Color4b::Black); |
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
|
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT ); |
|
glDisable(GL_LIGHTING); |
|
glDepthRange(0.0f,1.0f); |
|
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); |
|
glDepthMask(GL_TRUE); |
|
glDrawBuffer(GL_BACK); |
|
glReadBuffer(GL_BACK); |
|
|
|
/////** Si disegnano le front face **///// |
|
glDepthRange(2.0*ZTWIST,1.0f); |
|
if(IsClosedFlag) glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); |
|
glEnable(GL_CULL_FACE); |
|
glCullFace(GL_BACK); |
|
glColor(Color4b::Red); |
|
DrawFill(m); |
|
|
|
if(!IsClosedFlag) { |
|
glCullFace(GL_FRONT); |
|
glColor(Color4b::Black); |
|
DrawFill(m); |
|
snapC.OpenGLSnap(); |
|
} |
|
|
|
int cnt=0; |
|
snapZ.OpenGLSnap(GL_DEPTH_COMPONENT); |
|
|
|
glDepthRange(0,1.0f-2.0*ZTWIST); |
|
double MM[16]; |
|
glGetDoublev(GL_MODELVIEW_MATRIX,MM); |
|
double MP[16]; |
|
glGetDoublev(GL_PROJECTION_MATRIX,MP); |
|
int VP[4]; |
|
glGetIntegerv(GL_VIEWPORT,VP); |
|
double tx,ty,tz; |
|
|
|
for(unsigned int i=0;i<m.vert.size();++i) |
|
{ |
|
gluProject(m.vert[i].P()[0],m.vert[i].P()[1],m.vert[i].P()[2], |
|
MM,MP,VP, |
|
&tx,&ty,&tz); |
|
int col=1; |
|
|
|
if(tx>=0 && tx<snapZ.sx && ty>=0 && ty<snapZ.sy) |
|
{ |
|
int txi=floor(tx),tyi=floor(ty); |
|
float sd=snapZ.Pix(tx,ty); |
|
if(!IsClosedFlag) { |
|
col = max( max(snapC.Pix(txi+0,tyi+0)[0],snapC.Pix(txi+1,tyi+0)[0]), |
|
max(snapC.Pix(txi+0,tyi+1)[0],snapC.Pix(txi+1,tyi+1)[0])); |
|
|
|
// col=snapC.Pix(txi+0,tyi+0)[0]; |
|
} |
|
if(col!=0 && tz<sd) { |
|
PixSeen[i]++; |
|
cnt++; |
|
} |
|
} |
|
} |
|
glPopAttrib(); |
|
//printf("Seen %i vertexes on %i\n",cnt,m.vert.size()); |
|
return cnt; |
|
} |
|
|
|
void SmoothVisibility(bool Enhance=false) |
|
{ |
|
FaceIterator fi; |
|
std::vector<float> VV2; |
|
std::vector<int> VC(VV.size(),1); |
|
VV2=VV; |
|
for(fi=m.face.begin();fi!=m.face.end();++fi) |
|
for(int i=0;i<3;++i) |
|
{ |
|
VV2[(*fi).V(i)-&*m.vert.begin()] += VV[(*fi).V1(i)-&*m.vert.begin()]; |
|
++VC[(*fi).V(i)-&*m.vert.begin()]; |
|
} |
|
|
|
if(!Enhance) |
|
for(unsigned int i=0;i<VV2.size();++i) |
|
VV[i]=VV2[i]/VC[i]; |
|
else |
|
for(unsigned int i=0;i<VV2.size();++i) |
|
VV[i]=VV[i]+ (VV[i]-VV2[i]/VC[i])*.5; |
|
} |
|
|
|
|
|
void MapFalseColor() |
|
{ |
|
float minv=*min_element(VV.begin(),VV.end()); |
|
float maxv=*max_element(VV.begin(),VV.end()); |
|
printf("Visibility Range %f %f\n", minv,maxv); |
|
MapFalseColor(minv, maxv); |
|
} |
|
|
|
void MapFalseColor(float minv, float maxv) |
|
{ |
|
VertexIterator vi; |
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi){ |
|
float gval=(VV[vi-m.vert.begin()]-minv)/(maxv-minv); |
|
math::Clamp(gval,0.0f,1.0f); |
|
(*vi).C().ColorRamp(1.0,0.0,gval); |
|
} |
|
} |
|
|
|
/* |
|
The visibility is mapped in [0..1] |
|
then clamped to [low,high] |
|
this value is mapped again in [0.1] and gamma corrected; |
|
and at the end is scaled for 'Scale' |
|
*/ |
|
|
|
void MapVisibility(float Gamma=1, float LowPass=0, float HighPass=1, float Scale= 1.0) |
|
{ |
|
float minv=*min_element(VV.begin(),VV.end()); |
|
float maxv=*max_element(VV.begin(),VV.end()); |
|
printf("Visibility Range %f %f\n", minv,maxv); |
|
|
|
VertexIterator vi; |
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi){ |
|
float gval=(VV[vi-m.vert.begin()]-minv)/(maxv-minv); |
|
if(gval<LowPass) gval=LowPass; |
|
if(gval>HighPass) gval=HighPass; |
|
(*vi).C().SetGrayShade(Scale*pow((gval-LowPass)/(HighPass-LowPass),Gamma)); |
|
} |
|
} |
|
|
|
//void ApplyLightingEnvironment(std::vector<float> &W, float Gamma=1) |
|
// { |
|
// assert(W.size()==VN.size()); |
|
// MESH_TYPE::VertexIterator vi; |
|
// |
|
// for(vi=m.vert.begin();vi!=m.vert.end();++vi) |
|
// { |
|
// float gray=0; |
|
// bitset<VisMax> &msk=VM[vi-m.vert.begin()]; |
|
// for(int i=0;i<VN.size();++i) |
|
// if(msk[i]) gray+=W[i]; |
|
// |
|
// (*vi).C().SetGrayShade(gray); |
|
// } |
|
// } |
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
#endif // __VCG_MESH_VISIBILITY
|
|
|