#include "StdAfx.h" #include "Camera.h" #include "ClientApp.h" #include "ClientState.h" #include "Player.h" #include "ObjectManager.h" #include "Map/Map.h" #include "UI/UChat.h" #include "UI/UIGamePlay.h" #include "Console.h" #include "PlayerInputMgr.h" #include "Skill/SpellProcess.h" #define LOCKVIEW_ANGLE ((NI_PI/180)*30) #define CAMERA_MOVE_SPEED 0.40f bool g_bRoteXY = false; CGameObject* pCamMouseObj = NULL; CCamera::CCamera(void) { m_bDithering = FALSE; m_count = 0; m_fCamDist = 17.0f; m_fDesirdCamDist = m_fCamDist; m_fDeltaZoomIn = 0.0f; m_kLButtonPos = NiPoint3(m_fCamDist, 0, m_fCamDist*0.5f); m_kRButtonPos = NiPoint3(m_fCamDist, 0, m_fCamDist*0.5f); m_pkLocalPos = &m_kRButtonPos; m_bLockView = FALSE; m_bLButtonDown = FALSE; m_bRButtonDown = FALSE; m_fMaxCameraDist = 22.f; m_fOffSetAngle = 0.0f; m_fAngleValue = 0.0f; m_fLastiX = 0.0f; m_eyeHight = Eye_OffSet; m_bForceRotate = false; m_fShakingTime = 0.0f; float width = (float)GetSystemMetrics( SM_CXSCREEN ); float f = 1024.f / width; SYState()->Camera_Move_Speed = CAMERA_MOVE_SPEED * f; m_fLastFacing = 0.0f; m_bAutoRotCamera = true; } CCamera::~CCamera(void) { if (m_count) { m_count--; SYState()->ClientApp->ShowPointer(); } } void CCamera::Reset() { float fFov = ClientState->GetCamFOV(); float fFar = ClientState->GetCamFarDist(); float fNear = ClientState->GetCamNearDist(); float fAspectRatio = 1.0f; NiRenderer* Render = SYState()->Render; if (Render) { Ni2DBuffer* pkBackbuffer = Render->GetDefaultBackBuffer(); fAspectRatio = (float)pkBackbuffer->GetWidth() / (float)pkBackbuffer->GetHeight(); } else { NiAppWindow* pWindow = SYState()->ClientApp->GetAppWindow(); NIASSERT(pWindow); fAspectRatio = (float)pWindow->GetWidth() / (float)pWindow->GetHeight(); } // Setup the camera frustum and viewport float fVerticalFieldOfViewRad = NI_PI / 180.0f * fFov; float fViewPlaneHalfHeight = tanf(fVerticalFieldOfViewRad * 0.5f); float fViewPlaneHalfWidth = fViewPlaneHalfHeight * fAspectRatio; NiFrustum kFrustum = NiFrustum( -fViewPlaneHalfWidth, fViewPlaneHalfWidth, fViewPlaneHalfHeight, -fViewPlaneHalfHeight, fNear, fFar); NiRect kPort(0.0f, 1.0f, 1.0f, 0.0f); m_NiCamera.SetViewFrustum(kFrustum); m_NiCamera.SetViewPort(kPort); } void CCamera::SetDefault() { Reset(); NiPoint3 kTranslation(0.0f, 1.0f, 0.0f); NiPoint3 kLook = NiPoint3::ZERO - kTranslation; kLook.Unitize(); NiPoint3 kLookTangent = kLook.Cross(NiPoint3::UNIT_Z); kLookTangent.Unitize(); NiPoint3 kLookBiTangent = kLookTangent.Cross(kLook); NiMatrix3 kRotation(kLook, kLookBiTangent, kLookTangent); NiMatrix3 kRotX; NiMatrix3 kRotZ; kRotX.MakeXRotation(-NI_HALF_PI); kRotZ.MakeZRotation(NI_HALF_PI); m_NiCamera.SetRotate(kRotZ * kRotX); m_NiCamera.SetTranslate(kTranslation); m_NiCamera.Update(0.0f); m_fCamPitch = 0.0f; m_fCamYaw = 0.0f; m_fCamDist = 17.0f; m_fZoomSpeed = 2.0f; m_fAcc = 5.0f; m_fMaxCameraDist = 22.f; } void CCamera::SetTransform(const NiTransform& xform) { m_NiCamera.SetTranslate(xform.m_Translate); m_NiCamera.SetRotate(xform.m_Rotate); m_NiCamera.Update(0.0f); //HACK } void CCamera::Shaking( float fTime, float amplitude, float period ) { m_fShakingTime = fTime; Dither(amplitude, period); } void CCamera::Dither(float amplitude, float period) { m_bDithering = TRUE; m_fNoiseSeed = NiApplication::ms_pkApplication->GetAccumTime(); m_fDitherTime = 0.0f; m_fInitAmp = amplitude; m_fDitherPeriod = period; } uint32 uiLastMovementFlags = 0; void CCamera::UpdateBindingCharacterInput() { CPlayerLocal* pkPlayer = ObjectMgr->GetLocalPlayer(); NIASSERT(pkPlayer); uint32 uiMovementFlags = pkPlayer->GetMovementFlags(); float fCurMoveAngle, fLastMoveAngle; fCurMoveAngle = pkPlayer->GetDesiredAngle(); fLastMoveAngle = pkPlayer->GetLastDesirdAngle(); float fTime = SYState()->ClientApp->GetAccumTime(); if( pkPlayer->GetDesiredAngle() != pkPlayer->GetLastDesirdAngle() && !pkPlayer->IsMoving() ) { if( fTime - pkPlayer->GetLastSendMovementTime() > 0.35 ) { pkPlayer->SetSendMovementDuration(0.5f); pkPlayer->SetLastSendMovementTime(fTime); pkPlayer->SetLastMovementFlags(uiMovementFlags); pkPlayer->SendMovementPacket( MOVE_SET_FACING ); pkPlayer->SetLastDesiredAngle(fCurMoveAngle); } } if( !pkPlayer->IsPathMove() ) { NiPoint3 kDir = m_NiCamera.GetWorldDirection(); NiPoint2 moveDir = NiPoint2(0, 0); if ( (m_bRButtonDown ) && !pCamMouseObj) //如果锁定视角 { //if ( uiMovementFlags & MOVEFLAG_MOVE_FORWARD ) moveDir.y = -1; if ( !(uiMovementFlags & MOVEFLAG_MOVE_FORWARD) && ( uiMovementFlags & MOVEFLAG_STRAFE_LEFT || uiMovementFlags & MOVEFLAG_STRAFE_RIGHT) ) moveDir.y = 0; } else { if ( !(uiMovementFlags & (MOVEFLAG_MOVING_MASK | MOVEFLAG_TURNING_MASK | MOVEFLAG_STRAFING_MASK)) ) { uiLastMovementFlags = uiMovementFlags; return ; } } if ( pkPlayer->IsDead() ) { uiLastMovementFlags = uiMovementFlags; return; } if ( SYState()->LocalPlayerInput->IsMoveLocked() ) { uiLastMovementFlags = uiMovementFlags; return; } if (uiMovementFlags & MOVEFLAG_MOVE_FORWARD) { moveDir.y = -1.0f; } else if (uiMovementFlags & MOVEFLAG_MOVE_BACKWARD) { moveDir.y = 1.0f; } if (uiMovementFlags & MOVEFLAG_STRAFE_LEFT) { moveDir.x = 1.0f; } else if (uiMovementFlags & MOVEFLAG_STRAFE_RIGHT) { moveDir.x = -1.0f; } NiPoint2 kForward = NiPoint2(kDir.x, kDir.y); moveDir.Unitize(); float fZ = 0.0f; if ( m_fOffSetAngle != 0.0f && !m_bRButtonDown ) fZ = m_fLastFacing; else { fZ = NiATan2(-kDir.y, kDir.x) - NI_PI/2; } fZ += NiATan2(-moveDir.y, moveDir.x) - NI_PI/2; while( fZ < 0.f ) fZ += NI_TWO_PI; while( fZ > NI_TWO_PI ) fZ -= NI_TWO_PI; if ( uiLastMovementFlags != uiMovementFlags ) { pkPlayer->SetDesiredAngle(fZ); } if ( m_bRButtonDown ) { pkPlayer->SetDesiredAngle(fZ); } } uiLastMovementFlags = uiMovementFlags; } bool CCamera::SetRotateXY(float fX, float fY) { if ( fX != 0.0f ) { g_bRoteXY = true; m_bRButtonDown = true; } else g_bRoteXY = false; HandleInput(m_fDeltaTime, (int)fX, 0, 0, TRUE); m_NiCamera.Update(0.0f,false); return true; } void CCamera::LookAt(NiPoint3 kEyePos, NiPoint3 kLookAt) { NiPoint3 kWorldUp(0.0, 0.0, 1.0f); NiPoint3 kDir = kEyePos - kLookAt; kDir.Unitize(); NiPoint3 kRight = kWorldUp.UnitCross(kDir); NiPoint3 kUp = kDir.UnitCross(kRight); NiMatrix3 kRot = NiMatrix3(-kDir, kUp, kRight); m_NiCamera.SetRotate( kRot ); } void CCamera::SetAutoRotCamera(BOOL bRot) { m_bAutoRotCamera = bRot; } void CCamera::LockView(BOOL bLock) { //先计算出相机的新位置 m_bLockView = bLock; } void CCamera::LookPlayer() { //琐定相机到人物身后 CPlayerLocal* pkPlayer = ObjectMgr->GetLocalPlayer(); NiPoint3 kPlayerPos = pkPlayer->GetLocalPlayerPos(); NiMatrix3 kMat = pkPlayer->GetMatrixRotate(); NiPoint3 kDir = pkPlayer->GetRotate(); NiMatrix3 kNewMat; kNewMat.MakeIdentity(); kNewMat.MakeZRotation( kDir.z ); kNewMat.GetCol(1, kDir); //kDir = -kDir; /*NiPoint3 kCameraPos = kPlayerPos + kDir * m_fCamDist; kCameraPos.z += 30.0f;*/ kDir.Unitize(); kDir.z += 0.5f; kDir.Unitize(); //m_kLButtonPos = kCameraPos; m_kLButtonPos = kDir; m_kRButtonPos = m_kLButtonPos; m_pkLocalPos = &m_kLButtonPos; m_bLButtonDown = true; //LookAt(kCameraPos, kPlayerPos); // } bool CCamera::IsInWater() { CMap* pkMap = CMap::Get(); if ( pkMap ) { if ( !pkMap->GetWaterFlag(m_kTranslate.x, m_kTranslate.y) ) return false; float fHight = pkMap->GetWaterHeight(m_kTranslate.x, m_kTranslate.y); if ( fHight > m_kTranslate.z ) return true; } return false; } void CCamera::NewUpdate(float dt) { NiInputSystem* pkInput = SYState()->Input; NIASSERT(pkInput); NiInputMouse* pkMouse = pkInput->GetMouse(); NIASSERT(pkMouse); CPlayerLocal* pkPlayer = ObjectMgr->GetLocalPlayer(); NiInputErr err = pkMouse->GetLastError(); if (err != NIIERR_OK) { for (unsigned int ui = NiInputMouse::NIM_LEFT; ui < NiInputMouse::NIM_NUM_BUTTONS; ui++) { pkMouse->RecordButtonRelease((NiInputMouse::Button)ui); } if (m_count) { m_count--; SYState()->ClientApp->ShowPointer(); } } // Poll the axis positions int iX; int iY; int iZ; if(UInGame::Get()) { if ( m_count ) { m_bRButtonDown = pkMouse->ButtonIsDown(NiInputMouse::NIM_RIGHT); m_bLButtonDown = pkMouse->ButtonIsDown(NiInputMouse::NIM_LEFT); } else { m_bRButtonDown = pkMouse->ButtonIsDown(NiInputMouse::NIM_RIGHT) && UInGame::Get()->IsMouseDown(NiInputMouse::NIM_RIGHT); m_bLButtonDown = pkMouse->ButtonIsDown(NiInputMouse::NIM_LEFT) && UInGame::Get()->IsMouseDown(NiInputMouse::NIM_LEFT); } } else { m_bRButtonDown = pkMouse->ButtonIsDown(NiInputMouse::NIM_RIGHT); m_bLButtonDown = pkMouse->ButtonIsDown(NiInputMouse::NIM_LEFT); } pCamMouseObj = SYState()->LocalPlayerInput->GetLastTargetObject(); CPlayerInputMgr * InputMsg = SYState()->LocalPlayerInput; if ( InputMsg->IsUseMouseMove() ) { m_bLButtonDown = FALSE; } BOOL bIsButtonDown = FALSE; pkMouse->GetPositionDelta(iX, iY, iZ); if ( pCamMouseObj ) //鼠标上有对象 { if ( m_bLockView ) { //有对象,鼠标滑动并且按了左或右键后再隐藏 if(iX != 0 || iY != 0 || iZ != 0) { if(m_bRButtonDown ) { bIsButtonDown = TRUE; if (!m_count) { m_count++; SYState()->ClientApp->HidePointer(); GetCursorPos(&m_pt); } else { SetCursorPos(m_pt.x, m_pt.y); } } } } else { //有对象,鼠标滑动并且按了左或右键后再隐藏 if(iX != 0 || iY != 0 || iZ != 0) { if(m_bRButtonDown || m_bLButtonDown ) { bIsButtonDown = TRUE; if (!m_count) { m_count++; SYState()->ClientApp->HidePointer(); GetCursorPos(&m_pt); } else { SetCursorPos(m_pt.x, m_pt.y); } } } } } else //鼠标上没对象 { //按了左键或右键立即隐藏 if ( m_bLockView ) { if(m_bRButtonDown ) { if (!m_count) { m_count++; SYState()->ClientApp->HidePointer(); GetCursorPos(&m_pt); } else { SetCursorPos(m_pt.x, m_pt.y); } bIsButtonDown = TRUE; } } else { if(m_bRButtonDown || m_bLButtonDown ) { if (!m_count) { m_count++; SYState()->ClientApp->HidePointer(); GetCursorPos(&m_pt); } else { SetCursorPos(m_pt.x, m_pt.y); } bIsButtonDown = TRUE; } } //没对象 鼠标按下后立即隐藏 } HandleInput(dt, iX, iY,iZ, bIsButtonDown); if ( m_bLockView ) { if (!m_bRButtonDown&& m_count) { m_count--; SYState()->ClientApp->ShowPointer(); } } else { if (!m_bRButtonDown && !m_bLButtonDown && m_count) { m_count--; SYState()->ClientApp->ShowPointer(); } } if ( m_fShakingTime > 0.0f ) { m_fShakingTime -= dt; UpdateDitherOffset(dt); } m_NiCamera.Update(0.0f,false); pkPlayer->SetCameraVec( m_NiCamera.GetWorldDirection() ); } bool bCheckFlag = false; float GenerateAngleDir(NiPoint3 kRB, NiPoint3 kLB) //左边是正,右边是负 { CPlayerLocal* pkPlayer = ObjectMgr->GetLocalPlayer(); NIASSERT(pkPlayer); NiPoint3 kPlayerPos = pkPlayer->GetLocalPlayerPos(); NiPoint3 kUpDir = NiPoint3(0.0, 0.0, 1.0f); kPlayerPos.z = kRB.z = kLB.z = 0.0f; NiPoint3 kDirR = kPlayerPos - kRB; kDirR.Unitize(); NiPoint3 kNewDir = kDirR.Cross( kUpDir ); kNewDir.Unitize(); kNewDir = -kNewDir; NiPoint3 kDirL = kLB - kRB; kDirL.Unitize(); float fDot = kDirL.Dot( kNewDir ); return fDot; } float g_fCameraDisDelta = 0.0f; float g_fZoomStr = 0.0f; bool g_bCamIsColliding = false; float g_fTemp = 0.0f; float g_fCamZoomSpeed = 0.01f; float g_fDestDis = 17.0f; float g_fCurDis = 17.0f; float g_fZoomSpeed = 0.5f; float g_fDisLenth = 0.0f; void CCamera::HandleInput(float dt, int iX,int iY, int iZ, bool bRot) { CPlayerLocal* pkPlayer = ObjectMgr->GetLocalPlayer(); NIASSERT(pkPlayer); NiPoint3 kPlayerPos = pkPlayer->GetLocalPlayerPos(); NiAVObject* pNode = NULL; if ( pkPlayer->isInShapShift()) { pNode = pkPlayer->GetShapShiftNodeByName( "Dummy03" ); } if ( !pNode ) { pNode = pkPlayer->GetSceneNode()->GetObjectByName("Dummy03"); } CCharacter* pmount = pkPlayer->GetMountCreature(); if ( pNode /*&& pmount*/ ) { float CurPos = (pNode->GetWorldTranslate().z - 0.1f); kPlayerPos.z = CurPos; } else { kPlayerPos.z += Eye_OffSet; } NiMatrix3 mat = m_NiCamera.GetRotate(); // --------------------------------------- if ( m_bLockView ) { m_pkLocalPos = &m_kRButtonPos; } else { if ( m_bRButtonDown ) { if ( m_fOffSetAngle != 0.0f ) { m_kRButtonPos = m_kLButtonPos; } else m_kLButtonPos = m_kRButtonPos; m_pkLocalPos = &m_kRButtonPos; m_fOffSetAngle = 0.0f; m_fAngleValue = 0.0f; NiPoint3 kDir = m_NiCamera.GetWorldDirection(); m_fLastFacing = NiATan2(-kDir.y, kDir.x) - NI_PI/2; } else if ( m_bLButtonDown ) { //bCheckFlag = false; m_pkLocalPos = &m_kLButtonPos; } else //都没按下 { if ( m_fOffSetAngle != 0.0f ) { m_kRButtonPos = m_kLButtonPos; m_pkLocalPos = &m_kLButtonPos; } else { m_kLButtonPos = m_kRButtonPos; m_pkLocalPos = &m_kRButtonPos; } } } NiPoint3 kPos = *m_pkLocalPos; if ( m_bAutoRotCamera ) if ( m_fOffSetAngle != 0.0f && !m_bLButtonDown && pkPlayer->IsMoving() ) //如果弧度夹角不等于零,鼠标左键没按下, 并且人物在移动中 恢复夹角 { float fDX = m_fLastiX * dt * SYState()->Camera_Follow_Speed * 0.2; m_fAngleValue -= fDX; NiMatrix3 rot; rot.MakeIdentity(); rot.MakeZRotation(-fDX); kPos = rot * kPos; if ( fDX < 0.0f ) fDX = -fDX; m_fOffSetAngle -= fDX; if ( m_fOffSetAngle <= 0.0f ) { m_fOffSetAngle = 0.0f; m_fAngleValue = 0.0f; } } if (iX != 0 && bRot ) { float fDX = iX * dt * GetMouseMoveSpeed(iX); NiMatrix3 rot; rot.MakeIdentity(); rot.MakeZRotation(fDX*SYState()->Camera_Move_Speed); kPos = rot * kPos; m_fLastiX = 1.0f * 2.0f; if ( m_bLButtonDown && !m_bRButtonDown ) //如果左键按下,并且右键没按下 那么开始计算弧度夹角 { m_fAngleValue += fDX*SYState()->Camera_Move_Speed; if ( m_fAngleValue > 0.0f ) { if ( m_fAngleValue > NI_PI ) { m_fOffSetAngle = NI_PI - (m_fAngleValue - NI_PI); m_fLastiX = -m_fLastiX; //反转 } else { m_fOffSetAngle = m_fAngleValue; } } else { if ( m_fAngleValue < -NI_PI ) { m_fOffSetAngle = -NI_PI - (m_fAngleValue - (-NI_PI)); m_fOffSetAngle = -m_fOffSetAngle; } else { m_fOffSetAngle = -m_fAngleValue; m_fLastiX = -m_fLastiX; //反转 } } } } if ( iY != 0 && bRot && !m_bLockView) { float fDY = iY * dt * GetMouseMoveSpeed(iY); NiPoint3 kDirVector; mat.GetCol(0, kDirVector); NiPoint3 kUp = NiPoint3::UNIT_Z; float fDeltaY = fDY * SYState()->Camera_Move_Speed; if (((kUp.Dot(kDirVector) > 0.99f) && (fDY < 0.0f)) || ((kUp.Dot(kDirVector) < -0.99f) && (fDY > 0.0f))) { fDeltaY = 0.0f; } NiMatrix3 rot; NiPoint3 kRightVector; mat.GetCol(2, kRightVector); rot.MakeIdentity(); rot.MakeRotation(fDeltaY, kRightVector); kPos = rot * kPos; } NiPoint3 kCamWorldPos = kPos + kPlayerPos; NiPoint3 kNewDir = kCamWorldPos - kPlayerPos; kNewDir.Unitize(); //m_fCamDist = m_fDesirdCamDist; if ( m_fCamDist != m_fDesirdCamDist ) { g_fCameraDisDelta += dt*g_fCamZoomSpeed; if ( abs(m_fDesirdCamDist - m_fCamDist) < 0.1f ) m_fDesirdCamDist = m_fCamDist; m_fCamDist = NiLerp(g_fCameraDisDelta, m_fCamDist, m_fDesirdCamDist); } else { g_fCameraDisDelta = 0.0f; } //float fTT = NiClamp(dt, 0.0f, 1.0f); //char buff[MAX_PATH]; //sprintf(buff, "%f\n", fTT); //OutputDebugString(buff); if ( g_fCurDis != g_fDestDis ) { float fT = g_fDestDis - g_fCurDis; if ( fT > 0.0f ) { g_fCurDis += dt * 3.5f; if ( g_fCurDis > g_fDestDis ) g_fCurDis = g_fDestDis; } else { g_fCurDis -= dt * 3.5f; if ( g_fCurDis < g_fDestDis ) g_fCurDis = g_fDestDis; } } kCamWorldPos = kNewDir * g_fCurDis + kPlayerPos; LookAt( kCamWorldPos, kPlayerPos); CMap* pkMap = CMap::Get(); static const NiPoint3 kExtent = NiPoint3(0.3f, 0.3f, 0.3f); ResultList collrl; float fDis = 0.0f; pkMap->MultiCollideBox(kPlayerPos, kCamWorldPos, kExtent, collrl); if (collrl.size() > 0) { kCamWorldPos = kPlayerPos - (kPlayerPos - kCamWorldPos) * collrl[0].fTime; if ( !g_bCamIsColliding ) g_bCamIsColliding = true; g_fTemp = (kPlayerPos - kCamWorldPos).Length(); fDis = g_fTemp; } else { if ( g_bCamIsColliding ) { //恢复视角 g_fCurDis = g_fTemp; g_bCamIsColliding = false; g_fCamZoomSpeed = 0.001f; kCamWorldPos = kNewDir * g_fCurDis + kPlayerPos; } fDis = g_fCurDis; } BOOL bFirstPersonView = FALSE; //if ( fDis <= 3.0 ) // pkPlayer->SetAlpha( fDis / 3.0f ); //else // pkPlayer->SetAlpha(1.0f); if ( fDis <= 1.0f ) bFirstPersonView = TRUE; else bFirstPersonView = FALSE; pkPlayer->GetSceneNode()->SetAppCulled( bFirstPersonView ); m_NiCamera.SetTranslate(kCamWorldPos); m_kTranslate = kCamWorldPos; *m_pkLocalPos = kPos; } void CCamera::Update(float dt) { if( dt > (35.0f/1000.0f) ) dt = (35.0f/1000.0f); m_fDeltaTime = dt; NewUpdate(dt); } float CCamera::GetMouseMoveSpeed(int delta) { int value = abs(delta); int iLevel = 0; if ( value > 0 && value <= 10 ) { iLevel = 0; } else if ( value > 10 && value <= 25 ) { iLevel = 1; } else if ( value > 25 && value <= 50 ) { iLevel = 2; } else if ( value > 50 && value <= 70 ) { iLevel = 3; } else if ( value > 70 ) { iLevel = 4; } float speed = 0.09f; switch (iLevel) { case 0: speed = 0.09f; break; case 1: speed = 0.15f; break; case 2: speed = 0.20f; break; case 3: speed = 0.22f; break; case 4: speed = 0.25f; break; } return speed; } namespace perlinnoise2d { inline float Fade(float T) { return T * T * T * (T * (T * 6 - 15) + 10); } inline float Lerp( float a, float b, float t) { return a + t * (b - a); } // seeded static int Permutations[256] = { 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, 8,99,37,240,21,10,23, 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; float Grad(INT hash,float x, float y) { INT H = hash & 15; float U = H < 8 || H == 12 || H == 13 ? x : y; float V = H < 4 || H == 12 || H == 13 ? y : 0; return ((H & 1) == 0 ? U : -U) + ((H & 2) == 0 ? V : -V); } float Noise2D(float X,float Y) { INT TruncX = (int)(X), TruncY = (int)(Y), IntX = TruncX & 255, IntY = TruncY & 255; float FracX = X - TruncX, FracY = Y - TruncY; float U = Fade(FracX), V = Fade(FracY); INT A = Permutations[IntX] + IntY, AA = Permutations[A & 255], AB = Permutations[(A + 1) & 255], B = Permutations[(IntX + 1) & 255] + IntY, BA = Permutations[B & 255], BB = Permutations[(B + 1) & 255]; return Lerp( Lerp( Grad(Permutations[AA], FracX, FracY ), Grad(Permutations[BA], FracX-1,FracY ), U), Lerp( Grad(Permutations[AB], FracX, FracY-1 ), Grad(Permutations[BB], FracX-1,FracY-1 ), U), V); } } void CCamera::UpdateDitherOffset(float dt) { // use noise would be better. NiPoint3 OldPos = m_NiCamera.GetTranslate(); #if 1 // NOTE: 1d noise 会更有效率, 但是不能在XOZ平面生成较为连续的散列. 因此采用2D NOISE, 分别在 XZ, ZX 处采样. m_fDitherTime += dt; static const float xSpeed = 1.0f; // NOISE 激荡系数 static const float zSpeed = 6.0f; // 60.0f float nx = m_fDitherTime * xSpeed * m_fNoiseSeed ; float nz = m_fDitherTime * zSpeed * m_fNoiseSeed; float ofsx = m_fInitAmp * perlinnoise2d::Noise2D(nx, nz); // 考虑采取幂函数放大, 让曲线变得更加尖锐 // ofsx = powf(ofsx, Sharpness); float ofsz = m_fInitAmp * perlinnoise2d::Noise2D(nz, nx); OldPos.x += ofsx; OldPos.z += ofsz; if (m_fDitherTime > m_fDitherPeriod) { m_bDithering = FALSE; } #else // 采用阻尼震动不太好控制周期,容易出现过阻尼情况, 导致偏移量很规则. const float k = 0.2f; m_fDitherTime += dt; float fAmp = m_fInitAmp*powf(1.1f, - 2.0f *m_fDitherTime); if (fAmp <= 0.01f) { m_bDithering = FALSE; return; } float xt = fAmp * NiCos( m_fDitherTime); OldPos.z += xt; #endif m_NiCamera.SetTranslate(OldPos); } void CCamera::UpdateFrustumPlanes() { m_kPlanes.Set(m_NiCamera.GetViewFrustum(), m_NiCamera.GetWorldTransform()); } bool CCamera::TestVisible(const NiBound& kBound) { // Determine if the object is not visible by comparing its world // bound to each culling plane. unsigned int ui; for(ui = 0; ui < NiFrustumPlanes::MAX_PLANES; ui++) { int iSide = kBound.WhichSide( m_kPlanes.GetPlane(ui)); if(iSide == NiPlane::NEGATIVE_SIDE) { // The object is not visible since it is on the negative // side of the plane. break; } } if(ui == NiFrustumPlanes::MAX_PLANES) return true; return false; } void CCamera::SetCameraZ(int iz) { if(iz != 0) { iz *= 120; BOOL bFirstPersonView = FALSE; g_fDisLenth += (float)iz * 0.003f * m_fZoomSpeed; g_fZoomSpeed += iz * 0.03f; g_fZoomSpeed = abs(g_fZoomSpeed); g_fDestDis -= (float)iz * 0.006f * m_fZoomSpeed; if(g_fDestDis < 0.2f) g_fDestDis = 0.2f; if(g_fDestDis > m_fMaxCameraDist) g_fDestDis = m_fMaxCameraDist; } }