頭と尻尾はくれてやる!

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


フロントカメラが得た画像を自分の顔のテクスチャ用にシェーダに渡したい(3)

フロントカメラが得た画像を自分の顔のテクスチャ用にシェーダに渡したい(2)
↑この続き。
次はシェーダ部分。まずは頂点シェーダから。
vertex SimpleVertex myVertex(MyVertexInput in [[stage_in]],
                             constant SCNSceneBuffer &scn_frame [[buffer(0)]] ,
                             constant MyNodeBuffer &scn_node [[buffer(1)]] ,
                             constant float4x4 &displayTransform[[buffer(2)]]
                             )
{
    float3 fixedPosition =  in.position * 1.20;//—(4)
    
    SimpleVertex vert;
    vert.position = scn_node.modelViewProjectionTransform *  float4(fixedPosition, 1.0);//—(5)


    //テクスチャ座標の計算
    float4 vertexCamera = scn_node.modelViewTransform * float4(in.position, 1.0);//—(6)
    float4 vertexClipSpace = scn_frame.projectionTransform * vertexCamera;
    vertexClipSpace /= vertexClipSpace.w;

    float4 vertexImageSpace = float4(vertexClipSpace.xy * 0.5 + 0.5, 0.0, 1.0);//—(7)
    vertexImageSpace.y = 1.0 - vertexImageSpace.y;

    float4 transformedVertex = displayTransform * vertexImageSpace;
    vert.texCoords = transformedVertex.xy;
    
    return vert;
}
↑サンプルコードのshader modifiersに記述されている内容を頂点シェーダに持ってきた。
displayTransformによる変換を行わないと画像は横向いてる。
サンプルコードにもあった顔を大きくするという処理は、(4)、(5)のようにしてフラグメントシェーダに渡せば顔の頂点は移動して顔が大きくなる。
ただし、テクスチャ画像のどこを拾うか?ということを考えると拡大による頂点移動前なので元々の座標で計算する(6)。
(7)で [-1 〜 1] → [0 〜 1] に変換してる。
fragment half4 myFragment(SimpleVertex in [[stage_in]],
                          texture2d<float, access::sample> textureY [[texture(0)]], 
                          texture2d<float, access::sample> textureCbCr [[texture(1)]]
                          )
{
    constexpr sampler colorSampler(mip_filter::linear,
                                   mag_filter::linear,
                                   min_filter::linear);
    
    const float4x4 ycbcrToRGBTransform = float4x4(
                                                  float4(+1.0000f, +1.0000f, +1.0000f, +0.0000f),
                                                  float4(+0.0000f, -0.3441f, +1.7720f, +0.0000f),
                                                  float4(+1.4020f, -0.7141f, +0.0000f, +0.0000f),
                                                  float4(-0.7010f, +0.5291f, -0.8860f, +1.0000f)
                                                  );

    float4 ycbcr = float4(textureY.sample(colorSampler, in.texCoords).r ,
                          textureCbCr.sample(colorSampler, in.texCoords).rg, 1.0);

    half4 rgb = half4(ycbcrToRGBTransform * ycbcr);

    return half4( rgb.rgb , 1);
}
↑フラグメントシェーダ部分。ほとんど公式サンプルのページ(※1)に書いてる通りだけど。
公式ではfloat4を返してて、そんなのできるの?!と驚いたのだけど確かにfloat4でも動いた。以前はhalf4を使ってたと思うのだが。惰性でhalf4にしてるけど、今のデバイスならfloat4でもOKなのでしょう。
↑頂点シェーダ内で顔の頂点をずらして遊んでみた。
追従性はさすが!なのだが、、、
なぜか顔部分が白っぽくなる。
YCbCr→RGBの変換方法がまずい?
ライティングの設定?
実はもともと白っぽいのをいい具合に変換して表示されている?
などといろいろと調べたが原因はわからない。
これじゃあ使えないな、、、😢


※1 Creating Face-Based AR Experiences | Apple Developer Documentation


スポンサーサイト

<< SceneKitで直線を描く  TopPage  フロントカメラが得た画像を自分の顔のテクスチャ用にシェーダに渡したい(2) >>

コメント


管理者にだけ表示を許可する
 

トラックバック

トラックバックURL
https://ringsbell.blog.fc2.com/tb.php/1269-985e04e2




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

FC2Ad