当前位置: 首页 > news >正文

Win32 OpenGL编程(10) 视口变换

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

讨论新闻组及文件

提要

在前文(系列文章(7),以下简称XO7,系列其他文章类似)中的照相机比喻中提到了4种3D变换,如下:

1.确定照相机的位置的过程对应于“视图变换”(Viewing Transformations)

2.确定物体位置的过程对应于“模型变换”(Modeling Transformations)

3.确定照相机放大倍数的过程对应于“投影变换”(Projection Transformations)

4.确定照片大小的过程对应于“视口变换”(Viewport Transformations)

XO7中我们讲的是第一种变换视图变换,即改变观察者本身的位置,视角等的变换效果,XO8中讲的是第二种变换模型变换,XO9中讲的是投影变换,本文开始讲解最后一个变换,视口变换。

视口变换

此变换应该算是4种变换中最简单的了,在照相机比喻中我说他是确认照片大小,在实际中,确认的是绘制的区域,当然,我们以前没有设定视口变换前,默认是占据整个窗口的客户区的。只有一个关键函数glViewport,而且较易理解:

《OpenGL Programming Guide 》:

glViewport — set the viewport
C Specification
void glViewport( GLint x,
GLint y,
GLsizei width,
GLsizei height);
Parameters

x, y

Specify the lower left corner of the viewport rectangle,
in pixels. The initial value is (0,0).
width, height

Specify the width and height
of the viewport.
When a GL context is first attached to a window,
width and height are set to the dimensions of that
window.

无论前面进行了多少处理,最终的图像将映射到这个矩形中,默认情况时占据整个窗口的客户区,在前面的所有例子中,(七巧板的例子除外)我们没有接触到视口变换,那么默认就是窗口创建那一瞬间的大小,我们可以尝试改变窗口大小,发现事实上图形没有变大,并且,位置也不再居中了,这个时候我们就需要进行视口变换,调整视口。这里,因为以前有七巧板的例子了,也有原来没有使用的例子,我就不提供新的此用途的例子了,仅仅看两个例子的区别。

未在窗口改变时重新设定视口的情况:

正常情况:

image

窗口缩小时:图像偏移了。

image

窗口放大时:图像不居中。

image

看七巧板中的例子:

因为有以下代码:

void 
ReShape
(unsigned 
auWidth
, unsigned 
auHeight
)
{
    glViewport
(0, 0, auWidth
, auHeight
);
}

// FUNCTIONS //

LRESULT CALLBACK WindowProc
(HWND hwnd
, 
                            UINT msg
, 
                            WPARAM wparam
, 
                            LPARAM lparam
)
{
    // this is the main message handler of the system
    
PAINTSTRUCT        ps
;        // used in WM_PAINT
    
HDC                hdc
;    // handle to a device context

    // what is the message 
    
switch
(msg
)
    {    
    case 
WM_CREATE
: 
        {
            // do initialization stuff here
            // return success
            
return
(0);
        } break
;

    case 
WM_PAINT
: 
        {
            // simply validate the window 
            
hdc 
= BeginPaint
(hwnd
,&ps
);     

            // end painting
            
EndPaint
(hwnd
,&ps
);

            // return success
            
return
(0);
        } break
;

    case 
WM_DESTROY
: 
        {
            // kill the application, this sends a WM_QUIT message 
            
PostQuitMessage
(0);

            // return success
            
return
(0);
        } break
;
    case 
WM_SIZE
:
        {
            ReShape
(LOWORD
(lparam
), HIWORD
(lparam
));
        }
    default
:break
;

    } // end switch

    // process any messages that we didn't take care of 
    
return 
(DefWindowProc
(hwnd
, msg
, wparam
, lparam
));

} // end WinProc

注意reshape的作用,此时,窗口大小改变时,会重新设定视口,这样,图形将会随着窗口大小改变而改变(这是大部分情况下我们需要的)

正常情况下:

image 窗口缩小:图形还是居中,因为纵横比的改变,导致图形纵横比也改变了。

image 窗口放大时:图形还是居中,因为纵横比的改变,导致图形纵横比也改变了。

image

