zoukankan      html  css  js  c++  java
  • CSharpGL(4)设计和使用Camera

    CSharpGL(4)设计和使用Camera

    +BIT祝威+悄悄在此留下版了个权的信息说:

    主要内容

    描述在OpenGL中Camera的概念和用处。

    设计一个Camera以及操控Camera的SatelliteRotator。

    以PyramidElement为例演示如何使用Camera和SatelliteRotator。

    +BIT祝威+悄悄在此留下版了个权的信息说:

    下载

    您可以在(https://github.com/bitzhuwei/CSharpGL)找到最新的源码。欢迎感兴趣的同学fork之。

    +BIT祝威+悄悄在此留下版了个权的信息说:

    Camera

    在OpenGL中的Camera概念可以方便我们设定projection矩阵和view矩阵。

    定义

      1     /// <summary>
      2     /// 摄像机。
      3     /// </summary>
      4     public class Camera :
      5         ICamera,
      6         IPerspectiveViewCamera, IOrthoViewCamera,
      7         IViewCamera, IPerspectiveCamera, IOrthoCamera
      8     {
      9         /// <summary>
     10         /// 默认目标为vec3(0, 0, 0)
     11         /// </summary>
     12         public static readonly vec3 defaultTarget = new vec3(0, 0, 0);
     13 
     14         /// <summary>
     15         /// 默认位置为vec3(0, 0, 1)
     16         /// </summary>
     17         public static readonly vec3 defaultPosition = new vec3(0, 0, 1);
     18 
     19         /// <summary>
     20         /// 默认上方为vec3(0, 1, 0)
     21         /// </summary>
     22         public static readonly vec3 defaultUpVector = new vec3(0, 1, 0);
     23 
     24         internal Camera() { }
     25 
     26         /// <summary>
     27         /// 摄像机。
     28         /// </summary>
     29         /// <param name="cameraType">类型</param>
     30         /// <param name="width">OpenGL窗口的宽度</param>
     31         /// <param name="height">OpenGL窗口的高度</param>
     32         public Camera(CameraType cameraType, double width, double height)
     33         {
     34             this.lastHeight = width;
     35             this.lastHeight = height;
     36 
     37             IPerspectiveCamera perspectiveCamera = this;
     38             perspectiveCamera.FieldOfView = 60.0f;
     39             perspectiveCamera.AspectRatio = width / height;
     40             perspectiveCamera.Near = 0.01;
     41             perspectiveCamera.Far = 10000;
     42 
     43             const int factor = 100;
     44             IOrthoCamera orthoCamera = this;
     45             orthoCamera.Left = -width / 2 / factor;
     46             orthoCamera.Right = width / 2 / factor;
     47             orthoCamera.Bottom = -height / 2 / factor;
     48             orthoCamera.Top = height / 2 / factor;
     49             orthoCamera.Near = -10000;
     50             orthoCamera.Far = 10000;
     51 
     52             this.Target = defaultTarget;
     53             this.Position = defaultPosition;
     54             this.UpVector = defaultUpVector;
     55 
     56             this.CameraType = cameraType;
     57         }
     58 
     59         public void Resize(double width, double height)
     60         {
     61             double aspectRatio = width / height;
     62 
     63             IPerspectiveCamera perspectiveCamera = this;
     64             perspectiveCamera.AspectRatio = aspectRatio;
     65 
     66             IOrthoCamera orthoCamera = this;
     67 
     68             double lastAspectRatio = this.lastWidth / this.lastHeight;
     69             if (aspectRatio > lastAspectRatio)
     70             {
     71                 double top = orthoCamera.Top;
     72                 double newRight = top * aspectRatio;
     73                 orthoCamera.Left = -newRight;
     74                 orthoCamera.Right = newRight;
     75             }
     76             else if (aspectRatio < lastAspectRatio)
     77             {
     78                 double right = orthoCamera.Right;
     79                 double newTop = right / aspectRatio;
     80                 orthoCamera.Bottom = -newTop;
     81                 orthoCamera.Top = newTop;
     82             }
     83 
     84             //const int factor = 100;
     85             //if (width / 2 / factor != orthoCamera.Right)
     86             //{
     87             //    orthoCamera.Left = -width / 2 / factor;
     88             //    orthoCamera.Right = width / 2 / factor;
     89             //}
     90             //if (height / 2 / factor != orthoCamera.Top)
     91             //{
     92             //    orthoCamera.Bottom = -height / 2 / factor;
     93             //    orthoCamera.Top = height / 2 / factor;
     94             //}
     95         }
     96 
     97         double lastWidth;
     98         double lastHeight;
     99 
    100         /// <summary>
    101         /// Gets or sets the target.
    102         /// </summary>
    103         /// <value>
    104         /// The target.
    105         /// </value>
    106         [Description("The target of the camera (the point it's looking at)"), Category("Camera")]
    107         public vec3 Target { get; set; }
    108 
    109         /// <summary>
    110         /// Gets or sets up vector.
    111         /// </summary>
    112         /// <value>
    113         /// Up vector.
    114         /// </value>
    115         [Description("The up direction, relative to camera. (Controls tilt)."), Category("Camera")]
    116         public vec3 UpVector { get; set; }
    117 
    118         /// <summary>
    119         /// The camera position.
    120         /// </summary>
    121         private vec3 position = new vec3(0, 0, 0);
    122 
    123         /// <summary>
    124         /// Every time a camera is used to project, the projection matrix calculated
    125         /// and stored here.
    126         /// </summary>
    127         private mat4 projectionMatrix = mat4.identity();
    128 
    129         ///// <summary>
    130         ///// The screen aspect ratio.
    131         ///// </summary>
    132         //private double aspectRatio = 1.0f;
    133 
    134         /// <summary>
    135         /// Gets or sets the position.
    136         /// </summary>
    137         /// <value>
    138         /// The position.
    139         /// </value>
    140         [Description("The position of the camera"), Category("Camera")]
    141         public vec3 Position
    142         {
    143             get { return position; }
    144             set { position = value; }
    145         }
    146 
    147         /// <summary>
    148         /// camera's perspective type.
    149         /// </summary>
    150         public CameraType CameraType { get; set; }
    151 
    152         #region IPerspectiveCamera 成员
    153 
    154         double IPerspectiveCamera.FieldOfView { get; set; }
    155 
    156         double IPerspectiveCamera.AspectRatio { get; set; }
    157 
    158         double IPerspectiveCamera.Near { get; set; }
    159 
    160         double IPerspectiveCamera.Far { get; set; }
    161 
    162         #endregion
    163 
    164         #region IOrthoCamera 成员
    165 
    166         double IOrthoCamera.Left { get; set; }
    167 
    168         double IOrthoCamera.Right { get; set; }
    169 
    170         double IOrthoCamera.Bottom { get; set; }
    171 
    172         double IOrthoCamera.Top { get; set; }
    173 
    174         double IOrthoCamera.Near { get; set; }
    175 
    176         double IOrthoCamera.Far { get; set; }
    177 
    178         #endregion
    179     }
    Camera
    +BIT祝威+悄悄在此留下版了个权的信息说:

    通过Camera获取矩阵

    根据上面的Camera的定义,很容易给出其对应的projection矩阵和view矩阵。

     1     public static class Camera2Matrix
     2     {
     3 
     4         /// <summary>
     5         /// 根据摄像机的类型获取其投影矩阵
     6         /// </summary>
     7         /// <param name="camera"></param>
     8         /// <returns></returns>
     9         public static mat4 GetProjectionMat4(this ICamera camera)
    10         {
    11             mat4 result;
    12 
    13             switch (camera.CameraType)
    14             {
    15                 case CameraType.Perspecitive:
    16                     result = ((IPerspectiveCamera)camera).GetProjectionMat4();
    17                     break;
    18                 case CameraType.Ortho:
    19                     result = ((IOrthoCamera)camera).GetProjectionMat4();
    20                     break;
    21                 default:
    22                     throw new NotImplementedException();
    23             }
    24 
    25             return result;
    26         }
    27 
    28         /// <summary>
    29         /// Extension method for <see cref="IPerspectiveCamera"/> to get projection matrix.
    30         /// </summary>
    31         /// <param name="camera"></param>
    32         /// <returns></returns>
    33         public static mat4 GetProjectionMat4(this IPerspectiveCamera camera)
    34         {
    35             mat4 perspective = glm.perspective(
    36                 (float)(camera.FieldOfView * Math.PI / 180.0f),
    37                 (float)camera.AspectRatio, (float)camera.Near, (float)camera.Far);
    38             return perspective;
    39         }
    40 
    41         /// <summary>
    42         /// Extension method for <see cref="IOrthoCamera"/> to get projection matrix.
    43         /// </summary>
    44         /// <param name="camera"></param>
    45         /// <returns></returns>
    46         public static mat4 GetProjectionMat4(this IOrthoCamera camera)
    47         {
    48             mat4 ortho = glm.ortho(
    49                 (float)camera.Left, (float)camera.Right,
    50                 (float)camera.Bottom, (float)camera.Top,
    51                 (float)camera.Near, (float)camera.Far);
    52             return ortho;
    53         }
    54 
    55         /// <summary>
    56         /// Extension method for <see cref="IViewCamera"/> to get view matrix.
    57         /// </summary>
    58         /// <param name="camera"></param>
    59         /// <returns></returns>
    60         public static mat4 GetViewMat4(this IViewCamera camera)
    61         {
    62             mat4 lookAt = glm.lookAt(camera.Position, camera.Target, camera.UpVector);
    63             return lookAt;
    64         }
    65     }
    +BIT祝威+悄悄在此留下版了个权的信息说:

    缩放Camera

     1     public static class MouseWheelHelper
     2     {
     3         /// <summary>
     4         /// 对摄像机执行一次缩放操作
     5         /// </summary>
     6         /// <param name="camera"></param>
     7         /// <param name="delta"></param>
     8         public static void MouseWheel(this ICamera camera, int delta)
     9         {
    10             //if (camera.CameraType == CameraTypes.Perspecitive)
    11             {
    12                 var target2Position = camera.Position - camera.Target;
    13                 if (target2Position.Magnitude() < 0.01)
    14                 {
    15                     target2Position.Normalize();
    16                     target2Position.x *= 0.01f;
    17                     target2Position.y *= 0.01f;
    18                     target2Position.z *= 0.01f;
    19                 }
    20                 var scaledTarget2Position = target2Position * (1 - delta * 0.001f);
    21                 camera.Position = camera.Target + scaledTarget2Position;
    22                 double lengthDiff = scaledTarget2Position.Magnitude() - target2Position.Magnitude();
    23                 // Increase ortho camera's Near/Far property in case the camera's position changes too much.
    24                 IPerspectiveCamera perspectiveCamera = camera;
    25                 perspectiveCamera.Far += lengthDiff;
    26                 //perspectiveCamera.Near += lengthDiff;
    27                 IOrthoCamera orthoCamera = camera;
    28                 orthoCamera.Far += lengthDiff;
    29                 orthoCamera.Near += lengthDiff;
    30             }
    31             //else if (camera.CameraType == CameraTypes.Ortho)
    32             {
    33                 IOrthoCamera orthoCamera = camera;
    34                 double distanceX = orthoCamera.Right - orthoCamera.Left;
    35                 double distanceY = orthoCamera.Top - orthoCamera.Bottom;
    36                 double centerX = (orthoCamera.Left + orthoCamera.Right) / 2;
    37                 double centerY = (orthoCamera.Bottom + orthoCamera.Top) / 2;
    38                 orthoCamera.Left = centerX - distanceX * (1 - delta * 0.001) / 2;
    39                 orthoCamera.Right = centerX + distanceX * (1 - delta * 0.001) / 2;
    40                 orthoCamera.Bottom = centerY - distanceY * (1 - delta * 0.001) / 2;
    41                 orthoCamera.Top = centerX + distanceY * (1 - delta * 0.001) / 2;
    42             }
    43         }
    44 
    45     }
    +BIT祝威+悄悄在此留下版了个权的信息说:

    Rotator

    有了Camera,我们就想通过改变Camera的位置、朝向来实现在场景中进行移动的功能。SatelliteRotator可以根据鼠标操作使Camera围绕其Target在给定的球面上移动,就像卫星围绕恒星运动一样。

      1     /// <summary>
      2     /// Rotates a camera on a sphere, whose center is camera's Target.
      3     /// <para>Just like a satellite moves around a fixed star.</para>
      4     /// </summary>
      5     public class SatelliteRotator : ICameraRotator
      6     {
      7         private Point downPosition = new Point();
      8         private Size bound = new Size();
      9         public bool mouseDownFlag = false;
     10         private float horizontalRotationFactor = 4;
     11         private float verticalRotationFactor = 4;
     12         private vec3 up;
     13         private vec3 back;
     14         private vec3 right;
     15 
     16         /// <summary>
     17         /// Rotates a camera on a sphere, whose center is camera's Target.
     18         /// <para>Just like a satellite moves around a fixed star.</para>
     19         /// </summary>
     20         /// <param name="camera"></param>
     21         public SatelliteRotator(ICamera camera = null)
     22         {
     23             this.Camera = camera;
     24         }
     25 
     26 
     27         public override string ToString()
     28         {
     29             return string.Format("back:{0}|{3:0.00},up:{1}|{4:0.00},right:{2}|{5:0.00}",
     30                 back, up, right, back.Magnitude(), up.Magnitude(), right.Magnitude());
     31             //return base.ToString();
     32         }
     33 
     34 
     35         private ICamera originalCamera;
     36 
     37         public ICamera Camera { get; set; }
     38 
     39         public void MouseUp(int x, int y)
     40         {
     41             this.mouseDownFlag = false;
     42         }
     43 
     44         public void MouseMove(int x, int y)
     45         {
     46             if (this.mouseDownFlag)
     47             {
     48                 IViewCamera camera = this.Camera;
     49                 if (camera == null) { return; }
     50 
     51                 vec3 back = this.back;
     52                 vec3 right = this.right;
     53                 vec3 up = this.up;
     54                 Size bound = this.bound;
     55                 Point downPosition = this.downPosition;
     56                 {
     57                     float deltaX = -horizontalRotationFactor * (x - downPosition.X) / bound.Width;
     58                     float cos = (float)Math.Cos(deltaX);
     59                     float sin = (float)Math.Sin(deltaX);
     60                     vec3 newBack = new vec3(
     61                         back.x * cos + right.x * sin,
     62                         back.y * cos + right.y * sin,
     63                         back.z * cos + right.z * sin);
     64                     back = newBack;
     65                     right = up.cross(back);
     66                     back.Normalize();
     67                     right.Normalize();
     68                 }
     69                 {
     70                     float deltaY = verticalRotationFactor * (y - downPosition.Y) / bound.Height;
     71                     float cos = (float)Math.Cos(deltaY);
     72                     float sin = (float)Math.Sin(deltaY);
     73                     vec3 newBack = new vec3(
     74                         back.x * cos + up.x * sin,
     75                         back.y * cos + up.y * sin,
     76                         back.z * cos + up.z * sin);
     77                     back = newBack;
     78                     up = back.cross(right);
     79                     back.Normalize();
     80                     up.Normalize();
     81                 }
     82 
     83                 camera.Position = camera.Target +
     84                     back * (float)((camera.Position - camera.Target).Magnitude());
     85                 camera.UpVector = up;
     86                 this.back = back;
     87                 this.right = right;
     88                 this.up = up;
     89                 this.downPosition.X = x;
     90                 this.downPosition.Y = y;
     91             }
     92         }
     93 
     94         public void SetBounds(int width, int height)
     95         {
     96             this.bound.Width = width;
     97             this.bound.Height = height;
     98         }
     99 
    100         public void MouseDown(int x, int y)
    101         {
    102             this.downPosition.X = x;
    103             this.downPosition.Y = y;
    104             this.mouseDownFlag = true;
    105             PrepareCamera();
    106         }
    107 
    108         private void PrepareCamera()
    109         {
    110             var camera = this.Camera;
    111             if (camera != null)
    112             {
    113                 vec3 back = camera.Position - camera.Target;
    114                 vec3 right = Camera.UpVector.cross(back);
    115                 vec3 up = back.cross(right);
    116                 back.Normalize();
    117                 right.Normalize();
    118                 up.Normalize();
    119 
    120                 this.back = back;
    121                 this.right = right;
    122                 this.up = up;
    123 
    124                 if (this.originalCamera == null)
    125                 { this.originalCamera = new Camera(); }
    126                 this.originalCamera.Position = camera.Position;
    127                 this.originalCamera.UpVector = camera.UpVector;
    128             }
    129         }
    130 
    131         public void Reset()
    132         {
    133             IViewCamera camera = this.Camera;
    134             if (camera == null) { return; }
    135             IViewCamera originalCamera = this.originalCamera;
    136             if (originalCamera == null) { return; }
    137 
    138             camera.Position = originalCamera.Position;
    139             camera.UpVector = originalCamera.UpVector;
    140         }
    141     }
    SatelliteRotator
    +BIT祝威+悄悄在此留下版了个权的信息说:

    总结

    除了本文的SatelliteRotator,还有一种称为轨迹球(AraBall)的移动Camera的方式。这里暂时就不实现了。

  • 相关阅读:
    事件
    dom对象
    逻辑运算和作用域的问题
    json
    数组
    字符串
    函数
    js的数据类型和全局方法
    js
    10.16 js内容
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/CSharpGL-4-use-camera.html
Copyright © 2011-2022 走看看