浏览量:1,784

齐次表示

齐次表示在图形学中占有非常重要的位置。点表示三维空间中的一个位置,向量表示一个方向,没有具体的位置。使用的矩阵,可以对坐标进行仿射变换,比如旋转、缩放以及错切变换等,然而使用这种矩阵并不能进行平移变换。点的平移是有意义的,但是向量的平移是没有意义的。 简单来说,在三维空间上,点和向量的表示都是3维的,把扩展1维,就得到齐次向量表示,即。若为零,表示一个三维向量;若非零,则表示点。 齐次向量扩展1维,那么原先由的矩阵表示的变换也需要扩展1维,变成的齐次矩阵。的齐次矩阵可以实现旋转、缩放和错切变换,形式为:     矩阵不能表示的位移变换,也可以采用的齐次矩阵来表示     易知,若是一个向量,则得到的结果仍等于,因为向量的位移是没有意义的。 图1. 点的透视投影 齐次表示除了能表表三维空间上所有的仿射变换(两条互相平面的直线,变换后,仍然互相平行),还可以表示透视变换,参见文章《OpenGL原理介绍》,如图1所示。一个点投影到照相机的近平面上,是在轴的负方向上,表示投影平面到源点的距离,则有,则,同理,有,即: 透视变换不能把深度信息给丢弃掉,所以图形学里面引入了伪深度的概念,来表示,透视变换后的坐标为: 其中,。 我们很容易用4×4的齐次矩阵来表示透视变换,如下所示:     的齐次矩阵既可以表示仿射变换也可以表示透视变换,大大简化了硬件的设计要求,图形学中起到了非常重要的位置。    

spacer
浏览量:2,131

OpenGL雾简介

本文主要对OpenGL中雾的计算原理进行介绍,在参考【1】的第6章、 NEHE教程的第16章和第41章都有示例代码。 一. 雾的计算原理 把片断(fragment)颜色和雾颜色以一定比例混合,就能产生雾的效果。比例因子f,主要有三种计算混合因子的方法,如下面的三个等式所示,其中c指的是眼睛坐标与片段中心之间的距离或者是雾坐标,通过等式计算出个的因子f,需要缩放至范围内。 雾浓度的计算等式 在RGBA模式和颜色索引模式下,都能支持雾的计算,具体可以参考【1】。 二. OpenGL雾相关的API函数 void glFog{f,i}(GLenum  pname,  TYPE  param); void glFog{f,i}v(GLenum  pname,  const TYPE *  params); void glFogCoord{d,f}(TYPE  coord); void glFogCoord{d,f}v(TYPE *  coord); void glFogCoordPointer(GLenum  type,  GLsizei  stride,  GLvoid *  pointer); void glFog{f,i}(GLenum  pname,  TYPE  param);

spacer
浏览量:2,188

模板缓冲区

