vtk中体绘制源码分析

来源:互联网 发布:小腻腻淘宝是正品吗 编辑:程序博客网 时间:2024/06/09 16:26

void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren, vtkVolume* vol)

    for (int i = 0; i < noOfComponents; ++i)
    {
      this->Impl->UpdateOpacityTransferFunction(ren, vol, i);
      this->Impl->UpdateGradientOpacityTransferFunction(ren, vol, i);
      this->Impl->UpdateColorTransferFunction(ren, vol, i);
    }

滴啊用了mapper内部类的UpdateOpacityTransferFunction

int vtkOpenGLGPUVolumeRayCastMapper::vtkInternal::
  UpdateOpacityTransferFunction(vtkRenderer* ren, vtkVolume* vol,
                                unsigned int component)
{
  if (!vol)
  {
    return 1;
  }

  vtkVolumeProperty* volumeProperty = vol->GetProperty();

  // Transfer function table index based on whether independent / dependent
  // components. If dependent, use the first scalar opacity transfer function
  unsigned int lookupTableIndex = volumeProperty->GetIndependentComponents() ?
                                  component : 0;
  vtkPiecewiseFunction* scalarOpacity =
    volumeProperty->GetScalarOpacity(lookupTableIndex);

  if (scalarOpacity->GetSize() < 1)
  {
    scalarOpacity->AddPoint(this->ScalarsRange[component][0], 0.0);
    scalarOpacity->AddPoint(this->ScalarsRange[component][1], 0.5);
  }

  int filterVal =
    volumeProperty->GetInterpolationType() == VTK_LINEAR_INTERPOLATION ?
      vtkTextureObject::Linear : vtkTextureObject::Nearest;

  double scalarRange[2];
  for (int i = 0; i < 2; ++i)
  {
    scalarRange[i] = this->ScalarsRange[component][i];
  }

  this->OpacityTables->GetTable(lookupTableIndex)->Update(
    scalarOpacity,this->Parent->BlendMode,
    this->ActualSampleDistance,
    scalarRange,
    volumeProperty->GetScalarOpacityUnitDistance(component),
#if GL_ES_VERSION_2_0 != 1
    filterVal,
#else
    vtkTextureObject::Nearest,
#endif
    vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()));

  return 0;
}

2.mappper内部类方法中又调用了vtkOpenGLVolumeOpacityTable的update方法


 // Update opacity tranfer function texture.
  //--------------------------------------------------------------------------
  void Update(vtkPiecewiseFunction* scalarOpacity,
              int blendMode,
              double sampleDistance,
              double range[2],
              double unitDistance,
              int filterValue,
              vtkOpenGLRenderWindow* renWin)
  {
    bool needUpdate = false;
    if (!this->TextureObject)
    {
      this->TextureObject = vtkTextureObject::New();
    }

    this->TextureObject->SetContext(renWin);

    if (this->LastRange[0] != range[0] ||
        this->LastRange[1] != range[1])
    {
      this->LastRange[0] = range[0];
      this->LastRange[1] = range[1];
      needUpdate = true;
    }

    if(scalarOpacity->GetMTime() > this->BuildTime ||
       this->TextureObject->GetMTime() > this->BuildTime ||
       (this->LastBlendMode != blendMode) ||
       (blendMode == vtkVolumeMapper::COMPOSITE_BLEND &&
        this->LastSampleDistance != sampleDistance) ||
       needUpdate || !this->TextureObject->GetHandle())
    {
      int const idealW = scalarOpacity->EstimateMinNumberOfSamples(this->LastRange[0],
        this->LastRange[1]);
      int const newWidth = this->GetMaximumSupportedTextureWidth(renWin, idealW);

      if(this->Table == NULL || this->TextureWidth != newWidth)
      {
        this->TextureWidth = newWidth;
        delete [] this->Table;
        this->Table = new float[this->TextureWidth];
      }

      scalarOpacity->GetTable(this->LastRange[0],
                              this->LastRange[1],
                              this->TextureWidth,
                              this->Table);
      this->LastBlendModespacing = blendMode;

      // Correct the opacity array for the  between the planes if we
      // are using a composite blending operation
      // TODO Fix this code for sample distance in three dimensions
        if(blendMode == vtkVolumeMapper::COMPOSITE_BLEND)
        {
          float* ptr = this->Table;
          double factor = sampleDistance/unitDistance;
          int i=0;
          while(i < this->TextureWidth)
          {
            if(*ptr > 0.0001f)
            {
              *ptr = static_cast<float>(1.0-pow(1.0-static_cast<double>(*ptr),
                                        factor));
            }
            ++ptr;
            ++i;
          }
          this->LastSampleDistance = sampleDistance;
        }
        else if (blendMode==vtkVolumeMapper::ADDITIVE_BLEND)
        {
          float* ptr = this->Table;
          double factor = sampleDistance/unitDistance;
          int i = 0;
          while( i < this->TextureWidth)
          {
            if(*ptr > 0.0001f)
            {
              *ptr = static_cast<float>(static_cast<double>(*ptr)*factor);
            }
            ++ptr;
            ++i;
          }
          this->LastSampleDistance = sampleDistance;
        }

      this->TextureObject->SetWrapS(vtkTextureObject::ClampToEdge);
      this->TextureObject->SetMagnificationFilter(filterValue);
      this->TextureObject->SetMinificationFilter(filterValue);
      this->TextureObject->Create2DFromRaw(this->TextureWidth, 1, 1,
                                              VTK_FLOAT,
                                              this->Table);
      this->LastInterpolation = filterValue;
      this->BuildTime.Modified();
    }

    if(this->LastInterpolation != filterValue)
    {
      this->LastInterpolation = filterValue;
      this->TextureObject->SetMagnificationFilter(filterValue);
      this->TextureObject->SetMinificationFilter(filterValue);
    }
  }

3.内部又调用了 vtkPiecewiseFunction 的GetTable方法

// Returns a table of function values evaluated at regular intervals
void vtkPiecewiseFunction::GetTable( double xStart, double xEnd,
                                     int size, double* table,
                                     int stride )
{
  int i;
  int idx = 0;
  int numNodes = static_cast<int>(this->Internal->Nodes.size());

  // Need to keep track of the last value so that
  // we can fill in table locations past this with
  // this value if Clamping is On.
  double lastValue = 0.0;
  if ( numNodes != 0 )
  {
    lastValue = this->Internal->Nodes[numNodes-1]->Y;
  }

  double *tptr     = NULL;
  double x         = 0.0;
  double x1        = 0.0;
  double x2        = 0.0;
  double y1        = 0.0;
  double y2        = 0.0;
  double midpoint  = 0.0;
  double sharpness = 0.0;

  // For each table entry
  for ( i = 0; i < size; i++ )
  {
    // Find our location in the table
    tptr = table + stride*i;

    // Find our X location. If we are taking only 1 sample, make
    // it halfway between start and end (usually start and end will
    // be the same in this case)
    if ( size > 1 )
    {
      x = xStart + (double(i)/double(size-1))*(xEnd-xStart);
    }
    else
    {
      x = 0.5*(xStart+xEnd);
    }

    // Do we need to move to the next node?
    while ( idx < numNodes &&
            x > this->Internal->Nodes[idx]->X )
    {
      idx++;
      // If we are at a valid point index, fill in
      // the value at this node, and the one before (the
      // two that surround our current sample location)
      // idx cannot be 0 since we just incremented it.
      if ( idx < numNodes )
      {
        x1 = this->Internal->Nodes[idx-1]->X;
        x2 = this->Internal->Nodes[idx  ]->X;

        y1 = this->Internal->Nodes[idx-1]->Y;
        y2 = this->Internal->Nodes[idx  ]->Y;

        // We only need the previous midpoint and sharpness
        // since these control this region
        midpoint  = this->Internal->Nodes[idx-1]->Midpoint;
        sharpness = this->Internal->Nodes[idx-1]->Sharpness;

        // Move midpoint away from extreme ends of range to avoid
        // degenerate math
        if ( midpoint < 0.00001 )
        {
          midpoint = 0.00001;
        }

        if ( midpoint > 0.99999 )
        {
          midpoint = 0.99999;
        }
      }
    }

    // Are we at the end? If so, just use the last value
    if ( idx >= numNodes )
    {
      *tptr = (this->Clamping)?(lastValue):(0.0);
    }
    // Are we before the first node? If so, duplicate this nodes values
    else if ( idx == 0 )
    {
      *tptr = (this->Clamping)?(this->Internal->Nodes[0]->Y):(0.0);
    }
    // Otherwise, we are between two nodes - interpolate
    else
    {
      // Our first attempt at a normalized location [0,1] -
      // we will be modifying this based on midpoint and
      // sharpness to get the curve shape we want and to have
      // it pass through (y1+y2)/2 at the midpoint.
      double s = (x - x1) / (x2 - x1);

      // Readjust based on the midpoint - linear adjustment
      if ( s < midpoint )
      {
        s = 0.5 * s / midpoint;
      }
      else
      {
        s = 0.5 + 0.5*(s-midpoint)/(1.0-midpoint);
      }

      // override for sharpness > 0.99
      // In this case we just want piecewise constant
      if ( sharpness > 0.99 )
      {
        // Use the first value since we are below the midpoint
        if ( s < 0.5 )
        {
          *tptr = y1;
          continue;
        }
        // Use the second value at or above the midpoint
        else
        {
          *tptr = y2;
          continue;
        }
      }

      // Override for sharpness < 0.01
      // In this case we want piecewise linear
      if ( sharpness < 0.01 )
      {
        // Simple linear interpolation
        *tptr = (1-s)*y1 + s*y2;
        continue;
      }

      // We have a sharpness between [0.01, 0.99] - we will
      // used a modified hermite curve interpolation where we
      // derive the slope based on the sharpness, and we compress
      // the curve non-linearly based on the sharpness

      // First, we will adjust our position based on sharpness in
      // order to make the curve sharper (closer to piecewise constant)
      if ( s < .5 )
      {
        s = 0.5 * pow(s*2,1.0 + 10*sharpness);
      }
      else if ( s > .5 )
      {
        s = 1.0 - 0.5 * pow((1.0-s)*2,1+10*sharpness);
      }

      // Compute some coefficients we will need for the hermite curve
      double ss = s*s;
      double sss = ss*s;

      double h1 =  2*sss - 3*ss + 1;
      double h2 = -2*sss + 3*ss;
      double h3 =    sss - 2*ss + s;
      double h4 =    sss -   ss;

      double slope;
      double t;

      // Use one slope for both end points
      slope = y2 - y1;
      t = (1.0 - sharpness)*slope;

      // Compute the value
      *tptr = h1*y1 + h2*y2 + h3*t + h4*t;

      // Final error check to make sure we don't go outside
      // the Y range
      double min = (y1<y2)?(y1):(y2);
      double max = (y1>y2)?(y1):(y2);

      *tptr = (*tptr < min)?(min):(*tptr);
      *tptr = (*tptr > max)?(max):(*tptr);

    }
  }
}

