返回

解决Unity正交视图大小随窗口变化问题

windows

正交视图大小随窗口变化问题

正交投影视图(Orthographic projection view)在游戏开发中常用于2D游戏,其特点是平行线在投影后依然平行,物体大小不随距离改变。当游戏窗口尺寸改变时,正交视图内的物体大小可能会出现变化,这通常是由多种原因造成的。本文将讨论此类问题的产生原因,并提供几种有效的解决方法。

问题根源

问题的核心在于,游戏内的物体渲染是基于特定视图大小计算的,当窗口尺寸改变,而视图大小没有随之调整时,渲染系统会根据新的窗口尺寸缩放游戏内容,这导致了物体看起来变大或变小。

在提供的代码示例中,直接修改了窗口的像素高度,却没有对正交摄像机的投影范围进行同步调整。例如,窗口高度增加时,如果正交摄像机的显示范围维持不变,相当于游戏内容被“放大”到新的窗口大小,所以对象看起来变大了。相反,窗口高度降低则会导致内容看起来变小。

解决方法

这里将介绍几种不同的解决方式,让你的游戏对象大小保持不变。

方案一:调整正交摄像机大小

最直接的方式是在每次窗口尺寸变化时,同步调整正交摄像机的可视范围。摄像机的orthographicSize属性(例如,在 Unity 中)控制着摄像机的垂直可视范围,因此当窗口的纵横比改变时,就需要调整此值,以保证游戏内容比例正确,看起来没有被拉伸或挤压。

操作步骤:

  1. 获取当前窗口的纵横比。
  2. 根据新的纵横比,计算需要调整的正交摄像机尺寸。
  3. 更新摄像机的orthographicSize属性。

示例代码(C# Unity):

using UnityEngine;

public class CameraSizeAdjuster : MonoBehaviour
{
    public Camera orthographicCamera;

    private void Start()
    {
       AdjustCameraSize();
    }
   
   void Update()
    {
        //检查窗口大小是否改变。
        if(Screen.width!= _lastWidth || Screen.height!= _lastHeight){
         AdjustCameraSize();
         _lastWidth = Screen.width;
         _lastHeight=Screen.height;

        }
    }
    
   int _lastWidth=0;
   int _lastHeight=0;


    void AdjustCameraSize()
    {
        if (orthographicCamera == null) return;


       float targetAspect = (float)Screen.width / Screen.height;
       float originalAspect =(float)orthographicCamera.pixelWidth/orthographicCamera.pixelHeight;


        if(targetAspect != originalAspect){

        orthographicCamera.orthographicSize =orthographicCamera.orthographicSize *(originalAspect / targetAspect) ; 
          
        }


    }
}

此代码段中,AdjustCameraSize函数计算了当前的屏幕纵横比和摄像机的像素纵横比,如果纵横比不同,会按比例缩放正交摄像机大小。

方案二:使用固定的渲染分辨率

这种方案下,游戏的渲染尺寸始终保持一致。例如,可以将游戏渲染到固定的纹理,然后将其缩放到屏幕尺寸。即使窗口尺寸改变,渲染纹理的分辨率始终不变,确保了正交投影视图下对象的大小不变化。

操作步骤:

  1. 创建一个渲染纹理(Render Texture)。
  2. 配置摄像机将渲染输出到此纹理。
  3. 将纹理绘制到屏幕。
  4. 调整绘制时使用的缩放比例来适配不同大小的窗口。

示例代码 (使用RenderTexture and Screen Overlay 方式):

using UnityEngine;
using UnityEngine.UI;

public class FixedResolutionRenderer : MonoBehaviour
{
    public int fixedWidth = 800;
    public int fixedHeight = 600;
    public RawImage rawImage;  // Reference to UI Raw Image
    public Camera renderCamera;

    private RenderTexture renderTexture;


    void Start()
    {
       CreateRenderTexture();
        UpdateRawImageRect();

      
       // 设置相机目标纹理
         renderCamera.targetTexture = renderTexture;


         }



     private void CreateRenderTexture() {
            if (renderTexture != null) renderTexture.Release();
             renderTexture=new RenderTexture(fixedWidth,fixedHeight,0);

          }
      void Update()
        {


             if(rawImage!= null )   {

                float aspectRatio=(float)Screen.width / Screen.height;

                 RectTransform transform = rawImage.GetComponent<RectTransform>();

               // 根据纵横比适配显示比例
               if( aspectRatio >= (float)fixedWidth / fixedHeight ){

                        float targetHeight= Screen.height;
                           float  targetWidth =   Screen.height *  ((float)fixedWidth/fixedHeight)   ;
                           transform.sizeDelta=new Vector2(targetWidth,targetHeight);



                }else
                {


                    float targetWidth = Screen.width;
                           float  targetHeight = Screen.width *( (float)fixedHeight /fixedWidth)  ;
                             transform.sizeDelta=new Vector2(targetWidth,targetHeight);



                }




         
         }
    }
     //将RenderTexture 纹理 更新到RawImage上
    private void UpdateRawImageRect() {


      if (renderTexture==null)  {return ; }

        rawImage.texture = renderTexture;




    }

     
}

该示例创建了一个指定大小的渲染纹理,并让摄像机渲染到此纹理,接着它将这个纹理放到UI RawImage 控件上,然后适配UI 元素大小使其自适应屏幕。

方案三:结合 Canvas Scaler 组件使用 (Unity)

如果使用的是 Unity 的 UI 系统,Canvas Scaler 组件提供了一种非常便利的解决屏幕缩放的方法。该组件可以根据窗口大小自动缩放 UI 元素。

操作步骤:

  1. 在 Canvas 组件中添加 Canvas Scaler 组件。
  2. 设置 UI Scale ModeScale With Screen Size
  3. 配置 Reference Resolution 以指定设计分辨率。

通过合理配置 Match 和其他选项,可以让 UI 和场景元素一起按需缩放。

安全建议

  • 定期备份你的项目,防止代码改动出现意外情况。
  • 逐步测试每一个修改,确认每个解决方案是否符合预期。
  • 在部署前,尽可能在不同分辨率下进行测试。

选择哪种解决方案取决于项目需求,对技术点的熟悉程度,以及团队的工作习惯,请综合考量。正确理解这些方案的原理,将帮助你更加高效的进行游戏开发。