vtkOpenGLSphereMapper.cxx 12.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*=========================================================================

  Program:   Visualization Toolkit

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkOpenGLSphereMapper.h"

Ken Martin's avatar
Ken Martin committed
16
#include "vtkOpenGLHelper.h"
17 18

#include "vtkMath.h"
Ken Martin's avatar
Ken Martin committed
19 20 21
#include "vtkMatrix4x4.h"
#include "vtkOpenGLActor.h"
#include "vtkOpenGLCamera.h"
Ken Martin's avatar
Ken Martin committed
22
#include "vtkOpenGLIndexBufferObject.h"
Ken Martin's avatar
Ken Martin committed
23
#include "vtkOpenGLVertexArrayObject.h"
Ken Martin's avatar
Ken Martin committed
24
#include "vtkOpenGLVertexBufferObject.h"
25 26
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
27
#include "vtkPolyData.h"
28 29 30 31 32 33
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkShaderProgram.h"

#include "vtkSphereMapperVS.h"

Ken Martin's avatar
Ken Martin committed
34 35
#include "vtk_glew.h"

Ken Martin's avatar
Ken Martin committed
36

37 38 39 40 41 42 43 44 45

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkOpenGLSphereMapper)

//-----------------------------------------------------------------------------
vtkOpenGLSphereMapper::vtkOpenGLSphereMapper()
{
  this->ScaleArray = 0;
  this->Invert = false;
46
  this->Radius = 0.3;
47 48 49
}

//-----------------------------------------------------------------------------
50 51 52
void vtkOpenGLSphereMapper::GetShaderTemplate(
  std::map<vtkShader::Type, vtkShader *> shaders,
  vtkRenderer *ren, vtkActor *actor)
53
{
54 55
  this->Superclass::GetShaderTemplate(shaders,ren,actor);
  shaders[vtkShader::Vertex]->SetSource(vtkSphereMapperVS);
56 57
}

58 59 60
void vtkOpenGLSphereMapper::ReplaceShaderValues(
  std::map<vtkShader::Type, vtkShader *> shaders,
  vtkRenderer *ren, vtkActor *actor)
61
{
62 63 64
  std::string VSSource = shaders[vtkShader::Vertex]->GetSource();
  std::string FSSource = shaders[vtkShader::Fragment]->GetSource();

Ken Martin's avatar
Ken Martin committed
65
  vtkShaderProgram::Substitute(VSSource,
Ken Martin's avatar
Ken Martin committed
66 67 68 69
    "//VTK::Camera::Dec",
    "uniform mat4 VCDCMatrix;\n"
    "uniform mat4 MCVCMatrix;");

Ken Martin's avatar
Ken Martin committed
70
  vtkShaderProgram::Substitute(FSSource,
71
    "//VTK::PositionVC::Dec",
72
    "varying vec4 vertexVCVSOutput;");
73

Ken Martin's avatar
Ken Martin committed
74 75 76
  // we create vertexVC below, so turn off the default
  // implementation
  vtkShaderProgram::Substitute(FSSource,
77 78
    "//VTK::PositionVC::Impl",
    "vec4 vertexVC = vertexVCVSOutput;\n");
Ken Martin's avatar
Ken Martin committed
79

80 81 82 83 84
  // for lights kit and positional the VCDC matrix is already defined
  // so don't redefine it
  std::string replacement =
    "uniform float invertedDepth;\n"
    "uniform int cameraParallel;\n"
85 86
    "varying float radiusVCVSOutput;\n"
    "varying vec3 centerVCVSOutput;\n"
87
    "uniform mat4 VCDCMatrix;\n";
Ken Martin's avatar
Ken Martin committed
88
  vtkShaderProgram::Substitute(FSSource,"//VTK::Normal::Dec",replacement);
89

90
  vtkShaderProgram::Substitute(FSSource,"//VTK::Depth::Impl",
91
    // compute the eye position and unit direction
92 93 94
    "  vec3 EyePos;\n"
    "  vec3 EyeDir;\n"
    "  if (cameraParallel != 0) {\n"
95
    "    EyePos = vec3(vertexVC.x, vertexVC.y, vertexVC.z + 3.0*radiusVCVSOutput);\n"
96 97 98 99 100 101
    "    EyeDir = vec3(0.0,0.0,-1.0); }\n"
    "  else {\n"
    "    EyeDir = vertexVC.xyz;\n"
    "    EyePos = vec3(0.0,0.0,0.0);\n"
    "    float lengthED = length(EyeDir);\n"
    "    EyeDir = normalize(EyeDir);\n"
102 103
    // we adjust the EyePos to be closer if it is too far away
    // to prevent floating point precision noise
104 105
    "    if (lengthED > radiusVCVSOutput*3.0) {\n"
    "      EyePos = vertexVC.xyz - EyeDir*3.0*radiusVCVSOutput; }\n"
106
    "    }\n"
107 108

    // translate to Sphere center
109
    "  EyePos = EyePos - centerVCVSOutput;\n"
110
    // scale to radius 1.0
111
    "  EyePos = EyePos/radiusVCVSOutput;\n"
112 113 114 115
    // find the intersection
    "  float b = 2.0*dot(EyePos,EyeDir);\n"
    "  float c = dot(EyePos,EyePos) - 1.0;\n"
    "  float d = b*b - 4.0*c;\n"
116
    "  vec3 normalVCVSOutput = vec3(0.0,0.0,1.0);\n"
117 118 119 120 121 122
    "  if (d < 0.0) { discard; }\n"
    "  else {\n"
    "    float t = (-b - invertedDepth*sqrt(d))*0.5;\n"

    // compute the normal, for unit sphere this is just
    // the intersection point
123
    "    normalVCVSOutput = invertedDepth*normalize(EyePos + t*EyeDir);\n"
124
    // compute the intersection point in VC
125
    "    vertexVC.xyz = normalVCVSOutput*radiusVCVSOutput + centerVCVSOutput;\n"
126 127
    "    }\n"
    // compute the pixel's depth
128
   // " normalVCVSOutput = vec3(0,0,1);\n"
129 130 131 132
    "  vec4 pos = VCDCMatrix * vertexVC;\n"
    "  gl_FragDepth = (pos.z / pos.w + 1.0) / 2.0;\n"
    );

133 134
  // Strip out the normal line -- the normal is computed as part of the depth
  vtkShaderProgram::Substitute(FSSource,"//VTK::Normal::Impl", "");
135

136 137 138 139
  shaders[vtkShader::Vertex]->SetSource(VSSource);
  shaders[vtkShader::Fragment]->SetSource(FSSource);

  this->Superclass::ReplaceShaderValues(shaders,ren,actor);
140 141 142 143 144 145 146 147 148 149
}

