Subversion Repositories gelsvn

Rev

Rev 457 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
386 jab 1
/*
2
 *  harmonics.cpp
3
 *  GEL
4
 *
5
 *  Created by J. Andreas Bærentzen on 01/09/08.
6
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
7
 *
8
 */
9
 
10
#include <iostream>
457 jab 11
 
12
#include "harmonics.h"
13
 
14
#if USE_SPARSE_MATRIX
15
#include <arlgsym.h>
16
#endif
17
 
386 jab 18
#include <CGLA/Vec3d.h>
457 jab 19
#include <CGLA/Mat2x2d.h>
386 jab 20
#include <LinAlg/Matrix.h>
21
#include <LinAlg/Vector.h>
22
#include <LinAlg/LapackFunc.h>
23
 
24
#include <GL/glew.h>
25
#include <GLGraphics/glsl_shader.h>
26
 
27
#include <HMesh/mesh_optimization.h>
596 jab 28
#include <HMesh/curvature.h>
386 jab 29
#include <HMesh/triangulate.h>
30
#include <HMesh/load.h>
31
#include <HMesh/x3d_save.h>
32
 
596 jab 33
#include <GLGraphics/Console.h>
386 jab 34
 
596 jab 35
//#include "CSCMatrixBuilder.h"
386 jab 36
 
37
using namespace CGLA;
38
using namespace std;
39
using namespace HMesh;
40
using namespace Geometry;
41
using namespace GLGraphics;
42
using namespace LinAlg;
43
 
391 jab 44
bool Harmonics::is_initialized=false;
45
GLuint Harmonics::prog_P0;
386 jab 46
 
47
 
48
namespace
49
{
457 jab 50
 
397 jab 51
	string vss =
457 jab 52
	"#version 120\n"
53
	"#extension GL_EXT_gpu_shader4 : enable\n"
54
	"	\n"
55
	"	\n"
56
	"	attribute float eigenvalue;\n"
57
	"	attribute float eigenvalue2;\n"
58
	"	varying vec3 normal;\n"
59
	"	varying float eig;\n"
60
	"	varying float eig2;\n"
61
	"	\n"
62
	"	void main(void)\n"
63
	"	{\n"
64
	"		gl_Position =  ftransform();\n"
65
	"		normal = normalize(gl_NormalMatrix * gl_Normal);\n"
66
	"		eig = eigenvalue;\n"
67
	"		eig2 = eigenvalue2;\n"
68
	"	}\n";
386 jab 69
 
457 jab 70
	string fss = 	
71
	"#version 120\n"
72
	"#extension GL_EXT_gpu_shader4 : enable\n"
73
	"	\n"
74
	"	varying vec3 normal;\n"
75
	"	varying float eig;\n"
76
	"	varying float eig2;\n"
77
	"	uniform float eig_max;\n"
78
	"	uniform float eig_max2;\n"
79
	"	uniform bool do_highlight;\n"
80
	"	uniform bool do_diffuse;\n"
81
	"	const vec3 light_dir = vec3(0,0,1);\n"
82
	"	\n"
83
	" float basef(float x) {return max(0.0,min(1.0,2.0-4.0*abs(x)));\n}" 
84
	"	void main()\n"
85
	"	{\n"
86
	"		float dot_ln = max(0.0,dot(light_dir, normal));\n"
87
	"		\n"
88
	"		float eig_norm = eig/eig_max;\n"
89
	"		float stripe_signal = 250 * eig_norm;\n"
90
	//"		vec4 stripe_col = abs(stripe_signal) < 3.14 ? vec4(1,1,0,0) : vec4(.4,.4,.4,0);\n"
91
	"		vec4 stripe_col = -vec4(.4,.4,.4,0);\n"
92
	"		\n"
93
	"       float alpha = (1.0-eig_norm) * 2.0 * 3.1415926;\n"
94
	"       float offs = 2.0*3.1415/3.0;\n"
95
	"		gl_FragColor = vec4(0,0,1,0)*basef(eig_norm)+vec4(0,1,0,0)*basef(eig_norm-0.5)+vec4(1,0,0,0)* basef(eig_norm-1.0);\n"
96
	"		if(do_diffuse)   gl_FragColor *= dot_ln;\n"
97
	"		if(do_highlight) gl_FragColor += dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*vec4(.5,.5,.5,0);\n"
98
	"		gl_FragColor -= vec4(.4,.4,.4,.4)*smoothstep(0.2,0.6,cos(stripe_signal));\n"
99
	"	}\n";
100
}
101
 
102
 
103
 
104
#if USE_SPARSE_MATRIX
105
 
