頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


macOSでテキストファイルの読み込み、保存ができない

macOSアプリでテキストファイルを保存しようとしたらファイルの有無は教えてくれるんだけど、読み書きができない。

Error Domain=NSCocoaErrorDomain Code=257 "The file “status.txt” couldn’t be opened because you don’t have permission to view it."

みたいな警告が出る。
ちなみにファイルの有無の確認はこんなの↓
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    if ([fileManager fileExistsAtPath:filePath]) {
        // the file exists

    } else {
        // not exist
}
読み込むのはこんなの↓
{
    NSError *error = nil;
    NSString *content = [NSString stringWithContentsOfFile:filePath
                                                  encoding:NSUTF8StringEncoding
                                                     error:&error];
}
エラーメッセージにpermissionがどうのとあるのでpermissionの変更をしてもダメでどういうことやねんと悩んでいたんだけど、、、

Xcodeのサンドボックス設定

↑結局、サンドボックスをオフにする、でいけた。確かデフォルトでオンになっていたと思う。
ただしmacOSアプリではリリースするのにはサンドボックスを使うのが必須だったような気がするが。今回はリリース目的ではないのでこれでよしとしよう。


MPSCNNConvolutionのイニシャライズができない

APPLE公式のサンプルコードでMPSCNNHelloWorldってiOSデバイスでMNISTができるのがある。
ところが最新のサンプル(残念ながらSwiftのみ)をダウンロードしてきても、SlimMPSCNNConvolutionクラスで親クラス(MPSCNNConvolution)のイニシャライザ部分で

Cannot invoke 'MPSCNNConvolution.init' with an argument list of type '(device: MTLDevice, convolutionDescriptor: MPSCNNConvolutionDescriptor, kernelWeights: UnsafePointer<Float>, biasTerms: UnsafePointer<Float>, flags: MPSCNNConvolutionFlags)'

ってエラーでビルドさえできない。
以前ダウンロードしてたObjective-C用のでも

No visible @interface for 'MPSCNNConvolution' declares the selector 'initWithDevice:convolutionDescriptor:kernelWeights:biasTerms:flags:'

そんなイニシャライザはねえよ!ってエラーで同じくビルドもできない。

リファレンスにはdeprecatedとなっているが代わりにこうしろってのもよくわからないし、ヘッダーに書いてるメソッド(initWithDevice:weights:)も動きそうにない。

dev cenのフォーラムを見ると、この4月の始め頃から同じように困っている人のコメントがあった。
それに対し、すでにバグレポートを出したよ、なんてリプライもあったんだけど、そんなの待ってられないなあ?
と思ってたらAPIとしてはもうないけどメソッドとしてはまだあるのでselector使ったらいいよ、って記述が。

なんだかよくわかんないけど、試してみた。ただselectorって引数をたくさんとれないので面倒だけどNSInvocationとか使う。

{
//    self = [super initWithDevice:device
//           convolutionDescriptor:convDesc
//                   kernelWeights:weightP
//                       biasTerms:biasP
//                           flags:MPSCNNConvolutionFlagsNone];
//    ↑もとがこれ

    
    NSInvocation *invocation;
    NSMethodSignature *signature;
    SEL argSelector =  @selector(initWithDevice:convolutionDescriptor:kernelWeights:biasTerms:flags:);

    MPSCNNConvolution *cnnc = [MPSCNNConvolution alloc];
    
    signature = [self methodSignatureForSelector:argSelector];
    invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:cnnc];
    [invocation setSelector:argSelector];
    NSUInteger n = 0;
    
    [invocation setArgument:&device atIndex:2];
    [invocation setArgument:&convDesc atIndex:3];
    [invocation setArgument:&weightP atIndex:4];
    [invocation setArgument:&biasP atIndex:5];
    [invocation setArgument:&n atIndex:6];

    [invocation invoke];
    
    //返り値を得る
    [invocation getReturnValue:(void*)&cnnc];
    self = (SlimMPSCNNConvolution *)cnnc;
}
もともとのメソッドの最後の引数のMPSCNNConvolutionFlagsNoneもdeprecatedだし、もともとこれしかなかったやつでもとの値もゼロなのでそれを入れてる。
とりあえずこれで動いた!!!



