void VolumeRenderable::_notifyCurrentCamera( Camera* cam ) { MovableObject::_notifyCurrentCamera(cam); // Fake orientation toward camera Vector3 zVec = getParentNode()->_getDerivedPosition() - cam->getDerivedPosition(); zVec.normalise(); Vector3 fixedAxis = cam->getDerivedOrientation() * Vector3::UNIT_Y ; Vector3 xVec = fixedAxis.crossProduct( zVec ); xVec.normalise(); Vector3 yVec = zVec.crossProduct( xVec ); yVec.normalise(); Quaternion oriQuat; oriQuat.FromAxes( xVec, yVec, zVec ); oriQuat.ToRotationMatrix(mFakeOrientation); Matrix3 tempMat; Quaternion q = getParentNode()->_getDerivedOrientation().UnitInverse() * oriQuat ; q.ToRotationMatrix(tempMat); Matrix4 rotMat = Matrix4::IDENTITY; rotMat = tempMat; rotMat.setTrans(Vector3(0.5f, 0.5f, 0.5f)); mUnit->setTextureTransform(rotMat); }
bool Quaternion::FromLookRotation(const Vector3& direction, const Vector3& upDirection) { Quaternion ret; Vector3 forward = direction.Normalized(); Vector3 v = forward.CrossProduct(upDirection); // If direction & upDirection are parallel and crossproduct becomes zero, use FromRotationTo() fallback if (v.LengthSquared() >= M_EPSILON) { v.Normalize(); Vector3 up = v.CrossProduct(forward); Vector3 right = up.CrossProduct(forward); ret.FromAxes(right, up, forward); } else ret.FromRotationTo(Vector3::FORWARD, forward); if (!ret.IsNaN()) { (*this) = ret; return true; } else return false; }
//----------------------------------------------------------------------------- const Matrix4& AutoParamDataSource::getSpotlightViewProjMatrix(size_t index) const { if (index < OGRE_MAX_SIMULTANEOUS_LIGHTS) { const Light& l = getLight(index); if (&l != &mBlankLight && l.getType() == Light::LT_SPOTLIGHT && mSpotlightViewProjMatrixDirty[index]) { Frustum frust; SceneNode dummyNode(0); dummyNode.attachObject(&frust); frust.setProjectionType(PT_PERSPECTIVE); frust.setFOVy(l.getSpotlightOuterAngle()); frust.setAspectRatio(1.0f); // set near clip the same as main camera, since they are likely // to both reflect the nature of the scene frust.setNearClipDistance(mCurrentCamera->getNearClipDistance()); // Calculate position, which same as spotlight position, in camera-relative coords if required dummyNode.setPosition(l.getDerivedPosition(true)); // Calculate direction, which same as spotlight direction Vector3 dir = - l.getDerivedDirection(); // backwards since point down -z dir.normalise(); Vector3 up = Vector3::UNIT_Y; // Check it's not coincident with dir if (Math::Abs(up.dotProduct(dir)) >= 1.0f) { // Use camera up up = Vector3::UNIT_Z; } // cross twice to rederive, only direction is unaltered Vector3 left = dir.crossProduct(up); left.normalise(); up = dir.crossProduct(left); up.normalise(); // Derive quaternion from axes Quaternion q; q.FromAxes(left, up, dir); dummyNode.setOrientation(q); // The view matrix here already includes camera-relative changes if necessary // since they are built into the frustum position mSpotlightViewProjMatrix[index] = PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE * frust.getProjectionMatrixWithRSDepth() * frust.getViewMatrix(); mSpotlightViewProjMatrixDirty[index] = false; } return mSpotlightViewProjMatrix[index]; } else return Matrix4::IDENTITY; }
void ThingRenderable::initialise() { // Fill array with randomly oriented quads Vector3 ax, ay, az; Quaternion q; things.clear(); orbits.clear(); for(size_t x=0; x<mCount; x++) { ax = Vector3(Math::SymmetricRandom(), Math::SymmetricRandom(), Math::SymmetricRandom()); ay = Vector3(Math::SymmetricRandom(), Math::SymmetricRandom(), Math::SymmetricRandom()); az = ax.crossProduct(ay); ay = az.crossProduct(ax); ax.normalise(); ay.normalise(); az.normalise(); q.FromAxes(ax, ay, az); //std::cerr << ax.dotProduct(ay) << " " << ay.dotProduct(az) << " " << az.dotProduct(ax) << std::endl; things.push_back(q); ax = Vector3(Math::SymmetricRandom(), Math::SymmetricRandom(), Math::SymmetricRandom()); ay = Vector3(Math::SymmetricRandom(), Math::SymmetricRandom(), Math::SymmetricRandom()); az = ax.crossProduct(ay); ay = az.crossProduct(ax); ax.normalise(); ay.normalise(); az.normalise(); q.FromAxes(ax, ay, az); orbits.push_back(q); } // Create buffers size_t nvertices = mCount*4; // n+1 planes //size_t elemsize = 2*3; // position, normal //size_t dsize = elemsize*nvertices; Ogre::IndexData *idata = new Ogre::IndexData(); Ogre::VertexData *vdata = new Ogre::VertexData(); // Quads unsigned short *faces = new unsigned short[mCount*6]; for(uint16 x=0; x<uint16(mCount); x++) { faces[x*6+0] = x*4+0; faces[x*6+1] = x*4+1; faces[x*6+2] = x*4+2; faces[x*6+3] = x*4+0; faces[x*6+4] = x*4+2; faces[x*6+5] = x*4+3; } // Setup buffers vdata->vertexStart = 0; vdata->vertexCount = nvertices; VertexDeclaration* decl = vdata->vertexDeclaration; VertexBufferBinding* bind = vdata->vertexBufferBinding; size_t offset = 0; decl->addElement(0, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( offset, nvertices, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); bind->setBinding(0, vbuf); //vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true); HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). createIndexBuffer( HardwareIndexBuffer::IT_16BIT, mCount*6, HardwareBuffer::HBU_STATIC_WRITE_ONLY); idata->indexBuffer = ibuf; idata->indexCount = mCount*6; idata->indexStart = 0; ibuf->writeData(0, ibuf->getSizeInBytes(), faces, true); // Delete temporary buffers delete [] faces; // Now make the render operation mRenderOp.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST; mRenderOp.indexData = idata; mRenderOp.vertexData = vdata; mRenderOp.useIndexes = true; }
void FollowCamera::update(Real time, const PosInfo& posIn, PosInfo* posOut, COLLISION_WORLD* world, bool bounce) { if (!ca || !posOut) return; /// input from car posInfoIn Vector3 posGoal = posIn.pos; Quaternion orientGoal = posIn.rot; /// output saved back to car posInfoOut Quaternion camRotFinal; const static Quaternion qO = Quaternion(Degree(180),Vector3::UNIT_Z) * Quaternion(Degree(-90),Vector3::UNIT_Y), qR = Quaternion(Degree(90),Vector3(0,1,0)); Quaternion orient = orientGoal * qO; Vector3 ofs = orient * ca->mOffset, goalLook = posGoal + ofs; first = iFirst < 2; ///par few first frames after reset if (iFirst < 10) // after reset { ++iFirst; mDistReduce = 0.f; mATilt = 0.f; } /// Camera Tilt from terrain/road slope under car //------------------------------------------------------------------------------------------- const float // params . . . Rdist = 1.f, // dist from car to ray (front or back) HupCar = 1.5f, // car up dir dist - for pipes - so pos stays inside pipe Habove = 1.5f, // up axis dist, above car - for very high terrain angles HMaxDepth = 12.f; // how far down can the ray goes const static Radian r0(0.f), angMin = Degree(10.f), // below this angle, tilt has no effect - terrain bumps maxDiff = Degree(1.4f); // max diff of tilt - no sudden jumps const float smoothSpeed = 14.f; // how fast to apply tilt change bool bUseTilt = ca->mType == CAM_ExtAng || ca->mType == CAM_Follow; Radian tilt(0.f); if (pSet->cam_tilt && bUseTilt) { // car pos Vector3 carUp = posIn.pos - HupCar * posIn.carY; MATHVECTOR<float,3> pos(carUp.x, -carUp.z, carUp.y + Habove); // to vdr/blt const static MATHVECTOR<float,3> dir(0,0,-1); // cast rays down // car rot, yaw angle Quaternion q = posIn.rot * Quaternion(Degree(90),Vector3(0,1,0)); float angCarY = q.getYaw().valueRadians() + PI_d/2.f; float ax = cosf(angCarY)*Rdist, ay = sinf(angCarY)*Rdist; //LogO("pos: "+fToStr(pos[0],2,4)+" "+fToStr(pos[1],2,4)+" a: "+fToStr(angCarY,2,4)+" dir: "+fToStr(ax,2,4)+" "+fToStr(ay,2,4)); // cast 2 rays - 2 times, average 2 angles COLLISION_CONTACT ct0,ct1,ct20,ct21; MATHVECTOR<float,3> ofs(ax*0.5f,ay*0.5f,0),ofs2(ax,ay,0); world->CastRay(pos+ofs, dir, HMaxDepth,chassis, ct0, 0,0, true, true); world->CastRay(pos-ofs, dir, HMaxDepth,chassis, ct1, 0,0, true, true); world->CastRay(pos+ofs2,dir, HMaxDepth,chassis, ct20, 0,0, true, true); world->CastRay(pos-ofs2,dir, HMaxDepth,chassis, ct21, 0,0, true, true); #ifdef CAM_TILT_DBG MATHVECTOR<float,3> v; v = pos+ofs; posHit[0] = Vector3(v[0],v[2]- ct0.GetDepth(), -v[1]); v = pos-ofs; posHit[1] = Vector3(v[0],v[2]- ct1.GetDepth(), -v[1]); v = pos+ofs2; posHit[2] = Vector3(v[0],v[2]- ct20.GetDepth(),-v[1]); v = pos-ofs2; posHit[3] = Vector3(v[0],v[2]- ct21.GetDepth(),-v[1]); #endif if (ct0.GetColObj() && ct1.GetColObj() && ct20.GetColObj() && ct21.GetColObj() ) tilt = (GetAngle(Rdist, ct1.GetDepth() - ct0.GetDepth()) + GetAngle(2.f*Rdist, ct21.GetDepth() - ct20.GetDepth())) * 0.5f; //else LogO(String("no hit: ")+(ct0.col?"1":"0")+(ct1.col?" 1":" 0")); //if (tilt < angMin && tilt > -angMin) tilt = 0.f; if (tilt < r0 && tilt >-angMin) { Radian d = tilt-angMin; tilt = std::min(r0, tilt + d*d*5.f); } if (tilt > r0 && tilt < angMin) { Radian d =-angMin-tilt; tilt = std::max(r0, tilt - d*d*5.f); } //LogO("a "+fToStr(angCarY,3,5)+" d "+fToStr(ct0.GetDepth(),3,5)+" "+fToStr(ct1.GetDepth(),3,5)+" t "+fToStr(tilt.valueDegrees(),3,5)); } // smooth tilt angle mATilt += std::min(maxDiff, std::max(-maxDiff, tilt - mATilt)) * time * smoothSpeed; //------------------------------------------------------------------------------------------- if (ca->mType == CAM_Car) /* 3 Car - car pos & rot full */ { camPosFinal = goalLook; camRotFinal = orient; posOut->camPos = camPosFinal; // save result in out posInfo posOut->camRot = camRotFinal; return; } if (ca->mType == CAM_Follow) ofs = ca->mOffset; Vector3 pos,goalPos; pos = camPosFinal - ofs; goalPos = posGoal; Vector3 xyz; if (ca->mType != CAM_Arena) { Real x,y,z,xz; // pitch & yaw to direction vector Real ap = bUseTilt ? (ca->mPitch.valueRadians() + mATilt.valueRadians()) : ca->mPitch.valueRadians(), ay = ca->mYaw.valueRadians(); y = sin(ap), xz = cos(ap); x = sin(ay) * xz, z = cos(ay) * xz; xyz = Vector3(x,y,z); xyz *= ca->mDist; } bool manualOrient = false; switch (ca->mType) { case CAM_Arena: /* 2 Arena - free pos & rot */ goalPos = ca->mOffset - ofs; break; case CAM_Free: /* 1 Free - free rot, pos from car */ goalPos += xyz; break; case CAM_Follow: /* 0 Follow - car rotY & pos from behind car, smooth */ { Quaternion orient = orientGoal * qR; orient.FromAngleAxis(orient.getYaw(), Vector3::UNIT_Y); goalPos += orient * xyz; } break; case CAM_ExtAng: /* 4 Extended Angle - car in center, angle smooth */ { Quaternion orient = orientGoal * qR; Quaternion ory; ory.FromAngleAxis(orient.getYaw(), Vector3::UNIT_Y); if (first) { qq = ory; } else qq = orient.Slerp(ca->mSpeed * time, qq, ory, true); // smooth dist from vel #if 0 { if (first) { mPosNodeOld = posGoal; } Real vel = (posGoal - mPosNodeOld).length() / std::max(0.002f, std::min(0.1f, time)); mPosNodeOld = posGoal; if (first) mVel = 0.f; else mVel += (vel - mVel) * time * 8.f; //par- vel smooth speed if (!first) xyz *= 1.f + std::min(100.f, mVel) * 0.01f; //par- vel dist factor } #endif Quaternion qy = Quaternion(ca->mYaw,Vector3(0,1,0)); goalPos += qq * (xyz + ca->mOffset); camPosFinal = goalPos; camRotFinal = qq * qy * Quaternion(Degree(-ca->mPitch - mATilt), Vector3(1,0,0)); manualOrient = true; } break; } if (!manualOrient) // if !CAM_ExtAng { float dtmul = ca->mSpeed == 0 ? 1.0f : ca->mSpeed * time; if (ca->mType == CAM_Arena) { Vector3 Pos(0,0,0), goalPos = ca->mOffset; Pos = camPosFinal; //read last state (smooth) Pos += (goalPos - Pos) * dtmul; mAPitch += (ca->mPitch - mAPitch) * dtmul; mAYaw += (ca->mYaw - mAYaw) * dtmul; if (first) { Pos = goalPos; mAPitch = ca->mPitch; mAYaw = ca->mYaw; } camPosFinal = Pos; camRotFinal = Quaternion(Degree(mAYaw),Vector3(0,1,0)) * Quaternion(Degree(mAPitch),Vector3(1,0,0)); manualOrient = true; } else { if (first) pos = goalPos; Vector3 addPos,addLook; addPos = (goalPos - pos).normalisedCopy() * (goalPos - pos).length() * dtmul; if (addPos.squaredLength() > (goalPos - pos).squaredLength()) addPos = goalPos - pos; pos += addPos; camPosFinal = pos + ofs; goalLook = posGoal + ofs; if (first) { mLook = goalLook; } addLook = (goalLook - mLook) * dtmul;//Rot; mLook += addLook; } } //camLookFinal = mLook; if (!manualOrient) // CAM_Free or CAM_Follow { Vector3 zdir = camPosFinal - mLook; zdir.normalise(); Vector3 xVec = Vector3::UNIT_Y.crossProduct(zdir); xVec.normalise(); Vector3 yVec = zdir.crossProduct(xVec); yVec.normalise(); Quaternion q; q.FromAxes(xVec, yVec, zdir); camRotFinal = q; } // cast ray from car to camera, reduce dist if hit //------------------------------------------------------------------------------------------- Vector3 pp = camPosFinal; if (bounce) pp += posIn.camOfs * ca->mOfsMul * gPar.camBncScale * pSet->cam_bnc_mul; Vector3 p = posGoal; p.y += 1.f; //up //Vector3 d = camRotFinal * Vector3::UNIT_Z; d.normalise(); Vector3 d = pp - p; d.normalise(); if (!first && ca->mType != CAM_Arena) { MATHVECTOR<float,3> pos1(p.x,-p.z,p.y), dir(d.x,-d.z,d.y); //dir = dir.Normalize(); COLLISION_CONTACT ct; float maxLen = (p - pp).length(); //cam near world->CastRay(pos1, dir, maxLen,chassis, ct, 0,0, true, true, true/*+*/); //dbgLen = -maxLen; if (ct.GetColObj()) { float len = ct.GetDepth(); //dbgLen = len; len -= 0.2f + ct.GetNormal()[2]; ///par normal up, flat terrain, move closer if (len < maxLen) { Real dist = maxLen - len; if (dist > mDistReduce) mDistReduce = dist; } } } // save result in out posInfo posOut->camPos = mDistReduce > 0.0001f ? (pp - d * mDistReduce) : pp; posOut->camRot = camRotFinal; // smooth, back to normal dist if (mDistReduce > 0.f) mDistReduce -= time * 10.f; }
//----------------------------------------------------------------------- void Camera::setDirection(const Vector3& vec) { // Do nothing if given a zero vector // (Replaced assert since this could happen with auto tracking camera and // camera passes through the lookAt point) if (vec == Vector3::ZERO) return; // Remember, camera points down -Z of local axes! // Therefore reverse direction of direction vector before determining local Z Vector3 zAdjustVec = -vec; zAdjustVec.normalise(); Quaternion targetWorldOrientation; if( mYawFixed ) { Vector3 xVec = mYawFixedAxis.crossProduct( zAdjustVec ); xVec.normalise(); Vector3 yVec = zAdjustVec.crossProduct( xVec ); yVec.normalise(); targetWorldOrientation.FromAxes( xVec, yVec, zAdjustVec ); } else { // Get axes from current quaternion Vector3 axes[3]; updateView(); mRealOrientation.ToAxes(axes); Quaternion rotQuat; if ( (axes[2]+zAdjustVec).squaredLength() < 0.00005f) { // Oops, a 180 degree turn (infinite possible rotation axes) // Default to yaw i.e. use current UP rotQuat.FromAngleAxis(Radian(Math::PI), axes[1]); } else { // Derive shortest arc to new direction rotQuat = axes[2].getRotationTo(zAdjustVec); } targetWorldOrientation = rotQuat * mRealOrientation; } // transform to parent space if (mParentNode) { mOrientation = mParentNode->_getDerivedOrientation().Inverse() * targetWorldOrientation; } else { mOrientation = targetWorldOrientation; } // TODO If we have a fixed yaw axis, we mustn't break it by using the // shortest arc because this will sometimes cause a relative yaw // which will tip the camera invalidateView(); }
/// Default shadow camera setup implementation void DefaultShadowCameraSetup::getShadowCamera (const SceneManager *sm, const Camera *cam, const Viewport *vp, const Light *light, Camera *texCam, size_t iteration) const { Vector3 pos, dir; // reset custom view / projection matrix in case already set texCam->setCustomViewMatrix(false); texCam->setCustomProjectionMatrix(false); texCam->setNearClipDistance(light->_deriveShadowNearClipDistance(cam)); texCam->setFarClipDistance(light->_deriveShadowFarClipDistance(cam)); // get the shadow frustum's far distance Real shadowDist = light->getShadowFarDistance(); if (!shadowDist) { // need a shadow distance, make one up shadowDist = cam->getNearClipDistance() * 300; } Real shadowOffset = shadowDist * (sm->getShadowDirLightTextureOffset()); // Directional lights if (light->getType() == Light::LT_DIRECTIONAL) { // set up the shadow texture // Set ortho projection texCam->setProjectionType(PT_ORTHOGRAPHIC); // set ortho window so that texture covers far dist texCam->setOrthoWindow(shadowDist * 2, shadowDist * 2); // Calculate look at position // We want to look at a spot shadowOffset away from near plane // 0.5 is a little too close for angles Vector3 target = cam->getDerivedPosition() + (cam->getDerivedDirection() * shadowOffset); // Calculate direction, which same as directional light direction dir = - light->getDerivedDirection(); // backwards since point down -z dir.normalise(); // Calculate position // We want to be in the -ve direction of the light direction // far enough to project for the dir light extrusion distance pos = target + dir * sm->getShadowDirectionalLightExtrusionDistance(); // Round local x/y position based on a world-space texel; this helps to reduce // jittering caused by the projection moving with the camera // Viewport is 2 * near clip distance across (90 degree fov) //~ Real worldTexelSize = (texCam->getNearClipDistance() * 20) / vp->getActualWidth(); //~ pos.x -= fmod(pos.x, worldTexelSize); //~ pos.y -= fmod(pos.y, worldTexelSize); //~ pos.z -= fmod(pos.z, worldTexelSize); Real worldTexelSize = (shadowDist * 2) / texCam->getViewport()->getActualWidth(); //get texCam orientation Vector3 up = Vector3::UNIT_Y; // Check it's not coincident with dir if (Math::Abs(up.dotProduct(dir)) >= 1.0f) { // Use camera up up = Vector3::UNIT_Z; } // cross twice to rederive, only direction is unaltered Vector3 left = dir.crossProduct(up); left.normalise(); up = dir.crossProduct(left); up.normalise(); // Derive quaternion from axes Quaternion q; q.FromAxes(left, up, dir); //convert world space camera position into light space Vector3 lightSpacePos = q.Inverse() * pos; //snap to nearest texel lightSpacePos.x -= fmod(lightSpacePos.x, worldTexelSize); lightSpacePos.y -= fmod(lightSpacePos.y, worldTexelSize); //convert back to world space pos = q * lightSpacePos; } // Spotlight else if (light->getType() == Light::LT_SPOTLIGHT) { // Set perspective projection texCam->setProjectionType(PT_PERSPECTIVE); // set FOV slightly larger than the spotlight range to ensure coverage Radian fovy = light->getSpotlightOuterAngle()*1.2; // limit angle if (fovy.valueDegrees() > 175) fovy = Degree(175); texCam->setFOVy(fovy); // Calculate position, which same as spotlight position pos = light->getDerivedPosition(); // Calculate direction, which same as spotlight direction dir = - light->getDerivedDirection(); // backwards since point down -z dir.normalise(); } // Point light else { // Set perspective projection texCam->setProjectionType(PT_PERSPECTIVE); // Use 120 degree FOV for point light to ensure coverage more area texCam->setFOVy(Degree(120)); // Calculate look at position // We want to look at a spot shadowOffset away from near plane // 0.5 is a little too close for angles Vector3 target = cam->getDerivedPosition() + (cam->getDerivedDirection() * shadowOffset); // Calculate position, which same as point light position pos = light->getDerivedPosition(); dir = (pos - target); // backwards since point down -z dir.normalise(); } // Finally set position texCam->setPosition(pos); // Calculate orientation based on direction calculated above /* // Next section (camera oriented shadow map) abandoned // Always point in the same direction, if we don't do this then // we get 'shadow swimming' as camera rotates // As it is, we get swimming on moving but this is less noticeable // calculate up vector, we want it aligned with cam direction Vector3 up = cam->getDerivedDirection(); // Check it's not coincident with dir if (up.dotProduct(dir) >= 1.0f) { // Use camera up up = cam->getUp(); } */ Vector3 up = Vector3::UNIT_Y; // Check it's not coincident with dir if (Math::Abs(up.dotProduct(dir)) >= 1.0f) { // Use camera up up = Vector3::UNIT_Z; } // cross twice to rederive, only direction is unaltered Vector3 left = dir.crossProduct(up); left.normalise(); up = dir.crossProduct(left); up.normalise(); // Derive quaternion from axes Quaternion q; q.FromAxes(left, up, dir); texCam->setOrientation(q); }