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矩阵。

定义

     /// <summary>
/// 摄像机。
/// </summary>
public class Camera :
ICamera,
IPerspectiveViewCamera, IOrthoViewCamera,
IViewCamera, IPerspectiveCamera, IOrthoCamera
{
/// <summary>
/// 默认目标为vec3(0, 0, 0)
/// </summary>
public static readonly vec3 defaultTarget = new vec3(, , ); /// <summary>
/// 默认位置为vec3(0, 0, 1)
/// </summary>
public static readonly vec3 defaultPosition = new vec3(, , ); /// <summary>
/// 默认上方为vec3(0, 1, 0)
/// </summary>
public static readonly vec3 defaultUpVector = new vec3(, , ); internal Camera() { } /// <summary>
/// 摄像机。
/// </summary>
/// <param name="cameraType">类型</param>
/// <param name="width">OpenGL窗口的宽度</param>
/// <param name="height">OpenGL窗口的高度</param>
public Camera(CameraType cameraType, double width, double height)
{
this.lastHeight = width;
this.lastHeight = height; IPerspectiveCamera perspectiveCamera = this;
perspectiveCamera.FieldOfView = 60.0f;
perspectiveCamera.AspectRatio = width / height;
perspectiveCamera.Near = 0.01;
perspectiveCamera.Far = ; const int factor = ;
IOrthoCamera orthoCamera = this;
orthoCamera.Left = -width / / factor;
orthoCamera.Right = width / / factor;
orthoCamera.Bottom = -height / / factor;
orthoCamera.Top = height / / factor;
orthoCamera.Near = -;
orthoCamera.Far = ; this.Target = defaultTarget;
this.Position = defaultPosition;
this.UpVector = defaultUpVector; this.CameraType = cameraType;
} public void Resize(double width, double height)
{
double aspectRatio = width / height; IPerspectiveCamera perspectiveCamera = this;
perspectiveCamera.AspectRatio = aspectRatio; IOrthoCamera orthoCamera = this; double lastAspectRatio = this.lastWidth / this.lastHeight;
if (aspectRatio > lastAspectRatio)
{
double top = orthoCamera.Top;
double newRight = top * aspectRatio;
orthoCamera.Left = -newRight;
orthoCamera.Right = newRight;
}
else if (aspectRatio < lastAspectRatio)
{
double right = orthoCamera.Right;
double newTop = right / aspectRatio;
orthoCamera.Bottom = -newTop;
orthoCamera.Top = newTop;
} //const int factor = 100;
//if (width / 2 / factor != orthoCamera.Right)
//{
// orthoCamera.Left = -width / 2 / factor;
// orthoCamera.Right = width / 2 / factor;
//}
//if (height / 2 / factor != orthoCamera.Top)
//{
// orthoCamera.Bottom = -height / 2 / factor;
// orthoCamera.Top = height / 2 / factor;
//}
} double lastWidth;
double lastHeight; /// <summary>
/// Gets or sets the target.
/// </summary>
/// <value>
/// The target.
/// </value>
[Description("The target of the camera (the point it's looking at)"), Category("Camera")]
public vec3 Target { get; set; } /// <summary>
/// Gets or sets up vector.
/// </summary>
/// <value>
/// Up vector.
/// </value>
[Description("The up direction, relative to camera. (Controls tilt)."), Category("Camera")]
public vec3 UpVector { get; set; } /// <summary>
/// The camera position.
/// </summary>
private vec3 position = new vec3(, , ); /// <summary>
/// Every time a camera is used to project, the projection matrix calculated
/// and stored here.
/// </summary>
private mat4 projectionMatrix = mat4.identity(); ///// <summary>
///// The screen aspect ratio.
///// </summary>
//private double aspectRatio = 1.0f; /// <summary>
/// Gets or sets the position.
/// </summary>
/// <value>
/// The position.
/// </value>
[Description("The position of the camera"), Category("Camera")]
public vec3 Position
{
get { return position; }
set { position = value; }
} /// <summary>
/// camera's perspective type.
/// </summary>
public CameraType CameraType { get; set; } #region IPerspectiveCamera 成员 double IPerspectiveCamera.FieldOfView { get; set; } double IPerspectiveCamera.AspectRatio { get; set; } double IPerspectiveCamera.Near { get; set; } double IPerspectiveCamera.Far { get; set; } #endregion #region IOrthoCamera 成员 double IOrthoCamera.Left { get; set; } double IOrthoCamera.Right { get; set; } double IOrthoCamera.Bottom { get; set; } double IOrthoCamera.Top { get; set; } double IOrthoCamera.Near { get; set; } double IOrthoCamera.Far { get; set; } #endregion
}

