void BackdropNodeGadget::frame( const std::vector<Gaffer::Node *> &nodes ) { GraphGadget *graph = ancestor<GraphGadget>(); if( !graph ) { return; } Box3f b; for( std::vector<Node *>::const_iterator it = nodes.begin(), eIt = nodes.end(); it != eIt; ++it ) { NodeGadget *nodeGadget = graph->nodeGadget( *it ); if( nodeGadget ) { b.extendBy( nodeGadget->transformedBound( NULL ) ); } } if( b.isEmpty() ) { return; } graph->setNodePosition( node(), V2f( b.center().x, b.center().y ) ); V2f s( b.size().x / 2.0f, b.size().y / 2.0f ); boundPlug()->setValue( Box2f( V2f( -s ) - V2f( g_margin ), V2f( s ) + V2f( g_margin + 2.0f * g_margin ) ) ); }
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; }
Imath::Box3f StandardNodeGadget::bound() const { Box3f b = IndividualContainer::bound(); LinearContainer::Orientation orientation = inputNoduleContainer()->getOrientation(); if( orientation == LinearContainer::X ) { // enforce a minimum width float width = std::max( b.size().x, g_minWidth ); float c = b.center().x; b.min.x = c - width / 2.0f; b.max.x = c + width / 2.0f; } // add the missing spacing to the border if we have no nodules on a given side Box3f inputContainerBound = inputNoduleContainer()->transformedBound( this ); Box3f outputContainerBound = outputNoduleContainer()->transformedBound( this ); if( inputContainerBound.isEmpty() ) { if( orientation == LinearContainer::X ) { b.max.y += g_spacing + g_borderWidth; } else { b.min.x -= g_spacing + g_borderWidth; } } if( outputContainerBound.isEmpty() ) { if( orientation == LinearContainer::X ) { b.min.y -= g_spacing + g_borderWidth; } else { b.max.x += g_spacing + g_borderWidth; } } // add on a little bit in the major axis, so that the nodules don't get drawn in the frame corner if( orientation == LinearContainer::X ) { b.min.x -= g_borderWidth; b.max.x += g_borderWidth; } else { b.min.y -= g_borderWidth; b.max.y += g_borderWidth; } return b; }
void StandardNodule::renderLabel( const Style *style ) const { const NodeGadget *nodeGadget = ancestor<NodeGadget>(); if( !nodeGadget ) { return; } const std::string &label = plug()->getName().string(); // we rotate the label based on the angle the connection exits the node at. V3f tangent = nodeGadget->noduleTangent( this ); float theta = IECore::radiansToDegrees( atan2f( tangent.y, tangent.x ) ); // but we don't want the text to be vertical, so we bend it away from the // vertical axis. if( ( theta > 0.0f && theta < 90.0f ) || ( theta < 0.0f && theta >= -90.0f ) ) { theta = sign( theta ) * lerp( 0.0f, 45.0f, fabs( theta ) / 90.0f ); } else { theta = sign( theta ) * lerp( 135.0f, 180.0f, (fabs( theta ) - 90.0f) / 90.0f ); } // we also don't want the text to be upside down, so we correct the rotation // if that would be the case. Box3f labelBound = style->textBound( Style::LabelText, label ); V2f anchor( labelBound.min.x - 1.0f, labelBound.center().y ); if( theta > 90.0f || theta < -90.0f ) { theta = theta - 180.0f; anchor.x = labelBound.max.x + 1.0f; } // now we can actually do the rendering. if( getHighlighted() ) { glScalef( 1.2, 1.2, 1.2 ); } glRotatef( theta, 0, 0, 1.0f ); glTranslatef( -anchor.x, -anchor.y, 0.0f ); style->renderText( Style::LabelText, label ); }
static Mat4f getTransformationToBox(Box3f box) { // T_to_box to transform the unit circle in the bounding box Vec3f mid=box.center(); Vec3f size=box.size(); float max_size=box.maxsize(); size=Vec3f(max_size,max_size,max_size); float cos_pi_4= cos((float)M_PI/4.0); float _mat[16]={ size.x?(0.5*size.x/cos_pi_4):1.0f , 0 , 0 , mid.x, 0 , size.y?(0.5*size.y/cos_pi_4):1.0f, 0 , mid.y, 0 , 0 , size.z?0.5*size.z/cos_pi_4:1.0f , mid.z, 0 , 0 , 0 , 1 }; Mat4f T_to_box=Mat4f(_mat); return T_to_box; }
Mesh Mesh::createBox(const Box3f &box) { Vector3f center = box.center(); Vector3f extents = box.extents() * 0.5; Mesh mesh; int i = 0; for (int f = 0; f < 3; ++f) { for (int s = -1; s <= 1; s += 2) { Vector3f p(center), n(0.f), u(0.f), v(0.f); p[f] += extents[f] * s; n[f] = s; u[(f + 1) % 3] = extents[(f + 1) % 3]; v[(f + 2) % 3] = extents[(f + 2) % 3]; mesh.addVertex(p - u - v, n, Vector2f(0.f, 0.f)); mesh.addVertex(p + u - v, n, Vector2f(1.f, 0.f)); mesh.addVertex(p - u + v, n, Vector2f(0.f, 1.f)); mesh.addVertex(p + u + v, n, Vector2f(1.f, 1.f)); mesh.addTriangle(i, i + 1, i + 2); mesh.addTriangle(i + 1, i + 2, i + 3); i += 4; } } return mesh; }
void MultiQuadLight::prepareForRender() { Bvh::PrimVector prims; prims.reserve(_geometry.size()); _bounds = Box3f(); for (int i = 0; i < _geometry.size(); ++i) { Box3f bounds = _geometry.bounds(i); _bounds.grow(bounds); prims.emplace_back(bounds, bounds.center(), i); } _triangleAreas.resize(_geometry.triangleCount()); for (int i = 0; i < _geometry.triangleCount(); ++i) { const QuadGeometry::TriangleInfo &t = _geometry.triangle(i); _triangleAreas[i] = MathUtil::triangleArea(t.p0, t.p1, t.p2); } _bvh.reset(new Bvh::BinaryBvh(std::move(prims), 1)); constructSampleBounds(); }
// static bool GeometryUtils::boxTriangleIntersection( const Vector3f& u0, const Vector3f& u1, const Vector3f& u2, const Box3f& box ) { // use separating axis theorem to test overlap between triangle and box // need to test for overlap in these directions: // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle // we do not even need to test these) // 2) normal of the triangle // 3) crossproduct(edge from tri, {x,y,z}-direction) // this gives 3x3=9 more tests Vector3f v0; Vector3f v1; Vector3f v2; float min; float max; float p0; float p1; float p2; float rad; float fex; float fey; float fez; Vector3f normal; // These are the triangle edges. Vector3f e0; Vector3f e1; Vector3f e2; Vector3f boxCenter = box.center(); Vector3f boxHalfSize = 0.5f * box.size; // Move everything so that the box center is in (0,0,0). v0 = u0 - boxCenter; v1 = u0 - boxCenter; v2 = u0 - boxCenter; // Compute triangle edges. e0 = v1 - v0; e1 = v2 - v1; e2 = v0 - v2; // Bullet 3: // Test the 9 tests first (this was faster). fex = std::abs( e0.x ); fey = std::abs( e0.y ); fez = std::abs( e0.z ); AXISTEST_X01( e0.z, e0.y, fez, fey ); AXISTEST_Y02( e0.z, e0.x, fez, fex ); AXISTEST_Z12( e0.y, e0.x, fey, fex ); fex = std::abs( e1.x ); fey = std::abs( e1.y ); fez = std::abs( e1.z ); AXISTEST_X01( e1.z, e1.y, fez, fey ); AXISTEST_Y02( e1.z, e1.x, fez, fex ); AXISTEST_Z0( e1.y, e1.x, fey, fex ); fex = std::abs( e2.x ); fey = std::abs( e2.y ); fez = std::abs( e2.z ); AXISTEST_X2( e2.z, e2.y, fez, fey ); AXISTEST_Y1( e2.z, e2.x, fez, fex ); AXISTEST_Z12( e2.y, e2.x, fey, fex ); // Bullet 1: // first test overlap in the {x,y,z}-directions // find min, max of the triangle each direction, and test for overlap in // that direction -- this is equivalent to testing a minimal AABB around // the triangle against the AABB. // Test in x direction. minMax3( v0.x, v1.x, v2.x, min, max ); if( min > boxHalfSize.x || max < -boxHalfSize.x ) { return false; } // Test in y direction. minMax3( v0.y, v1.y, v2.y, min, max ); if( min > boxHalfSize.y || max < -boxHalfSize.y ) { return false; } // Test in z direction. minMax3( v0.z, v1.z, v2.z, min, max ); if( min > boxHalfSize.z || max < -boxHalfSize.z ) { return false; } /* Bullet 2: */ /* test if the box intersects the plane of the triangle */ /* compute plane equation of triangle: normal*x+d=0 */ normal = Vector3f::cross( e0, e1 ); if( !planeBoxOverlap( normal, v0, boxHalfSize ) ) { return false; } return true; /* box and triangle overlaps */ }
// static Box3f Box3f::scale( const Box3f& b, const Vector3f& s ) { Vector3f size = s * b.size; return{ b.center() - 0.5f * size, size }; }