首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

  • 24-12-03 00:44
  • 2611
  • 10227
juejin.cn

前言

大家好,我是一牛,今天我和大家分享的是如何使用 Metal 渲染图片。在上一节我们学会了如何渲染三角形,在这个基础上,渲染一张图片就会变得很容易。

纹理

首先我们先来复习下纹理的定义。纹理(Texture)是计算机图形学和图像处理中的一个重要概念,通常指用来为几何表面添加细节的二维或三维图像数据。在视觉上,纹理可以提供物体表面细节的逼真感,例如木纹、金属反光或粗糙度。在本文中我们通过图片生成纹理。

在Metal中我们可以使用MetalKit中的工具类MTKTextureLoader来生成纹理。

swift
代码解读
复制代码
nonisolated func createTexture() async -> MTLTexture? { let device = MTLCreateSystemDefaultDevice()! let loader = MTKTextureLoader(device: device) guard let url = Bundle.main.url(forResource: "lena_color", withExtension: "png") else { return nil } let texture = try? await loader.newTexture(URL: url) return texture }

对于简单格式图片,我们可以使用这个工具类生成纹理,对于特殊格式使用这个方法生成纹理可能会失败。

纹理坐标系

也就是说屏幕的左上角对应纹理坐标(0, 0)屏幕右下角对应纹理坐标(1.0,1.0), 屏幕中心点是纹理坐标(0.5,0.5)。

大家都知道,Metal的绘制的基本图元是三角形,渲染一张图片我们只需要绘制两个三角形。

swift
代码解读
复制代码
let vertices = [ // 左上角 Vertex(pixelPosition: [-256, 256], textureCoordinate: [0.0, 0.0]), // 左下角 Vertex(pixelPosition: [-256, -256], textureCoordinate: [0.0, 1.0]), // 右下角 Vertex(pixelPosition: [ 256, -256], textureCoordinate: [1.0, 1.0]), // 左上角 Vertex(pixelPosition: [-256, 256], textureCoordinate: [0.0, 0.0]), // 右下角 Vertex(pixelPosition: [ 256, -256], textureCoordinate: [1.0, 1.0]), // 右上角 Vertex(pixelPosition: [ 256, 256], textureCoordinate: [1.0, 0.0]), ]

(-256, 256)是图片的像素坐标,表示图片的左上角,它对应的纹理坐标是(0, 0)。图片像素坐标需要在顶点阶段转换成光栅化阶段需要的归一化坐标。为了演示方便,图片的长度和宽度恰好是256

设置纹理

less
代码解读
复制代码
commanderEncoder?.setFragmentTexture(texture, index: 0)

将生成的纹理交给片元函数处理。

顶点阶段

swift
代码解读
复制代码
vertex RasterizerData vertexShader(uint vertexID [[vertex_id]], constant Vertex *vertices [[buffer(0)]], constant uint2 *viewportSizePointer [[buffer(1)]] ) { float2 pixelPosition = vertices[vertexID].pixelPosition; float2 viewportSize = float2(*viewportSizePointer); RasterizerData out; out.position = float4(0.0, 0.0, 0.0, 1.0); out.position.xy = pixelPosition / (viewportSize / 2.0); out.textureCoordinate = vertices[vertexID].textureCoordinate; return out; }

和上一篇文章不同的是,我们传入了画布的尺寸。[[buffer(1)]]表示我们插槽1传入数据。

less
代码解读
复制代码
commanderEncoder?.setVertexBytes(&viewPortSize, length: MemoryLayout.stride, index: 1)

我们通过转化我们得到光栅化所需要的归一化坐标,可以看出图片会一直保持在画布的中间。

片元阶段

swift
代码解读
复制代码
fragment float4 fragmentShader(RasterizerData in [[stage_in]], texture2d<half> colorTexture [[texture(0)]] ) { constexpr sampler textureSampler (mag_filter::linear, min_filter::linear); const half4 colorSample = colorTexture.sample(textureSampler, in.textureCoordinate); return float4(colorSample); }

sampler 是 Metal Shading Language 中用于定义纹理采样方式的对象。

•mag_filter::linear: 当纹理被放大时,使用线性插值进行采样。

•min_filter::linear: 当纹理被缩小时,使用线性插值进行采样。

总结

通过本文的学习,我们了解了如何在 Metal 中加载纹理、设置纹理以及在着色器中采样纹理数据,最终实现了图片的渲染。相比于渲染简单的几何图形,纹理的引入让渲染内容更加丰富和多样化。下一步,我们将学习离屏渲染。

创作不易,请大家多多点赞收藏!感谢大家!

Demo见github

注:本文转载自juejin.cn的一牛的文章"https://juejin.cn/post/7443379759604006966"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

141
iOS
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top