diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 8e36c766e4..bc633e7419 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -73,6 +73,7 @@ CVAR(Float, gl_sclipthreshold, 10.0, CVAR_ARCHIVE) CVAR(Float, gl_sclipfactor, 1.8, CVAR_ARCHIVE) CVAR(Int, gl_particles_style, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth CVAR(Int, gl_billboard_mode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, gl_billboard_faces_camera, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, gl_billboard_particles, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, gl_enhanced_nv_stealth, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CUSTOM_CVAR(Int, gl_fuzztype, 0, CVAR_ARCHIVE) @@ -262,6 +263,8 @@ void GLSprite::Draw(int pass) //&& GLRenderer->mViewActor != NULL && (gl_billboard_mode == 1 || (actor && actor->renderflags & RF_FORCEXYBILLBOARD)))); + const bool drawBillboardFacingCamera = gl_billboard_faces_camera; + gl_RenderState.Apply(); Vector v1; @@ -269,11 +272,9 @@ void GLSprite::Draw(int pass) Vector v3; Vector v4; - if (drawWithXYBillboard) + if (drawWithXYBillboard || drawBillboardFacingCamera) { - // Rotate the sprite about the vector starting at the center of the sprite - // triangle strip and with direction orthogonal to where the player is looking - // in the x/y plane. + // Compute center of sprite float xcenter = (x1 + x2)*0.5; float ycenter = (y1 + y2)*0.5; float zcenter = (z1 + z2)*0.5; @@ -281,17 +282,40 @@ void GLSprite::Draw(int pass) Matrix3x4 mat; mat.MakeIdentity(); - mat.Translate(xcenter, zcenter, ycenter); - mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch.Degrees); - mat.Translate(-xcenter, -zcenter, -ycenter); + + if (drawWithXYBillboard) + { + // Rotate the sprite about the vector starting at the center of the sprite + // triangle strip and with direction orthogonal to where the player is looking + // in the x/y plane. + mat.Translate(xcenter, zcenter, ycenter); + mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch.Degrees); + mat.Translate(-xcenter, -zcenter, -ycenter); + } + + if (drawBillboardFacingCamera) { + // [CMB] Rotate relative to camera XY position, not just camera direction, + // which is nicer in VR + float xrel = xcenter - FIXED2FLOAT(GLRenderer->mViewActor->X()); + float yrel = ycenter - FIXED2FLOAT(GLRenderer->mViewActor->Y()); + float zrel = zcenter - FIXED2FLOAT(GLRenderer->mViewActor->Z()); + + float absAngleDeg = RAD2DEG(atan2(-yrel, xrel)); + float counterRotationDeg = 270. - float(GLRenderer->mAngles.Yaw); // counteracts existing sprite rotation + float relAngleDeg = counterRotationDeg + absAngleDeg; + + mat.Translate(xcenter, zcenter, ycenter); + mat.Rotate(0, 1, 0, relAngleDeg); + mat.Translate(-xcenter, -zcenter, -ycenter); + } + v1 = mat * Vector(x1, z1, y1); v2 = mat * Vector(x2, z1, y2); v3 = mat * Vector(x1, z2, y1); v4 = mat * Vector(x2, z2, y2); } - else + else { - v1 = Vector(x1, z1, y1); v2 = Vector(x2, z1, y2); v3 = Vector(x1, z2, y1);