Camera

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

通过Camera获取矩阵

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

     public static class Camera2Matrix
{ /// <summary>
/// 根据摄像机的类型获取其投影矩阵
/// </summary>
/// <param name="camera"></param>
/// <returns></returns>
public static mat4 GetProjectionMat4(this ICamera camera)
{
mat4 result; switch (camera.CameraType)
{
case CameraType.Perspecitive:
result = ((IPerspectiveCamera)camera).GetProjectionMat4();
break;
case CameraType.Ortho:
result = ((IOrthoCamera)camera).GetProjectionMat4();
break;
default:
throw new NotImplementedException();
} return result;
} /// <summary>
/// Extension method for <see cref="IPerspectiveCamera"/> to get projection matrix.
/// </summary>
/// <param name="camera"></param>
/// <returns></returns>
public static mat4 GetProjectionMat4(this IPerspectiveCamera camera)
{
mat4 perspective = glm.perspective(
(float)(camera.FieldOfView * Math.PI / 180.0f),
(float)camera.AspectRatio, (float)camera.Near, (float)camera.Far);
return perspective;
} /// <summary>
/// Extension method for <see cref="IOrthoCamera"/> to get projection matrix.
/// </summary>
/// <param name="camera"></param>
/// <returns></returns>
public static mat4 GetProjectionMat4(this IOrthoCamera camera)
{
mat4 ortho = glm.ortho(
(float)camera.Left, (float)camera.Right,
(float)camera.Bottom, (float)camera.Top,
(float)camera.Near, (float)camera.Far);
return ortho;
} /// <summary>
/// Extension method for <see cref="IViewCamera"/> to get view matrix.
/// </summary>
/// <param name="camera"></param>
/// <returns></returns>
public static mat4 GetViewMat4(this IViewCamera camera)
{
mat4 lookAt = glm.lookAt(camera.Position, camera.Target, camera.UpVector);
return lookAt;
}
}
+BIT祝威+悄悄在此留下版了个权的信息说:

缩放Camera

     public static class MouseWheelHelper
{
/// <summary>
/// 对摄像机执行一次缩放操作
/// </summary>
/// <param name="camera"></param>
/// <param name="delta"></param>
public static void MouseWheel(this ICamera camera, int delta)
{
//if (camera.CameraType == CameraTypes.Perspecitive)
{
var target2Position = camera.Position - camera.Target;
if (target2Position.Magnitude() < 0.01)
{
target2Position.Normalize();
target2Position.x *= 0.01f;
target2Position.y *= 0.01f;
target2Position.z *= 0.01f;
}
var scaledTarget2Position = target2Position * ( - delta * 0.001f);
camera.Position = camera.Target + scaledTarget2Position;
double lengthDiff = scaledTarget2Position.Magnitude() - target2Position.Magnitude();
// Increase ortho camera's Near/Far property in case the camera's position changes too much.
IPerspectiveCamera perspectiveCamera = camera;
perspectiveCamera.Far += lengthDiff;
//perspectiveCamera.Near += lengthDiff;
IOrthoCamera orthoCamera = camera;
orthoCamera.Far += lengthDiff;
orthoCamera.Near += lengthDiff;
}
//else if (camera.CameraType == CameraTypes.Ortho)
{
IOrthoCamera orthoCamera = camera;
double distanceX = orthoCamera.Right - orthoCamera.Left;
double distanceY = orthoCamera.Top - orthoCamera.Bottom;
double centerX = (orthoCamera.Left + orthoCamera.Right) / ;
double centerY = (orthoCamera.Bottom + orthoCamera.Top) / ;
orthoCamera.Left = centerX - distanceX * ( - delta * 0.001) / ;
orthoCamera.Right = centerX + distanceX * ( - delta * 0.001) / ;
orthoCamera.Bottom = centerY - distanceY * ( - delta * 0.001) / ;
orthoCamera.Top = centerX + distanceY * ( - delta * 0.001) / ;
}
} }
+BIT祝威+悄悄在此留下版了个权的信息说:

Rotator

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

     /// <summary>
/// Rotates a camera on a sphere, whose center is camera's Target.
/// <para>Just like a satellite moves around a fixed star.</para>
/// </summary>
public class SatelliteRotator : ICameraRotator
{
private Point downPosition = new Point();
private Size bound = new Size();
public bool mouseDownFlag = false;
private float horizontalRotationFactor = ;
private float verticalRotationFactor = ;
private vec3 up;
private vec3 back;
private vec3 right; /// <summary>
/// Rotates a camera on a sphere, whose center is camera's Target.
/// <para>Just like a satellite moves around a fixed star.</para>
/// </summary>
/// <param name="camera"></param>
public SatelliteRotator(ICamera camera = null)
{
this.Camera = camera;
} public override string ToString()
{
return string.Format("back:{0}|{3:0.00},up:{1}|{4:0.00},right:{2}|{5:0.00}",
back, up, right, back.Magnitude(), up.Magnitude(), right.Magnitude());
//return base.ToString();
} private ICamera originalCamera; public ICamera Camera { get; set; } public void MouseUp(int x, int y)
{
this.mouseDownFlag = false;
} public void MouseMove(int x, int y)
{
if (this.mouseDownFlag)
{
IViewCamera camera = this.Camera;
if (camera == null) { return; } vec3 back = this.back;
vec3 right = this.right;
vec3 up = this.up;
Size bound = this.bound;
Point downPosition = this.downPosition;
{
float deltaX = -horizontalRotationFactor * (x - downPosition.X) / bound.Width;
float cos = (float)Math.Cos(deltaX);
float sin = (float)Math.Sin(deltaX);
vec3 newBack = new vec3(
back.x * cos + right.x * sin,
back.y * cos + right.y * sin,
back.z * cos + right.z * sin);
back = newBack;
right = up.cross(back);
back.Normalize();
right.Normalize();
}
{
float deltaY = verticalRotationFactor * (y - downPosition.Y) / bound.Height;
float cos = (float)Math.Cos(deltaY);
float sin = (float)Math.Sin(deltaY);
vec3 newBack = new vec3(
back.x * cos + up.x * sin,
back.y * cos + up.y * sin,
back.z * cos + up.z * sin);
back = newBack;
up = back.cross(right);
back.Normalize();
up.Normalize();
} camera.Position = camera.Target +
back * (float)((camera.Position - camera.Target).Magnitude());
camera.UpVector = up;
this.back = back;
this.right = right;
this.up = up;
this.downPosition.X = x;
this.downPosition.Y = y;
}
} public void SetBounds(int width, int height)
{
this.bound.Width = width;
this.bound.Height = height;
} public void MouseDown(int x, int y)
{
this.downPosition.X = x;
this.downPosition.Y = y;
this.mouseDownFlag = true;
PrepareCamera();
} private void PrepareCamera()
{
var camera = this.Camera;
if (camera != null)
{
vec3 back = camera.Position - camera.Target;
vec3 right = Camera.UpVector.cross(back);
vec3 up = back.cross(right);
back.Normalize();
right.Normalize();
up.Normalize(); this.back = back;
this.right = right;
this.up = up; if (this.originalCamera == null)
{ this.originalCamera = new Camera(); }
this.originalCamera.Position = camera.Position;
this.originalCamera.UpVector = camera.UpVector;
}
} public void Reset()
{
IViewCamera camera = this.Camera;
if (camera == null) { return; }
IViewCamera originalCamera = this.originalCamera;
if (originalCamera == null) { return; } camera.Position = originalCamera.Position;
camera.UpVector = originalCamera.UpVector;
}
}

SatelliteRotator

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

总结

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

CSharpGL(4)设计和使用Camera的更多相关文章

  1. CSharpGL(2)设计和使用场景元素及常用接口

    CSharpGL(2)设计和使用场景元素及常用接口 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo,更适合入 ...

  2. BIT祝威博客汇总(Blog Index)

    +BIT祝威+悄悄在此留下版了个权的信息说: 关于硬件(Hardware) <穿越计算机的迷雾>笔记 继电器是如何成为CPU的(1) 继电器是如何成为CPU的(2) 关于操作系统(Oper ...

  3. 图像采集系统的Camera Link标准接口设计

    高速数据采集系统可对相机采集得到的实时图像进行传输.实时处理,同时实现视频采集卡和计算机之间的通信.系统连接相机的接口用的是Camera Link接口,通过Camera Link接口把实时图像高速传输 ...

  4. 115-基于TI TMS320DM6467无操作系统Camera Link智能图像分析平台

    基于TI TMS320DM6467无操作系统Camera Link智能图像分析平台 1.板卡概述 该板卡是我公司推出的一款具有高可靠性.效率大化.无操作系统的智能视频处理卡,是机器视觉开发上的选.  ...

  5. 115-基于TI TMS320DM6467T Camera Link 机器视觉 智能图像分析平台

    基于TI TMS320DM6467无操作系统Camera Link智能图像分析平台 1.板卡概述 该板卡是我公司推出的一款具有超高可靠性.效率最大化.无操作系统的智能视频处理卡,是机器视觉开发上的首选 ...

  6. 基于CameraLink的逻辑综合和版图设计

    前期接口设计用的是Vivado18.3+Modelsim10.6,逻辑综合及版图生成的环境是Ubuntu16,逻辑综合用的工具Design Compiler,生成版图用的工具是Encounter. 下 ...

  7. 关于camera 构架设计的一点看法

    camera的构架目前来看有两种,一种是集中式管理,比如说建立一个引擎,引擎向上提供接口,向下管理所有模块.把camera的所有功能划分为不同的模块,又引擎统一管理.模块的结构就比较随意了,可以统一接 ...

  8. CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口

    CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口 开始 像下面这样的四个视口的功能是很常用的,所以我花了几天时间在CSharpGL中集成了这个功能. 在CSh ...

  9. CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率

    CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率 当场景中有比较复杂的模型时,条件渲染能够加速对复杂模型的渲染. 条件渲染(Conditio ...

随机推荐

  1. CozyRSS开发记录14-RSS源管理初步完工

    CozyRSS开发记录14-RSS源管理初步完工 1.添加源的响应 DialogHost.Show有几个版本的重载,加一个DialogClosingEventHandler参数.我们让添加源对话框的添 ...

  2. (UWP开发)基于Windows10 Anniversary SDK创造出位于可视化层的DropShadow

    Windows.UI.Composition API是可以从任何通用Windows平台应用程序调用的声明性保留模式API,从而可以直接在应用程序中创建合成对象.动画和效果. Composition A ...

  3. Maven的配置和使用(三)

    下面记录下如何使用Maven进行jar包的管理和更新. 在Maven中我们是通过对pom.xml文件的配置来对项目的包进行管理的,找到该文件并打开: <project xmlns="h ...

  4. web前端开发学习内容

    应该 具备的 知识技能 :懂web标准,熟练手写 xhtml css3 并符合 符合w3c标准                       代码能 兼容主流浏览器.ie6.7.8.9 ff 等.    ...

  5. Effective C++ 笔记2(构造,析构,赋值)

    条款5:了解C++默默编写并且调用了哪些函数 1.  构造函数,析构函数,拷贝赋值函数,拷贝构造函数. class Empty { public: //默认构造函数 Empty(){}; //拷贝构造 ...

  6. 【刷题记录】首师附NOIP练习20160820

    [由于老师不让发题目,So只能发考点喽!!!!噜噜噜] [题目(嘘~~~~~)]:百度云下载 [T1]:好像是DP,路径压缩+排序+分情况处理100分(噜噜噜) [T2]:正解好难的样子,DFS乱搞了 ...

  7. <转>Unity3D研究院之C#使用Socket与HTTP连接服务器传输数据包

    最近项目中需要使用HTTP与Socket,把自己这段时间学习的资料整理一下.有关Socket与HTTP的基础知识MOMO就不赘述拉,不懂得朋友自己谷歌吧.我们项目的需求是在登录的时候使用HTTP请求, ...

  8. [资料分享]nutch视频教程

  9. C#获取存储过程返回值和输出参数值的方法

    //转自网络,先留个底 1.获取Return返回值 //存储过程 //Create PROCEDURE MYSQL // @a int, // @b int //AS // return @a + @ ...

  10. Asp.Net Mvc + ComBoost.Mvc快速开发

    ComBoost项目地址 http://comboost.wodsoft.com https://github.com/Kation/ComBoost/tree/develop 准备工作 首先,在Vi ...