1 /*=========================================================================
2
3 Program: Visualization Toolkit
4
5 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
6 All rights reserved.
7 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
8
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notice for more information.
12
13 =========================================================================*/
14 #include "vtkOpenGLGlyph3DHelper.h"
15
16 #include "vtkglVBOHelper.h"
17
18 #include "vtkBitArray.h"
19 #include "vtkCamera.h"
20 #include "vtkDataObject.h"
21 #include "vtkHardwareSelector.h"
22 #include "vtkMath.h"
23 #include "vtkMatrix3x3.h"
24 #include "vtkMatrix4x4.h"
25 #include "vtkNew.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkOpenGLError.h"
28 #include "vtkOpenGLRenderWindow.h"
29 #include "vtkOpenGLRenderer.h"
30 #include "vtkOpenGLShaderCache.h"
31 #include "vtkProperty.h"
32 #include "vtkShader.h"
33 #include "vtkShaderProgram.h"
34 #include "vtkTransform.h"
35
36
37 #include "vtkglGlyph3DVSFragmentLit.h"
38
39 using vtkgl::substitute;
40
41 //-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkOpenGLGlyph3DHelper)42 vtkStandardNewMacro(vtkOpenGLGlyph3DHelper)
43
44 //-----------------------------------------------------------------------------
45 vtkOpenGLGlyph3DHelper::vtkOpenGLGlyph3DHelper()
46 {
47 this->ModelTransformMatrix = NULL;
48 this->ModelNormalMatrix = NULL;
49 this->ModelColor = NULL;
50 this->UseFastPath = false;
51 this->UsingInstancing = false;
52
53 // we always tell our triangle VAO to emulate to be safe
54 // this is because it seems that GLEW_ARB_vertex_array_object
55 // does not always handle the attributes for GLEW_ARB_instanced_arrays
56 this->Tris.vao.SetForceEmulation(true);
57 }
58
59 //-----------------------------------------------------------------------------
GetShaderTemplate(std::string & VSSource,std::string & FSSource,std::string & GSSource,int lightComplexity,vtkRenderer * ren,vtkActor * actor)60 void vtkOpenGLGlyph3DHelper::GetShaderTemplate(std::string &VSSource,
61 std::string &FSSource,
62 std::string &GSSource,
63 int lightComplexity, vtkRenderer* ren, vtkActor *actor)
64 {
65 this->Superclass::GetShaderTemplate(VSSource,FSSource,GSSource,lightComplexity,ren,actor);
66
67 VSSource = vtkglGlyph3DVSFragmentLit;
68 }
69
ReplaceShaderValues(std::string & VSSource,std::string & FSSource,std::string & GSSource,int lightComplexity,vtkRenderer * ren,vtkActor * actor)70 void vtkOpenGLGlyph3DHelper::ReplaceShaderValues(std::string &VSSource,
71 std::string &FSSource,
72 std::string &GSSource,
73 int lightComplexity,
74 vtkRenderer* ren,
75 vtkActor *actor)
76 {
77 if (lightComplexity > 0)
78 {
79 // we use vertex instead of vertexMC
80 substitute(VSSource,
81 "//VTK::PositionVC::Impl",
82 "vertexVC = MCVCMatrix * vertex;\n"
83 " gl_Position = MCDCMatrix * vertex;\n");
84 }
85
86 // deal with color
87 if (this->UsingInstancing)
88 {
89 substitute(VSSource,"//VTK::Color::Dec",
90 "attribute vec4 glyphColor;\n"
91 "varying vec4 vertexColor;");
92 }
93 else
94 {
95 substitute(VSSource,
96 "//VTK::Color::Dec",
97 "uniform vec4 glyphColor;\n"
98 "varying vec4 vertexColor;");
99 }
100 substitute(VSSource,"//VTK::Color::Impl",
101 "vertexColor = glyphColor;");
102
103
104 // crate the material/color property declarations, and VS implementation
105 // these are always defined
106 std::string colorDec =
107 "uniform float opacityUniform; // the fragment opacity\n"
108 "uniform vec3 ambientColorUniform; // intensity weighted color\n"
109 "uniform vec3 diffuseColorUniform; // intensity weighted color\n";
110 // add some if we have a backface property
111 if (actor->GetBackfaceProperty())
112 {
113 colorDec +=
114 "uniform float opacityUniformBF; // the fragment opacity\n"
115 "uniform vec3 ambientColorUniformBF; // intensity weighted color\n"
116 "uniform vec3 diffuseColorUniformBF; // intensity weighted color\n";
117 }
118 // add more for specular
119 if (lightComplexity)
120 {
121 colorDec +=
122 "uniform vec3 specularColorUniform; // intensity weighted color\n"
123 "uniform float specularPowerUniform;\n";
124 if (actor->GetBackfaceProperty())
125 {
126 colorDec +=
127 "uniform vec3 specularColorUniformBF; // intensity weighted color\n"
128 "uniform float specularPowerUniformBF;\n";
129 }
130 }
131 colorDec += "varying vec4 vertexColor;\n";
132 substitute(FSSource,"//VTK::Color::Dec", colorDec);
133
134 // now handle the more complex fragment shader implementation
135 // the following are always defined variables. We start
136 // by assiging a default value from the uniform
137 std::string colorImpl =
138 "vec3 ambientColor;\n"
139 " vec3 diffuseColor;\n"
140 " float opacity;\n";
141 if (lightComplexity)
142 {
143 colorImpl +=
144 " vec3 specularColor;\n"
145 " float specularPower;\n";
146 }
147 if (actor->GetBackfaceProperty())
148 {
149 if (lightComplexity)
150 {
151 colorImpl +=
152 " if (int(gl_FrontFacing) == 0) {\n"
153 " ambientColor = ambientColorUniformBF;\n"
154 " diffuseColor = diffuseColorUniformBF;\n"
155 " specularColor = specularColorUniformBF;\n"
156 " specularPower = specularPowerUniformBF;\n"
157 " opacity = opacityUniformBF; }\n"
158 " else {\n"
159 " ambientColor = ambientColorUniform;\n"
160 " diffuseColor = diffuseColorUniform;\n"
161 " specularColor = specularColorUniform;\n"
162 " specularPower = specularPowerUniform;\n"
163 " opacity = opacityUniform; }\n";
164 }
165 else
166 {
167 colorImpl +=
168 " if (int(gl_FrontFacing) == 0) {\n"
169 " ambientColor = ambientColorUniformBF;\n"
170 " diffuseColor = diffuseColorUniformBF;\n"
171 " opacity = opacityUniformBF; }\n"
172 " else {\n"
173 " ambientColor = ambientColorUniform;\n"
174 " diffuseColor = diffuseColorUniform;\n"
175 " opacity = opacityUniform; }\n";
176 }
177 }
178 else
179 {
180 colorImpl +=
181 " ambientColor = ambientColorUniform;\n"
182 " diffuseColor = diffuseColorUniform;\n"
183 " opacity = opacityUniform;\n";
184 if (lightComplexity)
185 {
186 colorImpl +=
187 " specularColor = specularColorUniform;\n"
188 " specularPower = specularPowerUniform;\n";
189 }
190 }
191
192 // now handle scalar coloring
193 if (this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT ||
194 (this->ScalarMaterialMode == VTK_MATERIALMODE_DEFAULT &&
195 actor->GetProperty()->GetAmbient() > actor->GetProperty()->GetDiffuse()))
196 {
197 substitute(FSSource,"//VTK::Color::Impl", colorImpl +
198 " ambientColor = vertexColor.rgb;\n"
199 " opacity = vertexColor.a;");
200 }
201 else if (this->ScalarMaterialMode == VTK_MATERIALMODE_DIFFUSE ||
202 (this->ScalarMaterialMode == VTK_MATERIALMODE_DEFAULT &&
203 actor->GetProperty()->GetAmbient() <= actor->GetProperty()->GetDiffuse()))
204 {
205 substitute(FSSource,"//VTK::Color::Impl", colorImpl +
206 " diffuseColor = vertexColor.rgb;\n"
207 " opacity = vertexColor.a;");
208 }
209 else
210 {
211 substitute(FSSource,"//VTK::Color::Impl", colorImpl +
212 " diffuseColor = vertexColor.rgb;\n"
213 " ambientColor = vertexColor.rgb;\n"
214 " opacity = vertexColor.a;");
215 }
216
217 if (this->UsingInstancing)
218 {
219 substitute(VSSource,
220 "//VTK::Glyph::Dec",
221 "attribute mat4 GCMCMatrix;");
222 }
223 else
224 {
225 substitute(VSSource,
226 "//VTK::Glyph::Dec",
227 "uniform mat4 GCMCMatrix;");
228 }
229 substitute(VSSource,
230 "//VTK::Glyph::Impl",
231 "vec4 vertex = GCMCMatrix * vertexMC;\n");
232
233 // new code for normal matrix if we have normals
234 if (this->Layout.NormalOffset)
235 {
236 if (this->UsingInstancing)
237 {
238 substitute(VSSource,
239 "//VTK::Normal::Dec",
240 "uniform mat3 normalMatrix;\n"
241 "attribute vec3 normalMC;\n"
242 "attribute mat3 glyphNormalMatrix;\n"
243 "varying vec3 normalVCVarying;");
244 }
245 else
246 {
247 substitute(VSSource,
248 "//VTK::Normal::Dec",
249 "uniform mat3 normalMatrix;\n"
250 "attribute vec3 normalMC;\n"
251 "uniform mat3 glyphNormalMatrix;\n"
252 "varying vec3 normalVCVarying;");
253 }
254 substitute(VSSource, "//VTK::Normal::Impl",
255 "normalVCVarying = normalMatrix * glyphNormalMatrix * normalMC;");
256 this->ShaderVariablesUsed.push_back("normalMatrix");
257 }
258
259 // override one part of the clipping code
260 if (this->GetNumberOfClippingPlanes())
261 {
262 // add all the clipping planes
263 int numClipPlanes = this->GetNumberOfClippingPlanes();
264 if (numClipPlanes > 6)
265 {
266 vtkErrorMacro(<< "OpenGL has a limit of 6 clipping planes");
267 numClipPlanes = 6;
268 }
269
270 substitute(VSSource,
271 "//VTK::Clip::Impl",
272 "for (int planeNum = 0; planeNum < numClipPlanes; planeNum++)\n"
273 " {\n"
274 " clipDistances[planeNum] = dot(clipPlanes[planeNum], vertex);\n"
275 " }\n");
276 }
277
278
279 this->Superclass::ReplaceShaderValues(VSSource,FSSource,GSSource,
280 lightComplexity,ren,actor);
281 }
282
283 //-----------------------------------------------------------------------------
~vtkOpenGLGlyph3DHelper()284 vtkOpenGLGlyph3DHelper::~vtkOpenGLGlyph3DHelper()
285 {
286 }
287
GlyphRender(vtkRenderer * ren,vtkActor * actor,vtkIdType numPts,std::vector<unsigned char> & colors,std::vector<float> & matrices,std::vector<float> & normalMatrices,std::vector<vtkIdType> & pickIds,unsigned long pointMTime)288 void vtkOpenGLGlyph3DHelper::GlyphRender(vtkRenderer* ren, vtkActor* actor, vtkIdType numPts,
289 std::vector<unsigned char> &colors, std::vector<float> &matrices,
290 std::vector<float> &normalMatrices, std::vector<vtkIdType> &pickIds,
291 unsigned long pointMTime)
292 {
293 this->CurrentInput = this->GetInput();
294 this->UsingInstancing = false;
295
296 vtkHardwareSelector* selector = ren->GetSelector();
297 bool selecting_points = selector && (selector->GetFieldAssociation() ==
298 vtkDataObject::FIELD_ASSOCIATION_POINTS);
299
300 #if GL_ES_VERSION_2_0 != 1 || GL_ES_VERSION_3_0 == 1
301 if (actor->GetProperty()->GetRepresentation() == VTK_SURFACE &&
302 !selector &&
303 (vtkOpenGLRenderWindow::GetContextSupportsOpenGL32() ||
304 GLEW_ARB_instanced_arrays))
305 {
306 this->GlyphRenderInstances(ren, actor, numPts,
307 colors, matrices, normalMatrices, pointMTime);
308 return;
309 }
310 #endif
311
312 bool primed = false;
313
314 for (vtkIdType inPtId = 0; inPtId < numPts; inPtId++)
315 {
316 if (selecting_points)
317 {
318 selector->RenderAttributeId(pickIds[inPtId]);
319 }
320 if (!primed)
321 {
322 this->RenderPieceStart(ren,actor);
323 this->UpdateShader(this->Tris, ren, actor);
324 this->Tris.ibo.Bind();
325 primed = true;
326 }
327
328 // handle the middle
329 vtkShaderProgram *program = this->Tris.Program;
330 vtkgl::VBOLayout &layout = this->Layout;
331
332 // Apply the extra transform
333 program->SetUniformMatrix4x4("GCMCMatrix", &(matrices[inPtId*16]));
334
335 // for lit shaders set normal matrix
336 if (this->LastLightComplexity > 0 && this->Layout.NormalOffset &&
337 !this->UsingInstancing)
338 {
339 program->SetUniformMatrix3x3("glyphNormalMatrix", &(normalMatrices[inPtId*9]));
340 }
341
342 program->SetUniform4uc("glyphColor", &(colors[inPtId*4]));
343
344 if (selector)
345 {
346 program->SetUniform3f("mapperIndex", selector->GetPropColorValue());
347 }
348
349 // First we do the triangles, update the shader, set uniforms, etc.
350 if (actor->GetProperty()->GetRepresentation() == VTK_POINTS)
351 {
352 glDrawRangeElements(GL_POINTS, 0,
353 static_cast<GLuint>(layout.VertexCount - 1),
354 static_cast<GLsizei>(this->Tris.indexCount),
355 GL_UNSIGNED_INT,
356 reinterpret_cast<const GLvoid *>(NULL));
357 }
358 if (actor->GetProperty()->GetRepresentation() == VTK_WIREFRAME)
359 {
360 // TODO wireframe of triangles is not lit properly right now
361 // you either have to generate normals and send them down
362 // or use a geometry shader.
363 glMultiDrawElements(GL_LINE_LOOP,
364 (GLsizei *)(&this->Tris.elementsArray[0]),
365 GL_UNSIGNED_INT,
366 reinterpret_cast<const GLvoid **>(&(this->Tris.offsetArray[0])),
367 (GLsizei)this->Tris.offsetArray.size());
368 }
369 if (actor->GetProperty()->GetRepresentation() == VTK_SURFACE)
370 {
371 glDrawRangeElements(GL_TRIANGLES, 0,
372 static_cast<GLuint>(layout.VertexCount - 1),
373 static_cast<GLsizei>(this->Tris.indexCount),
374 GL_UNSIGNED_INT,
375 reinterpret_cast<const GLvoid *>(NULL));
376 }
377 }
378 if (primed)
379 {
380 this->Tris.ibo.Release();
381 this->RenderPieceFinish(ren,actor);
382 }
383 }
384
385 //-----------------------------------------------------------------------------
SetCameraShaderParameters(vtkgl::CellBO & cellBO,vtkRenderer * ren,vtkActor * actor)386 void vtkOpenGLGlyph3DHelper::SetCameraShaderParameters(vtkgl::CellBO &cellBO,
387 vtkRenderer* ren, vtkActor *actor)
388 {
389 // do the superclass and then reset a couple values
390 this->Superclass::SetCameraShaderParameters(cellBO,ren,actor);
391
392 vtkShaderProgram *program = cellBO.Program;
393
394 // Apply the extra transform
395 if (this->ModelTransformMatrix)
396 {
397 program->SetUniformMatrix4x4("GCMCMatrix", this->ModelTransformMatrix);
398 }
399
400 // for lit shaders set normal matrix
401 if (this->LastLightComplexity > 0 && this->ModelNormalMatrix &&
402 this->Layout.NormalOffset && !this->UsingInstancing)
403 {
404 program->SetUniformMatrix3x3("glyphNormalMatrix", this->ModelNormalMatrix);
405 }
406 }
407
408 //-----------------------------------------------------------------------------
SetPropertyShaderParameters(vtkgl::CellBO & cellBO,vtkRenderer * ren,vtkActor * actor)409 void vtkOpenGLGlyph3DHelper::SetPropertyShaderParameters(vtkgl::CellBO &cellBO,
410 vtkRenderer *ren, vtkActor *actor)
411 {
412 // do the superclass and then reset a couple values
413 this->Superclass::SetPropertyShaderParameters(cellBO,ren,actor);
414
415 vtkShaderProgram *program = cellBO.Program;
416
417 if (this->ModelColor)
418 {
419 program->SetUniform4uc("glyphColor", this->ModelColor);
420 }
421 }
422
423 //-----------------------------------------------------------------------------
SetMapperShaderParameters(vtkgl::CellBO & cellBO,vtkRenderer * ren,vtkActor * actor)424 void vtkOpenGLGlyph3DHelper::SetMapperShaderParameters(vtkgl::CellBO &cellBO,
425 vtkRenderer *ren, vtkActor *actor)
426 {
427 this->Superclass::SetMapperShaderParameters(cellBO,ren,actor);
428
429 vtkHardwareSelector* selector = ren->GetSelector();
430 if (selector && selector->GetCurrentPass() == vtkHardwareSelector::ID_LOW24)
431 {
432 cellBO.Program->SetUniform3f("mapperIndex", selector->GetPropColorValue());
433 }
434 }
435
436 #if GL_ES_VERSION_2_0 != 1 || GL_ES_VERSION_3_0 == 1
GlyphRenderInstances(vtkRenderer * ren,vtkActor * actor,vtkIdType numPts,std::vector<unsigned char> & colors,std::vector<float> & matrices,std::vector<float> & normalMatrices,unsigned long pointMTime)437 void vtkOpenGLGlyph3DHelper::GlyphRenderInstances(
438 vtkRenderer* ren, vtkActor* actor, vtkIdType numPts,
439 std::vector<unsigned char> &colors, std::vector<float> &matrices,
440 std::vector<float> &normalMatrices,
441 unsigned long pointMTime)
442 {
443 this->UsingInstancing = true;
444 this->RenderPieceStart(ren,actor);
445 this->UpdateShader(this->Tris, ren, actor);
446
447 // do the superclass and then reset a couple values
448 if (this->Tris.indexCount && // we have points and one of
449 (this->VBOBuildTime > this->InstanceBuffersLoadTime ||
450 this->Tris.ShaderSourceTime > this->InstanceBuffersLoadTime ||
451 pointMTime > this->InstanceBuffersLoadTime.GetMTime()))
452 {
453 this->Tris.vao.Bind();
454 // add 3 new BOs?
455 this->MatrixBuffer.Bind();
456 this->MatrixBuffer.Upload(matrices, vtkgl::BufferObject::ArrayBuffer);
457 if (!this->Tris.vao.AddAttributeMatrixWithDivisor(this->Tris.Program, this->MatrixBuffer,
458 "GCMCMatrix", 0, 16*sizeof(float), VTK_FLOAT, 4, false, 1))
459 {
460 vtkErrorMacro(<< "Error setting 'GCMCMatrix' in shader VAO.");
461 }
462 this->MatrixBuffer.Release();
463
464 if (this->Layout.NormalOffset && this->LastLightComplexity > 0)
465 {
466 this->NormalMatrixBuffer.Bind();
467 this->NormalMatrixBuffer.Upload(normalMatrices, vtkgl::BufferObject::ArrayBuffer);
468 if (!this->Tris.vao.AddAttributeMatrixWithDivisor(this->Tris.Program, this->NormalMatrixBuffer,
469 "glyphNormalMatrix", 0, 9*sizeof(float), VTK_FLOAT, 3, false, 1))
470 {
471 vtkErrorMacro(<< "Error setting 'glyphNormalMatrix' in shader VAO.");
472 }
473 this->NormalMatrixBuffer.Release();
474 }
475
476 this->ColorBuffer.Bind();
477 this->ColorBuffer.Upload(colors, vtkgl::BufferObject::ArrayBuffer);
478 if (!this->Tris.vao.AddAttributeArrayWithDivisor(this->Tris.Program, this->ColorBuffer,
479 "glyphColor", 0, 4*sizeof(unsigned char), VTK_UNSIGNED_CHAR, 4, true, 1, false))
480 {
481 vtkErrorMacro(<< "Error setting 'diffuse color' in shader VAO.");
482 }
483 this->ColorBuffer.Release();
484
485 this->InstanceBuffersLoadTime.Modified();
486 }
487
488 this->Tris.ibo.Bind();
489 #if GL_ES_VERSION_3_0 == 1
490 glDrawElementsInstanced(GL_TRIANGLES,
491 static_cast<GLsizei>(this->Tris.indexCount),
492 GL_UNSIGNED_INT,
493 reinterpret_cast<const GLvoid *>(NULL),
494 numPts);
495 #else
496 if (vtkOpenGLRenderWindow::GetContextSupportsOpenGL32())
497 {
498 glDrawElementsInstanced(GL_TRIANGLES,
499 static_cast<GLsizei>(this->Tris.indexCount),
500 GL_UNSIGNED_INT,
501 reinterpret_cast<const GLvoid *>(NULL),
502 numPts);
503 }
504 else if (GLEW_ARB_instanced_arrays)
505 {
506 glDrawElementsInstancedARB(GL_TRIANGLES,
507 static_cast<GLsizei>(this->Tris.indexCount),
508 GL_UNSIGNED_INT,
509 reinterpret_cast<const GLvoid *>(NULL),
510 numPts);
511 }
512 #endif
513 vtkOpenGLCheckErrorMacro("failed after Render");
514
515 this->Tris.ibo.Release();
516 this->RenderPieceFinish(ren, actor);
517 }
518 #endif
519
520 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)521 void vtkOpenGLGlyph3DHelper::PrintSelf(ostream& os, vtkIndent indent)
522 {
523 this->Superclass::PrintSelf(os, indent);
524 }
525