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