2016-09-18 3 views
0

this siteに出て、しばらくの間SDFを学び始めました。しかし、私はまだ非常にこのコードの後ろにアイデアを得ることはありません:GLSL関数をメタルに変換する

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 
} 

私は期待したものを得ます。

  1. 私の変換方法は、inoutが完全ではないと思われます。私はShadertoyコードからそれを借りましたが、私はそれが実際にそのように機能することを納得させるものではありません。

  2. cはどのように便利ですか?サイドからのコードでは、コメント:私はそれが本当に何を意味するのか理解していない

Many of the operators partition space into cells. An identifier or cell index is returned, if possible. This return value is intended to be optionally used e.g. as a random seed to change parameters of the distance functions inside the cells.

。誰かがセルインデックスを使用する方法のいくつかの例を提案することができますか?

アップデート1:

私は、コードを変更します。

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; 
} 

、今、私は別のエラーメッセージが出ます:

fatal error: unexpectedly found nil while unwrapping an Optional value

このラインから:

command_encoder.setComputePipelineState(cps) 
をなぜなら、私は Metalファイルを分割する方法のためである 私はエラーを疑う アップデート1中:

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:10

はここMetaView.swiftから、全体のコードです。だから私は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); 
} 

エラー:

Call to pMod1 is ambiguous

答えて

2

金属で同等の機能が

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++の場合と同様に、参照渡しが必要です。金属では、あなたはまた、hg_sdf関数のpMod家族の目的は可能、スペースを「折る」ことです

constantthreadgroupなどではなく)明示的にthreadアドレス空間にあるものとして、それを修飾する必要があります定期的に繰り返すオブジェクトの複製を作成します。cの値は、オブジェクトが存在する折りたたまれたスペースの "パーティション"を示すオブジェクトインデックスのようなものです。オブジェクトの外観を調整しない限り無視できます(別のマテリアルを適用するか、サーフェスディテールを追加するなど)

これはすべてJohann Körndorfer's talk hereで完全に記述されています。

更新

関数を呼び出すためには、あなたがメタルで参照することによりスウィズルベクトル成分を渡すことができないので、あなたは、あなたが変更したいスウィズルアウトコンポーネントを格納するための一時変数を作成する必要があります。 pxので

float px = p.x; 
float c = pMod1(px, size); 
p.x = px; 

p.xは今pMod1内部pxに書き込まれた値が含まれ、参照によって渡されました。

+0

アドバイスごとに変更されましたが、新しいエラーがあります。私の** Update1 **にすべての詳細を確認してください。 – sooon

+0

残念ながら、スイッツベクトルコンポーネントは参照渡しできません。 'p.x'をローカル変数にコピーし、関数に_that_を渡し、関数呼び出しの後に_back_を' p.x'に代入する必要があります。また、関数の結果を 'p.x'に代入しないでください。戻り値はセルインデックスであり、参照パラメータで返す値とはまったく異なります。 – warrenm

+0

'pMod()'関数で 'thread float&p'の値を' c'を返すので、どのように使うことができますか?私は彼らが同じ機能を使用しているビデオをチェックしますが、何とか彼らは値 'p'を取り戻しました。 – sooon

関連する問題