Subversion Repositories gelsvn

Rev

Rev 416 | Rev 596 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 416 Rev 457
Line 6... Line 6...
6
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
6
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
7
 *
7
 *
8
 */
8
 */
9
 
9
 
10
#include <iostream>
10
#include <iostream>
-
 
11
 
-
 
12
#include "harmonics.h"
-
 
13
 
-
 
14
#if USE_SPARSE_MATRIX
-
 
15
#include <arlgsym.h>
-
 
16
#endif
-
 
17
 
11
#include <CGLA/Vec3f.h>
18
#include <CGLA/Vec3f.h>
12
#include <CGLA/Vec3d.h>
19
#include <CGLA/Vec3d.h>
-
 
20
#include <CGLA/Mat2x2d.h>
13
#include <LinAlg/Matrix.h>
21
#include <LinAlg/Matrix.h>
14
#include <LinAlg/Vector.h>
22
#include <LinAlg/Vector.h>
15
#include <LinAlg/LapackFunc.h>
23
#include <LinAlg/LapackFunc.h>
16
 
24
 
17
#include <GL/glew.h>
25
#include <GL/glew.h>
Line 26... Line 34...
26
#include <HMesh/load.h>
34
#include <HMesh/load.h>
27
#include <HMesh/x3d_save.h>
35
#include <HMesh/x3d_save.h>
28
 
36
 
29
#include <GLConsole/GLConsole.h>
37
#include <GLConsole/GLConsole.h>
30
 
38
 
31
#include "harmonics.h"
39
#include "curvature.h"
-
 
40
#include "CSCMatrixBuilder.h"
32
 
41
 
33
using namespace CGLA;
42
using namespace CGLA;
34
using namespace std;
43
using namespace std;
35
using namespace HMesh;
44
using namespace HMesh;
36
using namespace Geometry;
45
using namespace Geometry;
Line 42... Line 51...
42
GLuint Harmonics::prog_P0;
51
GLuint Harmonics::prog_P0;
43
 
52
 
44
 
53
 
