将GLSL函数转换为Metal
Convert GLSL functions to Metal
我偶然发现了这个网站,并开始研究SDF一段时间了。然而,我仍然不太明白这段代码背后的意思:
float pMod1(inout float p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
我把它转换成我的Metal
代码:
#define _inout(T) T
...
float pMod1(_inout (float) p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
但没有得到预期的结果。但是,如果我改为
#define _inout(T) T
...
float pMod1(_inout (float) p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return p; // <-- change from c to p
}
我得到了我想要的。
我怀疑我转换
inout
的方式不完全正确。我从一些Shadertoy
代码中借用了它,但我不相信它真的是这样工作的。c
如何有用?在代码中从侧面注释:
我不明白它到底是什么意思。有人可以建议一些例子如何使用单元格索引?许多运算符将空间划分为单元格。一个标识符如果可能的话,返回单元格索引。这个返回值是打算可选地使用,例如作为一个随机的种子改变单元格内部距离函数参数
Update1:
我将代码改为:
float pMod1(thread float &p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
,现在我得到另一个错误信息:
致命错误:在展开可选值
时意外发现nil
from this行:
command_encoder.setComputePipelineState(cps)
下面是来自MetaView.swift的全部代码:
import MetalKit
public class MetalView: MTKView, NSWindowDelegate {
var queue: MTLCommandQueue! = nil
var cps: MTLComputePipelineState! = nil
var timer: Float = 0
var timerBuffer: MTLBuffer!
var mousexBuffer: MTLBuffer!
var mouseyBuffer: MTLBuffer!
var pos: NSPoint!
var floatx: Float!
var floaty: Float!
required public init(coder: NSCoder) {
super.init(coder: coder)
self.framebufferOnly = false
device = MTLCreateSystemDefaultDevice()
registerShaders()
}
override public func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
if let drawable = currentDrawable {
let command_buffer = queue.commandBuffer()
let command_encoder = command_buffer.computeCommandEncoder()
command_encoder.setComputePipelineState(cps) ///////<-- This line throw an error.
command_encoder.setTexture(drawable.texture, atIndex: 0)
command_encoder.setBuffer(timerBuffer, offset: 0, atIndex: 1)
command_encoder.setBuffer(mousexBuffer, offset: 0, atIndex: 2)
command_encoder.setBuffer(mouseyBuffer, offset: 0, atIndex: 3)
update()
let threadGroupCount = MTLSizeMake(8, 8, 1)
let threadGroups = MTLSizeMake(drawable.texture.width / threadGroupCount.width, drawable.texture.height / threadGroupCount.height, 1)
command_encoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
command_encoder.endEncoding()
command_buffer.presentDrawable(drawable)
command_buffer.commit()
}
}
func registerShaders() {
queue = device!.newCommandQueue()
do {
let library = device!.newDefaultLibrary()!
let kernel = library.newFunctionWithName("compute")!
timerBuffer = device!.newBufferWithLength(sizeof(Float), options: [])
mousexBuffer = device!.newBufferWithLength(sizeof(Float), options: [])
mouseyBuffer = device!.newBufferWithLength(sizeof(Float), options: [])
cps = try device!.newComputePipelineStateWithFunction(kernel)
} catch let e {
Swift.print("(e)")
}
}
func update() {
timer += 0.01
var bufferPointer = timerBuffer.contents()
memcpy(bufferPointer, &timer, sizeof(Float))
bufferPointer = mousexBuffer.contents()
memcpy(bufferPointer, &floatx, sizeof(NSPoint))
bufferPointer = mouseyBuffer.contents()
memcpy(bufferPointer, &floaty, sizeof(NSPoint))
}
override public func mouseDragged(event: NSEvent) {
pos = convertPointToLayer(convertPoint(event.locationInWindow, fromView: nil))
let scale = layer!.contentsScale
pos.x *= scale
pos.y *= scale
floatx = Float(pos.x)
floaty = Float(pos.y)
debugPrint("Hello",pos.x,pos.y)
}
}
更新2:我怀疑Update1中的错误是因为我分割Metal
文件的方式。因此,我通过将所有函数复制到1 Metal
文件中来简化它,现在我产生了新的错误:
float pMod1(thread float &p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
static float map( float3 p )
{
float size = 10.0;
p.x = pMod1(p.x,size);/////<--- this produce the error.
float box = fBox(p, float3(1));
float sphere = length(p - float3(1)) - 1;
float d = min(box,sphere);
float guard = -fBoxCheap(p, float3(size*0.5));
guard = abs(guard) + size*0.1;
return min(d,guard);
}
错误:对
pMod1
的调用是二义的
Metal中的等效函数为
float pMod1(thread float &p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
为了修改形参,需要通过引用传递它,就像在c++中一样。在Metal中,您还需要显式地将其限定为位于thread
地址空间(与constant
, threadgroup
等相反)
hg_sdf中pMod
系列函数的目的是"折叠"空间,允许您创建定期重复的对象的副本。c
值类似于对象索引,表示对象位于折叠空间的哪个"分区"。你可以忽略它,除非你正在调整对象外观(通过应用不同的材料或添加表面细节等)
这些在Johann Körndorfer的演讲中都有详细的描述。
为了调用这个函数,你需要创建一个临时变量来存储你想要修改的swizzleout组件,因为你不能在Metal中通过引用传递swizzledvector组件。
float px = p.x;
float c = pMod1(px, size);
p.x = px;
由于px
是通过引用传递的,因此p.x
现在包含了在pMod1
中写入px
的值
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 是否可以从int转换为enum类类型
- 将QOpenGLWidget子类转换为使用Metal而不是OpenGL的子类是否可行?
- 将GLSL函数转换为Metal