diff --git a/Changes.md b/Changes.md
index 45a969a1aa..4f71d9bec5 100644
--- a/Changes.md
+++ b/Changes.md
@@ -11,6 +11,11 @@ Improvements
- 3Delight : Added light muting support.
- Arnold : Added support for specifying the name of a shader in the node menu using Arnold's `ui.name` metadata. This improves the formatting of the OpenPBR Surface menu item.
+- VisualiserTool : Added new visualisation for vector (V3f) data.
+ - The `vectorScale` plug can be used to scale the vector line. The Shift + + and Shift + - keyboard shortcuts can also be used to change the scale.
+ - The `vectorColor` plug can be used to change the color of the vector line.
+ - The vector value being visualised for the vertex nearest the cursor is shown next to the vertex.
+- ColorSwatchPlugValueWidget : Changed the display transform of the color chooser dialogue to match that of the `ColorSwatchPlugValueWidget` creating it instead of the script window.
Fixes
-----
diff --git a/include/GafferSceneUI/Private/VisualiserTool.h b/include/GafferSceneUI/Private/VisualiserTool.h
index 4e35dc60a1..e5a8c556df 100644
--- a/include/GafferSceneUI/Private/VisualiserTool.h
+++ b/include/GafferSceneUI/Private/VisualiserTool.h
@@ -99,6 +99,12 @@ class GAFFERSCENEUI_API VisualiserTool : public SelectionTool
Gaffer::FloatPlug *sizePlug();
const Gaffer::FloatPlug *sizePlug() const;
+ Gaffer::FloatPlug *vectorScalePlug();
+ const Gaffer::FloatPlug *vectorScalePlug() const;
+
+ Gaffer::Color3fPlug *vectorColorPlug();
+ const Gaffer::Color3fPlug *vectorColorPlug() const;
+
private:
friend VisualiserGadget;
@@ -108,17 +114,20 @@ class GAFFERSCENEUI_API VisualiserTool : public SelectionTool
{
Selection(
const GafferScene::ScenePlug &scene,
+ const GafferScene::ScenePlug &uniformPScene,
const GafferScene::ScenePlug::ScenePath &path,
const Gaffer::Context &context
);
const GafferScene::ScenePlug &scene() const;
+ const GafferScene::ScenePlug &uniformPScene() const;
const GafferScene::ScenePlug::ScenePath &path() const;
const Gaffer::Context &context() const;
private:
GafferScene::ConstScenePlugPtr m_scene;
+ GafferScene::ConstScenePlugPtr m_uniformPScene;
GafferScene::ScenePlug::ScenePath m_path;
Gaffer::ConstContextPtr m_context;
};
@@ -134,6 +143,9 @@ class GAFFERSCENEUI_API VisualiserTool : public SelectionTool
GafferScene::ScenePlug *internalScenePlug();
const GafferScene::ScenePlug *internalScenePlug() const;
+ GafferScene::ScenePlug *internalSceneUniformPPlug();
+ const GafferScene::ScenePlug *internalSceneUniformPPlug() const;
+
void connectOnActive();
void disconnectOnInactive();
bool mouseMove( const GafferUI::ButtonEvent &event );
diff --git a/python/GafferSceneUI/VisualiserToolUI.py b/python/GafferSceneUI/VisualiserToolUI.py
index ffacb852b9..08ebe7111f 100644
--- a/python/GafferSceneUI/VisualiserToolUI.py
+++ b/python/GafferSceneUI/VisualiserToolUI.py
@@ -60,6 +60,7 @@
"tool:exclusive", False,
"toolbarLayout:activator:modeIsColor", lambda node : node["mode"].getValue() == GafferSceneUI.VisualiserTool.Mode.Color,
+ "toolbarLayout:activator:modeIsAuto", lambda node : node["mode"].getValue() == GafferSceneUI.VisualiserTool.Mode.Auto,
plugs = {
@@ -90,7 +91,7 @@
""",
"toolbarLayout:section", "Bottom",
- "toolbarLayout:width", 100,
+ "toolbarLayout:width", 45,
],
"mode" : [
@@ -158,10 +159,48 @@
"plugValueWidget:type", ""
],
+ "vectorScale" : [
+
+ "description",
+ """
+ The scale factor to apply to vectors.
+ """,
+
+ "toolbarLayout:section", "Bottom",
+ "toolbarLayout:width", 45,
+
+ "toolbarLayout:visibilityActivator", "modeIsAuto",
+
+ ],
+
+ "vectorColor" : [
+
+ "description",
+ """
+ The colour to use for drawing vectors.
+ """,
+
+ "toolbarLayout:section", "Bottom",
+ "toolbarLayout:width", 175,
+
+ "toolbarLayout:visibilityActivator", "modeIsAuto",
+ "colorPlugValueWidget:colorChooserButtonVisible", False,
+
+ "plugValueWidget:type", "GafferSceneUI.VisualiserToolUI._UntransformedColorWidget",
+
+ ],
},
)
+class _UntransformedColorWidget( GafferUI.ColorPlugValueWidget ) :
+
+ def __init__( self, plugs, **kw ) :
+
+ GafferUI.ColorPlugValueWidget.__init__( self, plugs, **kw )
+
+ self.setDisplayTransform( GafferUI.Widget.identityDisplayTransform )
+
class _DataNameChooser( GafferUI.PlugValueWidget ) :
__primitiveVariablePrefix = "primitiveVariable:"
diff --git a/python/GafferUI/ColorPlugValueWidget.py b/python/GafferUI/ColorPlugValueWidget.py
index 819e4f626c..6388c25717 100644
--- a/python/GafferUI/ColorPlugValueWidget.py
+++ b/python/GafferUI/ColorPlugValueWidget.py
@@ -70,7 +70,7 @@ def __init__( self, plugs, **kw ) :
sole( Gaffer.Metadata.value( plug, "colorPlugValueWidget:colorChooserVisible" ) for plug in self.getPlugs() )
)
- self.__chooserButton.setVisible( not any( p.direction() == Gaffer.Plug.Direction.Out for p in self.getPlugs() ) )
+ self.__chooserButton.setVisible( self.__chooserButtonVisible() )
self.__blinkBehaviour = None
@@ -122,7 +122,7 @@ def setPlugs( self, plugs ) :
self.__swatch.setPlugs( plugs )
# Update widget visibility if the plug directions changed
- self.__chooserButton.setVisible( not any( p.direction() == Gaffer.Plug.Direction.Out for p in self.getPlugs() ) )
+ self.__chooserButton.setVisible( self.__chooserButtonVisible() )
self.setColorChooserVisible( self.__colorChooserVisible )
def setHighlighted( self, highlighted ) :
@@ -163,6 +163,13 @@ def __chooserButtonClicked( self, widget ) :
for plug in self.getPlugs() :
Gaffer.Metadata.registerValue( plug, "colorPlugValueWidget:colorChooserVisible", visible, persistent = False )
+ def __chooserButtonVisible( self ) :
+
+ return (
+ not any( p.direction() == Gaffer.Plug.Direction.Out for p in self.getPlugs() ) and
+ not any( Gaffer.Metadata.value( p, "colorPlugValueWidget:colorChooserButtonVisible" ) == False for p in self.getPlugs() )
+ )
+
GafferUI.PlugValueWidget.registerType( Gaffer.Color3fPlug, ColorPlugValueWidget )
GafferUI.PlugValueWidget.registerType( Gaffer.Color4fPlug, ColorPlugValueWidget )
diff --git a/python/GafferUI/ColorSwatchPlugValueWidget.py b/python/GafferUI/ColorSwatchPlugValueWidget.py
index 35b7b6f29d..dcd76a3fb4 100644
--- a/python/GafferUI/ColorSwatchPlugValueWidget.py
+++ b/python/GafferUI/ColorSwatchPlugValueWidget.py
@@ -101,7 +101,7 @@ def __buttonRelease( self, widget, event ) :
if not self._editable() :
return False
- _ColorPlugValueDialogue.acquire( self.getPlugs() )
+ _ColorPlugValueDialogue.acquire( self.getPlugs(), self.displayTransform() )
return True
@@ -125,11 +125,12 @@ def _colorFromPlugs( plugs ) :
# actually be functionality of CompoundEditor?
class _ColorPlugValueDialogue( GafferUI.ColorChooserDialogue ) :
- def __init__( self, plugs, parentWindow ) :
+ def __init__( self, plugs, parentWindow, displayTransform ) :
GafferUI.ColorChooserDialogue.__init__(
self,
- color = _colorFromPlugs( plugs )
+ color = _colorFromPlugs( plugs ),
+ displayTransform = displayTransform
)
# we use these to decide which actions to merge into a single undo
@@ -192,7 +193,7 @@ def __init__( self, plugs, parentWindow ) :
parentWindow.addChildWindow( self, removeOnClose = True )
@classmethod
- def acquire( cls, plugs ) :
+ def acquire( cls, plugs, displayTransform ) :
plug = next( iter( plugs ) )
@@ -212,7 +213,7 @@ def acquire( cls, plugs ) :
window.setVisible( True )
return window
- window = _ColorPlugValueDialogue( plugs, scriptWindow )
+ window = _ColorPlugValueDialogue( plugs, scriptWindow, displayTransform )
window.setVisible( True )
return False
diff --git a/src/GafferSceneUI/VisualiserTool.cpp b/src/GafferSceneUI/VisualiserTool.cpp
index e0adcef7bc..1fef23b64e 100644
--- a/src/GafferSceneUI/VisualiserTool.cpp
+++ b/src/GafferSceneUI/VisualiserTool.cpp
@@ -39,6 +39,8 @@
#include "GafferSceneUI/SceneView.h"
#include "GafferSceneUI/ScriptNodeAlgo.h"
+#include "GafferScene/ResamplePrimitiveVariables.h"
+
#include "GafferUI/Gadget.h"
#include "GafferUI/Pointer.h"
#include "GafferUI/Style.h"
@@ -99,6 +101,13 @@ const float g_textSizeDefault = 9.0f;
const float g_textSizeMin = 6.0f;
const float g_textSizeInc = 0.5f;
+// Vector constants
+const float g_vectorScaleDefault = 1.f;
+const float g_vectorScaleMin = 10.f * std::numeric_limits< float >::min();
+float const g_vectorScaleInc = 0.01f;
+
+const Color3f g_vectorColorDefault( 1.f, 1.f, 1.f );
+
// Opacity and value constants
const float g_opacityDefault = 1.0f;
const float g_opacityMin = 0.0f;
@@ -286,6 +295,124 @@ std::string const g_vertexLabelShaderFragSource
"}\n"
);
+//-----------------------------------------------------------------------------
+// Vector shader
+//-----------------------------------------------------------------------------
+
+struct UniformBlockVectorShader
+{
+ alignas( 16 ) Imath::M44f o2v;
+ alignas( 16 ) Imath::M44f n2v;
+ alignas( 16 ) Imath::M44f v2c;
+ alignas( 16 ) Imath::M44f o2c;
+ alignas( 16 ) Imath::Color3f color;
+ alignas( 4 ) float opacity;
+ alignas( 4 ) float scale;
+};
+
+#define UNIFORM_BLOCK_VECTOR_GLSL_SOURCE \
+ "layout( std140, row_major ) uniform UniformBlock\n" \
+ "{\n" \
+ " mat4 o2v;\n" \
+ " mat4 n2v;\n" \
+ " mat4 v2c;\n" \
+ " mat4 o2c;\n" \
+ " vec3 color;\n" \
+ " float opacity;\n" \
+ " float scale;\n" \
+ "} uniforms;\n"
+
+#define ATTRIB_GLSL_LOCATION_VS 1
+
+#define ATTRIB_VECTOR_GLSL_SOURCE \
+ "layout( location = " BOOST_PP_STRINGIZE( ATTRIB_GLSL_LOCATION_PS ) " ) in vec3 ps;\n" \
+ "layout( location = " BOOST_PP_STRINGIZE( ATTRIB_GLSL_LOCATION_VS ) " ) in vec3 vs;\n"
+
+// Opengl vertex shader code (point format)
+
+const std::string g_vectorShaderVertSourcePoint
+(
+ "#version 330\n"
+
+ UNIFORM_BLOCK_VECTOR_GLSL_SOURCE
+
+ ATTRIB_VECTOR_GLSL_SOURCE
+
+ "void main()\n"
+ "{\n"
+ " vec3 position = ps;\n"
+
+ " if( gl_VertexID == 1 )\n"
+ " {\n"
+ " position = vs;\n"
+ " }\n"
+
+ " gl_Position = vec4( position, 1.0 ) * uniforms.o2c;\n"
+ "}\n"
+);
+
+// Opengl vertex shader code (vector format)
+
+const std::string g_vectorShaderVertSourceVector
+(
+ "#version 330\n"
+
+ UNIFORM_BLOCK_VECTOR_GLSL_SOURCE
+
+ ATTRIB_VECTOR_GLSL_SOURCE
+
+ "void main()\n"
+ "{\n"
+ " vec3 position = ps;\n"
+
+ " if( gl_VertexID == 1 )\n"
+ " {\n"
+ " position += vs * uniforms.scale;"
+ " }\n"
+
+ " gl_Position = vec4( position, 1.0 ) * uniforms.o2c;\n"
+ "}\n"
+);
+
+// Opengl vertex shader code (bivector format)
+
+const std::string g_vectorShaderVertSourceBivector
+(
+ "#version 330\n"
+
+ UNIFORM_BLOCK_VECTOR_GLSL_SOURCE
+
+ ATTRIB_VECTOR_GLSL_SOURCE
+
+ "void main()\n"
+ "{\n"
+ " vec4 position = vec4( ps, 1.0 ) * uniforms.o2v;\n"
+
+ " if( gl_VertexID == 1 )\n"
+ " {\n"
+ " position.xyz += normalize( vs * mat3( uniforms.n2v ) ) * ( uniforms.scale * length( vs ) );\n"
+ " }\n"
+
+ " gl_Position = position * uniforms.v2c;\n"
+ "}\n"
+);
+
+// Opengl fragment shader code
+
+std::string const g_vectorShaderFragSource
+(
+ "#version 330\n"
+
+ UNIFORM_BLOCK_VECTOR_GLSL_SOURCE
+
+ "layout( location = 0 ) out vec4 cs;\n"
+
+ "void main()\n"
+ "{\n"
+ " cs = vec4( uniforms.color, uniforms.opacity );\n"
+ "}\n"
+);
+
//-----------------------------------------------------------------------------
// Helper Methods
//-----------------------------------------------------------------------------
@@ -372,9 +499,6 @@ enum class VisualiserShaderType
VertexLabel
};
-std::array g_vertSources = { g_colorShaderVertSource, g_vertexLabelShaderVertSource };
-std::array g_fragSources = { g_colorShaderFragSource, g_vertexLabelShaderFragSource };
-
// The gadget that does the actual opengl drawing of the shaded primitive
class VisualiserGadget : public Gadget
{
@@ -423,6 +547,7 @@ class VisualiserGadget : public Gadget
if( layer == Gadget::Layer::MidFront )
{
renderColorVisualiser( viewportGadget, mode );
+ renderVectorVisualiser( viewportGadget, mode );
}
else if( layer == Gadget::Layer::Front )
@@ -662,9 +787,13 @@ class VisualiserGadget : public Gadget
ConstDataPtr vData = vIt->second.data;
- if( mode == VisualiserTool::Mode::Auto && vData->typeId() == IntVectorDataTypeId )
+ if(
+ mode == VisualiserTool::Mode::Auto && (
+ vData->typeId() == IntVectorDataTypeId || // Will be handled by `renderVertexLabelValue()` instead.
+ vData->typeId() == V3fVectorDataTypeId // Will be handled by `renderVectorVisualiser()` instead.
+ )
+ )
{
- // Will be handled by `renderVertexLabelValue()` instead.
continue;
}
@@ -837,7 +966,12 @@ class VisualiserGadget : public Gadget
const VisualiserTool::CursorValue value = m_tool->cursorValue();
- if( mode == VisualiserTool::Mode::Auto && std::holds_alternative( value ) )
+ if(
+ mode == VisualiserTool::Mode::Auto && (
+ std::holds_alternative( value ) ||
+ std::holds_alternative( value )
+ )
+ )
{
return;
}
@@ -976,6 +1110,8 @@ class VisualiserGadget : public Gadget
const std::string dataName = m_tool->dataNamePlug()->getValue();
const std::string primitiveVariableName = primitiveVariableFromDataName( dataName );
+ float cursorVertexValueTextScale = 2.f;
+
// Loop through current selection
for( const auto &location : m_tool->selection() )
@@ -1016,10 +1152,14 @@ class VisualiserGadget : public Gadget
if(
mode == VisualiserTool::Mode::Auto &&
primitive->typeId() == MeshPrimitive::staticTypeId() &&
- vData->typeId() != IntVectorDataTypeId
+ vData->typeId() != IntVectorDataTypeId &&
+ vData->typeId() != V3fVectorDataTypeId
)
{
// Will be handled by `renderColorVisualiser()` instead.
+ // If the data type is V3f data, we continue right before
+ // drawing the per-vertex label in order to get and display
+ // the value closest to the cursor.
continue;
}
@@ -1035,6 +1175,15 @@ class VisualiserGadget : public Gadget
}
}
+ if( mode == VisualiserTool::Mode::Auto && vData && vData->typeId() == V3fVectorDataTypeId )
+ {
+ cursorVertexValueTextScale = 1.f;
+ }
+ else
+ {
+ cursorVertexValueTextScale = 2.f;
+ }
+
// Find "P" vertex attribute
//
// TODO : We need to use the same polygon offset as the Viewer uses when it draws the
@@ -1293,6 +1442,13 @@ class VisualiserGadget : public Gadget
}
}
+ if( mode == VisualiserTool::Mode::Auto && vData && vData->typeId() == V3fVectorDataTypeId )
+ {
+ // Do everything except drawing the per-vertex value. That will
+ // be handled by `renderVectorVisualiser()` instead.
+ continue;
+ }
+
// Draw value label
if( !std::holds_alternative( vertexValue ) && rasterPos )
@@ -1336,9 +1492,9 @@ class VisualiserGadget : public Gadget
drawStrokedText(
viewportGadget,
text,
- scale.x * 2.f,
+ scale.x * cursorVertexValueTextScale,
V2f(
- cursorVertexRasterPos.value().x - style->textBound( GafferUI::Style::LabelText, text ).size().x * scale.x,
+ cursorVertexRasterPos.value().x - style->textBound( GafferUI::Style::LabelText, text ).size().x * 0.5f * cursorVertexValueTextScale * scale.x,
cursorVertexRasterPos.value().y
),
style,
@@ -1351,6 +1507,259 @@ class VisualiserGadget : public Gadget
m_cursorVertexValue = cursorVertexValue;
}
+ void renderVectorVisualiser( const ViewportGadget *viewportGadget, VisualiserTool::Mode mode ) const
+ {
+ const std::string name = primitiveVariableFromDataName( m_tool->dataNamePlug()->getValue() );
+ if( name.empty() || mode != VisualiserTool::Mode::Auto )
+ {
+ return;
+ }
+
+ buildShader( m_vectorShaderPoint, g_vectorShaderVertSourcePoint, g_vectorShaderFragSource );
+ buildShader( m_vectorShaderVector, g_vectorShaderVertSourceVector, g_vectorShaderFragSource );
+ buildShader( m_vectorShaderBivector, g_vectorShaderVertSourceBivector, g_vectorShaderFragSource );
+
+ if( !m_vectorShaderPoint || !m_vectorShaderVector || !m_vectorShaderBivector )
+ {
+ return;
+ }
+
+ // Get the cached converter from IECoreGL, this is used to convert primitive
+ // variable data to opengl buffers which will be shared with the IECoreGL renderer
+ IECoreGL::CachedConverter *converter = IECoreGL::CachedConverter::defaultCachedConverter();
+
+ GLint uniformBinding;
+ glGetIntegerv( GL_UNIFORM_BUFFER_BINDING, &uniformBinding );
+
+ if( !m_vectorUniformBuffer )
+ {
+ GLuint buffer = 0u;
+ glGenBuffers( 1, &buffer );
+ glBindBuffer( GL_UNIFORM_BUFFER, buffer );
+ glBufferData( GL_UNIFORM_BUFFER, sizeof( UniformBlockVectorShader ), 0, GL_DYNAMIC_DRAW );
+ m_vectorUniformBuffer.reset( new IECoreGL::Buffer( buffer ) );
+ }
+
+ glBindBufferBase( GL_UNIFORM_BUFFER, g_uniformBlockBindingIndex, m_vectorUniformBuffer->buffer() );
+
+ UniformBlockVectorShader uniforms;
+ uniforms.color = m_tool->vectorColorPlug()->getValue();
+ uniforms.opacity = m_tool->opacityPlug()->getValue();
+ uniforms.scale = m_tool->vectorScalePlug()->getValue();
+
+ // Get the world to view and view to clip space matrices
+ const M44f w2v = viewportGadget->getCameraTransform().gjInverse();
+ glGetFloatv( GL_PROJECTION_MATRIX, uniforms.v2c.getValue() );
+
+ // Set OpenGL state
+ GLfloat lineWidth;
+ glGetFloatv( GL_LINE_WIDTH, &lineWidth );
+ glLineWidth( 1.f );
+
+ const GLboolean depthEnabled = glIsEnabled( GL_DEPTH_TEST );
+ if( !depthEnabled )
+ {
+ glEnable( GL_DEPTH_TEST );
+ }
+
+ GLboolean depthWriteEnabled;
+ glGetBooleanv( GL_DEPTH_WRITEMASK, &depthWriteEnabled );
+ if( depthWriteEnabled )
+ {
+ glDepthMask( GL_FALSE );
+ }
+
+ GLboolean lineSmooth;
+ glGetBooleanv( GL_LINE_SMOOTH, &lineSmooth );
+ if( lineSmooth )
+ {
+ glDisable( GL_LINE_SMOOTH );
+ }
+
+ const GLboolean blendEnabled = glIsEnabled( GL_BLEND );
+ if( !blendEnabled )
+ {
+ glEnable( GL_BLEND );
+ }
+
+ // Store current shader program to be restored after drawing.
+ // We set the shader program for drawing vectors when we know
+ // the interpretation of the visualised data, which may
+ // be different per object.
+ GLint shaderProgram;
+ glGetIntegerv( GL_CURRENT_PROGRAM, &shaderProgram );
+ std::optional currentShaderProgram;
+
+ // Set OpenGL vertex attribute array state
+ GLint arrayBinding;
+ glGetIntegerv( GL_ARRAY_BUFFER_BINDING, &arrayBinding );
+
+ glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
+
+ glVertexAttribDivisor( ATTRIB_GLSL_LOCATION_PS, 1 );
+ glEnableVertexAttribArray( ATTRIB_GLSL_LOCATION_PS );
+ glVertexAttribDivisor( ATTRIB_GLSL_LOCATION_VS, 1 );
+ glEnableVertexAttribArray( ATTRIB_GLSL_LOCATION_VS );
+
+ // Loop through the current selection
+ for( const auto &location : m_tool->selection() )
+ {
+ ScenePlug::PathScope scope( &location.context(), &location.path() );
+
+ // Check path exists
+ if( !location.scene().existsPlug()->getValue() )
+ {
+ continue;
+ }
+
+ // Extract primitive
+ auto primitive = runTimeCast( location.scene().objectPlug()->getValue() );
+ if( !primitive )
+ {
+ continue;
+ }
+
+ // Find named vertex attribute
+ // NOTE : Conversion to IECoreGL mesh may generate vertex attributes (eg. "N")
+ // so check named primitive variable exists on IECore mesh primitive.
+ const auto vIt = primitive->variables.find( name );
+ if( vIt == primitive->variables.end() )
+ {
+ continue;
+ }
+
+ auto vData = runTimeCast( vIt->second.data );
+ if( !vData )
+ {
+ // Will be handled by `renderColorVisualiser()` or `renderVertexLabelValue()` instead.
+ continue;
+ }
+
+ if( vIt->second.interpolation == PrimitiveVariable::Uniform )
+ {
+ primitive = runTimeCast( location.uniformPScene().objectPlug()->getValue() );
+
+ if( !primitive )
+ {
+ continue;
+ }
+ }
+
+ // Make sure we have "P" data and it is the correct type.
+ const auto pIt = primitive->variables.find( g_pName );
+ if( pIt == primitive->variables.end() )
+ {
+ continue;
+ }
+
+ auto pData = runTimeCast( pIt->second.data );
+ if( !pData )
+ {
+ continue;
+ }
+
+ IECoreGL::ConstBufferPtr pBuffer = nullptr;
+ IECoreGL::ConstBufferPtr vBuffer = nullptr;
+ GLsizei vertexCount = 0;
+
+ // Retrieve cached IECoreGL primitive
+
+ if( vIt->second.interpolation != PrimitiveVariable::FaceVarying )
+ {
+ pBuffer = runTimeCast( converter->convert( pData.get() ) );
+ vBuffer = runTimeCast( converter->convert( vData.get() ) );
+ vertexCount = (GLsizei)pData->readable().size();
+ }
+ else
+ {
+ auto primitiveGL = runTimeCast( converter->convert( primitive.get() ) );
+ if( !primitiveGL )
+ {
+ continue;
+ }
+
+ pBuffer = primitiveGL->getVertexBuffer( g_pName );
+ vBuffer = primitiveGL->getVertexBuffer( name );
+ vertexCount = primitiveGL->getVertexCount();
+ }
+
+ if( !pBuffer || !vBuffer )
+ {
+ continue;
+ }
+
+ GLint vDataProgram;
+ switch( vData->getInterpretation() )
+ {
+ case GeometricData::Interpretation::Point :
+ vDataProgram = m_vectorShaderPoint->program();
+ break;
+ case GeometricData::Interpretation::Normal :
+ vDataProgram = m_vectorShaderBivector->program();
+ break;
+ default :
+ vDataProgram = m_vectorShaderVector->program();
+ }
+ if( !currentShaderProgram || currentShaderProgram.value() != vDataProgram )
+ {
+ glUseProgram( vDataProgram );
+ currentShaderProgram = vDataProgram;
+ }
+
+ // Get the object to world transform
+ M44f o2w;
+ ScenePlug::ScenePath path( location.path() );
+ while( !path.empty() )
+ {
+ scope.setPath( &path );
+ o2w = o2w * location.scene().transformPlug()->getValue();
+ path.pop_back();
+ }
+
+ // Compute object/normal to view and object to clip matrices
+ uniforms.o2v = o2w * w2v;
+ uniforms.n2v = ( uniforms.o2v.gjInverse() ).transpose();
+ uniforms.o2c = uniforms.o2v * uniforms.v2c;
+
+ // Upload OpenGL uniform block data
+ glBufferData( GL_UNIFORM_BUFFER, sizeof( UniformBlockVectorShader ), &uniforms, GL_DYNAMIC_DRAW );
+
+ // Instance a line segment for each element of vector data
+ glBindBuffer( GL_ARRAY_BUFFER, pBuffer->buffer() );
+ glVertexAttribPointer( ATTRIB_GLSL_LOCATION_PS, 3, GL_FLOAT, GL_FALSE, 0, nullptr );
+ glBindBuffer( GL_ARRAY_BUFFER, vBuffer->buffer() );
+ glVertexAttribPointer( ATTRIB_GLSL_LOCATION_VS, 3, GL_FLOAT, GL_FALSE, 0, nullptr );
+ glDrawArraysInstanced( GL_LINES, 0, 2, vertexCount );
+
+ }
+
+ // Restore OpenGL state
+
+ glPopClientAttrib();
+ glBindBuffer( GL_ARRAY_BUFFER, arrayBinding );
+ glBindBuffer( GL_UNIFORM_BUFFER, uniformBinding );
+
+ glLineWidth( lineWidth );
+
+ if( lineSmooth )
+ {
+ glEnable( GL_LINE_SMOOTH );
+ }
+ if( !blendEnabled )
+ {
+ glDisable( GL_BLEND );
+ }
+ if( !depthEnabled )
+ {
+ glDisable( GL_DEPTH_TEST );
+ }
+ if( depthWriteEnabled )
+ {
+ glDepthMask( GL_TRUE );
+ }
+ glUseProgram( shaderProgram );
+ }
+
VisualiserTool::CursorValue cursorVertexValue() const
{
return m_cursorVertexValue;
@@ -1361,6 +1770,10 @@ class VisualiserGadget : public Gadget
mutable IECoreGL::ConstBufferPtr m_colorUniformBuffer;
mutable IECoreGL::ConstShaderPtr m_vertexLabelShader;
mutable IECoreGL::ConstBufferPtr m_vertexLabelUniformBuffer;
+ mutable IECoreGL::ConstShaderPtr m_vectorShaderPoint;
+ mutable IECoreGL::ConstShaderPtr m_vectorShaderVector;
+ mutable IECoreGL::ConstShaderPtr m_vectorShaderBivector;
+ mutable IECoreGL::ConstBufferPtr m_vectorUniformBuffer;
mutable IECoreGL::ConstBufferPtr m_vertexLabelStorageBuffer;
mutable std::size_t m_vertexLabelStorageCapacity;
@@ -1428,9 +1841,26 @@ VisualiserTool::VisualiserTool( SceneView *view, const std::string &name ) : Sel
addChild( new V3fPlug( "valueMin", Plug::In, g_valueMinDefault ) );
addChild( new V3fPlug( "valueMax", Plug::In, g_valueMaxDefault ) );
addChild( new FloatPlug( "size", Plug::In, g_textSizeDefault, g_textSizeMin ) );
+ addChild( new FloatPlug( "vectorScale", Plug::In, g_vectorScaleDefault, g_vectorScaleMin ) );
+ addChild( new Color3fPlug( "vectorColor", Plug::In, g_vectorColorDefault ) );
addChild( new ScenePlug( "__scene", Plug::In ) );
+ addChild( new ScenePlug( "__uniformPScene", Plug::In ) );
+
+ ScenePlug *inScene = view->inPlug();
+
+ PathFilterPtr filter = new PathFilter( "__resampleFilter" );
+ filter->pathsPlug()->setValue( new StringVectorData( { "/..." } ) );
+ addChild( filter );
- internalScenePlug()->setInput( view->inPlug() );
+ ResamplePrimitiveVariablesPtr resamplePrimVars = new ResamplePrimitiveVariables( "__resamplePrimVars" );
+ addChild( resamplePrimVars );
+ resamplePrimVars->inPlug()->setInput( inScene );
+ resamplePrimVars->namesPlug()->setValue( "P" );
+ resamplePrimVars->interpolationPlug()->setValue( IECoreScene::PrimitiveVariable::Interpolation::Uniform );
+ resamplePrimVars->filterPlug()->setInput( filter->outPlug() );
+
+ internalScenePlug()->setInput( inScene);
+ internalSceneUniformPPlug()->setInput( resamplePrimVars->outPlug() );
// Connect signal handlers
//
@@ -1553,14 +1983,44 @@ const FloatPlug *VisualiserTool::sizePlug() const
return getChild( g_firstPlugIndex + 5 );
}
+FloatPlug *VisualiserTool::vectorScalePlug()
+{
+ return getChild( g_firstPlugIndex + 6 );
+}
+
+const FloatPlug *VisualiserTool::vectorScalePlug() const
+{
+ return getChild( g_firstPlugIndex + 6 );
+}
+
+Color3fPlug *VisualiserTool::vectorColorPlug()
+{
+ return getChild( g_firstPlugIndex + 7 );
+}
+
+const Color3fPlug *VisualiserTool::vectorColorPlug() const
+{
+ return getChild( g_firstPlugIndex + 7 );
+}
+
ScenePlug *VisualiserTool::internalScenePlug()
{
- return getChild( g_firstPlugIndex + 6 );
+ return getChild( g_firstPlugIndex + 8 );
}
const ScenePlug *VisualiserTool::internalScenePlug() const
{
- return getChild( g_firstPlugIndex + 6 );
+ return getChild( g_firstPlugIndex + 8 );
+}
+
+ScenePlug *VisualiserTool::internalSceneUniformPPlug()
+{
+ return getChild( g_firstPlugIndex + 9 );
+}
+
+const ScenePlug *VisualiserTool::internalSceneUniformPPlug() const
+{
+ return getChild( g_firstPlugIndex + 9 );
}
const std::vector &VisualiserTool::selection() const
@@ -1674,11 +2134,25 @@ bool VisualiserTool::keyPress( const KeyEvent &event )
if( event.key == "Plus" || event.key == "Equal" )
{
- sizePlug()->setValue( sizePlug()->getValue() + g_textSizeInc );
+ if( event.modifiers == KeyEvent::Modifiers::None )
+ {
+ sizePlug()->setValue( sizePlug()->getValue() + g_textSizeInc );
+ }
+ else if( event.modifiers == KeyEvent::Modifiers::Shift )
+ {
+ vectorScalePlug()->setValue( vectorScalePlug()->getValue() + g_vectorScaleInc );
+ }
}
else if( event.key == "Minus" || event.key == "Underscore" )
{
- sizePlug()->setValue( std::max( sizePlug()->getValue() - g_textSizeInc, g_textSizeMin ) );
+ if( event.modifiers == KeyEvent::Modifiers::None )
+ {
+ sizePlug()->setValue( std::max( sizePlug()->getValue() - g_textSizeInc, g_textSizeMin ) );
+ }
+ else if( event.modifiers == KeyEvent::Modifiers::Shift )
+ {
+ vectorScalePlug()->setValue( std::max( vectorScalePlug()->getValue() - g_vectorScaleInc, g_vectorScaleMin ) );
+ }
}
return false;
@@ -1771,7 +2245,9 @@ void VisualiserTool::plugDirtied( const Plug *plug )
if(
plug == activePlug() ||
plug == internalScenePlug()->objectPlug() ||
- plug == internalScenePlug()->transformPlug()
+ plug == internalScenePlug()->transformPlug() ||
+ plug == internalSceneUniformPPlug()->objectPlug() ||
+ plug == internalSceneUniformPPlug()->transformPlug()
)
{
m_selectionDirty = true;
@@ -1784,7 +2260,9 @@ void VisualiserTool::plugDirtied( const Plug *plug )
plug == valueMinPlug() ||
plug == valueMaxPlug() ||
plug == sizePlug() ||
- plug == modePlug()
+ plug == modePlug() ||
+ plug == vectorScalePlug() ||
+ plug == vectorColorPlug()
)
{
m_gadgetDirty = true;
@@ -1873,7 +2351,7 @@ void VisualiserTool::updateSelection() const
for( PathMatcher::Iterator it = selectedPaths.begin(), eIt = selectedPaths.end(); it != eIt; ++it )
{
- m_selection.emplace_back( *scene, *it, *view()->context() );
+ m_selection.emplace_back( *scene, *internalSceneUniformPPlug(), *it, *view()->context() );
}
}
@@ -2136,9 +2614,10 @@ void VisualiserTool::makeGadgetFirst()
VisualiserTool::Selection::Selection(
const ScenePlug &scene,
+ const ScenePlug &uniformPScene,
const ScenePlug::ScenePath &path,
const Context &context
-) : m_scene( &scene ), m_path( path ), m_context( &context )
+) : m_scene( &scene ), m_uniformPScene( &uniformPScene ), m_path( path ), m_context( &context )
{
}
@@ -2148,6 +2627,11 @@ const ScenePlug &VisualiserTool::Selection::scene() const
return *m_scene;
}
+const ScenePlug &VisualiserTool::Selection::uniformPScene() const
+{
+ return *m_uniformPScene;
+}
+
const ScenePlug::ScenePath &VisualiserTool::Selection::path() const
{
return m_path;