/** * Calculate the end of the directonal marker line. * * This is done by calculating the scale we need to multiply the directional marker by to * reach each of the three sides of the bounding box, then take the smallest of these, * because that is the side it will intersect. Finally, multiply by an overall scale factor. */ CC3Vector CC3DirectionMarkerNode::calculateLineEnd() { CC3Box pbb = getParentBoundingBox(); CC3Vector md = getMarkerDirection(); CC3Vector pbbDirScale = cc3v(calcScale( md.x, pbb.minimum.x, pbb.maximum.x ), calcScale( md.y, pbb.minimum.y, pbb.maximum.y ), calcScale( md.z, pbb.minimum.z, pbb.maximum.z )); //CC3_PUSH_NOSHADOW GLfloat dirScale = MIN(pbbDirScale.x, MIN(pbbDirScale.y, pbbDirScale.z)); dirScale = dirScale * getDirectionMarkerScale(); //CC3_POP_NOSHADOW // Ensure that the direction marker has the minimum length specified by directionMarkerMinimumLength if (directionMarkerMinimumLength) { GLfloat gblUniScale = getGlobalScale().length() / CC3Vector::kCC3VectorUnitCubeLength; GLfloat minScale = directionMarkerMinimumLength / gblUniScale; dirScale = MAX(dirScale, minScale); } CC3Vector lineEnd = md.scaleUniform( dirScale ); //LogTrace(@"%@ calculated line end %@ from pbb scale %@ and dir scale %.3f and min global length: %.3f", self, // NSStringFromCC3Vector(lineEnd), NSStringFromCC3Vector(pbbDirScale), dirScale, directionMarkerMinimumLength); return lineEnd; }
void CC3Matrix::populateToLookAt( const CC3Vector& targetLocation, const CC3Vector& eyeLocation, const CC3Vector& upDirection ) { CC3Vector fwdDir = targetLocation.difference( eyeLocation ); populateToPointTowards( fwdDir, upDirection ); transpose(); translateBy( eyeLocation.negate() ); m_isIdentity = false; m_isRigid = true; }
/** * Overridden to establish a default parent bounding box for parents that have no bounding * box, such as cameras and lights. The default parent box is calculated as 5% of the size * of the entire scene. */ CC3Box CC3DirectionMarkerNode::getParentBoundingBox() { CC3Box pbb = super::getParentBoundingBox(); if ( !pbb.isZero() ) return pbb; CC3Vector bbDim = CC3Vector::kCC3VectorZero; CC3Scene* pScene = getScene(); if ( pScene ) bbDim = getScene()->getBoundingBox().getSize().scaleUniform( 0.05f ); return CC3Box( bbDim.negate(), bbDim ); }
void CC3ActionMoveDirectionallyBy::update( float t ) { GLfloat deltaTime = t - m_prevTime; GLfloat deltaDist = m_distance * deltaTime; CC3Vector moveDir = getTargetDirection().normalize(); CC3Vector prevLoc = getTargetNode()->getLocation(); getTargetNode()->setLocation( prevLoc.add( moveDir.scaleUniform(deltaDist) ) ); m_prevTime = t; /*LogTrace(@"%@: time: %.3f, delta time: %.3f, delta dist: %.3f, was at: %@, now at: %@", self, t, deltaTime, deltaDist, NSStringFromCC3Vector(prevLoc), NSStringFromCC3Vector(self.targetCC3Node.location));*/ }
// Short-circuit the identity transform. isRigid unchanged under translation. void CC3Matrix::translateBy( const CC3Vector& aTranslation ) { if ( !aTranslation.isZero() ) { implTranslateBy( aTranslation ); m_isIdentity = false; } }
// Short-circuit the identity transform void CC3Matrix::scaleBy( const CC3Vector& aScale ) { if ( !aScale.equals( CC3Vector::kCC3VectorUnitCube ) ) { implScaleBy( aScale ); m_isIdentity = false; m_isRigid = false; } }
void CC3Matrix::populateFromTranslation( const CC3Vector& aTranslation ){ if ( aTranslation.isZero() ) { populateIdentity(); } else { implPopulateFromTranslation( aTranslation ); m_isIdentity = false; m_isRigid = true; } }
void CC3Matrix::populateFromScale( const CC3Vector& aScale ) { if ( aScale.equals( CC3Vector::kCC3VectorUnitCube )) { populateIdentity(); } else { implPopulateFromScale( aScale ); m_isIdentity = false; m_isRigid = false; } }
CC3Vector CC3Camera::getProjectLocation( const CC3Vector& a3DLocation ) { // Convert specified location to a 4D homogeneous location vector // and transform it using the modelview and projection matrices. CC3Vector4 hLoc; hLoc.fromLocation(a3DLocation); hLoc = getViewMatrix()->transformHomogeneousVector( hLoc ); hLoc = getProjectionMatrix()->transformHomogeneousVector( hLoc ); // Convert projected 4D vector back to 3D. CC3Vector projectedLoc = hLoc.homogenizedCC3Vector(); // The projected vector is in a projection coordinate space between -1 and +1 on all axes. // Normalize the vector so that each component is between 0 and 1 by calculating ( v = (v + 1) / 2 ). projectedLoc = projectedLoc.average( CC3Vector::kCC3VectorUnitCube ); CCAssert(_viewport.h > 0 && _viewport.w > 0, "%CC3Camera does not have a valid viewport"); // Map the X & Y components of the projected location (now between 0 and 1) to display coordinates. GLfloat g2p = 1.0f / CCDirector::sharedDirector()->getContentScaleFactor(); projectedLoc.x *= ((GLfloat)_viewport.w * g2p); projectedLoc.y *= ((GLfloat)_viewport.h * g2p); // Using the vector from the camera to the 3D location, determine whether or not the // 3D location is in front of the camera by using the dot-product of that vector and // the direction the camera is pointing. Set the Z-component of the projected location // to be the signed distance from the camera to the 3D location, with a positive sign // indicating the location is in front of the camera, and a negative sign indicating // the location is behind the camera. CC3Vector camToLocVector = a3DLocation - getGlobalLocation(); GLfloat camToLocDist = camToLocVector.length(); GLfloat frontOrBack = (GLfloat)SIGN( camToLocVector.dot( getGlobalForwardDirection() ) ); projectedLoc.z = frontOrBack * camToLocDist; //LogTrace(@"%@ projecting location %@ to %@ and orienting with device to %@ using viewport %@", // self, NSStringFromCC3Vector(a3DLocation), NSStringFromCC3Vector(projectedLoc), // NSStringFromCC3Vector(orientedLoc), NSStringFromCC3Viewport(_viewport)); return projectedLoc; }
/** * Returns a 4D directional vector which can be added to each vertex when creating * the shadow volume vertices from the corresponding shadow caster vertices. * * The returned vector is in the local coordinate system of the shadow caster. * * The returned directional vector is a small offset vector in the direction away * from the light. A unit vector in that direction is scaled by both the distance * from the center of the shadow casting node to the camera and the * shadowVolumeVertexOffsetFactor property. Hence, if the shadow caster is farther * away from the camera, the returned value will be larger, to reduce the chance * of Z-fighting between the faces of the shadow volume and the shadow caster. */ CC3Vector4 CC3ShadowVolumeMeshNode::getShadowVolumeVertexOffsetForLightAt( const CC3Vector4& localLightPos ) { CC3Vector scLoc = getShadowCaster()->getLocalContentCenterOfGeometry(); CC3Vector lgtLoc = localLightPos.cc3Vector(); CC3Vector camLoc = getShadowCaster()->getGlobalTransformMatrixInverted()->transformLocation( getActiveCamera()->getGlobalLocation() ); // Get a unit offset vector in the direction away from the light CC3Vector offsetDir = (_light->isDirectionalOnly() ? lgtLoc.negate() : scLoc.difference( lgtLoc )).normalize(); // Get the distance from the shadow caster CoG and the camera, and scale the // unit offset vector by that distance and the shadowVolumeVertexOffsetFactor GLfloat camDist = scLoc.distance( camLoc ); CC3Vector offset = offsetDir.scaleUniform( camDist * _shadowVolumeVertexOffsetFactor ); CC3_TRACE("CC3ShadowVolumeMeshNode nudging vertices by %s", offset.stringfy().c_str()); // Create and return a 4D directional vector from the offset return CC3Vector4().fromDirection(offset); }
void CC3Camera::moveWithDuration( float t, CC3Node* aNode, const CC3Vector& targetLoc, const CC3Vector& aDirection, GLfloat padding, bool checkScene ) { CC3Vector newLoc = calculateLocationToShowAllOf( aNode, targetLoc, aDirection, padding, checkScene ); CC3Vector newFwdDir = aDirection.negate(); //LogInfo(@"%@ \n\tmoving to: %@ \n\tpointing towards: %@ \n\tnear clipping distance: %.3f" // @"\n\tfar clipping distance: %.3f \n\tto show all of: %@", // self, NSStringFromCC3Vector(newLoc), NSStringFromCC3Vector(newFwdDir), // self.nearClippingDistance, self.farClippingDistance, aNode); ensureAtRootAncestor(); if (t > 0.0f) { runAction( CC3ActionMoveTo::actionWithDuration( t, newLoc ) ); runAction( CC3ActionRotateToLookTowards::actionWithDuration( t, newFwdDir )); } else { setLocation( newLoc ); setForwardDirection( newFwdDir ); } }
// Short-circuit the identity transform. isRigid unchanged under rotation. void CC3Matrix::rotateBy( const CC3Vector& aRotation ) { if ( !aRotation.isZero() ) { implRotateBy( aRotation ); m_isIdentity = false; } }
void CC3DirectionMarkerNode::setMarkerDirection( const CC3Vector& aDirection ) { m_markerDirection = aDirection.normalize(); }
void CC3ActionRotateToLookTowards::initWithDuration( float t, const CC3Vector& aDirection ) /// forwardDirection { return super::initWithDuration( t, aDirection.normalize() ); }
void CC3PointParticle::pointNormalAt( const CC3Vector& camLoc ) { setNormal( camLoc.difference( getLocation() ).normalize() ); }
CC3Vector CC3Camera::calculateLocationToShowAllOf( CC3Node* aNode, const CC3Vector& targLoc, const CC3Vector& aDirection, GLfloat padding, bool checkScene ) { ensureSceneUpdated( checkScene ); // Complementary unit vectors pointing towards camera from node, and vice versa CC3Vector camDir = aDirection.normalize(); CC3Vector viewDir = camDir.negate(); // The camera's new forward direction will be viewDir. Use a matrix to detrmine // the camera's new up and right directions assuming the same scene up direction. CC3Matrix3x3 rotMtx; CC3Matrix3x3PopulateToPointTowards(&rotMtx, viewDir, getReferenceUpDirection()); CC3Vector upDir = CC3Matrix3x3ExtractUpDirection(&rotMtx); CC3Vector rtDir = CC3Matrix3x3ExtractRightDirection(&rotMtx); // Determine the eight vertices, of the node's bounding box, in the global coordinate system CC3Box gbb = aNode->getGlobalBoundingBox(); CC3Vector targetLoc = targLoc; // If a target location has not been specified, use the center of the node's global bounding box if ( targetLoc.isNull() ) targetLoc = gbb.getCenter(); CC3Vector bbMin = gbb.minimum; CC3Vector bbMax = gbb.maximum; CC3Vector bbVertices[8]; bbVertices[0] = cc3v(bbMin.x, bbMin.y, bbMin.z); bbVertices[1] = cc3v(bbMin.x, bbMin.y, bbMax.z); bbVertices[2] = cc3v(bbMin.x, bbMax.y, bbMin.z); bbVertices[3] = cc3v(bbMin.x, bbMax.y, bbMax.z); bbVertices[4] = cc3v(bbMax.x, bbMin.y, bbMin.z); bbVertices[5] = cc3v(bbMax.x, bbMin.y, bbMax.z); bbVertices[6] = cc3v(bbMax.x, bbMax.y, bbMin.z); bbVertices[7] = cc3v(bbMax.x, bbMax.y, bbMax.z); // Express the camera's FOV in terms of ratios of the near clip bounds to // the near clip distance, so we can determine distances using similar triangles. CCSize fovRatios = getFovRatios(); // Iterate through all eight vertices of the node's bounding box, and calculate // the largest distance required to place the camera away from the center of the // node in order to fit all eight vertices within the camera's frustum. // Simultaneously, calculate the extra distance from the center of the node to // the vertex that will be farthest from the camera, so we can ensure that all // vertices will fall within the frustum's far end. GLfloat maxCtrDist = 0; GLfloat maxVtxDeltaDist = 0; GLfloat minVtxDeltaDist = 0; for (int i = 0; i < 8; i++) { // Get a vector from the target location to the vertex CC3Vector relVtx = bbVertices[i] - targetLoc; // Project that vector onto each of the camera's new up and right directions, // and use similar triangles to determine the distance at which to place the // camera so that the vertex will fit in both the up and right directions. GLfloat vtxDistUp = fabs(relVtx.dot( upDir ) / fovRatios.height); GLfloat vtxDistRt = fabs(relVtx.dot( rtDir ) / fovRatios.width); GLfloat vtxDist = MAX(vtxDistUp, vtxDistRt); // Calculate how far along the view direction the vertex is from the center GLfloat vtxDeltaDist = relVtx.dot( viewDir ); GLfloat ctrDist = vtxDist - vtxDeltaDist; // Accumulate the maximum distance from the node's center to the camera // required to fit all eight points, and the distance from the node's // center to the vertex that will be farthest away from the camera. maxCtrDist = MAX(maxCtrDist, ctrDist); maxVtxDeltaDist = MAX(maxVtxDeltaDist, vtxDeltaDist); minVtxDeltaDist = MIN(minVtxDeltaDist, vtxDeltaDist); } // Add some padding so we will have a bit of space around the node when it fills the view. maxCtrDist *= (1 + padding); // Determine if we need to move the far end of the camera frustum farther away GLfloat farClip = viewDir.scaleUniform(maxCtrDist + maxVtxDeltaDist).length(); farClip *= (GLfloat)(1 + kCC3FrustumFitPadding); // Include a little bit of padding if (farClip > getFarClippingDistance()) setFarClippingDistance( farClip ); // Determine if we need to move the near end of the camera frustum closer GLfloat nearClip = viewDir.scaleUniform(maxCtrDist + minVtxDeltaDist).length(); nearClip *= (GLfloat)(1 - kCC3FrustumFitPadding); // Include a little bit of padding if (nearClip < getNearClippingDistance()) setNearClippingDistance( nearClip ); //LogTrace(@"%@ moving to %@ to show %@ at %@ within %@ with new farClip: %.3f", self, // NSStringFromCC3Vector(CC3VectorAdd(targLoc, CC3VectorScaleUniform(camDir, maxCtrDist))), // aNode, NSStringFromCC3Vector(targLoc), _frustum, self.farClippingDistance); // Return the new location of the camera, return targetLoc.add( camDir.scaleUniform( maxCtrDist ) ); }