//! renders the node. void COctTreeSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); if (vertexType == -1 || !driver) return; ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera) return; bool isTransparentPass = SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; ++PassCount; driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); SViewFrustum frust = *camera->getViewFrustum(); //transform the frustum to the current absolute transformation core::matrix4 invTrans(AbsoluteTransformation); invTrans.makeInverse(); /* //frust.transform(invTrans); //const core::aabbox3d<float> &box = frust.getBoundingBox(); */ frust.transform(invTrans); switch(vertexType) { case video::EVT_STANDARD: { //StdOctTree->calculatePolys(box); StdOctTree->calculatePolys(frust); OctTree<video::S3DVertex>::SIndexData* d = StdOctTree->getIndexData(); for (u32 i=0; i<Materials.size(); ++i) { if ( 0 == d[i].CurrentSize ) continue; video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType); bool transparent = (rnd && rnd->isTransparent()); // only render transparent buffer if this is the transparent render pass // and solid only in solid pass if (transparent == isTransparentPass) { driver->setMaterial(Materials[i]); driver->drawIndexedTriangleList( &StdMeshes[i].Vertices[0], StdMeshes[i].Vertices.size(), d[i].Indices, d[i].CurrentSize / 3); } } // for debug purposes only if ( DebugDataVisible && !Materials.empty() && PassCount==1) { const core::aabbox3d<float> &box = frust.getBoundingBox(); core::array< core::aabbox3d<f32> > boxes; video::SMaterial m; m.Lighting = false; driver->setMaterial(m); if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS ) { StdOctTree->renderBoundingBoxes(box, boxes); for (u32 b=0; b<boxes.size(); ++b) driver->draw3DBox(boxes[b], video::SColor(0,255,255,255)); } if ( DebugDataVisible & scene::EDS_BBOX ) driver->draw3DBox(Box,video::SColor(0,255,0,0)); } break; } case video::EVT_2TCOORDS: { //LightMapOctTree->calculatePolys(box); LightMapOctTree->calculatePolys(frust); OctTree<video::S3DVertex2TCoords>::SIndexData* d = LightMapOctTree->getIndexData(); for (u32 i=0; i<Materials.size(); ++i) { if ( 0 == d[i].CurrentSize ) continue; video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType); bool transparent = (rnd && rnd->isTransparent()); // only render transparent buffer if this is the transparent render pass // and solid only in solid pass if (transparent == isTransparentPass) { driver->setMaterial(Materials[i]); driver->drawIndexedTriangleList( &LightMapMeshes[i].Vertices[0], LightMapMeshes[i].Vertices.size(), d[i].Indices, d[i].CurrentSize / 3); } } // for debug purposes only if (DebugDataVisible && !Materials.empty() && PassCount==1) { const core::aabbox3d<float> &box = frust.getBoundingBox(); core::array< core::aabbox3d<f32> > boxes; video::SMaterial m; m.Lighting = false; driver->setMaterial(m); if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS ) { LightMapOctTree->renderBoundingBoxes(box, boxes); for (u32 b=0; b<boxes.size(); ++b) driver->draw3DBox(boxes[b], video::SColor(0,255,255,255)); } if ( DebugDataVisible & scene::EDS_BBOX ) driver->draw3DBox(Box,video::SColor(0,255,0,0)); } } break; } }
void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, UINT32 timeMs) { if (!node || node->getType() != ESNT_CAMERA) return; ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); if (firstUpdate) { camera->updateAbsolutePosition(); if (CursorControl) { CursorControl->setPosition(0.5f, 0.5f); CursorPos = CenterCursor = CursorControl->getRelativePosition(); } LastAnimationTime = timeMs; firstUpdate = false; } // If the camera isn't the active camera, and receiving input, then don't process it. if (!camera->isInputReceiverEnabled()) { firstInput = true; return; } if (firstInput) { allKeysUp(); firstInput = false; } ISceneManager * smgr = camera->getSceneManager(); if (smgr && smgr->getActiveCamera() != camera) return; // get time FLOAT32 timeDiff = (FLOAT32)(timeMs - LastAnimationTime); LastAnimationTime = timeMs; // update position Vector3 pos = camera->getPosition(); // Update rotation Vector3 target = (camera->getTarget() - camera->getAbsolutePosition()); Vector3 relativeRotation = target.getHorizontalAngle(); if (CursorControl) { if (CursorPos != CenterCursor) { relativeRotation.y -= (0.5f - CursorPos.x) * RotateSpeed; relativeRotation.x -= (0.5f - CursorPos.y) * RotateSpeed * MouseYDirection; // X < MaxVerticalAngle or X > 360-MaxVerticalAngle if (relativeRotation.x > MaxVerticalAngle * 2 && relativeRotation.x < 360.0f - MaxVerticalAngle) { relativeRotation.x = 360.0f - MaxVerticalAngle; } else if (relativeRotation.x > MaxVerticalAngle && relativeRotation.x < 360.0f - MaxVerticalAngle) { relativeRotation.x = MaxVerticalAngle; } // Do the fix as normal, special case below // reset cursor position to the centre of the window. CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); // needed to avoid problems when the event receiver is disabled CursorPos = CenterCursor; } // Special case, mouse is whipped outside of window before it can update. IVideoDriver* driver = smgr->getVideoDriver(); Vector2 mousepos(UINT32(CursorControl->getPosition().x), UINT32(CursorControl->getPosition().y)); rect<UINT32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height); // Only if we are moving outside quickly. bool reset = !screenRect.isPointInside(mousepos); if (reset) { // Force a reset. CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); CursorPos = CenterCursor; } } // set target target.set(0, 0, Math::_max<Real>(1.f, pos.length())); Vector3 movedir = target; Matrix4 mat; mat.setRotationDegrees(Vector3(relativeRotation.x, relativeRotation.y, 0)); //mat.transformVect(target); target = mat.transformAffine(target); if (NoVerticalMovement) { mat.setRotationDegrees(Vector3(0, relativeRotation.y, 0)); //mat.transformVect(movedir); target = mat.transformAffine(target); } else { movedir = target; } movedir.normalise(); if (CursorKeys[EKA_MOVE_FORWARD]) pos += movedir * timeDiff * MoveSpeed; if (CursorKeys[EKA_MOVE_BACKWARD]) pos -= movedir * timeDiff * MoveSpeed; // strafing Vector3 strafevect = target; strafevect = strafevect.crossProduct(camera->getUpVector()); if (NoVerticalMovement) strafevect.y = 0.0f; strafevect.normalise(); if (CursorKeys[EKA_STRAFE_LEFT]) pos += strafevect * timeDiff * MoveSpeed; if (CursorKeys[EKA_STRAFE_RIGHT]) pos -= strafevect * timeDiff * MoveSpeed; // For jumping, we find the collision response animator attached to our camera // and if it's not falling, we tell it to jump. if (CursorKeys[EKA_JUMP_UP]) { const ISceneNodeAnimatorList& animators = camera->getAnimators(); ISceneNodeAnimatorList::const_iterator it = animators.begin(); while (it != animators.end()) { if (ESNAT_COLLISION_RESPONSE == (*it)->getType()) { ISceneNodeAnimatorCollisionResponse * collisionResponse = static_cast<ISceneNodeAnimatorCollisionResponse *>(*it); if (!collisionResponse->isFalling()) collisionResponse->jump(JumpSpeed); } it++; } } // write translation camera->setPosition(pos); // write right target target += pos; camera->setTarget(target); }
//! render void CParticleSystemSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera || !driver) return; #if 0 // calculate vectors for letting particles look to camera core::vector3df view(camera->getTarget() - camera->getAbsolutePosition()); view.normalize(); core::vector3df horizontal = camera->getUpVector().crossProduct(view); horizontal.normalize(); horizontal *= 0.5f * ParticleSize.Width; core::vector3df vertical = horizontal.crossProduct(view); vertical.normalize(); vertical *= 0.5f * ParticleSize.Height; view *= -1.0f; #else const core::matrix4 &m = camera->getViewFrustum()->Matrices [ video::ETS_VIEW ]; f32 f; f = 0.5f * ParticleSize.Width; const core::vector3df horizontal ( m[0] * f, m[4] * f, m[8] * f ); f = -0.5f * ParticleSize.Height; const core::vector3df vertical ( m[1] * f, m[5] * f, m[9] * f ); const core::vector3df view ( -m[2], -m[6] , -m[10] ); #endif // reallocate arrays, if they are too small reallocateBuffers(); // create particle vertex data s32 idx = 0; for (u32 i=0; i<Particles.size(); ++i) { const SParticle& particle = Particles[i]; Buffer.Vertices[0+idx].Pos = particle.pos + horizontal + vertical; Buffer.Vertices[0+idx].Color = particle.color; Buffer.Vertices[0+idx].Normal = view; Buffer.Vertices[1+idx].Pos = particle.pos + horizontal - vertical; Buffer.Vertices[1+idx].Color = particle.color; Buffer.Vertices[1+idx].Normal = view; Buffer.Vertices[2+idx].Pos = particle.pos - horizontal - vertical; Buffer.Vertices[2+idx].Color = particle.color; Buffer.Vertices[2+idx].Normal = view; Buffer.Vertices[3+idx].Pos = particle.pos - horizontal + vertical; Buffer.Vertices[3+idx].Color = particle.color; Buffer.Vertices[3+idx].Normal = view; idx +=4; } // render all core::matrix4 mat; if (!ParticlesAreGlobal) mat.setTranslation(AbsoluteTransformation.getTranslation()); driver->setTransform(video::ETS_WORLD, mat); driver->setMaterial(Buffer.Material); driver->drawVertexPrimitiveList(Buffer.getVertices(), Particles.size()*4, Buffer.getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES); // for debug purposes only: if ( DebugDataVisible & scene::EDS_BBOX ) { driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); video::SMaterial deb_m; deb_m.Lighting = false; driver->setMaterial(deb_m); driver->draw3DBox(Buffer.BoundingBox, video::SColor(0,255,255,255)); } }
//! render void CBillboardSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera || !driver) return; // make billboard look to camera core::vector3df pos = getAbsolutePosition(); core::vector3df campos = camera->getAbsolutePosition(); core::vector3df target = camera->getTarget(); core::vector3df up = camera->getUpVector(); core::vector3df view = target - campos; view.normalize(); core::vector3df horizontal = up.crossProduct(view); if ( horizontal.getLength() == 0 ) { horizontal.set(up.Y,up.X,up.Z); } horizontal.normalize(); core::vector3df topHorizontal = horizontal * 0.5f * TopEdgeWidth; horizontal *= 0.5f * Size.Width; // pointing down! core::vector3df vertical = horizontal.crossProduct(view); vertical.normalize(); vertical *= 0.5f * Size.Height; view *= -1.0f; for (s32 i=0; i<4; ++i) vertices[i].Normal = view; /* Vertices are: 2--1 |\ | | \| 3--0 */ vertices[0].Pos = pos + horizontal + vertical; vertices[1].Pos = pos + topHorizontal - vertical; vertices[2].Pos = pos - topHorizontal - vertical; vertices[3].Pos = pos - horizontal + vertical; // draw if (DebugDataVisible & scene::EDS_BBOX) { driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); video::SMaterial m; m.Lighting = false; driver->setMaterial(m); driver->draw3DBox(BBox, video::SColor(0,208,195,152)); } driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); driver->setMaterial(Material); driver->drawIndexedTriangleList(vertices, 4, indices, 2); }
//! OnAnimate() is called just before rendering the whole scene. void CSceneNodeAnimatorCameraMaya::animateNode(ISceneNode *node, u32 timeMs) { //Alt + LM = Rotate around camera pivot //Alt + LM + MM = Dolly forth/back in view direction (speed % distance camera pivot - max distance to pivot) //Alt + MM = Move on camera plane (Screen center is about the mouse pointer, depending on move speed) if (!node || node->getType() != ESNT_CAMERA) return; ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); // If the camera isn't the active camera, and receiving input, then don't process it. if (!camera->isInputReceiverEnabled()) return; scene::ISceneManager * smgr = camera->getSceneManager(); if (smgr && smgr->getActiveCamera() != camera) return; if (OldCamera != camera) { LastCameraTarget = OldTarget = camera->getTarget(); OldCamera = camera; } else { OldTarget += camera->getTarget() - LastCameraTarget; } f32 nRotX = RotX; f32 nRotY = RotY; f32 nZoom = CurrentZoom; if ( (isMouseKeyDown(0) && isMouseKeyDown(2)) || isMouseKeyDown(1) ) { if (!Zooming) { ZoomStart = MousePos; Zooming = true; } else { const f32 targetMinDistance = 0.1f; nZoom += (ZoomStart.X - MousePos.X) * ZoomSpeed; if (nZoom < targetMinDistance) // jox: fixed bug: bounce back when zooming to close nZoom = targetMinDistance; } } else if (Zooming) { const f32 old = CurrentZoom; CurrentZoom = CurrentZoom + (ZoomStart.X - MousePos.X ) * ZoomSpeed; nZoom = CurrentZoom; if (nZoom < 0) nZoom = CurrentZoom = old; Zooming = false; } // Translation --------------------------------- core::vector3df translate(OldTarget); const core::vector3df upVector(camera->getUpVector()); const core::vector3df target = camera->getTarget(); core::vector3df pos = camera->getPosition(); core::vector3df tvectX = pos - target; tvectX = tvectX.crossProduct(upVector); tvectX.normalize(); const SViewFrustum* const va = camera->getViewFrustum(); core::vector3df tvectY = (va->getFarLeftDown() - va->getFarRightDown()); tvectY = tvectY.crossProduct(upVector.Y > 0 ? pos - target : target - pos); tvectY.normalize(); if (isMouseKeyDown(2) && !Zooming) { if (!Translating) { TranslateStart = MousePos; Translating = true; } else { translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed + tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed; } } else if (Translating) { translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed + tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed; OldTarget = translate; Translating = false; } // Rotation ------------------------------------ if (isMouseKeyDown(0) && !Zooming) { if (!Rotating) { RotateStart = MousePos; Rotating = true; nRotX = RotX; nRotY = RotY; } else { nRotX += (RotateStart.X - MousePos.X) * RotateSpeed; nRotY += (RotateStart.Y - MousePos.Y) * RotateSpeed; } } else if (Rotating) { RotX += (RotateStart.X - MousePos.X) * RotateSpeed; RotY += (RotateStart.Y - MousePos.Y) * RotateSpeed; nRotX = RotX; nRotY = RotY; Rotating = false; } // Set pos ------------------------------------ pos = translate; pos.X += nZoom; pos.rotateXYBy(nRotY, translate); pos.rotateXZBy(-nRotX, translate); camera->setPosition(pos); camera->setTarget(translate); // Rotation Error ---------------------------- // jox: fixed bug: jitter when rotating to the top and bottom of y pos.set(0,1,0); pos.rotateXYBy(-nRotY); pos.rotateXZBy(-nRotX+180.f); camera->setUpVector(pos); LastCameraTarget = camera->getTarget(); }
void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) { if (node->getType() != ESNT_CAMERA) return; ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); if (firstUpdate) { camera->updateAbsolutePosition(); if (CursorControl && camera) { CursorControl->setPosition(0.5f, 0.5f); CursorPos = CenterCursor = CursorControl->getRelativePosition(); } LastAnimationTime = timeMs; firstUpdate = false; } // get time f32 timeDiff = (f32) ( timeMs - LastAnimationTime ); LastAnimationTime = timeMs; // update position core::vector3df pos = camera->getPosition(); // Update rotation core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition()); core::vector3df relativeRotation = target.getHorizontalAngle(); if (CursorControl) { if (CursorPos != CenterCursor) { relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed; relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed; // X < MaxVerticalAngle or X > 360-MaxVerticalAngle if (relativeRotation.X > MaxVerticalAngle*2 && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = 360.0f-MaxVerticalAngle; } else if (relativeRotation.X > MaxVerticalAngle && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = MaxVerticalAngle; } // reset cursor position CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); // needed to avoid problems when the ecent receiver is // disabled CursorPos = CenterCursor; } } // set target target.set(0,0, core::max_(1.f, pos.getLength())); core::vector3df movedir = target; core::matrix4 mat; mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0)); mat.transformVect(target); if (NoVerticalMovement) { mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0)); mat.transformVect(movedir); } else { movedir = target; } movedir.normalize(); if (CursorKeys[EKA_MOVE_FORWARD]) pos += movedir * timeDiff * MoveSpeed; if (CursorKeys[EKA_MOVE_BACKWARD]) pos -= movedir * timeDiff * MoveSpeed; // strafing core::vector3df strafevect = target; strafevect = strafevect.crossProduct(camera->getUpVector()); if (NoVerticalMovement) strafevect.Y = 0.0f; strafevect.normalize(); if (CursorKeys[EKA_STRAFE_LEFT]) pos += strafevect * timeDiff * MoveSpeed; if (CursorKeys[EKA_STRAFE_RIGHT]) pos -= strafevect * timeDiff * MoveSpeed; // For jumping, we find the collision response animator attached to our camera // and if it's not falling, we tell it to jump. if (CursorKeys[EKA_JUMP_UP]) { const core::list<ISceneNodeAnimator*> & animators = camera->getAnimators(); core::list<ISceneNodeAnimator*>::ConstIterator it = animators.begin(); while(it != animators.end()) { if(ESNAT_COLLISION_RESPONSE == (*it)->getType()) { ISceneNodeAnimatorCollisionResponse * collisionResponse = static_cast<ISceneNodeAnimatorCollisionResponse *>(*it); if(!collisionResponse->isFalling()) collisionResponse->jump(JumpSpeed); } it++; } } // write translation camera->setPosition(pos); // write right target TargetVector = target; target += pos; camera->setTarget(target); }
void CBillboardGroupSceneNode::updateBillboards() { ICameraSceneNode* camera = SceneManager->getActiveCamera(); if ( !camera ) return; core::vector3df camPos = camera->getAbsolutePosition(); core::vector3df ref = core::vector3df(0,1,0); camera->getAbsoluteTransformation().rotateVect(ref); core::vector3df view, right, up; bool farAway = false; core::vector3df center = BoundingBox.getCenter(); AbsoluteTransformation.transformVect(center); core::vector3df camDir = camPos - center; if ( camDir.getLengthSQ() >= (FarDistance + Radius)*(FarDistance + Radius) ) { farAway = true; view = center - camPos; view.normalize(); right = ref.crossProduct( view ); up = view.crossProduct( right ); } core::vector3df rotatedCamDir = camDir; AbsoluteTransformation.inverseRotateVect( rotatedCamDir ); if ( farAway && (rotatedCamDir - LastCamDir).getLengthSQ() < 1000.0f ) { return; } LastCamDir = rotatedCamDir; // Update the position of every billboard for ( s32 i=0; i<Billboards.size(); i++ ) { if ( !farAway ) { core::vector3df pos = Billboards[i].Position; AbsoluteTransformation.transformVect( pos ); view = pos - camPos; view.normalize(); } core::vector3df thisRight = right; core::vector3df thisUp = up; if ( Billboards[i].HasAxis ) { core::vector3df axis = Billboards[i].Axis; AbsoluteTransformation.rotateVect(axis); thisRight = axis.crossProduct( view ); thisUp = axis; } else if ( !farAway ) { thisRight = ref.crossProduct( view ); thisUp = view.crossProduct( thisRight ); } f32 rollrad = Billboards[i].Roll * core::DEGTORAD; f32 cos_roll = cos( rollrad ); f32 sin_roll = sin( rollrad ); core::vector3df a = cos_roll * thisRight + sin_roll * thisUp; core::vector3df b = -sin_roll * thisRight + cos_roll * thisUp; a *= Billboards[i].Size.Width / 2.0f; b *= Billboards[i].Size.Height / 2.0f; s32 vertexIndex = 4 * i; // 4 vertices per billboard core::vector3df billPos = Billboards[i].Position; AbsoluteTransformation.transformVect(billPos); MeshBuffer.Vertices[vertexIndex ].Pos = billPos - a + b; MeshBuffer.Vertices[vertexIndex+1].Pos = billPos + a + b; MeshBuffer.Vertices[vertexIndex+2].Pos = billPos + a - b; MeshBuffer.Vertices[vertexIndex+3].Pos = billPos - a - b; } }