Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Viewer Guides #5960

Open
BrianHanke opened this issue Jul 15, 2024 · 42 comments
Open

Feature Request: Viewer Guides #5960

BrianHanke opened this issue Jul 15, 2024 · 42 comments

Comments

@BrianHanke
Copy link
Contributor

Howdy all, it would be nice to have some guide options to help setting up a camera. For example, darken the out of frame area, rule of thirds, title safe area, etc. I'm always game to try implementing stuff myself if it's doable in Python, so let me know if that's a possibility. Thanks!

example

@johnhaddon
Copy link
Member

I think it is possible to implement such a thing in pure Python. The closest example code might be the CropWindowTool, which draws a camera-relative overlay. Unfortunately that is written in C++, but it might be good enough to give you the gist of things : https://github.com/GafferHQ/gaffer/blob/main/src/GafferSceneUI/CropWindowTool.cpp. There are two main components :

  • A Tool, which appears in the toolbar on the left hand side. This has Plugs to define any settings you want.
  • A Gadget, which is responsible for doing the drawing in the Viewer, using OpenGL.

Both Tools and Gadgets can be subclassed in Python, but the only examples are the boilerplate we have in the unit tests :

https://github.com/GafferHQ/gaffer/blob/main/python/GafferUITest/GadgetTest.py#L84-L106
https://github.com/GafferHQ/gaffer/blob/main/python/GafferUITest/ToolTest.py#L49-L56

If you do take a stab at this, feel free to keep asking questions on here and I'll do my best to answer them.

Ideally I think this would be best implemented natively as part of the Viewer's camera overlay, with the options being in the Camera menu. But that would involve C++...

@BrianHanke
Copy link
Contributor Author

Thanks @johnhaddon! I'll have a look. I can handle C++ to a limited extent, but it would be more cumbersome for sure, having to set up all the dependencies and compile everything. I think I could probably adapt the crop tool C++ to be a button click and draw some lines in the viewer. But I'll look into the Python way first.

@BrianHanke
Copy link
Contributor Author

@johnhaddon My first question is to ask if there's a way to run the unit test code, or a version of it, "live" from the Python Editor? For example, to create that TestTool sample in the existing viewer.

@johnhaddon
Copy link
Member

You should be able to run this direct in the PythonEditor :

class TestTool( GafferUI.Tool ) :

		def __init__( self, view, name = "TestTool" ) :

			GafferUI.Tool.__init__( self, view, name )

IECore.registerRunTimeTyped( TestTool, typeName = "GafferUITest::TestTool" )
GafferUI.Tool.registerTool( "TestTool", GafferSceneUI.SceneView, TestTool )

The only change from the unit test is that I've registered the tool against GafferSceneUI.SceneView, which makes it available in the 3d viewer. We don't refresh the tools on the fly at the moment, so you'll need to run that code before opening the viewer or the first time (or make a new Viewer afterwards).

This will get you to your first error (always a good development milestone!) :

ERROR : Exception: Unable to find file "gafferUITestTestTool.png"

That's just because the Viewer is looking for an icon that doesn't exist - if you make the icon then you should be getting somewhere...

@BrianHanke
Copy link
Contributor Author

Cool, that worked. I duplicated one of the existing icons and renamed it and the new tool showed up on the toolbar. I'm super busy these days but I'll keep chipping away at this in my free time. Will be fun!

@BrianHanke
Copy link
Contributor Author

@johnhaddon I'm finding some time to look at this again. I'm feeling confident with how the Tool works, but I haven't been able to target the Gadget at the Viewer in the current Gaffer window. I can get a new Gaffer window to pop up though. I tried sticking GafferSceneUI.SceneView in various spots, but I couldn't figure it out. Any tips?

On a related note, I found the resolutionGate stuff in SceneView.cpp. It looks like style->renderRectangle() is what creates the resolution gate when looking through a camera? Maybe there's a way to activate that through Python to draw, for example, two new rectangles, one for action safe and one for title safe? I figured I'd start simple with that before trying rule of thirds.

@johnhaddon
Copy link
Member

Here's some example code that shows how you can do some drawing relative to the resolution gate (assuming you are looking through a camera). The drawing is all delegated to a Gadget subclass, which is currently just drawing a really thick white rectangle over the top. I'll leave it to you to fill in the maths to render different areas of interest. To have different modes, you'd want to add a plug to specify the mode on your Tool class, and then use metadata to provide an appropriate UI for it in a toolbar in the viewer. Then connect to plugSetSignal(), and when the plug is set, update your gadget with information about what mode it should be drawing. Hopefully that makes sense?