上述七巧板的例子中,很好的演示了glViewport的作用,源代码在以前就已经提供了,这里不再说了。但是,我们会发现一个问题,就是窗口纵横比改变的时候,图形实际也改变了纵横比导致变形了,这样不太符合大部分情况下我们的想法,我们可以通过控制窗口的纵横比来控制这一点,(大部分情况下)或者直接通过控制glViewport参数的纵横比也可以达到保证图像不扭曲的目的。(但是图形可能移位)

屏幕分割

玩过真三国无双系列的玩家们不知道在同一台机器上与战友们浴血奋斗过没有,我是有过,显示时,一个玩家在上面,一个在下面,在同一台机器上不需要通过网络就能享受联机的乐趣,的确很有意思,事实上,我们通过视口变换连续绘制图形两次就能达到这样的效果(我不知道真三国是否也是通过这样的技术实现的),比如上述的七巧板的例子吧,我们想在屏幕上绘制4次,让四个人同时玩,进行对战,那么我们就可以这样做:

void 
ReShape
(unsigned 
auWidth
, unsigned 
auHeight
)
{
    WindowWidth 
= auWidth
;
    WindowHeight 
= auHeight
;

}

// All Scene Show code 

void 
SceneShow
(GLvoid
)        
{
    glClear
(GL_COLOR_BUFFER_BIT
);    

    // left bottom
    
glViewport
(0, 0, WindowWidth
/2, WindowHeight
/2);

    gTriBTop
.Draw
();
    gTriBRight
.Draw
();
    gTriSLeft
.Draw
();
    gRectangle
.Draw
();
    gTriSMid
.Draw
();
    gTriMLeft
.Draw
();
    gParal
.Draw
();

    // right bottom
    
glViewport
(WindowWidth
/2, 0, WindowWidth
/2, WindowHeight
/2);

    gTriBTop
.Draw
();
    gTriBRight
.Draw
();
    gTriSLeft
.Draw
();
    gRectangle
.Draw
();
    gTriSMid
.Draw
();
    gTriMLeft
.Draw
();
    gParal
.Draw
();

    // left top 
    
glViewport
(0 , WindowHeight
/2, WindowWidth
/2, WindowHeight
/2);

    gTriBTop
.Draw
();
    gTriBRight
.Draw
();
    gTriSLeft
.Draw
();
    gRectangle
.Draw
();
    gTriSMid
.Draw
();
    gTriMLeft
.Draw
();
    gParal
.Draw
();

    // right top 
    
glViewport
(WindowWidth
/2 , WindowHeight
/2, WindowWidth
/2, WindowHeight
/2);

    gTriBTop
.Draw
();
    gTriBRight
.Draw
();
    gTriSLeft
.Draw
();
    gRectangle
.Draw
();
    gTriSMid
.Draw
();
    gTriMLeft
.Draw
();
    gParal
.Draw
();

    glFlush
();
}  

显示效果:

image

注意上述代码中,我们的具体的显示代码只有一份,显示代码中并不知道自己绘制了几份,绘制在什么地方,这也就是OpenGL这样设计的好处,本身图形的绘制很简单,在原点附近绘制一个标准的图形而已,一种又一种变换后,却可以产生于原来图形千差万别的图形,这一点有点像设计模式中的decorator模式.

为节省篇幅仅贴出关键片段,完整源代码见我博客源代码的2009-10-29\JTFourTangram 目录,获取方式见文章最后关于获取博客完整源代码的说明。

呵呵,相当happy吧,同一台机子,4个人同时玩七巧板,(事实上,什么游戏都可以借鉴),什么?就一个鼠标没有办法操作?晕哪,你不会插四个鼠标?插四个鼠标也没有用?呵呵,推荐你看看我以前写的关于多鼠标的东西,4个人用4个鼠标同时玩,不是什么不可能的^^以前魔兽好像有个4国战争的游戏地图很流行,要是额外设计,我们可以在同一台机器上玩^^发挥大家的创意吧。

参考资料

1. 《OpenGL Reference Manual 》,OpenGL参考手册

2. 《OpenGL 编程指南》(《OpenGL Programming Guide 》),Dave Shreiner,Mason Woo,Jackie Neider,Tom Davis 著,徐波译,机械工业出版社