106
double calculate_laplace_entry(VertexCirculator vc,Vec3d vertex)
107
{
108
	//* this piece of code is taken from the orginal make_laplace_operator...
109
	HalfEdgeIter h = vc.get_halfedge();
110
	Vec3d nbr(h->vert->pos);
111
	Vec3d left(h->next->vert->pos);
112
	Vec3d right(h->opp->prev->opp->vert->pos);
397 jab 113
 
457 jab 114
	double d_left = dot(normalize(nbr-left),normalize(vertex-left));
115
	double d_right = dot(normalize(nbr-right),normalize(vertex-right));
116
	double a_left  = acos(min(1.0, max(-1.0, d_left))); // w positive...?
117
	double a_right = acos(min(1.0, max(-1.0, d_right)));
118
 
119
	double w = 1.0/tan(a_left) + 1.0/tan(a_right);
120
	return -w;
121
}
122
 
123
void Harmonics::make_laplace_operator_sparse()
124
{
125
	bool is_generalized=true;
126
	CSCMatrixBuilder<double> mb_M;
127
	//+GENERALIZED
128
	CSCMatrixBuilder<double> mb_S;
129
	// S has the same type as V
130
	S.Resize(mani.no_vertices());
131
 
596 jab 132
	for(VertexIter v = mani.vhandles_begin(); v != mani.vhandles_end(); ++v)
457 jab 133
		if(!is_boundary(v))
134
		{
135
			int i = v->touched;
136
			double area_i = voronoi_area(v);
137
			Vec3d vertex(v->pos);
138
			double a_sum = 0;
139
			for(VertexCirculator vc(v); !vc.end(); ++vc)
140
			{
141
				int j = vc.get_vertex()->touched;
142
				double entry = calculate_laplace_entry(vc,vertex);
143
				if(!is_generalized)
144
				{
145
					double area_j = voronoi_area(vc.get_vertex());
146
					entry /= sqrt(area_i*area_j);
147
				}
148
				if(j > i)
149
					mb_M.insert_entry(j,entry);
150
				a_sum += entry;
151
			}
152
			//cout << a_sum << " ";
153
			mb_M.insert_entry(i,-a_sum);
154
			mb_M.next_column();
155
 
156
			if(!is_generalized)
157
				area_i = 1; // if standard S is an identity matrix;
158
			mb_S.insert_entry(i,area_i);
159
			mb_S.next_column_nonsort();
160
			S[i] = area_i;
161
		}     
162
 
163
	cout << "solving generalized problem... i = " << mani.no_vertices()<< endl;
164
 
165
 
166
	//+STANDARD
167
	//ArpackPP::ARluSymStdEig<double> dprob(50L, mb_M.get_Matrix(), "SA");
168
	//+GENERALIZED (shifted inv mode)
169
	ARluSymGenEig<double> dprob('S',maximum_eigenvalue, mb_M.get_Matrix(), mb_S.get_Matrix(), 0.0);
170
	//ArpackPP::ARluSymGenEig<double> dprob(number_of_eigenvalues, mb_M.get_Matrix(), mb_S.get_Matrix());
171
 
172
	dprob.FindEigenvectors();
173
	int conv = dprob.ConvergedEigenvalues();
174
	cout << conv << " eigenvectors found" << endl;
175
	Q.Resize(conv, dprob.GetN());
176
	V.Resize(conv);
177
 
178
	qnorm.Resize(conv);
179
	for(int i = 0; i < conv; i++)
386 jab 180
	{
457 jab 181
		V[i] = dprob.Eigenvalue(i);
182
		qnorm[i] = 0;
183
		for(int j = 0; j < dprob.GetN(); j++)
386 jab 184
		{
457 jab 185
			Q[i][j] = dprob.Eigenvector(i,j);
186
			qnorm[i] += Q[i][j]*Q[i][j];
386 jab 187
		}
457 jab 188
 
189
		cout << "(" << i << ":" << sqrt(V[i]/V[1]
190
										) << ")" << V[i]/V[1] << "V= "<< V[i] << " exp " << exp(-0.01*V[i]/V[1]) << " Qnorm " << qnorm[i]<< endl;
386 jab 191
	}
457 jab 192
 
193
	cout  << endl;
386 jab 194
}
195
 
457 jab 196
Harmonics::Harmonics(Manifold& _mani):mani(_mani)
197
{
198
	assert(is_initialized);
199
 
200
	maximum_eigenvalue = min(size_t(500),mani.no_vertices());
201
 
202
	triangulate(mani);
203
	mani.enumerate_vertices();
204
	make_laplace_operator_sparse();
205
 
206
	if(maximum_eigenvalue == -1)
386 jab 207
	{
457 jab 208
		cout << "not found" << endl;
209
		return;
210
	}
211
 
212
	proj.resize(maximum_eigenvalue);
213
 
214
	max_eig_values.resize(maximum_eigenvalue, 1e-10f);
215
 
216
	cout << endl << "Proj" << endl;
217
	for(int es=0; es<maximum_eigenvalue; ++es)  //o(n^2)
386 jab 218
	{
457 jab 219
		proj[es] = Vec3d(0.0);
596 jab 220
		for(VertexIter v=mani.vhandles_begin(); v != mani.vhandles_end(); ++v)
457 jab 221
		{
222
			proj[es] +=  Vec3d(v->pos) * Q[es][v->touched] * S[v->touched];
223
			max_eig_values[es] = max(max_eig_values[es], static_cast<float>(abs(Q[es][v->touched])));     
224
		}     
386 jab 225
	}
457 jab 226
	cout << endl;
386 jab 227
}
228
 