//-----------------------------------------------------------------------------
vtkOpenGLSphereMapper::~vtkOpenGLSphereMapper()
{
  this->SetScaleArray(0);
}


//-----------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
150
void vtkOpenGLSphereMapper::SetCameraShaderParameters(
Ken Martin's avatar
Ken Martin committed
151
  vtkOpenGLHelper &cellBO,
Ken Martin's avatar
Ken Martin committed
152
  vtkRenderer* ren, vtkActor *actor)
153
{
Ken Martin's avatar
Ken Martin committed
154 155 156 157 158 159 160 161 162
  vtkShaderProgram *program = cellBO.Program;

  vtkOpenGLCamera *cam = (vtkOpenGLCamera *)(ren->GetActiveCamera());

  vtkMatrix4x4 *wcdc;
  vtkMatrix4x4 *wcvc;
  vtkMatrix3x3 *norms;
  vtkMatrix4x4 *vcdc;
  cam->GetKeyMatrices(ren,wcvc,norms,vcdc,wcdc);
163
  if (program->IsUniformUsed("VCDCMatrix"))
164
  {
165
    program->SetUniformMatrix("VCDCMatrix", vcdc);
166
  }
167 168

  if (program->IsUniformUsed("MCVCMatrix"))
169
  {
170
    if (!actor->GetIsIdentity())
171
    {
172 173 174 175 176
      vtkMatrix4x4 *mcwc;
      vtkMatrix3x3 *anorms;
      ((vtkOpenGLActor *)actor)->GetKeyMatrices(mcwc,anorms);
      vtkMatrix4x4::Multiply4x4(mcwc, wcvc, this->TempMatrix4);
      program->SetUniformMatrix("MCVCMatrix", this->TempMatrix4);
177
    }
178
    else
179
    {
180
      program->SetUniformMatrix("MCVCMatrix", wcvc);
Ken Martin's avatar
Ken Martin committed
181
    }
182
  }
183

184
  if (program->IsUniformUsed("cameraParallel"))
185
  {
186
    cellBO.Program->SetUniformi("cameraParallel", cam->GetParallelProjection());
187
  }
188 189 190
}

//-----------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
191
void vtkOpenGLSphereMapper::SetMapperShaderParameters(
Ken Martin's avatar
Ken Martin committed
192
  vtkOpenGLHelper &cellBO,
Ken Martin's avatar
Ken Martin committed
193
  vtkRenderer *ren, vtkActor *actor)
