1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkPBRIrradianceTexture.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 "vtkPBRIrradianceTexture.h"
16 #include "vtkObjectFactory.h"
17 #include "vtkOpenGLFramebufferObject.h"
18 #include "vtkOpenGLQuadHelper.h"
19 #include "vtkOpenGLRenderUtilities.h"
20 #include "vtkOpenGLRenderWindow.h"
21 #include "vtkOpenGLState.h"
22 #include "vtkRenderer.h"
23 #include "vtkShaderProgram.h"
24 #include "vtkTextureObject.h"
25
26 #include "vtk_glew.h"
27
28 #include <sstream>
29
30 vtkStandardNewMacro(vtkPBRIrradianceTexture);
31
32 vtkCxxSetObjectMacro(vtkPBRIrradianceTexture, InputTexture, vtkOpenGLTexture);
33
34 //------------------------------------------------------------------------------
~vtkPBRIrradianceTexture()35 vtkPBRIrradianceTexture::~vtkPBRIrradianceTexture()
36 {
37 if (this->InputTexture)
38 {
39 this->InputTexture->Delete();
40 }
41 }
42
43 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)44 void vtkPBRIrradianceTexture::PrintSelf(ostream& os, vtkIndent indent)
45 {
46 this->Superclass::PrintSelf(os, indent);
47 os << indent << "IrradianceStep: " << this->IrradianceStep << "\n";
48 os << indent << "IrradianceSize: " << this->IrradianceSize << endl;
49 }
50
51 //------------------------------------------------------------------------------
52 // Release the graphics resources used by this texture.
ReleaseGraphicsResources(vtkWindow * win)53 void vtkPBRIrradianceTexture::ReleaseGraphicsResources(vtkWindow* win)
54 {
55 if (this->InputTexture)
56 {
57 this->InputTexture->ReleaseGraphicsResources(win);
58 }
59 this->Superclass::ReleaseGraphicsResources(win);
60 }
61
62 //------------------------------------------------------------------------------
Load(vtkRenderer * ren)63 void vtkPBRIrradianceTexture::Load(vtkRenderer* ren)
64 {
65 vtkOpenGLRenderWindow* renWin = vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow());
66 if (!renWin)
67 {
68 vtkErrorMacro("No render window.");
69 }
70
71 if (!this->InputTexture)
72 {
73 vtkErrorMacro("No input cubemap specified.");
74 }
75
76 this->InputTexture->Render(ren);
77
78 if (this->GetMTime() > this->LoadTime.GetMTime() ||
79 this->InputTexture->GetMTime() > this->LoadTime.GetMTime())
80 {
81 if (this->TextureObject == nullptr)
82 {
83 this->TextureObject = vtkTextureObject::New();
84 }
85 this->TextureObject->SetContext(renWin);
86 this->TextureObject->SetFormat(GL_RGB);
87 this->TextureObject->SetInternalFormat(GL_RGB16F);
88 this->TextureObject->SetDataType(GL_FLOAT);
89 this->TextureObject->SetWrapS(vtkTextureObject::ClampToEdge);
90 this->TextureObject->SetWrapT(vtkTextureObject::ClampToEdge);
91 this->TextureObject->SetWrapR(vtkTextureObject::ClampToEdge);
92 this->TextureObject->SetMinificationFilter(vtkTextureObject::Linear);
93 this->TextureObject->SetMagnificationFilter(vtkTextureObject::Linear);
94 this->TextureObject->CreateCubeFromRaw(
95 this->IrradianceSize, this->IrradianceSize, 3, VTK_FLOAT, nullptr);
96
97 this->RenderWindow = renWin;
98
99 vtkOpenGLState* state = renWin->GetState();
100 vtkOpenGLState::ScopedglViewport svp(state);
101 vtkOpenGLState::ScopedglEnableDisable sdepth(state, GL_DEPTH_TEST);
102 vtkOpenGLState::ScopedglEnableDisable sblend(state, GL_BLEND);
103 vtkOpenGLState::ScopedglEnableDisable sscissor(state, GL_SCISSOR_TEST);
104
105 std::string FSSource = vtkOpenGLRenderUtilities::GetFullScreenQuadFragmentShaderTemplate();
106
107 vtkShaderProgram::Substitute(FSSource, "//VTK::FSQ::Decl",
108 "//VTK::TEXTUREINPUT::Decl\n"
109 "uniform vec3 shift;\n"
110 "uniform vec3 contribX;\n"
111 "uniform vec3 contribY;\n"
112 "const float PI = 3.14159265359;\n"
113 "vec3 GetSampleColor(vec3 dir)\n"
114 "{\n"
115 " //VTK::SAMPLING::Decl\n"
116 " //VTK::COLORSPACE::Decl\n"
117 "}\n");
118
119 if (this->ConvertToLinear)
120 {
121 vtkShaderProgram::Substitute(
122 FSSource, "//VTK::COLORSPACE::Decl", "return pow(col, vec3(2.2));");
123 }
124 else
125 {
126 vtkShaderProgram::Substitute(FSSource, "//VTK::COLORSPACE::Decl", "return col;");
127 }
128
129 if (this->InputTexture->GetCubeMap())
130 {
131 vtkShaderProgram::Substitute(
132 FSSource, "//VTK::TEXTUREINPUT::Decl", "uniform samplerCube inputTex;");
133
134 vtkShaderProgram::Substitute(
135 FSSource, "//VTK::SAMPLING::Decl", "vec3 col = texture(inputTex, dir).rgb;");
136 }
137 else
138 {
139 vtkShaderProgram::Substitute(
140 FSSource, "//VTK::TEXTUREINPUT::Decl", "uniform sampler2D inputTex;");
141
142 vtkShaderProgram::Substitute(FSSource, "//VTK::SAMPLING::Decl",
143 " dir = normalize(dir);\n"
144 " float theta = atan(dir.z, dir.x);\n"
145 " float phi = asin(dir.y);\n"
146 " vec2 p = vec2(theta * 0.1591 + 0.5, phi * 0.3183 + 0.5);\n"
147 " vec3 col = texture(inputTex, p).rgb;\n");
148 }
149
150 std::stringstream fsImpl;
151 fsImpl
152 << " const vec3 x = vec3(1.0, 0.0, 0.0);\n"
153 " const vec3 y = vec3(0.0, 1.0, 0.0);\n"
154 " vec3 n = normalize(vec3(shift.x + contribX.x * texCoord.x + contribY.x * texCoord.y,\n"
155 " shift.y + contribX.y * texCoord.x + contribY.y * texCoord.y,\n"
156 " shift.z + contribX.z * texCoord.x + contribY.z * texCoord.y));\n"
157 " vec3 t = normalize(cross(n, y));\n"
158 " mat3 m = mat3(t, cross(n, t), n);\n"
159 " vec3 acc = vec3(0.0);\n"
160 " float nSamples = 0.0;\n"
161 " for (float phi = 0.0; phi < 2.0 * PI; phi += "
162 << this->IrradianceStep
163 << ")\n"
164 " {\n"
165 " for (float theta = 0.0; theta < 0.5 * PI; theta += "
166 << this->IrradianceStep
167 << ")\n"
168 " {\n"
169 " vec3 sample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));\n"
170 " float factor = cos(theta) * sin(theta);\n"
171 " acc += GetSampleColor(m * sample) * factor;\n"
172 " nSamples = nSamples + 1.0;\n"
173 " }\n"
174 " }\n"
175 " gl_FragData[0] = vec4(acc * (PI / nSamples), 1.0);\n";
176
177 vtkShaderProgram::Substitute(FSSource, "//VTK::FSQ::Impl", fsImpl.str());
178
179 vtkOpenGLQuadHelper quadHelper(renWin,
180 vtkOpenGLRenderUtilities::GetFullScreenQuadVertexShader().c_str(), FSSource.c_str(), "");
181
182 vtkNew<vtkOpenGLFramebufferObject> fbo;
183 fbo->SetContext(renWin);
184 renWin->GetState()->PushFramebufferBindings();
185 fbo->Bind();
186
187 if (!quadHelper.Program || !quadHelper.Program->GetCompiled())
188 {
189 vtkErrorMacro("Couldn't build the shader program for irradiance.");
190 }
191 else
192 {
193 this->InputTexture->GetTextureObject()->Activate();
194 quadHelper.Program->SetUniformi("inputTex", this->InputTexture->GetTextureUnit());
195
196 float shift[6][3] = { { 1.f, 1.f, 1.f }, { -1.f, 1.f, -1.f }, { -1.f, 1.f, -1.f },
197 { -1.f, -1.f, 1.f }, { -1.f, 1.f, 1.f }, { 1.f, 1.f, -1.f } };
198 float contribX[6][3] = { { 0.f, 0.f, -2.f }, { 0.f, 0.f, 2.f }, { 2.f, 0.f, 0.f },
199 { 2.f, 0.f, 0.f }, { 2.f, 0.f, 0.f }, { -2.f, 0.f, 0.f } };
200 float contribY[6][3] = { { 0.f, -2.f, 0.f }, { 0.f, -2.f, 0.f }, { 0.f, 0.f, 2.f },
201 { 0.f, 0.f, -2.f }, { 0.f, -2.f, 0.f }, { 0.f, -2.f, 0.f } };
202
203 for (int i = 0; i < 6; i++)
204 {
205 fbo->AddColorAttachment(0, this->TextureObject, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i);
206 fbo->ActivateDrawBuffers(1);
207 fbo->Start(this->IrradianceSize, this->IrradianceSize);
208
209 quadHelper.Program->SetUniform3f("shift", shift[i]);
210 quadHelper.Program->SetUniform3f("contribX", contribX[i]);
211 quadHelper.Program->SetUniform3f("contribY", contribY[i]);
212 quadHelper.Render();
213 fbo->RemoveColorAttachment(0);
214
215 // Computing irradiance can be long depending on the GPU.
216 // On Windows 7, a computation longer than 2 seconds triggers GPU timeout.
217 // The following call do a glFlush() that inform the OS that the computation is finished
218 // thus avoids the trigger of the GPU timeout.
219 renWin->WaitForCompletion();
220 }
221 this->InputTexture->GetTextureObject()->Deactivate();
222 }
223 renWin->GetState()->PopFramebufferBindings();
224 this->LoadTime.Modified();
225 }
226
227 this->TextureObject->Activate();
228 }
229