is possible import or include metal
file metal file? have metal file math functions , include or import if needed in metal project. possible?
i tried:
#include "sdf.metal"
and got error:
metallib: multiply defined symbols _z4vmaxdv2_f command/applications/xcode.app/contents/developer/platforms/macosx.platform/usr/bin/metallib failed exit code 1
update:
here both shader files:
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
and shaders.metal:
#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; <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 there no specular lighting when there 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); }
update2:
and metalview.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) 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() { 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) } }
update 3
after implement per kickimusbutticus's solution, shader did compile. have error:
your setup incorrect (edit: , setup in other answer , previous version of answer.)
you can use header in c++ (metal based on c++11, after all...). need 1 more file, i'll call sdf.h
. file includes function prototype declarations without namespace declaration. , need #include
after using namespace metal;
declaration in other files. make sure header file not .metal
file , not in compile sources
list in build phases. if header being treated compiled source, that's what's causing compilererror
.
sdf.h
:
// sdfheaders.metal #ifndef sdf_headers #define sdf_headers float kk(float2 v); float kkk(float3 v); #endif
sdf.metal
:
#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
:
here use functions after including sdf.h
.
// shaders.metal #include <metal_stdlib> using namespace metal; #include "sdf.h" float fboxcheap(float3 p, float3 b) { //cheap box return kkk(abs(p) - b); } // ...
and of course, build after cleaning. luck!
Comments
Post a Comment