clippingShader.cpp 11.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps  *
* version 0.1                                                                  *
* Copyright (C) 2009-2011, IGG Team, LSIIT, University of Strasbourg           *
*                                                                              *
* This library is free software; you can redistribute it and/or modify it      *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your     *
* option) any later version.                                                   *
*                                                                              *
* This library 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 Lesser General Public License  *
* for more details.                                                            *
*                                                                              *
* You should have received a copy of the GNU Lesser General Public License     *
* along with this library; if not, write to the Free Software Foundation,      *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.           *
*                                                                              *
* Web site: http://cgogn.u-strasbg.fr/                                         *
* Contact information: cgogn@unistra.fr                                        *
*                                                                              *
*******************************************************************************/

#include "Utils/clippingShader.h"

namespace CGoGN
{

namespace Utils
{

ClippingShader::ClippingShader()
{
35 36 37
	// Initialize clipping planes variables
	m_unif_clipPlanes = 0;
	/*m_clipPlaneQuaternion[0] = 1.0;
38 39
	m_clipPlaneQuaternion[1] = 0.0;
	m_clipPlaneQuaternion[2] = 0.0;
40
	m_clipPlaneQuaternion[3] = 0.0;*/
41
	
42
	// Initialize color attenuation variables
43 44
	m_colorAttenuationFactor = 0.0;
	m_unif_colorAttenuationFactor = 0;
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

	// Plane Drawer
	float planeSize = 100.0;
	m_planeDrawer = new Drawer();
	m_planeDrawer->newList(GL_COMPILE);
	m_planeDrawer->begin(GL_QUADS);
	m_planeDrawer->color3f(0.7, 0.7, 0.2);
	m_planeDrawer->vertex3f(-planeSize/2.0, -planeSize/2.0, 0.0);
	m_planeDrawer->vertex3f(-planeSize/2.0, planeSize/2.0, 0.0);
	m_planeDrawer->vertex3f(planeSize/2.0, planeSize/2.0, 0.0);
	m_planeDrawer->vertex3f(planeSize/2.0, -planeSize/2.0, 0.0);
	m_planeDrawer->end();
	m_planeDrawer->endList();
}

ClippingShader::~ClippingShader()
{
	delete m_planeDrawer;
63 64
}

65
void ClippingShader::setClippingPlaneEquation(Geom::Vec4f clipPlane, int planeIndex)
66
{
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
	// Check if the given index is not out of range
	if ((planeIndex < 0) || ((4*planeIndex) > ((int)m_clipPlanesEquations.size() - 1)))
	{
		CGoGNerr
		<< "ERROR - "
		<< "ClippingShader::setClippingPlaneEquation"
		<< " - Given plane index is out of range"
		<< CGoGNendl;
		return;
	}

	// Copy the given clipPlane
	int i;
	for (i = 0; i < 4; i++)
		m_clipPlanesEquations[4*planeIndex + i] = clipPlane[i];
82 83

	// Recalculate quaternion rotation
84
	/*float m[4][4];
85 86 87 88 89 90
	build_rotmatrix(m, m_clipPlaneQuaternion);
	Geom::Matrix44f rotMat;
	int i, j;
	for (i = 0; i < 4; i++)
		for (j = 0; j < 4; j++)
			rotMat(i, j) = m[i][j];
91
	Geom::Vec4f rotatedVec = rotMat * m_clipPlaneEquation;*/
92

93 94
	// Send again the whole planes equations array to shader
	sendClippingPlanesUniform();
95 96
}

97
Geom::Vec4f ClippingShader::getClippingPlaneEquation(int planeIndex)
98
{
99 100 101 102 103
	// Check if the given index is not out of range
	if ((planeIndex < 0) || (4*planeIndex > ((int)m_clipPlanesEquations.size() - 1)))
	{
		CGoGNerr
		<< "ERROR - "
104
		<< "ClippingShader::getClippingPlaneEquation"
105 106 107 108 109 110 111 112 113 114 115 116
		<< " - Given plane index is out of range"
		<< CGoGNendl;
		return Geom::Vec4f(0.0, 0.0, 0.0, 0.0);
	}
	else
	{
		return Geom::Vec4f(
				m_clipPlanesEquations[4*planeIndex + 0],
				m_clipPlanesEquations[4*planeIndex + 1],
				m_clipPlanesEquations[4*planeIndex + 2],
				m_clipPlanesEquations[4*planeIndex + 3]);
	}
117 118
}

119
/*void ClippingShader::setClippingPlaneQuaternion(float quat[4])
120 121 122 123 124 125
{
	m_clipPlaneQuaternion[0] = quat[0];
	m_clipPlaneQuaternion[1] = quat[1];
	m_clipPlaneQuaternion[2] = quat[2];
	m_clipPlaneQuaternion[3] = quat[3];

126
	// Recalculate and send again the clipping plane equation
127 128 129 130 131 132
	setClippingPlaneEquation(m_clipPlaneEquation);
}

Geom::Vec4f ClippingShader::getClippingPlaneQuaternion()
{
	return Geom::Vec4f (m_clipPlaneQuaternion[0], m_clipPlaneQuaternion[1], m_clipPlaneQuaternion[2], m_clipPlaneQuaternion[3]);
133
}*/
134 135 136

void ClippingShader::setClippingColorAttenuationFactor(float colorAttenuationFactor)
{
137
	// Copy the given value
138
	m_colorAttenuationFactor = colorAttenuationFactor;
139 140 141

	// Send again the uniform to shader
	sendColorAttenuationFactorUniform();
142 143
}

144 145 146 147 148
float ClippingShader::getClippingColorAttenuationFactor()
{
	return m_colorAttenuationFactor;
}

149
void ClippingShader::setPlaneClipping(int planesCount)
150
{
151 152 153 154 155 156 157 158 159 160 161
	// Verify that the given clipping planes count is valid
	if (planesCount < 0)
	{
		CGoGNerr
		<< "ERROR - "
		<< "ClippingShader::setPlanesClipping"
		<< " - Given clipping planes count given is not positive !"
		<< CGoGNendl;
		return;
	}

162 163 164
	// Shader name
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

165 166 167 168 169
	// Verify that the shader has been well created
	if (!isCreated())
	{
		CGoGNerr
		<< "ERROR - "
170
		<< "ClippingShader::setPlaneClipping"
171
		<< " - Could not process shader "
172
		<< shaderName
173 174 175 176 177 178 179 180 181 182
		<< " source code : shader has not been created or has failed to compile"
		<< CGoGNendl;
		return;
	}
	
	// Verify that the shader does not use a geometry shader
	if (getGeometryShaderSrc() != NULL)
	{
		CGoGNerr
		<< "ERROR - "
183
		<< "ClippingShader::setPlaneClipping"
184
		<< " - Could not process shader "
185
		<< shaderName
186 187 188 189 190
		<< " source code : unable to add clipping to a shader which uses a geometry shader"
		<< CGoGNendl;
		return;
	}

191 192 193 194 195
	// String for clipping planes count
	std::string planesCountStr;
	std::stringstream ss;
	ss << planesCount;
	planesCountStr = ss.str();
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210
	// Strings that will be inserted into the source code

	std::string VS_head_insertion =
	"\n"
	"VARYING_VERT vec3 clip_NonTransformedPos;\n"
	"\n";

	std::string VS_mainBegin_insertion =
	"\n"
	"	// Pass the non transformed vertex position to the fragment shader for clipping\n"
	"	clip_NonTransformedPos = VertexPosition;\n";

	std::string FS_head_insertion =
	"\n"
211
	"#define CLIP_PLANES_COUNT " + planesCountStr + "\n"
212
	"\n"
213
	"uniform vec4 clip_ClipPlanes[CLIP_PLANES_COUNT];\n"
214 215 216 217 218 219 220
	"uniform float clip_ColorAttenuationFactor;\n"
	"\n"
	"VARYING_FRAG vec3 clip_NonTransformedPos;\n"
	"\n";

	std::string FS_mainBegin_insertion =
	"\n"
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
	"	// Distance to the nearest plane, stored for color attenuation\n"
	"	float clip_MinDistanceToPlanes = -1.0;\n"
	"\n"
	"	// Do clipping for each plane\n"
	"	int i;\n"
	"	for (i = 0; i < CLIP_PLANES_COUNT; i++)\n"
	"	{\n"
	"		// Copy the plane to make it modifiable\n"
	"		vec4 clip_CurrClipPlane = clip_ClipPlanes[i];\n"
	"\n"
	"		// If the plane normal is zero, use a default normal vector (0.0, 0.0, 1.0)\n"
	"		float clip_NPlane = length(clip_CurrClipPlane.xyz);\n"
	"		if (clip_NPlane == 0.0)\n"
	"		{\n"
	"			clip_CurrClipPlane.z = 1.0;\n"
	"			clip_NPlane = 1.0;\n"
	"		}\n"
	"\n"
	"		// Signed distance between the point and the plane\n"
240 241
	"		float clip_DistanceToPlane = dot(clip_NonTransformedPos, clip_CurrClipPlane.xyz);\n"
	"		clip_DistanceToPlane += clip_CurrClipPlane.w;\n"
242 243
	"		clip_DistanceToPlane /= clip_NPlane;\n"
	"\n"
244 245 246 247 248 249 250 251 252 253 254 255
	"		// Keep the fragment only if it is 'above' the plane\n"
	"		if (clip_DistanceToPlane < 0.0)\n"
	"			discard;\n"
	"		// Else keep the positive distance to the nearest plane\n"
	"		else\n"
	"		{\n"
	"			if (clip_MinDistanceToPlanes < 0.0)\n"
	"				clip_MinDistanceToPlanes = clip_DistanceToPlane;\n"
	"			else\n"
	"				clip_MinDistanceToPlanes = min(clip_MinDistanceToPlanes, clip_DistanceToPlane);\n"
	"		}\n"
	"	}\n";
256 257 258

	std::string FS_mainEnd_insertion =
	"\n"
259 260 261
	"	// Attenuate the final fragment color depending on its distance to the nearest plane\n"
	"	if (clip_MinDistanceToPlanes > 0.0)\n"
	"		gl_FragColor.rgb /= (1.0 + clip_MinDistanceToPlanes*clip_ColorAttenuationFactor);\n";
262

263

264 265
	// If the previous planes count was zero, the previous shader source codes were the original ones. Store them
	// (the planes count is initially zero when the object is constructed)
266
	if (getClippingPlanesCount() == 0)
267
	{
268 269
		originalVertShaderSrc = getVertexShaderSrc();
		originalFragShaderSrc = getFragmentShaderSrc();
270
	}
271 272 273 274 275 276 277

	// If the given plane count is > 0, modify the original shader sources
	if (planesCount > 0)
	{

		// Use a shader mutator
		ShaderMutator SM(shaderName, originalVertShaderSrc, originalFragShaderSrc, "");
278
	
279
		// First check if the vertex shader contains the VertexPosition attribute
280
		if (!SM.containsVariableDeclaration(ShaderMutator::VERTEX_SHADER, "VertexPosition"))
281 282 283 284 285 286 287 288 289 290 291 292
		{
			CGoGNerr
			<< "ERROR - "
			<< "ClippingShader::setPlaneClipping"
			<< " - Could not process shader "
			<< m_nameVS
			<< " source code : no VertexPosition attribute found"
			<< CGoGNendl;
			return;
		}

		// Modify vertex shader source code
293 294 295
		SM.insertCodeBeforeMainFunction(ShaderMutator::VERTEX_SHADER, VS_head_insertion);
		SM.insertCodeAtMainFunctionBeginning(ShaderMutator::VERTEX_SHADER, VS_mainBegin_insertion);

296 297

		// Modify fragment shader source code
298 299 300 301
		SM.setMinShadingLanguageVersion(ShaderMutator::FRAGMENT_SHADER, 120); // Following code insertions need at least shading language 120 (GLSL arrays)
		SM.insertCodeBeforeMainFunction(ShaderMutator::FRAGMENT_SHADER, FS_head_insertion);
		SM.insertCodeAtMainFunctionEnd(ShaderMutator::FRAGMENT_SHADER, FS_mainEnd_insertion);
		SM.insertCodeAtMainFunctionBeginning(ShaderMutator::FRAGMENT_SHADER, FS_mainBegin_insertion);
302

303 304 305
		// Reload both shaders
		reloadVertexShaderFromMemory(SM.getModifiedVertexShaderSrc().c_str());
		reloadFragmentShaderFromMemory(SM.getModifiedFragmentShaderSrc().c_str());
306

307 308 309 310 311 312 313 314
	}
	// Else no clipping is wanted anymore, so get back the original shader sources
	else
	{
		// Reload both original shaders
		reloadVertexShaderFromMemory(originalVertShaderSrc.c_str());
		reloadFragmentShaderFromMemory(originalFragShaderSrc.c_str());
	}
315

316 317 318
	// Resize the planes equations uniform to the right size
	m_clipPlanesEquations.resize(4*(size_t)planesCount, 0.0);

319
	// Recompile shaders (automatically calls updateClippingUniforms)
320 321 322 323 324
	recompile();
}

void ClippingShader::updateClippingUniforms()
{
325 326 327 328
	// These uniforms only exist if the clipping planes count is > 0
	if (getClippingPlanesCount() <= 0)
		return;

329 330 331
	// Shader name
	std::string shaderName = m_nameVS + "/" + m_nameFS + "/" + m_nameGS;

332
	// Get uniforms locations
333 334
	m_unif_clipPlanes = glGetUniformLocation(program_handler(), "clip_ClipPlanes");
	if (m_unif_clipPlanes == -1)
335 336 337
	{
		CGoGNerr
		<< "ERROR - "
338
		<< "ClippingShader::updateClippingUniforms"
339
		<< " - uniform 'clip_ClipPlane' not found in shader "
340
		<< shaderName
341 342 343 344 345 346 347
		<< CGoGNendl;
	}
	m_unif_colorAttenuationFactor = glGetUniformLocation(program_handler(), "clip_ColorAttenuationFactor");
	if (m_unif_colorAttenuationFactor == -1)
	{
		CGoGNerr
		<< "ERROR - "
348
		<< "ClippingShader::updateClippingUniforms"
349
		<< " - uniform 'clip_ColorAttenuationFactor' not found in shader "
350
		<< shaderName
351 352 353
		<< CGoGNendl;
	}
	
354 355 356
	// Send again uniforms values
	sendClippingPlanesUniform();
	sendColorAttenuationFactorUniform();
357 358
}

359 360 361 362 363 364 365 366 367 368 369 370
void ClippingShader::sendClippingPlanesUniform()
{
	bind();
	glUniform4fv(m_unif_clipPlanes, m_clipPlanesEquations.size()/4, &m_clipPlanesEquations.front());
}

void ClippingShader::sendColorAttenuationFactorUniform()
{
	bind();
	glUniform1f(m_unif_colorAttenuationFactor, m_colorAttenuationFactor);
}

371 372 373 374 375
void ClippingShader::displayClippingPlane()
{
	m_planeDrawer->callList();
}

376 377 378 379
} // namespace Utils

} // namespace CGoGN