Ios Metal-`include`或`import`功能
是否可以将Ios Metal-`include`或`import`功能,ios,macos,metal,Ios,Macos,Metal,是否可以将金属文件导入或包含到另一个金属文件中?假设我有一个包含所有数学函数的金属文件,我只会在金属项目中需要时包含或导入它。可能吗 我试过: #include "sdf.metal" 我得到了一个错误: metallib:多定义符号_Z4vmaxDv2_f Command/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/usr/bin/metallib 失败,退出代码为1 更新: 以下是我的两个着色器文件
金属
文件导入或包含到另一个金属文件中?假设我有一个包含所有数学函数的金属文件,我只会在金属项目中需要时包含或导入它。可能吗
我试过:
#include "sdf.metal"
我得到了一个错误:
metallib:多定义符号_Z4vmaxDv2_f
Command/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/usr/bin/metallib
失败,退出代码为1
更新:
以下是我的两个着色器文件:
SDF.metal:
#ifndef MYAPP_METAL_CONSTANTS
#define MYAPP_METAL_CONSTANTS
#include <metal_stdlib>
namespace metal {
float kk(float2 v) {
return max(v.x, v.y);
}
float kkk(float3 v) {
return max(max(v.x, v.y), v.z);
}
}
#endif
更新3
按照KickimusButticus的解决方案实现后,着色器进行了编译。但是,我还有一个错误:
如果在该符号上运行,您会发现编译器认为您有两个或多个签名为vmax(float2v)
的函数定义。检查包含的文件是否有此函数的多个定义,或者包含此函数的文件和包含此函数的文件是否都提供了此定义。您的设置不正确(编辑:我的其他答案和此答案的以前版本中的设置也是如此。)
<>你可以使用一个标题,就像C++一样。你只需要一个文件,我就称它为SDF.h
。该文件包含没有命名空间声明的函数原型声明。您需要在使用名称空间金属的之后包含代码>其他文件中的声明。确保头文件不是.metal
文件,并且它不在构建阶段的编译源代码
列表中。如果标头被视为已编译的源代码,则很可能是导致编译器错误的原因
SDF.h
:
SDF.metal
:
当然,清洁后再建造。祝你好运 我照你说的做了,它确实编译了。但是,我在第行的命令\u encoder.setComputePipelineState(cps)
-处有另一个运行时错误。致命错误:在展开可选值时意外发现nil
。我更新了上面的MetalView
文件。这是您的metal文件编译的进度。哪个选项是意外的nil
?它是cps吗?registerShaders()中的try/catch块是否打印出有用的内容?好的,我认为问题在于在构建阶段的“编译源代码”列表中有SDFHeaders.metal。试着把它移到那里。另外,我对我的答案做了一些其他的修改。请看一看并做一些调整。我可以注意到,正如您所说,Metal 1基于C++11,而Metal 2基于C++14吗?需要注意的一点很重要,这让我有一段时间感到困惑,那就是include语句(与代码其余部分中的import语句不同)尊重您的项目目录结构。这意味着,如果要包含与执行包含操作的文件不在同一文件夹中的文件,则必须为其提供该文件的路径(即#include../shared.h”
,如果该文件位于父文件夹中)
#include <metal_stdlib>
#include "SDF.metal"
using namespace metal;
float fBoxCheap(float3 p, float3 b) { //cheap box
return kkk(abs(p) - b);
}
float map( float3 p )
{
float box2 = fBoxCheap(p-float3(0.0,3.0,0.0),float3(4.0,3.0,1.0));
return box2;
}
float3 getNormal( float3 p )
{
float3 e = float3( 0.001, 0.00, 0.00 );
float deltaX = map( p + e.xyy ) - map( p - e.xyy );
float deltaY = map( p + e.yxy ) - map( p - e.yxy );
float deltaZ = map( p + e.yyx ) - map( p - e.yyx );
return normalize( float3( deltaX, deltaY, deltaZ ) );
}
float trace( float3 origin, float3 direction, thread float3 &p )
{
float totalDistanceTraveled = 0.0;
for( int i=0; i <64; ++i)
{
p = origin + direction * totalDistanceTraveled;
float distanceFromPointOnRayToClosestObjectInScene = map( p );
totalDistanceTraveled += distanceFromPointOnRayToClosestObjectInScene;
if( distanceFromPointOnRayToClosestObjectInScene < 0.0001 )
{
break;
}
if( totalDistanceTraveled > 10000.0 )
{
totalDistanceTraveled = 0.0000;
break;
}
}
return totalDistanceTraveled;
}
float3 calculateLighting(float3 pointOnSurface, float3 surfaceNormal, float3 lightPosition, float3 cameraPosition)
{
float3 fromPointToLight = normalize(lightPosition - pointOnSurface);
float diffuseStrength = clamp( dot( surfaceNormal, fromPointToLight ), 0.0, 1.0 );
float3 diffuseColor = diffuseStrength * float3( 1.0, 0.0, 0.0 );
float3 reflectedLightVector = normalize( reflect( -fromPointToLight, surfaceNormal ) );
float3 fromPointToCamera = normalize( cameraPosition - pointOnSurface );
float specularStrength = pow( clamp( dot(reflectedLightVector, fromPointToCamera), 0.0, 1.0 ), 10.0 );
// Ensure that there is no specular lighting when there is no diffuse lighting.
specularStrength = min( diffuseStrength, specularStrength );
float3 specularColor = specularStrength * float3( 1.0 );
float3 finalColor = diffuseColor + specularColor;
return finalColor;
}
kernel void compute(texture2d<float, access::write> output [[texture(0)]],
constant float &timer [[buffer(1)]],
constant float &mousex [[buffer(2)]],
constant float &mousey [[buffer(3)]],
uint2 gid [[thread_position_in_grid]])
{
int width = output.get_width();
int height = output.get_height();
float2 uv = float2(gid) / float2(width, height);
uv = uv * 2.0 - 1.0;
// scale proportionately.
if(width > height) uv.x *= float(width)/float(height);
if(width < height) uv.y *= float(height)/float(width);
float posx = mousex * 2.0 - 1.0;
float posy = mousey * 2.0 - 1.0;
float3 cameraPosition = float3( posx * 0.01,posy * 0.01, -10.0 );
float3 cameraDirection = normalize( float3( uv.x, uv.y, 1.0) );
float3 pointOnSurface;
float distanceToClosestPointInScene = trace( cameraPosition, cameraDirection, pointOnSurface );
float3 finalColor = float3(1.0);
if( distanceToClosestPointInScene > 0.0 )
{
float3 lightPosition = float3( 5.0, 2.0, -10.0 );
float3 surfaceNormal = getNormal( pointOnSurface );
finalColor = calculateLighting( pointOnSurface, surfaceNormal, lightPosition, cameraPosition );
}
output.write(float4(float3(finalColor), 1), gid);
}
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)
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)
}
}
// SDFHeaders.metal
#ifndef SDF_HEADERS
#define SDF_HEADERS
float kk(float2 v);
float kkk(float3 v);
#endif
#include <metal_stdlib>
using namespace metal;
#include "SDF.h"
float kk(float2 v) {
return max(v.x, v.y);
}
float kkk(float3 v) {
return max(max(v.x, v.y), v.z);
}
// Shaders.metal
#include <metal_stdlib>
using namespace metal;
#include "SDF.h"
float fBoxCheap(float3 p, float3 b) { //cheap box
return kkk(abs(p) - b);
}
// ...