45
namespace
54
namespace
46
{
55
{
47
 
56
	
48
	string vss =
57
	string vss =
49
"#version 120\n"
58
	"#version 120\n"
50
"#extension GL_EXT_gpu_shader4 : enable\n"
59
	"#extension GL_EXT_gpu_shader4 : enable\n"
51
"	\n"
60
	"	\n"
52
"	\n"
61
	"	\n"
53
"	attribute float eigenvalue;\n"
62
	"	attribute float eigenvalue;\n"
54
"	attribute float eigenvalue2;\n"
63
	"	attribute float eigenvalue2;\n"
55
"	varying vec3 normal;\n"
64
	"	varying vec3 normal;\n"
56
"	varying float eig;\n"
65
	"	varying float eig;\n"
57
"	varying float eig2;\n"
66
	"	varying float eig2;\n"
58
"	\n"
67
	"	\n"
59
"	void main(void)\n"
68
	"	void main(void)\n"
60
"	{\n"
69
	"	{\n"
61
"		gl_Position =  ftransform();\n"
70
	"		gl_Position =  ftransform();\n"
62
"		normal = normalize(gl_NormalMatrix * gl_Normal);\n"
71
	"		normal = normalize(gl_NormalMatrix * gl_Normal);\n"
63
"		eig = eigenvalue;\n"
72
	"		eig = eigenvalue;\n"
64
"		eig2 = eigenvalue2;\n"
73
	"		eig2 = eigenvalue2;\n"
65
"	}\n";
74
	"	}\n";
66
	
-
 
67
string fss = 	
-
 
68
"#version 120\n"
-
 
69
"#extension GL_EXT_gpu_shader4 : enable\n"
-
 
70
"	\n"
-
 
71
"	varying vec3 normal;\n"
-
 
72
"	varying float eig;\n"
-
 
73
"	varying float eig2;\n"
-
 
74
"	uniform float eig_max;\n"
-
 
75
"	uniform float eig_max2;\n"
-
 
76
"	uniform bool do_highlight;\n"
-
 
77
"	uniform bool do_diffuse;\n"
-
 
78
"	const vec3 light_dir = vec3(0,0,1);\n"
-
 
79
"	\n"
-
 
80
"	void main()\n"
-
 
81
"	{\n"
-
 
82
"		float dot_ln = dot(light_dir, normal);\n"
-
 
83
"		\n"
-
 
84
"		float eig_norm = eig/eig_max;\n"
-
 
85
"		float stripe_signal = 100 * eig_norm;\n"
-
 
86
"		vec4 stripe_col = abs(stripe_signal) < 3.14 ? vec4(1,1,0,0) : vec4(.1,.1,.1,0);\n"
-
 
87
"		\n"
-
 
88
"		gl_FragColor = eig_norm * vec4(-1,0,1,0);\n"
-
 
89
"		if(do_diffuse)   gl_FragColor *= dot_ln;\n"
-
 
90
"		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"
-
 
91
"		gl_FragColor += stripe_col * smoothstep(0.8,1.0,cos(stripe_signal));\n"
-
 
92
"	}\n";
-
 
93
	
75
	
-
 
76
	string fss = 	
-
 
77
	"#version 120\n"
-
 
78
	"#extension GL_EXT_gpu_shader4 : enable\n"
-
 
79
	"	\n"
-
 
80
	"	varying vec3 normal;\n"
-
 
81
	"	varying float eig;\n"
-
 
82
	"	varying float eig2;\n"
-
 
83
	"	uniform float eig_max;\n"
-
 
84
	"	uniform float eig_max2;\n"
94
	double voronoi_area(VertexIter v)
85
	"	uniform bool do_highlight;\n"
-
 
86
	"	uniform bool do_diffuse;\n"
-
 
87
	"	const vec3 light_dir = vec3(0,0,1);\n"
-
 
88
	"	\n"
-
 
89
	" float basef(float x) {return max(0.0,min(1.0,2.0-4.0*abs(x)));\n}" 
-
 
90
	"	void main()\n"
95
	{
91
	"	{\n"
-
 
92
	"		float dot_ln = max(0.0,dot(light_dir, normal));\n"
-
 
93
	"		\n"
96
	double area_mixed = 0;
94
	"		float eig_norm = eig/eig_max;\n"
97
	//For each triangle T from the 1-ring neighborhood of x
95
	"		float stripe_signal = 250 * eig_norm;\n"
-
 
96
	//"		vec4 stripe_col = abs(stripe_signal) < 3.14 ? vec4(1,1,0,0) : vec4(.4,.4,.4,0);\n"
98
	for(VertexCirculator vc(v); !vc.end(); ++vc)
97
	"		vec4 stripe_col = -vec4(.4,.4,.4,0);\n"
-
 
98
	"		\n"
-
 
99
	"       float alpha = (1.0-eig_norm) * 2.0 * 3.1415926;\n"
-
 
100
	"       float offs = 2.0*3.1415/3.0;\n"
-
 
101
	"		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"
-
 
102
	"		if(do_diffuse)   gl_FragColor *= dot_ln;\n"
-
 
103
	"		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"
-
 
104
	"		gl_FragColor -= vec4(.4,.4,.4,.4)*smoothstep(0.2,0.6,cos(stripe_signal));\n"
-
 
105
	"	}\n";
99
	{
106
}
-
 
107
 
-
 
108
 
-
 
109
 
100
		FaceIter f = vc.get_face();
110
#if USE_SPARSE_MATRIX
-
 
111
 
101
		double f_area = area(f);
112
double calculate_laplace_entry(VertexCirculator vc,Vec3d vertex)
102
		
113
{
-
 
114
	//* this piece of code is taken from the orginal make_laplace_operator...
103
		HalfEdgeIter he = vc.get_halfedge();
115
	HalfEdgeIter h = vc.get_halfedge();
104
		Vec3d v1(he->vert->pos);
116
	Vec3d nbr(h->vert->pos);
105
		Vec3d v2(he->next->vert->pos);
117
	Vec3d left(h->next->vert->pos);
106
		Vec3d v0(he->next->next->vert->pos);
118
	Vec3d right(h->opp->prev->opp->vert->pos);
107
		
119
	
108
		double a0 = acos(dot(v1-v0, v2-v0)/(length(v1-v0)*length(v2-v0)));
120
	double d_left = dot(normalize(nbr-left),normalize(vertex-left));
-
 
121
	double d_right = dot(normalize(nbr-right),normalize(vertex-right));
109
		double a1 = acos(dot(v2-v1, v0-v1)/(length(v2-v1)*length(v0-v1)));
122
	double a_left  = acos(min(1.0, max(-1.0, d_left))); // w positive...?
110
		double a2 = acos(dot(v0-v2, v1-v2)/(length(v0-v2)*length(v1-v2)));
123
	double a_right = acos(min(1.0, max(-1.0, d_right)));
111
		
124
	
-
 
125
	double w = 1.0/tan(a_left) + 1.0/tan(a_right);
-
 
126
	return -w;
-
 
127
}
-
 
128
 
-
 
129
void Harmonics::make_laplace_operator_sparse()
-
 
130
{
-
 
131
	bool is_generalized=true;
-
 
132
	CSCMatrixBuilder<double> mb_M;
-
 
133
	//+GENERALIZED
-
 
134
	CSCMatrixBuilder<double> mb_S;
-
 
135
	// S has the same type as V
-
 
136
	S.Resize(mani.no_vertices());
-
 
137
	
112
		if(a0>(M_PI/2.0) && a1>(M_PI/2.0) && a2>(M_PI/2.0)) // f is non-obtuse
138
	for(VertexIter v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
-
 
139
		if(!is_boundary(v))
113
		{
140
		{
-
 
141
			int i = v->touched;
-
 
142
			double area_i = voronoi_area(v);
-
 
143
			Vec3d vertex(v->pos);
-
 
144
			double a_sum = 0;
114
			// Add Voronoi formula (see Section 3.3)
145
			for(VertexCirculator vc(v); !vc.end(); ++vc)
-
 
146
			{
-
 
147
				int j = vc.get_vertex()->touched;
-
 
148
				double entry = calculate_laplace_entry(vc,vertex);
115
			area_mixed += (1.0/8) * 
149
				if(!is_generalized)
-
 
150
				{
-
 
151
					double area_j = voronoi_area(vc.get_vertex());
116
			((1.0/tan(a1)) * sqr_length(v2-v0) + 
152
					entry /= sqrt(area_i*area_j);
-
 
153
				}
-
 
154
				if(j > i)
117
			 (1.0/tan(a2)) * sqr_length(v1-v0));
155
					mb_M.insert_entry(j,entry);
-
 
156
				a_sum += entry;
118
		}
157
			}
-
 
158
			//cout << a_sum << " ";
-
 
159
			mb_M.insert_entry(i,-a_sum);
-
 
160
			mb_M.next_column();
-
 
161
			
-
 
162
			if(!is_generalized)
-
 
163
				area_i = 1; // if standard S is an identity matrix;
-
 
164
			mb_S.insert_entry(i,area_i);
-
 
165
			mb_S.next_column_nonsort();
-
 
166
			S[i] = area_i;
-
 
167
		}     
-
 
168
	
-
 
169
	cout << "solving generalized problem... i = " << mani.no_vertices()<< endl;
-
 
170
	
-
 
171
	
-
 
172
	//+STANDARD
-
 
173
	//ArpackPP::ARluSymStdEig<double> dprob(50L, mb_M.get_Matrix(), "SA");
-
 
174
	//+GENERALIZED (shifted inv mode)
-
 
175
	ARluSymGenEig<double> dprob('S',maximum_eigenvalue, mb_M.get_Matrix(), mb_S.get_Matrix(), 0.0);
-
 
176
	//ArpackPP::ARluSymGenEig<double> dprob(number_of_eigenvalues, mb_M.get_Matrix(), mb_S.get_Matrix());
-
 
177
	
-
 
178
	dprob.FindEigenvectors();
-
 
179
	int conv = dprob.ConvergedEigenvalues();
-
 
180
	cout << conv << " eigenvectors found" << endl;
-
 
181
	Q.Resize(conv, dprob.GetN());
-
 
182
	V.Resize(conv);
-
 
183
	
-
 
184
	qnorm.Resize(conv);
-
 
185
	for(int i = 0; i < conv; i++)
-
 
186
	{
119
		else // Voronoi inappropriate
187
		V[i] = dprob.Eigenvalue(i);
-
 
188
		qnorm[i] = 0;
-
 
189
		for(int j = 0; j < dprob.GetN(); j++)
120
		{
190
		{
121
			// Add either area(f)/4 or area(f)/2
191
			Q[i][j] = dprob.Eigenvector(i,j);
122
			if(a0>M_PI/2.0)// the angle of f at x is obtuse
-
 
123
				area_mixed += f_area/2;
192
			qnorm[i] += Q[i][j]*Q[i][j];
124
			else
-
 
125
				area_mixed += f_area/4;
-
 
126
		}
193
		}
-
 
194
		
-
 
195
		cout << "(" << i << ":" << sqrt(V[i]/V[1]
-
 
196
										) << ")" << V[i]/V[1] << "V= "<< V[i] << " exp " << exp(-0.01*V[i]/V[1]) << " Qnorm " << qnorm[i]<< endl;
127
	}
197
	}
-
 
198
	
128
	return area_mixed;
199
	cout  << endl;
129
}
200
}
130
 
201
 
-
 
202
Harmonics::Harmonics(Manifold& _mani):mani(_mani)
-
 
203
{
-
 
204
	assert(is_initialized);
-
 
205
	
-
 
206
	maximum_eigenvalue = min(size_t(500),mani.no_vertices());
-
 
207
	
-
 
208
	triangulate(mani);
131
	double barycentric_area(VertexIter v)
209
	mani.enumerate_vertices();
-
 
210
	make_laplace_operator_sparse();
-
 
211
	
-
 
212
	if(maximum_eigenvalue == -1)
132
	{
213
	{
133
	double barea = 0;
214
		cout << "not found" << endl;
-
 
215
		return;
-
 
216
	}
-
 
217
	
-
 
218
	proj.resize(maximum_eigenvalue);
-
 
219
	
134
	//For each triangle T from the 1-ring neighborhood of x
220
	max_eig_values.resize(maximum_eigenvalue, 1e-10f);
-
 
221
	
-
 
222
	cout << endl << "Proj" << endl;
135
	for(VertexCirculator vc(v); !vc.end(); ++vc)
223
	for(int es=0; es<maximum_eigenvalue; ++es)  //o(n^2)
136
	{
224
	{
137
		FaceIter f = vc.get_face();
225
		proj[es] = Vec3d(0.0);
-
 
226
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
-
 
227
		{
-
 
228
			proj[es] +=  Vec3d(v->pos) * Q[es][v->touched] * S[v->touched];
-
 
229
			max_eig_values[es] = max(max_eig_values[es], static_cast<float>(abs(Q[es][v->touched])));     
138
		barea += area(f)/3.0;
230
		}     
139
	}
231
	}
140
	return barea;
232
	cout << endl;
141
}
-
 
142
 
-
 
143
}
233
}
144
 
234
 
-
 
235
#else
145
void Harmonics::make_laplace_operator()
236
void Harmonics::make_laplace_operator()
146
{
237
{
147
	Q.Resize(mani.no_vertices(), mani.no_vertices());
238
	Q.Resize(mani.no_vertices(), mani.no_vertices());
148
	
239
	
149
	for(VertexIter v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
240
	for(VertexIter v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
Line 179... Line 270...
179
			Q[i][i] = -a_sum;
270
			Q[i][i] = -a_sum;
180
		}
271
		}
181
	EigenSolutionsSym(Q,V);
272
	EigenSolutionsSym(Q,V);
182
}
273
}
183
 
274
 
184
 
-
 
185
Harmonics::Harmonics(Manifold& _mani):mani(_mani)
275
Harmonics::Harmonics(Manifold& _mani):mani(_mani)
186
{
276
{
187
	assert(is_initialized);
277
	assert(is_initialized);
188
		
278
	
189
	triangulate(mani);
279
	triangulate(mani);
190
	mani.enumerate_vertices();
280
	mani.enumerate_vertices();
191
	maximum_eigenvalue = mani.no_vertices()-1;
281
	maximum_eigenvalue = mani.no_vertices()-1;
192
	make_laplace_operator();
282
	make_laplace_operator();
193
	
283
	
194
	proj.resize(maximum_eigenvalue);
284
	proj.resize(maximum_eigenvalue);
195
	max_eig_values.resize(maximum_eigenvalue, 1e-10f);
285
	max_eig_values.resize(maximum_eigenvalue, 1e-10f);
196
 
286
	
-
 
287
	cout << "Projection magnitude" << endl;
197
	for(int es=0; es<maximum_eigenvalue; ++es)
288
	for(int es=0; es<maximum_eigenvalue; ++es)
198
	{
289
	{
199
		proj[es] = Vec3d(0.0);
290
		proj[es] = Vec3d(0.0);
200
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
291
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
201
		{
292
		{
202
 
-
 
203
			proj[es] +=  Vec3d(v->pos) * Q[es][v->touched];
293
			proj[es] +=  Vec3d(v->pos) * Q[es][v->touched];
204
			max_eig_values[es] = max(max_eig_values[es], static_cast<float>(abs(Q[es][v->touched])));
294
			max_eig_values[es] = max(max_eig_values[es], static_cast<float>(abs(Q[es][v->touched])));
205
		}
295
		}
206
	}
296
	}
207
}
297
}
208
 
298
 
-
 
299
#endif
-
 
300
 
209
void Harmonics::add_frequency(int es, float scale)
301
void Harmonics::add_frequency(int es, float scale)
210
{
302
{
211
	if(es<maximum_eigenvalue)
303
	if(es<maximum_eigenvalue)
212
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
304
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
213
		{
305
		{
Line 229... Line 321...
229
		add_frequency(es, scale);
321
		add_frequency(es, scale);
230
}
322
}
231
 
323
 
232
void Harmonics::parse_key(unsigned char key)
324
void Harmonics::parse_key(unsigned char key)
233
{
325
{
234
		int& display_eigenvalue = GetCVarRef<int>("display.harmonics.eigenvalue");
326
	float& display_t = GetCVarRef<float>("display.harmonics.time");
235
		int& display_diffuse = GetCVarRef<int>("display.harmonics.diffuse");
327
	int& display_diffuse = GetCVarRef<int>("display.harmonics.diffuse");
236
		int& display_highlight = GetCVarRef<int>("display.harmonics.highlight");
328
	int& display_highlight = GetCVarRef<int>("display.harmonics.highlight");
237
		switch(key) {
329
	switch(key) {
238
			case '+': 
330
		case '+': 
239
				display_eigenvalue = min(display_eigenvalue+1, maximum_eigenvalue); 
331
			display_t = display_t+0.001; 
240
				break;
332
			break;
241
			case '-': 
333
		case '-': 
242
				display_eigenvalue = max(display_eigenvalue-1, 0); 
334
			display_t = display_t-0.001; 
243
				break;
335
			break;
244
			case 'd':	
336
		case 'd':	
245
				display_diffuse = !display_diffuse; 
337
			display_diffuse = !display_diffuse; 
246
				break;
338
			break;
247
			case 'h':
339
		case 'h':
248
				display_highlight = !display_highlight;
340
			display_highlight = !display_highlight;
249
				break;			
341
			break;			
250
		}
342
	}
251
 
343
	
252
}
344
}
253
 
345
 
-
 
346
 
254
void Harmonics::draw()
347
void Harmonics::draw_adf()
255
{
348
{
256
	int& display_eigen = GetCVarRef<int>("display.harmonics.eigenvalue");
349
	float& t = GetCVarRef<float>("display.harmonics.time");
257
	int& display_eigen2 = GetCVarRef<int>("display.harmonics.eigenvalue");
-
 
258
	int& do_diffuse = GetCVarRef<int>("display.harmonics.diffuse");
350
	int& do_diffuse = GetCVarRef<int>("display.harmonics.diffuse");
259
	int& do_highlight = GetCVarRef<int>("display.harmonics.highlight");
351
	int& do_highlight = GetCVarRef<int>("display.harmonics.highlight");
260
 
352
	
-
 
353
	vector<double> F(mani.no_vertices(),0);
-
 
354
	double F_max = 0;
-
 
355
	for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
-
 
356
	{
-
 
357
		int v_idx = v->touched;
-
 
358
		for(int e=1;e<V.Length();++e)
-
 
359
			F[v_idx] += sqr(Q[e][v_idx])*exp(-(t)*V[e]/V[1]);
-
 
360
		F_max = max(F[v_idx], F_max);
261
 
361
	}
-
 
362
	cout << "F max" <<  F_max << endl;
262
	glUseProgram(prog_P0);
363
	glUseProgram(prog_P0);
263
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max"),max_eig_values[display_eigen]);
364
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max"),F_max);//2*M_PI);
264
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max2"),max_eig_values[display_eigen2]);
-
 
265
	glUniform1i(glGetUniformLocation(prog_P0,"do_diffuse"),do_diffuse);
365
	glUniform1i(glGetUniformLocation(prog_P0,"do_diffuse"),do_diffuse);
266
   	glUniform1i(glGetUniformLocation(prog_P0,"do_highlight"),do_highlight);
366
   	glUniform1i(glGetUniformLocation(prog_P0,"do_highlight"),do_highlight);
267
	GLuint attrib = glGetAttribLocationARB(prog_P0, "eigenvalue");
367
	GLuint attrib = glGetAttribLocationARB(prog_P0, "eigenvalue");
268
	GLuint attrib2 = glGetAttribLocationARB(prog_P0, "eigenvalue2");
-
 
269
	
368
	
270
	glFrontFace(GL_CW);
369
	glFrontFace(GL_CW);
271
	for(FaceIter f=mani.faces_begin(); f != mani.faces_end(); ++f)
370
	for(FaceIter f=mani.faces_begin(); f != mani.faces_end(); ++f)
272
	{
371
	{
273
		FaceCirculator fc(f);
372
		FaceCirculator fc(f);
274
		glBegin(GL_TRIANGLES);
373
		glBegin(GL_TRIANGLES);
275
		while(!fc.end())
374
		while(!fc.end())
276
		{
375
		{
277
			int i = fc.get_vertex()->touched;
376
			int i = fc.get_vertex()->touched;
278
			glVertexAttrib1f(attrib,Q[display_eigen][i]);
377
			glVertexAttrib1f(attrib,F[i]);
279
			glVertexAttrib1f(attrib2,Q[display_eigen2][i]);
-
 
280
			glNormal3fv(normal(fc.get_vertex()).get());
378
			glNormal3fv(normal(fc.get_vertex()).get());
281
			glVertex3fv(fc.get_vertex()->pos.get());
379
			glVertex3fv(fc.get_vertex()->pos.get());
282
			++fc;
380
			++fc;
283
		}
381
		}
284
		glEnd();
382
		glEnd();
Line 306... Line 404...
306
	print_glsl_program_log(prog_P0);
404
	print_glsl_program_log(prog_P0);
307
	
405
	
308
	// Install program object as part of current state
406
	// Install program object as part of current state
309
	glUseProgram(0);
407
	glUseProgram(0);
310
	
408
	
311
	CreateCVar("display.harmonics.eigenvalue",0);
409
	CreateCVar("display.harmonics.time",0.0f);
312
	CreateCVar("display.harmonics.eigenvalue2",0);
410
	CreateCVar("display.harmonics.eigenvalue2",0);
313
	CreateCVar("display.harmonics.highlight",1);
411
	CreateCVar("display.harmonics.highlight",1);
314
	CreateCVar("display.harmonics.diffuse",1);
412
	CreateCVar("display.harmonics.diffuse",1);
-
 
413
	CreateCVar("display.harmonics.diffusion_distance_init_vertex",0);
315
 
414
	
316
}
415
}