金属碎片着色器-如何根据可通过绘图功能调整的均匀度为每个像素分配颜色?

杰米2020

我有一个MTKView,它正在渲染一个具有一定大小的多维数据集,以便其一个面可以填满整个屏幕。

我正在向片段着色器传递一个包含随机Float的struct变量(称为theuniforms),并且我想根据float的值为屏幕上的每个像素着色一种不同的颜色。

现在,它会根据Float的值将整个四边形变为红色或蓝色,这在绘制函数中是随机的。

我认为我的设置是错误的,因为在任何帧上我都只能访问一个随机浮点数,并且在该帧期间所有像素都将被着色(我将没有一组随机浮点数来确定像素颜色)。但是,我认为我可以简单地将更多变量添加到struct变量中来解决此问题。

主要问题是通过片段功能访问单个像素……如果它甚至足以确定屏幕上每个像素的颜色,它的性能是否足够。

import UIKit
import MetalKit

class ViewController: UIViewController, MTKViewDelegate {
     
     var metaldevice: MTLDevice!
     var metalview: MTKView!
     var metallibrary: MTLLibrary!
     var metalqueue: MTLCommandQueue!
     var metalpipelinestate: MTLRenderPipelineState!
     var metalmesh: MTKMesh!
     
     var theuniforms = Uniforms(color: 1)
     
     struct Uniforms {
          var color = Float(1)
     }
     
     override var prefersStatusBarHidden: Bool { return true }
     override var prefersHomeIndicatorAutoHidden: Bool { return true }
     override func viewDidLoad() {
          super.viewDidLoad()

          self.view.backgroundColor = .black
          
          self.metaldevice = MTLCreateSystemDefaultDevice()
          self.metalview = MTKView()
          self.metalview.frame = UIScreen.main.bounds
          self.metalview.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 1)
          self.metalview.delegate = self
          self.metalview.device = self.metaldevice
          self.view.addSubview(self.metalview)
          
          self.metallibrary = self.metaldevice.makeDefaultLibrary()
          self.metalqueue = self.metaldevice.makeCommandQueue()
          self.metalmesh = self.returncube()
          
          let vfunc = self.metallibrary.makeFunction(name: "vertex_main")
          let ffunc = self.metallibrary.makeFunction(name: "fragment_main")
          let descriptor = MTLRenderPipelineDescriptor()
          descriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
          descriptor.vertexFunction = vfunc
          descriptor.fragmentFunction = ffunc
          descriptor.vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(self.metalmesh.vertexDescriptor)
          
          self.metalpipelinestate = try! self.metaldevice.makeRenderPipelineState(descriptor: descriptor)
          

     }


     func returncube() -> MTKMesh {
          let allocator = MTKMeshBufferAllocator(device: self.metaldevice)
          let model = MDLMesh(boxWithExtent: [2, 2, 2], segments: [1, 1, 1], inwardNormals: false, geometryType: .triangles, allocator: allocator)
          let mesh = try! MTKMesh(mesh: model, device: self.metaldevice)
          return mesh
     }
     
     func draw(in view: MTKView) {
          let descriptor = self.metalview.currentRenderPassDescriptor
          let buffer = self.metalqueue.makeCommandBuffer()
          let encoder = buffer?.makeRenderCommandEncoder(descriptor: descriptor!)
          encoder?.setRenderPipelineState(self.metalpipelinestate)
          
          self.theuniforms.color = Float.random(in: 1.0...2.0)
          
          encoder?.setVertexBytes(&theuniforms, length: MemoryLayout<Uniforms>.stride, index: 1)
          encoder?.setVertexBuffer(self.metalmesh.vertexBuffers[0].buffer, offset: 0, index: 0)
          for mesh in self.metalmesh.submeshes {
               encoder?.drawIndexedPrimitives(type: .triangle, indexCount: mesh.indexCount, indexType: mesh.indexType, indexBuffer: mesh.indexBuffer.buffer, indexBufferOffset: mesh.indexBuffer.offset)
          }
          
          encoder?.endEncoding()
          let drawable = self.metalview.currentDrawable
          buffer?.present(drawable!)
          buffer?.commit()
          
     }
     
     func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
          
     }
}


这是着色器代码

#include <metal_stdlib>
using namespace metal;
#include <simd/simd.h>

struct VertexIn {
     float4 position [[attribute(0)]];
};

struct Uniforms {
     float color;
};

struct VertexOut {
     float4 position [[position]];
     Uniforms uniforms;
};

vertex VertexOut vertex_main(const VertexIn in [[stage_in]],
                          constant Uniforms &uniforms [[buffer(1)]]
                          )
{
     VertexOut out;
     out.position = in.position;
     out.uniforms = uniforms;
     return out;
}

fragment float4 fragment_main( VertexOut in [[stage_in]])
{
     
     float4 color;
     
     if (in.uniforms.color > 1.5){ color = float4(1, 0, 0, 1); }
     else { color = float4(0, 0, 1, 1); }
     return color;
}
登姆

首先,您不应该使用制服来更改CPU过载的每个像素的颜色,但这是GPU任务,因此您应该在着色器内部使用某些功能。而且,如果您希望制服相应地更改片段的颜色,则必须将其传递到片段函数中setFragmentBytes(&theuniforms, length: MemoryLayout<Uniforms>.stride, index: 1),然后在片段函数中调用它。如果我做对了,您会在立方体上想要类似白噪声的东西,因此这里是着色器:

#include <metal_stdlib>
using namespace metal;
#include <simd/simd.h>

struct VertexIn {
     float4 position [[attribute(0)]];
};

struct Uniforms {
     float color;
};

struct VertexOut {
     float4 position [[position]];
};

vertex VertexOut vertex_main(const VertexIn in [[stage_in]])
{
     VertexOut out;
     out.position = in.position;
   
     return out;
}



float rand(float2 co)
{
    return fract(sin(dot(co.xy ,float2(12.9898,78.236))) * 43758.5453);
}


fragment float4 fragment_main( VertexOut in [[stage_in]],constant Uniforms &uniforms [[buffer(1)]])
{
              
                                                                                      
     float2 pos = in.position.xy;
     
     float4 color = float4(rand(pos));
     
     //if (in.uniforms.color > 1.5){ color = float4(1, 0, 0, 1); }
     //else { color = float4(0, 0, 1, 1); }
     return color;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章