import OpenGL.GL as GL

class GuideGadget( GafferUI.Gadget ) :

	def __init__( self, tool ) :
	
		GafferUI.Gadget.__init__( self, "GuideGadget" )

		# Weakref to avoid circular reference
		self.__tool = weakref.ref( tool )

	def renderLayer( self, layer, style, reason ) :

		resolutionGate = self.__tool().view().resolutionGate()
		if resolutionGate.isEmpty() :
			# Really you'd just return here, but I want to draw something at
			# all times so you can see that it is working easily.
			resolutionGate = imath.Box2f( imath.V2f( 100 ), imath.V2f( 200 ) )

		viewportGadget = self.ancestor( GafferUI.ViewportGadget )
		with GafferUI.ViewportGadget.RasterScope( viewportGadget ) :

			# Excuse the ancient GL code. You could ignore `style` and `RasterScope`
			# and write your own modern GL code here if you prefer.

			GL.glPushAttrib( GL.GL_CURRENT_BIT | GL.GL_LINE_BIT | GL.GL_ENABLE_BIT );
			GL.glEnable( GL.GL_LINE_SMOOTH )
			GL.glColor4f( 1, 1, 1, 1 )
			GL.glLineWidth( 5 )
			style.renderRectangle( resolutionGate )
			
			GL.glPopAttrib()

	def layerMask( self ) :

		return self.Layer.Front

	def renderBound( self ) :

			b = imath.Box3f()
			b.makeInfinite()
			return b

class TestTool( GafferUI.Tool ) :

	def __init__( self, view, name = "TestTool" ) :

		GafferUI.Tool.__init__( self, view, name )
		
		self.__guideGadget = GuideGadget( self )
		view.viewportGadget().addChild( self.__guideGadget )

IECore.registerRunTimeTyped( TestTool, typeName = "GafferUITest::TestTool" )
GafferUI.Tool.registerTool( "TestTool", GafferSceneUI.SceneView, TestTool )

@BrianHanke
Copy link
Contributor Author

Cool! That works great and it's very clear what everything does. I'm surprised how similar it is to the C++ syntax. I'm off to the races now, will report back when I get more features added.

@BrianHanke
Copy link
Contributor Author

Things are happening!

success

@BrianHanke
Copy link
Contributor Author

BrianHanke commented Sep 4, 2024

@johnhaddon Ok, getting close! All the math is done for action safe, title safe and rule of thirds rectangles. Working well.

I'd like to put the guide options in the Camera menu, if possible. I added dummy entries, but I don't know how to link them to the gadget(s). Do you have some sample code for that? Thanks a lot!

mockup

@johnhaddon
Copy link
Member

Nice!

Did you add your menu items by editing python/GafferSceneUI/SceneViewUI.py? The problem here is that menu is specifically for exposing native functionality implemented in C++. So the most natural way of implementing it all would be to move your Python drawing code to CameraOverlay in src/GafferSceneUI/SceneView.cpp. We could add an extension point to allow you to put stuff in that menu non-intrusively, but I don't think it would be all that natural.

I originally suggested the Python-based Tool approach as a way of avoiding C++ and making a non-intrusive extension that could be loaded as a plugin. With that approach I think the best we can do is add the guides as a menu in a toolbar at the bottom of the screen, active when the tool is activated from the toolbar.

I do agree though that from a UX perspective, putting this in the main camera menu is best. So I think maybe the question is : how would you feel about learning a little bit of C++?

@BrianHanke
Copy link
Contributor Author

Yep, I was messing around in SceneViewUI,py. I was trying to copy how the grid toggle works. I was confused since it looks like the menu was populated and then magic, but I understand why now.

I'm definitely game for C++. I have some experience with it already and SceneView.cpp looks like my kind of C++, i.e. not many pointers! Should be straightforward to port the rectangle math. Let me know what my next steps should be.

