Esempio n. 1
0
void CameraController::frame( const Imath::Box3f &box, const Imath::V3f &viewDirection, const Imath::V3f &upVector )
{
	// make a matrix to centre the camera on the box, with the appropriate view direction
	M44f cameraMatrix = rotationMatrixWithUpDir( V3f( 0, 0, -1 ), viewDirection, upVector );
	M44f translationMatrix;
	translationMatrix.translate( box.center() );
	cameraMatrix *= translationMatrix;

	// translate the camera back until the box is completely visible
	M44f inverseCameraMatrix = cameraMatrix.inverse();
	Box3f cBox = transform( box, inverseCameraMatrix );

	Box2f screenWindow = m_data->screenWindow->readable();
	if( m_data->projection->readable()=="perspective" )
	{
		// perspective. leave the field of view and screen window as is and translate
		// back till the box is wholly visible. this currently assumes the screen window
		// is centred about the camera axis.
		float z0 = cBox.size().x / screenWindow.size().x;
		float z1 = cBox.size().y / screenWindow.size().y;

		m_data->centreOfInterest = std::max( z0, z1 ) / tan( M_PI * m_data->fov->readable() / 360.0 ) + cBox.max.z +
			m_data->clippingPlanes->readable()[0];

		cameraMatrix.translate( V3f( 0.0f, 0.0f, m_data->centreOfInterest ) );
	}
	else
	{
		// orthographic. translate to front of box and set screen window
		// to frame the box, maintaining the aspect ratio of the screen window.
		m_data->centreOfInterest = cBox.max.z + m_data->clippingPlanes->readable()[0] + 0.1; // 0.1 is a fudge factor
		cameraMatrix.translate( V3f( 0.0f, 0.0f, m_data->centreOfInterest ) );

		float xScale = cBox.size().x / screenWindow.size().x;
		float yScale = cBox.size().y / screenWindow.size().y;
		float scale = std::max( xScale, yScale );

		V2f newSize = screenWindow.size() * scale;
		screenWindow.min.x = cBox.center().x - newSize.x / 2.0f;
		screenWindow.min.y = cBox.center().y - newSize.y / 2.0f;
		screenWindow.max.x = cBox.center().x + newSize.x / 2.0f;
		screenWindow.max.y = cBox.center().y + newSize.y / 2.0f;
	}

	m_data->transform->matrix = cameraMatrix;
	m_data->screenWindow->writable() = screenWindow;
}
Esempio n. 2
0
IECore::ConstObjectPtr MapProjection::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	// early out if it's not a primitive with a "P" variable
	const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
	if( !inputPrimitive )
	{
		return inputObject;
	}

	const V3fVectorData *pData = inputPrimitive->variableData<V3fVectorData>( "P" );
	if( !pData )
	{
		return inputObject;
	}

	// early out if the uv set name hasn't been provided

	const string uvSet = uvSetPlug()->getValue();

	if( uvSet == "" )
	{
		return inputObject;
	}

	// get the camera and early out if we can't find one

	ScenePath cameraPath;
	ScenePlug::stringToPath( cameraPlug()->getValue(), cameraPath );

	ConstCameraPtr constCamera = runTimeCast<const Camera>( inPlug()->object( cameraPath ) );
	if( !constCamera )
	{
		return inputObject;
	}

	M44f cameraMatrix = inPlug()->fullTransform( cameraPath );
	M44f objectMatrix = inPlug()->fullTransform( path );
	M44f objectToCamera = objectMatrix * cameraMatrix.inverse();

	bool perspective = constCamera->getProjection() == "perspective";

	Box2f normalizedScreenWindow;
	if( constCamera->hasResolution() )
	{
		normalizedScreenWindow = constCamera->frustum();
	}
	else
	{
		// We don't know what resolution the camera is meant to render with, so take the whole aperture
		// as the screen window
		normalizedScreenWindow = constCamera->frustum( Camera::Distort );
	}

	// do the work

	PrimitivePtr result = inputPrimitive->copy();

	V2fVectorDataPtr uvData = new V2fVectorData();
	uvData->setInterpretation( GeometricData::UV );

	result->variables[uvSet] = PrimitiveVariable( PrimitiveVariable::Vertex, uvData );

	const vector<V3f> &p = pData->readable();
	vector<V2f> &uv = uvData->writable();
	uv.reserve( p.size() );

	for( size_t i = 0, e = p.size(); i < e; ++i )
	{
		V3f pCamera = p[i] * objectToCamera;
		V2f pScreen = V2f( pCamera.x, pCamera.y );
		if( perspective )
		{
			pScreen /= -pCamera.z;
		}
		uv.push_back(
			V2f(
				lerpfactor( pScreen.x, normalizedScreenWindow.min.x, normalizedScreenWindow.max.x ),
				lerpfactor( pScreen.y, normalizedScreenWindow.min.y, normalizedScreenWindow.max.y )
			)
		);
	}

	return result;
}
Esempio n. 3
0
void CameraTool::viewportCameraChanged()
{
	const TransformTool::Selection &selection = cameraSelection();
	if( !selection.transformPlug )
	{
		return;
	}

	if( !view()->viewportGadget()->getCameraEditable() )
	{
		return;
	}

	// Figure out the offset from where the camera is in the scene
	// to where the user has just moved the viewport camera.

	const M44f viewportCameraTransform = view()->viewportGadget()->getCameraTransform();
	M44f cameraTransform;
	{
		Context::Scope scopedContext( selection.context.get() );
		cameraTransform = selection.scene->fullTransform( selection.path );
	}

	if( cameraTransform == viewportCameraTransform )
	{
		return;
	}

	const M44f offset = cameraTransform.inverse() * viewportCameraTransform;

	// This offset is measured in the downstream world space.
	// Transform it into the space the transform is applied in.
	// This requires a "change of basis" because it is a transformation
	// matrix.

	const M44f sceneToTransformSpace = selection.sceneToTransformSpace();
	const M44f transformSpaceOffset = sceneToTransformSpace.inverse() * offset * sceneToTransformSpace;

	// Now apply this offset to the current value on the transform plug.

	M44f plugTransform;
	{
		Context::Scope scopedContext( selection.upstreamContext.get() );
		plugTransform = selection.transformPlug->matrix();
	}
	plugTransform = plugTransform * transformSpaceOffset;
	const V3f t = plugTransform.translation();

	Eulerf e; e.extract( plugTransform );
	e.makeNear( degreesToRadians( selection.transformPlug->rotatePlug()->getValue() ) );
	const V3f r = radiansToDegrees( V3f( e ) );

	UndoScope undoScope( selection.transformPlug->ancestor<ScriptNode>(), UndoScope::Enabled, m_undoGroup );

	for( int i = 0; i < 3; ++i )
	{
		setValueOrAddKey( selection.transformPlug->rotatePlug()->getChild( i ), selection.context->getTime(), r[i] );
		setValueOrAddKey( selection.transformPlug->translatePlug()->getChild( i ), selection.context->getTime(), t[i] );
	}

	// Create an action to save/restore the current center of interest, so that
	// when the user undos a framing action, they get back to the old center of
	// interest as well as the old transform.
	Action::enact(
		selection.transformPlug,
		// Do
		boost::bind(
			&CameraTool::setCameraCenterOfInterest,
			CameraToolPtr( this ), selection.path,
			view()->viewportGadget()->getCenterOfInterest()
		),
		// Undo
		boost::bind(
			&CameraTool::setCameraCenterOfInterest,
			CameraToolPtr( this ), selection.path,
			getCameraCenterOfInterest( selection.path )
		)
	);
}