You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
306 lines
11 KiB
306 lines
11 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkUnstructuredGridHomogeneousRayIntegrator.cxx,v $
|
|
|
|
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.
|
|
|
|
=========================================================================*/
|
|
|
|
/*
|
|
* Copyright 2004 Sandia Corporation.
|
|
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
|
|
* license for use of this work by or on behalf of the
|
|
* U.S. Government. Redistribution and use in source and binary forms, with
|
|
* or without modification, are permitted provided that this Notice and any
|
|
* statement of authorship are reproduced on all copies.
|
|
*/
|
|
|
|
#include "vtkUnstructuredGridHomogeneousRayIntegrator.h"
|
|
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkVolumeProperty.h"
|
|
#include "vtkVolume.h"
|
|
#include "vtkAbstractVolumeMapper.h"
|
|
#include "vtkUnstructuredGrid.h"
|
|
#include "vtkDoubleArray.h"
|
|
#include "vtkColorTransferFunction.h"
|
|
#include "vtkPiecewiseFunction.h"
|
|
|
|
#include <math.h>
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
vtkCxxRevisionMacro(vtkUnstructuredGridHomogeneousRayIntegrator, "$Revision: 1.2 $");
|
|
vtkStandardNewMacro(vtkUnstructuredGridHomogeneousRayIntegrator);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
vtkUnstructuredGridHomogeneousRayIntegrator::vtkUnstructuredGridHomogeneousRayIntegrator()
|
|
{
|
|
this->Property = NULL;
|
|
|
|
this->NumComponents = 0;
|
|
this->ColorTable = NULL;
|
|
this->AttenuationTable = NULL;
|
|
this->TableShift = NULL;
|
|
this->TableScale = NULL;
|
|
|
|
this->UseAverageColor = 0;
|
|
this->TransferFunctionTableSize = 1024;
|
|
}
|
|
|
|
vtkUnstructuredGridHomogeneousRayIntegrator::~vtkUnstructuredGridHomogeneousRayIntegrator()
|
|
{
|
|
for (int i = 0; i < this->NumComponents; i++)
|
|
{
|
|
delete[] this->ColorTable[i];
|
|
delete[] this->AttenuationTable[i];
|
|
}
|
|
delete[] this->ColorTable;
|
|
delete[] this->AttenuationTable;
|
|
delete[] this->TableShift;
|
|
delete[] this->TableScale;
|
|
}
|
|
|
|
void vtkUnstructuredGridHomogeneousRayIntegrator::PrintSelf(ostream &os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
|
|
os << indent << "UseAverageColor: " << this->UseAverageColor << endl;
|
|
os << indent << "TransferFunctionTableSize: "
|
|
<< this->TransferFunctionTableSize << endl;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void vtkUnstructuredGridHomogeneousRayIntegrator::GetTransferFunctionTables(vtkDataArray *scalars)
|
|
{
|
|
for (int i = 0; i < this->NumComponents; i++)
|
|
{
|
|
delete[] this->ColorTable[i];
|
|
delete[] this->AttenuationTable[i];
|
|
}
|
|
delete[] this->ColorTable;
|
|
delete[] this->AttenuationTable;
|
|
delete[] this->TableShift;
|
|
delete[] this->TableScale;
|
|
|
|
this->NumComponents = scalars->GetNumberOfComponents();
|
|
|
|
this->ColorTable = new float*[this->NumComponents];
|
|
this->AttenuationTable = new float*[this->NumComponents];
|
|
this->TableShift = new double[this->NumComponents];
|
|
this->TableScale = new double[this->NumComponents];
|
|
|
|
for (int c = 0; c < this->NumComponents; c++)
|
|
{
|
|
double range[2];
|
|
scalars->GetRange(range, c);
|
|
if (range[0] >= range[1])
|
|
{
|
|
range[1] = range[0] + 1;
|
|
}
|
|
this->TableScale[c] = this->TransferFunctionTableSize/(range[1]-range[0]);
|
|
this->TableShift[c]
|
|
= -range[0]*this->TransferFunctionTableSize/(range[1]-range[0]);
|
|
|
|
this->ColorTable[c] = new float[3*this->TransferFunctionTableSize];
|
|
if (this->Property->GetColorChannels(c) == 1)
|
|
{
|
|
// Get gray values. Store temporarily in allocated RGB array.
|
|
this->Property->GetGrayTransferFunction(c)
|
|
->GetTable(range[0], range[1], this->TransferFunctionTableSize,
|
|
this->ColorTable[c]);
|
|
// Convert gray into RGB. Copy backward so that we can use the same
|
|
// array.
|
|
for (int i = this->TransferFunctionTableSize-1; i >= 0; i--)
|
|
{
|
|
this->ColorTable[c][3*i + 0]
|
|
= this->ColorTable[c][3*i + 1]
|
|
= this->ColorTable[c][3*i + 2] = this->ColorTable[c][i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->Property->GetRGBTransferFunction(c)
|
|
->GetTable(range[0], range[1], this->TransferFunctionTableSize,
|
|
this->ColorTable[c]);
|
|
}
|
|
|
|
this->AttenuationTable[c] = new float[this->TransferFunctionTableSize];
|
|
this->Property->GetScalarOpacity(c)
|
|
->GetTable(range[0], range[1], this->TransferFunctionTableSize,
|
|
this->AttenuationTable[c]);
|
|
|
|
// Adjust attenuation by scalar unit length. This will make the unit
|
|
// lenth the same as the model.
|
|
float unitlength = this->Property->GetScalarOpacityUnitDistance(c);
|
|
for (int i = 0; i < this->TransferFunctionTableSize; i++)
|
|
{
|
|
this->AttenuationTable[c][i] /= unitlength;
|
|
}
|
|
}
|
|
|
|
this->TablesBuilt.Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void vtkUnstructuredGridHomogeneousRayIntegrator::Initialize(vtkVolume *volume,
|
|
vtkDataArray *scalars)
|
|
{
|
|
vtkVolumeProperty *property = volume->GetProperty();
|
|
|
|
if ( (property == this->Property)
|
|
&& (this->TablesBuilt > property->GetMTime())
|
|
&& (this->TablesBuilt > this->MTime) )
|
|
{
|
|
// Nothing changed from the last time Initialize was run.
|
|
return;
|
|
}
|
|
|
|
this->Property = property;
|
|
this->Volume = volume;
|
|
|
|
if (property->GetIndependentComponents())
|
|
{
|
|
this->GetTransferFunctionTables(scalars);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void vtkUnstructuredGridHomogeneousRayIntegrator::Integrate(
|
|
vtkDoubleArray *intersectionLengths,
|
|
vtkDataArray *nearIntersections,
|
|
vtkDataArray *vtkNotUsed(farIntersections),
|
|
float color[4])
|
|
{
|
|
vtkIdType numIntersections = intersectionLengths->GetNumberOfTuples();
|
|
|
|
if (this->Property->GetIndependentComponents())
|
|
{
|
|
if (this->NumComponents == 1)
|
|
{
|
|
// Optimize for what I think is one of the most common uses.
|
|
for (vtkIdType i = 0; i < numIntersections; i++)
|
|
{
|
|
int table_index
|
|
= (int)( this->TableScale[0]*nearIntersections->GetComponent(i, 0)
|
|
+ this->TableShift[0] );
|
|
if (table_index < 0)
|
|
{
|
|
table_index = 0;
|
|
}
|
|
if (table_index >= this->TransferFunctionTableSize)
|
|
{
|
|
table_index = this->TransferFunctionTableSize-1;
|
|
}
|
|
float *c = this->ColorTable[0] + 3*table_index;
|
|
float tau = this->AttenuationTable[0][table_index];
|
|
float alpha = 1-(float)exp(-intersectionLengths->GetComponent(i,0)*tau);
|
|
color[0] += c[0]*alpha*(1-color[3]);
|
|
color[1] += c[1]*alpha*(1-color[3]);
|
|
color[2] += c[2]*alpha*(1-color[3]);
|
|
color[3] += alpha*(1-color[3]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Generic case.
|
|
for (vtkIdType i = 0; i < numIntersections; i++)
|
|
{
|
|
float newcolor[4];
|
|
int table_index
|
|
= (int)( this->TableScale[0]*nearIntersections->GetComponent(i, 0)
|
|
+ this->TableShift[0] );
|
|
if (table_index < 0)
|
|
{
|
|
table_index = 0;
|
|
}
|
|
if (table_index >= this->TransferFunctionTableSize)
|
|
{
|
|
table_index = this->TransferFunctionTableSize-1;
|
|
}
|
|
float *c = this->ColorTable[0] + 3*table_index;
|
|
float tau = this->AttenuationTable[0][table_index];
|
|
newcolor[0] = c[0]; newcolor[1] = c[1];
|
|
newcolor[2] = c[2]; newcolor[3] = tau;
|
|
for (int component = 1; component < this->NumComponents; component++)
|
|
{
|
|
table_index
|
|
= (int)( this->TableScale[component]
|
|
*nearIntersections->GetComponent(i, component)
|
|
+ this->TableShift[component] );
|
|
if (table_index < 0)
|
|
{
|
|
table_index = 0;
|
|
}
|
|
if (table_index >= this->TransferFunctionTableSize)
|
|
{
|
|
table_index = this->TransferFunctionTableSize-1;
|
|
}
|
|
c = this->ColorTable[component] + 3*table_index;
|
|
tau = this->AttenuationTable[component][table_index];
|
|
// Here we handle the mixing of material properties. This never
|
|
// seems to be defined very clearly. I handle this by assuming
|
|
// that each scalar represents a cloud of particles of a certian
|
|
// color and a certain density. We mix the scalars in the same
|
|
// way as mixing these particles together. By necessity, the
|
|
// density becomes greater. The "opacity" parameter is really
|
|
// interpreted as the attenuation coefficient (which is
|
|
// proportional to density) and can therefore easily be greater
|
|
// than one. The opacity of the resulting color will, however,
|
|
// always be scaled between 0 and 1.
|
|
if (tau + newcolor[3] > 1.0e-8f)
|
|
{
|
|
newcolor[0] *= newcolor[3]/(tau + newcolor[3]);
|
|
newcolor[1] *= newcolor[3]/(tau + newcolor[3]);
|
|
newcolor[2] *= newcolor[3]/(tau + newcolor[3]);
|
|
newcolor[0] += c[0]*tau/(tau + newcolor[3]);
|
|
newcolor[1] += c[1]*tau/(tau + newcolor[3]);
|
|
newcolor[2] += c[2]*tau/(tau + newcolor[3]);
|
|
newcolor[3] += tau;
|
|
}
|
|
}
|
|
float alpha = 1 - (float)exp(-intersectionLengths->GetComponent(i,0)
|
|
*newcolor[3]);
|
|
color[0] += newcolor[0]*alpha*(1-color[3]);
|
|
color[1] += newcolor[1]*alpha*(1-color[3]);
|
|
color[2] += newcolor[2]*alpha*(1-color[3]);
|
|
color[3] += alpha*(1-color[3]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int numComponents = nearIntersections->GetNumberOfComponents();
|
|
for (vtkIdType i = 0; i < numIntersections; i++)
|
|
{
|
|
double c[4];
|
|
if (numComponents == 4)
|
|
{
|
|
nearIntersections->GetTuple(i, c);
|
|
}
|
|
else
|
|
{
|
|
double *lt = nearIntersections->GetTuple(i);
|
|
c[0] = c[1] = c[2] = lt[0];
|
|
c[3] = lt[1];
|
|
}
|
|
float alpha = 1-(float)exp(-intersectionLengths->GetComponent(i,0)*c[3]);
|
|
color[0] += (float)c[0]*alpha*(1-color[3]);
|
|
color[1] += (float)c[1]*alpha*(1-color[3]);
|
|
color[2] += (float)c[2]*alpha*(1-color[3]);
|
|
color[3] += alpha*(1-color[3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|