澳门网上娱乐.NET平台下本着C3D文件的读写。OpenGL 数据处理(下)

【题外话】

1 纹理基础

纹理是平种植结构化的存储形式(Textures are a structured form of
storage),着色器可以于内读取数据,也克以数据形容副其中。通常用于储存图像数据,并保有多种形式。最广的纹路为2维,但是也是1维、3维或者数组(多单纹理叠加形成单一的逻辑对象)、立方体等花样之纹理。

为创建一个纹理,首先得调用函数(glGenTextures())让OpenGL保存一个名以备使用。该名表示了一个就给创造的纹理对象,只有以拿其绑定至纹路目标(texture
target)后才打开它看成纹理的生命周期。这和以缓存对象绑定到缓存绑定点类似。然而不同的凡,一旦用一个纹理绑定到有目标后,它的色在它叫回收前都非克转。

纹理和图纸据的都靠经编码的图像像素数量。不同的凡大面积的图纸文件格式,比如PNG,JPG,BMP等,是图像为存储信息若使的对信息的特种编码方式。它存储于磁盘中,或者内存中,但是连无能够让GPU所识别。这些文件格式当让读入后,还是要经CPU解压成bitmap,再传递到GPU端进行动。

假定纹理格式是会让GPU所识别的比如说素格式,能为迅速寻址并采样。压缩纹理,是一样种GPU能一直读取并出示的格式,使得图像无需解压即可开展渲染,节约大量之内存。其中非减纹理的格式如下。

RGBA8888:每个像素4字节,RGBA通道各占8号,
OpenGL内GL_RGBA默认类型。
RGBA4444: 每个像素2字节,RGBA通道各占4各。
RGB888: 每个像素3字节,RGB通道各占8员,无透明通道。
RGB565:每个像素2字节,RGB通道各占5/6/5各类,无透明通道。
RGBA5551
每个像素2字节,RGB通道各占5个,透明通道1位,所以要完全透明或不透明。

恰使图的JPEG和PNG等压缩格式一样,纹理也闹那各种压缩格式,如(DXT纹理压缩格式,.dds)(ETC纹理压缩格式,.ktx多纹理和.pkm单纹理)(PVRTC纹理压缩格式,.pvr)。具体的压缩格式不透讨论,但是得知道不同GPU芯片制造商采用了不同之GPU架构,因此其支持之纹理压缩格式不同,其中iPhone系列使用的是Imagination
Technologies的PVRTC架构GPU,其并为iPhone
A系列处理为主之内。不同芯片制造商的GPU支持纹理可参考文章1和文章2。下面图片源于文章2。

澳门网上娱乐 1

前不久实验室设自身修改C3D(The 3D Biomechanics Data
Standard)文件,虽然从网上找到了一个为c3d4sharp的类库,这个类库单纯读取C3D文件之言语还可以,但是倘若要是兑现修改或创造C3D文件就比麻烦了。同时c3d4sharp实现得比较简单,很多C3D文件里片数据还未支持。好以C3D文件总体不是十分复杂,于是我就算起又勾了一个C3D文件读写的库房,现在以codeplex上创造了只门类被C3D.NET。

1.1 原始图像数据

计算机图形最初的当儿只得用个图(bitmap)表示,最早的电脑图形对于有点只能用0和1代表黑色或白色,后来可以据此自0-256之价来表示其灰度。

 

1.1.1 像素包装

图像数据以内存中甚少为严密包裹的花样有,在众多硬件平台上,出于性能考虑,图像的每一行应还起某特定对齐地址开始。在默认情况下,OpenGL采用4独字节的对准齐方式。例如,有同一摆RGB图像,包含3单重,每个分量占1单字节,如果图像宽度为199像素,那么每一行要的字节数为597字节。但是只要硬件的网布局是以4字节排列,那么图像的各一样执行最终都见面填充额外的3独空字节,从而让每一行的内存地址偏移量为4之整数加倍。尽管这样表面上看起是浪费了内存空间,但是这种排列能够给大部分CPU更快捷的获取数据块。另外多未经压缩的图形格式为按这种惯例,如Windows中的.BMP文件。Targa(.TGA)是坐1字节排列的。

在朝OpenGL提交图像数据要打OpenGL中取图像数据经常,OpenGL需要知道对数码为何种措施包装和解包装操作。通过函数void glPixelStorei (GLenum pname, GLint param)glPixelStoref (GLenum pname, GLfloat param)可以转或恢复如从的储存方。例如需要改变成为一体包裹方式(即像素行的指向齐方式,可卜1.2.4.8)调用函数glPixelStorei(GL_UNPACK_ALIGNMENT, 1)。其参数都是为GL_UNPACK_和GL_PACK_否前缀方式改为对出现,前正代表从今内存中读取数据(对函数glReadPixels产生潜移默化),后者表示存储数据及内存中(对调用函数glTexImage2D顶发生影响)。该函数的事无巨细介绍参考官网或原著。

【文章索引】

1.1.2 像素图

今日底微机图形都因像素图(pixmap)的点子囤,它发出一定量栽不同的章程囤图形,其一为亮度信息(luminance)加颜色分量(Cb,
Cr),其第二也RGB(A)颜色分量。

OpenGL中无法直接读取像素图。只能通过第三方库获取像素图中之像素数量。此外,在OpenGL中允许以GPU中之颜色缓存读取到内存中。对承诺函数如下。其中pixels所依赖的内存空间需要足够存储图形。如果指定的窗口坐标越了同意的限,实际只能得到OpenGL缓存区内部数据。Format表示了pixel指向的内存空间颜色布局方式。

void  glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)

此外需要注意,glReadPixels从图硬件中复制数据,通常会由此总线传输到系统内存。在这种状态下,应用程序必将给死,直至内存传输就。此外,如果指定了一个与图片硬件本地排列不同的像素布局,那么当数开展重定格式时以发生额外的特性开销。另外要留意的是欠函数将数据形容副内存中,它的作为中上文的函数glPixelStorei安装有些参数的熏陶。

除此以外该函数对于用对缓存机制的OpenGL环境,默认的凡读取后台缓存区数据,可以由此调用如下函数来如果其读取前台缓存区,其参数为GL_FRONT、GL_BACK等。

void glReadBuffer(GLenum mode);
  1. C3D文件格式的结构
  2. C3D文件头之构造
  3. C3D文件参数集合的组织
  4. C3D文件数量区域之布局
  5. 采取C3D.NET读写文件示例
1.1.3 包装的比如素格式

齐同一节中函数glReadPixels的参数type,通常采取的是GL_FLOAT等门类,但是呢供诸如GL_UNSIGNED_BYTE_3_2_2相当包裹的RGB以及有包的RGBA值类型,为底凡允许图形数据因更多之缩减形式储存,以便同重宽广的水彩图形硬件匹配。

GL_UNSIGNED_BYTE_3_2_2包档次指用1只字节即8各项存储三独颜色分量,其储存顺从高位到低位分别吗第1及第3单重。GL_UNSIGNED_BYTE_3_2_2_REV坐反顺序存储。

 

1.1.4 保存像素

于OpenGL的苏存区读取出来的颜料数据足以叫贮存到地面图片被。原书中采取的是GLTools三正在库中的API,此处不具体介绍。对于mac
OS环境下,可以利用CoreGraphics框架中之连带API使用这些像素数量绘制NSImage图片并储存至磁盘中。代码如下。

- (void)saveImage {
    CGSize imageSize = CGSizeZero;
    unsigned int imageByteSize = imageSize.width * imageSize.height * 4;
    GLubyte *rawImagePixels = (GLubyte *)malloc(imageByteSize);
    glReadPixels(0, 0, imageSize.width, imageSize.height, GL_RGBA, GL_FLOAT, rawImagePixels);

    CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
    CGContextRef imageContext = CGBitmapContextCreate(rawImagePixels, imageSize.width, imageSize.height, 8, imageSize.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
    CGImageRef cgImage = CGBitmapContextCreateImage(imageContext);
    NSImage *image = [[NSImage alloc] initWithCGImage:cgImage size:imageSize];
    CGContextRelease(imageContext);
    CGColorSpaceRelease(genericRGBColorspace);
    CGImageRelease(cgImage);
    free(rawImagePixels);

    [image lockFocus];
    //先设置 下面一个实例
    NSBitmapImageRep *bits = [[NSBitmapImageRep alloc]initWithFocusedViewRect:NSMakeRect(0, 0, imageSize.width, imageSize.height)];
    [image unlockFocus];
    //再设置后面要用到得 props属性
    NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor];
    //之后 转化为NSData 以便存到文件中
    NSData *imageData = [bits representationUsingType:NSJPEGFileType properties:imageProps];
    //设定好文件路径后进行存储就ok了
    NSString *filePath = @"";
    [imageData writeToFile:filePath atomically:YES];
}

【一、C3D文件格式的组织】

1.1.5 读取像素

原书中采取GLTools三着库相关API读取targa图片文件中之像素数量。而以mac
OS环境遭受,可以先行通过NSImage读取文件,然后经过Core
Graphics框架中之有关API将其转化为像从数据,其代码如下。

