1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4 
5   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
6   All rights reserved.
7   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
8 
9      This software is distributed WITHOUT ANY WARRANTY; without even
10      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11      PURPOSE.  See the above copyright notice for more information.
12 
13 =========================================================================*/
14 
15 #include "vtkActor.h"
16 #include "vtkCamera.h"
17 #include "vtkCommand.h"
18 #include "vtkMath.h"
19 #include "vtkNew.h"
20 #include "vtkOpenGLPolyDataMapper.h"
21 #include "vtkPLYReader.h"
22 #include "vtkProperty.h"
23 #include "vtkRegressionTestImage.h"
24 #include "vtkRenderWindow.h"
25 #include "vtkRenderWindowInteractor.h"
26 #include "vtkRenderer.h"
27 #include "vtkShaderProgram.h"
28 #include "vtkShaderProperty.h"
29 #include "vtkTestUtilities.h"
30 #include "vtkTimerLog.h"
31 #include "vtkTriangleMeshPointNormals.h"
32 
33 #define VTK_CREATE(type, name) vtkSmartPointer<type> name = vtkSmartPointer<type>::New()
34 
35 //------------------------------------------------------------------------------
36 // Update a uniform in the shader for each render. We do this with a
37 // callback for the UpdateShaderEvent
38 class vtkShaderCallback : public vtkCommand
39 {
40 public:
New()41   static vtkShaderCallback* New() { return new vtkShaderCallback; }
42   vtkRenderer* Renderer;
Execute(vtkObject *,unsigned long,void * calldata)43   void Execute(vtkObject*, unsigned long, void* calldata) override
44   {
45     vtkShaderProgram* program = reinterpret_cast<vtkShaderProgram*>(calldata);
46 
47     float diffuseColor[3];
48 
49 #if 0 // trippy mode
50     float inputHSV[3];
51     double theTime = vtkTimerLog::GetUniversalTime();
52     double twopi = 2.0*vtkMath::Pi();
53 
54     inputHSV[0] = sin(twopi*fmod(theTime,3.0)/3.0)/4.0 + 0.25;
55     inputHSV[1] = sin(twopi*fmod(theTime,4.0)/4.0)/2.0 + 0.5;
56     inputHSV[2] = 0.7*(sin(twopi*fmod(theTime,19.0)/19.0)/2.0 + 0.5);
57     vtkMath::HSVToRGB(inputHSV,diffuseColor);
58     cellBO->Program->SetUniform3f("diffuseColorUniform", diffuseColor);
59 
60     if (this->Renderer)
61     {
62       inputHSV[0] = sin(twopi*fmod(theTime,5.0)/5.0)/4.0 + 0.75;
63       inputHSV[1] = sin(twopi*fmod(theTime,7.0)/7.0)/2.0 + 0.5;
64       inputHSV[2] = 0.5*(sin(twopi*fmod(theTime,17.0)/17.0)/2.0 + 0.5);
65       vtkMath::HSVToRGB(inputHSV,diffuseColor);
66       this->Renderer->SetBackground(diffuseColor[0], diffuseColor[1], diffuseColor[2]);
67 
68       inputHSV[0] = sin(twopi*fmod(theTime,11.0)/11.0)/2.0+0.5;
69       inputHSV[1] = sin(twopi*fmod(theTime,13.0)/13.0)/2.0 + 0.5;
70       inputHSV[2] = 0.5*(sin(twopi*fmod(theTime,17.0)/17.0)/2.0 + 0.5);
71       vtkMath::HSVToRGB(inputHSV,diffuseColor);
72       this->Renderer->SetBackground2(diffuseColor[0], diffuseColor[1], diffuseColor[2]);
73     }
74 #else
75     diffuseColor[0] = 0.4;
76     diffuseColor[1] = 0.7;
77     diffuseColor[2] = 0.6;
78     program->SetUniform3f("diffuseColorUniform", diffuseColor);
79 #endif
80   }
81 
vtkShaderCallback()82   vtkShaderCallback() { this->Renderer = nullptr; }
83 };
84 
85 //------------------------------------------------------------------------------
TestUserShader2(int argc,char * argv[])86 int TestUserShader2(int argc, char* argv[])
87 {
88   vtkNew<vtkActor> actor;
89   vtkNew<vtkRenderer> renderer;
90   vtkNew<vtkOpenGLPolyDataMapper> mapper;
91   renderer->SetBackground(0.0, 0.0, 0.0);
92   vtkNew<vtkRenderWindow> renderWindow;
93   renderWindow->SetSize(400, 400);
94   renderWindow->AddRenderer(renderer);
95   renderer->AddActor(actor);
96   renderer->GradientBackgroundOn();
97   vtkNew<vtkRenderWindowInteractor> iren;
98   iren->SetRenderWindow(renderWindow);
99 
100   const char* fileName = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/dragon.ply");
101   vtkNew<vtkPLYReader> reader;
102   reader->SetFileName(fileName);
103   reader->Update();
104 
105   delete[] fileName;
106 
107   vtkNew<vtkTriangleMeshPointNormals> norms;
108   norms->SetInputConnection(reader->GetOutputPort());
109   norms->Update();
110 
111   mapper->SetInputConnection(norms->GetOutputPort());
112   actor->SetMapper(mapper);
113   actor->GetProperty()->SetAmbientColor(0.2, 0.2, 1.0);
114   actor->GetProperty()->SetDiffuseColor(1.0, 0.65, 0.7);
115   actor->GetProperty()->SetSpecularColor(1.0, 1.0, 1.0);
116   actor->GetProperty()->SetSpecular(0.5);
117   actor->GetProperty()->SetDiffuse(0.7);
118   actor->GetProperty()->SetAmbient(0.5);
119   actor->GetProperty()->SetSpecularPower(20.0);
120   actor->GetProperty()->SetOpacity(1.0);
121 
122   vtkShaderProperty* sp = actor->GetShaderProperty();
123 
124   // Clear all custom shader tag replacements
125   // The following code is mainly for regression testing as we do not have any
126   // custom shader replacements.
127   sp->ClearAllVertexShaderReplacements();
128   sp->ClearAllFragmentShaderReplacements();
129   sp->ClearAllGeometryShaderReplacements();
130   sp->ClearAllShaderReplacements();
131 
132   // Use our own hardcoded shader code. Generally this is a bad idea in a
133   // general purpose program as there are so many things VTK supports that
134   // hardcoded shaders will not handle depth peeling, picking, etc, but if you
135   // know what your data will be like it can be very useful. The mapper will set
136   // a bunch of uniforms regardless of if you are using them. But feel free to
137   // use them :-)
138   sp->SetVertexShaderCode(
139     "//VTK::System::Dec\n" // always start with this line
140     "in vec4 vertexMC;\n"
141     // use the default normal decl as the mapper
142     // will then provide the normalMatrix uniform
143     // which we use later on
144     "//VTK::Normal::Dec\n"
145     "uniform mat4 MCDCMatrix;\n"
146     "void main () {\n"
147     "  normalVCVSOutput = normalMatrix * normalMC;\n"
148     // do something weird with the vertex positions
149     // this will mess up your head if you keep
150     // rotating and looking at it, very trippy
151     "  vec4 tmpPos = MCDCMatrix * vertexMC;\n"
152     "  gl_Position = tmpPos*vec4(0.2+0.8*abs(tmpPos.x),0.2+0.8*abs(tmpPos.y),1.0,1.0);\n"
153     "}\n");
154   sp->SetFragmentShaderCode(
155     "//VTK::System::Dec\n" // always start with this line
156     "//VTK::Output::Dec\n" // always have this line in your FS
157     "in vec3 normalVCVSOutput;\n"
158     "uniform vec3 diffuseColorUniform;\n"
159     "void main () {\n"
160     "  float df = max(0.0, normalVCVSOutput.z);\n"
161     "  float sf = pow(df, 20.0);\n"
162     "  vec3 diffuse = df * diffuseColorUniform;\n"
163     "  vec3 specular = sf * vec3(0.4,0.4,0.4);\n"
164     "  gl_FragData[0] = vec4(0.3*abs(normalVCVSOutput) + 0.7*diffuse + specular, 1.0);\n"
165     "}\n");
166 
167   // Setup a callback to change some uniforms
168   VTK_CREATE(vtkShaderCallback, myCallback);
169   myCallback->Renderer = renderer;
170   mapper->AddObserver(vtkCommand::UpdateShaderEvent, myCallback);
171 
172   renderWindow->Render();
173   renderer->GetActiveCamera()->SetPosition(-0.2, 0.4, 1);
174   renderer->GetActiveCamera()->SetFocalPoint(0, 0, 0);
175   renderer->GetActiveCamera()->SetViewUp(0, 1, 0);
176   renderer->ResetCamera();
177   renderer->GetActiveCamera()->Zoom(2.0);
178   renderWindow->Render();
179 
180   int retVal = vtkRegressionTestImage(renderWindow);
181   if (retVal == vtkRegressionTester::DO_INTERACTOR)
182   {
183     iren->Start();
184   }
185 
186   return !retVal;
187 }
188