As far as general features for this, I was thinking:

  1. Action safe, title safe, rule of thirds guides (done). Are there other popular guide formats that people use?
  2. Toggle for each guide in the Camera menu.
  3. Maybe a Settings menu to choose line thickness and color. But that would lead to behavior where if the rule of thirds guide was a different color/thickness than the existing resolution gate it would hide the latter since it goes on top.
  4. It would also be cool to have the area outside the resolution gate darkened. Not sure how OpenGL would handle that, you'd need like a dark colored rectangle with some transparency, and then the center of it covering the resolution gate would have to be totally transparent. Not a top priority, just an idea I had.

@BrianHanke
Copy link
Contributor Author

Oh man, I figured out how to dim the area outside the resolution gate. This is probably the jankiest Python code in history, but it works. Will need some cleaning up!

dimmed

@johnhaddon
Copy link
Member

Action safe, title safe, rule of thirds guides (done). Are there other popular guide formats that people use?

I don't know of others, but then I'm pretty ignorant in this area - feels likely that someone might want something additional though? In Gaffer we'd usually support that by providing an API something like SceneView.registerGuide( name, parameters, of, the guide ). I think that's probably further than we should go at this point, but I would suggest an implementation that could be extended in that direction in future. So :

  • CameraOverlay could have a static map with the definitions of the guides, where the definition gives us everything we need to draw it.
  • SceneView could have a StringVectorDataPlug whose value was the names of the guides that are currently visible.
  • The camera menu could set that plug.

Later, it would be straightforward to add a public API for registering additional guide definitions in the static map. Does that make sense? If I'm not describing things clearly or in enough detail then just ask...

Maybe a Settings menu to choose line thickness and color. But that would lead to behavior where if the rule of thirds guide was a different color/thickness than the existing resolution gate it would hide the latter since it goes on top.

We tend not to provide too much user-facing configurability of this sort, partly because we want to keep Gaffer as simple as we can, and partly because we think it can often be a crutch used to avoid just making the defaults work well in the first place.

@BrianHanke
Copy link
Contributor Author

I think that makes sense! I looked around a bit more and those three seem to be the main guides in video editing apps. I agree about the line thickness/color customization, I already talked myself out of it.

I guess my main question now is how best to create a build environment on Windows where I can start messing around with C++, assuming that's the best way to go. Once I get set up I'm sure I'll have some questions about how to structure the new code and where to put it.

Usually the easiest thing for me is to find stuff that mostly already does what I want and repurpose it, so hopefully I can use things like the existing resolution gate code and, for example, the grid toggle in the scene menu. The math for all the features seems to be working fine in Python, so porting that over will be the easy part.

@johnhaddon
Copy link
Member

I guess my main question now is how best to create a build environment on Windows where I can start messing around with C++

We're just starting to transition to MSVC 2022 for Gaffer 1.5, so I'm not sure if it's best for you to jump straight to that, or to set up with the existing MSVC and dependencies. @ericmehl, any thoughts?

@ericmehl
Copy link
Collaborator

I'd say go with 2019 for now since that will definitely work with current releases. When we get 2022 support rolled out, it should be very close to a drop-in replacement.

@ericmehl
Copy link
Collaborator

I like to use VS Code and it's built-in terminal for doing builds. You may be tempted to launch it with gaffer env code to get all the Gaffer paths setup and you'd be able to launch Gaffer from the terminal with just gaffer. But! Windows won't let you overwrite DLL files that are in use, so you wouldn't be able to build certain modules.

It's kind of annoying, but instead I duplicate the gaffer.cmd file to a new location and modify these lines

gaffer/bin/gaffer.cmd

Lines 161 to 165 in bc2ff07

if "%GAFFER_DEBUG%" NEQ "" (
%GAFFER_DEBUGGER% "%GAFFER_ROOT%"\bin\python.exe "%GAFFER_ROOT%"/bin/__gaffer.py %*
) else (
"%GAFFER_ROOT%"\bin\python.exe "%GAFFER_ROOT%"/bin/__gaffer.py %*
)
I replace those lines with just code and it will launch VS Code. Then you'll have the environment set up and the DLL files won't be locked.

I also add a few lines to that batch script :

  • call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" This allows you to launch from any command line. Otherwise you need to make sure you're launching from the "Developer Command Prompt for x64" shortcut that Visual Studio creates for you.
  • set PYTHONUTF8=1 Gaffer's build needs this helper line.
  • set GAFFER_CACHE_DIR=..\cache
  • set GAFFER_BUILD_DIR=..\build
  • set GAFFER_BUILD_NAME=GafferDev
  • set PACKAGE_EXTENSION=zip
  • set GAFFER_SPHINX=DummyPath
  • set DELIGHT=DummyPath