// 读取图片
NSImage *image = [NSImage imageNamed:@""];
NSData *imageNSData = [image TIFFRepresentation];
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageNSData, NULL);
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
// 将图片转换为二进制数据
CGSize pixelSizeToUseForTexture = image.size;
GLubyte *imageData = calloc(1, (int)pixelSizeToUseForTexture.width * (int)pixelSizeToUseForTexture.height * 4);
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
CGContextRef imageContext = CGBitmapContextCreate(imageData, (size_t)pixelSizeToUseForTexture.width, (size_t)pixelSizeToUseForTexture.height, 8, (size_t)pixelSizeToUseForTexture.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGContextDrawImage(imageContext, CGRectMake(0, 0, pixelSizeToUseForTexture.width, pixelSizeToUseForTexture.height), imageRef);
CGContextRelease(imageContext);
CGColorSpaceRelease(genericRGBColorspace);
//此时已经获取的像素数据存储在imageData所表示的内存空间内,使用像素数据生成纹理的方法在后面载入纹理时候介绍
free(imageData);

第一说C3D文件整体不是老复杂,也尚未多复杂的定义,C3D的文档格式可以自那个官网下载或者在线阅读。首先C3D文件是以Section为单位存储的,每一个Section固定啊512字节。Section一定是据顺序存储的,不过有意思的凡,Section的序号是自从1始发之,而无是0。C3D文件分为三部分,分别是Section
ID = 1的C3D文件头(固定啊一个Section,512字节),Section
ID一般等2(在文书头内见面吃闹)的C3D参数集合以及Section
ID不明了当几(在文件头和参数集合中都见面受出)的C3D数据有。

1.2 载入纹理

要是得到像从数据后,可以调用函数载入纹理,纹理要让载入,这些纹理就会见变成当下纹理状态的同组成部分,有三单假设下OpenGL函数最常用来打缓存中载入纹理。

void glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
void glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);

此处仅仅受了载入1维、2维及3维纹理,立方体纹理后面介绍。该函数从data指向的内存地址复制纹理信息,这种多少复制可能会见生出特别充分的支出,稍后将讨论几只减轻这个题目的不二法门。其target参数通常采取GL_TEXTURE_1(2/3)D,同时为可以应用GL_PROXY_TEXTURE_1(2/3)D指定代理纹理,代理纹理内容后介绍。level参数指定了mip贴图层次,对于非mip贴图的纹理,该参数总为0。

internalformat参数指定了纹路单元颜色存储方,以及是否开展削减,常用GL_RGBA。参数width、height和depth指定加载纹理的宽窄、高度与深,此处需要留意的是,这些价值最好为2的整数蒙面,对于OpenGL2.0在先的版,不符合要求的值导致纹理贴图被隐式禁用,尽管之后的本子可以下无符合要求的数目,但是会下滑实现效率。

参数border指定了一个纹理边界宽度,这个价少设置为0,在介绍纹理过滤时,该参数扮演了根本之角色。参数format和type表示pixels指向的像素数量被之数码格式。

而是C3D也时有发生不行复杂的地方,一个凡关于整型的使,可以利用下有号的(Int16),也堪运用无符号的(UInt16),只不过后者会积存的数据量要多有罢了,既然这样,不知怎么当初还要采取闹记号的整型。而且最重点之是,文档内没有外标识能指出文档使用的是何种整型。官方给来的解决措施是,可以依据例如帧总数、帧索引等看清,如果念来负数,则应用无符号的,否则用闹号的。

1.2.1 使用颜色缓存区

一维以及二维纹理可以自GPU的水彩缓存区加载数据并将那作一个初的纹理来使。函数如下。源缓存区通过glReadBuffer设置。2D颜色缓存区是绝非深度,因此不能够读博3D纹理。

void glCopyTexImage1D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
void glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);

旁一个凡C3D文件能够于不同品类的CPU上转移,这表现让不同CPU可能应用的字节序(Endian)和浮点数字不同,比如大家用之CPU都是行使Little-Endian以及IEEE754的浮点数标准。从网上查还发现发生DEC
(VAX)以及IBM等CPU采用不同之浮点数标准,详见我前面同一首文章:http://www.cnblogs.com/mayswind/p/3365594.html。而C3D则是支持3接近CPU,Intel
CPU采用Little-Endian以及IEEE754标准的浮点数,DEC
(VAX)采用的Little-Endian以及故意的浮点数,MIPS
(SGI)采用的Big-Endian以及IEEE754标准的浮点数,所以当读取文档的早晚恐怕得分外开展拍卖,在第三节省会详细说明。

1.2.2 更新纹理

复加载纹理可能会见成为性的瓶颈,当有已加载的纹理数据不再使用,可以替代掉其中的有些或全体,替换纹理内容往往比用函数glTextImage加载纹理更快。更新纹理函数如下。其中绝大部分参数和glTextImage函数中的参数准确对应。xOffset、yOffset、zOffset参数指定了当原本纹理贴图中启交替纹理数据的偏移量。

void glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
void glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
void glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);

此外,OpenGL还得从GPU颜色缓存区读博纹理,并插入或调换原来纹理的一致局部,其函数如下。这里需要留意的凡由颜色缓存区是2D之,因此glCopyTexSubImage3D获取到之凡一个颜料平面。

void glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
void glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
void glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);

 

1.2.3 纹理对象

纹理状态包含纹理图像本身和同一组纹理参数,这些参数控制过滤与纹理坐标的行。使用函数glTexParameter可以安装这些纹理状态参数。glTexImage和glTexSubImage函数调用时耗费内存较多,在纹理直接开展快捷切换或者另行加载不同纹理是支付很挺之操作。OpenGL可以经过纹理对象管理大多还纹理并当他们中进行快速切换。纹理状态由目前绑定纹理对象保障,纹理对象由一个无符号整数标识。可以经过下函数生成一个纹理对象往往组。

void glGenTextures (GLsizei n, GLuint *textures);

绑定其中的某某纹理可以由此函数glBindTexture好。此后有纹理加载与纹理参数设置只影响时绑定的纹路对象。调用函数glDeleteTextures形成。多次调用函数在销毁大容量纹理时或许会见时有发生一定之推。判断有句柄是否问纹理句子柄可以调用函数glIsTexture

【二、C3D文件头的组织】

1.2.4 加载纹理示例

用读取到之像素数量加载到纹理中代码如下,注意此处imageData未如从数据,如果改段内存为malloc函数分配,在利用完后必须自由内存。

// 将二进制数据写入纹理中
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// 下面函数设置了纹理参数,用于描述当纹素坐标不为整数时,以及纹理坐标不在[0-1]范围内时,纹理颜色采样策略
// 具体请参考文章http://blog.csdn.net/wangdingqiaoit/article/details/51457675
// 这里使用最近纹素坐标采样方式,下文还会继续讲解设置纹理参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

第一来说第一有,也即是C3D的文件头,C3D的文书头一定就占1只Section,即一定的512字节,所以只要读取前512字节就可以把方方面面头数据获得到了。虽然每个Section有512字节的多,但是于C3D的公文头才占了怪少的一致局部,在文书头挨起大气空的区域。其中第一片段凡是文本头参数有,内容如下:

2 纹理应用

澳门网上娱乐 2

2.1 创建同初始化纹理(Creating and Initializing Textures)

整的纹路创建过程包括好成一个名,将那绑定至有纹理目标,然后告诉OpenGL需要以内部蕴藏图像的尺寸。其利用实例的代码如下。

// The type used for names in OpenGL is GLuint
GLuint texture;

// Generate a name for the texture
glGenTextures(1, &texture);

// Now bind it to the context using the GL_TEXTURE_2D binding point
glBindTexture(GL_TEXTURE_2D, texture);

// Specify the amount of storage we want to use for the texture
// 注意该接口在OpenGL 4.3后才能使用,因此mac中无法调用该函数
glTexStorage2D(GL_TEXTURE_2D,    // 2D texture
               1,                // 1 mipmap level
               GL RGBA32F,       // 32-bit floating-point RGBA data
               256, 256);        // 256 x 256 texels

拖欠函数的参数mipmapping代表表示纹理细分级数,该技术根据拖欠参数生成一层层不同分辨率的贴图,在渲染时冲物体远近选取适当分辨率的贴图,从而加快渲染速度并缓解锯齿现象。internal
format
为纹理内部保存图像的数额格式,width和height为图像的丰足和强。该函数调用后,OpenGL将会分配足够的内存空间用于存储纹理。接下来要使用函数glTexSubImage2D()也缓存中输入数据。其示例如下。

// Define some data to upload into the texture
float * data = new float[256 * 256 * 4];

// generate_texture() is a function that fills memory with image data
generate_texture(data, 256, 256);

// Assume the texture is already bound to the GL_TEXTURE_2D target 
glTexSubImage2D(GL_TEXTURE_2D,     // 2D texture
                0,                 // Level 0
                0, 0,              // Offset 0, 0
                256, 256,          // 256 x 256 texels, replace entire image
                GL_RGBA,           // Four channel data
                GL_FLOAT,          // Floating-point data
                data);             // Pointer to data
// Free the memory we allocated before - OpenGL now has our data
delete [] data;

简言之的纹路贴图实例如下,源代码。

澳门网上娱乐 3

字节 类型 说明
00H Byte 参数集合开始的Section ID(通常为0x02,但也不一定)
01H Byte 文件标识(固定为0x50)
02H-03H Int16 每帧里3D坐标点的个数
04H-05H Int16 每帧里模拟测量的个数
06H-07H Int16 第1帧的序号(最小为1)
08H-09H Int16 最后1帧的序号
0AH-0BH Int16 最大插值差距
0CH-0FH Single 比例因子(正数表示存储的帧为整数帧,负数为浮点帧)
10H-11H Int16  数据区域开始的Section ID
12H-13H Int16 每帧模拟采样个数
14H-17H Single 帧率

2.2 纹理目标与项目(Texture Targets and Types)

OpenGL中可用的纹路类型如下,每个重点字都简单了一样部分GL_TEXTURE_
1D:同维纹理。 2D:老二维纹理。
3D:老三维纹理。RECTANGLE:矩形纹理。1D_ARRAY:一样维纹理数组。2D_ARRAY:仲维纹理数组。CUBE_MAP:立方体纹理。CUBE_MAP_ARRAY:立方体纹理数组。BUFFER:缓存纹理。2D_MULTISAMPLE:二维差不多重样本纹理。2D_MULTISAMPLE _ARRAY:二维几近重样本纹理数组。

GL_TEXTURE_2D品类的纹理是最常用项目,通常用于包裹模型表面。GL_TEXTURE_1D类的纹路被当高度也1的次维纹理。另外,3D纹理可以用于表示拥有容量的纹理(can
be used to represent a
volume),具有三维纹理坐标。矩形纹理是次维纹理的一个特例,它们当经着色器读取数据的法跟支持之参数方面发出细小的差别。由于并非有的硬件都支持尺寸未呢2的整数浅幂的纹理,矩形纹理便叫引入。现代底硬件通常还支持尺寸未呢2的平头潮幂的纹路,因此矩形纹理可以为作是2维纹理的一个子集,通常不会见采取。

GL_TEXTURE_1D_ARRAYGL_TEXTURE_2D_ARRAY表示结合于么对象被的同等组纹理图像。在本章后面会详细讨论。同样的,立方体纹理表示了六张方形图片集合,它们做成一个立方,该立方体通常可以给用来模拟光照条件。正而GL_TEXTURE_1D_ARRAYGL_TEXTURE _2D_ARRAYGL_TEXTURE_CUBE_MAP_ARRAY
表示了立方体纹理的一个数组。

GL_TEXTURE_BUFFER代表的纹路是看似于1D纹理的一个非正规类型,不同之处在于其的积存实际上在缓存中。除此之外,该项目纹理的容量比较1D纹理大得多。OpenGL中不过小之渴求凡65536纹初次(The
minimum requirement from the OpenGL specification is 65536
texels),但是事实上大部分落实允许创建更特别的缓存—通常只是达成几百百万字节。缓存纹理同样缺乏某些1D纹理支持的特性,如过滤(filtering)和mipmaps。

最后,GL_TEXTURE_2D_MULTISAMPLEGL_TEXTURE_2D_MULTISAMPLE_ARRAY用以多再采样抗锯齿(multi-sample
antialiasing),该计数用于加强图形质量,特别是对此线条与绝大部分形的边缘。

在此之后的亚片段,也就算是储存的轩然大波,听上应该占据多字节,但是由限了轩然大波数量最为多不能够超越18独,同时事件名称最为丰富也4字节,所以事件部分也仅仅占好少之长空。由于C3D主要是为了记录运动的多寡,可能以其间有诸多于主要的地方,事件就是用来标记出这些地方的。一个波包括三独内容,分别是无限丰富四字节的轩然大波名称、一字节的事件是否应该显示的状态及一个四字节底但精度浮点数表示事件出现的辰。

2.3 在正在色器中由纹理中读取数据(Reading from Textures in Shaders)

创造纹理对象并拿数据传其中后,可以当在色器中读取数据,例如用于为有着色。在方色器中,纹理被声称也采样变量(sampler
variables),它们经sampler类型的统一变量和表面关系。GLSL中生出差不多个采样类型变量关键词用于声明不同品类的纹路对象。在GLSL中得使内置函数texelFetch及坐标值获取纹理中对承诺坐标的颜色值。其所以法如下。

#version 410 core 
uniform sampler2D s; 
out vec4 color;

void main(void) {
  color = texelFetch(s, ivec2(gl_FragCoord.xy), 0);
}

上述代码中gl_FragCoord为OpenGL的置变量,表示的凡正值给拍卖的局部在窗口坐标系中之坐标,坐标的单位吗浮点型数据。然而函数texelFetch的参数必须是自(0,0)到(width,
height)范围外之整数型数据。第三个参数是纹理的mipmap等级。因为此处纹理并未启用mipmap功能,因此使用0。

字节 类型 说明
12AH-12BH Int16 事件名是否支持4字节(支持为0x3039,不支持为0)
12CH-12DH Int16 事件数量(最大为18)
130H-176H Single[] 按事件顺序存储的每个事件发生的时间(第1个帧为0.0s)
178H-188H Byte[] 按事件顺序存储的每个事件是否应该显示(1为显示,0为不显示)
18CH-1D2H Char[] 按事件顺序存储的每个事件的名称(每个事件占4字节)
2.3.1 采样器类型(Sampler Types)

纹理类型和纹理声明关键字的对应如下。(GL_TEXTURE_1D,sampler1D)(GL_TEXTURE_2D,sampler2D)(GL_TEXTURE_3D,sampler3D)(GL_TEXTURE_RECTANGLE,sampler2DRect)(GL _TEXTURE_1D_ARRAY,sampler1DArray)(GL_TEXTURE_2D_ARRAY,sampler2DArray)(GL _TEXTURE _CUBE_MAP,samplerCube)(GL_TEXTURE_CUBE_MAP_ARRAY,samplerCubeArray)(GL _TEXTURE_BUFFER,samplerBuffer)(GL_TEXTURE_2D_MULTISAMPLE,sampler2DMS)(GL_ TEXTURE_2D_MULTISAMPLE_ARRAY,sampler2DMSArray)

GLSL中之相继sanpler类型纹理数据表示的莫浮点型数据,它们啊能于纹理中贮存有标志和无符号的多寡,并以方色器中读取这些数据。为了表示包含有记号整形数据的纹理数据变量,只需要以针对承诺重点词前面加前缀i,同样的,为了表示包含无符号整形数据的纹理数据变量,只需要在针对诺重点词之前加前缀u。例如isampler2Dusampler2D

从今纹理中读取数据的函数有多单变形。他们之率先只参数为纹理数据,第二参数为采样作标,第三个参数为纹理mipmap级别。函数如下。函数的返回值一定是4维向量,如果纹理中之颜料通道小于4,那么短的坦途将赶回回0。如果回去值备受的某某成员永远不会见于运,那么在色器编译器将会优化掉冗余代码。

vec4 texelFetch(sampler1D s, int P, int lod); 
vec4 texelFetch(sampler2D s, ivec2 P, int lod); 
ivec4 texelFetch(isampler2D s, ivec2 P, int lod); 
uvec4 texelFetch(usampler3D s, ivec3 P, int lod);

 

2.4 从文本被读博纹理(Loading Textures from Files)

储存图片的格式很多,但是那个少的格式会生好之仓储OpenGL支持之具有属性,或者能够描述一下如mipmaps,cubemaps等高级特性。一个满足上述原则的纹路格式为.KTX或者Khronos
TeXture
format
,它专用于OpenGL中纹理的囤,它看成容器能储存压缩后底纹理,也能积存此处使用的莫减纹理。实际上,.ktx文件格式中连了绝大多数需传递及纹理函数中的参数,这些函数能一直由文本中加载纹理,如glTexStorage2D()glTexSubImage2D().KTX文件之腔结构如下。

struct header {
  unsigned char      identifier[12];    用于验证是否为合法.ktx文件
  unsigned int       endianness;        表示文件中数据是以大端模式还是小端模式存储
  unsigned int       gltype;            GLenum类型数据
  unsigned int       gltypesize;        以gltype为单位的单个数据字节大小,当数据的大小端类型
                                        和系统环境不匹配时,在加载数据时需要转换
  unsigned int       glformat;          GLenum类型数据
  unsigned int       glinternalformat;        GLenum类型数据
  unsigned int       glbaseinternalformat;    GLenum类型数据
  unsigned int       pixelwidth;
  unsigned int       pixelheight;
  unsigned int       pixeldepth;
  unsigned int       arrayelements;
  unsigned int       faces;
  unsigned int       miplevels;
  unsigned int       keypairbytes;      在数据头末尾,纹理数据之前存储额外信息
};

至上圣经中提供了一个C++loader类用于加载纹理中之数码,但是遗憾之凡那里面使用的凡OpenGL4.3的接口,因此当mac上无法正常使用,因此无具体研究,需要了解得查阅官方源代码。这里仅需要指定其加载原来还是经过c语言文件操作读取二迈入制流,根据KTX文件官方的格式规范分析其中的像素数量,随后通过函数glTexStorage2D报名纹理内存,通过函数glTexSubImage2D同像素数量载入。

【三、C3D文件参数集合的结构】 

2.4.1 纹理坐标(Texture Coordinates)

当前方的以身作则中,片段着色器中一直行使时之标准配备坐标作为纹理坐标读取数据,另外,OpenGL也同意以从定义的纹路坐标。通常对当有些着色器中的几近重复纹理而言,推荐下以及被之纹理坐标。对应的顶点着色器代码如下。

#version 410 core 
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (location = 0) in vec4 position;
layout (location = 4) in vec2 tc; 
out VS_OUT {
  vec2 tc;
} vs_out;

void main(void) {
  //Calculate the position of each vertex
  vec4 pos_vs = mv_matrix * position;
  //Pass the texture coordinate through unmodified
  vs out.tc = tc;
  gl_Position = proj_matrix * pos_vs;
}

有的着色器代码如下。

#version 410 core
layout (binding = 0) uniform sampler2D tex_object;
// Input from vertex shader
in VS_OUT {
  vec2 tc;
} fs_in;
// Output to framebuffer
out vec4 color;

void main(void) {
  // Simply read from the texture at the (scaled) coordinates, and assign the result to the shader’s output.
  color = texture(tex_object, fs_in.tc * vec2(3.0, 1.0));
}

透过也终极指定纹理坐标的方式,可以以纹理贴图布满整个模型,得到如下效果,源代码。纹理坐标可以是程序生成,也可以是艺术家使用模型编辑软件用其蕴含在模型文件被。

澳门网上娱乐 4

C3D文件存储了大气之参数,其下了看似目录的方式囤了参数,不过还吓就发生一级。即参数有只有参数组和参数,并且每个参数组里只能有参数不能够还包含参数组,每个参数必须于一个参数组内。参数集合起始于文件头中的首先个字节表示的Section
ID,通常为2,但是呢不必然,有的文件会于文书头晚留有空白,然后参数集合起始之Section
ID就滞缓了。所以判断是否为C3D文件千万不要同开始念上个Int16然后判断是不是0x5002,而肯定要一口咬定第二单字节是无是0x50,确定参数集合的职也势必要是基于文件的首先许节来。

2.4.2 纹理的行使

纹理的以含有初始化纹理对象,程序和着色器之间数据通信,着色器内部读博纹理数据三独关键等级。前面都讲到,OpenGL中时线程会有一个OpenGLContext,纹理对象只有绑定到上下文中才会叫在色器使用。一个着色器可以蕴涵多个纹理对象,它们得以经GL_TEXTURE0相当于枚举值关联。

默认情况下,调用函数glBindTexture(GL_TEXTURE_2D, textureID);会默认将当前纹理关联到GL_TEXTURE0,再次调用绑定函数会将最终一不行绑定的纹理和GL_TEXTURE0事关,之前绑定的纹理和GL_TEXTURE1/2…涉及。并且这正值色器内部的底有纹理变量都见面从GL_TEXTURE0波及的纹路对象中读取数据。

留神,通常用以渲染代码中将纹理数据输入到正色器的纹理变量中,但是有时并不需要手动指定,OpenGL会自动关联数据,如上文的演示。但是有时对复杂的逻辑必须手动关联这些数量。调用函数glUniform1i(_textureLoc, 0);,这里第二个参数的值和像GL_TEXTURE0等枚举变量的末梢一个数值一一对应。

对此急需启用多单纹理对象,完整的运用办法如下。

// 1. 在着色器中声明纹理变量
uniform sampler2D length_texture;
uniform sampler2D orientation_texture;
uniform sampler2D grasscolor_texture;
uniform sampler2D bend_texture;

// 2. 在调用函数glLinkProgram(program);后,获取纹理变量的绑定点,即位置
_colorTextureLoc = glGetUniformLocation(_program, "grasscolor_texture");
_bendTextureLoc = glGetUniformLocation(_program, "bend_texture");
_orientationTextureLoc = glGetUniformLocation(_program, "orientation_texture");
_lengthTextureLoc = glGetUniformLocation(_program, "length_texture");

// 3. 在初始化程序后,从文件或者内存中加载纹理数据
GLenum texturePoint[] = {GL_TEXTURE1, GL_TEXTURE2, GL_TEXTURE3, GL_TEXTURE4};
NSArray *textureFileNames = @[@"grass_length.ktx", @"grass_orientation.ktx", @"grass_color.ktx" ,@"grass_bend.ktx"];
GLuint textures[] = {_lengthTxtureID, _orientationTxtureID, _colorTxtureID, _bendTxtureID};
for (int i = 0; i < 4; i++) {
  glActiveTexture(texturePoint[i]);
  [[TextureManager shareManager] loadObjectWithFileName:textureFileNames[i] toTextureID:&textures[i]];
}

// 4. 在渲染代码内,将纹理对象和着色器中的纹理变量相关联
glUniform1i(_lengthTextureLoc, 1);
glUniform1i(_orientationTextureLoc, 2);
glUniform1i(_colorTextureLoc, 3);
glUniform1i(_bendTextureLoc, 4);

若于参数集合,开头的4字节概念如下:

2.5 控制纹理数据的读取方式(Controlling How Texture Data Is Read)

纹理坐标是标准坐标,其范围也0.0至1.0里面。OpenGL允许控制当坐标不在斯范围外不时对应之拍卖政策,称为采样器的包装模式(wrapping
mode)。同样,也得安装纹理数据的乘除办法,这给誉为采样器的过滤模式(filtering
mode)。控制其的参数为在采样器对象(sampler
object)中。创建采样器的代码如下。

void glGenSamplers (GLsizei count, GLuint *samplers);

设置采样器参数的代码如下。

void glSamplerParameteri (GLuint sampler, GLenum pname, GLint param);
void glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param);

当安了采样器参数后,需要以那个绑定至某纹理单元,其代码如下。

void glBindSampler(GLuint unit, GLuint sampler);

参数unit指要绑定至采样器的纹理单元索引。这样纹理对象和采样器对象都绑定至平纹理单元,此时,完整的因素数据和参数就能构建着色器所待的纹素数据。将纹理采样器逻辑与纹理数据分离有以下三单特点。

第一,它同意吗歧之纹理对象下同样的纹路参数,不用于每个纹理数据遭到都蕴含冗余数据。
第二,它同意以创新纹理对象时,不用再行创新采样器参数。
第三,它同意对同一个纹理对象下多套不同的采样器参数。

片次可能拿纹理采样器参数集成及纹理数据里面。为了改变这种类型的采样器参数,首先用用纹理对象绑定至纹路单元,然后通过纹理单元调用以下函数。

void glTexParameterf (GLenum target, GLenum pname, GLfloat param);
void glTexParameteri (GLenum target, GLenum pname, GLint param);
字节 类型 说明
00H Byte 第一个参数所在的Section在整个参数集合中的位置(通常为0x01,说明开头4字节之后就是第一个参数)
01H Byte 参数集合部分标识(固定为0x50)
02H Byte 参数集合所占Section数量
03H Byte 生成文件的CPU类型(0x54为Intel,0x55为DEC (VAX, PDP-11),0x56为MIPS (SGI/MIPS))
2.5.1 使用多还纹理

偶然,在单个着色器中,需要使用多单纹理。OpenGL直冲多重复纹理单元,此时先后中要创造多独采样器统一变量,它们引用了不同的纹路单元,同时还待被绑定至上下文中。获取最特别支持纹理单元数量代码如下。

GLint units;
glGetIntegerv(GL MAX COMBINED TEXTURE IMAGE UNITS, &units);

以纹理绑定至有特定的纹理单元之前,首先需要转移活跃的纹理单元。其函数如下。void glActiveTexture (GLenum texture);,其中参数texture为内部定义变量如GL_TEXTURE0形式。生成三个纹理单元的代码如下。

GLuint textures[3];
glGenTextures(3, &textures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glActiveTexture(GL_TEXTURE2); 
glBindTexture(GL_TEXTURE_2D, textures[2]);

当左右文中绑定多个纹理时,需要也着色器中的采样器统一变量指定到不同之纹理单元,此时产生星星点点种艺术可供应选择。第一,通过以先后中调用函数glGetUniformLocation()得到它们绑定的纹路单元。第二,可以一直在方色器声明变量时同时指定绑定的纹理单元。当指定了纹理单元后,在程序中调用函数glUniform1i()足直接拿纹理输入到在色器中。此处需要专注,采样器变量并无含一个于正色器中能为读取的整形变量,但是以设置纹理对应之纹理单元数据,他叫当做是一个整形的统一变量。在在色器中宣示绑定至纹路单元0、1与2之采样器统一变量代码如下。

layout (binding = 0) uniform sampler2D foo; 
layout (binding = 1) uniform sampler2D bar; 
layout (binding = 2) uniform sampler2D baz;

内前面2个字节官方说一直忽略就实行,但是为了配合于写入的时段要如写上的。第3许节其实我们以梯次读到头也不需要者数目。这间重点之凡CPU类型,由于不同CPU类型采用的配节序以及存储的浮点数字有所不同,所以我们还需要根据CPU类型进行对应的处理。

2.5.2 纹理过滤(Texture Filtering)

纹理中的纹素坐标和屏幕及之如从坐标几乎不容许全对应。因此,纹理作为几何图形标贴图的时光,它们总会让牵涉伸或者缩减。因为几哪图形具有方向性,一个规定的纹路在同一时间在范的不同表面上会见产生不同的抽表现。

于前文中,着色器中针对纹理采样使用的函数为texelFetch(),其参数必须也整数,这里可以清楚啊纹素坐标,即纹理中的例如从坐标。对于下专业纹理坐标时,纹理采样需要调用函数texture()。对承诺变形如下。该函数的参数0和1分头针对许纹理中之相应维度的最好小和最好可怜纹素,p的取值可以不再0到1范围外,此时OpenGL的拍卖政策将见面于末端介绍。

vec4 texture(sampler1D s, float P); 
vec4 texture(sampler2D s, vec2 P); 
ivec4 texture(isampler2D s, vec2 P); 
uvec4 texture(usampler3D s, vec3 P);

抽或拉伸纹理的照耀中,颜色的乘除过程叫名纹理过滤。在装采样器参数函数中,参数GL_TEXTURE_MAG_FILTERGL_TEXTURE_MIN_FILTER个别表示拉伸和收缩纹理时使用的水彩计算方式。两栽基本的计量策略GL_NEARESTGL_LINEAR可以为使用。确保对参数GL_TEXTURE_MIN_FILTER总得挑选了上述两个政策之一,因为默认的纹路过滤设置更没mipmap纹理(稍后介绍)时未见面收效。

新近过滤策略是极度简单易行也是不过抢的过滤方法。该策略下摘离开想要采样的纹素坐标最近的纹素,并拿该颜色信息返回作为有颜色。该方针的一定是,当纹理被顶放大后,图像中会油然而生大量请勿总是色块。设置采样器过滤策略也日前过滤代码如下。

glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

线性过滤的性质消耗又怪,但是对当代之图像硬件,这个影响可以忽略。线性过滤的策略是,对于需要采样的纹路坐标,取其周围纹素及协调的加权平均值作为有的颜色值返回。当采样坐标位于单个纹素中心时,会直接回该纹素的颜色值。线性过滤的特色是当纹理被顶拉伸时,图像模糊化。设置采样器过滤策略也线性过滤的代码如下。

glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

对此和一个纹理使用有限栽不同之过滤方法相比如下。

澳门网上娱乐 5

对于Intel和DEC生成的文档,都是动Little-Endian字节序存储的文档,所以自然要运用Little-Endian来读取Int16、Single等品类;而MIPS则使的Big-Endian字节序存储文档,所以当读取的时候肯定要是判断时电脑默认的配节序以及文档采用的字节序。

2.5.3 分级细化纹理(Mipmaps)

各自细化纹理可以增进渲染性能,同时提升气象视觉质量。它解决了运用正规纹理映射面临的一定量只问题。其一为闪烁(scintillation)(混叠效应(aliasing
artifacts)),它起于当用大尺寸纹理渲染小尺码模型时。在体育场景中,这种光景充分频繁。

第二只问题更多之凡和属性相关,但那因以及第一个问题类似。纹理占用了汪洋底内存,相邻片段访问了无联系的纹路,导致纹理中很老有几乎未被用。

独家细化纹理指的凡部分列的图像,即于加载纹理时,同时加载了自不过酷尺寸及无限小尺码的纹路。OpenGL提供了初的同组过滤模式来针对不同的几乎哪模型选取最可之纹理。在牺牲内存的前提下,可以祛除闪烁现象,同时解决以未相邻内存直接的寻址性能压力,同时可以需要的时提供高分辨率的纹路。

分级细化纹理由同样多元纹理组成,每个纹理在各轴上之长都是前面一个纹理的一半。分级细化纹理并无求得是正方形纹理,但是最后一摆放纹理尺寸像素一定也1*1。当内1个维度到1后,只需要缩小另外一个维度即可。对于2D纹理,使用各自细化纹理将格外增加1/3的内存开销。

这调用函数glTexImage2D加载分级细化纹理时,参数level传分级索引,0意味着未经缩小的纹路。使用函数glTexStorage2D()分配内存时得以指定在参数levels中指定分级的索引数,另外,可以安装渲染时行使的尽小最老纹理索引值。其代码如下。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);

若是对于Intel和MIPS生成的文档,对于浮点数字之贮存都是采取标准的IEEE754浮点数字,对于.NET而言不待展开任何处理;而DEC生成的文档则使特有浮点数,需要用4只字节全部读取以后再展开特殊的变换,转换方法见我之前的文章:http://www.cnblogs.com/mayswind/p/3365594.html。

2.5.4 分级细化纹理过滤(Mipmap Filtering)

分级细化纹理过滤方式于受一般纹理,其发出4单附加的过滤方式。GL_NEAREST_MIPMA
P_NEAREST:
慎选近年来之纹路贴图,选择近年来底纹素。GL_LINEAR_MIPMAP_LINEAR
在分别纹理直接实施线性插值确定最终之纹理图,然后以履行纹素之间的加权平均线性过滤操作。GL_NEAREST_MIPMAP_LINEARGL_LINEAR_MIPMAP_NEAREST。前一个参数表示纹素的过滤方式,后一个参数表示分级纹理的选择方式。

假定纹理的过滤模式于安装也GL_LINEAR或者GL_NEAREST,那么纹理分级不会见为启用。必须利用上述4单分别细化纹理过滤方式面临之一个。

纹理的过滤方式亟待根据实际求来挑选,例如,GL_NEAREST_MIPMAP_NEAREST供十分好之性质和低混染(闪烁)效果,但是近年来过滤法总会造成视觉上的来得问题。GL_LINEAR_MIPMAP_NEAREST一般说来用于加速游戏,因为以了重复胜似质量的线性过滤,同时多年来甄选各自纹理策略也会迅速形成。需要小心的是,设置分级纹理过滤方式只能用于参数GL_TEXTURE_MIN_FILTERGL_TEXTURE_MAG_FILTER唯其如此以简单只为主过滤法则。

使用以来挑选各自纹理策略有甚好的视觉体验。从模型侧面看,在不同之外表上能够看见不同分级索引纹理之间的过火,从一个高分辨率表面转换到另外一个表面或者会见映入眼帘扭曲线或者坏盛的过分。GL_LINEAR_MIPMAP_LINEARGL_NEAREST_MIPMAP_
LINEAR
以挑个别纹理时实行了额外的插值来排除这种强烈的忒区域,但是会招致额外的性开销。GL_LINEAR_MIPMAP_LINEAR平凡为叫做3次线性纹理分级细化(trilinear
mipmapping),另外还有复上进的图像过滤技术,它们可以有十分好的结果。

每当是之下就囤在有的参数了,参数分为两近似,分别是参数组和参数。

2.5.5 生成分级细化纹理等级(Generating Mip Levels)

前文已经讲到,在加载纹理时加载所有级别的独家纹理会浪费额外的内存,并且其中一部分纹理无论是程序员还是用户几乎都非会见以,因此在程序中通过相关API生成分级纹理是一个再次高效又常用的法。该功能对许函数如下,它会转于同组完整的个别纹理。

void glGenerateMipmap(GLenum target);

纹理目标参数和前边文生成纹理可选参数相同,此时急需专注,生成纹理的速度并无会见比较加载纹理的速又快。对于性要求高,以及视觉特效要求大之顺序,仍然推荐加载预生成纹理。

对参数组,要存储以下6独内容:

2.5.6 使用分别细化纹理(Mipmaps in Action)

应用各自纹理的实例如下,源代码。

澳门网上娱乐 6

字节 类型 说明
00H SByte 参数组名称长度(如果为负数则表示该参数组锁定请不要修改,而长度为绝对值)
01H SByte 参数组ID的负数
02H – … Char[] 参数组名称(仅包含大写字母、0-9以及下划线_)
… + 1 – … + 2 Int16 下一参数组/参数的偏移(包含本内容的2字节)
… + 3 Byte 参数组描述长度
… + 4 –  Char[] 参数组描述内容(ASCII码)
2.5.7 纹理包装(Texture Wrap)

便,纹理采样函数中的职务坐标范围是0交1里,如果过量这界定,OpenGL将见面依据采样器的包模式处理多少。通过调用函数glSamplerParameteri好指定包装模式,其中参数GL_TEXTURE_WRAP_S(T/R)分级针对许坐标的老三单重,其值可以装的档次也GL_REPEATGL_MIRRORED_REPEATGL_CLAMP_TO_EDGEGL_CLAMP_TO_BORDER。其中repeat模式可以了解呢整数值取1,小数值仅获得小数部分,用于将小尺寸贴图贴于大尺寸的几何表面。MIRRORED_REPEAT表示镜像重复。

当以线性过滤时,纹理边缘之纹素需要取该周围纹素值计算,此时,如包装模式为GL_REPEAT,那么OpenGL将见面获纹理另一侧的首先排列或者第一执。这种模式在纹理将会卷入模型,并且每单跟指向边拼接在共同时非常常用(如球体中)。

混有纹理包装模式还要分开为片种植。第一种to_border的水彩由事先通过函数glSamplerParameterfv和参数GL_TEXTURE_BORDER_COLOR设置而得。第二种to_edge强制令大于1的值等于1,小于0的值等于0。四种不同的纹路包装模式如下,从达成到下,从错误到右,分别吗TO_BORDERMIRRORED_REPEATTO_EDGEREPEAT。不同门类包装模式如下图所示,源代码。

澳门网上娱乐 7

C3D文件没有规定一个参数组后边与任何一个参数组还是和该参数组里的有着参数,所以读取的时刻如果专注下。而参数的始末则跟参数组基本相同,只是在生同样参数组/参数的晃动与参数组描述长度之间存放着该参数的实际上数目罢了,由于位置描述起来最累了,这里虽非写了。

2.6 数组纹理(Array Textures)

上文中多只正色器中援引多独纹理都是透过声明多个采样器变量实现之,另外OpenGL还提供了采样器数组变量来加载数组纹理。其实以各自纹理中单个采样器同样引用了差不多个纹理,此外cube类型的纹路中每个面还是独自的一个纹理对象。需要小心的凡,OpenGL不支持创造3D底纹理数组。数组纹理的成员为能够是个别纹理。为了区别单个纹理和纹理数组,通常数组元素被称为层(layers)。

2D纹理数组可以为看是一个特殊之3D纹理(同样的1D纹理数组能于作是2D纹理),它们中间的基本点区别是几度组纹理的各层之间不见面时有发生过滤用,另外纹理数组能支撑之分子大小或者较3D纹理尺寸还怪。

字节

2.6.1 加载2D纹理数组(Loading a 2D Array Texture)

开创2D纹理数组的步子为,创建纹理对象,绑定至GL_TEXTURE_2D_ARRAY目标,分配内存,填充数据。这里以3D纹理模式分配内存和填充数据,第3维被了解为数组元素,或者层。另外.KTX格式文件支持数组纹理,可以由文本被直接读博纹理数组。读博纹理代码如下。

GLuint tex;
glGenTextures(1,_&tex); 
glBindTexture(GL TEXTURE 2D ARRAY, tex);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 8, GL_RGBA8, 256, 256, 100);
for (int i = 0; i < 100; i++) {
  glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, 256, 256, 1, GL_RGBA, GL_UNSIGNED_BYTE, image_data[i]);
}

这边提供64个外星人头像纹,在屏幕被绘制264单头像,将每个头像的转角度与偏离值传入顶点着色器,并以中计算模型出现的肆意位置、片段的纹路坐标和纹理索引。顶点着色器代码如下。

#version 410 core
layout (location = 0) in int alien_index;
out VS_OUT {
  flat int alien;
  vec2 tc; 
} vs_out;
struct droplet_t {
  loat x_offset; 
  float y_offset; 
  float orientation; 
  float unused;
};
layout (std140) uniform droplets {
  droplet_t droplet[256];
};

void main(void) {
  const vec2[4] position = vec2[4](vec2(-0.5, -0.5), vec2(0.5, -0.5), vec2(-0.5, 0.5), vec2(0.5, 0.5));
  vs_out.tc = position[gl VertexID].xy + vec2(0.5); 
  vs_out.alien = alien_index % 64;
  float co = cos(droplet[alien_index].orientation); 
  float so = sin(droplet[alien_index].orientation); 
  mat2 rot = mat2(vec2(co, so), vec2(-so, co)); 
  vec2 pos = 0.25 * rot * position[gl VertexID];
  gl_Position = vec4(pos.x + droplet[alien_index].x_offset, pos.y + droplet[alien_index].y_offset,0.5, 1.0);
}

以部分着色器中,使用自极限着色器中拿走的多寡及从程序中得到的纹理数据直接着色。代码如下。其中采样函数中之老三只参数为用纹理的层索引,即现实行使谁外星头像。

#version 410 core
layout (location = 0) out vec4 color;
in VS_OUT {
  flat int alien;
  vec2 tc; 
} fs_in;
layout (binding = 0) uniform sampler2DArray tex_aliens; 

void main(void) { 
  color = texture(tex_aliens, vec3(fs_in.tc, float(fs_in.alien)));
 }

渲染模型有代码如下。

void render(double currentTime) {
  static const GLfloat black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; 
  float t = (float)currentTime;
  glViewport(0, 0, info.windowWidth, info.windowHeight);     
  glClearBufferfv(GL_COLOR, 0, black);
  glUseProgram(render_prog);
  glBindBufferBase(GL_UNIFORM_BUFFER, 0, rain_buffer); 
  //GL_MAP_INVALIDATE_BUFFER_BIT 表示对映射的内存除缓存以外区域不会更新其值
  vmath::vec4 * droplet = (vmath::vec4 *)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 256 * sizeof(vmath::vec4), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
  // droplet_x_offset等数组值已经提前预设
  for (int i = 0; i < 256; i++) {
    droplet[i][0] = droplet_x_offset[i]; 
    droplet[i][1] = 2.0f - fmodf((t + float(i)) * droplet_fall_speed[i], 4.31f);
    droplet[i][2] = t * droplet_rot_speed[i];
    droplet[i][3] = 0.0f; 
  }
  glUnmapBuffer(GL_UNIFORM_BUFFER);
  int alien_index;
  for (alien_index = 0; alien_index < 256; alien_index++) {
    glVertexAttribI1i(0, alien_index);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  }
}

最终绘制结果如下,圆源码。

澳门网上娱乐 8

类型

2.7 在方色器中为纹理中形容副数据(Writing to Textures in Shaders)

需要注意的是,下文内容以OpenGL4.2与以上版本才会用,在4.2事先只能通过离屏渲染的技艺将通图像渲染到整纹理中(该技术延续文章提到)。OpenGL不仅能当应用被读博纹理数据到纹理对象吃,还同意以正色器中直接读取和描写副纹理数据。正使采取采样器变量可以表示一个纹理对象,使用”image”变量可以象征纹理内的相同摆图纸。和sampler变量一样,image变量有image1D等众变形,最常用的凡image2D。着色器中纹理的声明方式吗uniform image2D my_image;

在色器中读博纹理数据与描绘副纹理数据的函数如下。注意,对于不同之纹理类型,该函数有各种变形。这里要留意,坐标参数p为整形值,其代表纹素坐标,此处过滤模式尚未另外意义。

vec4 imageLoad(readonly image2D image, ivec2 P); 
void imageStore(image2D image, ivec2 P, vec4 data);

另外,图像变量也能积存整形数据,其针对性许函数如下。

ivec4 imageLoad(readonly iimage2D image, ivec2 P); 
void imageStore(iimage2D image, ivec2 P, ivec4 data); 
uvec4 imageLoad(readonly uimage2D image, ivec2 P); 
void imageStore(uimage2D image, ivec2 P, uvec4 data);

跟纹理绑定需要激活当前纹理不同,使用函数glBindImageTexture()好直接拿图像绑定至图像单元。其参数unit为从0增长的绑定点;参数level表示分级数量之目;在行使单个纹理的时参数layered设置为GL_FALSE,此时参数layer被忽视,当以纹理数组时该参数设置为GL_TRUE,此时参数layer为对应索引;参数可选GL_READ_ONLY、GL_WRITE_ONLY或者GL_READ_WRITE。

参数format指图片中数据,必须与分配内存时一样,可选GL_RGBA32F等(占用内存大小一致即可,例如GL_RGBA32F和GL_RGBA32I以及GL_RGBA32UI内可自由匹配)。另外,在正在色器中描写副数据时系统活动处理,读取数据时必须采用相应项目的宣示标识符号(如rgba32f)。需要指出的凡格式GL_R11F_G11F_B10F只和友好配合,而GL_RGB10_A2UI和GL_RGB10_A2不过互相配合。

采用加载与储存图片数的着色器示例代码如下。

#version 410 core
// Uniform image variables:
// Input image - note use of format qualifier because of loads 
layout (binding = 0, rgba32ui) readonly uniform uimage2D image_in; 
// Output image
layout (binding = 1) uniform writeonly uimage2D image_out;
void main(void) {
  // Use fragment coordinate as image coordinate
  ivec2 P = ivec2(gl_FragCoord.xy); 
  // Read from input image 
  uvec4 data = imageLoad(image_in, P);
  // Write inverted data to output image
  imageStore(image_out, P, ~data);
}

尽管达文代码很复杂,但马上使得有些着色器更加强劲。这表示部分着色器不再是不得不往定点位置写副数据,它会向一个图纸的人身自由位置写副数据,同时通过多只图像变量还能往多独图像遭到写副数据。同时上面的技艺驱动任意阶段的着色器都能够通往图片中描绘副数据。但是要小心的凡,如果多个正色器都指向同一个内存位置的图像更改,必须下原子操作。(GPU高并发特性导致同时刻多独一样等级着色器函数同时运行)。

说明

2.7.1 图像中之原子操作(Atomic Operations on Images)

碰巧使正在色器储存闭包统一变量中的原子操作一样,图像变量中呢提供了相应的原子操作。OpenGL中提供的有关内置函数如下。除了imageAtomicCompSwap,各个函数参数都出于图形变量,修改点坐标,数据做。

imageAtomicAdd:读-加-存,返回原始值。
imageAtomicAnd:读-逻辑与-存,返回原始值。
imageAtomicOr:读-逻辑或-存,返回原始值。
imageAtomicXor:读-逻辑异或-存,返回原始值。
imageAtomicMin:读-取小-存,返回原始值。
imageAtomicMax:读-取大-存,返回原始值。
imageAtomicExchange:读-存,返回原始值。
imageAtomicCompSwap:读-和comp比较-如果相等存,返回原始值。

上述顺序函数都留存以下几个重载函数,其代码如下。

uint imageAtomicAdd(uimage1D image, int P, uint data); 
uint imageAtomicAdd(uimage2D image, ivec2 P, uint data); 
uint imageAtomicCompSwap(uimage3D image, ivec3 P, uint comp, uint data);

采取原子计算变量,image变量,着色器储存闭包变量可以呢每个像素的拥有有建立一个链表。其中原子变量用于表示各个部分在数码数组中的目,着色器存储闭包用于表示数据数组,image变量用于存储每个像素点的链表头索引(这里用注意OepnGL在光栅化过程被,通常每个像素包含多只有)。一个示范代码如下。

#version 430 core
// Atomic counter for filled size
layout (binding = 0, offset = 0) uniform atomic_uint fill_counter; 
// 2D image to store head pointers
layout (binding = 0) uniform uimage2D head_pointer;
// Shader storage buffer containing appended fragments
struct list_item {
  vec4 color; 
  float depth; 
  int facing; 
  uint next;
};
layout (binding = 0, std430) buffer list_item_block {
  list_item   item[];
};
// Input from vertex shader
in VS_OUT {
  vec4 in; 
} fs_in;
void main(void) {
  ivec2 P = ivec2(gl_FragCoord.xy);
  uint index = atomicCounterIncrement(fill_counter);
  uint old_head = imageAtomicExchange(head_pointer, P, index);
  item[index].color = fs_in.color;
  item[index].depth = gl_FragCoord.z;
  // gl_FrontFacing 为back-face culling stage阶段生成的变量,无论精选是否被禁用,该变量都会生成。
  item[index].facing = gl_FrontFacing ? 1 : 0;
  // 需要注意的是在OpenGL的光栅化过程中,每个像素会含多个片段,
  // 而此处内置变量gl_FragCoord的x和y取值为0到当前在屏幕中渲染视图的宽高
  item[index].next = old_head;
}

每当另外一个有的着色器中,通过追溯链表的计拿每个像素的保有片段的吃水值叠加在一起,并以其用作出口颜色用于渲染图形。其代码如下。注:这里修被例子分了三只program来处理图像,第一独program用于先行处理数据,其中调用函数imageStore(head_ pointer, P, uvec4(0xFFFFFFFF));将image变量中享有变量赋值为极深整数,用于标识链表末尾。而这边上下两单部分着色器分别吗第二同老三只级次遭遇之有的着色器代码。

#version 430 core
// 2D image to store head pointers,关键字coherent表示内存连续
layout (binding = 0, r32ui) coherent uniform uimage2D head_pointer;
// Shader storage buffer containing appended fragments
struct list_item {
  vec4 color; 
  float depth; 
  int facing; 
  uint next;
};
layout (binding = 0, std430) buffer list_item_block {
  list_item  item[];
};
layout (location = 0) out vec4 color; 
const uint max_fragments = 10;
void main(void) {
  uint frag_count = 0;
  float depth_accum = 0.0;
  ivec2 P = ivec2(gl_FragCoord.xy);
  uint index = imageLoad(head_pointer, P).x;
  while (index != 0xFFFFFFFF && frag_count < max_fragments) {
    list_item this_item = item[index];
    if (this_item.facing != 0) {
      depth_accum -= this_item.depth;
    } else { 
      depth_accum += this_item.depth;
    }
    index = this_item.next;
    frag_count++;
  }
  depth_accum *= 3000.0;
  color = vec4(depth_accum, depth_accum, depth_accum, 1.0); 
}

事先的始末

2.8 合伙看图片(Synchronizing Access to Images)

刚好而前文说明在色器存储闭包统一变量时同步操作一样,对于图片数据的写照副乎时有发生内存屏障来实现同步看。其函数为glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BIT);。即当某些着色器必须运用前一个着色器写副的颜料变量时,需要以点滴只操作间插入内存屏障以担保第一个正在色器中之图像写入操作让完整执行后,后续使用及拖欠数额的代码才见面实行。同样的,该函数也产生照应之着色器语法版本,为memoryBarrierImage()。该函数包了还某个函数中图纸操作完执行后套数才见面吃执行回来操作。

此地原著中有一个演示程序,使用了前文的简单单部分着色器,但是该有的逻辑必须采用OpenGL4.2以上特性,mac只能支持及4.1。示例程序运行结果如下。

