1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24
25 #include "pxr/pxr.h"
26
27 #include "pxr/imaging/garch/glApi.h"
28
29 #include "pxr/usdImaging/usdImagingGL/unitTestGLDrawing.h"
30
31 #include "pxr/base/arch/systemInfo.h"
32 #include "pxr/base/gf/bbox3d.h"
33 #include "pxr/base/gf/frustum.h"
34 #include "pxr/base/gf/matrix4d.h"
35 #include "pxr/base/gf/matrix4f.h"
36 #include "pxr/base/gf/range3d.h"
37 #include "pxr/base/gf/rotation.h"
38 #include "pxr/base/gf/vec3d.h"
39 #include "pxr/base/tf/getenv.h"
40 #include "pxr/base/trace/trace.h"
41
42 #include "pxr/imaging/glf/simpleLightingContext.h"
43 #include "pxr/imaging/hd/mesh.h"
44 #include "pxr/imaging/hd/renderIndex.h"
45 #include "pxr/usd/usd/stage.h"
46 #include "pxr/usd/usdGeom/bboxCache.h"
47 #include "pxr/usd/usdGeom/metrics.h"
48 #include "pxr/usd/usdGeom/tokens.h"
49
50 #include "pxr/usdImaging/usdImaging/unitTestHelper.h"
51 #include "pxr/usdImaging/usdImaging/tokens.h"
52
53 #include "pxr/usdImaging/usdImagingGL/engine.h"
54
55 #include <iomanip>
56 #include <iostream>
57 #include <sstream>
58 #include <fstream>
59
60 PXR_NAMESPACE_USING_DIRECTIVE
61
62 using UsdImagingGLEngineSharedPtr = std::shared_ptr<class UsdImagingGLEngine>;
63
64 class My_TestGLDrawing : public UsdImagingGL_UnitTestGLDrawing {
65 public:
My_TestGLDrawing()66 My_TestGLDrawing() {
67 _mousePos[0] = _mousePos[1] = 0;
68 _mouseButton[0] = _mouseButton[1] = _mouseButton[2] = false;
69 _rotate[0] = _rotate[1] = 0;
70 _translate[0] = _translate[1] = _translate[2] = 0;
71 }
72
73 // UsdImagingGL_UnitTestGLDrawing overrides
74 virtual void InitTest();
75 virtual void DrawTest(bool offscreen);
76 virtual void ShutdownTest();
77
78 virtual void MousePress(int button, int x, int y, int modKeys);
79 virtual void MouseRelease(int button, int x, int y, int modKeys);
80 virtual void MouseMove(int x, int y, int modKeys);
81
82 private:
83 UsdStageRefPtr _stage;
84 UsdImagingGLEngineSharedPtr _engine;
85 GlfSimpleLightingContextRefPtr _lightingContext;
86
87 float _rotate[2];
88 float _translate[3];
89 int _mousePos[2];
90 bool _mouseButton[3];
91 };
92
93 GLuint vao;
94
95 void
InitTest()96 My_TestGLDrawing::InitTest()
97 {
98 TRACE_FUNCTION();
99
100 std::cout << "My_TestGLDrawing::InitTest()\n";
101 _stage = UsdStage::Open(GetStageFilePath());
102 SdfPathVector excludedPaths;
103
104 if (UsdImagingGLEngine::IsHydraEnabled()) {
105 std::cout << "Using HD Renderer.\n";
106 _engine.reset(new UsdImagingGLEngine(
107 _stage->GetPseudoRoot().GetPath(), excludedPaths));
108 if (!_GetRenderer().IsEmpty()) {
109 if (!_engine->SetRendererPlugin(_GetRenderer())) {
110 std::cerr << "Couldn't set renderer plugin: " <<
111 _GetRenderer().GetText() << std::endl;
112 exit(-1);
113 } else {
114 std::cout << "Renderer plugin: " << _GetRenderer().GetText()
115 << std::endl;
116 }
117 }
118 } else{
119 std::cout << "Using Reference Renderer.\n";
120 _engine.reset(
121 new UsdImagingGLEngine(_stage->GetPseudoRoot().GetPath(),
122 excludedPaths));
123 }
124
125 for (const auto &renderSetting : GetRenderSettings()) {
126 _engine->SetRendererSetting(TfToken(renderSetting.first),
127 renderSetting.second);
128 }
129
130 std::cout << glGetString(GL_VENDOR) << "\n";
131 std::cout << glGetString(GL_RENDERER) << "\n";
132 std::cout << glGetString(GL_VERSION) << "\n";
133
134 if (_ShouldFrameAll()) {
135 TfTokenVector purposes;
136 purposes.push_back(UsdGeomTokens->default_);
137 purposes.push_back(UsdGeomTokens->proxy);
138
139 // Extent hints are sometimes authored as an optimization to avoid
140 // computing bounds, they are particularly useful for some tests where
141 // there is no bound on the first frame.
142 bool useExtentHints = true;
143 UsdGeomBBoxCache bboxCache(UsdTimeCode::Default(), purposes, useExtentHints);
144
145 GfBBox3d bbox = bboxCache.ComputeWorldBound(_stage->GetPseudoRoot());
146 GfRange3d world = bbox.ComputeAlignedRange();
147
148 GfVec3d worldCenter = (world.GetMin() + world.GetMax()) / 2.0;
149 double worldSize = world.GetSize().GetLength();
150
151 std::cerr << "worldCenter: " << worldCenter << "\n";
152 std::cerr << "worldSize: " << worldSize << "\n";
153 if (UsdGeomGetStageUpAxis(_stage) == UsdGeomTokens->z) {
154 // transpose y and z centering translation
155 _translate[0] = -worldCenter[0];
156 _translate[1] = -worldCenter[2];
157 _translate[2] = -worldCenter[1] - worldSize;
158 } else {
159 _translate[0] = -worldCenter[0];
160 _translate[1] = -worldCenter[1];
161 _translate[2] = -worldCenter[2] - worldSize;
162 }
163 } else {
164 _translate[0] = GetTranslate()[0];
165 _translate[1] = GetTranslate()[1];
166 _translate[2] = GetTranslate()[2];
167 }
168
169 if(IsEnabledTestLighting()) {
170 if(UsdImagingGLEngine::IsHydraEnabled()) {
171 // set same parameter as GlfSimpleLightingContext::SetStateFromOpenGL
172 // OpenGL defaults
173 _lightingContext = GlfSimpleLightingContext::New();
174 if (!IsEnabledSceneLights()) {
175 GlfSimpleLight light;
176 if (IsEnabledCameraLight()) {
177 light.SetPosition(GfVec4f(_translate[0], _translate[2], _translate[1], 0));
178 } else {
179 light.SetPosition(GfVec4f(0, -.5, .5, 0));
180 }
181 light.SetDiffuse(GfVec4f(1,1,1,1));
182 light.SetAmbient(GfVec4f(0,0,0,1));
183 light.SetSpecular(GfVec4f(1,1,1,1));
184 GlfSimpleLightVector lights;
185 lights.push_back(light);
186 _lightingContext->SetLights(lights);
187 }
188
189 GlfSimpleMaterial material;
190 material.SetAmbient(GfVec4f(0.2, 0.2, 0.2, 1.0));
191 material.SetDiffuse(GfVec4f(0.8, 0.8, 0.8, 1.0));
192 material.SetSpecular(GfVec4f(0,0,0,1));
193 material.SetShininess(0.0001f);
194 _lightingContext->SetMaterial(material);
195 _lightingContext->SetSceneAmbient(GfVec4f(0.2,0.2,0.2,1.0));
196 } else {
197 glEnable(GL_LIGHTING);
198 glEnable(GL_LIGHT0);
199 if (IsEnabledCameraLight()) {
200 float position[4] = {_translate[0], _translate[2], _translate[1], 0};
201 glLightfv(GL_LIGHT0, GL_POSITION, position);
202 } else {
203 float position[4] = {0,-.5,.5,0};
204 glLightfv(GL_LIGHT0, GL_POSITION, position);
205 }
206 }
207 }
208 }
209
210 void
DrawTest(bool offscreen)211 My_TestGLDrawing::DrawTest(bool offscreen)
212 {
213 TRACE_FUNCTION();
214
215 std::cout << "My_TestGLDrawing::DrawTest()\n";
216
217 TfStopwatch renderTime;
218
219 HdPerfLog& perfLog = HdPerfLog::GetInstance();
220 perfLog.Enable();
221
222 // Reset all counters we care about.
223 perfLog.ResetCache(HdTokens->extent);
224 perfLog.ResetCache(HdTokens->points);
225 perfLog.ResetCache(HdTokens->topology);
226 perfLog.ResetCache(HdTokens->transform);
227 perfLog.SetCounter(UsdImagingTokens->usdVaryingExtent, 0);
228 perfLog.SetCounter(UsdImagingTokens->usdVaryingPrimvar, 0);
229 perfLog.SetCounter(UsdImagingTokens->usdVaryingTopology, 0);
230 perfLog.SetCounter(UsdImagingTokens->usdVaryingVisibility, 0);
231 perfLog.SetCounter(UsdImagingTokens->usdVaryingXform, 0);
232
233 const int width = GetWidth();
234 const int height = GetHeight();
235
236 if (GetCameraPath().empty()) {
237 GfMatrix4d viewMatrix(1.0);
238 viewMatrix *= GfMatrix4d().SetRotate(GfRotation(GfVec3d(0, 1, 0), _rotate[0]));
239 viewMatrix *= GfMatrix4d().SetRotate(GfRotation(GfVec3d(1, 0, 0), _rotate[1]));
240 viewMatrix *= GfMatrix4d().SetTranslate(GfVec3d(_translate[0], _translate[1], _translate[2]));
241
242 GfMatrix4d modelViewMatrix = viewMatrix;
243 if (UsdGeomGetStageUpAxis(_stage) == UsdGeomTokens->z) {
244 // rotate from z-up to y-up
245 modelViewMatrix =
246 GfMatrix4d().SetRotate(GfRotation(GfVec3d(1.0,0.0,0.0), -90.0)) *
247 modelViewMatrix;
248 }
249
250 const double aspectRatio = double(width)/height;
251 GfFrustum frustum;
252 frustum.SetPerspective(60.0, aspectRatio, 1, 100000.0);
253 const GfMatrix4d projMatrix = frustum.ComputeProjectionMatrix();
254
255 _engine->SetCameraState(modelViewMatrix, projMatrix);
256 } else {
257 _engine->SetCameraPath(SdfPath(GetCameraPath()));
258 }
259
260 const CameraUtilFraming framing(
261 GetDisplayWindow(), GetDataWindow(), GetPixelAspectRatio());
262 if (framing.IsValid()) {
263 _engine->SetRenderBufferSize(GfVec2i(width, height));
264 _engine->SetFraming(framing);
265 _engine->SetOverrideWindowPolicy({true, CameraUtilFit});
266 } else {
267 const GfVec4d viewport(0, 0, width, height);
268 _engine->SetRenderViewport(viewport);
269 }
270
271 bool const useAovs = !GetRendererAov().IsEmpty();
272 GfVec4f fboClearColor = useAovs? GfVec4f(0.0f) : GetClearColor();
273 GLfloat clearDepth[1] = { 1.0f };
274 bool const clearOnlyOnce = ShouldClearOnce();
275 bool cleared = false;
276
277 UsdImagingGLRenderParams params;
278 params.drawMode = GetDrawMode();
279 params.enableLighting = IsEnabledTestLighting();
280 params.enableIdRender = IsEnabledIdRender();
281 params.enableSceneMaterials = IsEnabledSceneMaterials();
282 params.complexity = _GetComplexity();
283 params.cullStyle = GetCullStyle();
284 params.showGuides = IsShowGuides();
285 params.showRender = IsShowRender();
286 params.showProxy = IsShowProxy();
287 params.clearColor = GetClearColor();
288
289 glViewport(0, 0, width, height);
290
291 glEnable(GL_DEPTH_TEST);
292
293 if (useAovs) {
294 _engine->SetRendererAov(GetRendererAov());
295 }
296
297 if(IsEnabledTestLighting()) {
298 if(UsdImagingGLEngine::IsHydraEnabled()) {
299 _engine->SetLightingState(_lightingContext);
300 } else {
301 _engine->SetLightingStateFromOpenGL();
302 }
303 }
304
305 if (PresentDisabled()) {
306 _engine->SetEnablePresentation(false);
307 }
308
309 if (!GetClipPlanes().empty()) {
310 params.clipPlanes = GetClipPlanes();
311 for (size_t i=0; i<GetClipPlanes().size(); ++i) {
312 glEnable(GL_CLIP_PLANE0 + i);
313 }
314 }
315
316 for (double const &t : GetTimes()) {
317 UsdTimeCode time = t;
318 if (t == -999) {
319 time = UsdTimeCode::Default();
320 }
321
322 params.frame = time;
323
324 // Make sure we render to convergence.
325 TfErrorMark mark;
326 int convergenceIterations = 0;
327
328 {
329 TRACE_FUNCTION_SCOPE("test profile: renderTime");
330
331 renderTime.Start();
332
333 do {
334 TRACE_FUNCTION_SCOPE("iteration render convergence");
335
336 convergenceIterations++;
337
338 if (cleared && clearOnlyOnce) {
339 // Don't clear the FBO
340 } else {
341 glClearBufferfv(GL_COLOR, 0, fboClearColor.data());
342 glClearBufferfv(GL_DEPTH, 0, clearDepth);
343
344 cleared = true;
345 }
346
347 _engine->Render(_stage->GetPseudoRoot(), params);
348 } while (!_engine->IsConverged());
349
350 {
351 TRACE_FUNCTION_SCOPE("glFinish");
352 glFinish();
353 }
354
355 renderTime.Stop();
356 }
357
358 TF_VERIFY(mark.IsClean(), "Errors occurred while rendering!");
359
360 std::cout << "Iterations to convergence: " << convergenceIterations << std::endl;
361 std::cout << "itemsDrawn " << perfLog.GetCounter(HdTokens->itemsDrawn) << std::endl;
362 std::cout << "totalItemCount " << perfLog.GetCounter(HdTokens->totalItemCount) << std::endl;
363
364 std::string imageFilePath = GetOutputFilePath();
365 if (!imageFilePath.empty()) {
366 if (time != UsdTimeCode::Default()) {
367 std::stringstream suffix;
368 suffix << "_" << std::setw(3) << std::setfill('0') << params.frame << ".png";
369 imageFilePath = TfStringReplace(imageFilePath, ".png", suffix.str());
370 }
371 std::cout << imageFilePath << "\n";
372 WriteToFile("color", imageFilePath);
373 }
374 }
375
376 if (!GetPerfStatsFile().empty()) {
377 std::ofstream perfstatsRaw(GetPerfStatsFile(), std::ofstream::out);
378 if (TF_VERIFY(perfstatsRaw)) {
379 perfstatsRaw << "{ 'profile' : 'renderTime', "
380 << " 'metric' : 'time', "
381 << " 'value' : " << renderTime.GetSeconds() << ", "
382 << " 'samples' : " << GetTimes().size() << " }" << std::endl;
383 }
384 }
385 }
386
387 void
ShutdownTest()388 My_TestGLDrawing::ShutdownTest()
389 {
390 std::cout << "My_TestGLDrawing::ShutdownTest()\n";
391 }
392
393 void
MousePress(int button,int x,int y,int modKeys)394 My_TestGLDrawing::MousePress(int button, int x, int y, int modKeys)
395 {
396 _mouseButton[button] = 1;
397 _mousePos[0] = x;
398 _mousePos[1] = y;
399 }
400
401 void
MouseRelease(int button,int x,int y,int modKeys)402 My_TestGLDrawing::MouseRelease(int button, int x, int y, int modKeys)
403 {
404 _mouseButton[button] = 0;
405 }
406
407 void
MouseMove(int x,int y,int modKeys)408 My_TestGLDrawing::MouseMove(int x, int y, int modKeys)
409 {
410 int dx = x - _mousePos[0];
411 int dy = y - _mousePos[1];
412
413 if (_mouseButton[0]) {
414 _rotate[0] += dx;
415 _rotate[1] += dy;
416 } else if (_mouseButton[1]) {
417 _translate[0] += dx;
418 _translate[1] -= dy;
419 } else if (_mouseButton[2]) {
420 _translate[2] += dx;
421 }
422
423 _mousePos[0] = x;
424 _mousePos[1] = y;
425 }
426
427 void
BasicTest(int argc,char * argv[])428 BasicTest(int argc, char *argv[])
429 {
430 My_TestGLDrawing driver;
431 driver.RunTest(argc, argv);
432 }
433
main(int argc,char * argv[])434 int main(int argc, char *argv[])
435 {
436 BasicTest(argc, argv);
437 std::cout << "OK" << std::endl;
438 }
439