在里面给table填充了值

4.然后在有调用了生成文理的方法

bool vtkTextureObject::Create2DFromRaw(unsigned int width, unsigned int height,
                                       int numComps, int dataType, void *data)
{
  assert(this->Context);

  // Now determine the texture parameters using the arguments.
  this->GetDataType(dataType);
  this->GetInternalFormat(dataType, numComps, false);
  this->GetFormat(dataType, numComps, false);

  if (!this->InternalFormat || !this->Format || !this->Type)
  {
    vtkErrorMacro("Failed to determine texture parameters. IF="
      << this->InternalFormat << " F=" << this->Format << " T=" << this->Type);
    return false;
  }

  GLenum target = GL_TEXTURE_2D;
  this->Target = target;
  this->Components = numComps;
  this->Width = width;
  this->Height = height;
  this->Depth = 1;
  this->NumberOfDimensions = 2;
  this->Context->ActivateTexture(this);
  this->CreateTexture();
  this->Bind();

  // Source texture data from the PBO.
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  glTexImage2D(
        this->Target,
        0,
        this->InternalFormat,
        static_cast<GLsizei>(this->Width),
        static_cast<GLsizei>(this->Height),
        0,
        this->Format,
        this->Type,
        static_cast<const GLvoid *>(data));

  vtkOpenGLCheckErrorMacro("failed at glTexImage2D");

  this->Deactivate();
  return true;
}

暂时分析到此

0 0