おまけ。
MPSCNNConvolutionDescriptorの
cnnConvolutionDescriptorWithKernelWidth:kernelHeight:inputFeatureChannels:outputFeatureChannels:neuronFilter:
ってメソッドもdeprecatedだけど、現在そのままでも警告はでるけど動いてくれる。
cnnConvolutionDescriptorWithKernelWidth:kernelHeight:inputFeatureChannels:outputFeatureChannels:
ってのがiOS11.0から使えるみたいなので、こっちを使うと警告は消えた。
ただ最後のneuronFilter:で渡していた項目見ると重要だろ?と思うんだがそのままでも動いてる。なんでや?!
でも気持ち悪いのでちゃんと設定しておく。
もともとのコードでは活性化関数にReLUを使うって指定してる。
なのでこんな感じにしといた。
{
    MPSCNNConvolutionDescriptor *convDesc = …

    MPSNNNeuronDescriptor *fusedNeuronDescriptor =[MPSNNNeuronDescriptor new];
    fusedNeuronDescriptor.neuronType = MPSCNNNeuronTypeReLU;
    fusedNeuronDescriptor.a = 0.0;
    convDesc.fusedNeuronDescriptor = fusedNeuronDescriptor;
}




Xcode 9.3
iOS 11.3.1


SceneKitでシェーダを適用すると不具合発生?

Blenderで二つのオブジェクト+1つのarmatureを持つオブジェクトを作成し、daeファイルとして出力。それをSceneKitで使おうとしたらすごくはまった、というか全然できない!というお話。
なお、オブジェクト1つ+1つのarmatureなら何も問題ない。

Blenderでオブジェクト作成

↑Blenderで円柱と直方体のオブジェクトを作成、1つのarmatureと親子関係を設定してる。

Blenderでテクスチャを表示

↑円柱、直方体それぞれテクスチャを割り当ててる(けど本筋には関係ない)。
これらをdaeファイルとして出力。

Scene Editorでオブジェクト構成確認

↑そのdaeファイルおよび2枚のテクスチャ画像をXcodeに持ってきた。
Armature,Cylinder,Cubeの3つが同列にある。

これをSceneKit使って表示させる。
{
    SCNScene *daeScene = [SCNScene sceneNamed:@"parts.scnassets/testObject.dae"];
    [mainScene.rootNode addChildNode:daeScene.rootNode];
}
SceneKitで表示したオブジェクト

↑意図通り表示されてる。
armatureがある場合は一番トップにある、つまり一番の”親”のボーンを動かせば全体の位置や姿勢をコントロールできる。ここでは3番めの画像にあるように’PBone’という名前を付けてる。
それに対応するSCNNodeオブジェクトをpBoneNodeとすると、
{
    pBoneNode.position = _position;
    pBoneNode.orientation = _orientation;
}
ってな感じで全体を動かせる。

ボーンの位置と姿勢をセットしたオブジェクト

↑pBoneNodeの位置を(1,0,0)にして、z軸周りに+45°回転させた。ここまでは完全に意図通り動いてくれてる。


ところが、や。


このオブジェクトにシェーダを使おうとしたんよ。
-(void)applyShaderForNode:(SCNNode *)node
{
    SCNMaterial *material = node.geometry.firstMaterial;
    
    SCNProgram *program = [SCNProgram program];
    program.vertexFunctionName = @"myVertex";
    program.fragmentFunctionName = @"myFragment";
    material.program = program;
    
    SCNMaterialProperty *imageProperty = [SCNMaterialProperty materialPropertyWithContents:@"paper5.jpg"];
    [material setValue:imageProperty forKey:@"mainTexture"];
}
↑こんな感じで特別なことはやってない。よくあるサンプルコードのままだろう。

画面をクリックしたらシェーダを適用するように実装したんだが、、、

シェーダを適用したオブジェクト

シェーダ適用後、円柱は意図通り表示されているのだが、直方体の位置、姿勢がおかしい。デフォルト値というか未設定の場合の値になってるような。
そもそもオブジェクト(ここでは直方体と円柱)の位置、姿勢を設定する必要はなく、armatureの各ボーンの位置、姿勢を設定すればいい。
その関係がシェーダ(SCNProgram)を使うとはずれちゃってるってことなんだろうか???
何かの設定不足、もしくはSceneKitの不具合なのか、、、?

何かご存知の方、お教えください〜 m(._.)m



ここからはおまけ。
正しい位置、姿勢で表示されてないってことはいわゆるmodel view matrix(*1)がおかしいのか?ってことでシェーダに各マトリックスを送って表示させてみた。さっきのシェーダ適用の部分にこんなのを追加した。
{
    SCNMatrix4 mvMatrix = pBoneNode.transform;
    NSValue *mvBuffer = [NSValue valueWithSCNMatrix4:mvMatrix];
    [material setValue:mvBuffer forKey:@"mvMatrix"];


    SCNMatrix4 cameraMatrix = [self cameraMatrix];
    NSValue *cameraBuffer = [NSValue valueWithSCNMatrix4:cameraMatrix];
    [material setValue:cameraBuffer forKey:@"cameraMatrix"];


    SCNView *scnView = (SCNView *)self.view;
    SCNMatrix4 projectionMatrix = scnView.pointOfView.camera.projectionTransform;
    NSValue *projectionBuffer = [NSValue valueWithSCNMatrix4:projectionMatrix];
    [material setValue:projectionBuffer forKey:@"projectionMatrix"];
}
これを頂点シェーダで受ける。
vertex SimpleVertex myVertex(MyVertexInput in [[stage_in]],
                             constant MyNodeBuffer &scn_node [[buffer(0)]] ,
                             constant float4x4 &mvMatrix[[buffer(1)]] ,
                             constant float4x4 &cameraMatrix[[buffer(2)]] ,
                             constant float4x4 &projectionMatrix[[buffer(3)]]
                             )
{
    SimpleVertex vert;
    vert.position = projectionMatrix * cameraMatrix * mvMatrix * float4(in.position, 1.0);

}
これなら正しく表示されるだろうと思ったら、、、

各マトリックスを適用したオブジェクト

↑なっ、なんでやねん?!なんで今度は円柱がおかしいのん?しかも原点でも元の姿勢でもないし。意味不明、、、orz

(*1)文献等により表現は違うようですが、つまるところ各頂点データにたいして、位置や姿勢を考慮したマトリックスの意味(カメラは除く)


Blender 2.79
macOS High Sierra 10.13.4


追記:この件、バグレポート出しました



SCNFloorの床にオブジェクトが映らない

SCNFloorの床1

↑床(SCNFloorオブジェクト)に映るのと映らないのがある、、、
赤い立方体が床に映ってないけど、shipの方も床に接触しなかったら映らなくなったりしてた。
なんだよ、これ、、、
けどもういいわ。深入りするのはやめよう。だってSceneKitだもの。

SCNFloorの床2

↑最初のはコードで書いてたんだが素直に(?)Scene Editorで床を作成したらいけた。



macOS High Sierra 10.13.4


SCNFloorの床が逆さま?

SceneKitで物理エンジンを試そうと”床”を作ったんだ。
{
    SCNFloor *floorGeometry = [SCNFloor floor];
    SCNNode *floorNode = [SCNNode nodeWithGeometry:floorGeometry];
    floorGeometry.firstMaterial.diffuse.contents = [NSColor lightGrayColor];//—(1)
    floorNode.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeStatic shape:nil];//—(2)
    [mainScene.rootNode addChildNode:floorNode];
    
//    floorNode.orientation = rotationQuaternion;//—(3)
}
↑こんな感じで(1)床に色付けて、(2)物理エンジンで処理できるように設定。
最初(3)の回転はなしとする。

SCNFloorデフォルト

↑これで実行するとどういうわけか床に色が付かない。物理演算は期待通りには動いてるけど。

そこで(3)のようにして床をx軸周りに180度回転させた。そうすると、、、

SCNFloorを180度回転

↑床の色は見えた。やっぱりさっきは裏を見ていたのか、と思ったのだが今度は物理演算の挙動がおかしい。180度回転させたのでxz平面より上側に質量があるような挙動になってる(平面上部より立方体を落とそうとするのだが生成と同時に平面の下へ追い出されそこから自由落下する)。

まあSCNBoxとか使えばなんとかなるからいいけどさ、、、




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad