CSharpGL(4)设计和使用Camera
CSharpGL(4)设计和使用Camera
主要内容
描述在OpenGL中Camera的概念和用处。
设计一个Camera以及操控Camera的SatelliteRotator。
以PyramidElement为例演示如何使用Camera和SatelliteRotator。
下载
您可以在(https://github.com/bitzhuwei/CSharpGL)找到最新的源码。欢迎感兴趣的同学fork之。
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
通过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;
}
}
缩放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) / ;
}
} }
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
总结
除了本文的SatelliteRotator,还有一种称为轨迹球(AraBall)的移动Camera的方式。这里暂时就不实现了。
CSharpGL(4)设计和使用Camera的更多相关文章
- CSharpGL(2)设计和使用场景元素及常用接口
CSharpGL(2)设计和使用场景元素及常用接口 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo,更适合入 ...
- BIT祝威博客汇总(Blog Index)
+BIT祝威+悄悄在此留下版了个权的信息说: 关于硬件(Hardware) <穿越计算机的迷雾>笔记 继电器是如何成为CPU的(1) 继电器是如何成为CPU的(2) 关于操作系统(Oper ...
- 图像采集系统的Camera Link标准接口设计
高速数据采集系统可对相机采集得到的实时图像进行传输.实时处理,同时实现视频采集卡和计算机之间的通信.系统连接相机的接口用的是Camera Link接口,通过Camera Link接口把实时图像高速传输 ...
- 115-基于TI TMS320DM6467无操作系统Camera Link智能图像分析平台
基于TI TMS320DM6467无操作系统Camera Link智能图像分析平台 1.板卡概述 该板卡是我公司推出的一款具有高可靠性.效率大化.无操作系统的智能视频处理卡,是机器视觉开发上的选. ...
- 115-基于TI TMS320DM6467T Camera Link 机器视觉 智能图像分析平台
基于TI TMS320DM6467无操作系统Camera Link智能图像分析平台 1.板卡概述 该板卡是我公司推出的一款具有超高可靠性.效率最大化.无操作系统的智能视频处理卡,是机器视觉开发上的首选 ...
- 基于CameraLink的逻辑综合和版图设计
前期接口设计用的是Vivado18.3+Modelsim10.6,逻辑综合及版图生成的环境是Ubuntu16,逻辑综合用的工具Design Compiler,生成版图用的工具是Encounter. 下 ...
- 关于camera 构架设计的一点看法
camera的构架目前来看有两种,一种是集中式管理,比如说建立一个引擎,引擎向上提供接口,向下管理所有模块.把camera的所有功能划分为不同的模块,又引擎统一管理.模块的结构就比较随意了,可以统一接 ...
- CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口
CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口 开始 像下面这样的四个视口的功能是很常用的,所以我花了几天时间在CSharpGL中集成了这个功能. 在CSh ...
- CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率
CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率 当场景中有比较复杂的模型时,条件渲染能够加速对复杂模型的渲染. 条件渲染(Conditio ...
随机推荐
- webpack初试
前言: 知道这完儿,没用过.关于webpack有很多介绍了,就不多说了.放几个链接,方便新手理解.这是给纯没用过的人了解的.这里只是简单介绍一下webpack的基本用法.大多内容都是来自webpack ...
- fullPage.js学习笔记
中秋节,一个人呆着,挺无聊的,还是学习最有趣,不论是什么,开阔视野都是好的. 参考网址:http://www.dowebok.com/77.html 上面有详细介绍及案例展示,很不错哦,可以先去看看 ...
- 进击的Python【第二十章】
1.Django请求的生命周期 路由系统 -> 试图函数(获取模板+数据=>渲染) -> 字符串返回给用户 2.路由系统 /index/ -> 函数或类.as_view() / ...
- Good Bye 2016
A - New Year and Hurry (water) #include <bits/stdc++.h> using namespace std; int main() { ]; ; ...
- Gridview样式的CSS控制
页面代码: .<asp:GridView ID="gvCustomres" runat="server" . DataSourceID="cus ...
- div高度根据内容自动增大
1.很多时候我们希望容器高度能够自适应内部元素的变化,需要用到min-height属性. 2.有时候用了min-height还是不会随着内容自适应高度,您需要检查下容器的子元素是不是有浮动属性,当子元 ...
- 总结30个CSS3选择器(转载)
或许大家平时总是在用的选择器都是:#id .class 以及标签选择器.可是这些还远远不够,为了在开发中更加得心应手,本文总结了30个CSS3选择器,希望对大家有所帮助. 1 *:通用选择器 * ...
- 原生JS 年月日、省市区 三级联动
这个算生日日期,因为是从100年前的到现年. <select id="sel_year"></select> <select id="sel ...
- Vim 插入递增列
<C-a> ++1 <C-x> --1 安装Plugin 'terryma/vim-multiple-cursors'后 <C-v> 选所有数字 <C ...
- mysql 命令行还原备份数据库
通常数据库还原备份可以通过navicat等数据库管理工具进行,只需要简单的导出导入就行了,但遇到有索引外键的数据库,数据库管理工具运行.sql文件会报错,这时候可以尝试命令行导入,亲测可以成功 MyS ...