頭と尻尾はくれてやる!

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


ビット演算子のチルダ(~)って何やねん?

久々にMetalで描画するためにいろいろとコードを見てたりするのだが、Appleのコード(※1)に下のような面白いのがあった。
// The 256 byte aligned size of our uniform structures
static const size_t kAlignedSharedUniformsSize = (sizeof(SharedUniforms) & ~0xFF) + 0x100;
シェーダに渡すデータサイズを256バイトの倍数だといくらになるのかを計算している。
SharedUniformsという構造体(※2)のデータサイズを満たしつつ、256の倍数だといくらかを得たい。メモリの確保も必要になるので当然なるべく小さい方がいい。
構造体の中身がどんなのでもこの式でOKというものだけど、、、

なんて難解なんだ!

そんな難解な記述しなくてもええやん、と突っ込みたくなる。

なんだよ?0xFFの前の~(チルダ)は?!

調べるとビット演算でチルダはビット反転(補数を作る)なんだそうな(※3)。
0xFFは2進数だと全部1だから、その補数ってことは2進数では
…11 0000 0000
ってことか?
これとの&だから16進数で言うと下2桁をゼロにして、それより上のビットはそのままをキープできる。ここはすでに256の倍数。下2桁分は切り捨ててるようなものだから、あとで+0x100してる。
0x00との&だと上の桁までゼロにしちゃうから0xFFの補数を使ってたのか。



※1 ↓ここにも書いてるようにXcodeでプロジェクト新規作成時にARKitアプリで描画にMetal、言語にObjective-Cを選択した場合にできるコード。
SCNGeometryからMDLMeshを作成する

※2 ↓SharedUniforms はこんな構造体として定義されてる
typedef struct {
    // Camera Uniforms
    matrix_float4x4 projectionMatrix;
    matrix_float4x4 viewMatrix;
    matrix_float4x4 displayTransform;
    
    // Lighting Properties
    vector_float3 ambientLightColor;
    vector_float3 directionalLightDirection;
    vector_float3 directionalLightColor;
    float materialShininess;
} SharedUniforms;
※3 参考サイト
もう一度基礎からC言語 第19回 いろいろな演算子~ビット演算子 ビット演算子


Objective-Cでsmoothstep関数を使いたい

よくある関数らしい(?)smoothstep関数をObjective-Cで使いたくなったのだが、なさそうなので書いてみた。C++でもあるらしいけどそれだけのためにObjective-C++にするのが面倒なので。

参考サイトを見つつ書いてみたのがこんなの↓
-(float)smoothstepEdge0:(float)edge0 edge1:(float)edge1 x:(float) x
{
    x = [self clamp:(x - edge0) / (edge1 - edge0) minX:0.0 maxX:1.0];
    float r = x * x * (3 - 2 * x);
    
    return r;
}

-(float)clamp:(float)x minX:(float)minX maxX:(float)maxX
{
     return fmin(fmax(x, minX), maxX);
}

{
    // 実行してみる 
    float edge0 = 0.1;//—(1)
    float edge1 = 0.4;//—(1)

    float dX = 0.01;
    for(NSUInteger ite=0;ite<50;ite++) {
        float x = dX * (float)ite;
        float y = [self smoothstepEdge0:edge0 edge1:edge1 x:x];
        
        NSLog(@"%f %f”,x,y);
    }
}
clamp関数を使うみたいだが、なぜかclamp関数は以前に作っていた。
(1)この場合、0.1より小さいと0、0.4より大きいと1となり、その間はなめらかにつないでくれる。
0から0.5で入力xを変化させ、その時の出力yを計算してグラフ化(MacのNumbersを使用)した。

smoothstep関数のグラフ

↑スムーズにつながっている。
こんな関数でこんなグラフになるって、、、考えた人すごいよなあ。


参考サイト
c++ - Smoothstep function - Stack Overflow
smoothstep


Metalシェーダのfloat3とpacked_float3の違い

sizeof(simd_float3)=16という罠
↑ここと似たような話。ここで躓いてたので解決は早かったかもしれない。

そもそもはSCNVector3のデータ”列”をシェーダに渡したかった。1つだけではなく複数のSCNVector3を渡したい。
{
    SCNVector3 *offsets = calloc(… );//—(1)
    //(値を入れる処理)
    …

    NSData *data = [NSData dataWithBytes:offsets length:sizeof(SCNVector3)*NofVertices];
    [node.geometry.firstMaterial setValue:data forKey:@"offsets”];//—(2)
}
↑ (1)メモリ確保して、なんらかの値を入れる処理がある、とする。
(2)データ列をNSDataオブジェクトにしてそれをセットする。
ここまではよくある話。

これを頂点シェーダで受ける時に最初は下のようにして受けていた↓
…
 constant float3 *offsets [[buffer(3)]],
…
ところがこれだとなにやらおかしい。

Metal-Shading-Language-Specification
↑シェーダで使える関数とかここで見てる。
ここでfloat3について調べると、、、

リファレンスのスクショ1
↑サイズが16バイト?float3よ、お前もか、、、!
じゃあどうするの?と思って他のところを見ると

リファレンスのスクショ2
↑packed_float3というのがあってこれだと12バイトで受けてくれる。
…
//constant float3 *offsets [[buffer(3)]],
constant packed_float3 *offsets [[buffer(3)]],
uint vertexID [[vertex_id]] )
{
    float3 offset = offsets[vertexID];
    …
}
↑このように変更してSCNVector3を受け取ることができた。


simd_float4x4の作成方法

ARKitやSceneKit、Metalなどを使っているとAccelerateフレームワークのsimdなんとか、というタイプの値を使うことが多い。

floatで4x4のマトリックスを作成しようとしたのだが、
simd_make_float4x4
というのがない。
たいていはこのような形式なのでsimd_make_float...などと入力するとXcodeがそれっぽいのを

Xcodeのサジェスト内容

↑このようにサジェストしてくれるが、マトリックス作成用のが見つからない。

結局、simd_float4x4のプロパティにはcolumnsというのがあるとリファレンスで読んだので以下のようにした。
{
    simd_float4x4 matrix;

    simd_float4 c0 = simd_make_float4(+1.0000f, +1.0000f, +1.0000f, +0.0000f);
    simd_float4 c1 = simd_make_float4(+0.0000f, -0.3441f, +1.7720f, +0.0000f);
    simd_float4 c2 = simd_make_float4(+1.4020f, -0.7141f, +0.0000f, +0.0000f);
    simd_float4 c3 = simd_make_float4(-0.7010f, +0.5291f, -0.8860f, +1.0000f);
    
    matrix.columns[0] = c0;
    matrix.columns[1] = c1;
    matrix.columns[2] = c2;
    matrix.columns[3] = c3;
}



ポケモンGOのいつでも冒険モードのためにスマートウォッチを購入したが


↑Amazonの初売りセールでこのitDEALというところの"スマートウォッチ"を購入した(腕時計型万歩計という感じだが以下スマートウォッチとしておく)。

目的は「ポケモンGO」の「いつでも冒険モード」でiPhoneを持っていない時でも歩数を数えてもらうためだ。そうすれば効率的にタマゴを孵化させたり相棒がアメを集めることができる!と思ったのである。

確かこの「いつでも冒険モード」が始まった時にAppleの標準アプリであるヘルスケアアプリへのアクセス許可を設定した記憶があった。

Niantic サポート
ポケモンGOのヘルプ1

↑実際ポケGOのヘルプページにあるようにこの機能を使うにはiOSの場合、ポケGOアプリからヘルスケアアプリへのアクセスが必要となる。

なので、なんの疑いもなくiPhoneが自動的にカウントする歩数に適当な係数をかけてポケGOアプリを起動させていない間の歩いた距離を計算しているのだろうと思い、万歩計機能のあるスマートウォッチを購入したのだった。

ところが。

ポケGOアプリはスマートウォッチの歩数をカウントしない

と思う。あくまで自分が調べた範囲で、だが。

ヘルスケアアプリのスクショ

↑これはヘルスケアアプリのスクショ。iPhoneとスマートウォッチ双方の記録が確認できる(iPhoneっぽいアイコンがiPhoneで計測した歩数、アプリのアイコンのがスマートウォッチのもの)。
しかし、ポケGOアプリ内で表示される歩数の変化を眺めていると、これはiPhoneのカウントした歩数と完全に一致。スマートウォッチの数えた歩数は除外されていた。


ということはポケGOアプリは起動していない間も歩数ではなくGPSで移動距離を計測していたということになる?
試しにiOSの設定/プライバシー/位置情報サービス/ポケGOで「常に許可」→「このAppの使用中のみ許可」に変更すると、、、

ポケモンGOのスクショ

↑歩数のところが表示されなくなった。GPSで歩数を数えているわけじゃないのにややこしい表示だ。
ともかく、「いつでも冒険モード」には位置情報が必須ということなんだろう。

おそらくこれはポケGO側の仕様であり、他のスマートウォッチでも同様なのだろう。
いつでも冒険モードは、AppleWatch単体で移動距離加算されるのか【ポケモンGO】
↑ただしApple Watchはこの記事によるといけるらしい。


ポケモンGOのヘルプ2

↑よく読むと確かに常に位置情報必須とある(アンダーラインは私が追記)。


今後、ポケGOの仕様変更を期待するしかないなあ、、、



iOS 12.1.2
ポケモンGO 0.131.3




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

FC2Ad