本文主要介绍模板缓冲区的用途,基本用法,主要的操作函数和模板缓冲区在倒影渲染中的应用。 示例代码下载地址:https://github.com/twinklingstar20/twinklingstar_cn_demo_stencil_buffer/ 一. 介绍 所谓的模板缓冲区是做什么用的,举个简单的例子来说明,如图1所示。屏幕上画一个平面,把这个平面写入到模板缓冲区中,再画小球的时候,进行模板测试,小球在平面范围内的内容会显示出来,不在平面范围内的就不显示。假设,把图1中画的平面,看成一扇窗户,而小球看成窗户外面的风景,那么只有在窗户范围内的风景才会显示出来。所谓的模板缓冲区,基本就干这么一件事儿,它在倒影(Reflection)和阴影(Shadow)效果处理上,都起到非常重要的作用。 图1. (1)画一个平面和一个球;(2)启用模板测试,小球不在平面范围内的内容不显示;(3)关闭模板测试,小球在与不在平面范围内,都将内容显示出来 只有存在模板缓冲区的情况下,才会进行模板测试,即将存储在模板缓冲区中的值与参考值进行对比,通过测试的像素才可能在屏幕上显示,而且依赖测试的结果,可能对模板缓冲区中的值进行修改。 OpenGL和DirectX都支持模板缓冲区,每个像素占的位数通常是1、4、8等。渲染过程中,对片断(Fragment)的处理,包括裁剪测试、透明度测试、模板测试、深度测试等等,它们的顺序如图2所示,模板测试发生在深度测试之间。 图2. 每个片断的处理管线 二. OpenGL中与模板缓冲区相关的操作 OpenGL中与模板缓冲区相关的操作,主要有下面几种。 glEnable/glDisable(GL_STENCIL_TEST); glClearStencil(0); glClear(… | GL_STENCIL_BUFFER_BIT); glStencilFunc(function, ref, mask); glStencilOp(stencil_fail, depth_fail, depth_pass); glStencilMask(mask); 默认情况下,模板测试是关闭的,需要调用glEnable()开启模板测试,不用时调用glDisable关系模板测试。 glClearStencil()和glClear()用于清除模板缓冲区。 glStencilFunc设置模板测试比较的条件、参考值和掩码,function可以取的值和意义如下表所示: glStencilOp()用于更新模板缓冲区的操作,模板缓冲区的更新与模板测试的结果和深度测试的结果都有关系,该函数有3个参数,它们的意思分别表示: (1) stencil_fail,规定模板测试失败时进行的操作,默认值是GL_KEEP; (2) depth_fail,规定模板测试通过,但是深度测试失败时的操作,默认值是GL_KEEP; (3) depth_pass,规定了下面有两种情况的操作,默认值是GL_KEEP: i. 模板测试和深度测试都通过 ii.  模板测试通过但是不存在深度缓冲区或者未开启深度测试 glStencilOp()中3个参数可取值和它们对应的意义如下表所示: 三. 倒影

spacer
浏览量:914

How AGP Work(转载)

本文转载于http://computer.howstuffworks.com/agp.htm,对AGP进行了介绍。在图形渲染中主要有三种内存:系统内存(System Memory),显存(Video Memory)和AGP内存(AGP Memory)。系统内存和显存都容易理解,不过AGP内存是什么呢?简单来说,就是把RAM中划出一小块内存,当作显存来用,在“AGP Memory Improvements”小节,有详细的介绍。 Introduction You point, you click; you drag and you drop. Files open and close in separate windows. Movies play, pop-ups pop, and video games fill the screen, immersing you in a world of 3-D

spacer
浏览量:1,567

任意点与平面的反射矩阵

问题描述:设三维空间上,存在一个点,一个平面,求点经过平面的投影点,其中,,,如图1所示。 图1. 点是点经过平面的投影点 设表示点到平面的有向距离,则有: 由于点和点到平面的距离大小相等,且垂直于平面,则有: 把(1)代入(2)式中,得到: 设点和点分别用齐次坐标表示(参见《齐次表示》),则,,那么等式(3)可以表示成齐次矩阵与齐次坐标乘积的形式,即,则为:   (4)  

spacer
浏览量:1,355

OGRE内存分配策略

本文介绍了OGRE渲染引擎中的内存分配器,前言介绍了OGRE版本、编译环境、工具等信息,接着介绍了OGRE渲染引擎中的内存分配和策略的设计、实现。 一. 前言 分析的ogre源代码版本是 操作系统:windows 7 x64 编译工具:CMake 编译器:Visual Studio 2008 编译完成后会生成一个OgreBuildSettings.h文件,包括一些用户自定义的信息,举个简单的例子,下面的几个宏表示编译源码,使它支持D3D9渲染和OpenGL渲染功能,编译的插件有BSP、OCTREE、PCZ、PFX、CG,使用小端字节序。 #define OGRE_BUILD_RENDERSYSTEM_D3D9 /* #undef OGRE_BUILD_RENDERSYSTEM_D3D11 */ #define OGRE_BUILD_RENDERSYSTEM_GL /* #undef OGRE_BUILD_RENDERSYSTEM_GLES */ /* #undef OGRE_BUILD_RENDERSYSTEM_GLES2 */ #define OGRE_BUILD_PLUGIN_BSP #define OGRE_BUILD_PLUGIN_OCTREE #define OGRE_BUILD_PLUGIN_PCZ #define OGRE_BUILD_PLUGIN_PFX #define OGRE_BUILD_PLUGIN_CG OGRE的配置信息,包括分配器的选择、是否提供多线程支持、系统和编译器相关的一些宏定义等,一般保存在下面的几个头文件中。 OgreBuildSettings.h OgreConfig.h

spacer
浏览量:2,396

内存分配器浅谈

ogre渲染引擎中采用的是nedmalloc内存分配器,查了些资料,看了些论文,这里对ogre中使用的nedmalloc内存分配器进行简单的介绍。第1小节,介绍的是好的内存处理器的目标,第2小节,介绍dlmalloc分配器的基本思想,第3小节,介绍nedmalloc的性能。 一. 简介 参考【2】,作者总结了1995年以前的内存分配器,对内存分配器的目的、需要解决的问题、采用的策略等都进行了总结。其中要解决的一个很重要的问题就是碎片化(fragmentation),因为应用程序可以在任意时间,分配任意大小的对象,并在将来的某个时间释放这些内存,就可能导致一个结果就是:在两个使用的内存块之间存在非常小的空闲块,无法满足所要求的内存申请要求,也已经证实碎片化问题是无法避免。对碎片问题的研究在【2】都有详细的表述。 一个内存分配器主要的目的可以总结为如下几点: (1)最大化兼容性 与其它程序兼容,特别是它应该遵守ANSI/POSIX规范 (2)最大化可移植性 尽可能少的依赖系统相关的特征(比如系统调用),同时在某些系统上也要提供一些有用特征的可选操作。遵守系统对字节对齐规则和取址规则的约束。 (3)最小化时间 malloc()、free()和realloc()消耗的时间尽可能的少 (4)最大化可调性 一些可选的方法可以由用户来控制。有静态的(编译时)方法,使用(#define定义一些宏);有动态的(运行时)方法,使用命令来控制。 (5)最大化局部性 尽可能的分配物理内存相互接近的内存块,在程序执行时有利于最小化页面和cache的丢失。 (6)最大化错误检测 通用目的分配器也作为通用目的的内存错误检测工具,显得不太可能,但是分配器应该提供一些由于重写内存、多次释放等原因造成的内存崩溃。 (7)最小化异常 一个使用默认配置的分配器在不同的应用背景下,应该尽可能少的出现异常,比如在窗口工具包里、GUI应用中、编译器中、网络浏览器中等等。 一个内存分配器应当能记录使用的和空闲的内存,在合适的时间范围内最小化存储空间的浪费,即要做到时间开销和空间浪费之间的一个平衡。 二. dlmalloc算法基本思想 这里以dlmalloc内存分配器为例,参考【1】【3】,这里介绍它的算法基本思想。 2.1 边界标签 图1. 边界标签 在内存块的前面和后面都有大小信息,这能带来两个好处: (1)       两个相邻的空闲块能够合并成一个大的内存块 (2)       所有的内存块既能向前遍历,也能向后遍历。 2.2 装箱方法 图2. 装箱方法 内存块均以箱子的形式来维护,以箱子的大小来分组,有128个固定大小的箱子类型,小于512个字节的箱子之间的间隔大小是8个字节。对块的搜索采用最小优先、最佳优先的准则,以便减小碎片化的效果。在1995年以前的版本中,箱子中的块都没有进行排序,所以最佳优先的策略仅仅是一种估计。最近的实现版本中,箱子里的块不采用按大小排序,而是采用了最老优先的准则。 所以把这类算法的归类为“带合并的最佳优先算法”,相邻的空闲块合并为一个更大的空闲块,通过大小排序,把它保存在对应的箱子中。 通过边界标签完成合并和通过装箱方法完成最佳优先匹配,就是内存分配算法的主要思想。在此基础上完成一些启发式的改进,这些改进也是在实现中必需考虑到的一些因素,包括局部性的维护(Locality Preservation)、拓展块的维护(Wilderness Preservation)、内存映射(Memory Mapping)和高速缓存(Cache)。

spacer
浏览量:847

智能指针

示例代码:https://github.com/twinklingstar20/twinklingstar_cn_demo_ogre_smart_pointer 看到Ogre中的智能指针SharedPtr,于是结合以前在Webkit内核中看到的智能指针PassRefPtr和RefPtr一起进行介绍。 由于C++缺乏语言级别的GC(Garbage Collection)支持,实现的代码容易发生内存泄漏的BUG,但是GC也由于额外的负担,降低了代码的效率。另外一种朴素的方法就是智能指针,所谓的智能指针就是将一个计数器与指向的对象的指针相关联,引用计数跟踪该类有多少个对象共享同一指针,当引用计数达到一个阈值时,删除该对象。 对智能指针有深入的理解,前提必须对C++中复制构造函数、运算符重载、对象返回值的原理等有较深入的理解,这些概念的深入理解可以参考《Thinking in C++》这本书中第11章“References &the Copy-Constructor”小节的内容。这里就举一个简单的例子: #include <iostream> #include <vector> using namespace std; class TestCopyConstructor { public: TestCopyConstructor(string nm) { name = nm; } TestCopyConstructor& operator=(const TestCopyConstructor& s)//重载运算符 { this->name = s.name+"New"; printf("operator = : %s\n",name.c_str()); return

spacer
浏览量:2,097

GLSL与RenderMan、ISL、Cg、HLSL的对比

本文参考【1】第20章,选择性的翻译了其中的部分内容,最后的总结参考【2】中的文章。简单的介绍了着色语言的编年史,以及OpenGL的GLSL着色语言与RenderMan着色语言、ISL、Cg、HLSL四种着色语言的对比。 一. 着色语言编年史 普遍认为Rob Cook和Ken Perlin是第一批开发语言来描述着色计算的人,他们针对的主要是离线渲染系统。Perlin的贡献主要在定义了噪音函数和引入了控制结构,Cook的贡献主要在对着色器的分类上,包括平面着色器、光照着色器、气候着色器等等。人们努力的开发一种能充分描述着色计算的语言,直到Pixar公司推出RenderMan接口规范,达到了一个小巅峰。RenderMan是描述离线渲染系统的着色语言的产业标准,在今天仍旧得到广泛的应用。 第一个交互式着色语言是在北卡罗来纳大学的大规模并行图形系统下得到验证的,该系统名叫PixelFlow,PixelFlow使用到的着色语言是由Marc Olano在1998年描述的。后来,Olano离开北卡,加入SGI公司,定义并且实现了一款运行在OpenGL之上的交互式着色语言,它能使用多通道渲染方法来执行着色器。到了2000年,推出了OpenGL着色器,这是第一款商业上实时的、高级的渲染语言。 OpenGL的GLSL、微软的HLSL、NVIDIA的Cg都是尝试定义商业上可行的、实时的、高级着色语言。3Dlabs的Dave Baldwin在2001年10月推出了描述着色语言的白皮书,就是GLSL。NVIDIA的Cg的规范是在2002年6月推出的,微软的HLSL规范是在2002年11月推出的。 二. RenderMan 在1988年,经过几年的开发,Pixar发布了RenderMan接口规范,这些接口定义了建模程序和渲染程序之间的通行协议,为了能产生照片级真实感质量的图像,原始的目标客户主要动画生产商,后来在电影上也得到应用。 与OpenGL不同的是,它有一整套自己的图形处理管线,不需要太关心交互性和硬件实现。它支持几何图元、层次性建模、相机属性、着色器属性等等,这些与OpenGL着色语言类似。 RenderMan着色语言是RenderMan的组成部分,这种语言也是基于C,能够描述任意的着色器,通过RenderMan接口,把它传输给渲染器。与GLSL类似,可以定义场景中的一些特征,可以计算颜色、位置、透明度等。 GLSL为了能够与当前的商业图形硬件相匹配,抽象出了两种着色器:顶点着色器和片断着色器。而RenderMan抽象出了五类着色器:光照着色器、位移着色器、平面着色器、容量着色器和图像着色器。 两种语言在数据类型的定义上也存在一定的差别。 三. ISL ISL是Interactive Shading Language的缩写,是描述OpenGL着色器的语言,这里说的OpenGL着色器是第1节中由Olano在2000年推出的产品,它是由SGI开发的软件包,现在已经被淘汰了。OpenGL着色器不仅定义了着色语言(该着色语言称为交互式着色语言),而且定义了一组API,用于定义着色器和在渲染过程中使用它们的方法。 ISL支持平面着色器和光照着色器,在这一点上,与RenderMan更加类似。 ISL用于提供过去的和现有的硬件的可移植性而设计,GLSL用于提供现有的和将来的硬件的可编程而设计。即,如果图形硬件不支持可编程性,就不会支持GLSL语言;相反,ISL能在各种硬件上执行各种特效,包括在不支持或者明显支持编程性的硬件上。 ISL相当是一种汇编语言,不需要底层的硬件的改变,而GLSL需要硬件底层定义相应的功能,GLSL能把高级语言转化为硬件可执行的机器码,高级语言的编译器是由硬件产商生产的,更容易实现编译器的优化。 四. HLSL HLSL是High-Level Shader Language的缩写,是由微软定义的,在2002年跟DirectX 9一起发布的。与GLSL相类似,它支持顶点着色器(Vertex Shader)和像素着色器(Pixel Shader)。 HLSL的执行环境与GLSL不同,如图1所示。翻译器在DirectX之外,即HLSL程序从来不会直接发送给DirectX 9或者DirectX 10的API上执行。相反,HLSL编译器编译HLSL源码,生成汇编级原码或者二进制程序。 图1 微软的HLSL的执行环境 这种方法的优点是,HLSL程序能够离线编译生成二进制代码,然后再加入到主程序当中,但是在运行时二进制代码仍然需要转化为机器码。GLSL的编译、链接都放到硬件层来实现,给了硬件生产商大量的空间进行着色器优化和体系创新。 HLSL是为DirectX而设计,所有权归微软所有;GLSL是为OpenGL设计,它是一种开放的跨平台标准,改变很少且对以前的版本保持着高度的兼容性。 五. Cg Cg是C for

spacer
浏览量:6,369

OpenGL着色器介绍

本文主要介绍如何使用OpenGL实现着色器程序,首先会简单介绍着色器在OpenGL渲染管线中是什么个位置,接着是介绍可以通过GLSL语言实现的两类着色器:顶点着色器和片段着色器,最后使用OpenGL实现了个DEMO(在文章最后面,提供了下载),演示如何使用OpenGL接口创建着色器程序。 会例代码下载地址:https://github.com/twinklingstar20/twinklingstar_cn_demo_basic_shader/ 一. 简介 OpenGL是把图像数据和几何数据发送给图形硬件,进行一系列处理,最终显示到屏幕上。我们可以随意的设置管线上某些阶段的状态、参数等,但是OpenGL图形管线的基本操作和顺序是不能改变的,即是“固定渲染管线”。通过OpenGL着色语言和支持它的OpenGL API接口,就允许应用程序开发者使用高级编程语言来实现自己的着色器,这就使得开发者能够使用硬件来实现更丰富的渲染效果,这种就称为“可编程渲染管线”。在应用程序当中,这两种管线不能同时使用,只能使用其中的一种渲染管线。 使用OpenGL的着色器,可以丰富渲染效果,能实现的功能包括: (1)       更加真实的材质-金属、石头、木头等 (2)       更加真实的光照效果-区域光照、柔和阴影等 (3)       自然现象-火、烟、水、云等 (4)       高级渲染效果-全局光照、光线追踪器等 (5)       非照片级材质-绘画效果、笔写效果等 (6)       纹理内存新的一些用途-向量的存储、模糊值、多项式系数等 (7)       过程纹理-动态生成的2D、3D纹理等 (8)       图像处理-卷积、复杂混合、模糊掩盖锐化处理(unsharp masking)等 (9)       动画效果-关键帧插值、粒子系统、程序定义的运动等 (10)   自定义的抗锯齿方法 (11)   一般的计算-排序、数学建模、流体动力学等 上面所述的许多技术原先只能通过软件来实现,如果通过OpenGL提供的GLSL语言和接口,可以将那些功能放在硬件层实现,明显渲染效果会得到提升,而且减轻了CPU的负担。 二. 顶点处理器(Vertex Processor)和片断处理器(Fragment Processor) 在《OpenGL原理介绍》一文中,对OpenGL渲染管线的各个阶段进行了介绍,并不是渲染管线中的各个阶段都能通过着色语言实现的着色器来替换。GLSL着色语言能实现两类处理器的功能:顶点处理器和片断处理器。GLSL语言经过很精细地设计,使硬件能够并行的处理顶点和片段,这就给硬件产商实现更快的图形硬件。图1,显示了OpenGL中可编程渲染管线的逻辑图。 图1. OpenGL中的可编程渲染管线的逻辑图 2.1 顶点处理器 传统的顶点处理器能对顶点值和它相关的数据进行处理,主要操作有: (1)      

spacer