【问题标题】:Problem with RenderTarget and Transformation Matrix in MonoGameMonoGame 中 RenderTarget 和转换矩阵的问题
【发布时间】:2023-02-01 12:03:11
【问题描述】:

我一直试图在不同的分辨率下找到一个好的解决方案,但没有一个效果很好,精灵要么扭曲,一切都被抵消,要么各种不同的恶作剧。

我得到的最好的解决方案是这个,它使用 RenderTarget 和转换矩阵根据分辨率缩小所有内容,但是当纵横比与虚拟分辨率不同时,Y 轴上的东西会偏移 gif of it happening,这是绘制代码:

GraphicsDevice.SetRenderTarget(RenderTarget);

var scaleX = (float)ScreenWidths[CurrentResolution] / 1920;
var scaleY = (float)ScreenHeights[CurrentResolution] / 1080;
var matrix = Matrix.CreateScale(scaleX, scaleX, 1.0f);

spriteBatch.Begin(transformMatrix: matrix);

GraphicsDevice.Clear(BackgroundColor);            

foreach (var uiElement in UIElements)
{
    uiElement.Draw(gameTime, spriteBatch);
}

spriteBatch.End();

GraphicsDevice.SetRenderTarget(null);

spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend,
            SamplerState.LinearClamp, DepthStencilState.Default,
            RasterizerState.CullNone);

var offsetX = ScreenWidths[CurrentResolution] / 2 - 1920 / 2 * scaleX;
var offsetY = ScreenHeights[CurrentResolution] / 2 - 1080 / 2 * scaleY;
spriteBatch.Draw(RenderTarget, new Rectangle((int)offsetX, (int)offsetY, (int)(1920), (int)(1080)), Color.White);

spriteBatch.End();

var mouseState = Mouse.GetState();
MousePosition = Vector2.Transform(new Vector2(mouseState.X, mouseState.Y), Matrix.Invert(matrix));

base.Draw(gameTime);

这是在初始化:

ScreenWidths = new int\[\] { 1920, 960, 1366, 1280, 1280, 1366 };
ScreenHeights = new int\[\] { 1080, 540, 768, 1024, 720, 680 };

RenderTarget = new RenderTarget2D(
    GraphicsDevice,
    GraphicsDevice.PresentationParameters.BackBufferWidth,
    GraphicsDevice.PresentationParameters.BackBufferHeight,
    false,
    GraphicsDevice.PresentationParameters.BackBufferFormat,
    DepthFormat.Depth24);

这是按钮的代码:

if (Main.CurrentResolution >= 0 && Main.CurrentResolution < Main.ScreenWidths.Length - 1)              { 
    Main.CurrentResolution++;
    Main.graphics.PreferredBackBufferWidth = Main.ScreenWidths[Main.CurrentResolution];
    Main.graphics.PreferredBackBufferHeight = Main.ScreenHeights[Main.CurrentResolution];
    Main.graphics.ApplyChanges();             
}

我将如何修复 Y 轴上的偏移量?甚至什么是处理不同分辨率的更好方法?