These can go anywhere before the code line I talk about above. You can use other directories for lines starting at GAFFER_CACHE_DIR if you want.

I also replace

gaffer/bin/gaffer.cmd

Lines 5 to 6 in bc2ff07

set GAFFER_ROOT=%~dp0%..
set "GAFFER_ROOT=%GAFFER_ROOT:\=/%"

with set GAFFER_ROOT=YourGafferBuildDirectory. That way you can have the duplicated script above in a different directory from your Gaffer build directory to keep things separated.

Finally, launch VS Code from the duplicated launch script. To make a build, from the VS Code terminal, go to the Gaffer source code directory and run

scons -j $THREADS build BUILD_TYPE=$BUILD_TYPE OPTIONS=.github\workflows\main\sconsOptions`

Replace $THREADS with your CPU core count and $BUILD_TYPE with either Release or RelWithDebInfo. The former will create a build of Gaffer that runs faster because it has all the optimizations, but you won't be able to do step-by-step debugging. The second will allow that debugging but at the cost of some speed of Gaffer.

Let me know if I can clarify any of that or if you're having trouble getting it started. It's been a while since I first set this up so I may have overlooked something.

@BrianHanke
Copy link
Contributor Author

Thanks so much for the detailed info @ericmehl! I also usually use VS Code and its terminal. I'll start chipping away at this soon. Bear with me as I'm sure I'll have more questions!

@BrianHanke
Copy link
Contributor Author

Ok, I've made a fair bit of progress and I have a few questions @ericmehl:

  1. Does it matter where the Gaffer Dependencies go? I have them in C:\Source\gaffer-build and the main Gaffer source in C:\Source\gaffer.

  2. I downloaded Gaffer Dependencies 8.0.1 since that's the most recent one with a Windows version. Is that ok?

  3. I made all the gaffer.cmd changes you suggested and I think I have it right. I opened C:\Source\gaffer in VS Code and created a workspace. I configured the include folders and all includes seem to be found. However, I'm getting this error (SceneView.cpp, but similar ones come up elsewhere):

expected an identifier C/C++ (40) [Ln 1183, Col 12]
cannot define dllimport entity C/C++ (1391) [Ln 1934, Col 1]

Any idea how to fix that?

  1. What do you do to configure Python correctly? I've got 3.11 in my main PATH, but if I set a custom PATH in gaffer.cmd with no Python then it finds the Gaffer Python but it can't find scons and pip isn't available to install it.

Hopefully that all made sense. Thanks!

@ericmehl
Copy link
Collaborator

  1. Does it matter where the Gaffer Dependencies go? I have them in C:\Source\gaffer-build and the main Gaffer source in C:\Source\gaffer.

That should work fine, and it's good that they are not in the same directory as your Gaffer source. So in your case you'd set set GAFFER_BUILD_DIR=C:\Source\gaffer

2. I downloaded Gaffer Dependencies 8.0.1 since that's the most recent one with a Windows version. Is that ok?

Yes, that's the best dependencies to use. The 9.0 release will be the one John mentioned will be built using MSVC 2022. I'm wrestling those into submission as we speak.

3. I'm getting this error (SceneView.cpp, but similar ones come up elsewhere):

I think the first error may be fixed by telling VS Code where to find header files. Try adding this to the "settings" entry in your workspace file.

"C_Cpp.default.includePath": [
    "${workspaceFolder}/include",
    "${env:GAFFER_ROOT}/include",
    "${env:GAFFER_ROOT}/include/Imath",
    "${env:DELIGHT}/include"
],

And the second error should be fixed by adding something like

"C_Cpp.default.defines": [
    "Gaffer_EXPORTS",
    "GafferImage_EXPORTS",
    "GafferScene_EXPORTS",
    "GafferUI_EXPORTS",
    "GafferSceneUI_EXPORTS",
    "NOMINMAX",
    "MD",
    "_MT"
],

in the "settings" block of your code workspace file. That will define some global macros that the Scons build script normally defines when it does a build. That way the intellisense in VS Code will get the same values.

4. What do you do to configure Python correctly?

There are a couple of options for this :

  1. Keep your non-Gaffer Python on PATH and use it to kick off Scons, so you can install Scons on it with pip.
  2. Install Scons into Gaffer's Python using python -m pip install Scons. The -m pip means "run the pip module" so you don't need a dedicated pip command.

Option #2 will pollute Gaffer's Python installation somewhat, so I think ideally you'd go with option 1. But I'm not sure there's really anything wrong with option 2.

@BrianHanke
Copy link
Contributor Author

Great thanks, making progress. Got scons running, installed Inkscape, but it can't find Qt: "Checking for Qt...no." Do I need to install it separately? If so, any particular version?

@ericmehl
Copy link
Collaborator

That might be a slightly misleading error message. It's actually trying to build a super-simple program linking to Qt to see if it succeeds. So it may be not finding Qt, or that quick build may be failing.

It will output more information to a file in the source code directory called config.log. If that file exists, can you paste it here?

@BrianHanke
Copy link
Contributor Author

file C:\Source\gaffer\SConstruct,line 714:
Configure(confdir = .sconf_temp)
scons: Configure: Checking for Inkscape...
scons: Configure: (cached) yes

scons: Configure: Checking for Sphinx...
scons: Configure: (cached) no

scons: Configure: Checking for Qt...
.sconf_temp\conftest_731c39a501e4419ece6181da209afcc8_0.cpp <-
|
| #include
| #include "QtCore/qconfig.h"
|
| int main()
| {
|#ifdef QT_VERSION_MAJOR
| std::cout << QT_VERSION_MAJOR;
|#else
| std::cout << 4;
|#endif
| return 0;
| }
|
cl /Fo.sconf_temp\conftest_731c39a501e4419ece6181da209afcc8_0.obj /c .sconf_temp\conftest_731c39a501e4419ece6181da209afcc8_0.cpp /DBOOST_FILESYSTEM_VERSION=3 /DBOOST_FILESYSTEM_NO_DEPRECATED /Iinclude /nologo /external:I C:\Source\build/include /external:I C:\Source\build/include/Imath /external:I C:\Source\build/include/GL /nologo /DOPENEXR_DLL /DIMATH_DLL /DNOMINMAX /D__PRETTY_FUNCTION__=FUNCSIG /DBOOST_ALL_DYN_LINK /DBOOST_ALL_NO_LIB /W4 /experimental:external /external:W0 /Zc:inline /GR /TP /FC /EHsc /MP /permissive- /D_USE_MATH_DEFINES /std:c++17 /DHAVE_SNPRINTF /WX /wd4251 /wd4100 /wd4706 /wd4267 /wd4244 /wd4305 /D_CRT_SECURE_NO_WARNINGS /wd4127 /wd4456 /wd4459 /wd4201 /wd4275 /wd4324 /wd4458 /wd4003 /wd4702 /wd4180 /DNDEBUG /MD /DBOOST_DISABLE_ASSERTS /O2 /wd4702
conftest_731c39a501e4419ece6181da209afcc8_0.cpp
C:\Source\gaffer.sconf_temp\conftest_731c39a501e4419ece6181da209afcc8_0.cpp(3): fatal error C1083: Cannot open include file: 'QtCore/qconfig.h': No such file or directory
scons: Configure: no

@ericmehl
Copy link
Collaborator

Gah, I mis-typed when I told you to set the GAFFER_BUILD_DIR above. It should be set to the directory you extracted the dependencies to, so for you set GAFFER_BUILD_DIR=C:\Source\gaffer-build. Try that and see if it fixes it.

@BrianHanke
Copy link
Contributor Author

Success, it's building now! 👀

@BrianHanke
Copy link
Contributor Author

Oops, failed on 3Delight: Cannot open include file: 'nsi.h': No such file or directory, etc. Can I just turn off 3DL or do I need to update another envar?

@ericmehl
Copy link
Collaborator

In the startup script you made, try set DELIGHT="" instead of set DELIGHT=DummyPath. It needs to be set to something non-null, but I think setting it to an empty string will do the job of disabling that module.

@BrianHanke
Copy link
Contributor Author

Hmm, it didn't like that either. DELIGHT= and DELIGHT='' also failed. I just installed 3Delight again, back in business!

@BrianHanke
Copy link
Contributor Author

Getting close! The build finished without any obvious errors. I find gaffer.cmd now in C:\Source\gaffer-build\bin. Double-clicking on it launches the Gaffer UI... sort of. The console is full of errors like:

ERROR : IECore.loadConfig : Error executing file "C:\Source\gaffer-build\startup\gui\editor.py" - "cannot import name 'AnaglyphUI' from partially initialized module 'GafferImageUI' (most likely due to a circular import) (C:\Source\gaffer-build\python\GafferImageUI\__init__.py)".

gaffer

@BrianHanke
Copy link
Contributor Author

I noticed the title bar said 1.5 so I tried again with 1.4, same problem. My build is missing some files compared to the official release. For example, AnaglyphUI.py is missing.

My workflow so far is:

  1. Extract gafferDependencies-8.0.1-windows to C:\Source\gaffer-build.
  2. Clone Gaffer to C:\Source\gaffer with git clone https://github.com/GafferHQ/gaffer.git.
  3. I put a copy of gaffer.cmd into the top level of C:\Source\gaffer with the following changes:

set GAFFER_ROOT=C:\Source\gaffer-build

and

call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
set PYTHONUTF8=1
set GAFFER_CACHE_DIR=..\cache
set GAFFER_BUILD_DIR=C:\Source\gaffer-build
set GAFFER_BUILD_NAME=GafferDev
set PACKAGE_EXTENSION=zip
set GAFFER_SPHINX=DummyPath
set DELIGHT=C:\Program Files\3Delight

code
  1. I run that gaffer.cmd, which opens VS Code.
  2. I run scons -j 8 build BUILD_TYPE=RELEASE OPTIONS=.github\workflows\main\sconsOptions in the VS Code terminal. It goes through the build process with no errors.

And that's where we're at now. Any ideas where I'm going wrong? Thanks!

@ericmehl
Copy link
Collaborator

It sounds like the step buildExtensions is not running, or not working. It should run as part of the build target you're building everything else from.

Try running scons -j 8 buildExtensions BUILD_TYPE=RELEASE OPTIONS=.github\workflows\main\sconsOptions (without clearing anything out first, just on top of what you've already built) and see what the result is.

There are some nodes that are actually just wrappers around an internal node network, and Anaglyph is one of those. They are converted from .gfr files using Gaffer.ExtensionAlgo.exportNode() and Gaffer.ExtensionAlgo.exportNodeUI() in the SConstruct script.

But as I mentioned, this should all be happening as part of build so there's something not quite right going on.

@ericmehl
Copy link
Collaborator

When you copied the gaffer.cmd file to modify it for launching VS Code, did you keep the name as gaffer.cmd? If so, try changing it to gaffer-code.cmd or similar. The process exporting the extensions launches Gaffer itself to do that, so it may be launching your VS Code launcher instead of the real gaffer.cmd.

@BrianHanke
Copy link
Contributor Author

Success! I renamed gaffer.cmd and everything works perfectly now. Thanks for getting me up and running, this was the easiest build environment setup I've ever experienced.

@ericmehl
Copy link
Collaborator

Awesome! I'm happy it's working for you now. Onwards to the fun stuff!

@BrianHanke
Copy link
Contributor Author

Thanks! Speaking of fun stuff, hi @johnhaddon. 🙂 Before getting started I wanted to check in about which source files I should look to for adapting to this project. I'm thinking all I need is SceneView.cpp for the resolution gate and whichever Python file populates the camera menu. I was thinking of looking at the grid toggle for a model how to create a toggle for each viewer guide. Let me know if that sounds like a good starting place and anything else I might need to know. Thanks again!

@johnhaddon
Copy link
Member

johnhaddon commented Sep 12, 2024

Yes, I think all your work will be in SceneView.cpp and SceneViewUI.py. I think something like this :

  • Modify CameraOverlay in SceneView.cpp, so it can draw the additional guides, and has a method for setting which guides to draw. This bit is equivalent to the gadget you made in Python.
  • Modify SceneView::Camera in SceneView.cpp to add a StringVectorDataPlug to specify the guides which should be visible, and when the plug is set, tell the CameraOverlay what should be visible. This bit is equivalent to the tool you made in Python.
  • Modify _CameraPlugValueWidget.__menuDefinition in SceneViewUI.py to add menu items for showing the guides by editing the plug value. In the same file you'll find menu items for managing USD purpose - these are managing a list of strings as well, so might be a good model for managing the list of visible guides.

@BrianHanke
Copy link
Contributor Author

@ericmehl Making good progress over here! I just turned my attention to SceneViewUI.py though and I'm having build problems. I added some stuff that I had a feeling wasn't going to work, built the project, then the viewer refused to load in my test scene. I undid the changes, built again, same problem. I can't get back to the state things were in before even though all the source code has been reverted. The error messages are below. Any idea what I did wrong and how to fix it? Thanks!

ERROR : EventLoop.__qtIdleCallback : Traceback (most recent call last):
ERROR :   File "C:\Source\gaffer-build\python\GafferUI\EventLoop.py", line 285, in __qtIdleCallback
ERROR :     if not c() :
ERROR :   File "C:\Source\gaffer-build\python\GafferUI\LazyMethod.py", line 163, in __idle  
ERROR :     cls.__doPendingCalls( widget, method )
ERROR :   File "C:\Source\gaffer-build\python\GafferUI\LazyMethod.py", line 176, in __doPendingCalls
ERROR :     method( widget, *pendingCall.args, **pendingCall.kw )
ERROR :   File "C:\Source\gaffer-build\python\GafferUI\NodeSetEditor.py", line 282, in __lazyUpdate
ERROR :     self._updateFromSet()
ERROR :   File "C:\Source\gaffer-build\python\GafferUI\Viewer.py", line 187, in _updateFromSet
ERROR :     self.__currentView = GafferUI.View.create( plug )
ERROR :   File "C:\Source\gaffer-build\startup\gui\viewer.py", line 64, in __sceneView      
ERROR :     view = GafferSceneUI.SceneView()
ERROR :   File "C:\Source\gaffer-build\startup\gui\viewer.py", line 195, in __loadRendererSettings
ERROR :     script.load()
ERROR : IECore.Exception: Line 285 of C:\Source\gaffer-build\startup\gui\cyclesViewerSettings.gfr : AttributeError: '__ParametersPlugProxy' object has no attribute 'parent'
ERROR :

@BrianHanke
Copy link
Contributor Author

Never mind. For some reason launching Gaffer from the VS Code terminal causes this error, but not so outside of VS Code. No clue why this suddenly started happening, but we're back in business for now.

@BrianHanke
Copy link
Contributor Author

Good morning @johnhaddon: it's working!

I have a separate set of variables and functions for each guide, so it's not very streamlined. I wanted to get it working and then turn my attention to refining the code. I don't know how best to combine everything into one function. I was thinking it needs something that includes the names of each guide and then a related boolean on or off for each. The C++ could loop through each name and check its state and the Python could populate the menu by iterating over each name and checking or setting its state.

You mentioned a StringVectorDataPlug, but I'm not sure how that would work. Let me know if this makes any sense at all. Maybe I should open a PR so you can see what I've done so far?

guides.mp4

@johnhaddon
Copy link
Member

it's working!

Nice one!

I don't know how best to combine everything into one function.

It may be that I was too optimistic in thinking it could be consolidated into one. But let me sketch out one approach. You could have a static "registry" mapping from the names of guides to their definitions :

static unordered_map<string, GuideDefinition> g_guideDefinitions = {
   { "Action Safe" : ... },
   ...
};

Then on the View you could add a StringVectorDataPlug which contains the names of the guides that should be rendered. The UI would just add and remove names from this list. Then the rendering would look something like this :

ConstStringVectorData visibleGuides = guidePlug()->getValue();
for( const auto &name : visibleGuides->readable() )
{
     auto it = g_guideDefinitions.find( name );
     if( it != g_guideDefinitions.end() )
     {
           renderGuide( it->second );
     }
}

The main thing I like about this is that later on we could easily expose a public function for people to add their own definitions into the registry. But the big question I've left unanswered here is "what does GuideDefinition contain?". It may be that it's not easy to define it flexibly enough to do everything we want without making such a mess that we'd have been better with individual functions in the first place. But perhaps it could just contain a list of lines to draw, specified in a normalised0-1 space across the resolution gate?

Maybe I should open a PR so you can see what I've done so far?

That would be great, or if you'd like to avoid the public gaze for a bit, you could just send me the URL for your branch on GitHub and we can discuss there.

@BrianHanke
Copy link
Contributor Author

I think I understand how that would work, makes sense in terms of making things amenable to future expansion. I sent you an invite for my mini repo. It's just the two source code files and some stuff to help me get up and running quickly with the build environment. Looking forward to your thoughts! I marked all my additions with BHGC and made some notes about what I'm not sure about.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants