当前位置:  编程技术>移动开发
本页文章导读:
    ▪LogCat下令详细说明        LogCat命令详细说明 Android日志系统提供了记录和查看系统调试信息的功能。日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过 logcat 命令来查看和使用. 使用logcat命.........
    ▪ OpenGL 纹路本质        OpenGL 纹理本质几个月前调试3D纹理时发现一个有趣的问题:同样的3D HW lib库在android2.2系统上可以正常工作,但在2.3系统上却不能工作,显示的图像白屏,调试了几天才将问题定位并解决,解.........
    ▪ 【OpenGL4.0】GLSL-几何着色器详解跟实例(GS:Geometry Shader)       【OpenGL4.0】GLSL-几何着色器详解和实例(GS:Geometry Shader)一、什么是几何着色器(GS:Geometry Shader) Input Assembler(IA)从顶点缓冲区上的输入流中接收顶点数据,并且把数据项转换为规范的.........

[1]LogCat下令详细说明
    来源: 互联网  发布时间: 2014-02-18
LogCat命令详细说明

Android日志系统提供了记录和查看系统调试信息的功能。日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过 logcat 命令来查看和使用.


使用logcat命令

你可以用 logcat 命令来查看系统日志缓冲区的内容:

[adb] logcat [<option>] ... [<filter-spec>] ...

请查看Listing of logcat Command Options ,它对logcat命令有详细的描述 .

你也可以在你的电脑或运行在模拟器/设备上的远程adb shell端来使用logcat命令,也可以在你的电脑上查看日志输出。

$ adb logcat

你也这样使用:

# logcat

过滤日志输出

每一个输出的Android日志信息都有一个标签和它的优先级.

  • 日志的标签是系统部件原始信息的一个简要的标志。(比如:“View”就是查看系统的标签).
  • 优先级有下列集中,是按照从低到高顺利排列的:
    • V — Verbose (lowest priority)
    • D — Debug
    • I — Info
    • W — Warning
    • E — Error
    • F — Fatal
    • S — Silent (highest priority, on which nothing is ever printed)

在运行logcat的时候在前两列的信息中你就可以看到 logcat 的标签列表和优先级别,它是这样标出的:<priority>/<tag> .

下面是一个logcat输出的例子,它的优先级就似乎I,标签就是ActivityManage:

I/ActivityManager( 585): Starting activity: Intent { action=android.intent.action...}

为了让日志输出能体现管理的级别,你还可以用过滤器来控制日志输出,过滤器可以帮助你描述系统的标签等级.

过滤器语句按照下面的格式描tag:priority ... , tag 表示是标签,priority 是表示标签的报告的最低等级. 从上面的tag的中可以得到日志的优先级. 你可以在过滤器中多次写tag:priority .

这些说明都只到空白结束。下面有一个列子,例子表示支持所有的日志信息,除了那些标签为”ActivityManager”和优先级为”Info”以上的和标签为” MyApp”和优先级为” Debug”以上的。 小等级,优先权报告为tag.

adb logcat ActivityManager:I MyApp:D *:S

上面表达式的最后的元素 *:S ,,是设置所有的标签为”silent”,所有日志只显示有”View” and “MyApp”的,用 *:S 的另一个用处是 能够确保日志输出的时候是按照过滤器的说明限制的,也让过滤器也作为一项输出到日志中.

下面的过滤语句指显示优先级为warning或更高的日志信息:

adb logcat *:W

如果你电脑上运行logcat ,相比在远程adbshell端,你还可以为环境变量ANDROID_LOG_TAGS :输入一个参数来设置默认的过滤

export ANDROID_LOG_TAGS="ActivityManager:I MyApp:D *:S"

需要注意的是ANDROID_LOG_TAGS 过滤器如果通过远程shell运行logcat 或用adb shell logcat 来运行模拟器/设备不能输出日志.

控制日志输出格式

日志信息包括了许多元数据域包括标签和优先级。可以修改日志的输出格式,所以可以显示出特定的元数据域。可以通过 -v 选项得到格式化输出日志的相关信息.

  • brief — Display priority/tag and PID of originating process (the default format).
  • process — Display PID only.
  • tag — Display the priority/tag only.
  • thread — Display process:thread and priority/tag only.
  • raw — Display the raw log message, with no other metadata fields.
  • time — Display the date, invocation time, priority/tag, and PID of the originating process.
  • long — Display all metadata fields and separate messages with a blank lines.

当启动了logcat ,你可以通过-v 选项来指定输出格式:

[adb] logcat [-v <format>]

下面是用 thread 来产生的日志格式:

adb logcat -v thread

需要注意的是你只能-v 选项来规定输出格式 option.

查看可用日志缓冲区

Android日志系统有循环缓冲区,并不是所有的日志系统都有默认循环缓冲区。为了得到日志信息,你需要通过-b 选项来启动logcat 。如果要使用循环缓冲区,你需要查看剩余的循环缓冲期:

  • radio — 查看缓冲区的相关的信息.
  • events — 查看和事件相关的的缓冲区.
  • main — 查看主要的日志缓冲区

-b 选项使用方法:

[adb] logcat [-b <buffer>]

下面的例子表示怎么查看日志缓冲区包含radio 和 telephony信息:

adb logcat -b radio

查看stdout 和stderr

在默认状态下,Android系统有stdout 和 stderr (System.out和System.err )输出到/dev/null ,在运行Dalvik VM的进程中,有一个系统可以备份日志文件。在这种情况下,系统会用stdout 和stderr 和优先级 I.来记录日志信息

通过这种方法指定输出的路径,停止运行的模拟器/设备,然后通过用setprop 命令远程输入日志

$ adb shell stop $ adb shell setprop log.redirect-stdio true $ adb shell start

系统直到你关闭模拟器/设备前设置会一直保留,可以通过添加/data/local.prop 可以使用模拟器/设备上的默认设置

Logcat命令列表 Option Description -b <buffer> 加载一个可使用的日志缓冲区供查看,比如event 和radio . 默认值是main 。具体查看Viewing Alternative Log Buffers.

    
[2] OpenGL 纹路本质
    来源: 互联网  发布时间: 2014-02-18
OpenGL 纹理本质

几个月前调试3D纹理时发现一个有趣的问题:同样的3D HW lib库在android2.2系统上可以正常工作,但在2.3系统上却不能工作,显示的图像白屏,调试了几天才将问题定位并解决,解决方法很简单:

1、修改GLExtensions.h头文件对于变量mHaveDirectTexture赋值使其值为TRUE

2、使用mFailoverTexture作为当前纹理绘图

下面详细介绍OpenGL纹理知识及如何确认问题所在:


一、OpenGL基本原理

OpenGL是将用数学语言和色彩等信息描述的三维空间物体通过计算转换成二维图像并显示出来的程序库。
三维空间中的对象被描述成一系列的顶点(用来定义几何对象)或像素(用来定义图像)。OpenGL对数据进行几个步骤的处理将其转换成像素,这些像素存放帧缓冲区中形成最终需要的图形。---- 本质所在

整个数据处理流程:

1、OpenGL  纹理介绍

比如绘制一面砖墙,就可以用一幅真实的砖墙图像或照片作为纹理贴到一个矩形上,这样,一面逼真的砖墙就画好了。如果不用纹理映射的方法,则墙上的每一块砖都必须作为一个独立的多边形来画。另外,纹理映射能够保证在变换多边形时,多边形上的纹理图案也随之变化。例如,以透视投影方式观察墙面时,离视点远的砖块的尺寸就会缩小,而离视点较近的就会大些。此外,纹理映射也常常运用在其他一些领域,如飞行仿真中常把一大片植被的图像映射到一些大多边形上用以表示地面,或用大理石、木材、布匹等自然物质的图像作为纹理映射到多边形上表示相应的物体。

最基本的执行纹理映射所需的步骤:
1)定义纹理  
2)控制滤波 
3)说明映射方式
4)绘制场景,给出顶点的纹理坐标和几何坐标。
注意:纹理映射只能在RGBA方式下执行,不能运用于颜色表方式。
纹理不仅可以是二维的,也可以是一维或其它维的。


纹理定义:
void glTexImage2D(GLenum target,GLint level,GLint components, GLsizei width, glsizei height,GLint border, GLenum format, GLenum type, const GLvoid *pixels); 定义一个二维纹理映射
参数target是常数GL_TEXTURE_2D。
参数level表示多级分辨率的纹理图像的级数,若只有一种分辨率,则level设为0。
参数components是一个从1到4的整数,指出选择了R、G、B、A中的哪些分量用于调整和混合,1表示选择了R分量,2表示选择了R和A两个分量,3表示选择了R、G、B三个分量,4表示选择了R、G、B、A四个分量。
参数width和height给出了纹理图像的长度和宽度
参数border为纹理边界宽度,它通常为0,width和height必须是2m+2b,这里m是整数,长和宽可以有不同的值,b是border的值。纹理映射的最大尺寸依赖于OpenGL,但它至少必须是使用64x64(若带边界为66x66),若width和height设置为0,则纹理映射关闭。

参数format和type描述了纹理映射的格式和数据类型,它们在这里的意义与在函数glDrawPixels()中的意义相同,事实上,纹理数据与glDrawPixels()所用的数据有同样的格式。数format可以是GL_COLOR_INDEX、GL_RGB、GL_RGBA、GL_RED、GL_GREEN、GL_BLUE、GL_ALPHA、GL_LUMINANCE或GL_LUMINANCE_ALPHA(注意:不能用GL_STENCIL_INDEX和GL_DEPTH_COMPONENT)。
类似地,参数type是GL_BYPE、GL_UNSIGNED_BYTE、GL_SHORT、 GL_UNSIGNED_SHORT、GL_INT、GL_UNSIGNED_INT、GL_FLOAT或GL_BITMAP。
参数pixels包含了纹理图像数据,这个数据描述了纹理图像本身和它的边界。


纹理控制函数:

void glTexParameter{if}[v](GLenum target,GLenum pname,TYPE param); 具体控制方式:
纹理图像为正方形或长方形,但当它映射到一个多边形或曲面上并变换到屏幕坐标时,纹理的单个纹素很少对应于屏幕图像上的象素。根据所用变换和所用纹理映射,屏幕上单个象素可以对应于一个纹素的一小部分(即放大)或一大批纹素(即缩小)。
glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
第一个参数可以是GL_TEXTURE_1D或GL_TEXTURE_2D,即表明所用的纹理是一维的还是二维的;第二个参数指定滤波方法,其中参数值GL_TEXTURE_MAG_FILTER指定为放大滤波方法GL_TEXTURE_MIN_FILTER指定为缩小滤波方法;第三个参数说明滤波方式,若选择GL_NEAREST则采用坐标最靠近象素中心的纹素,这有可能使图像走样;若选择GL_LINEAR则采用最靠近象素中心的四个象素的加权平均值。


void glTexParameter{if}[v](GLenum target,GLenum pname,TYPE param); 如提供了mipmap, 对放大和缩小映射的影响: 1) 对于放大映射, 只使用最小等级的纹理图像. 2) 对于缩小映射, 使用最合适的一种或两种的mipmap的滤波方法. 如滤波方法为GL_NEAREST或GL_LINEAR, 则只使用最小等级的mipmap. 3) 只同时使用一个mipmap, 选择滤波方法GL_NEAREST_MIPMAP_NEAREST或GL_LINEAR_MIPMAP_NEAREST(使用线性插值).   使用那种mipmap取决于缩小量.缺点为存在一个到使用下一个mipmap的切换点. 4) 使用滤波方法GL_NEAREST_MIPMAP_LINEAR或GL_LINEAR_MIPMAP_LINEAR, 根据两个最合适的mipmap中的纹素值进行线性插值. 警告: 如指定一种mipmap纹理滤波方法,但未提供一组完整的mipmap, 则OpenGL隐式禁用纹理映射.


void glTexParameter{if}[v](GLenum target,GLenum pname,TYPE param); 重复与约简
纹理坐标可以超出(0,1)范围,并且在纹理映射过程中可以重复映射或约简映射。在重复映射的情况下,纹理可以在s,t方向上重复,即
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
若将参数GL_REPEAT改为GL_CLAMP,则所有大于1的纹素值都置为1,所有小于0的值都置为0。


实际上,可以用纹理中的值来调整多边形(曲面)原来的颜色,或用纹理图像中的颜色与多边形(曲面)原来的颜色进行混合。因此,OpenGL提供了三种纹理映射的方式,这个函数是: void glTexEnv{if}[v](GLenum target,GLenum pname,TYPE param);
第一个参数为纹理环境,必为GL_TEXTURE_ENV。第二个参数为纹理环境参数的名称。第三个参数为单值符号常数或指向参数数组的指针。设置纹理映射方式。
若参数pname是GL_TEXTURE_ENV_MODE,则参数param可以是GL_DECAL、GL_MODULATE或GL_BLEND,以说明纹理值怎样与原来表面颜色的处理方式;
若参数pname是GL_TEXTURE_ENV_COLOR,则参数param是包含四个浮点数(分别是R、G、B、A分量)的数组,这些值只在采用GL_BLEND纹理函数时才有用。


纹理坐标 
在绘制纹理映射场景时,不仅要给每个顶点定义几何坐标,而且也要定义纹理坐标。经过多种变换后,几何坐标决定顶点在屏幕上绘制的位置,而纹理坐标决定纹理图像中的哪一个纹素赋予该顶点。并且顶点之间的纹理坐标插值与平滑着色插值方法相同。
纹理图像是方形数组,纹理坐标通常可定义成一、二、三或四维形式,称为s,t,r和q坐标,以区别于物体坐标(x,y,z,w)和其他坐标。一维纹理常用s坐标表示,二维纹理常用(s,t)坐标表示,目前忽略r坐标,q坐标象w一样,一般值为1,主要用于建立齐次坐标。OpenGL坐标定义的函数: 
void gltexCoord{1234}{sifd}[v](TYPE coords);
   设置当前纹理坐标,此后调用glVertex*()所产生的顶点都赋予当前的纹理坐标。对于gltexCoord1*(),s坐标被设置成给定值,t和r设置为0,q设置为1;用gltexCoord2*()可以设置s和t坐标值,r设置为0,q设置为1;对于gltexCoord3*(),q设置为1,其它坐标按给定值设置;用gltexCoord4*()可以给定所有的坐标。


坐标自动生成 
在某些场合(环境映射等)下,为获得特殊效果需要自动产生纹理坐标,并不要求为用函数gltexCoord*()为每个物体顶点赋予纹理坐标值。OpenGL提供了自动产生纹理坐标的函数,其如下: void glTexGen{if}[v](GLenum coord,GLenum pname,TYPE param); 自动产生纹理坐标。
第一个参数必须是GL_S、GL_T、GL_R或GL_Q,它指出纹理坐标s,t,r,q中的哪一个要自动产生;
第二个参数值为GL_TEXTURE_GEN_MODE、GL_OBJECT_PLANE或 GL_EYE_PLANE;
第三个参数param是一个定义纹理产生参数的指针,其值取决于第二个参数pname的设置,当pname为GL_TEXTURE_GEN_MODE时,param是一个常量,即GL_OBJECT_LINEAR、GL_EYE_LINEAR或GL_SPHERE_MAP,它们决定用哪一个函数来产生纹理坐标。对于pname的其它可能值,param是一个指向参数数组的指针。


纹理对象 
使用纹理对象来存储纹理数据的步骤: 1) 生成纹理对象名称 2) 将纹理对象绑定到纹理数据(包括图像数据数组和纹理属性), 即创建纹理对象. 3) 如果OpenGL实现高性能纹理工作集, 应检查是否有足够的空间来存储所有的纹理对象. 如没有足够空间, 应设置每个纹理对象的优先级, 以确保最常用的纹理留在工作集中 4) 绑定和重新绑定纹理对象, 以便可以将其中的纹理映射到物体上.

生成纹理对象名称
void glGenTextures(GLsizei n, GLint* textureNames); 功能: 通过数组textureNames返回n个未用的纹理对象名, 返回的名称不必是相邻的整数. GLboolean glIsTexture(GLint textureName); 功能: 如textureName是已被绑定的纹理对象名, 且没有被删除, 则返回GL_TRUE, 如textureName为0, 或非0, 但不是已有纹理对象的名称, 返回GL_FALSE. 注意: 如glGenTextures()返回, 但未使用glBindTextures()绑定, 仍返回GL_FALSE.


生成纹理对象名称
void glGenTextures(GLsizei n, GLint* textureNames); 功能: 通过数组textureNames返回n个未用的纹理对象名, 返回的名称不必是相邻的整数. GLboolean glIsTexture(GLint textureName); 功能: 如textureName是已被绑定的纹理对象名, 且没有被删除, 则返回GL_TRUE, 如textureName为0, 或非0, 但不是已有纹理对象的名称, 返回GL_FALSE. 注意: 如glGenTextures()返回, 但未使用glBindTextures()绑定, 仍返回GL_FALSE.


创建和使用纹理对象
void glBindTexture(GLenum target, GLuint textureName); 功能: 完成下面几项工作. 1) 如textureName为非零无符号整数, 首次被使用, 则创建一新的纹理对象, 并将其名称设置为参数textureName的值. 2) 绑定一个已创建的纹理对象时, 该纹理对象将进入活动状态. 3) 如textureName为0, OpenGL将停止使用纹理对象, 返回到未命名的默认纹理. 4) 首次被创建时, target指定了维数, 其取值为GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D 或 GL_TEXTURE_CUBE_MAP. 5) 首次被创建时, 诸如缩小滤波方法, 放大滤波方法, 环绕模式, 边框颜色, 纹理优先级等纹理属性被设置为默认值.


纹理映射整个过程:

三维图形中Texture Mapping应用的最广,将位图粘贴到模型表面使物体更具有真实感。模型做变换时映射的纹理也会随之变化。
auxDIBImageLoad(Filename); // 载入位图并返回指针 
glGenTextures(1, &texture[0]); // 创建纹理 
glBindTexture(GL_TEXTURE_2D, texture[0]); //选择纹理
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); //使用来自位图数据生成纹理 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //显示图像时采用的滤波方式,线形滤波需要CPU和显卡做更多的运算 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // 非线形滤波,低质量贴图,图片斑驳
glBindTexture(GL_TEXTURE_2D, texture[0]); // 选择纹理 
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 纹理和四边形的左上 


二、解决问题的方法

从图片显示白屏原因可能是生成的图片或者贴图纹理上显示有问题,因此先从图片生成源查起,在androdi2.3中有个函数:(layer.cpp文件)

void Layer::reloadTexture(const Region& dirty)
{
    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
    if (buffer == NULL) {
        // this situation can happen if we ran out of memory for instance.
        // not much we can do. continue to use whatever texture was bound
        // to this context.
        return;
    }

    if (mGLExtensions.haveDirectTexture()) {
        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
        if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
            // not sure what we can do here...
            goto slowpath;
        }
    } else {
slowpath:
        GGLSurface t;
        if (buffer->usage & GRALLOC_USAGE_SW_READ_MASK) {
            status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);  // 1、得到生成图片的缓冲区存储在GGLSurface类型变量中
            LOGE_IF(res, "error %d (%s) locking buffer %p",
                    res, strerror(res), buffer.get());
                                        
            if (res == NO_ERROR) {
                mBufferManager.loadTexture(dirty, t); // 2、加载到3D纹理中生成纹理贴图
                buffer->unlock();
            }
        } else {
            // we can't do anything
        }
    }
}

因此可以在以上两个点加入代码,将生成的图片内容生成位图文件,从而分析出其具体的问题。

其中生成bmp图片的代码如下,代码很清晰明了就不再分析了,利用一个普通的dummy.bmp文件生成图,而利用glReadPixels读取纹理图内容再处理保存成一帧帧的位图文件

#define BMP_Header_Length 54

static void dump_surface_info(GGLSurface *sur)
{	
	LOGI("===== dump_surface_info ========== \n");
	
	LOGI("width = %d" ,sur->width);
	LOGI("height = %d",sur->height);
	LOGI("stride = %d",sur->stride);
	LOGI("format = %d",sur->format);
	LOGI("data = 0x%x" ,sur->data);
}

static int bmp_convert_format(int format,GLenum *fmt,GLenum *type)
{
	switch(format){
		case HAL_PIXEL_FORMAT_RGBA_8888:
		case HAL_PIXEL_FORMAT_RGBX_8888:
			*fmt = GL_RGBA;
			*type= GL_UNSIGNED_BYTE;
			break;
			
		case HAL_PIXEL_FORMAT_RGB_888:
			*fmt = GL_RGB;
			*type= GL_UNSIGNED_BYTE;
			break;
			
		case HAL_PIXEL_FORMAT_RGB_565:
			*fmt = GL_RGB;
			*type= GL_UNSIGNED_SHORT_5_6_5;
			break;
			
		case HAL_PIXEL_FORMAT_RGBA_5551:
			*fmt = GL_RGBA;
			*type= GL_UNSIGNED_SHORT_5_5_5_1;
			break;
			
		case HAL_PIXEL_FORMAT_RGBA_4444:
			*fmt = GL_RGBA;
			*type= GL_UNSIGNED_SHORT_4_4_4_4;
			break;
	}
	return 0;
}

/* 函数bmp_capture_grab
 * 抓取窗口中的像素,这里强制按照RGB888进行读取,存储为24位颜色图片
*/
int bmp_capture_grab(GGLSurface *sur,char *fname,int no)
{
	FILE* pDummyFile = NULL;
	FILE* pWritingFile = NULL;
	GLubyte* pPixelData = NULL;
	GLubyte BMP_Header[BMP_Header_Length];
	GLint i, j;
	GLint PixelDataLength;
	GLint WindowWidth,WindowHeight;
	char  filename[256];
	GLenum mFormat=GL_RGB,mType=GL_UNSIGNED_BYTE;	
	
	LOGI("===== bmp_capture_grab info ========== \n");
	dump_surface_info(sur);

	//bmp_convert_format(sur->format,&mFormat,&mType);
	
	LOGI("bmp capture start format=0x%x,type=0x%x....",mFormat,mType);

	WindowWidth  = sur->width;
	WindowHeight = sur->height;

	// 计算像素数据的实际长度
	i = WindowWidth * 3; // 得到每一行的像素数据长度
	while (i % 4 != 0) // 补充数据,直到i是的倍数
		++i; // 本来还有更快的算法, 但这里仅追求直观,对速度没有太高要求

	PixelDataLength = i * WindowHeight;

	// 分配内存和打开文件
	pPixelData = (GLubyte*) malloc(PixelDataLength);
	if (pPixelData == NULL){
		LOGI("malloc buffer out of memory failed");
		return -1;
	}

	pDummyFile = fopen("/system/etc/dummy.bmp", "rb");
	if (pDummyFile == NULL){
		LOGE("open dummy file failed");
		return -1;
	}

	sprintf(filename,"/system/etc/%s_%04d.bmp",fname,no);
	pWritingFile = fopen(filename, "wb");
	if (pWritingFile == NULL){
		LOGE("open grab file failed(%s)",filename);
		return -1;
	}

	// 读取像素
	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
	glReadPixels(0, 0, WindowWidth, WindowHeight, GL_RGB, GL_UNSIGNED_BYTE,pPixelData);

	// 把dummy.bmp的文件头复制为新文件的文件头
	fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);
	fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);
	fseek(pWritingFile, 0x0012, SEEK_SET);
	i = WindowWidth;
	j = WindowHeight;
	fwrite(&i, sizeof(i), 1, pWritingFile);
	fwrite(&j, sizeof(j), 1, pWritingFile);

	// 写入像素数据
	fseek(pWritingFile, 0, SEEK_END);
	fwrite(pPixelData, PixelDataLength, 1, pWritingFile);

	// 释放内存和关闭文件
	fclose(pDummyFile);
	fclose(pWritingFile);
	free(pPixelData);
	pPixelData = NULL;
	
	LOGI("bmp capture end succcess");

	return 0;	
}



    
[3] 【OpenGL4.0】GLSL-几何着色器详解跟实例(GS:Geometry Shader)
    来源: 互联网  发布时间: 2014-02-18
【OpenGL4.0】GLSL-几何着色器详解和实例(GS:Geometry Shader)

一、什么是几何着色器(GS:Geometry Shader)


Input Assembler(IA)从顶点缓冲区上的输入流中接收顶点数据,并且把数据项转换为规范的格式。vertex shader通常用来把顶点从模型空间变换到平面空间,vertex shader读取一个顶点,输出一个顶点。Pixel Shader读取单一pixel属性,输出包含颜色和Z信息的的片断。而geometry shader是DirectX10提出的,把同一区域的所有顶点作为输入,产生新的顶点或者区域。此外数据流输出(steam output)把geometry shader输出的顶点信息复制为4个连续的输出缓冲子集。理论上来说,steam output的输出能力和Input Assembler的输入能力相匹配。
Shader就是一段可以改变像素、顶点和几何学特征的小程序。Vertex Shader是专门处理多边形顶点的。那么Geometry shader就是专门用来处理场景中的几何图形。在过去Vertex Shader每一次运行只能处理一个顶点的数据,并且每次只能输出一个顶点的结果。在整个游戏场景中,绘制的几何图形的任务量非常庞大,如果仅仅依靠Vertex Shader单一来完成,效率会极其低下。

现在DX10的设计师们在顶点与像素的处理过程中又加入了(Geometry shader)几何着色器。它可以根据顶点的信息来批量处理几何图形,对Vertex附近的数据进行函数处理,快速创造出新的多边形。通过stream out将这些结果传递给其他Shader或buffer,将CPU从复杂庞大的几何运算中解放出来。大爆炸,粒子效果,瀑布流水等复杂又关联的场景都可以用Geometry shader很逼真的表现出来。

图一是渲染管线示意图。


图一 渲染管线示意图

GS位于VS与PS之间,可以完成许多模型层面上的工作诸如LOD。以往这些工作都是在CPU上完成的,占用了宝贵的CPU循环 —— CPU可是很繁忙的东西,游戏逻辑、音乐、输入接受都是靠它,却无法提高多少性能,CPU的并行计算性能是远远无法和GPU相比的。



二、几何着色器功能简介

GS被设计针对每个图元执行一次。它能够访问图元的所有顶点,以及与其相关的输入变量的值。换句话说,如果前一阶段提供了某一个输出变量,那么GS就可以访问图元中所有顶点的那个变量的值。因此,GS中的输入变量都是数组类型。


需要注意的是,GS所接受的图元和以前的不同,它只接受“可调整的”图元。


可调整的图元(Adjacency Primitive)

在OpenGL中,我们定义了新的图元类型:

GL_LINES_ADJACENCY_EXT 
GL_LINE_STRIP_ADJACENCY_EXT 
GL_TRIANGLES_ADJACENCY_EXT 
GL_TRIANGLE_STRIP_ADJECENCY_EXT

我们可以在glBegin()、glDrawElements()中将他们作为新的参数使用。下面分别说明这4中类型的特点。

(1)Lines with Adjacecy


4*N个顶点被提供,N是要绘制的线段的数目。线段在#1个#2之间绘制,#0和#3提供调整信息。

(2)Line Strip with Adjacency


顶点数目是N+3,N是要绘制的线段的数目。线段在#1、#2、。。。、#N+1之间绘制,#0和#N+2提供调整信息。

(3)Triangles with Adjacency


顶点数目是6*N,组成三角形的是#0、#2、#4.而#1、#3、#5定义了修正三角形。

(4)Triangle Strip with Adjacency


顶点数目是2N+4.#0、#2、。。。定义三角形序列。其他的定义调整三角形。


在着色器链接之前,必须调用glProgramParameter进行相应的设置。

(1)设置GS可以输出的最大顶点数目

glProgramParameteriEXT( progname, GL_GEOMETRY_VERTICES_OUT_EXT, int value )

(2)设置GS接收的图元的类型

glProgramParameteriEXT( progname, GL_GEOMETRY_INPUT_TYPE_EXT, int value )

需要注意的是,GS的输出图元的类型必须和输入图元的类型匹配。

value的可能取值是:

A、GL_POINTS

B、GL_LINES

对应的输入图元类型可以是:GL_LINES、GL_LINE_STRIP、GL_LINE_LOOP

C、GL_LINES_ADJACENCY_EXT

对应的输入图元类型可以是:GL_LINES_ADJACENCY_EXT、GL_LINES_STRIP_ADJACENCY_EXT

D、GL_TRIANGLES

对应的输入图元类型可以是:GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN

E、GL_TRIANGLE_ADJACENCY_EXT

对应的输入图元类型可以是:GL_TRIANGLES_ADJACENCY_EXT、GL_TRIANGLE_STRIP_ADJACENCY_EXT

(3)设置输出图元类型

glProgramParameteriEXT( progname, GL_GEOMETRY_OUTPUT_TYPE_EXT, int value )

value的可能取值是:

GL_POINTS

GL_LINE_STRIP

GL_TRIANGLE_STRIP


GS可以输出0个、1个或者多个图元。这些图元的类型和它从前一阶段接收到的图元的类型不一定相同。然而,GS不能输出多种类型的图元。比如,GS可以接收三角形,输出多个线段序列,或者是输出0个或多个三角形序列。

这就是的GS有多种用途。下面是几个典型例子。一个GS可以依据某些准则比如可见性来移除一些图元。GS也可以产生额外的图元扩大所渲染的对象的形状。GS也可以计算图元的额外信息,而把图元原封不动的输出。GS也可以输出和输入图元完全不同的图元。


GLSL中GS与VS的交互


在GS中,绿色正方形所表示的是由变量gl_VerticesIn所指定的,即最大维数。

GS内置输出变量:
varying out vec4 gl_FrontColor;
varying out vec4 gl_BackColor;
varying out vec4 gl_FrontSecondaryColor;
varying out vec4 gl_BackSecondaryColor;
varying out vec4 gl_TexCoord[]; // at most gl_MaxTextureCoords
varying out float gl_FogFragCoord;


GS内置输入变量:
varying in vec4 gl_FrontColorIn[gl_VerticesIn];
varying in vec4 gl_BackColorIn[gl_VerticesIn];
varying in vec4 gl_FrontSecondaryColorIn[gl_VerticesIn];
varying in vec4 gl_BackSecondaryColorIn[gl_VerticesIn];
varying in vec4 gl_TexCoordIn[gl_VerticesIn][]; // at most will be// gl_MaxTextureCoords
varying in float gl_FogFragCoordIn[gl_VerticesIn];
varying in vec4 gl_PositionIn[gl_VerticesIn];
varying in float gl_PointSizeIn[gl_VerticesIn];
varying in vec4 gl_ClipVertexIn[gl_VerticesIn];


GS的功能实现基于两个很重要的内置函数:EmitVertex和EndPrimitive.这两个函数使得GS能够传送多个顶点或者图元到管线的下一阶段。GS为一个顶点定义输出变量,然后调用EmitVertex。之后,GS就能够接着定义下一个顶点的相关输出变量,再次调用EmitVertex。在对图元的所有顶点完成相同的操作之后,GS调用EndPrimitive让OpenGL知道图元的所有顶点都传送完毕。如果没有显式调用EndPrimitive,系统会隐式调用。不过显式调用是一个好的习惯,建议这么做。如果GS没有调用EmitVertex,那么输入的图元就不会被渲染。


需要注意的是,GS保证输出由输入图元产生的结果的顺序和输入图元的顺序是相同的。这会造成性能上的影响。比如,多个着色器单元并行运算,结果必须被保存然后进行排序。为了在兼容性和效率之间平衡,Shader  Model4.0做了一个限制:每一次执行最多只能产生1024个32位的值。


三、几何着色器运用实例

下面介绍一个实例:用GS实现一个粒子系统,绘制了很多上面贴了纹理的小正方形。

效果如下:


顶点着色器:

#version 400

layout (location = 0) in vec3 VertexPosition;

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;

void main()
{
    gl_Position = ModelViewMatrix * vec4(VertexPosition,1.0);
}
几何着色器:

#version 400

layout( points ) in;
layout( triangle_strip, max_vertices = 4 ) out;

uniform float Size2;   // Half the width of the quad

uniform mat4 ProjectionMatrix;

out vec2 TexCoord;

void main()
{
    mat4 m = ProjectionMatrix;

    gl_Position = m * (vec4(-Size2,-Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(0.0,0.0);
    EmitVertex();

    gl_Position = m * (vec4(Size2,-Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(1.0,0.0);
    EmitVertex();

    gl_Position = m * (vec4(-Size2,Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(0.0,1.0);
    EmitVertex();

    gl_Position = m * (vec4(Size2,Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(1.0,1.0);
    EmitVertex();

    EndPrimitive();
}
片断着色器:

#version 400

in vec2 TexCoord;

uniform sampler2D SpriteTex;

layout( location = 0 ) out vec4 FragColor;

void main()
{
    FragColor = texture(SpriteTex, TexCoord);
}



    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3