我做了这个相机课程,用于“调试”我的图形,它工作正常,但我不明白为什么它最终缩小了更多。
我实现了一个缩放功能,可以通过鼠标右键拖动屏幕(RMB)(左边你真的拖动屏幕),它就像Unity编辑器缩放一样(当你按住alt并使用RMB时,它的缩放功能)
问题是,如果我拿着人民币并像傻瓜一样摇晃它,缩放将缩小而不是放大,最终让一切都变得微不足道......我知道它有点愚蠢我的担心,但意味着theres那些不太精确的东西..在统一编辑器中,摇晃它就像一个白痴不会让事情最终变得超级缩小......
有人能告诉我是什么原因引起这种行为吗?有点狡猾......我的课,不介意简单,我只是把它扔进调试:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Shooter
{
/// <summary>
/// Provides a camera controllable by mouse.
/// Controls include dragging the "screen"...
/// </summary>
class MouseCamera2D
{
private Matrix m_mView; // stores the camera state (position, scale/zoom, rotation)
public Matrix ViewMatrix { get { return m_mView; } }
public Vector3 GetPosition() { return m_mView.Translation; }
public float m_scaleProportion = 0.01f; // the "speed" to scale, multiplies the offset from mouse drag
// input data
private MouseState m_mouseStateRef;
private MouseState m_mouseStatePreviows = new MouseState();
private KeyboardState m_kbStateRef;
private KeyboardState m_kbStatePreviows = new KeyboardState();
public Keys m_resetZoomKey = Keys.Z;
//private GraphicsDevice m_graphicsDeviceRef;
// ctor
public MouseCamera2D(MouseState mouseState_p, KeyboardState kbState_p/*, GraphicsDevice graphicsDevice_p*/){
if (mouseState_p == null ||kbState_p == null /*|| graphicsDevice_p == null*/) throw new Exception("cant be null"); // needs the reference
//m_graphicsDeviceRef = graphicsDevice_p;
m_mouseStateRef = mouseState_p; // init the reference
m_kbStateRef = kbState_p;
m_mView = Matrix.Identity; // set a valid matrix
//zoomPivot = new Vector2(m_graphicsDeviceRef.Viewport.Width * 0.5f, m_graphicsDeviceRef.Viewport.Height * 0.5f);
}
public void InputUpdate()
{
m_mouseStatePreviows = m_mouseStateRef;
m_mouseStateRef = Mouse.GetState();
m_kbStatePreviows = m_kbStateRef;
m_kbStateRef = Keyboard.GetState();
InputDragControl();
InputScaleControl();
InputZoomOriginal();
}
private void InputDragControl()
{
//mouseStatePreviows = mouseStateRef;
// mouseStateRef = Mouse.GetState();
if (m_mouseStateRef.LeftButton == ButtonState.Pressed)
{
// check if its a drag or a new pivot point
if (m_mouseStatePreviows.LeftButton == ButtonState.Pressed)
{
m_mView.M41 += (m_mouseStateRef.X - m_mouseStatePreviows.X);
m_mView.M42 += (m_mouseStateRef.Y - m_mouseStatePreviows.Y);
}
}
}
Vector3 zoomPivot;
private void InputScaleControl()
{
if (m_mouseStateRef.RightButton == ButtonState.Pressed)
{
// check if its a drag or a new pivot point
if (m_mouseStatePreviows.RightButton == ButtonState.Pressed)
{
float scale = ((m_mouseStateRef.X - m_mouseStatePreviows.X) + (m_mouseStateRef.Y - m_mouseStatePreviows.Y)); //compute distance with "1d direction"(not abs)
if (scale != 0.0f)
{
scale *= m_scaleProportion;
//center zoom on mouse cursor:
m_mView *=
Matrix.CreateTranslation(-zoomPivot)
*
Matrix.CreateScale(1.0f + scale)
*
Matrix.CreateTranslation(zoomPivot)
;
Console.WriteLine(scale.ToString());
Console.WriteLine(m_mView.M11.ToString());
Console.WriteLine("");
}
}
else
{
// new press, get pivot point:
zoomPivot.X = m_mouseStateRef.X;
zoomPivot.Y = m_mouseStateRef.Y;
}
}
}
private void InputZoomOriginal()
{
if( m_kbStateRef.IsKeyDown(m_resetZoomKey) )
{
m_mView *=
Matrix.CreateTranslation(-zoomPivot)
*
Matrix.CreateScale(1.0f/m_mView.M11)
*
Matrix.CreateTranslation(zoomPivot)
;
Console.WriteLine(m_mView.M11.ToString());
Console.WriteLine("");
}
}
}
}
答案 0 :(得分:2)
你的问题来自这段代码:
1.0f + scale
让我们进行单个像素的移动。使用m_scaleProportion = 0.01
时,如果缩小,则将乘以 0.99 。放大时,您将乘以 1.01 。
如果放大一个像素,然后输出一个像素,会发生什么?那么你实际上是将这两个值相乘。像这样: 0.99×1.01 = 0.9999 。这小于1.重复此操作,最终缩放量将变得越来越小。
如何正确实施缩放:
首先:我建议不要在大多数情况下通过乘法累加值(即:根据输入修改多帧的值)。在你的代码中,你不断地将矩阵(就像你正在使用*=
)相乘 - 这可能会慢慢导致浮点问题。 (所以:不要用矩阵来做,但也不要用普通的float
来做)
你应该做的是通过添加来累积鼠标移动。然后根据目前的整体运动更新矩阵。像这样的东西(伪代码):
if(mouseWentDown)
{
// store the starting matrix:
this.originalMatrix = this.currentMatrix;
int zoomAmount = 0;
}
else if(mouseIsDown)
{
// Accumulate the mouse movment:
zoomAmount += (how far the mouse moved this frame);
// Recalculate the matrix based on the starting matrix:
this.currentMatrix = this.originalMatrix *
Matrix.CreateScale((float)Math.Pow(2, zoomAmount * zoomRate));
}
请注意使用Math.Pow
函数来提供实际的缩放系数。此函数很好,因为它为负输入提供小于1的值,为正输入提供大于1的值。对于输入为零,它给出1(无缩放)。
当然,您可能希望将您的透视代码添加到上面。它会是类似的。您可能还需要调整缩放率。
注意:如果您使用此矩阵进行使用SpriteBatch
的2D工作,请不要缩放Z轴。仅缩放X和Y轴并保留Z = 1。
除此之外:您可能会注意到技术上上面的代码是通过乘法累加的,但只有在缩放完成时才会累积(因此它几乎没有那么糟糕)。在我自己的代码中,我通常会存储缩放量(从不将其重置为零)并重新生成完整的矩阵 - 它更加健壮。