Metal入门教程(二)三维变换
前言
Metal入門教程(一)圖片繪制
上一篇的教程介紹了如何繪制一張圖片,這次的目標是把圖片顯示到3D物體上,并進行三維變換。
Metal系列教程的代碼地址;
OpenGL ES系列教程在這里;
你的star和fork是我的源動力,你的意見能讓我走得更遠。
正文
核心思路
在圖片繪制的基礎上,給頂點數據增加z坐標,并使用頂點的索引緩存;為了實現三維變換,給頂點shader增加投影矩陣和模型變換矩陣。
效果展示
具體細節
1、新建MTKView、設置渲染管道、設置紋理數據
同Metal入門教程(一)圖片繪制;
2、設置頂點數據
- (void)setupVertex {static const LYVertex quadVertices[] ={ // 頂點坐標 頂點顏色 紋理坐標{{-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}},//頂點};self.vertices = [self.mtkView.device newBufferWithBytes:quadVerticeslength:sizeof(quadVertices)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:indiceslength: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:&matrixlength:sizeof(matrix)atIndex:LYVertexInputIndexMatrix]; } 復制代碼projectionMatrix 是投影變換矩陣,modelViewMatrix是模型變換矩陣,為了方便理解,把繞x、y、z軸旋轉用三次GLKMatrix4Rotate實現。
沒有找到Metal和MetalKit快捷創建矩陣的方法,于是用了GLKit的方法進行創建,再通過getMetalMatrixFromGLKMatrix:方法進行轉換,方法如下:
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.verticesoffset:0atIndex:LYVertexInputIndexVertices];[renderEncoder setFrontFacingWinding:MTLWindingCounterClockwise];[renderEncoder setCullMode:MTLCullModeBack]; 復制代碼頂點數據設置的index參數使用了枚舉變量LYVertexInputIndexVertices,這樣可以保證和shader里面的索引對齊;
在設置完頂點數據后,還增加CullMode(剔除模式),MTLWindingCounterClockwise表示對順時針順序的三角形進行剔除。
5、Shader處理
vertex RasterizerData // 頂點 vertexShader(uint vertexID [[ vertex_id ]],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 // 片元 samplingShader(RasterizerData input [[stage_in]],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); } 復制代碼頂點shader的buffer的修飾符有LYVertexInputIndexVertices和LYVertexInputIndexMatrix,與業務層的枚舉變量一致;
在計算頂點坐標的時候,增加了projectionMatrix 和 modelViewMatrix的處理;
片元shader的texture的修飾符是LYFragmentInputIndexTexture;
嘗試把從圖片讀取顏色的代碼屏蔽,使用上面的代碼,可以得到頂點顏色的顯示結果;
總結
Metal的三維變換與OpenGL ES一樣,重點是如何初始化矩陣,并且把矩陣傳遞給頂點shader;同時Metal的Shader有語法檢測,使用枚舉變量能在編譯階段就定位到問題。
這里可以下載demo代碼。
轉載于:https://juejin.im/post/5b40bebe6fb9a04f844aaa49
總結
以上是生活随笔為你收集整理的Metal入门教程(二)三维变换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样寻回win8因为删除后清空回收站的数
- 下一篇: flask 中文编码解码