问题描述
我有一个MTKView,它正在渲染一个具有一定大小的多维数据集,以便它的一个面可以填满整个屏幕。
我正在将包含随机Float的结构变量(称为统一变量)传递给片段着色器,我想根据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,1); }
else { color = float4(0,1); }
return color;
}
解决方法
首先,您不应该使用制服来更改使CPU过载的每个像素的颜色,但这是GPU任务,因此您应该在着色器内部使用某些功能。而且,如果您希望制服相应地更改片段的颜色,则必须将其传递到片段函数Sub Test4()
Dim rowDB As Long
Dim wsDB As Worksheet
Set wsDB = ActiveSheet
rowDB = WorksheetFunction.Match("30.06.2020",wsDB.Range("C7:C366"))
Debug.Print rowDB
End Sub
中,并在片段函数中调用它。如果我说对了,您会在立方体上想要类似白噪声的东西,因此这里是着色器:
setFragmentBytes(&theuniforms,length: MemoryLayout<Uniforms>.stride,index: 1)