excel表格怎样设置去除重复数据(怎么去掉excel表中重复数据)
697
2022-05-30
本文是基于“Metal渲染绘制三角形”这样顶点较少图形基础之上的延伸, 在渲染三角形的时候, 顶点数据的存储使用的是数组,当顶点传递时通过setVertexBytes(_:length:index:)方法,主要是由于绘制三角形时,所需的顶点只有三个,顶点数据很少,所以可以通过数组存储,此时的数据是存储在CPU中的;
Metal三角形的渲染绘制请参考:Metal之渲染绘制三角形
对于小于4KB(即4096字节)的一次性数据,使用setVertexBytes(:length:index:),如果数据长度超过4KB 或者需要多次使用顶点数据时,需要创建一个MTLBuffer对象,创建的buffer的目的就是为了将顶点数据存储到顶点缓存区,GPU可以直接访问该缓存区获取顶点数据,并且buffer缓存的数据需要通过setVertexBuffer(:offset:index:)方法传递到顶点着色器。
当图形的顶点数据较多时, 顶点的传递与存储过程如下:
① Metal -> MTLBuffer -> 缓存区(存储非常多自定义数据,GPU直接访问 -> 显存) -> 存储顶点数据;
② 创建的buffer的目的就是为了将顶点数据存储到顶点缓存区,GPU可以直接访问该缓存区获取顶点数据,并且buffer缓存的数据需要通过 setVertexBuffer(_:offset:index:)方法传递到顶点着色器。
metal文件中,在顶点着色函数需要对顶点坐标进行归一化处理,因为顶点数据初始化时使用的是物体坐标。顶点坐标的归一化主要有以下步骤:
定义顶点着色器输出
初始化输出剪辑空间位置
获取当前顶点坐标的xy:主要是因为绘制的图形是2D的,其z都为0
将传入的视图大小转换为vector_float2二维向量类型
顶点坐标归一化:可以通过一行代码同时分隔两个通道x和y,并执行除法,然后将结果放入输出的x和y通道中,即从像素空间位置转换为裁剪空间位置
#include
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
主要需要加载metal文件来获取顶点数据
获取GPU设备device: 通过视图控制器中初始化render对象时传入的MTKView对象view,利用view来获取GPU的使用权限
_device = mtkView.device;
1
设置绘制纹理的像素格式
mtkView.colorPixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
1
从项目中加载所以的.metal着色器文件
// 从项目中加载所以的.metal着色器文件 id
1
2
3
4
5
6
配置用于创建管道状态的管道描述符
// 配置用于创建管道状态的管道 MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; // 管道名称 pipelineStateDescriptor.label = @"Simple Pipeline"; // 可编程函数,用于处理渲染过程中的各个顶点 pipelineStateDescriptor.vertexFunction = vertexFunction; // 可编程函数,用于处理渲染过程总的各个片段/片元 pipelineStateDescriptor.fragmentFunction = fragmentFunction; // 设置管道中存储颜色数据的组件格式 pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;
1
2
3
4
5
6
7
8
9
10
同步创建并返回渲染管线对象
// 同步创建并返回渲染管线对象 NSError *error = NULL; _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
1
2
3
4
获取顶点数据
// 获取顶点数据 NSData *vertexData = [YDWRenderer generateVertexData]; // 创建一个vertex buffer,可以由GPU来读取 _vertexBuffer = [_device newBufferWithLength:vertexData.length options:MTLResourceStorageModeShared]; /* 复制vertex data 到vertex buffer 通过缓存区的"content"内容属性访问指针 * * memcpy(void *dst, const void *src, size_t n); * dst:目的地 * src:源内容 * n: 长度 */ memcpy(_vertexBuffer.contents, vertexData.bytes, vertexData.length); // 计算顶点个数 = 顶点数据长度 / 单个顶点大小 _numVertices = vertexData.length / sizeof(CCVertex);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 顶点数据 + (nonnull NSData *)generateVertexData { // 正方形 = 三角形+三角形 const CCVertex quadVertices[] = { // Pixel 位置, RGBA 颜色 { { -20, 20 }, { 1, 0, 0, 1 } }, { { 20, 20 }, { 1, 0, 0, 1 } }, { { -20, -20 }, { 1, 0, 0, 1 } }, { { 20, -20 }, { 0, 0, 1, 1 } }, { { -20, -20 }, { 0, 0, 1, 1 } }, { { 20, 20 }, { 0, 0, 1, 1 } }, }; // 行/列 数量 const NSUInteger NUM_COLUMNS = 25; const NSUInteger NUM_ROWS = 15; // 顶点个数 const NSUInteger NUM_VERTICES_PER_QUAD = sizeof(quadVertices) / sizeof(CCVertex); // 四边形间距 const float QUAD_SPACING = 50.0; // 数据大小 = 单个四边形大小 * 行 * 列 NSUInteger dataSize = sizeof(quadVertices) * NUM_COLUMNS * NUM_ROWS; // 开辟空间 NSMutableData *vertexData = [[NSMutableData alloc] initWithLength:dataSize]; // 当前四边形 CCVertex * currentQuad = vertexData.mutableBytes; // 获取顶点坐标(循环计算) // 行 for(NSUInteger row = 0; row < NUM_ROWS; row++) { // 列 for(NSUInteger column = 0; column < NUM_COLUMNS; column++) { // 左上角的位置 vector_float2 upperLeftPosition; // 计算X,Y 位置.注意坐标系基于2D笛卡尔坐标系,中心点(0,0),所以会出现负数位置 upperLeftPosition.x = ((-((float)NUM_COLUMNS) / 2.0) + column) * QUAD_SPACING + QUAD_SPACING/2.0; upperLeftPosition.y = ((-((float)NUM_ROWS) / 2.0) + row) * QUAD_SPACING + QUAD_SPACING/2.0; // 将quadVertices数据复制到currentQuad memcpy(currentQuad, &quadVertices, sizeof(quadVertices)); // 遍历currentQuad中的数据 for (NSUInteger vertexInQuad = 0; vertexInQuad < NUM_VERTICES_PER_QUAD; vertexInQuad++) { //修改vertexInQuad中的position currentQuad[vertexInQuad].position += upperLeftPosition; } // 更新索引 currentQuad += 6; } } return vertexData; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
创建命令队列
// 创建命令队列 _commandQueue = [_device newCommandQueue];
1
2
主要加载顶点缓冲区数据
为当前渲染的每个渲染传递创建一个新的命令缓冲区
// 为当前渲染的每个渲染传递创建一个新的命令缓冲区 id
1
2
3
4
创建渲染描述符
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor; // 判断渲染目标是否为空 if(renderPassDescriptor != nil) { // 创建渲染命令编码器,这样才可以渲染到something id
1
2
3
4
5
6
7
8
9
设置我们绘制的可绘制区域
/*设置绘制的可绘制区域 * *typedef struct { double originX, originY, width, height, znear, zfar; } MTLViewport; */ [renderEncoder setViewport:(MTLViewport){ 0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];
1
2
3
4
5
6
7
8
9
设置渲染管道
// 设置渲染管道 [renderEncoder setRenderPipelineState:_pipelineState];
1
2
为了从OC代码找发送数据预加载的MTLBuffer 到Metal 顶点着色函数中
// 将_vertexBuffer 设置到顶点缓存区中 [renderEncoder setVertexBuffer:_vertexBuffer offset:0 atIndex:CCVertexInputIndexVertices]; // 将 _viewportSize 设置到顶点缓存区绑定点设置数据 [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:CCVertexInputIndexViewportSize];
1
2
3
4
5
6
7
8
9
开始绘图
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:_numVertices];
1
2
3
结束编码,表示已该编码器生成的命令都已完成,并且从NTLCommandBuffer中分离
[renderEncoder endEncoding];
1
一旦框架缓冲区完成,使用当前可绘制的进度表
[commandBuffer presentDrawable:view.currentDrawable];
1
完成渲染并将命令缓冲区推送到GPU
[commandBuffer commit];
1
Metal之MTLBuffer批量加载顶点数量较多的图形渲染
渲染
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。