1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkOpenGLSkybox.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkOpenGLSkybox.h"
16 
17 #include "vtkCamera.h"
18 #include "vtkCommand.h"
19 #include "vtkObjectFactory.h"
20 #include "vtkOpenGLActor.h"
21 #include "vtkOpenGLError.h"
22 #include "vtkOpenGLPolyDataMapper.h"
23 #include "vtkOpenGLRenderer.h"
24 #include "vtkOpenGLShaderProperty.h"
25 #include "vtkOpenGLState.h"
26 #include "vtkPoints.h"
27 #include "vtkPolyData.h"
28 #include "vtkProperty.h"
29 #include "vtkRenderWindow.h"
30 #include "vtkShaderProgram.h"
31 #include "vtkTexture.h"
32 
33 #include <cmath>
34 
35 vtkStandardNewMacro(vtkOpenGLSkybox);
36 
vtkOpenGLSkybox()37 vtkOpenGLSkybox::vtkOpenGLSkybox()
38 {
39   vtkNew<vtkPolyData> poly;
40   vtkNew<vtkPoints> pts;
41   pts->SetNumberOfPoints(4);
42   pts->SetPoint(0, -1, -1, 0);
43   pts->SetPoint(1, 1, -1, 0);
44   pts->SetPoint(2, 1, 1, 0);
45   pts->SetPoint(3, -1, 1, 0);
46   poly->SetPoints(pts);
47   vtkNew<vtkCellArray> polys;
48   poly->SetPolys(polys);
49   polys->InsertNextCell(4);
50   polys->InsertCellPoint(0);
51   polys->InsertCellPoint(1);
52   polys->InsertCellPoint(2);
53   polys->InsertCellPoint(3);
54 
55   // this->CubeMapper->SetInputConnection(this->Cube->GetOutputPort(0));
56   this->CubeMapper->SetInputData(poly);
57   this->SetMapper(this->CubeMapper);
58   this->OpenGLActor->SetMapper(this->CubeMapper);
59 
60   vtkOpenGLShaderProperty* sp =
61     vtkOpenGLShaderProperty::SafeDownCast(this->OpenGLActor->GetShaderProperty());
62   sp->AddShaderReplacement(vtkShader::Vertex,
63     "//VTK::PositionVC::Dec",  // replace
64     true,                      // before the standard replacements
65     "//VTK::PositionVC::Dec\n" // we still want the default
66     "out vec3 TexCoords;\n",
67     false // only do it once
68   );
69   sp->AddShaderReplacement(vtkShader::Vertex,
70     "//VTK::PositionVC::Impl", // replace
71     true,                      // before the standard replacements
72     "  gl_Position = vec4(vertexMC.xy, 1.0, 1.0);\n"
73     "  vec4 tmpc = inverse(MCDCMatrix) * gl_Position;\n"
74     "  TexCoords = tmpc.xyz/tmpc.w;\n",
75     false // only do it once
76   );
77 
78   this->CubeMapper->AddObserver(
79     vtkCommand::UpdateShaderEvent, this, &vtkOpenGLSkybox::UpdateUniforms);
80 
81   this->LastProjection = -1;
82   this->LastGammaCorrect = false;
83 
84   this->GetProperty()->SetDiffuse(0.0);
85   this->GetProperty()->SetAmbient(1.0);
86   this->GetProperty()->SetSpecular(0.0);
87   this->OpenGLActor->SetProperty(this->GetProperty());
88   this->CurrentRenderer = nullptr;
89 }
90 
91 vtkOpenGLSkybox::~vtkOpenGLSkybox() = default;
92 
UpdateUniforms(vtkObject *,unsigned long,void * calldata)93 void vtkOpenGLSkybox::UpdateUniforms(vtkObject*, unsigned long, void* calldata)
94 {
95   vtkShaderProgram* program = reinterpret_cast<vtkShaderProgram*>(calldata);
96 
97   program->SetUniform3f("cameraPos", this->LastCameraPosition);
98   float plane[4];
99   double norm = vtkMath::Norm(this->FloorPlane, 3);
100   plane[0] = this->FloorPlane[0] / norm;
101   plane[1] = this->FloorPlane[1] / norm;
102   plane[2] = this->FloorPlane[2] / norm;
103   plane[3] = this->FloorPlane[3] / norm;
104   program->SetUniform4f("floorPlane", plane);
105   program->SetUniform3f("floorRight", this->FloorRight);
106   float front[3];
107   vtkMath::Cross(plane, this->FloorRight, front);
108   program->SetUniform3f("floorFront", front);
109   program->SetUniformf(
110     "leftEye", (this->CurrentRenderer->GetActiveCamera()->GetLeftEye() ? 1.0 : 0.0));
111 }
112 
113 // Actual Skybox render method.
Render(vtkRenderer * ren,vtkMapper * mapper)114 void vtkOpenGLSkybox::Render(vtkRenderer* ren, vtkMapper* mapper)
115 {
116   vtkOpenGLClearErrorMacro();
117 
118   if (this->LastProjection != this->Projection || this->LastGammaCorrect != this->GammaCorrect)
119   {
120     vtkOpenGLShaderProperty* sp =
121       vtkOpenGLShaderProperty::SafeDownCast(this->OpenGLActor->GetShaderProperty());
122 
123     std::string str = "//VTK::System::Dec\n" // always start with this line
124                       "//VTK::Output::Dec\n" // always have this line in your FS
125                       "in vec3 TexCoords;\n"
126                       "uniform vec3 cameraPos;\n" // wc camera position;
127                       "//VTK::Projection::Dec\n"
128                       "void main () {\n"
129                       "//VTK::Projection::Impl\n"
130                       "}\n";
131 
132     if (this->Projection == vtkSkybox::Cube)
133     {
134       vtkShaderProgram::Substitute(
135         str, "//VTK::Projection::Dec", "uniform samplerCube actortexture;\n");
136 
137       vtkShaderProgram::Substitute(str, "//VTK::Projection::Impl",
138         "  vec4 color = texture(actortexture, normalize(TexCoords - cameraPos));\n"
139         "//VTK::Gamma::Impl\n");
140     }
141     if (this->Projection == vtkSkybox::Sphere)
142     {
143       vtkShaderProgram::Substitute(str, "//VTK::Projection::Dec",
144         "uniform sampler2D actortexture;\n"
145         "uniform vec4 floorPlane;\n" // floor plane eqn
146         "uniform vec3 floorRight;\n" // floor plane right
147         "uniform vec3 floorFront;\n" // floor plane front
148       );
149 
150       vtkShaderProgram::Substitute(str, "//VTK::Projection::Impl",
151         "  vec3 diri = normalize(TexCoords - cameraPos);\n"
152         "  vec3 dirv = vec3(dot(diri,floorRight),\n"
153         "    dot(diri,floorPlane.xyz),\n"
154         "    dot(diri,floorFront));\n"
155         "  float phix = length(vec2(dirv.x, dirv.z));\n"
156         "  vec4 color = textureLod(actortexture, vec2(0.5*atan(dirv.x, "
157         "dirv.z)/3.1415927 + 0.5, atan(dirv.y,phix)/3.1415927 + 0.5), 1.0);\n"
158         "//VTK::Gamma::Impl\n");
159     }
160     if (this->Projection == vtkSkybox::StereoSphere)
161     {
162       vtkShaderProgram::Substitute(str, "//VTK::Projection::Dec",
163         "uniform sampler2D actortexture;\n"
164         "uniform vec4 floorPlane;\n" // floor plane eqn
165         "uniform vec3 floorRight;\n" // floor plane right
166         "uniform vec3 floorFront;\n" // floor plane front
167         "uniform float leftEye;\n"   // 1.0 for left, 0.0 for right
168       );
169 
170       vtkShaderProgram::Substitute(str, "//VTK::Projection::Impl",
171         "  vec3 diri = normalize(TexCoords - cameraPos);\n"
172         "  vec3 dirv = vec3(dot(diri,floorRight),\n"
173         "    dot(diri,floorPlane.xyz),\n"
174         "    dot(diri,floorFront));\n"
175         "  float phix = length(vec2(dirv.x, dirv.z));\n"
176         "  vec4 color = textureLod(actortexture, vec2(0.5*atan(dirv.x, dirv.z)/3.1415927 + "
177         "0.5, 0.5*atan(dirv.y,phix)/3.1415927 + 0.25 + 0.5*leftEye), 1.0);\n"
178         "//VTK::Gamma::Impl\n");
179     }
180     if (this->Projection == vtkSkybox::Floor)
181     {
182       vtkShaderProgram::Substitute(str, "//VTK::Projection::Dec",
183         "uniform vec4 floorPlane;\n" // floor plane eqn
184         "uniform vec3 floorRight;\n" // floor plane right
185         "uniform vec3 floorFront;\n" // floor plane front
186         "uniform mat4 MCDCMatrix;\n"
187         "uniform sampler2D actortexture;\n");
188 
189       vtkShaderProgram::Substitute(str, "//VTK::Projection::Impl",
190         "  vec3 dirv = normalize(TexCoords - cameraPos);\n"
191         "  float den = dot(floorPlane.xyz, dirv);\n"
192         "  if (abs(den) < 0.0001 ) { discard; } else {\n"
193         "    vec3 p0 = -1.0*floorPlane.w*floorPlane.xyz;\n"
194         "    vec3 p0l0 = p0 - cameraPos;\n"
195         "    float t = dot(p0l0, floorPlane.xyz) / den;\n"
196         "    if (t >= 0.0) {\n"
197         "      vec3 pos = dirv*t - p0l0;\n"
198         "      vec4 color = texture(actortexture, "
199         "vec2(dot(floorRight,pos), dot(floorFront, pos)));\n"
200         "      //VTK::Gamma::Impl\n"
201         // The discards cause a discontinuity with mipmapping
202         // on the horizon of the floor. So we fade out the floor
203         // along the horizon. Specifically starting at when the
204         // dot product equals .02 which is at 88.85 degrees and
205         // going to zero at 90 degrees.
206         "      gl_FragData[0].a *= (50.0*min(0.02, abs(den)));\n"
207         "      vec4 tpos = MCDCMatrix*vec4(pos.xyz,1.0);\n"
208         "      gl_FragDepth = clamp(0.5 + 0.5*tpos.z/tpos.w,0.0,1.0);\n"
209         "    } else { discard; }\n"
210         "  }\n");
211     }
212 
213     if (this->GammaCorrect)
214     {
215       vtkShaderProgram::Substitute(str, "//VTK::Gamma::Impl",
216         "gl_FragData[0] = vec4(pow(color.rgb, vec3(1.0 / 2.2)), color.a);\n");
217     }
218     else
219     {
220       vtkShaderProgram::Substitute(str, "//VTK::Gamma::Impl", "gl_FragData[0] = color;\n");
221     }
222 
223     sp->SetFragmentShaderCode(str.c_str());
224 
225     this->CubeMapper->Modified();
226     this->LastProjection = this->Projection;
227     this->LastGammaCorrect = this->GammaCorrect;
228   }
229 
230   double* pos = ren->GetActiveCamera()->GetPosition();
231   this->LastCameraPosition[0] = pos[0];
232   this->LastCameraPosition[1] = pos[1];
233   this->LastCameraPosition[2] = pos[2];
234 
235   this->CurrentRenderer = ren;
236 
237   // get opacity
238   static_cast<vtkOpenGLRenderer*>(ren)->GetState()->vtkglDepthMask(GL_TRUE);
239   static_cast<vtkOpenGLRenderer*>(ren)->GetState()->vtkglDepthFunc(GL_LEQUAL);
240 
241   // send a render to the mapper; update pipeline
242   this->Texture->Render(ren);
243   this->OpenGLActor->SetTexture(this->GetTexture());
244   mapper->Render(ren, this->OpenGLActor);
245   this->Texture->PostRender(ren);
246 
247   vtkOpenGLCheckErrorMacro("failed after Render");
248 }
249 
250 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)251 void vtkOpenGLSkybox::PrintSelf(ostream& os, vtkIndent indent)
252 {
253   this->Superclass::PrintSelf(os, indent);
254 }
255