澳门网上娱乐 9

 

2.9 纹理压缩(Texture Compression)

渲染图形时以纹理所有数据全载入GPU对于大质量的图像渲染十分重点,对于生容量的纹理数据一般采用纹理压缩的措施确保GPU处理纹理的短平快。纹理的压缩并无像类似于JPEG这种图像压缩有坏高之压缩率,但是以能节省大量的空间。另外是因为GPU在处理压缩纹理时所欲的数据再次少,因此处理时占用的内存带富(memory
bandwidth)也再度小。OpengGL中支持的压缩格式如下。其中各个门类大概相同关键字GL_COMPRESSED_

此处小勿涉嫌通用为PC端(由Nvidia和Intel提供的GPU芯片)的DXT(.dds)格式,通用为iOS设备的PVRTC纹理格式(A8计算机后,支持ASTC格式,其缩减比又胜,苹果设备的GPU为PowerVR),以及高通GPU支持之ATC格式。其中ETC2吗持有支持OpenGL
ES3.0的GPU通用纹理压缩格式。

Generic类型
RED、RG、RGB、RGBA、SRGB、DRGB_ALPHA、
RGTC类型
RED_RGTC1、SIGNED_RED_RGTC1、RG_RGTC2、SIGNED_RG_RGTC2
BPTC类型
RGBA_BPTC_UNORM、SRGB_ALPHA_BPTC_UNORM、RGB_BPTC_SIGNED_FLOAT、RGB_BPTC_UNSIGNED_FLOAT
ETC2类型
RGB8_ETC2、SRGB8_ETC2、RGB8_PUNCHTHROUGH_ALPHA1_ETC2、SRGB8_PUNCHTHROUGH_ALPHA1_ETC2、RGBA8_ETC2_EAC、SRGB8_ALPHA8_ETC2_EAC
EAC类型
R11_EAC、SIGNED_R11_EAC、RG11_EAC、SIGNED_RG11_EAC

Generic类型的纹路压缩格式允许OpenGL自行以极妙办法决定压缩编制。

RGTC类型压缩格式将纹理分解为4就4纹素的丘,各个块内部开展削减。该格式就针对动单或者双通道的发出号子和无符号数据格式的纹路生效。该格式压缩率大约为50%。

BPTC类型压缩格式同样用纹理分解为4乘4纹素的块,每个片的高等学校啊16字节。每个片内部使用了还复杂的抽方法,它对同组端点和他们中连线的岗位描述进行削减。这样即使能够通过端点来转每个像素的颜料信息。该格式用于单个通道为1字节之不标准化数据以及单个通道也4字节底浮点型数据格式的纹路。该格式对于RGBA浮点型格式的纹路压缩率为25%,对于RGB未标准化格式纹理压缩率为33%。

ETC2(爱立信纹理压缩)格式和EAC(Ericsson Alpha
Compression)格式都能够为OpenGL
ES3.0上述版本支持。它用来单个像素内存占用最好小的应用程序,这些应用程序位于移动装备中,他们之内存带富和计算机受到CPU的带动富有不行充分之别。

处理上述提到的格式,还有类似于S3TC格式(DXT的最初版本)和ETC1格式,在动用他们事先还待检讨时GPU是否支持该格式的纹理。最好的计是反省是否支持有关的扩张,例如当检查是不是支持S3TC格式时,使用字符串GL_EXT_texture_compression_
s3tc

Int16

2.9.1 使用压缩纹理(Using Compression)

减纹理可以经简单种植艺术,推荐以第一种先将纹理压缩后存储在文件被,OpenGL支持读取压缩纹理。另外OpenGL也支持于次中回落纹理,通过点名某个internalformat为有压缩格式,可以在加载纹理的还要针对纹理进行削减。

当使用压缩纹理和莫减纹理时连不曾任何区别。在采样函数内部OpenGL会自动进行换。KTX格式文件可以一直存储压缩纹理。检查纹理是否为裁减可以以函数glGetTex LevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params);。可以透过参数GL_TEXTURE_INTERNAL_FORMAT检查纹理格式是否也削减纹理。压缩的纹路格式可以指定为得以经函数glGetInternalFormativ()与参数GL_TEX
TURE_COMPRES SED获得。另外可以一直通过参数GL_TEXTURE_
COMPRESSED直接检查纹理是否让抽。

当加载了压缩纹理后,可以调用函数glGetCompressedTexImage()直白沾压缩的纹路数据。其代码如下。

 Glint imageSize = 0;
glGetTexParameteriv(GL_TEXTURE_2D,
                    GL_TEXTURE_COMPRESSED_IMAGE_SIZE,
                    &imageSize); 
void *data = malloc(imageSize);
glGetCompressedTexImage(GL_TEXTURE_2D, 0, data);

加载压缩纹理可以调用函数glCompressedTexImage1D()齐与她的附和更新纹理函数glCompressedTexSubImage3D。在以上述函数时需要注意x和y轴上的偏移量,此外大多数压缩纹理格式都是经过压缩4*4的纹素块来实现纹理压缩。(在原著示例代码loder类中,并未呈现减少纹理的特有处理,但开被涉嫌可以下其loader类可以一直加载压缩纹理,可能是运普通纹理加载函数仍能加载压缩纹理,此处需连续研究)。

产一致参数组/参数的撼动(包含本内容的2字节)

2.9.2 共享指数(Shared Exponents)

尽管以真情景下,共享指数并无是一个真的滑坡纹理格式,但是它们仍能在节约存储空间的情景下同意用浮点型纹理数据。该格式下将每个通道的小数部分以及她们合伙的指数部分因为平头术囤(The
fractional and exponential parts of each value are stored as
integers),在采样时算出颜色值。例如格式GL_RGB9_E5即是9bits用于存储每个通道的小数部分,5bit用于存储他们的一起指数部分,这样于RGB格式可以直达67%底压缩率。

 

2.10 纹理视图(Texture Views)

前文中存有案例被,程序中加载的纹理类型和着色器中使用的品种是同等之。但是有时会碰到加载的纹路类型以及着色器中得之纹理类型不配合的景象。此时足采取纹理视图(Texture
Views)在新的纹路对象被收录原纹理对象的数目。该技术的使用方法根本发生以下简单种,当然她得以而且采用。

一:纹理视图可以将某种类型纹理包装为一个不一的花色,例如,可以通过纹理视图将一个2D纹理作为一个单层2D往往组纹理使用。

二:纹理视图能够用纹理中的多寡包装成该真实性数据类型以外的数据。例如,加载一个里边格式为GL_RGBA32F(即4独32bit的float类型数据)纹理,创建一个GL_RGBA32UI底纹路视图。(so
that you can get at the individual bits of the texels)

Byte

2.10.1 纹理视图(Texture Views)

多数纹理类型且能够创造至少一个之上之纹理视图,但是缓存纹理(buffer
textures)不可知,因为它们已是缓存对象的视图,对于此类型纹理,只能用同一个缓存对象绑定至另外一个缓存纹理来使中的数据。

void glTextureView(GLuint texture, 
                   GLenum target,
                   GLuint origtexture,
                   GLenum internalformat,
                   GLuint minlevel,
                   GLuint numlevels,
                   GLuint minlayer,
                   GLuint numlayers);

系函数如达到所示,参数texture为视图内部纹理的标识名,target为新创建纹理类型,origtexture表示原本纹理标识名,target必须同origtexture兼容。internalformat为新纹理的数据类型,它必须跟旧纹理的数据类型兼容。

纹理类型兼容表如下。

Original Texture               New Texture
1D                             1D or 1D_ARRAY
2D                             2D or 2D_ARRAY
3D                             3D
CUBE_MAP                       CUBE_MAP, 2D, 2D_ARRAY, or CUBE_MAP_ARRAY
RECTANGLE                      RECTANGLE
BUFFER                         none
1D_ARRAY                       1D or 1D_ARRAY
2D_ARRAY                       2D or 2D_ARRAY
CUBE_MAP_ARRAY                 CUBE_MAP, 2D, 2D_ARRAY, or CUBE_MAP_ARRAY
2D_MULTISAMPLE                 2D_MULTISAMPLE or 2D_MULTISAMPLE_ARRAY
2D_MULTISAMPLE_ARRAY           2D_MULTISAMPLE or 2D_MULTISAMPLE_ARRAY

相当的格式必须在同样类格式中,格式分类如下。

Format Class           Members of the Class
128-bit                GL_RGBA32F, GL_RGBA32UI, GL_RGBA32I
96-bit                 GL_RGB32F, GL_RGB32UI, GL_RGB32I
64-bit                 GL_RGBA16F, GL_RG32F, GL_RGBA16UI, GL_RG32UI, GL_RGBA16I, GL_RG32I, GL_RGBA16, GL_RGBA16_SNORM
48-bit                 GL_RGB16, GL_RGB16_SNORM, GL_RGB16F, GL_RGB16UI, GL_RGB16I
32-bit                 GL_RG16F, GL_R11F_G11F_B10F, GL_R32F, GL_RGB10_A2UI, GL_RGBA8UI, GL_RG16UI, GL_R32UI, GL_RGBA8I, GL_RG16I, GL_R32I, 
                       GL_RGB10_A2, GL_RGBA8, GL_RG16, GL_RGBA8_SNORM, GL_RG16_SNORM, GL_SRGB8_ALPHA8, GL_RGB9_E5
24-bit                 GL_RGB8, GL_RGB8_SNORM, GL_SRGB8, GL_RGB8UI, GL_RGB8I
16-bit                 GL_R16F, GL_RG8UI, GL_R16UI, GL_RG8I, GL_R16I, GL_RG8, GL_R16, GL_RG8_SNORM, GL_R16_SNORM
8-bit                  GL_R8UI, GL_R8I, GL_R8, GL_R8_SNORM
RGTC1_RED              GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_SIGNED_RED_RGTC1
RGTC2_RG               GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_SIGNED_RG_RGTC2
BPTC_UNORM             GL_COMPRESSED_RGBA_BPTC_UNORM, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM
BPTC_FLOAT             GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT

minlevel和numlevels分别表示初纹理中率先独跟分级纹理和分级数量,这点儿单参数允许打原的分别纹理中取部分叠,例如当只有开创旧的各自纹理第一级纹理时该组参数分别吗0同1。

一致的参数minlayer和numlayers用于取数组纹理类型受到的有些重合。例如当需要抽取一个20交汇旧纹理的中档4层是,该组参数可以分级安装为8与4。

以应用该方式生成新纹理后,新纹理中的数变动会潜移默化原有纹理中的数目。例如,当使用2D型纹理通过纹理视图引用2D屡次组纹理中的有一样重叠时,使用函数glTexSubImage2D更新新纹理中之数后,旧纹理中针对应层的数目也就更改。新的纹理在正在色器中利用的方以及纹理的为主用法平,上述新纹理在方色器中因故要字sampler2D表示。

参数存放内容的类(-1 Char,1 Byte,2
Int16,4 Single),绝对值即为长

2.11 OpenGL数据操作总结

该章主要介绍OpenGL中大量数据的传递方式。在管道的起点,通过缓存对象和极属性为终端着色器自动提供极相关数据。另外还得经常量为着色器赋值,如统一变量,统一变量的下好使通过缓存或者默认统一变量闭包的方法。此外在色器存储闭包可以用于在色器直接的多少交流。统一变量可以用于存储纹理、图像和缓存数据,在方色器中可一直指向纹理数据、图像数据和缓存进行读写操作。纹理数据足以抽取部分并拿其包装称为另外一栽不同格式和品种的纹路数据镜像使用。另外原子操作可以打包现代赛并发GPU安全访问数。

 

Byte

参数内容维数(0-3)

 

Byte[]

参数每一样维大小(如果维数为0,就无此部分)

 

Byte[] 

参数实际内容

 

Byte

参数组描述长度

然后的情节

此用证明的即是,由于参数可以存放数组,所以多了维数的标识,即当维数为0时,存放的始末也Char、Byte、Int16、Single等易出之字节数组;而当维数为1时不时,存放的也Char[]、Byte[]、Int16[]、Single[]抵易出的字节数组,以此类推。而对数组的积存,其实就是数组每个元素依次进行仓储,而对于多维数组,则是按行优先开展仓储的,比如三维数组,先囤Data[0,0,1]再存储Data[0,0,2],依次类推。

然而用说明的是,对于Char[]以及Char[,]立即半种,如果表示的讲话实际应该相应之是String以及String[]。

 

【四、C3D文件数量区域之布局】

C3D数据区域因帧为单位寄放的,其实一定给这区域便是一个帧的集纳。而C3D帧其实分为两栽,一种植是整数帧,而另一样栽是浮点帧。这两头的区别在,前者存储的保有情节都是Int16,而后人则也Single,除此之外,前者的3D坐标点(X、Y、Z)还得倍加比例因子才好,而后人存储的始末相当给已经就以了百分比因子了。

数码区域开始于参数集合中之”POINT”参数组吃的”DATA_START”参数,其代表数据区域开始的Section
ID,除此之外,在文件头中也有一致份副本。不过据官方的传道,如果文件头与参数集合中还有内容,优先读取参数集合中的多寡。

对每个帧,又带有两独组成部分,第一有为3D坐标点部分,第二片吗拟采样部分。

  • 对每帧的3D坐标点部分,存储在该帧所有3D坐标点的数,每个3D坐标点包括4独Int16或Single数据,分别是X坐标、Y坐标、Z坐标以及Residual和Camera
    Mask,其中Residual和Camera
    Mask共占用一个Int16。比较有趣的是,对于浮点帧,Residual和Camera
    Mask仍然为要一个Int16,只不过存储的时要用相应的数值转换为Single再拓展仓储。

    • 对于浮点帧,存储的X、Y、Z坐标就是其实的坐标;而对此整数帧,存储的X、Y、Z的坐标还欲倍加比例因子才堪,比例因子存储于参数集合中的”POINT”参数组吃的”SCALE”参数。
    • Residual和Camera
      Mask共占用一个Int16,将那个更换为字节数组后,高位字节(第1独字节)的危位代表Residual的记号,即意味着该坐标点是否可行,如果也0尽管意味着中,如果为1虽然意味无效,而剩余的7单字节则为Camera
      Mask,每一样各代表一个摄像机,从没有到高位分别表示7独摄像机是否采用(为1吧用,为0乎不用)。而Residual的真实数据则为字节数组的第0字节乘以比例因子(浮点帧则也比例因子的绝对值)。
  • 设仿照采样部分,则存储方该帧所有的模仿采样的数额,不过每个帧可能含多只拟采样,同时每个模仿采样可能而饱含多单channel,存储的数就为该channel下记录的数目。不过存储的数码以及事实上的数额还得基于下述公式进行折算,其中data
    value为存储的多寡,real world value为实际的多寡。

    • zero
      offset可以从”ANALOG”参数组被之”OFFSET”中赢得,该多少也Int16底屡屡组,第i员因的便是第i单channel的zero
      offset。
    • channel
      scale可以从”ANALOG”参数组被之”SCALE”中落,该数量也Single的勤组,第i个因的尽管是dii个channel的scale。
    • general
      scale是负有拟采样都亟需倍加的比例,该数额足以由”ANALOG”参数组中之”GEN_SCALE”中获取,为Single。

    real world value = (data value – zero offset) channel scale general scale

 

【五、使用C3D.NET读写文件示例】

前方说了如此多,其实要用C3D.NET来分析的讲话实际是非常简单的。大家可打https://c3d.codeplex.com/下载C3D.NET之二进制文件或者源码,引用后根本的好像都在C3D这个命名空间下。

对此遍历所有的3D坐标可以运用以下的法,首先得于文本或者从流中创建C3D文件,然后从文本头着读取存储的第1轴的序号,然后读取采样点的数就得了,当然为堪无打参数组中读取,直接采用file.AllFrames[i].Point3Ds.Length也可以:

 1 C3DFile file = C3DFile.LoadFromFile("文件路径");
 2 Int16 firstFrameIndex = file.Header.FirstFrameIndex;
 3 Int16 pointCount = file.Parameters["POINT:USED"].GetData<Int16>();
 4 
 5 for (Int16 i = 0; i < file.AllFrames.Count; i++)
 6 {
 7     for (Int16 j = 0; j < pointCount; j++)
 8     {
 9         Console.WriteLine("Frame {0} : X = {1}, Y = {2}, Z = {3}",
10             firstFrameIndex + i,
11             file.AllFrames[i].Point3Ds[j].X,
12             file.AllFrames[i].Point3Ds[j].Y ,
13             file.AllFrames[i].Point3Ds[j].Z);
14     }
15 }

要读取模拟采样的话,采用的法子呢近乎:

 1 Single frameRate = file.Parameters["POINT", "RATE"].GetData<Single>();
 2 Int16 analogChannelCount = file.Parameters["ANALOG", "USED"].GetData<Int16>();
 3 Int16 analogSamplesPerFrame = (Int16)(file.Parameters["ANALOG", "RATE"].GetData<Int16>() / frameRate);
 4 
 5 for (Int16 i = 0; i < file.AllFrames.Count; i++)
 6 {
 7     for (Int16 j = 0; j < analogChannelCount; j++)
 8     {
 9         for (Int16 k = 0; k < analogSamplesPerFrame; k++)
10         {
11             Console.WriteLine("Frame {0}, Sample {1} : {2}",
12                 firstFrameIndex + i, j + 1,
13                 file.AllFrames[i].AnalogSamples[j][k]);
14         }
15     }
16 }

除却一次性将C3D文件内容全读取出来的这种方式外,还可以行使C3DReader来一帧一帧底读取。

 1 using (FileStream fs = new FileStream("文件路径", FileMode.Open, FileAccess.Read))
 2 {
 3     C3DReader reader = new C3DReader(fs);
 4     C3DHeader header = reader.ReadHeader();
 5     C3DParameterDictionary dictionary = reader.ReadParameters();
 6     Int32 index = header.FirstFrameIndex;
 7 
 8     while (true)
 9     {
10         C3DFrame frame = reader.ReadNextFrame(dictionary);
11 
12         if (frame == null)
13         {
14             break;
15         }
16 
17         for (Int16 j = 0; j < frame.Point3Ds.Length; j++)
18         {
19             Console.WriteLine("Frame {0} : X = {1}, Y = {2}, Z = {3}",
20                 index++,
21                 frame.Point3Ds[j].X,
22                 frame.Point3Ds[j].Y,
23                 frame.Point3Ds[j].Z);
24         }
25     }
26 }

对于开创一个C3D文件,只待用C3DFile.Create()就可以创建一个拖欠的C3D文件之,不含其他的参数集合。而保存C3D文件则一直以file.SaveTo(“文件路径”)就可了。

对此增长参数集合好采用以下的代码:

1 //首先需要添加参数集合,ID为正数
2 file.Parameters.AddGroup(1, "POINT", "");
3 //然后往指定ID的参数集合中添加参数即可
4 file.Parameters[1].Add("USED", "").SetData<Int16>(5);

补给加帧可以行使如下的代码:

1 file.AllFrames.Add(new C3DFrame(new C3DPoint3DData[] {
2     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
3     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
4     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
5     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask},
6     new C3DPoint3DData() { X = x, Y = y, Z = z, Residual = residual, CameraMask = cameraMask} }));

本来,也得以将C3DPoint3DData数组换成C3DAnalogSamples数组,或者双方同时丰富也得。

 

【相关链接】

  1. C3D.ORG:http://www.c3d.org/
  2. c3d4sharp – C3D File reading/writing tools written in
    C#:http://code.google.com/p/c3d4sharp/
  3. C3D.NET:https://c3d.codeplex.com/

相关文章