void CCameraInputHelper::Reset() { m_fYaw = 0.0f; m_fPitch = gf_PI*0.5f; m_fInputPitchDelta = 0.0f; m_fInputYawDelta = 0.0f; //reset interpolation m_fInterpolationTargetYaw = 0.0f; m_fInterpolationTargetPitch = 0.0f; m_bInterpolationTargetActive = false; m_fInterpolationTargetTimeout = 0.0f; //reset timer m_fLastUserInput = 0.0f; m_bAutoTracking = false; m_bNavCombatModeChanged = false; //reset tracking m_fTrackingYawDelta = 0.0f; m_fTrackingPitchDelta = 0.0f; //make sure reset is distributed m_bYawModified = true; m_bPitchModified = true; //make sure the direction is fixed SSpherical tmpSpherical; CartesianToSpherical(m_pHero->GetEntity()->GetForwardDir(), tmpSpherical); ForceCameraDirection(tmpSpherical.m_fYaw, tmpSpherical.m_fPitch, 0.3f); }
void CCameraInputHelper::SnapToPlayerDir() { //get target direction (player dir) Vec3 dir = m_pHero->GetEntity()->GetForwardDir(); SSpherical sph; CartesianToSpherical(dir, sph); //snap camera direction (in nav mode) to player direction //the camera direction is 90 degrees off and flipped compared to entity space sph.m_fYaw -= gf_PI * 0.5f; sph.m_fYaw *= -1.0f; SetInterpolationTarget(sph.m_fYaw, GetPitch()); }
/** * Given information about a point in the referenced frame of an icosahedral * face (tri, uvw), find the corresponding surface location in geographic * coordinate (lon, lat) */ void DymaxIcosa::FaceUVToGeo(int face, DPoint3 &uvw, double &lon, double &lat) { DPoint3 p_out = m_face[face].base + (m_face[face].vec_a * m_edge_length * uvw.x) + (m_face[face].vec_b * m_edge_length * uvw.y); p_out.Normalize(); DPoint3 p2; p2.x = p_out.x; p2.y = -p_out.z; p2.z = p_out.y; CartesianToSpherical(&lon, &lat, p2.x, p2.y, p2.z); lon += PId; if (lon > PI2d) lon -= PI2d; }
bool CCameraTracking::Update(SViewParams &viewParams, float &fHOffObstacleStrength, const SCamModeSettings &camMode, const CPlayer &hero, bool bObstacleFound /* = false */) { if(!g_pGameCVars->cl_cam_tracking || !m_pCamRayScan) return false; m_fFrameTime = max(g_fCamError, gEnv->pTimer->GetFrameTime()); //in combat mode this function doesn't really avoid obstacles, it avoids clipping float fCombatModeWeight = 5.0f; //default angle and minimum const float fNow = gEnv->pTimer->GetFrameStartTime().GetSeconds(); CCameraInputHelper *pCamHelper = hero.GetCameraInputHelper(); CRY_ASSERT(pCamHelper); float fLastUserInput = pCamHelper->GetLastUserInputTime(); //user input overrides auto-follow if(fNow - fLastUserInput < 0.5f) return false; bool bTrackingActive = camMode.camType == ECT_CamFollow && (camMode.collisionType == ECCT_CollisionTrack || camMode.collisionType == ECCT_CollisionTrackOrCut); //get current values Vec3 curCamDir = viewParams.position-viewParams.targetPos; m_curCamOrientation.Set(0.0f, 0.0f, 0.0f); CartesianToSpherical(curCamDir, m_curCamOrientation); curCamDir.Normalize(); if(m_curCamOrientation.m_fDist < g_pGameCVars->cl_cam_min_distance) m_curCamOrientation.m_fDist = g_pGameCVars->cl_cam_min_distance; //work in 0 .. 2PI m_curCamOrientation.m_fYaw += gf_PI; //if there is something in the way if(bObstacleFound) { //re-start fadeout m_fTimeCovered = 0.5f; //set last obstacle pos m_vLastObstaclePos = viewParams.position; //scan obstacle if(!IdentifyObstacle(curCamDir, hero)) return false; } else if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError) { //if there is nothing in the way, fade out the movement //time based fade if(m_fTimeCovered > 0) { m_fTimeCovered = max(m_fTimeCovered - m_fFrameTime, 0.0f); //these interpolators should be time and not frame based m_fYawDelta = (g_fInterpolationRate * m_fYawDelta) * g_fInterpolationWeight; m_fPitchDelta = (g_fInterpolationRate * m_fPitchDelta) * g_fInterpolationWeight; m_fSpeed = (g_fInterpolationRate * m_fSpeed) * g_fInterpolationWeight; } else { m_fYawDelta = 0.0f; m_fPitchDelta = 0.0f; m_fSpeed = 0.0f; } } //apply delta rotation for obstacle avoidance if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError) { if(bTrackingActive) { //set new yaw float newYaw = m_curCamOrientation.m_fYaw + m_fYawDelta; //re-align yaw //the camera direction is 90 degrees off and flipped compared to entity space newYaw = (newYaw - gf_PI * 0.5f) * -1.0f; //set new pitch float newPitch = m_curCamOrientation.m_fPitch + m_fPitchDelta; if(g_pGameCVars->cl_cam_orbit != 0) { //pCamHelper->SetTrackingDelta(-m_fYawDelta, m_fPitchDelta); pCamHelper->SetYawDelta(-m_fYawDelta); pCamHelper->SetPitchDelta(m_fPitchDelta); } else { //apply yaw/pitch on camera //pCamHelper->SetInterpolationTarget(newYaw, newPitch, gf_PI, 0.1f, 0.0f); //this will always reset follow cam interpolation pCamHelper->SetYawDelta(m_fYawDelta); pCamHelper->SetPitchDelta(m_fPitchDelta); } } else { //in orbit mode we basically simulate user input //pCamHelper->SetTrackingDelta(-fCombatModeWeight*g_fYawDelta, fCombatModeWeight*g_fPitchDelta); //in cutting mode we offset the camera to avoid clipping float offsetStrength = 0.0f; float offsetSpeed = 2.0f; if(bObstacleFound) { offsetStrength = (m_fYawDelta < 0.0f)?-g_fOffsetTrackingDistance:g_fOffsetTrackingDistance; offsetSpeed = 0.5f; } fHOffObstacleStrength = InterpolateTo(fHOffObstacleStrength, offsetStrength, offsetSpeed); } //CryLogAlways("new yaw %f, yawDelta %f", newYaw, g_yawDelta); return true; } else UpdateAutoFollow(viewParams, hero); return false; }
bool CCameraTracking::IdentifyObstacle(const Vec3 &vCamDir, const CPlayer &hero) { //check player direction Vec3 newDir = -hero.GetEntity()->GetForwardDir(); newDir.z += vCamDir.z; newDir.normalize(); //compute rotation speed const float fHeroSpeedModifier = clamp(hero.GetActorStats()->speedFlat / 4.0f, 0.3f, 1.0f); const float fNewSpeed = g_pGameCVars->cl_cam_tracking_rotation_speed * m_fFrameTime * fHeroSpeedModifier; m_fSpeed = InterpolateTo(m_fSpeed, fNewSpeed, (fNewSpeed>m_fSpeed)?0.1f:0.3f); //m_fSpeed = (g_fInterpolationRate * m_fSpeed + speed) * g_fInterpolationWeight; //get ray data from camera ray tests ray_hit *pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_RIGHT); if(!pRayHit || pRayHit->dist == 0.0f) pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_RIGHT); bool bHitsRight = (pRayHit && pRayHit->dist > 0.0f); Vec3 dirRight = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_RIGHT)):Vec3(ZERO); //ray data left side pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_LEFT); if(!pRayHit || pRayHit->dist == 0.0f) pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_LEFT); bool bHitsLeft = (pRayHit && pRayHit->dist > 0.0f); Vec3 dirLeft = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_LEFT)):Vec3(ZERO); //left or right if(bHitsRight ^ bHitsLeft) { //find rotation direction if(!bHitsRight && !bHitsLeft) { if(m_eLastDirYaw == eTD_LEFT) //continue last direction newDir = dirLeft; else newDir = dirRight; } else if(!bHitsRight) { m_eLastDirYaw = eTD_RIGHT; newDir = dirRight; } else { m_eLastDirYaw = eTD_LEFT; newDir = dirLeft; } //compute yaw/pitch for target position float newYaw = 0.0f; float newPitch = 0.0f; float newDist = 0.0f; CartesianToSpherical(newDir * m_curCamOrientation.m_fDist, newYaw, newPitch, newDist); newYaw += gf_PI; //now interpolate to target //compute delta yaw m_fYawDelta = (newYaw - m_curCamOrientation.m_fYaw) * m_fSpeed; if(m_eLastDirYaw == eTD_RIGHT && m_fYawDelta < 0.0f || m_eLastDirYaw == eTD_LEFT && m_fYawDelta > 0.0f) m_fYawDelta *= -1.0f; } //compute top/bottom rotation //ray data top side pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_CENTER); bool bHitsTop = (pRayHit && pRayHit->dist > 0.0f)?true:false; Vec3 vDirTop = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_CENTER)):Vec3(ZERO); //ray data bottom side pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_CENTER); bool bHitsBottom = (pRayHit && pRayHit->dist > 0.0f)?true:false; Vec3 vDirBottom = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_BOTTOM_CENTER)):Vec3(ZERO); //top or bottom (if not left or right) if(g_pGameCVars->cl_cam_tracking_allow_pitch && (bHitsTop ^ bHitsBottom) && !(bHitsRight ^ bHitsLeft)) { //find rotation direction if(!bHitsTop && !bHitsBottom) { if(m_eLastDirPitch == eTD_TOP) //continue last direction newDir = vDirTop; else newDir = vDirBottom; } else if(!bHitsBottom) { m_eLastDirPitch = eTD_BOTTOM; newDir = vDirBottom; } else { m_eLastDirPitch = eTD_TOP; newDir = vDirTop; } //compute yaw/pitch for target position float newYaw = 0.0f; float newPitch = 0.0f; float newDist = 0.0f; //newdist (raydist) will be ignored CartesianToSpherical(newDir, newYaw, newPitch, newDist); //compute delta pitch m_fPitchDelta = (newPitch - m_curCamOrientation.m_fPitch) * m_fSpeed * 10.0f; } //if all rays hit - don't bother! //this is a termination condition when the camera is pulled through geometry if(bHitsLeft & bHitsRight & bHitsBottom & bHitsTop) { if(m_bViewCovered) { //if obstacle behind player //if(g_rHit.dist > 0.0f) //this is a strange fix, but it's working better and is much cheaper than a raycast if(fabsf(m_fYawDelta) < 0.01f && fabsf(m_fPitchDelta) > 0.001f) return false; } m_bViewCovered = true; } else m_bViewCovered = false; return true; }
SpherePoint::SpherePoint(Vec3f &v) { CartesianToSpherical(v.x, v.y, v.z, &p, &phi, &theta); }
TextureResult HosekWilkieSky(const BufferUploads::TextureDesc& desc, const ParameterBox& parameters) { // The "turbidity" parameter is Linke’s turbidity factor. Hosek and Wilkie give these example parameters: // T = 2 yields a very clear, Arctic-like sky // T = 3 a clear sky in a temperate climate // T = 6 a sky on a warm, moist day // T = 10 a slightly hazy day // T > 50 represent dense fog auto defaultSunDirection = Normalize(Float3(1.f, 1.f, 0.33f)); Float3 sunDirection = parameters.GetParameter<Float3>(ParameterBox::ParameterNameHash("SunDirection"), defaultSunDirection); sunDirection = Normalize(sunDirection); auto turbidity = (double)parameters.GetParameter(ParameterBox::ParameterNameHash("turbidity"), 3.f); auto albedo = (double)parameters.GetParameter(ParameterBox::ParameterNameHash("albedo"), 0.1f); auto elevation = (double)Deg2Rad(parameters.GetParameter(ParameterBox::ParameterNameHash("elevation"), XlASin(sunDirection[2]))); auto* state = arhosek_rgb_skymodelstate_alloc_init(turbidity, albedo, elevation); auto pixels = std::make_unique<Float4[]>(desc._width*desc._height); for (unsigned y=0; y<desc._height; ++y) for (unsigned x=0; x<desc._width; ++x) { auto p = y*desc._width+x; pixels[p] = Float4(0.f, 0.f, 0.f, 1.f); Float3 direction(0.f, 0.f, 0.f); bool hitPanel = false; for (unsigned c = 0; c < 6; ++c) { Float2 tc(x / float(desc._width), y / float(desc._height)); auto tcMins = s_verticalPanelCoords[c][0]; auto tcMaxs = s_verticalPanelCoords[c][1]; if (tc[0] >= tcMins[0] && tc[1] >= tcMins[1] && tc[0] < tcMaxs[0] && tc[1] < tcMaxs[1]) { tc[0] = 2.0f * (tc[0] - tcMins[0]) / (tcMaxs[0] - tcMins[0]) - 1.0f; tc[1] = 2.0f * (tc[1] - tcMins[1]) / (tcMaxs[1] - tcMins[1]) - 1.0f; hitPanel = true; auto plusX = s_verticalPanels[c][0]; auto plusY = s_verticalPanels[c][1]; auto center = s_verticalPanels[c][2]; direction = center + plusX * tc[0] + plusY * tc[1]; } } if (hitPanel) { auto theta = CartesianToSpherical(direction)[0]; theta = std::min(.4998f * gPI, theta); auto gamma = XlACos(std::max(0.f, Dot(Normalize(direction), sunDirection))); auto R = arhosek_tristim_skymodel_radiance(state, theta, gamma, 0); auto G = arhosek_tristim_skymodel_radiance(state, theta, gamma, 1); auto B = arhosek_tristim_skymodel_radiance(state, theta, gamma, 2); pixels[p][0] = (float)R; pixels[p][1] = (float)G; pixels[p][2] = (float)B; } } arhosekskymodelstate_free(state); return TextureResult { BufferUploads::CreateBasicPacket( (desc._width*desc._height)*sizeof(Float4), pixels.get(), BufferUploads::TexturePitches(desc._width*sizeof(Float4), desc._width*desc._height*sizeof(Float4))), RenderCore::Metal::NativeFormat::R32G32B32A32_FLOAT, UInt2(desc._width, desc._height) }; }