Separate Item and Hand FOV from the World View.

Basically like in Java, and unlike the horrid Bedrock Edition, the FOV doesn't extend the arm in such a strange way. This just keeps the FOV for the hand and anything you're holding at the default levels, so you can get a nice high FOV without a broken hand and item placement.
This commit is contained in:
Spring 2026-03-10 22:33:21 -05:00
parent 1036b7368e
commit 9478058ddd
2 changed files with 56 additions and 13 deletions

View file

@ -409,6 +409,28 @@ float GameRenderer::getFov(float a, bool applyEffects)
} }
float GameRenderer::getViewmodelFov(float a)
{
// The first-person hand/item should not scale with the user's world FOV (Java-like viewmodel feel).
if (cameraFlip > 0) return 90;
shared_ptr<LocalPlayer> player = dynamic_pointer_cast<LocalPlayer>(mc->cameraTargetPlayer);
if (!player) return 70.0f;
float fov = 70.0f;
if (player->getHealth() <= 0)
{
float duration = player->deathTime + a;
fov /= ((1 - 500 / (duration + 500)) * 2.0f + 1);
}
int t = Camera::getBlockAt(mc->level, player, a);
if (t != 0 && Tile::tiles[t]->material == Material::water) fov = fov * 60 / 70;
return fov + fovOffsetO + (fovOffset - fovOffsetO) * a;
}
void GameRenderer::bobHurt(float a) void GameRenderer::bobHurt(float a)
{ {
shared_ptr<LivingEntity> player = mc->cameraTargetPlayer; shared_ptr<LivingEntity> player = mc->cameraTargetPlayer;
@ -591,6 +613,24 @@ void GameRenderer::unZoomRegion()
zoom = 1; zoom = 1;
} }
void GameRenderer::applyViewportFovAndAspectAdjustments(float& fov, float& aspect) const
{
if (!mc || !mc->player) return;
if ((mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_TOP) ||
(mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM))
{
aspect *= 2.0f;
fov *= 0.7f; // Reduce FOV to make things less fish-eye, at the expense of reducing vertical FOV from single player mode
}
else if ((mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT) ||
(mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT))
{
// Ideally I'd like to make the fov bigger here, but if I do then you can see that the arm isn't very long...
aspect *= 0.5f;
}
}
// 4J added as we have more complex adjustments to make for fov & aspect on account of viewports // 4J added as we have more complex adjustments to make for fov & aspect on account of viewports
void GameRenderer::getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects) void GameRenderer::getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects)
{ {
@ -600,18 +640,18 @@ void GameRenderer::getFovAndAspect(float& fov, float& aspect, float a, bool appl
aspect = g_rScreenWidth / static_cast<float>(g_rScreenHeight); aspect = g_rScreenWidth / static_cast<float>(g_rScreenHeight);
fov = getFov(a, applyEffects); fov = getFov(a, applyEffects);
if( ( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_TOP ) || applyViewportFovAndAspectAdjustments(fov, aspect);
( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM ) ) }
{
aspect *= 2.0f; void GameRenderer::getViewmodelFovAndAspect(float& fov, float& aspect, float a)
fov *= 0.7f; // Reduce FOV to make things less fish-eye, at the expense of reducing vertical FOV from single player mode {
} // Use the real window dimensions so the perspective updates on resize.
else if( ( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_LEFT ) || extern int g_rScreenWidth;
( mc->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT) ) extern int g_rScreenHeight;
{ aspect = g_rScreenWidth / static_cast<float>(g_rScreenHeight);
// Ideally I'd like to make the fov bigger here, but if I do then you an see that the arm isn't very long... fov = getViewmodelFov(a);
aspect *= 0.5f;
} applyViewportFovAndAspectAdjustments(fov, aspect);
} }
void GameRenderer::setupCamera(float a, int eye) void GameRenderer::setupCamera(float a, int eye)
@ -716,7 +756,7 @@ void GameRenderer::renderItemInHand(float a, int eye)
// 4J - have split out fov & aspect calculation so we can take into account viewports // 4J - have split out fov & aspect calculation so we can take into account viewports
float fov, aspect; float fov, aspect;
getFovAndAspect(fov, aspect, a, false); getViewmodelFovAndAspect(fov, aspect, a);
if (zoom != 1) if (zoom != 1)
{ {

View file

@ -102,6 +102,7 @@ public:
private: private:
void tickFov(); void tickFov();
float getFov(float a, bool applyEffects); float getFov(float a, bool applyEffects);
float getViewmodelFov(float a);
void bobHurt(float a); void bobHurt(float a);
void bobView(float a); void bobView(float a);
void moveCameraToPlayer(float a); void moveCameraToPlayer(float a);
@ -112,7 +113,9 @@ public:
void zoomRegion(double zoom, double xa, double ya); void zoomRegion(double zoom, double xa, double ya);
void unZoomRegion(); void unZoomRegion();
private: private:
void applyViewportFovAndAspectAdjustments(float& fov, float& aspect) const;
void getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects); // 4J added void getFovAndAspect(float& fov, float& aspect, float a, bool applyEffects); // 4J added
void getViewmodelFovAndAspect(float& fov, float& aspect, float a); // 4J added
public: public:
void setupCamera(float a, int eye); void setupCamera(float a, int eye);
private: private: