gologiusの巣

プログラミングなどの技術メモです。誰かの役に立てるとうれしいです。

メタセコイア ロボットのようなものにボーンを入れる

メタセコイアでボーンを入れてモデルを動かす際に,人なら不自然にならないように変形してほしい場合がほとんどです.

しかし,ロボットや機械などの無機物の場合には,変形してほしくない場合はどうすればよいのでしょうか.

つまり,一つのオブジェクトに一つのボーンを適用したい,一つのオブジェクトに二つ以上のボーンの影響を与えたくない場合です.

需要は非常に多いはずなのに,Webに全然それらしきことが書いていない(調べ不足かもしれませんが...)

というわけで,自分がやった方法をまとめてみました

今回使用するモデル

f:id:kamiwo_koete:20170321095623p:plain

分り易いように色を変えました.以下の説明はウェイトの色とごっちゃになってわかりづらいので,白で着色してます.

ボーンを入れる

左のコマンドパネルにボーンから.リギングタブでボーンの追加ができます.これは直観的にできるのではないでしょうか.

f:id:kamiwo_koete:20170321101649p:plain

スキン設定

動かしたいすべてのオブジェクトを選択します.

f:id:kamiwo_koete:20170321101754p:plain

スキニング,ボーン影響,正規化はどうでもいいです.変形させる際の設定なので.

スキニング

オブジェクトに各ボーンの影響度(=ウェイト)を設定していきます.肩を例に説明します.

  1. 動かしたいオブジェクトの頂点を選択
    • 例:オブジェクトshoulderの頂点をCtrl+Aなどですべて選択します
  2. 対応するボーンをボーンリストから選択
    • 例:bone1をクリック
  3. スキニング->ペイント->頂点で,全ボーンからのウェイトをクリアをクリック
    • 正規化していたり,余計な操作が入っていると,ウェイトが設定されている場合があるため
  4. スキニング->ペイント->頂点100の部分をクリック f:id:kamiwo_koete:20170321104017p:plain

これらの処理をすべての動かしたいオブジェクト,ボーンに適用します.

例の場合は,選択された頂点(=shoulder)へのbone1の影響度を100%にした,ということです.つまりbone1のみにshoulderは従う,ということです. (ここらへんの説明間違っていたら指摘お願いします.

説明動画と結果

www.youtube.com

もっといい方法あったら教えてください

参考

Metasequoia BBS

Unity ドーナツ(donuts) 描画

kamiwo-koete.hatenablog.jp

前の記事を応用して,ドーナツ型を描画します

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class Sector : MonoBehaviour
{

    public float radius = 10.0f;
    public float holeRadius = 5.0f;
    public float startDegree = 10.0f;
    public float endDegree = 170.0f;
    public int split = 5;

  
    void Start()
    {
        MeshFilter m = this.GetComponent<MeshFilter>();
        m.mesh = createMesh();
    }

    void Update()
    {

    }

    Mesh createMesh()
    {
        if(Mathf.Approximately(holeRadius , 0.0f)){
            return createSector();
        }

        return createDonuts();
    }

    Mesh createSector()
    {
        Mesh mesh = new Mesh();

        //頂点座標計算
        Vector3[] vertices = new Vector3[2 + split];
        Vector2[] uv = new Vector2[2 + split];

        vertices[0] = new Vector3(0f, 0f, 0f);
        uv[0] = new Vector2(0.5f, 0.5f);

        float deltaRad = Mathf.Deg2Rad * ((endDegree - startDegree) / (float)split);
        for (int i = 1; i < 2 + split; i++)
        {
            float x = Mathf.Cos(deltaRad * (i - 1) + (Mathf.Deg2Rad * startDegree));
            float y = Mathf.Sin(deltaRad * (i - 1) + (Mathf.Deg2Rad * startDegree));
            vertices[i] = new Vector3(
                x * radius,
                y * radius,
                0.0f);

            uv[i] = new Vector2(x * 0.5f + 0.5f, y * 0.5f + 0.5f);
        }
        mesh.vertices = vertices;
        mesh.uv = uv;

        //三角形を構成する頂点のindexを,順に設定していく
        int[] triangles = new int[3 * split];
        for (int i = 0; i < split; i++)
        {
            triangles[(i * 3)] = 0;
            triangles[(i * 3) + 1] = i + 1;
            triangles[(i * 3) + 2] = i + 2;
        }
        mesh.triangles = triangles;

        return mesh;
    }

    Mesh createDonuts()
    {
        Mesh mesh = new Mesh();

        Vector3[] vertices = new Vector3[2 + 2 * split];
        Vector2[] uv = new Vector2[2 + 2 * split];


        //頂点座標計算
        float deltaRad = Mathf.Deg2Rad * ((endDegree - startDegree) / (float)split);
        int indexOffset = vertices.Length / 2;
        for (int i = 0; i <vertices.Length/2; i++)
        {
            float x = Mathf.Cos(deltaRad * (i - 1) + (Mathf.Deg2Rad * startDegree));
            float y = Mathf.Sin(deltaRad * (i - 1) + (Mathf.Deg2Rad * startDegree));
            //外側
            vertices[i] = new Vector3(
                x * radius,
                y * radius,
                0.0f);
            //内側
            vertices[i + indexOffset] = new Vector3(
                x * holeRadius,
                y * holeRadius,
                0.0f);


            uv[i] = new Vector2(x * 0.5f + 0.5f, y * 0.5f + 0.5f);
            uv[i + indexOffset] = new Vector2(x * 0.5f * (holeRadius / radius) + 0.5f, y * 0.5f * (holeRadius / radius) + 0.5f);
        }
        mesh.vertices = vertices;
        mesh.uv = uv;

        //三角形を構成する頂点のindexを,順に設定していく
        int[] triangles = new int[6 * split];
        for (int i = 0; i < split; i++)
        {
            triangles[(i * 6) + 0] = i;
            triangles[(i * 6) + 1] = i + 1;
            triangles[(i * 6) + 2] = (i + indexOffset) + 1;

            triangles[(i * 6) + 3] = i;
            triangles[(i * 6) + 4] = (i + indexOffset) + 1;
            triangles[(i * 6) + 5] = (i + indexOffset);

        }
        mesh.triangles = triangles;

        return mesh;
    }
}

メインはcreateDonuts()のほうです. createSector()の方は前回と変わりません.

内径holeRadiusを0にすると,通常の扇形を描画します. 別に描画結果は変わりませんが,頂点数と面数が変わるので,計算コストが軽くなります.

結果

f:id:kamiwo_koete:20170319102524p:plain

Unity 扇型 描画

扇形を描画します.

ちなみにUIのゲージ等に利用したい場合は,UIのImageコンポーネント

  • ImageType -> Filled
  • Fill Meshod -> Radial 360

を利用したほうが楽です.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class Sector : MonoBehaviour
{

    public float radius = 10.0f;
    public float startDegree = 10.0f;
    public float endDegree = 170.0f;
    public int triangleNum = 5;

    void Start()
    {
        MeshFilter m = this.GetComponent<MeshFilter>();
        m.mesh = createMesh();
    }

    void Update()
    {

    }

    Mesh createMesh()
    {
        Mesh mesh = new Mesh();

        //頂点座標計算
        Vector3[] vertices = new Vector3[2 + triangleNum];
        Vector2[] uv = new Vector2[2 + triangleNum];

        vertices[0] = new Vector3(0f, 0f, 0f);
        uv[0] = new Vector2(0.5f, 0.5f);

        float deltaRad = Mathf.Deg2Rad * ((endDegree - startDegree) / (float)triangleNum);
        for (int i = 1; i < 2 + triangleNum; i++)
        {
            float x = Mathf.Cos(deltaRad * (i - 1) + (Mathf.Deg2Rad * startDegree));
            float y = Mathf.Sin(deltaRad * (i - 1) + (Mathf.Deg2Rad * startDegree));
            vertices[i] = new Vector3(
                x * radius,
                y * radius,
                0.0f);

            uv[i] = new Vector2(x * 0.5f + 0.5f, y * 0.5f + 0.5f);
        }
        mesh.vertices = vertices;
        mesh.uv = uv;

        //三角形を構成する頂点のindexを,順に設定していく
        int[] triangles = new int[3 * triangleNum];
        for (int i = 0; i < triangleNum; i++)
        {
            triangles[(i * 3)] = 0;
            triangles[(i * 3) + 1] = i + 1;
            triangles[(i * 3) + 2] = i + 2;
        }
        mesh.triangles = triangles;

        return mesh;
    }
}

UVの設定までしないとテクスチャが表示されません.

使い方は適当な空のGameObjectにこのスクリプトを追加するだけです.

実行結果は以下の通り. あと,マテリアルのシェーダーをSprites/Defaultにしておかないとテクスチャが表示されなかったので注意. f:id:kamiwo_koete:20170313004403p:plain

参考

http://www.itdadao.com/articles/c15a1049295p0.html

nanmo.hateblo.jp

Unity5.5でAndroid用にビルドする

本題ではないエラーその1

ビルドする際にこんなエラーが出た

Error building Player because scripts have compile errors in the editor

エラーがあるスクリプトがあるので直せとのこと. ただ,エラー表示が出てない. とりあえず,エディタを再起動したらエラーが出力されるようになった.

僕の場合は,外部アセットで使っていないデモ用スクリプトがエラーの原因だったので,そのまま消した.

本題ではないエラーその2

「PlayerSettings->Identification->Bundle Identifer」がデフォルトになってのでオリジナルにした.

これは初心者がよくやりそう

本題

ビルドはできたが,以下のエラーで起動できない.

your hardware does not support this application 

環境はAndroid 6.0, HTC HTV31

このエラーについては以下の通り

Failure to initialize! Your hardware does not support this application, sorry! - Unity Answers

そしてこれを参考に,PlayerSettingsの以下の図の場所をforce internalに変更する f:id:kamiwo_koete:20170305220807p:plain

そうすると動いた

OpencCV 3 &quot; Ptr&lt;FeatureDetector&gt; blobDetector = new SimpleBlobDetector(params);&quot; が使えない

OpenCVで,Circle Gridの検出などで,検出器のパラメータを変えたい場合,

answers.opencv.org

なんかを参考にすると,エラーが出た.

SimpleBlobDetector::Params params;
params.maxArea = paramMaxArea; // 100 * 100
params.minArea = paramMinArea; // 10 * 10
Ptr<FeatureDetector> blobDetector = new SimpleBlobDetector(params); //ここで引数のエラーがでる

なんでかと調べてたら,OpenCV 3以降は上記の方法ではダメみたいですね. ここに解決策がありました. c++ - opencv 3, blobdetection, The function/feature is not implemented () in detectAndCompute - Stack Overflow

Ptr<cv::SimpleBlobDetector> detector = cv::SimpleBlobDetector::create(params); 

にすればコンパイル通ります.

Python+OpenCVで動画のトリミングツールを作った

FPS(240FPSとか)のトリミングツールが欲しかったが,よさげのがパッとみつからなかったので自分で作った

 

OpenCVSample/Trimming.py at master · gologius/OpenCVSample · GitHub

 

awsdキーで全部の操作ができる.

自分用につくったのでクオリティはお察し

Python cv2.connectedComponentsWithStats

返り値で迷った.というかOpenCVのリファレンスPythonに厳しくないですか?

OpenCVSample/Labeling.py at master · gologius/OpenCVSample · GitHub

# -*- coding: utf-8 -*-

import cv2
import numpy as np


img = np.zeros((500,500,3),dtype=np.uint8)
for i in xrange(1,5):
    img = cv2.circle(img, (i*80,i*80), 5, (255,255,255), -1)     
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

labelnum, labelimg, contours, GoCs = cv2.connectedComponentsWithStats(gray)

for label in xrange(1,labelnum):
    x,y = GoCs[label]
    img = cv2.circle(img, (int(x),int(y)), 1, (0,0,255), -1)    
    
    x,y,w,h,size = contours[label]
    img = cv2.rectangle(img, (x,y), (x+w,y+h), (255,255,0), 1)    
    
    
print "label num ", labelnum 
print "contours ", contours
print "Gravity of Centers ", GoCs
cv2.imshow("img", img)
cv2.waitKey(-1)
cv2.imwrite("labeling.png",img)

f:id:kamiwo_koete:20161119214434p:plain

これでラベル数,ラベル付けされた画像,各ラベルを包括する矩形たち,各ラベルの重心がとれる. contours(包括する矩形)は最後にsize(矩形の面積,ピクセル数)が入ってるので注意. またcv2.circleに突っ込む場合,座標はtupleかつintでないと死ぬ