MarbleShaderDemo
Repository source: MarbleShaderDemo
Description¶
Makes solid marble texture with strong veins. The "veincolor" parameter controls the color of the veins. The background color is given by the surface's DiffuseColor.
Explore the parameter space with the vtkSliderWidget.
The file for the shader code is src/Testing/Data/Shaders/PerlinNoise.glsl
.
Parameters¶
- veinfreq - controls the lowest frequency of the color veins e.g. 10
- veinlevels - how many "levels" of vein tendrils it has e.g. 2
- warpfreq - lowest frequency of the turbulent warping in the marble e.g. 10
- warping - controls how much turbulent warping there will be e.g. 0.5
- veincolor - the color of the veins e.g. white: 1 1 1
- sharpness - controls how sharp or fuzzy the veins are (higher = sharper) e.g. 8
Cite
Perlin's original Siggraph Paper: Perlin, K. 1985. "An Image Synthesizer." Computer Graphics 19(3).
Cite
This shader is inspired by Larry Gritz's veined marble shader.
Other languages
See (PythonicAPI)
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
MarbleShaderDemo.cxx
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCameraOrientationWidget.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOpenGLPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkProperty2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkShaderProgram.h>
#include <vtkSliderRepresentation2D.h>
#include <vtkSliderWidget.h>
#include <vtkSmartPointer.h>
#include <vtkTextProperty.h>
#include <vtkVersion.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkTriangleFilter.h>
#include <vtkTriangleMeshPointNormals.h>
#include <vtkBYUReader.h>
#include <vtkOBJReader.h>
#include <vtkPLYReader.h>
#include <vtkPolyDataReader.h>
#include <vtkSTLReader.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>
#include <vtksys/SystemTools.hxx>
#if VTK_VERSION_NUMBER >= 90020210809ULL
#define VTK_HAS_COW 1
#endif
#if VTK_HAS_COW
#include <vtkCameraOrientationWidget.h>
#endif
#if VTK_VERSION_NUMBER >= 89000000000ULL
#define USE_SHADER_PROPERTIES 1
#include <vtkShaderProperty.h>
#endif
#include <array>
#include <chrono>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
// Delay time in milliseconds.
// #define DELAY 200
#define DELAY 20
namespace {
struct ShaderProperties
{
std::array<double, 3> veincolor{0.0, 0.501961, 0.0};
float veinfreq{7.5};
int veinlevels{3};
float warpfreq{1.5};
float warping{0.5};
float sharpness{8.0};
} shaderProperties;
std::string dispParameters();
// Commands for the vertex and fragment shaders.
struct ShaderCommand
{
std::string p1;
bool p2;
std::string p3;
bool p4;
};
ShaderCommand GetVertexShaderReplacement1();
ShaderCommand GetVertexShaderReplacement2();
ShaderCommand GetFragmentShaderReplacement1(std::string const& shaderCode);
ShaderCommand GetFragmentShaderReplacement2();
ShaderCommand GetFragmentShaderReplacement3();
// -----------------------------------------------------------------------
// Update uniform variables in the shader for each render. We do this with
// a callback for the UpdateShaderEvent.
class ShaderCallback : public vtkCommand
{
public:
static ShaderCallback* New()
{
return new ShaderCallback;
}
ShaderCallback()
{
this->veincolor = shaderProperties.veincolor;
this->veinfreq = shaderProperties.veinfreq;
this->veinlevels = shaderProperties.veinlevels;
this->warpfreq = shaderProperties.warpfreq;
this->warping = shaderProperties.warping;
this->sharpness = shaderProperties.sharpness;
}
void Execute(vtkObject*, unsigned long, void* calldata) override
{
vtkShaderProgram* program = reinterpret_cast<vtkShaderProgram*>(calldata);
if (program)
{
program->SetUniform3f("veincolor", shaderProperties.veincolor.data());
program->SetUniformf("veinfreq", shaderProperties.veinfreq);
program->SetUniformi("veinlevels", shaderProperties.veinlevels);
program->SetUniformf("warpfreq", shaderProperties.warpfreq);
program->SetUniformf("warping", shaderProperties.warping);
program->SetUniformf("sharpness", shaderProperties.sharpness);
if (HasChanged())
{
std::cout << dispParameters();
Update();
}
}
}
private:
void Update()
{
this->veincolor = shaderProperties.veincolor;
this->veinfreq = shaderProperties.veinfreq;
this->veinlevels = shaderProperties.veinlevels;
this->warpfreq = shaderProperties.warpfreq;
this->warping = shaderProperties.warping;
this->sharpness = shaderProperties.sharpness;
}
bool HasChanged()
{
if (this->veincolor != shaderProperties.veincolor)
{
return true;
}
if (this->veinfreq != shaderProperties.veinfreq)
{
return true;
}
if (this->veinlevels != shaderProperties.veinlevels)
{
return true;
}
if (this->warpfreq != shaderProperties.warpfreq)
{
return true;
}
if (this->warping != shaderProperties.warping)
{
return true;
}
if (this->sharpness != shaderProperties.sharpness)
{
return true;
}
return false;
}
public:
std::array<double, 3> veincolor;
float veinfreq;
int veinlevels;
float warpfreq;
float warping;
float sharpness;
};
// These callbacks do the actual work.
// Callbacks for the interactions
class SliderCallbackVeinFreq : public vtkCommand
{
public:
static SliderCallbackVeinFreq* New()
{
return new SliderCallbackVeinFreq;
}
virtual void Execute(vtkObject* caller, unsigned long, void*)
{
vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
float value = static_cast<vtkSliderRepresentation2D*>(
sliderWidget->GetRepresentation())
->GetValue();
shaderProperties.veinfreq = value;
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY));
}
SliderCallbackVeinFreq() = default;
};
class SliderCallbackVeinLevels : public vtkCommand
{
public:
static SliderCallbackVeinLevels* New()
{
return new SliderCallbackVeinLevels;
}
virtual void Execute(vtkObject* caller, unsigned long, void*)
{
vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
int value = static_cast<vtkSliderRepresentation2D*>(
sliderWidget->GetRepresentation())
->GetValue();
static_cast<vtkSliderRepresentation2D*>(sliderWidget->GetRepresentation())
->SetValue(value);
shaderProperties.veinlevels = value;
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY));
}
SliderCallbackVeinLevels() = default;
};
class SliderCallbackWarpFreq : public vtkCommand
{
public:
static SliderCallbackWarpFreq* New()
{
return new SliderCallbackWarpFreq;
}
virtual void Execute(vtkObject* caller, unsigned long, void*)
{
vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
float value = static_cast<vtkSliderRepresentation2D*>(
sliderWidget->GetRepresentation())
->GetValue();
shaderProperties.warpfreq = value;
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY));
}
SliderCallbackWarpFreq() : Shader(0)
{
}
ShaderCallback* Shader;
};
class SliderCallbackWarping : public vtkCommand
{
public:
static SliderCallbackWarping* New()
{
return new SliderCallbackWarping;
}
virtual void Execute(vtkObject* caller, unsigned long, void*)
{
vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
float value = static_cast<vtkSliderRepresentation2D*>(
sliderWidget->GetRepresentation())
->GetValue();
shaderProperties.warping = value;
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY));
}
SliderCallbackWarping() = default;
};
class SliderCallbackSharpness : public vtkCommand
{
public:
static SliderCallbackSharpness* New()
{
return new SliderCallbackSharpness;
}
virtual void Execute(vtkObject* caller, unsigned long, void*)
{
vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
float value = static_cast<vtkSliderRepresentation2D*>(
sliderWidget->GetRepresentation())
->GetValue();
shaderProperties.sharpness = value;
std::this_thread::sleep_for(std::chrono::milliseconds(DELAY));
}
SliderCallbackSharpness() = default;
};
vtkSmartPointer<vtkPolyData> ReadPolyData(const char* fileName);
struct SliderProperties
{
// Set up the sliders
double tubeWidth{0.008};
double sliderLength{0.075};
double sliderWidth{0.025};
double endCapLength{0.025};
double endCapWidth{0.025};
double titleHeight{0.025};
double labelHeight{0.020};
double minimumValue{0.0};
double maximumValue{1.0};
double initialValue{0.0};
std::array<double, 2> p1{0.02, 0.1};
std::array<double, 2> p2{0.18, 0.1};
std::string title{""};
std::string titleColor{"Black"};
std::string labelColor{"Black"};
std::string valueColor{"DarkSlateGray"};
std::string sliderColor{"BurlyWood"};
std::string selectedColor{"Lime"};
std::string barColor{"Black"};
std::string barEndsColor{"Indigo"};
};
vtkNew<vtkSliderWidget> MakeSliderWidget(SliderProperties const& properties,
vtkRenderer* currentRenderer,
vtkRenderWindowInteractor* interactor);
} // namespace
//----------------------------------------------------------------------------
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cout << "Usage: " << argv[0] << " PerlnNoise.glsl "
<< "[polydataFile] " << "[veincolor(0.0, 0.501961, 0.0)] "
<< "[veinfreq(7.5)] " << "[veinlevels(3)] "
<< "[warpfreq(1.5)] " << "[warping(0.5)] "
<< "[sharpness(8.0)]" << std::endl;
std::cout << "If the polydata file is not specified,"
" a sphere is used instead."
<< std::endl;
return EXIT_FAILURE;
}
vtkNew<vtkNamedColors> colors;
// Set the background color.
std::array<unsigned char, 4> bkg{{26, 51, 102, 255}};
colors->SetColor("BkgColor", bkg.data());
auto polyData = ReadPolyData(argc > 2 ? argv[2] : "");
std::ifstream shaderFile(argv[1]);
std::ostringstream shaderCode;
shaderCode << shaderFile.rdbuf();
// This is where we change the defaultshader properties.
// Defaulting to green.
shaderProperties.veincolor[0] = colors->GetColor3d("Green").GetData()[0];
shaderProperties.veincolor[1] = colors->GetColor3d("Green").GetData()[1];
shaderProperties.veincolor[2] = colors->GetColor3d("Green").GetData()[2];
// Create a transform to rescale the model.
double center[3];
polyData->GetCenter(center);
double bounds[6];
polyData->GetBounds(bounds);
double maxBound =
std::max(std::max(bounds[1] - bounds[0], bounds[3] - bounds[2]),
bounds[5] - bounds[4]);
// Build the pipeline.
// ren1 is for the slider rendering,
// ren2 is for the object rendering.
vtkNew<vtkRenderer> ren1;
ren1->SetBackground(colors->GetColor3d("Snow").GetData());
vtkNew<vtkRenderer> ren2;
vtkNew<vtkOpenGLPolyDataMapper> mapper;
ren2->SetBackground(colors->GetColor3d("SlateGray").GetData());
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->SetSize(800, 480);
renderWindow->SetWindowName("MarbleShaderDemo");
// The order here is important.
// This ensures that the sliders will be in ren1.
renderWindow->AddRenderer(ren2);
renderWindow->AddRenderer(ren1);
ren1->SetViewport(0.0, 0.0, 0.2, 1.0);
ren2->SetViewport(0.2, 0.0, 1, 1);
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renderWindow);
vtkNew<vtkInteractorStyleTrackballCamera> style;
interactor->SetInteractorStyle(style);
// Rescale the polydata to [-1,1].
vtkNew<vtkTransform> userTransform;
userTransform->Translate(-center[0], -center[1], -center[2]);
userTransform->Scale(1.0 / maxBound, 1.0 / maxBound, 1.0 / maxBound);
vtkNew<vtkTransformPolyDataFilter> transform;
transform->SetTransform(userTransform);
transform->SetInputData(polyData);
vtkNew<vtkTriangleFilter> triangles;
triangles->SetInputConnection(transform->GetOutputPort());
vtkNew<vtkTriangleMeshPointNormals> norms;
norms->SetInputConnection(triangles->GetOutputPort());
mapper->SetInputConnection(norms->GetOutputPort());
mapper->ScalarVisibilityOff();
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuse(1.0);
actor->GetProperty()->SetDiffuseColor(colors->GetColor3d("Wheat").GetData());
actor->GetProperty()->SetSpecular(.5);
actor->GetProperty()->SetSpecularPower(50);
ren2->AddActor(actor);
// Modify the vertex shader to pass the position of the vertex.
auto cmd = GetVertexShaderReplacement1();
#if USE_SHADER_PROPERTIES
vtkShaderProperty* sp = actor->GetShaderProperty();
sp->AddVertexShaderReplacement(cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#else
mapper->AddShaderReplacement(vtkShader::Vertex, cmd.p1, cmd.p2, cmd.p3,
cmd.p4);
#endif
cmd = GetVertexShaderReplacement2();
#if USE_SHADER_PROPERTIES
sp->AddVertexShaderReplacement(cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#else
mapper->AddShaderReplacement(vtkShader::Vertex, cmd.p1, cmd.p2, cmd.p3,
cmd.p4);
#endif
// Add the code to generate noise.
// These functions need to be defined outside of main.
// Use the System::Dec to declare and implement.
cmd = GetFragmentShaderReplacement1(shaderCode.str());
#if USE_SHADER_PROPERTIES
sp->AddFragmentShaderReplacement(cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#else
mapper->AddShaderReplacement(vtkShader::Fragment, // in the fragment shader
cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#endif
// Define varying and uniforms for the fragment shader here.
cmd = GetFragmentShaderReplacement2();
#if USE_SHADER_PROPERTIES
sp->AddFragmentShaderReplacement(cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#else
mapper->AddShaderReplacement(vtkShader::Fragment, // in the fragment shader
cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#endif
cmd = GetFragmentShaderReplacement3();
#if USE_SHADER_PROPERTIES
sp->AddFragmentShaderReplacement(cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#else
mapper->AddShaderReplacement(vtkShader::Fragment, // in the fragment shader
cmd.p1, cmd.p2, cmd.p3, cmd.p4);
#endif
std::cout << "------------" << std::endl;
std::cout << "Input: " << (argc > 2 ? argv[2] : "Generated Sphere")
<< std::endl;
std::cout << "------------" << std::endl;
std::cout << dispParameters();
vtkNew<ShaderCallback> myCallback;
mapper->AddObserver(vtkCommand::UpdateShaderEvent, myCallback);
// Setup a slider widget and callback for each varying parameter.
auto stepSize = 1.0 / 5.0;
auto posY = 0.1;
auto posX0 = 0.1;
auto posX1 = 0.9;
auto slwP = SliderProperties();
// Slider values
slwP.minimumValue = 1.0;
slwP.initialValue = 7.5;
slwP.maximumValue = 15.0;
slwP.title = "Vein Frequency";
// Screen coordinates.
slwP.p1[0] = posX0;
slwP.p1[1] = posY;
slwP.p2[0] = posX1;
slwP.p2[1] = posY;
auto sliderWidgetVeinFreq = MakeSliderWidget(slwP, ren1, interactor);
vtkNew<SliderCallbackVeinFreq> callbackVeinFreq;
sliderWidgetVeinFreq->AddObserver(vtkCommand::InteractionEvent,
callbackVeinFreq);
posY += stepSize;
// Slider values
slwP.minimumValue = 1;
slwP.initialValue = 3;
slwP.maximumValue = 5;
slwP.title = "Vein Levels";
// Screen coordinates.
slwP.p1[0] = posX0;
slwP.p1[1] = posY;
slwP.p2[0] = posX1;
slwP.p2[1] = posY;
auto sliderWidgetVeinLevels = MakeSliderWidget(slwP, ren1, interactor);
vtkNew<SliderCallbackVeinLevels> callbackVeinLevels;
sliderWidgetVeinLevels->AddObserver(vtkCommand::EndInteractionEvent,
callbackVeinLevels);
posY += stepSize;
// Slider values
slwP.minimumValue = 1.0;
slwP.initialValue = 1.5;
slwP.maximumValue = 2.0;
slwP.title = "Warp Frequency";
// Screen coordinates.
slwP.p1[0] = posX0;
slwP.p1[1] = posY;
slwP.p2[0] = posX1;
slwP.p2[1] = posY;
auto sliderWidgetWarpFreq = MakeSliderWidget(slwP, ren1, interactor);
vtkNew<SliderCallbackWarpFreq> callbackWarpFreq;
sliderWidgetWarpFreq->AddObserver(vtkCommand::InteractionEvent,
callbackWarpFreq);
posY += stepSize;
// Slider values
slwP.minimumValue = 0.0;
slwP.initialValue = 0.5;
slwP.maximumValue = 1.0;
slwP.title = "Warping";
// Screen coordinates.
slwP.p1[0] = posX0;
slwP.p1[1] = posY;
slwP.p2[0] = posX1;
slwP.p2[1] = posY;
auto sliderWidgetWarping = MakeSliderWidget(slwP, ren1, interactor);
vtkNew<SliderCallbackWarping> callbackWarping;
sliderWidgetWarping->AddObserver(vtkCommand::InteractionEvent,
callbackWarping);
posY += stepSize;
// Slider values
slwP.minimumValue = 0.01;
slwP.initialValue = 8.0;
slwP.maximumValue = 10.0;
slwP.title = "Sharpness";
// Screen coordinates.
slwP.p1[0] = posX0;
slwP.p1[1] = posY;
slwP.p2[0] = posX1;
slwP.p2[1] = posY;
auto sliderWidgetSharpness = MakeSliderWidget(slwP, ren1, interactor);
vtkNew<SliderCallbackSharpness> callbackSharpness;
sliderWidgetSharpness->AddObserver(vtkCommand::InteractionEvent,
callbackSharpness);
renderWindow->Render();
#if VTK_HAS_COW
vtkNew<vtkCameraOrientationWidget> camOrientManipulator;
camOrientManipulator->SetParentRenderer(ren2);
// Enable the widget.
camOrientManipulator->On();
#else
vtkNew<vtkAxesActor> axes;
vtkNew<vtkOrientationMarkerWidget> widget;
double rgba[4]{0.0, 0.0, 0.0, 0.0};
colors->GetColor("Carrot", rgba);
widget->SetOutlineColor(rgba[0], rgba[1], rgba[2]);
widget->SetOrientationMarker(axes);
widget->SetInteractor(interactor);
widget->SetViewport(0.0, 0.0, 0.2, 0.2);
widget->EnabledOn();
widget->InteractiveOn();
#endif
ren2->ResetCamera();
ren2->GetActiveCamera()->Zoom(1.0);
renderWindow->Render();
renderWindow->Render();
interactor->Start();
transform->GetOutput()->GetBounds(bounds);
std::cout << "------------" << std::endl;
std::cout << "Range: " << " x " << bounds[1] - bounds[0] << " y "
<< bounds[3] - bounds[2] << " z " << bounds[5] - bounds[4]
<< std::endl;
std::cout << "------------" << std::endl;
return EXIT_SUCCESS;
}
namespace {
std::string dispParameters()
{
std::stringstream ss;
ss << "------------" << std::endl;
ss << "veincolor: " << shaderProperties.veincolor[0] << ", "
<< shaderProperties.veincolor[1] << ", " << shaderProperties.veincolor[2]
<< std::endl;
ss << "veinfreq: " << shaderProperties.veinfreq << std::endl;
ss << "veinlevels: " << shaderProperties.veinlevels << std::endl;
ss << "warpfreq: " << shaderProperties.warpfreq << std::endl;
ss << "warping: " << shaderProperties.warping << std::endl;
ss << "sharpness: " << shaderProperties.sharpness << std::endl;
ss << "------------" << std::endl;
return ss.str();
}
vtkSmartPointer<vtkPolyData> ReadPolyData(const char* fileName)
{
vtkSmartPointer<vtkPolyData> polyData;
std::string extension =
vtksys::SystemTools::GetFilenameExtension(std::string(fileName));
if (extension == ".ply")
{
vtkNew<vtkPLYReader> reader;
reader->SetFileName(fileName);
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".vtp")
{
vtkNew<vtkXMLPolyDataReader> reader;
reader->SetFileName(fileName);
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".obj")
{
vtkNew<vtkOBJReader> reader;
reader->SetFileName(fileName);
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".stl")
{
vtkNew<vtkSTLReader> reader;
reader->SetFileName(fileName);
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".vtk")
{
vtkNew<vtkPolyDataReader> reader;
reader->SetFileName(fileName);
reader->Update();
polyData = reader->GetOutput();
}
else if (extension == ".g")
{
vtkNew<vtkBYUReader> reader;
reader->SetGeometryFileName(fileName);
reader->Update();
polyData = reader->GetOutput();
}
else
{
vtkNew<vtkSphereSource> source;
source->SetPhiResolution(25);
source->SetThetaResolution(25);
source->Update();
polyData = source->GetOutput();
}
return polyData;
}
ShaderCommand GetVertexShaderReplacement1()
{
ShaderCommand sc;
sc.p1 = "//VTK::Normal::Dec"; // replace the normal block
sc.p2 = true; // before the standard replacements
sc.p3 = "//VTK::Normal::Dec\n" // we still want the default
" out vec4 myVertexMC;\n";
sc.p4 = false; // only do it once
return sc;
}
ShaderCommand GetVertexShaderReplacement2()
{
ShaderCommand sc;
sc.p1 = "//VTK::Normal::Impl"; // replace the normal block
sc.p2 = true; // before the standard replacements
sc.p3 = "//VTK::Normal::Impl\n" // we still want the default
" myVertexMC = vertexMC;\n";
sc.p4 = false; // only do it once
return sc;
}
ShaderCommand GetFragmentShaderReplacement1(std::string const& shaderCode)
{
ShaderCommand sc;
sc.p1 = "//VTK::System::Dec";
sc.p2 = false; // before the standard replacements
sc.p3 = shaderCode;
sc.p4 = false; // only do it once
return sc;
}
ShaderCommand GetFragmentShaderReplacement2()
{
ShaderCommand sc;
sc.p1 = "//VTK::Normal::Dec"; // replace the normal block
sc.p2 = false; // before the standard replacements
sc.p3 = "//VTK::Normal::Dec\n" // we still want the default
" varying vec4 myVertexMC;\n"
" uniform vec3 veincolor = vec3(1.0, 1.0, 1.0);\n"
" uniform float veinfreq = 10.0;\n"
" uniform int veinlevels = 2;\n"
" uniform float warpfreq = 1;\n"
" uniform float warping = .5;\n"
" uniform float sharpness = 8.0;\n";
sc.p4 = false; // only do it once
return sc;
}
ShaderCommand GetFragmentShaderReplacement3()
{
ShaderCommand sc;
sc.p1 = "//VTK::Light::Impl", // replace the light block
sc.p2 = false; // after the standard replacements
sc.p3 = "//VTK::Light::Impl\n" // we still want the default calc
"\n"
"#define pnoise(x) ((noise(x) + 1.0) / 2.0)\n"
"#define snoise(x) (2.0 * pnoise(x) - 1.0)\n"
" vec3 Ct;\n"
" int i;\n"
" float turb, freq;\n"
" float turbsum;\n"
" /* perturb the lookup */\n"
" freq = 1.0;\n"
" vec4 offset = vec4(0.0,0.0,0.0,0.0);\n"
" vec4 noisyPoint;\n"
" vec4 myLocalVertexMC = myVertexMC;\n"
"\n"
" for (i = 0; i < 6; i += 1) {\n"
" noisyPoint[0] = snoise(warpfreq * freq * myLocalVertexMC);\n"
" noisyPoint[1] = snoise(warpfreq * freq * myLocalVertexMC);\n"
" noisyPoint[2] = snoise(warpfreq * freq * myLocalVertexMC);\n"
" noisyPoint[3] = 1.0;\n"
" offset += 2.0 * warping * (noisyPoint - 0.5) / freq;\n"
" freq *= 2.0;\n"
" }\n"
" myLocalVertexMC.x += offset.x;\n"
" myLocalVertexMC.y += offset.y;\n"
" myLocalVertexMC.z += offset.z;\n"
"\n"
" /* Now calculate the veining function for the lookup area */\n"
" turbsum = 0.0; freq = 1.0;\n"
" myLocalVertexMC *= veinfreq;\n"
" for (i = 0; i < veinlevels; i += 1) {\n"
" turb = abs (snoise (myLocalVertexMC));\n"
" turb = pow (smoothstep (0.8, 1.0, 1.0 - turb), sharpness) / "
"freq;\n"
" turbsum += (1.0-turbsum) * turb;\n"
" freq *= 1.5;\n"
" myLocalVertexMC *= 1.5;\n"
" }\n"
"\n"
" Ct = mix (diffuseColor, veincolor, turbsum);\n"
"\n"
" fragOutput0.rgb = opacity * (ambientColor + Ct + specular);\n"
" fragOutput0.a = opacity;\n";
sc.p4 = false; // only do it once
return sc;
}
vtkNew<vtkSliderWidget> MakeSliderWidget(SliderProperties const& properties,
vtkRenderer* currentRenderer,
vtkRenderWindowInteractor* interactor)
{
vtkNew<vtkNamedColors> colors;
vtkNew<vtkSliderRepresentation2D> slider;
slider->SetMinimumValue(properties.minimumValue);
slider->SetMaximumValue(properties.maximumValue);
slider->SetValue(properties.initialValue);
slider->SetTitleText(properties.title.c_str());
slider->GetPoint1Coordinate()->SetCoordinateSystemToNormalizedViewport();
slider->GetPoint1Coordinate()->SetValue(properties.p1[0], properties.p1[1]);
slider->GetPoint2Coordinate()->SetCoordinateSystemToNormalizedViewport();
slider->GetPoint2Coordinate()->SetValue(properties.p2[0], properties.p2[1]);
slider->SetTubeWidth(properties.tubeWidth);
slider->SetSliderLength(properties.sliderLength);
slider->SetSliderWidth(properties.sliderWidth);
slider->SetEndCapLength(properties.endCapLength);
slider->SetEndCapWidth(properties.endCapWidth);
slider->SetTitleHeight(properties.titleHeight);
slider->SetLabelHeight(properties.labelHeight);
// Set the color properties
// Change the color of the title.
slider->GetTitleProperty()->SetColor(
colors->GetColor3d(properties.titleColor).GetData());
// Change the color of the label.
slider->GetLabelProperty()->SetColor(
colors->GetColor3d(properties.labelColor).GetData());
// Change the color of the bar.
slider->GetTubeProperty()->SetColor(
colors->GetColor3d(properties.barColor).GetData());
// Change the color of the ends of the bar.
slider->GetCapProperty()->SetColor(
colors->GetColor3d(properties.barEndsColor).GetData());
// Change the color of the knob that slides.
slider->GetSliderProperty()->SetColor(
colors->GetColor3d(properties.sliderColor).GetData());
// Change the color of the knob when the mouse is held on it.
slider->GetSelectedProperty()->SetColor(
colors->GetColor3d(properties.selectedColor).GetData());
// Change the color of the text displaying the value.
slider->GetLabelProperty()->SetColor(
colors->GetColor3d(properties.valueColor).GetData());
vtkNew<vtkSliderWidget> sliderWidget;
sliderWidget->SetCurrentRenderer(currentRenderer);
sliderWidget->SetInteractor(interactor);
sliderWidget->SetRepresentation(slider);
sliderWidget->SetAnimationModeToAnimate();
sliderWidget->SetNumberOfAnimationSteps(10);
sliderWidget->EnabledOn();
return sliderWidget;
}
} // namespace
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MarbleShaderDemo)
find_package(VTK COMPONENTS
CommonColor
CommonCore
CommonTransforms
FiltersCore
FiltersGeneral
FiltersSources
IOGeometry
IOLegacy
IOPLY
IOXML
InteractionStyle
InteractionWidgets
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "MarbleShaderDemo: Unable to find the VTK build folder.")
endif()
# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(MarbleShaderDemo MACOSX_BUNDLE MarbleShaderDemo.cxx )
target_link_libraries(MarbleShaderDemo PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS MarbleShaderDemo
MODULES ${VTK_LIBRARIES}
)
Download and Build MarbleShaderDemo¶
Click here to download MarbleShaderDemo and its CMakeLists.txt file. Once the tarball MarbleShaderDemo.tar has been downloaded and extracted,
cd MarbleShaderDemo/build
If VTK is installed:
cmake ..
If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:
cmake -DVTK_DIR:PATH=/home/me/vtk_build ..
Build the project:
make
and run it:
./MarbleShaderDemo
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.