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. 用maven在eclipse中创建Web项目

    使用eclipse插件创建一个web project 首先创建一个Maven的Project如下图 我们勾选上Create a simple project (不使用骨架) 这里的Packing 选择 ...

  2. Service and controller in angularJs

    Separation of concern is at the heart while designing an AngularJS application. Your controller must ...

  3. Good Bye 2016

    A - New Year and Hurry (water) #include <bits/stdc++.h> using namespace std; int main() { ]; ; ...

  4. python urllib

    在伴随学习爬虫的过程中学习了解的一些基础库和方法总结扩展 1. urllib 在urllib.request module中定义下面的一些方法 urllib.request.urlopen(url,d ...

  5. 复利计算器(软件工程)及Junit测试———郭志豪

    计算:1.本金为100万,利率或者投资回报率为3%,投资年限为30年,那么,30年后所获得的利息收入:按复利计算公式来计算就是:1,000,000×(1+3%)^30 客户提出: 2.如果按照单利计算 ...

  6. ORACLE如何比较两个数据库的差异

    ORACLE怎么比较两个数据库的差异 方法1:使用PL-SQL工具 点击 工具->比较用户对象

  7. kafka的log存储解析——topic的分区partition分段segment以及索引等

    转自:http://blog.csdn.net/jewes/article/details/42970799 引言 Kafka中的Message是以topic为基本单位组织的,不同的topic之间是相 ...

  8. 面向对象课后深入学习(C++ 类的静态成员详细讲解)

    今天在刚申请了博客,一下午都在写那个随笔,所以说好的来看c++的也放在了最后,下星期就考试了,这个类的静态成员是我不是很懂的,在网上 看到一片很详细的博客考下来回去慢慢看. 在C++中,静态成员是属于 ...

  9. 数据库sqlite 存储图片

    SQLite可以存储 BLOB(binary large object,二进制大对象)格式数据,利用它可以在安卓应用开发中存储图片资源. 这里先讲下,怎样把数据从数据库中取出,并显示在imagView ...

  10. git flow工作流实际项目实践

    公司项目的开发流程主要是这样 代码分为 develop分支 master分支 平时我开发的时候,主要在develop分支上改动 一般来讲,有以下几种改动方式 1.直接在develop上修改代码 这种一 ...