194
{
Ken Martin's avatar
Ken Martin committed
195
  if (cellBO.IBO->IndexCount && (this->VBOBuildTime > cellBO.AttributeUpdateTime ||
196 197
      cellBO.ShaderSourceTime > cellBO.AttributeUpdateTime) &&
      cellBO.Program->IsAttributeUsed("offsetMC"))
198
  {
Ken Martin's avatar
Ken Martin committed
199 200
    cellBO.VAO->Bind();
    if (!cellBO.VAO->AddAttributeArray(cellBO.Program, this->VBO,
Ken Martin's avatar
Ken Martin committed
201 202
                                    "offsetMC", this->VBO->ColorOffset+sizeof(float),
                                    this->VBO->Stride, VTK_FLOAT, 2, false))
203
    {
204 205
      vtkErrorMacro(<< "Error setting 'offsetMC' in shader VAO.");
    }
206
  }
207

208
  if (cellBO.Program->IsUniformUsed("invertedDepth"))
209
  {
210
    cellBO.Program->SetUniformf("invertedDepth", this->Invert ? -1.0 : 1.0);
211
  }
212

213 214 215 216 217 218 219 220
  this->Superclass::SetMapperShaderParameters(cellBO,ren,actor);
}


//-----------------------------------------------------------------------------
void vtkOpenGLSphereMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
221
  os << indent << "Radius: " << this->Radius << "\n";
222 223
}

224 225
namespace
{
226
// internal function called by CreateVBO
Ken Martin's avatar
Ken Martin committed
227
void vtkOpenGLSphereMapperCreateVBO(float * points, vtkIdType numPts,
228
              unsigned char *colors, int colorComponents,
229 230
              vtkIdType nc,
              float *sizes, vtkIdType ns,
Ken Martin's avatar
Ken Martin committed
231
              vtkOpenGLVertexBufferObject *VBO)
232 233 234
{
  // Figure out how big each block will be, currently 6 or 7 floats.
  int blockSize = 3;
Ken Martin's avatar
Ken Martin committed
235 236 237 238 239 240
  VBO->VertexOffset = 0;
  VBO->NormalOffset = 0;
  VBO->TCoordOffset = 0;
  VBO->TCoordComponents = 0;
  VBO->ColorComponents = colorComponents;
  VBO->ColorOffset = sizeof(float) * blockSize;
241 242
  ++blockSize;

243 244
  // two more floats
  blockSize += 2;
Ken Martin's avatar
Ken Martin committed
245
  VBO->Stride = sizeof(float) * blockSize;
246 247

  // Create a buffer, and copy the data over.
Ken Martin's avatar
Ken Martin committed
248 249
  VBO->PackedVBO.resize(blockSize * numPts*3);
  std::vector<float>::iterator it = VBO->PackedVBO.begin();
250 251 252 253 254 255 256

  float *pointPtr;
  unsigned char *colorPtr;

  float cos30 = cos(vtkMath::RadiansFromDegrees(30.0));

  for (vtkIdType i = 0; i < numPts; ++i)
257
  {
258
    pointPtr = points + i*3;
259 260
    colorPtr = (nc == numPts ? colors + i*colorComponents : colors);
    float radius = (ns == numPts ? sizes[i] : sizes[0]);
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282

    // Vertices
    *(it++) = pointPtr[0];
    *(it++) = pointPtr[1];
    *(it++) = pointPtr[2];
    *(it++) = *reinterpret_cast<float *>(colorPtr);
    *(it++) = -2.0f*radius*cos30;
    *(it++) = -radius;

    *(it++) = pointPtr[0];
    *(it++) = pointPtr[1];
    *(it++) = pointPtr[2];
    *(it++) = *reinterpret_cast<float *>(colorPtr);
    *(it++) = 2.0f*radius*cos30;
    *(it++) = -radius;

    *(it++) = pointPtr[0];
    *(it++) = pointPtr[1];
    *(it++) = pointPtr[2];
    *(it++) = *reinterpret_cast<float *>(colorPtr);
    *(it++) = 0.0f;
    *(it++) = 2.0f*radius;
283
  }
Ken Martin's avatar
Ken Martin committed
284 285 286
  VBO->Upload(VBO->PackedVBO, vtkOpenGLBufferObject::ArrayBuffer);
  VBO->VertexCount = numPts*3;
  return;
287
}
288
}
289 290

//-------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
291 292 293
bool vtkOpenGLSphereMapper::GetNeedToRebuildBufferObjects(
  vtkRenderer *vtkNotUsed(ren),
  vtkActor *act)
294 295 296 297 298
{
  // picking state does not require a rebuild, unlike our parent
  if (this->VBOBuildTime < this->GetMTime() ||
      this->VBOBuildTime < act->GetMTime() ||
      this->VBOBuildTime < this->CurrentInput->GetMTime())
299
  {
300
    return true;
301
  }
302 303 304 305
  return false;
}

//-------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
306
void vtkOpenGLSphereMapper::BuildBufferObjects(
Ken Martin's avatar
Ken Martin committed
307
  vtkRenderer *vtkNotUsed(ren),
308
  vtkActor *act)
309 310 311 312
{
  vtkPolyData *poly = this->CurrentInput;

  if (poly == NULL)// || !poly->GetPointData()->GetNormals())
313
  {
314
    return;
315
  }
316 317 318 319 320 321 322

  // For vertex coloring, this sets this->Colors as side effect.
  // For texture map coloring, this sets ColorCoordinates
  // and ColorTextureMap as a side effect.
  // I moved this out of the conditional because it is fast.
  // Color arrays are cached. If nothing has changed,
  // then the scalars do not have to be regenerted.
323
  this->MapScalars(1.0);
324

325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
  vtkIdType numPts = poly->GetPoints()->GetNumberOfPoints();
  unsigned char *c;
  int cc;
  vtkIdType nc;
  if (this->Colors)
  {
    c = (unsigned char *)this->Colors->GetVoidPointer(0);
    nc = numPts;
    cc = this->Colors->GetNumberOfComponents();
  }
  else
  {
    double *ac = act->GetProperty()->GetColor();
    c = new unsigned char[3];
    c[0] = (unsigned char) (ac[0] *255.0);
    c[1] = (unsigned char) (ac[1] *255.0);
    c[2] = (unsigned char) (ac[2] *255.0);
    nc = 1;
    cc = 3;
  }

  float *scales;
  vtkIdType ns = poly->GetPoints()->GetNumberOfPoints();
  if (this->ScaleArray != NULL &&
      poly->GetPointData()->HasArray(this->ScaleArray))
  {
    scales = static_cast<float*>(poly->GetPointData()->GetArray(this->ScaleArray)->GetVoidPointer(0));
    ns = numPts;
  }
  else
  {
    scales = &this->Radius;
    ns = 1;
  }


361 362
  // Iterate through all of the different types in the polydata, building OpenGLs
  // and IBOs as appropriate for each type.
Ken Martin's avatar
Ken Martin committed
363 364
  vtkOpenGLSphereMapperCreateVBO(
    static_cast<float *>(poly->GetPoints()->GetVoidPointer(0)),
365 366 367
    numPts,
    c, cc, nc,
    scales, ns,
Ken Martin's avatar
Ken Martin committed
368
    this->VBO);
369

370 371 372 373 374
  if (!this->Colors)
  {
    delete [] c;
  }

375
  // create the IBO
376 377 378 379
  this->Primitives[PrimitivePoints].IBO->IndexCount = 0;
  this->Primitives[PrimitiveLines].IBO->IndexCount = 0;
  this->Primitives[PrimitiveTriStrips].IBO->IndexCount = 0;
  this->Primitives[PrimitiveTris].IBO->IndexCount = this->VBO->VertexCount;
380
  this->VBOBuildTime.Modified();
381 382 383 384 385 386 387 388 389 390 391
}


//----------------------------------------------------------------------------
void vtkOpenGLSphereMapper::Render(vtkRenderer *ren, vtkActor *act)
{
  vtkProperty *prop = act->GetProperty();
  bool is_opaque = (prop->GetOpacity() >= 1.0);

  // if we are transparent (and not backface culling) we have to draw twice
  if (!is_opaque && !prop->GetBackfaceCulling())
392
  {
393 394 395
    this->Invert = true;
    this->Superclass::Render(ren,act);
    this->Invert = false;
396
  }
397 398 399 400 401 402 403
  this->Superclass::Render(ren,act);
}

//-----------------------------------------------------------------------------
void vtkOpenGLSphereMapper::RenderPieceDraw(vtkRenderer* ren, vtkActor *actor)
{
  // draw polygons
404
  if (this->Primitives[PrimitiveTris].IBO->IndexCount)
405
  {
406
    // First we do the triangles, update the shader, set uniforms, etc.
407
    this->UpdateShaders(this->Primitives[PrimitiveTris], ren, actor);
408
    glDrawArrays(GL_TRIANGLES, 0,
Ken Martin's avatar
Ken Martin committed
409
                static_cast<GLuint>(this->VBO->VertexCount));
410
  }
411
}