【问题讨论】:

    标签: c# xna monogame screen-resolution


    【解决方案1】:

    在此示例中,您可以了解如何:

    • 在相对坐标中放置一个点,放置在屏幕上相同的相对位置
    • 在绝对坐标中放置一个点,放置在屏幕上相同的相对位置

    无论宽高比差异如何,事物都会以相对的方式正确定位。

    接下来你想要的是一个统一的比例,这里是 X/Y 的最小值,但你也可以强制它在一个特定的轴上。

    此外,您想要的矩阵可能是:缩放、旋转、平移。

    您可能希望将所有这些调整为您真正想要的。

    结果:

    resolution:   <960, 540>, pointRelative:   <480.000, 270.000>, pointAbsolute:     <50.000, 50.000>, scaleAbsolute: <0.500, 0.500>, scaleUniform: 0.500
    resolution:   <960, 680>, pointRelative:   <480.000, 340.000>, pointAbsolute:     <50.000, 62.963>, scaleAbsolute: <0.500, 0.630>, scaleUniform: 0.500
    resolution:   <960, 720>, pointRelative:   <480.000, 360.000>, pointAbsolute:     <50.000, 66.667>, scaleAbsolute: <0.500, 0.667>, scaleUniform: 0.500
    resolution:   <960, 768>, pointRelative:   <480.000, 384.000>, pointAbsolute:     <50.000, 71.111>, scaleAbsolute: <0.500, 0.711>, scaleUniform: 0.500
    resolution:  <960, 1024>, pointRelative:   <480.000, 512.000>, pointAbsolute:     <50.000, 94.815>, scaleAbsolute: <0.500, 0.948>, scaleUniform: 0.500
    resolution:  <960, 1080>, pointRelative:   <480.000, 540.000>, pointAbsolute:    <50.000, 100.000>, scaleAbsolute: <0.500, 1.000>, scaleUniform: 0.500
    resolution:  <1280, 540>, pointRelative:   <640.000, 270.000>, pointAbsolute:     <66.667, 50.000>, scaleAbsolute: <0.667, 0.500>, scaleUniform: 0.500
    resolution:  <1280, 680>, pointRelative:   <640.000, 340.000>, pointAbsolute:     <66.667, 62.963>, scaleAbsolute: <0.667, 0.630>, scaleUniform: 0.630
    resolution:  <1280, 720>, pointRelative:   <640.000, 360.000>, pointAbsolute:     <66.667, 66.667>, scaleAbsolute: <0.667, 0.667>, scaleUniform: 0.667
    resolution:  <1280, 768>, pointRelative:   <640.000, 384.000>, pointAbsolute:     <66.667, 71.111>, scaleAbsolute: <0.667, 0.711>, scaleUniform: 0.667
    resolution: <1280, 1024>, pointRelative:   <640.000, 512.000>, pointAbsolute:     <66.667, 94.815>, scaleAbsolute: <0.667, 0.948>, scaleUniform: 0.667
    resolution: <1280, 1080>, pointRelative:   <640.000, 540.000>, pointAbsolute:    <66.667, 100.000>, scaleAbsolute: <0.667, 1.000>, scaleUniform: 0.667
    resolution:  <1366, 540>, pointRelative:   <683.000, 270.000>, pointAbsolute:     <71.146, 50.000>, scaleAbsolute: <0.711, 0.500>, scaleUniform: 0.500
    resolution:  <1366, 680>, pointRelative:   <683.000, 340.000>, pointAbsolute:     <71.146, 62.963>, scaleAbsolute: <0.711, 0.630>, scaleUniform: 0.630
    resolution:  <1366, 720>, pointRelative:   <683.000, 360.000>, pointAbsolute:     <71.146, 66.667>, scaleAbsolute: <0.711, 0.667>, scaleUniform: 0.667
    resolution:  <1366, 768>, pointRelative:   <683.000, 384.000>, pointAbsolute:     <71.146, 71.111>, scaleAbsolute: <0.711, 0.711>, scaleUniform: 0.711
    resolution: <1366, 1024>, pointRelative:   <683.000, 512.000>, pointAbsolute:     <71.146, 94.815>, scaleAbsolute: <0.711, 0.948>, scaleUniform: 0.711
    resolution: <1366, 1080>, pointRelative:   <683.000, 540.000>, pointAbsolute:    <71.146, 100.000>, scaleAbsolute: <0.711, 1.000>, scaleUniform: 0.711
    resolution:  <1920, 540>, pointRelative:   <960.000, 270.000>, pointAbsolute:    <100.000, 50.000>, scaleAbsolute: <1.000, 0.500>, scaleUniform: 0.500
    resolution:  <1920, 680>, pointRelative:   <960.000, 340.000>, pointAbsolute:    <100.000, 62.963>, scaleAbsolute: <1.000, 0.630>, scaleUniform: 0.630
    resolution:  <1920, 720>, pointRelative:   <960.000, 360.000>, pointAbsolute:    <100.000, 66.667>, scaleAbsolute: <1.000, 0.667>, scaleUniform: 0.667
    resolution:  <1920, 768>, pointRelative:   <960.000, 384.000>, pointAbsolute:    <100.000, 71.111>, scaleAbsolute: <1.000, 0.711>, scaleUniform: 0.711
    resolution: <1920, 1024>, pointRelative:   <960.000, 512.000>, pointAbsolute:    <100.000, 94.815>, scaleAbsolute: <1.000, 0.948>, scaleUniform: 0.948
    resolution: <1920, 1080>, pointRelative:   <960.000, 540.000>, pointAbsolute:   <100.000, 100.000>, scaleAbsolute: <1.000, 1.000>, scaleUniform: 1.000
    

    代码:

    public void Test()
    {
        var sx = new[] { 1920, 1366, 1280, 960 };
        var sy = new[] { 1080, 1024, 768, 720, 680, 540 };
    
        var pt1 = new Vector2(0.5f, 0.5f);
        var pt2 = new Vector2(100, 100);
    
        foreach (var w in sx.Reverse())
        {
            foreach (var h in sy.Reverse())
            {
                var scaleX = w / 1920.0f;
                var scaleY = h / 1080.0f;
    
                var resolution = new Vector2(w, h);
                var scaleUniform = Math.Min(scaleX, scaleY);
                var scaleAbsolute = new Vector2(scaleX, scaleY);
                var pointRelative = pt1 * resolution;
                var pointAbsolute = pt2 * scaleAbsolute;
                Console.WriteLine(
                    $"{nameof(resolution)}: {resolution,12}, " +
                    $"{nameof(pointRelative)}: {pointRelative,20:F3}, " +
                    $"{nameof(pointAbsolute)}: {pointAbsolute,20:F3}, " +
                    $"{nameof(scaleAbsolute)}: {scaleAbsolute:F3}, " +
                    $"{nameof(scaleUniform)}: {scaleUniform:F3}"
                );
            }
        }
    }
    

    【讨论】:

    • 谢谢!这会处理定位问题,但我该如何做到这一点,以便变换矩阵在不同纵横比时不会扭曲游戏(然后使用黑色边框填充其余空间)?
    • 如前所述,您的矩阵可能应该是 Matrix.CreateScale(scaleUniform, scaleUniform, 1.0f),这很有意义,因为您想要统一缩放事物。
    【解决方案2】:

    如果不进行裁剪或拉伸,单个图像在绘制时会变形。

    您需要根据宽高比组和大小组而不是分辨率来定义虚拟屏幕源。

    为主要纵横比 5:4、16:9(10)、32:9(10) 制作源资源。如果为移动设备(或可能的 PC 屏幕)设计纵向模式,则反之亦然。 (10) 的原因是屏幕从 9 到 11 不等(因此 10 意味着大多数屏幕的失真更少)。

    如果源太大,一组资源将混叠,如果太小则像素化。 (Mipmap 在 3D 中解决了这个问题,但对于离散分辨率来说会很浪费)

    因此,大小组需要有两种大小,小号和中号,大号仅适用于原生 4k 和 8k 分辨率(两者都大于合理距离内的人类感知)。眼睛在一个小区域内有一个有限的 ~5K 聚焦区。

    由于分辨率减半和加倍会产生最少的伪像,因此我打算创建 800 的最小尺寸和 1600 的中等尺寸。

    并非所有尺寸/纵横比来源都需要符合此建议。


    我建议在类级别变量中计算和存储 Initialize 和 Resize 事件中的纵横比和大小选择。

    这些变量为第一个渲染通道的源资产做出选择。最终的绘制比例,以最小的失真来适应和填充屏幕(10 对 9 或 11)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-18
      • 2011-03-14
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-05
      相关资源
      最近更新 更多