# Metal入门教程（二）三维变换

### 前言

Metal入门教程（一）图片绘制

Metal系列教程的代码地址； OpenGL ES系列教程在这里

### 正文

#### 具体细节

##### 2、设置顶点数据
```- (void)setupVertex {
{  // 顶点坐标                          顶点颜色                    纹理坐标
{{-0.5f, 0.5f, 0.0f, 1.0f},      {0.0f, 0.0f, 0.5f},       {0.0f, 1.0f}},//左上
{{0.5f, 0.5f, 0.0f, 1.0f},       {0.0f, 0.5f, 0.0f},       {1.0f, 1.0f}},//右上
{{-0.5f, -0.5f, 0.0f, 1.0f},     {0.5f, 0.0f, 1.0f},       {0.0f, 0.0f}},//左下
{{0.5f, -0.5f, 0.0f, 1.0f},      {0.0f, 0.0f, 0.5f},       {1.0f, 0.0f}},//右下
{{0.0f, 0.0f, 1.0f, 1.0f},       {1.0f, 1.0f, 1.0f},       {0.5f, 0.5f}},//顶点
};
options:MTLResourceStorageModeShared];
static int indices[] =
{ // 索引
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
};
self.indexs = [self.mtkView.device newBufferWithBytes:indices
length:sizeof(indices)
options:MTLResourceStorageModeShared];
self.indexCount = sizeof(indices) / sizeof(int);
}```

`LYVertex`由顶点坐标、顶点颜色、纹理坐标组成； 索引缓存的创建和顶点缓存的创建一样，本质都是存放数据的缓存；

##### 3、设置投影变换和模型变换矩阵
```- (void)setupMatrixWithEncoder:(id<MTLRenderCommandEncoder>)renderEncoder {
CGSize size = self.view.bounds.size;
float aspect = fabs(size.width / size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 10.f);
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);
static float x = 0.0, y = 0.0, z = M_PI;
if (self.rotationX.on) {
x += self.slider.value;
}
if (self.rotationY.on) {
y += self.slider.value;
}
if (self.rotationZ.on) {
z += self.slider.value;
}
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, x, 1, 0, 0);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, y, 0, 1, 0);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, z, 0, 0, 1);

LYMatrix matrix = {[self getMetalMatrixFromGLKMatrix:projectionMatrix], [self getMetalMatrixFromGLKMatrix:modelViewMatrix]};

[renderEncoder setVertexBytes:&matrix
length:sizeof(matrix)
atIndex:LYVertexInputIndexMatrix];
}```

`projectionMatrix` 是投影变换矩阵，`modelViewMatrix`是模型变换矩阵，为了方便理解，把绕x、y、z轴旋转用三次`GLKMatrix4Rotate`实现。 没有找到Metal和MetalKit快捷创建矩阵的方法，于是用了GLKit的方法进行创建，再通过`getMetalMatrixFromGLKMatrix:`方法进行转换，方法如下：

```/**
找了很多文档，都没有发现metalKit或者simd相关的接口可以快捷创建矩阵的，于是只能从GLKit里面借力

@param matrix GLKit的矩阵
@return metal用的矩阵
*/
- (matrix_float4x4)getMetalMatrixFromGLKMatrix:(GLKMatrix4)matrix {
matrix_float4x4 ret = (matrix_float4x4){
simd_make_float4(matrix.m00, matrix.m01, matrix.m02, matrix.m03),
simd_make_float4(matrix.m10, matrix.m11, matrix.m12, matrix.m13),
simd_make_float4(matrix.m20, matrix.m21, matrix.m22, matrix.m23),
simd_make_float4(matrix.m30, matrix.m31, matrix.m32, matrix.m33),
};
return ret;
}```
##### 4、具体渲染过程
```        id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

[renderEncoder setViewport:(MTLViewport){0.0, 0.0, self.viewportSize.x, self.viewportSize.y, -1.0, 1.0 }];
[renderEncoder setRenderPipelineState:self.pipelineState];
[self setupMatrixWithEncoder:renderEncoder];

[renderEncoder setVertexBuffer:self.vertices
offset:0
atIndex:LYVertexInputIndexVertices];
[renderEncoder setFrontFacingWinding:MTLWindingCounterClockwise];
[renderEncoder setCullMode:MTLCullModeBack];```

```vertex RasterizerData // 顶点
constant LYVertex *vertexArray [[ buffer(LYVertexInputIndexVertices) ]],
constant LYMatrix *matrix [[ buffer(LYVertexInputIndexMatrix) ]]) {
RasterizerData out;
out.clipSpacePosition = matrix->projectionMatrix * matrix->modelViewMatrix * vertexArray[vertexID].position;
out.textureCoordinate = vertexArray[vertexID].textureCoordinate;
out.pixelColor = vertexArray[vertexID].color;

return out;
}

fragment float4 // 片元
texture2d<half> textureColor [[ texture(LYFragmentInputIndexTexture) ]])
{
constexpr sampler textureSampler (mag_filter::linear,
min_filter::linear);

//    half4 colorTex = textureColor.sample(textureSampler, input.textureCoordinate);
half4 colorTex = half4(input.pixelColor.x, input.pixelColor.y, input.pixelColor.z, 1);
return float4(colorTex);
}```

164 篇文章72 人订阅

3 条评论

## 相关文章

511

### CSS魔法堂：更丰富的前端动效by CSS Animation

在《CSS魔法堂：Transition就这么好玩》中我们了解到对于简单的补间动画，我们可以通过transition实现。那到底多简单的动画适合用transti...

1454

### Android Heroes Reading Notes 3

《Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧

502

### 【C#】分享一个可灵活设置边框的Panel

---------------------------更新：2014-05-19---------------------------

711

2267

892

622

23310

622

3018