3. 《Nehe OpenGL Tutorials》,Nehe著,在http://nehe.gamedev.net/ 上可以找到教程及相关的代码下载,(有PDF版本教程下载)Nehe自己还做了一个面向对象的框架,作为演示程序来说,这样的框架非常合适。也有中文版 ,各取所需吧。

4. 《OpenGL入门学习》 ,eastcowboy著,这是我在网上找到的一个比较好的教程,较为完善,而且非常通俗。这是第一篇的地址:http://bbs.pfan.cn/post-184355.html

本OpenGL系列其他文章

1. 《 Win32 OpenGL 编程(1)Win32下的OpenGL编程必须步骤 》

2. 《Win32 OpenGL编程(2) 寻找缺失的OpenGL函数 》

3. 《Win32 OpenGL编程(3) 基本图元(点,直线,多边形)的绘制 》

4. 《Win32 OpenGL编程(4) 2D图形基础(颜色及坐标体系进阶知识) 》

5. 《Win32 OpenGL编程(5)顶点数组详细介绍 》

6.《Win32 OpenGL编程(6) 踏入3D世界 》

7.《Win32 OpenGL编程(7) 3D视图变换——真3D的关键 》

8.《Win32 OpenGL编程(8) 3D模型变换及其组合应用 》

9.《Win32 OpenGL编程(9) 投影变换 》

应用举例:《Win32 OpenGL编程系列 2D例子 -- 七巧板图形绘制 》

完整源代码获取说明

由于篇幅限制,本文一般仅贴出代码的主要关心的部分,代码带工程(或者makefile)完整版(如果有的话)都能用Mercurial在Google Code中下载。文章以博文发表的日期分目录存放,请直接使用Mercurial克隆下库:

https://blog-sample-code.jtianling.googlecode.com/hg/

Mercurial使用方法见《分布式的,新一代版本控制系统Mercurial的介绍及简要入门 》

要是仅仅想浏览全部代码也可以直接到google code上去看,在下面的地址:

http://code.google.com/p/jtianling/source/browse?repo=blog-sample-code

原创文章作者保留版权 转载请注明原作者 并给出链接

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

相关文章:

  • SQL SERVER 的 CLR 存储过程
  • 有用的Oracle 管理工具 for windows助手
  • 现代软件构建系统的使用 CMake简介
  • 搜集的一些RTMP项目,有Server端也有Client端
  • .NET的数据绑定
  • 从员工、猎头到创业者的职场经验——《程序员羊皮卷》书
  • 完成从学习者到社会人的转变——《程序员羊皮卷》连载(14)
  • 百度全面放弃竞价排名的原因
  • Mobile Market如何能像淘宝网一样流行?
  • Ubuntu 9.10总算出来了
  • 《程序员羊皮卷》还未上市即告售罄的故事
  • [HOW TO]怎么在iPhone程序中实现可多选可搜索按字母排序的联系人选择器
  • 翻阅笔记所得杂记若干
  • Windows Embedded 6.0 R3开发初体验
  • 《程序员羊皮卷》荣升当当IT图书飙升榜第一名
  • 【Amaple教程】5. 插件
  • 78. Subsets
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • CSS 提示工具(Tooltip)
  • ES6 ...操作符
  • ES6简单总结(搭配简单的讲解和小案例)
  • Hibernate【inverse和cascade属性】知识要点
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • Python实现BT种子转化为磁力链接【实战】
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • 阿里云Kubernetes容器服务上体验Knative
  • 机器学习中为什么要做归一化normalization
  • 简单易用的leetcode开发测试工具(npm)
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 前端工程化(Gulp、Webpack)-webpack
  • 使用权重正则化较少模型过拟合
  • 学习使用ExpressJS 4.0中的新Router
  • ​VRRP 虚拟路由冗余协议(华为)
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • (02)vite环境变量配置
  • (4)STL算法之比较
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (十)T检验-第一部分
  • (十三)Flask之特殊装饰器详解
  • (四)图像的%2线性拉伸
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (转)创业家杂志:UCWEB天使第一步
  • (转载)hibernate缓存
  • .axf 转化 .bin文件 的方法
  • .NET处理HTTP请求
  • .net反混淆脱壳工具de4dot的使用
  • .NET连接数据库方式
  • .NET轻量级ORM组件Dapper葵花宝典
  • @Builder用法
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成
  • [20190401]关于semtimedop函数调用.txt