457 jab 229
#else
391 jab 230
void Harmonics::make_laplace_operator()
386 jab 231
{
232
	Q.Resize(mani.no_vertices(), mani.no_vertices());
233
 
596 jab 234
	for(VertexIDIterator v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
235
		if(!boundary(mani, *v)){
236
			int i = vtouched[*v];
237
			double area_i = voronoi_area(mani, *v);
238
			Vec3d vertex(mani.pos(*v));
386 jab 239
			Vec3d curv_normal(0);
240
			double a_sum = 0;
596 jab 241
            for(Walker wv = mani.walker(*v); !wv.full_circle(); wv = wv.circulate_vertex_cw())
386 jab 242
			{
596 jab 243
				int j = vtouched[wv.vertex()];
244
				double area_j = voronoi_area(mani, wv.vertex());
386 jab 245
 
596 jab 246
				Vec3d nbr(mani.pos(wv.vertex()));
247
				Vec3d left(mani.pos(wv.next().vertex()));
248
				Vec3d right(mani.pos(wv.opp().prev().opp().vertex()));
249
 
386 jab 250
				double d_left = dot(normalize(nbr-left),
251
									normalize(vertex-left));
252
				double d_right = dot(normalize(nbr-right),
253
									 normalize(vertex-right));
254
				double a_left  = acos(min(1.0, max(-1.0, d_left)));
255
				double a_right = acos(min(1.0, max(-1.0, d_right)));
256
 
257
				double w = 1.0/tan(a_left) + 1.0/tan(a_right);
258
 
259
				Q[i][j] = -w/sqrt(area_i*area_j);						
260
				//Q[i][j] = -1;						
261
				a_sum += Q[i][j];
262
			}
263
			Q[i][i] = -a_sum;
264
		}
265
	EigenSolutionsSym(Q,V);
266
}
267
 
596 jab 268
Harmonics::Harmonics(Manifold& _mani):mani(_mani), vtouched(_mani.allocated_vertices(), 0) 
386 jab 269
{
391 jab 270
	assert(is_initialized);
457 jab 271
 
596 jab 272
	triangulate_by_edge_face_split(mani);
273
 
274
    int i = 0;
275
    for(VertexIDIterator v = mani.vertices_begin(); v != mani.vertices_end(); ++v, ++i)
276
        vtouched[*v] = i;
391 jab 277
	maximum_eigenvalue = mani.no_vertices()-1;
278
	make_laplace_operator();
279
 
280
	proj.resize(maximum_eigenvalue);
409 jrf 281
	max_eig_values.resize(maximum_eigenvalue, 1e-10f);
457 jab 282
 
283
	cout << "Projection magnitude" << endl;
391 jab 284
	for(int es=0; es<maximum_eigenvalue; ++es)
386 jab 285
	{
399 jab 286
		proj[es] = Vec3d(0.0);
596 jab 287
		for(VertexIDIterator v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
386 jab 288
		{
596 jab 289
			proj[es] +=  Vec3d(mani.pos(*v)) * Q[es][vtouched[*v]];
290
			max_eig_values[es] = max(max_eig_values[es], static_cast<float>(abs(Q[es][vtouched[*v]])));
386 jab 291
		}
292
	}
293
}
294
 
457 jab 295
#endif
296
 
391 jab 297
void Harmonics::add_frequency(int es, float scale)
386 jab 298
{
391 jab 299
	if(es<maximum_eigenvalue)
596 jab 300
		for(VertexIDIterator v = mani.vertices_begin(); v != mani.vertices_end(); ++v){
301
			Vec3d p = Vec3d(proj[es]);
302
			double Qval = Q[es][vtouched[*v]];
399 jab 303
 
596 jab 304
			mani.pos(*v) += p * Qval * scale; 	
386 jab 305
		}
306
}
307
 
391 jab 308
void Harmonics::reset_shape()
386 jab 309
{
596 jab 310
	for(VertexIDIterator v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
311
		mani.pos(*v) = Vec3d(0);	
386 jab 312
}
391 jab 313
void Harmonics::partial_reconstruct(int E0, int E1, float scale)
386 jab 314
{
315
	for(int es=E0;es<=E1;++es)
391 jab 316
		add_frequency(es, scale);
386 jab 317
}
318
 
596 jab 319
Console::variable<float> display_harmonics_time;
320
Console::variable<int> display_harmonics_diffuse;
321
Console::variable<int> display_harmonics_highlight;
322
 
391 jab 323
void Harmonics::parse_key(unsigned char key)
386 jab 324
{
457 jab 325
	switch(key) {
326
		case '+': 
596 jab 327
			display_harmonics_time = display_harmonics_time+0.001; 
457 jab 328
			break;
329
		case '-': 
596 jab 330
			display_harmonics_time = display_harmonics_time-0.001; 
457 jab 331
			break;
332
		case 'd':	
596 jab 333
			display_harmonics_diffuse = !display_harmonics_diffuse; 
457 jab 334
			break;
335
		case 'h':
596 jab 336
			display_harmonics_highlight = !display_harmonics_highlight;
457 jab 337
			break;			
338
	}
339
 
391 jab 340
}
341
 
457 jab 342
 
343
void Harmonics::draw_adf()
391 jab 344
{
457 jab 345
	vector<double> F(mani.no_vertices(),0);
346
	double F_max = 0;
596 jab 347
	for(VertexIDIterator v = mani.vertices_begin(); v != mani.vertices_end(); ++v){
348
		int v_idx = vtouched[*v];
349
		for(int e = 1; e < V.Length(); ++e)
350
			F[v_idx] += sqr(Q[e][v_idx]) * exp(-(display_harmonics_time)*V[e]/V[1]);
457 jab 351
		F_max = max(F[v_idx], F_max);
352
	}
353
	cout << "F max" <<  F_max << endl;
386 jab 354
	glUseProgram(prog_P0);
457 jab 355
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max"),F_max);//2*M_PI);
596 jab 356
	glUniform1i(glGetUniformLocation(prog_P0,"do_diffuse"),display_harmonics_diffuse);
357
   	glUniform1i(glGetUniformLocation(prog_P0,"do_highlight"),display_harmonics_highlight);
386 jab 358
	GLuint attrib = glGetAttribLocationARB(prog_P0, "eigenvalue");
359
 
360
	glFrontFace(GL_CW);
596 jab 361
	for(FaceIDIterator f = mani.faces_begin(); f != mani.faces_end(); ++f){
386 jab 362
		glBegin(GL_TRIANGLES);
596 jab 363
        for(Walker w = mani.walker(*f); !w.full_circle(); w = w.circulate_face_cw()){
364
			int i = vtouched[w.vertex()];
457 jab 365
			glVertexAttrib1f(attrib,F[i]);
596 jab 366
			glNormal3dv(normal(mani, w.vertex()).get());
367
			glVertex3dv(mani.pos(w.vertex()).get());
386 jab 368
		}
369
		glEnd();
370
	}
371
	glFrontFace(GL_CCW);
372
	glUseProgram(0);
373
}
374
 
596 jab 375
void Harmonics::init(Console& cs)
386 jab 376
{
391 jab 377
	is_initialized = true;
386 jab 378
	string shader_path = "/Users/jab/GEL/apps/MeshEdit/";
397 jab 379
	GLuint vs = create_glsl_shader(GL_VERTEX_SHADER, vss);
380
	GLuint fs = create_glsl_shader(GL_FRAGMENT_SHADER, fss);
386 jab 381
 
382
	// Create the program
383
	prog_P0 = glCreateProgram();
384
 
385
	// Attach all shaders
386
	if(vs) glAttachShader(prog_P0, vs);
387
	if(fs) glAttachShader(prog_P0, fs);
388
 
389
	// Link the program object and print out the info log
390
	glLinkProgram(prog_P0);
391
	print_glsl_program_log(prog_P0);
392
 
393
	// Install program object as part of current state
394 jab 394
	glUseProgram(0);
388 jab 395
 
596 jab 396
    display_harmonics_diffuse.reg(cs, "display.harmonics.diffuse", "");    
397
    display_harmonics_time.reg(cs, "display.harmonics.time", ""); 
398
    display_harmonics_highlight.reg(cs, "display.harmonics.highlight", "");
399
 
400
 
386 jab 401
}