ios - Metal - `include` or `import` function -


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: enter image description here

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