Cloned library of VTK-5.0.0 with extra build files for internal package management.
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.
 
 
 
 
 
 

581 lines
17 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkEncodedGradientShader.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.
=========================================================================*/
#include "vtkEncodedGradientShader.h"
#include "vtkCamera.h"
#include "vtkDirectionEncoder.h"
#include "vtkEncodedGradientEstimator.h"
#include "vtkLight.h"
#include "vtkLightCollection.h"
#include "vtkMatrix4x4.h"
#include "vtkObjectFactory.h"
#include "vtkRenderer.h"
#include "vtkTransform.h"
#include "vtkVolume.h"
#include "vtkVolumeProperty.h"
#include <math.h>
vtkCxxRevisionMacro(vtkEncodedGradientShader, "$Revision: 1.2 $");
vtkStandardNewMacro(vtkEncodedGradientShader);
vtkEncodedGradientShader::vtkEncodedGradientShader()
{
int i, j;
for ( j = 0; j < VTK_MAX_SHADING_TABLES; j++ )
{
this->ShadingTableVolume[j] = NULL;
this->ShadingTableSize[j] = 0;
for ( i = 0; i < 6; i++ )
{
this->ShadingTable[j][i] = NULL;
}
}
this->ZeroNormalDiffuseIntensity = 0.0;
this->ZeroNormalSpecularIntensity = 0.0;
this->ActiveComponent = 0;
}
vtkEncodedGradientShader::~vtkEncodedGradientShader()
{
int i, j;
for ( j = 0; j < VTK_MAX_SHADING_TABLES; j++ )
{
for ( i=0; i<6; i++ )
{
if ( this->ShadingTable[j][i] )
{
delete [] this->ShadingTable[j][i];
}
}
}
}
float *vtkEncodedGradientShader::GetRedDiffuseShadingTable( vtkVolume *vol )
{
int index;
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == vol )
{
break;
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
vtkErrorMacro( << "No shading table found for that volume!" );
return NULL;
}
return this->ShadingTable[index][0];
}
float *vtkEncodedGradientShader::GetGreenDiffuseShadingTable( vtkVolume *vol )
{
int index;
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == vol )
{
break;
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
vtkErrorMacro( << "No shading table found for that volume!" );
return NULL;
}
return this->ShadingTable[index][1];
}
float *vtkEncodedGradientShader::GetBlueDiffuseShadingTable( vtkVolume *vol )
{
int index;
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == vol )
{
break;
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
vtkErrorMacro( << "No shading table found for that volume!" );
return NULL;
}
return this->ShadingTable[index][2];
}
float *vtkEncodedGradientShader::GetRedSpecularShadingTable( vtkVolume *vol )
{
int index;
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == vol )
{
break;
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
vtkErrorMacro( << "No shading table found for that volume!" );
return NULL;
}
return this->ShadingTable[index][3];
}
float *vtkEncodedGradientShader::GetGreenSpecularShadingTable( vtkVolume *vol )
{
int index;
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == vol )
{
break;
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
vtkErrorMacro( << "No shading table found for that volume!" );
return NULL;
}
return this->ShadingTable[index][4];
}
float *vtkEncodedGradientShader::GetBlueSpecularShadingTable( vtkVolume *vol )
{
int index;
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == vol )
{
break;
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
vtkErrorMacro( << "No shading table found for that volume!" );
return NULL;
}
return this->ShadingTable[index][5];
}
void vtkEncodedGradientShader::UpdateShadingTable(
vtkRenderer *ren, vtkVolume *vol,
vtkEncodedGradientEstimator *gradest)
{
double lightDirection[3], material[4], lightColor[3];
double lightPosition[3], lightFocalPoint[3];
double lightIntensity, viewDirection[3];
double cameraPosition[3], cameraFocalPoint[3], mag;
vtkLightCollection *lightCollection;
vtkLight *light;
double norm;
int update_flag;
vtkVolumeProperty *property;
vtkTransform *transform;
vtkMatrix4x4 *m;
double in[4], out[4], zero[4];
int index;
// Figure out which shading table we are working with
// First search through all existing ones, then if one
// is not found, use the first available index
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == vol )
{
break;
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
for ( index = 0; index < VTK_MAX_SHADING_TABLES; index++ )
{
if ( this->ShadingTableVolume[index] == NULL )
{
this->ShadingTableVolume[index] = vol;
break;
}
}
}
if ( index == VTK_MAX_SHADING_TABLES )
{
vtkErrorMacro( << "Too many shading tables!\n" <<
"Increase limit VTK_MAX_SHADING_TABLES and recompile!" );
return;
}
transform = vtkTransform::New();
m = vtkMatrix4x4::New();
vol->GetMatrix(m);
transform->SetMatrix(m);
transform->Inverse();
property = vol->GetProperty();
material[0] = property->GetAmbient(this->ActiveComponent);
material[1] = property->GetDiffuse(this->ActiveComponent);
material[2] = property->GetSpecular(this->ActiveComponent);
material[3] = property->GetSpecularPower(this->ActiveComponent);
update_flag = 0;
ren->GetActiveCamera()->GetPosition( cameraPosition );
ren->GetActiveCamera()->GetFocalPoint( cameraFocalPoint );
viewDirection[0] = cameraFocalPoint[0] - cameraPosition[0];
viewDirection[1] = cameraFocalPoint[1] - cameraPosition[1];
viewDirection[2] = cameraFocalPoint[2] - cameraPosition[2];
mag = sqrt( (double)(
viewDirection[0] * viewDirection[0] +
viewDirection[1] * viewDirection[1] +
viewDirection[2] * viewDirection[2] ) );
if ( mag )
{
viewDirection[0] /= mag;
viewDirection[1] /= mag;
viewDirection[2] /= mag;
}
memcpy( in, viewDirection, 3*sizeof(double) );
in[3] = 1.0;
transform->MultiplyPoint( in, out );
viewDirection[0] = out[0] / out[3];
viewDirection[1] = out[1] / out[3];
viewDirection[2] = out[2] / out[3];
in[0] = 0.0;
in[1] = 0.0;
in[2] = 0.0;
transform->MultiplyPoint( in, zero );
zero[0] /= zero[3];
zero[1] /= zero[3];
zero[2] /= zero[3];
viewDirection[0] -= zero[0];
viewDirection[1] -= zero[1];
viewDirection[2] -= zero[2];
// Loop through all lights and compute a shading table. For
// the first light, pass in an update_flag of 0, which means
// overwrite the shading table. For each light after that, pass
// in an update flag of 1, which means add to the shading table.
// All lights are forced to be directional light sources
// regardless of what they really are
// Set up the lights for traversal
lightCollection = ren->GetLights();
// In rare cases there are no lights
vtkLight *artificialLight=NULL;
if ( lightCollection->GetNumberOfItems() == 0 )
{
artificialLight = vtkLight::New();
artificialLight->SetIntensity(0.0);
lightCollection->AddItem(artificialLight);
}
vtkCollectionSimpleIterator sit;
lightCollection->InitTraversal(sit);
while ( (light = lightCollection->GetNextLight(sit)) != NULL )
{
if ( ! light->GetSwitch() )
{
continue;
}
// Get the light color, position, focal point, and intensity
light->GetColor( lightColor );
light->GetTransformedPosition( lightPosition );
light->GetTransformedFocalPoint( lightFocalPoint );
lightIntensity = light->GetIntensity( );
// Compute the light direction and normalize it
lightDirection[0] = lightFocalPoint[0] - lightPosition[0];
lightDirection[1] = lightFocalPoint[1] - lightPosition[1];
lightDirection[2] = lightFocalPoint[2] - lightPosition[2];
norm = sqrt( (double) ( lightDirection[0] * lightDirection[0] +
lightDirection[1] * lightDirection[1] +
lightDirection[2] * lightDirection[2] ) );
lightDirection[0] /= -norm;
lightDirection[1] /= -norm;
lightDirection[2] /= -norm;
memcpy( in, lightDirection, 3*sizeof(double) );
transform->MultiplyPoint( in, out );
lightDirection[0] = out[0] / out[3] - zero[0];
lightDirection[1] = out[1] / out[3] - zero[1];
lightDirection[2] = out[2] / out[3] - zero[2];
// Build / Add to the shading table
this->BuildShadingTable( index, lightDirection, lightColor,
lightIntensity, viewDirection,
material, ren->GetTwoSidedLighting(),
gradest, update_flag );
update_flag = 1;
}//while there is a light in the list of lights
if ( artificialLight )
{
lightCollection->RemoveItem(artificialLight);
artificialLight->Delete();
}
transform->Delete();
m->Delete();
}
// Build a shading table for a light with the given direction and
// color, for a material of the given type. material[0] = ambient,
// material[1] = diffuse, material[2] = specular, material[3] =
// specular exponent. If the ambient flag is 1, then ambient
// illumination is added. If not, then this means we are calculating
// the "other side" of two sided lighting, so no ambient intensity
// is added in. If update_flag is 0, the table is overwritten
// with the new values. If update_flag is 1, the new intensity values
// are added into the table. This way multiple light sources can
// be handled. There is one shading table per volume, and the index
// value indicates which index table is to be updated
void vtkEncodedGradientShader::BuildShadingTable( int index,
double lightDirection[3],
double lightColor[3],
double lightIntensity,
double viewDirection[3],
double material[4],
int twoSided,
vtkEncodedGradientEstimator *gradest,
int updateFlag )
{
double lx, ly, lz;
float n_dot_l;
float n_dot_v;
int i;
float *nptr;
float *sdr_ptr;
float *sdg_ptr;
float *sdb_ptr;
float *ssr_ptr;
float *ssg_ptr;
float *ssb_ptr;
float Ka, Es, Kd_intensity, Ks_intensity;
double half_x, half_y, half_z;
float mag, n_dot_h, specular_value;
int norm_size;
// Move to local variables
lx = lightDirection[0];
ly = lightDirection[1];
lz = lightDirection[2];
half_x = lx - viewDirection[0];
half_y = ly - viewDirection[1];
half_z = lz - viewDirection[2];
mag = sqrt( (double)(half_x*half_x + half_y*half_y + half_z*half_z ) );
if( mag != 0.0 )
{
half_x /= mag;
half_y /= mag;
half_z /= mag;
}
Ka = material[0] * lightIntensity;
Es = material[3];
Kd_intensity = material[1] * lightIntensity;
Ks_intensity = material[2] * lightIntensity;
nptr = gradest->GetDirectionEncoder()->GetDecodedGradientTable();
norm_size = gradest->GetDirectionEncoder()->GetNumberOfEncodedDirections();
if ( this->ShadingTableSize[index] != norm_size )
{
for ( i=0; i<6; i++ )
{
if ( this->ShadingTable[index][i] )
{
delete [] this->ShadingTable[index][i];
}
this->ShadingTable[index][i] = new float[norm_size];
}
this->ShadingTableSize[index] = norm_size;
}
sdr_ptr = this->ShadingTable[index][0];
sdg_ptr = this->ShadingTable[index][1];
sdb_ptr = this->ShadingTable[index][2];
ssr_ptr = this->ShadingTable[index][3];
ssg_ptr = this->ShadingTable[index][4];
ssb_ptr = this->ShadingTable[index][5];
// For each possible normal, compute the intensity of light at
// a location with that normal, and the given lighting and
// material properties
for ( i = 0; i < norm_size; i++ )
{
// If we have a zero normal, treat it specially
if ( ( *(nptr+0) == 0.0 ) &&
( *(nptr+1) == 0.0 ) &&
( *(nptr+2) == 0.0 ) )
{
// If we are not updating, initial everything to 0.0
if ( !updateFlag )
{
*(sdr_ptr) = 0.0;
*(sdg_ptr) = 0.0;
*(sdb_ptr) = 0.0;
*(ssr_ptr) = 0.0;
*(ssg_ptr) = 0.0;
*(ssb_ptr) = 0.0;
}
// Now add in ambient
*(sdr_ptr) += Ka * lightColor[0];
*(sdg_ptr) += Ka * lightColor[1];
*(sdb_ptr) += Ka * lightColor[2];
// Add in diffuse
*(sdr_ptr) +=
(Kd_intensity * this->ZeroNormalDiffuseIntensity * lightColor[0]);
*(sdg_ptr) +=
(Kd_intensity * this->ZeroNormalDiffuseIntensity * lightColor[1]);
*(sdb_ptr) +=
(Kd_intensity * this->ZeroNormalDiffuseIntensity * lightColor[2]);
// Add in specular
*(ssr_ptr) += this->ZeroNormalSpecularIntensity * lightColor[0];
*(ssg_ptr) += this->ZeroNormalSpecularIntensity * lightColor[1];
*(ssb_ptr) += this->ZeroNormalSpecularIntensity * lightColor[2];
}
else
{
// The dot product between the normal and the light vector
// used for diffuse illumination
n_dot_l = (*(nptr+0) * lx + *(nptr+1) * ly + *(nptr+2) * lz);
// The dot product between the normal and the halfway vector
// used for specular illumination
n_dot_h = (*(nptr+0) * half_x + *(nptr+1) * half_y + *(nptr+2) * half_z);
// Flip the normal if two sided lighting is on and the normal
// is pointing away from the viewer
if ( twoSided )
{
// The dot product between the normal and the view vector
// used for two sided lighting
n_dot_v = (*(nptr+0) * viewDirection[0] +
*(nptr+1) * viewDirection[1] +
*(nptr+2) * viewDirection[2]);
if ( n_dot_v > 0.0 )
{
n_dot_l = -n_dot_l;
n_dot_h = -n_dot_h;
}
}
// If we are updating, then begin by adding in ambient
if ( updateFlag )
{
*(sdr_ptr) += Ka * lightColor[0];
*(sdg_ptr) += Ka * lightColor[1];
*(sdb_ptr) += Ka * lightColor[2];
}
// Otherwise begin by setting the value to the ambient contribution
else
{
*(sdr_ptr) = Ka * lightColor[0];
*(sdg_ptr) = Ka * lightColor[1];
*(sdb_ptr) = Ka * lightColor[2];
*(ssr_ptr) = 0.0;
*(ssg_ptr) = 0.0;
*(ssb_ptr) = 0.0;
}
// If there is some diffuse contribution, add it in
if ( n_dot_l > 0 )
{
*(sdr_ptr) += (Kd_intensity * n_dot_l * lightColor[0]);
*(sdg_ptr) += (Kd_intensity * n_dot_l * lightColor[1]);
*(sdb_ptr) += (Kd_intensity * n_dot_l * lightColor[2]);
if ( n_dot_h > 0.001 )
{
specular_value = Ks_intensity * pow( (double)n_dot_h, (double)Es );
*(ssr_ptr) += specular_value * lightColor[0];
*(ssg_ptr) += specular_value * lightColor[1];
*(ssb_ptr) += specular_value * lightColor[2];
}
}
}
// Increment all the pointers
nptr += 3;
sdr_ptr++;
sdg_ptr++;
sdb_ptr++;
ssr_ptr++;
ssg_ptr++;
ssb_ptr++;
}
}
// Print the vtkEncodedGradientShader
void vtkEncodedGradientShader::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Zero Normal Diffuse Intensity: " <<
this->ZeroNormalDiffuseIntensity << endl;
os << indent << "Zero Normal Specular Intensity: " <<
this->ZeroNormalSpecularIntensity << endl;
os << indent << "ActiveComponent: " << this->ActiveComponent << endl;
}