2012年12月16日日曜日

Windows 8にアップグレード & SSDに引っ越し

TEST用のWin7のPC、
マザボがGIGABYTEのH55M-D2H

ディスクドライブ
HDD 1TB (システム予約領域:100MB C:112GB E:416GB F:402GB)
SSD 240GB

ソフトの再インストールや設定がめんどくさい & 年末で時間がもったいないので、
Win8にアップグレード後、SSDに起動ドライブを引っ越した際の作業内容のメモ

「SSDって何?」から開始したはず

【手順】
■Win8にアップグレード
CCleanerでCドライブのごみ掃除 使用領域が60GB -> 40GBに減ったはず
アップグレードアシスタントで×印の付いたソフトをアンインストールした気がする
Windows 8のディスクをDVDドライブに入れてセットアップ
特に問題無かったはず(約1時間~2時間)

■SSDへの引っ越し
SSDを、なんとかして接続
MiniTool Partition Wizard Home Edition 7.6.1を実行
システム予約領域とCドライブをSSDにコピー後に、Applyボタンを押す
再起動後の、ブート中に HDD -> SSDにコピーされた
コピー中に経過時間の表示があった、

SSDにコピーされているのを確認したらシャットダウン
HDDのSATAの接続ケーブルを外しておく

MBRを作成
Win8をDVDからブートさせて、システムの修復を選択
コマンドプロンプトを起動させて、bootrecコマンドを使用
bootrec /fixmbr
bootrec /fixboot
bootrec /ScanOs スキャン結果が出たらアップグレードしたWindowsを選択
bootrec /RebuildBcd
exit 後 PCの電源OFF

電源ON -> SSDでブートできたらOK
電源OFF HDDのSATAケーブルを接続
電源ON BIOSでHDDのブート優先順位 SSDを上にする
"Windows の修復なんとか"が 英文から日本語に切り替わった ! ?
"修復 し よ う としています" の画面が5分くらい表示されてた

Windows 8が起動したら 窓+E でハードディスクをチェック
C, E, Fドライブが表示されて、HDDのシステム予約領域とCドライブは見えなくなっていた
SSDのシステム予約領域とCドライブを最適化しておく

以上で作業終了

一番疲れたのがSATAケーブルの抜き差し
グラボを外さないと 手が・・届かない・・ ラジオペンチで解決

EaseUS Todo Backup、EaseUS Partition Masterでコピーしても、うまくいかなかった?


SSD ガリガリ音が無いので静か、アプリの起動が早くなった気がする

2012年12月8日土曜日

Android Walkman NW-F805のテスト 1

本体の裏を見ると、下側の左上にDIGITAL MEDIA PLAYERと記載されているのが
「何コレ?」

電車内でポケットに入るサイズの端末(電話嫌いなので、携帯電話はない)で、
ソースコードを無料で見るために、1週間テストした感想ですが、

(a). 本体上部の左側にある電源ボタンが押しにくい
(b). タッチパネルの反応がおかしい 「押してないよ!」
(c). なんとなく持ちにくい 片手で操作できない
(d). iPod Touch 5thより表示面積が小さいのに重い
(e). Androidに無料で、普通に使えるテキストビューアが無い?
(f). iOSでもテキストビューア無い?

(e)が問題、文字化け、50KB程度のファイルで固まる、複数ファイルを開けない・・・
使えるアプリが無い・・・
920 Text Editor が使えそうなんだけど200KBのテキストを開くと重い
https://github.com/jecelyin/920-Text-Editor にソースがあり
落として、Eclipseでビルドして動作確認 SDKなどのUpdateがめんどくさい、
JecEditText::drawView() でテキストを描画しているみたい
jniでgrep, syntax highlight, Universal Character Set Detector C Library
うーん、どうしようかなー。

(f)もあれだ、林檎教にお布施をしないとアプリが開発できない そういえば脱獄があった
あっ、XcodeするのにMac OSがいる・・・

おっ、ダクソ2が出るーーーーー
センの古城~アノールロンド突破がおもしろかった、
360のアジア版を買って連日朝までだった気がする。

2012年12月2日日曜日

iPod touch 5thで動画再生のテスト

をしていたらフリーズしました。

■フリーズした場合 電源とホームボタンを同時に長押しすると再起動するはず

■PCに接続するとitunesが起動して何かするのをやめさる方法
編集/設定/デバイスから xxxのiPod touch を選択
「iPod、iPhone、およびiPadを自動的に同期しない」

それにしても薄い&軽い

2012年11月4日日曜日

PCL メッシュの再構築のテスト2

pcl::GreedyProjectionTriangulationのテスト

入力元の点群


フィルタリング結果


再構築結果

残念、欠けている部分がちらほらとある



pcl::GreedyProjectionTriangulationのテスト

#include <stdio.h>
#include <boost/thread/thread.hpp>
// pcl
#include <pcl/point_cloud.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>


// PCLVisualizer のテスト
void TestCloudViewer003(const char* pFilePath)
{
  // テキストファイルから頂点を取得
  FILE* fp = fopen(pFilePath, "rt");
  
  int n;
  char buf[256];
  fscanf(fp, "%s %d", buf, &n);

  int num = n;

  // 点群の作成
  pcl::PointCloud::Ptr cloud( new pcl::PointCloud );

  cloud->width = num;
  cloud->height = 1;
  cloud->points.resize( cloud->width * cloud->height );

  int txtFmt = 1;
  float x, y, z;
  for(int i = 0; i < num; i++)
  {
    switch(txtFmt) {
    case 0:
      fscanf(fp, "%f %f %f", &x, &y, &z);
      break;
    case 1:
      fscanf(fp, "%f, %f, %f", &x, &y, &z);
      break;
    }
    cloud->points[i] = pcl::PointXYZ(x, y, z);
  }
  fclose(fp);

  // 点群の削減

  // フィルタリング結果の格納用
  pcl::PointCloud::Ptr filtered_cloud( new pcl::PointCloud );

  // ボクセルグリッドで点群のフィルタリングを行う
  pcl::VoxelGrid sor;
  sor.setInputCloud (cloud);
  sor.setLeafSize(1.0f, 1.0f, 1.0f);
  sor.filter(*filtered_cloud);

  // 点群の数を出力
  printf("source cloud size = %d\n", cloud->size());
  printf("filtered cloud size = %d\n", filtered_cloud->size());

  // 元データ
  pcl::PointCloud::Ptr src_cloud = filtered_cloud;

  pcl::PolygonMesh polyMesh;

  // KdTreeを作成
  pcl::search::KdTree::Ptr tree(new pcl::search::KdTree);
  float epsilon = tree->getEpsilon();
  tree->setEpsilon(0.01f);
    tree->setInputCloud(src_cloud); 

  // 法線ベクトルの推定
  pcl::NormalEstimation ne; 
    ne.setInputCloud(src_cloud); 
    ne.setSearchMethod(tree); 
    ne.setKSearch(8);

  // 法線ベクトル格納用
  pcl::PointCloud::Ptr norm(new pcl::PointCloud); 
    ne.compute(*norm);

  // 座標と法線ベクトルの点群
  pcl::PointCloud::Ptr clPosNormal(new pcl::PointCloud);
    pcl::concatenateFields(*src_cloud, *norm, *clPosNormal); 

  // ↓今回のテスト対象
  pcl::GreedyProjectionTriangulation gpt;

  pcl::search::KdTree::Ptr tree2 (new pcl::search::KdTree);
    tree2->setInputCloud(clPosNormal); 

  // パラメータをいろいろ設定
  gpt.setSearchRadius(20.0);
  gpt.setMu(2.5);
  gpt.setMaximumNearestNeighbors (150);
//  gpt.setMaximumSurfaceAngle(M_PI/4);
//  gpt.setMinimumAngle(M_PI/18);
//  gpt.setMaximumAngle(2*M_PI/3);
//  gpt.setNormalConsistency(false);

  // 入力データ等をセット
  gpt.setInputCloud (clPosNormal);
  gpt.setSearchMethod (tree2);

  // 再構築
  gpt.reconstruct (polyMesh);

  // 点群のビューア
  pcl::visualization::PCLVisualizer viewer("Cloud Viewer");
  
  viewer.setBackgroundColor (0.0, 0.2, 0.6);

  // 原点に座標軸を追加
  viewer.addCoordinateSystem(100.0, 0.0, 0.0, 0.0);

  // カメラ座標のセット
  double camPos[] = { 0.0, 60.0, 350.0 };
  double camLookAt[] = { 0.0, 60.0, 0.0 };
  double camUp[] = { 0.0, 1.0, 0.0 };
  viewer.setCameraPose(camPos[0], camPos[1], camPos[2], 
    camLookAt[0], camLookAt[1], camLookAt[2], camUp[0], camUp[1], camUp[2]);

  // ビューアに点群を追加
//  viewer.addPointCloud(filtered_cloud);
  viewer.addPointCloud(cloud);

  // ビューアにポリゴンメッシュを追加
//  viewer.addPolygonMesh(polyMesh);

    while (!viewer.wasStopped ())
    {
    viewer.spinOnce(10);

    boost::this_thread::sleep (boost::posix_time::microseconds (100000));
    }
}

int main(int argc, char** argv)
{
  TestCloudViewer003(argv[1]);

  return 0;
}

2012年10月28日日曜日

PCL メッシュの再構築のテスト1

input cloud からポリメッシュを作成するテスト (失敗例)

入力した点群↓





実行結果が↓の画像


テスト結果 何かが変? 何だチミは?


Point Cloud Library(v1.6.0)のテスト

#include <stdio.h>
#include <boost/thread/thread.hpp>

#include <pcl/point_cloud.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/marching_cubes_hoppe.h>

// PCLVisualizer のテスト
void TestCloudViewer003(const char* pFilePath)
{
 // テキストファイルから頂点を取得
 FILE* fp = fopen(pFilePath, "rt");
 
 int n;
 char buf[256];
 fscanf(fp, "%s %d", buf, &n);

 int num = n;

 // 点群の作成
 pcl::PointCloud::Ptr cloud( new pcl::PointCloud );

 cloud->width = num;
 cloud->height = 1;
 cloud->points.resize( cloud->width * cloud->height );

 int txtFmt = 1;
 float x, y, z;
 for(int i = 0; i < num; i++)
 {
  switch(txtFmt) {
  case 0:
   fscanf(fp, "%f %f %f", &x, &y, &z);
   break;
  case 1:
   fscanf(fp, "%f, %f, %f", &x, &y, &z);
   break;
  }
  cloud->points[i] = pcl::PointXYZ(x, y, z);
 }
 fclose(fp);

 // 点群の削減

 // フィルタリング結果の格納用
 pcl::PointCloud::Ptr filtered_cloud( new pcl::PointCloud );

 // ボクセルグリッドで点群のフィルタリングを行う
 pcl::VoxelGrid sor;
 sor.setInputCloud (cloud);
 sor.setLeafSize(1.0f, 1.0f, 1.0f);
 sor.filter(*filtered_cloud);

 // 点群の数を出力
 printf("source cloud size = %d\n", cloud->size());
 printf("filtered cloud size = %d\n", filtered_cloud->size());

 // 元データ
 pcl::PointCloud::Ptr src_cloud = filtered_cloud;

 pcl::PolygonMesh polyMesh;

 // KdTreeを作成
 pcl::search::KdTree::Ptr tree(new pcl::search::KdTree);
 float epsilon = tree->getEpsilon();
 tree->setEpsilon(0.01f);
    tree->setInputCloud(src_cloud); 

 // 法線ベクトルの推定
 pcl::NormalEstimation ne; 
    ne.setInputCloud(src_cloud); 
    ne.setSearchMethod(tree); 
    ne.setKSearch(8);

 // 法線ベクトル格納用
 pcl::PointCloud::Ptr norm(new pcl::PointCloud); 
    ne.compute(*norm);

 // 座標と法線ベクトルの点群
 pcl::PointCloud::Ptr clPosNormal(new pcl::PointCloud);
    pcl::concatenateFields(*src_cloud, *norm, *clPosNormal); 


 // ↓今回のテスト対象
 pcl::MarchingCubesHoppe mc;  

 pcl::search::KdTree::Ptr tree2 (new pcl::search::KdTree);
    tree2->setInputCloud(clPosNormal); 

 mc.setSearchMethod(tree2); 
 mc.setInputCloud(clPosNormal); 
 mc.setIsoLevel(0.0015); // 0.0 ~ 1.0
 mc.setGridResolution(50, 50, 50); 

 // 再構築
 mc.reconstruct(polyMesh); 


 // 点群のビューア
 pcl::visualization::PCLVisualizer viewer("Cloud Viewer");
 
 viewer.setBackgroundColor (0.0, 0.2, 0.6);

 // 原点に座標軸を追加
 viewer.addCoordinateSystem(100.0, 0.0, 0.0, 0.0);

 // カメラ座標のセット
 double camPos[] = { 0.0, 60.0, 350.0 };
 double camLookAt[] = { 0.0, 60.0, 0.0 };
 double camUp[] = { 0.0, 1.0, 0.0 };
 viewer.setCameraPose(camPos[0], camPos[1], camPos[2], 
  camLookAt[0], camLookAt[1], camLookAt[2], camUp[0], camUp[1], camUp[2]);

 // ビューアに点群を追加
 viewer.addPointCloud(filtered_cloud);
// viewer.addPointCloud(cloud);

 // ビューアにポリゴンメッシュを追加
 viewer.addPolygonMesh(polyMesh);

    while (!viewer.wasStopped ())
    {
  viewer.spinOnce(10);

  boost::this_thread::sleep (boost::posix_time::microseconds (100000));
    }
}

int main(int argc, char** argv)
{
    TestCloudViewer003(argv[1]);

    return 0;
}

2012年9月17日月曜日

C# TextFieldParser

参照設定にMicrosoft.VisualBasicを追加


TextFieldParserのテスト

using Microsoft.VisualBasic.FileIO;

public void TestTextFieldParser(String path)
{
    System.Text.Encoding enc = System.Text.Encoding.GetEncoding("shift_jis");
    
    TextFieldParser parser = new TextFieldParser(path, enc);

    // タブ区切り
    parser.SetDelimiters("\t");
    
    // コメントのトークンをセット
    parser.CommentTokens = new String[] { "//", "'" };

    // データの終わりまで処理する
    while(parser.EndOfData != true)
    {
        // 現在の行を処理して次の行に進める
        string[] splittedResult = parser.ReadFields();

        // 行数を取得
        long lineNum = parser.LineNumber;

        //出力ウィンドウに出力
        foreach (string output in splittedResult) {
            if(output.Length > 0) {
                System.Diagnostics.Debug.Print(output);
            }
        }
    }
}

2012年6月24日日曜日

C++/CLI テキストの置換

main.cpp

using namespace System;

// テキストファイルを開いて文字列置換を行うテスト
void ReplaceText(String^ path, String^ strOld, String^ strNew)
{
  if (!IO::File::Exists(path)) return;

  Text::Encoding^ enc = Text::Encoding::GetEncoding("shift_jis");

  // テキストファイルの読み込み
  IO::StreamReader^ sr = gcnew IO::StreamReader(path, enc);
  String^ textInput = sr->ReadToEnd();
  sr->Close();

  // 置換する
  String^ textOutput = textInput->Replace(strOld, strNew);

  // テキストファイルの書き込み
  IO::StreamWriter^ sw = gcnew IO::StreamWriter(path, false, enc);
  sw->Write(textOutput);
  sw->Close();
}

int main(array ^args)
{
  if(args->Length == 3) {
    ReplaceText(args[0], args[1], args[2]);
  }
    return 0;
}

2012年5月27日日曜日

MAXScript 文字列 コピー 置換

オブジェクト名に禁則文字が含まれていたので、エクスポート時に _で置換

文字列のコピーと置換のテスト


-- name に禁則文字 があったら rCh で置換する
fn ReplaceProhibitChar name rCh = (
  -- 禁則文字 仮
  prohibit = "\\/:,;*?\"<>|"

  -- 名前をコピーする
  newName = copy name
  
  -- 禁則文字を rCh に置換
  for j = 1 to prohibit.count do (
    for i = 1 to newName.count do (
      if prohibit[j] == newName[i] do (
        newName[i] = rCh
      )
    )
  )
  
  format "oldName %\n" name
  format "newName %\n" newName
  
  newName
)

str1 = ReplaceProhibitChar "aaa:0" "_"

2012年4月30日月曜日

Bullet 衝突回数のカウント

衝突回数をカウントして、剛体を削除するテスト bullet-2.79

main.cpp

#include <crtdbg.h>
#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>

#ifdef _DEBUG
#pragma comment(lib, "BulletCollision_debug.lib")
#pragma comment(lib, "BulletDynamics_debug.lib")
#pragma comment(lib, "LinearMath_debug.lib")
#else
#pragma comment(lib, "BulletCollision.lib")
#pragma comment(lib, "BulletDynamics.lib")
#pragma comment(lib, "LinearMath.lib")
#endif

// ↓コンタクトのコールバック
extern ContactProcessedCallback gContactProcessedCallback;

struct TestData {
  int count; // 衝突回数
  TestData() : count(0) {}
};

class TestBullet {
  btDiscreteDynamicsWorld*        m_pWorld;
  btVector3 m_vWorldSize;

    btDefaultCollisionConfiguration     m_config;
    btCollisionDispatcher         m_dispatcher;
    btAxisSweep3              m_broadphase;
    btSequentialImpulseConstraintSolver   m_solver;
  btAlignedObjectArray<btCollisionShape*> m_collisionShapes;

  btRigidBody*  m_Body1;
  TestData    m_BodyData1;
public:
  TestBullet() :
    m_dispatcher(&m_config),
    m_vWorldSize(1000.0f, 1000.0f, 1000.0f),
    m_broadphase(m_vWorldSize * -0.5f, m_vWorldSize * 0.5f, 1024),
    m_pWorld(0), m_Body1(0)
  {}
  ~TestBullet();

  void Init();
  void Update();
  void DeleteBody(btRigidBody** pBody);
  static bool HandleContactProcess(btManifoldPoint& p, void* a, void* b);
};

TestBullet::~TestBullet() {
  for (int i = m_pWorld->getNumCollisionObjects() - 1; i >= 0 ; i--) {
    btCollisionObject* obj = m_pWorld->getCollisionObjectArray()[i];
    btRigidBody* body = btRigidBody::upcast(obj);
    DeleteBody(&body);
  }
  for (int j = 0; j < m_collisionShapes.size(); j++) {
    btCollisionShape* shape = m_collisionShapes[j];
    m_collisionShapes[j] = 0;
    delete shape;
  }
  delete m_pWorld;
}

void TestBullet::Init() {
  m_pWorld = new btDiscreteDynamicsWorld(&m_dispatcher, &m_broadphase, &m_solver, &m_config);
  m_pWorld->setGravity(btVector3(0.0f, -9.8f * 1.0f, 0.0f));
  m_pWorld->getSolverInfo().m_numIterations = 2;

  // 地面の形状
  btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));
  m_collisionShapes.push_back(groundShape);

  btTransform groundTransform;
  groundTransform.setIdentity();
  groundTransform.setOrigin(btVector3(0.0f, -50.0f, 0.0f));

  // 地面の作成
  btScalar mass(0.0f);
  bool isDynamic = (mass != 0.f);

  btVector3 localInertia(0,0,0);
  if (isDynamic) groundShape->calculateLocalInertia(mass, localInertia);

  btDefaultMotionState* myMotionState = new btDefaultMotionState( groundTransform );
  btRigidBody::btRigidBodyConstructionInfo rbInfo0(mass, myMotionState, groundShape, localInertia);

  btRigidBody* pGroundBody = new btRigidBody(rbInfo0);
  m_pWorld->addRigidBody(pGroundBody);


  // 削除テスト用の剛体の作成
  btCollisionShape* colShape = new btSphereShape( 2.0f );
  m_collisionShapes.push_back(colShape);

  btTransform startTransform;
  startTransform.setIdentity();

  mass  = 100.0f;
  isDynamic = (mass != 0.f);
  if (isDynamic)  colShape->calculateLocalInertia(mass, localInertia);

  startTransform.setOrigin(btVector3(2, 5, 0));

  myMotionState = new btDefaultMotionState(startTransform);
  btRigidBody::btRigidBodyConstructionInfo rbInfo1(mass, myMotionState, colShape, localInertia);

  m_Body1 = new btRigidBody(rbInfo1);
  m_Body1->setUserPointer(&m_BodyData1);  // ユーザーデータをセット
  m_pWorld->addRigidBody(m_Body1);
}

void TestBullet::Update() {
  const btScalar dt = 1.0f / 30.0f;
  m_pWorld->stepSimulation(dt);

  btTransform trans;
  for (int i = m_pWorld->getNumCollisionObjects() - 1; i >= 0; i--) {
    btCollisionObject* obj = m_pWorld->getCollisionObjectArray()[i];
    btRigidBody* body = btRigidBody::upcast(obj);

    if(body && !body->isStaticObject()) {
      body->getMotionState()->getWorldTransform(trans);
      btVector3& pos = trans.getOrigin();

      printf("%f, %f, %f\n", pos.getX(), pos.getY(), pos.getZ());
    }
  }
  if(m_Body1 != NULL && m_BodyData1.count > 6) {
    DeleteBody(&m_Body1); // 削除テスト
  }
}

void TestBullet::DeleteBody(btRigidBody** ppBody) {
  btRigidBody* pBody = *ppBody;
  m_pWorld->removeRigidBody( pBody );
  btMotionState* pMotionState = pBody->getMotionState();
  if(pMotionState) {
    delete pMotionState;
  }
  delete pBody;
  *ppBody = NULL;
}

bool TestBullet::HandleContactProcess(btManifoldPoint& p, void* a, void* b) {
  btRigidBody* pBody0 = (btRigidBody*)a;
  btRigidBody* pBody1 = (btRigidBody*)b;

  TestData* pUserData0 = (TestData*)pBody0->getUserPointer();
  TestData* pUserData1 = (TestData*)pBody1->getUserPointer();

  // カウント
  if(pUserData0) pUserData0->count++;
  if(pUserData1) pUserData1->count++;
  return true;
}

int main() {
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
  TestBullet test;
  test.Init();
  // 衝突のコールバック関数をセット
  gContactProcessedCallback = TestBullet::HandleContactProcess;

  for (int i = 0; i < 100; i++) {
    test.Update();
  }
  return 0;
}

2012年4月29日日曜日

dcollide Kdopのテスト

K-DOP (K discrete oriented polytope)

main.cpp

#define _USE_MATH_DEFINES
#include <d-collide/dcollide.h>
#include <d-collide/proxyfactory.h>
#include <d-collide/math/vector.h>
#include <d-collide/shapes/mesh/meshfactory.h>

int main()
{
  // ワールド
  dcollide::World world;

  // プロキシファクトリを取得
  dcollide::ProxyFactory* pPf = world.getProxyFactory();

  // プロキシを作成
  dcollide::Proxy* pProxy = pPf->createProxy();

  // メッシュの頂点
  dcollide::Vertex vtx_array[] = {
    dcollide::Vertex(0, 10.18f, 0),
    dcollide::Vertex(-10, 0, -10),
    dcollide::Vertex( 10, 0, -10),
    dcollide::Vertex(-10, 0,  10),
    dcollide::Vertex( 10, 0,  10),
  };

  std::vector vertices;
  vertices.push_back( &vtx_array[0] );
  vertices.push_back( &vtx_array[1] );
  vertices.push_back( &vtx_array[2] );
  vertices.push_back( &vtx_array[3] );
  vertices.push_back( &vtx_array[4] );

  // メッシュのインデックス
  std::vector indices;
  indices.push_back(1); indices.push_back(2); indices.push_back(0);
  indices.push_back(3); indices.push_back(4); indices.push_back(0);

  // メッシュ
  dcollide::Mesh mesh(vertices, indices);
  mesh.setProxy( pProxy );

  // メッシュファクトリ
  dcollide::MeshFactory mf;

  // メッシュファクトリから球のメッシュを作成
  dcollide::Mesh* pSphereMesh = mf.createSphere(4.56f, 5.0f);
  pSphereMesh->setProxy( pProxy );

  // kdopのk
  int k = 6;    // 6:AABB 14, 18, 26
  // kdop
  dcollide::Kdop kdop(k);
  kdop.adjustToShape(&mesh);    // プロキシが無いとerror
//  kdop.adjustToShape(pSphereMesh);

  // AABB
  dcollide::Vector3 vMin =  kdop.getSurroundingAabbMin();
  dcollide::Vector3 vMax = kdop.getSurroundingAabbMax();
 
  printf("k = %d\n", k);
  for(int i = 0; i < k; ++i) 
  {
    // 原点から平面までの距離
    dcollide::real dist = kdop.getDistanceOfPlaneToOrigin(i);
    // 平面の法線ベクトル
    dcollide::Vector3 vN = kdop.getPlaneNormal(i);
    printf("%d [%f %f %f %f]\n", i, vN.getX(), vN.getY(), vN.getZ(), dist);
  }
  return 0;
}

2012年4月28日土曜日

MAXScript テキストファイルに書き出す

シーン内で使用しているテクスチャ画像の絶対パスをファイルに書き出す テスト

WriteDiffuseTexFilePath.ms

-- マテリアルのDiffuseテクスチャ画像の絶対パスをファイルに出力
fn WriteMtlInfo fs mtl = (
  d = mtl.DiffuseMap
  if undefined == d do return -2
  
  bm = d.bitmap
  if undefined == bm do return -3
  
  filePath = d.fileName
  
  -- ファイルの絶対パスを取得
  FileResolutionManager.getFullFilePath &filePath #Bitmap

  -- ¥ を /に変換
  strArray = filterString filePath "¥¥"
  filePath = ""
  for i = 1 to strArray.count do (
    filePath += strArray[i]
    if i < strArray.count do (
      filePath += "/"
    )
  )
  -- 画像の幅、高さ
  w = bm.width
  h = bm.height
  format "%¥n" filePath to:fs -- 絶対パスをファイルに出力
)

-- シーン内のマテリアル情報の取得
fn WriteDiffuseTexFilePath fileName = (
  if 0 == sceneMaterials.count do (
    format "sceneMaterials.count is 0¥n"
    return -1
  )

  -- ファイル出力先のディレクトリ
  fPath =  GetDir #export
  fPath += "¥¥" + fileName

  -- ファイルオープン
  fs = openFile fPath mode:"wt"
  if undefined  == fs do return -1
  
  for i = 1 to sceneMaterials.count do (
    mtl = sceneMaterials[ i ]   -- マテリアルを取得
    c = classof mtl     -- マテリアルのクラス名を取得

    if c == Standardmaterial do (
      WriteMtlInfo fs mtl
    )
    if c == Multimaterial do (
      nSubMtl = getNumSubMtls mtl -- マテリアルのサブマテリアル数を取得
      for j = 1 to nSubMtl do (
        subMtl = getSubMtl mtl j
        WriteMtlInfo fs subMtl
      )
    )
  )
  -- ファイルクローズ
  close fs  
)
-- exportフォルダにTexFilePath.txtが作成される
WriteDiffuseTexFilePath "TexFilePath.txt"

Win32++ (1) ボタン

main.cpp

// ボタンのテスト
#include <stdcontrols.h>
#include <controls.h>
#include <cstring.h>
#pragma comment(lib, "comctl32.lib")

// メッセージ
#define MY_MSG_001  (WM_APP + 1)

// ボタン
class MyButton : public CButton {
protected:
  int   m_nID;
public:
  MyButton(int id) : m_nID(id), CButton() {}
  virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam) {
    switch (HIWORD(wParam)) {
    case BN_CLICKED:
      {
        CWnd* pParent = this->GetParent();
        if(pParent) {
          this->SendMessage(pParent->GetHwnd(), MY_MSG_001, m_nID, 0);
        }
      }
      return TRUE;
    }
    return FALSE;
  }
};

// ビュー
class CView : public CWnd {
public:
  CView()       {}
  virtual ~CView()  {
    delete m_pButton1;
    delete m_pButton2;
  }

  virtual void OnCreate() {
    // ボタンを作成
    m_pButton1 = new MyButton(1);
    m_pButton1->Create(this);
    m_pButton1->MoveWindow(10, 10, 100, 24);
    m_pButton1->SetWindowTextW(L"ボタン1");

    m_pButton2 = new MyButton(2);
    m_pButton2->Create(this);
    m_pButton2->MoveWindow(10, 50, 100, 24);
    m_pButton2->SetWindowTextW(L"ボタン2");
  }
protected:
  virtual LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);

  MyButton* m_pButton1;
  MyButton* m_pButton2;
};

LRESULT CView::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) {
  CString str;

  switch (uMsg) {
  case MY_MSG_001:
    str.Format(L"%d %d\n", uMsg, wParam);
    TRACE(str);
    break;
  case WM_DESTROY:
    m_pButton1->Destroy();
    m_pButton2->Destroy();
    ::PostQuitMessage(0);
    break;
  }
  return WndProcDefault(uMsg, wParam, lParam);
}

class MyApp : public CWinApp {
public:
  MyApp() {}
    virtual ~MyApp() {}
  virtual BOOL InitInstance() {
    m_View.Create();
    return TRUE;
  }
private:
    CView m_View;
};

int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int) 
{
    MyApp MyApp;
    return MyApp.Run();
}

2012年4月27日金曜日

OpenCV 画像の90度回転

テキストをパースして、複数の画像を1枚にまとめてみる テスト

パース処理にboostのtokenizerを使用

貼り付ける画像が、貼り付け先の画像からはみ出るとエラーになるよ


テキストファイルの例

2                     <-- 貼り付ける画像数
1024 512              <-- 貼り付け先の画像の幅, 高さ
c:/temp/test1.bmp"    <-- 画像の絶対パス
0 0 0 200 200 0       <-- [画像のインデックス] [X座標] [Y座標] [幅] [高さ] [※回転]
c:/temp/test2.bmp"
1 210 0 32 128 1

main.cpp

#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

// 貼り付ける画像情報
struct ImageInfo {
  std::string   path;   // ファイルの絶対パス
  int       param[6]; // パラメータ
};

// src_imgをdst_imgのrect領域にコピー
void MatCopyPaste(const cv::Rect& rect, cv::Mat& dst_img, cv::Mat& src_img) {
  cv::Mat d = dst_img(rect);    // 貼り付け先のMatを取得
  src_img.copyTo(d);        // 貼り付け画像をコピーする
}

// 1画像の処理
void ImageProc(cv::Mat& dst_img, const ImageInfo& info) {
  // 貼り付ける画像を読み込む
  cv::Mat src_img = cv::imread(info.path, 1);
  assert(!src_img.empty());

  // 貼り付け先の画像のサイズ
  int imgWidth = info.param[3];
  int imgHeight = info.param[4];
  // 貼り付け位置
  int imgX = info.param[1];
  int imgY = info.param[2];

  // 貼り付け画像
  cv::Mat tmp_img(cv::Size(imgWidth, imgHeight), src_img.type());

  if(info.param[5] == 1) {
    // 画像を回転
    int src_w = src_img.size().width;
    int src_h = src_img.size().height;
    
    cv::Mat rot_img(cv::Size(src_h, src_w), src_img.type(), cv::Scalar(0, 0, 0));
    cv::transpose(src_img, rot_img);  // 転置 左回り 反時計回りに90度回転 
    cv::flip(rot_img, rot_img, 1);    // 左右反転 時計回りに90度回転

    cv::resize(rot_img, tmp_img, tmp_img.size(), cv::INTER_CUBIC);
  } else {
    // サイズ変更
    cv::resize(src_img, tmp_img, tmp_img.size(), cv::INTER_CUBIC);
  }

  // 指定した矩形に画像を貼り付ける
  cv::Rect rect(imgX, imgY, imgWidth, imgHeight); 
  MatCopyPaste(rect, dst_img, tmp_img);
}

int main( int argc, char **argv ) {
  int count = 0;
  std::string str;
  // 貼り付ける画像を記述したテキストファイルを読み込む
  std::ifstream ifs( "./data/ImgList.txt" );

  typedef boost::char_separator char_sep;
  typedef boost::tokenizer tokenizer;
  char_sep sep(" ");    // スペース区切り

  int imgNum, imgWidth, imgHeight;
  std::vector  imgDataArray;
  ImageInfo imgData;

  while(std::getline(ifs, str)) {
    std::vector tokenArray;

    // 読み込んだ文字列をトークンに分割して配列に格納
    tokenizer tok(str, sep);
    for (tokenizer::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) {
      tokenArray.push_back( *tok_iter );
    }

    switch(count) {
    case 0:  // 画像数
      // int にキャスト
      imgNum = boost::lexical_cast(tokenArray[0]);
      break;
    case 1:  // 画像の幅と高さ
      imgWidth = boost::lexical_cast(tokenArray[0]);
      imgHeight = boost::lexical_cast(tokenArray[1]);
      break;
    default: // 画像のパラメータ
      if(0 == count % 2) {
        // ファイルパス
        imgData.path = tokenArray[0];
      } else {
        // パラメータ
        for(int i = 0; i < 6; i++) {
          imgData.param[i] = boost::lexical_cast(tokenArray[i]);
        }
        imgDataArray.push_back(imgData);
      }
      break;
    }
    count++;
  }

  // 貼り付け先の画像
  cv::Mat dstImg(cv::Size(imgWidth, imgHeight), CV_8UC3, cv::Scalar(0, 0, 0));

  // 画像処理
  for(size_t i = 0; i < imgDataArray.size(); i++) {
    ImageProc(dstImg, imgDataArray[i]);
  }

  // 結果を保存
//  cv::imwrite("./data/result.png", dstImg);

  // 結果を表示
  cv::namedWindow("Result", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  cv::imshow("Result", dstImg);
  cv::waitKey(0);
  return 0;
}

2012年4月23日月曜日

MAXScript マテリアル毎にノードをまとめる

FBXをインポートしてみたら、ノード数が多いので

sceneMaterialsを使って、マテリアル毎にまとめるテスト

MergeNodeTest.ms

g_NodeNameArray = #() -- シーン中のノード名の配列

-- 再帰関数でノードを列挙する
fn EnumNode n =
(
  for n in n.children do
  (
    -- 配列にノード名を追加
    append g_NodeNameArray n.name
    -- 再帰処理
    EnumNode n
  )
)

-- 文字列の配列から一致する文字列のインデックスを取得
fn GetNameIndex strArray str = (
  for i = 1 to strArray.count do (
    if strArray[i] == str do (  
      return i
    )
  )
  -1  -- 一致する文字列が無い
)

-- マテリアル毎にノードをまとめるテスト
fn MergeNodePerStdMtl = (
  -- シーン内のノード数
  format "Scene Node Num = %\n" g_NodeNameArray.count
  
  -- シーン内のマテリアル数を出力
  format "sceneMaterials.count %\n" sceneMaterials.count
  
  -- シーン内のスタンダードマテリアル名の配列
  strStdMtlNameArray = #()
  
  for mtl in sceneMaterials do (
    -- マテリアルのクラス名を取得
    c = classof mtl
--    format "mtl.name = % class = %\n" mtl.name c

    if c == Standardmaterial do (
      -- スタンダードなマテリアル名を追加
      append strStdMtlNameArray mtl.name  
    )
    
    if c == Multimaterial do (
      nSubMtl = getNumSubMtls mtl
--      format "nSubMtl = %\n" nSubMtl    -- サブマテリアル数
    )
  )
  
  -- strStdMtlNameArrayが空なので抜ける
  if strStdMtlNameArray.count == 0 do return 1

  -- スタンダードマテリアルを使用するノードの配列を作成
  stdMtlNodeArray = #()
  stdMtlNodeArray.count = strStdMtlNameArray.count
  
  -- シーン内のノードをスタンダードマテリアル毎にマージする
  for i = 1 to g_NodeNameArray.count do (
    -- ノードを名前から取得
    n = getNodeByName g_NodeNameArray[i]
    if undefined == n do continue
    
    -- ノードのマテリアルを取得
    mtl = n.material
    if undefined == mtl do continue
    
    c = classof mtl -- マテリアルのクラス
    if c == Standardmaterial do (
      -- 配列のインデックスを取得
      idx = GetNameIndex strStdMtlNameArray mtl.name
      if -1 == idx do continue
      
      if undefined == stdMtlNodeArray[ idx ] then (
        -- 空なので、ノードをセット
        stdMtlNodeArray[idx] = n
      )
      else (
        -- ノードをマージする
        stdMtlNodeArray[idx] = stdMtlNodeArray[idx] + n
        -- マージしたノードは削除
        delete n
      )
    )
  )
)

rn = rootNode       -- ルートノードを取得する
EnumNode rn         -- シーン内のノードを列挙
MergeNodePerStdMtl()  -- スタンダードなマテリアル毎にノードをマージ

2012年4月21日土曜日

Unity アニメーションイベント

マテリアルのシェーダーは Transparent/Diffuse を使用

TestGL2_b.cs

using UnityEngine;
//using System.Collections;
 
//[RequireComponent(typeof(Animation))]
public class TestGL2_b : MonoBehaviour {
    Vector3[]       m_VtxArray;                 // 頂点の配列
    Vector2[]       m_UvArray;                  // UVの配列
    Vector2         m_uvOffset = Vector2.zero;  // UVのオフセット

    public Material m_Mtl;                      // マテリアル

    AnimationCurve  m_animCurve;                // アニメカーブ

    AnimationEvent  m_animEvtStart;             // 開始イベント
    AnimationEvent  m_animEvtEnd;               // 終了イベント

    AnimationClip   m_animClip;                 // アニメクリップ
    string          m_animName = "anim1";       // アニメ名

    int             m_loopCount = 0;            // ループ回数

    public void Start () {
        // アニメコンポーネントを追加
        Animation anim = GetComponent();
        if(null == anim) anim = gameObject.AddComponent();
        
        // 頂点とUVの作成
        m_VtxArray = new Vector3[4];
        m_UvArray = new Vector2[4];

        m_VtxArray[0] = new Vector3(0.0f, 0.0f, 0.0f);  // BottomLeft
        m_VtxArray[1] = new Vector3(0.0f, 1.0f, 0.0f);  // TopLeft
        m_VtxArray[2] = new Vector3(1.0f, 0.85f, 0.0f); // TopRight
        m_VtxArray[3] = new Vector3(1.0f, 0.0f, 0.0f);  // BottomRight

        m_UvArray[0] = new Vector2(0.0f, 0.0f);
        m_UvArray[1] = new Vector2(0.0f, 1.0f);
        m_UvArray[2] = new Vector2(1.0f, 1.0f);
        m_UvArray[3] = new Vector2(1.0f, 0.0f);

        CreateAnim();
    }

    void OnRenderObject() {
        // フェードイン、アウトをループさせるテスト
        // マテリアルの色変更
        Color color = m_Mtl.GetColor("_Color");
        // アニメの時間取得
        float time = animation[m_animName].time;    // アニメーションの経過時間になる
        
        time -= m_loopCount * animation[m_animName].length;
        // アニメカーブの値を取得
        float value = m_animCurve.Evaluate(time);
        color.a = value;

        // マテリアルの色セット
        m_Mtl.SetColor("_Color", color);

        // 四角形を描画
        DrawQuad();
    }

    // アニメーションを作成
    void CreateAnim() {
        float startTime = 0.0f;
        float endTime = 5.0f;
        float midTime = (endTime - startTime) * 0.5f;

        // アニメカーブを作成
        m_animCurve = new AnimationCurve();

        // アルファ値のキーフレームを追加
        m_animCurve.AddKey( new Keyframe(startTime, 0.0f) );
        m_animCurve.AddKey( new Keyframe(midTime, 1.0f) );
        m_animCurve.AddKey( new Keyframe(endTime, 0.0f) );

        // アニメーションクリップを作成
        m_animClip = new AnimationClip();
        m_animClip.wrapMode = WrapMode.Loop;
        m_animClip.SetCurve("", typeof(Material), "_Color.a", m_animCurve);

        // アニメーションイベントを作成
        m_animEvtStart = new AnimationEvent();
        m_animEvtStart.time = startTime;
        m_animEvtStart.intParameter = 987;
        m_animEvtStart.stringParameter = "start";
        m_animEvtStart.functionName = "AnimEventStart";

        m_animEvtEnd = new AnimationEvent();
        m_animEvtEnd.time = endTime;
        m_animEvtEnd.intParameter = 123;
        m_animEvtEnd.stringParameter = "end";
        m_animEvtEnd.functionName = "AnimEventEnd";

        // クリップにイベントを追加
        m_animClip.AddEvent(m_animEvtStart);
        m_animClip.AddEvent(m_animEvtEnd);

        // アニメーションにクリップを追加
        animation.AddClip(m_animClip, m_animName);
        // アニメーションの再生開始
        animation.Play(m_animName);
    }

    // パラメータ数は 0個か1個 2個だと実行時にエラー
    void AnimEventStart(string s) {
        print("AnimEventStart() " + s);
    }

    void AnimEventEnd(string s) {
        m_loopCount++;
        print("AnimEventEnd() " + s);
    }

    void DrawQuad() {
        m_Mtl.SetPass(0);

        GL.PushMatrix();
        GL.LoadOrtho();
        // 左下が 0, 0, 0
        GL.Begin(GL.QUADS);
        for(int i = 0; i < 4; i++) {
            GL.TexCoord(m_UvArray[i] + m_uvOffset);
            GL.Vertex(m_VtxArray[i]);
        }
        GL.End();
        GL.PopMatrix();
        m_uvOffset.x -= 0.001f;
        m_uvOffset.y -= 0.001f;
    }
}

Unity GL (2) 四角形の描画

TestGL2.cs

using UnityEngine;
 
public class TestGL2 : MonoBehaviour {
    Vector3[]       m_VtxArray;                 // 頂点の配列
    Vector2[]       m_UvArray;                  // UVの配列
    Vector2         m_uvOffset = Vector2.zero;  // UVのオフセット

    public Material m_Mtl;                      // 使用するマテリアル

    public void Start () {
        // 頂点とUVの作成
        m_VtxArray = new Vector3[4];
        m_UvArray = new Vector2[4];

        // 時計回りだと描画される?
        m_VtxArray[0] = new Vector3(0.25f, 0.25f, 0.0f); // BottomLeft
        m_VtxArray[1] = new Vector3(0.25f, 0.95f, 0.0f); // TopLeft
        m_VtxArray[2] = new Vector3(0.75f, 0.75f, 0.0f); // TopRight
        m_VtxArray[3] = new Vector3(0.75f, 0.25f, 0.0f); // BottomRight

        m_UvArray[0] = new Vector2(0.0f, 0.0f);
        m_UvArray[1] = new Vector2(0.0f, 1.0f);
        m_UvArray[2] = new Vector2(1.0f, 1.0f);
        m_UvArray[3] = new Vector2(1.0f, 0.0f);
    }

    void OnRenderObject() {
        DrawQuad();
    }

    void DrawQuad() {
        m_Mtl.SetPass(0);

        GL.PushMatrix();
        GL.LoadOrtho();         // 正射影 左下が 0, 0, 0
        //GL.LoadIdentity();
        //GL.LoadProjectionMatrix(Matrix4x4.identity);
        
        GL.Begin(GL.QUADS);
#if false
        // 反時計回り 描画されない
        for(int i = 3; i >= 0; i--) {
            GL.TexCoord(m_UvArray[i] + m_uvOffset);
            GL.Vertex(m_VtxArray[i]);
        }
#else
        // 時計回り 描画された 
        for(int i = 0; i < 4; i++) {
            GL.TexCoord(m_UvArray[i] + m_uvOffset);
            GL.Vertex(m_VtxArray[i]);
        }
#endif
        GL.End();
        GL.PopMatrix();

        m_uvOffset.x -= 0.001f;
        m_uvOffset.y -= 0.001f;
    }
}

2012年4月12日木曜日

Unity GL (1) ライン描画

GL.LINESでライン描画

空オブジェクトにスクリプトを追加、インスペクター上で、描画するメッシュを選択

TestGL1.cs

using UnityEngine;
 
public class TestGL1 : MonoBehaviour {
    Material        m_Material;                 // マテリアル
    Vector3[]       m_lineVtxArray;             // ライン描画用の頂点の配列
    public Color    m_lineColor = Color.blue;   // 描画色
    public Mesh     m_Mesh;                     // メッシュ

    public void Start () {
        CreateMaterial();
        CreateVtxArray();
    }

    void OnRenderObject() {
        DrawLine();
    }

    // OnPostRender カメラにスクリプトをアタッチすると呼ばれた
    void OnPostRender() {
//        print("OnPostRender");
    }

    // マテリアルを作成
    void CreateMaterial() {
        m_Material = new Material( "Shader \"Lines/Color\" {" +
            "SubShader {" +
            "    Pass { " +
            "       Blend SrcAlpha OneMinusSrcAlpha" +  // αブレンド
//          "       Blend Off" +        // ブレンド オフ
            "       Cull Off" +         // カリング オフ
            "       ZWrite Off" +       // Z値の書き込み オフ
//          "       ZTest Always" +     // Zテスト 常に描画
            "       ZTest Less" +       // Zテスト Z値が小さいと描画
            "       Fog { Mode Off }" + // フォグ オフ
            "       BindChannels {" +
            "           Bind \"Vertex\", vertex" + 
            "           Bind \"Color\", color" +
            "       }" +
            "} } }" );
        m_Material.hideFlags = HideFlags.HideAndDontSave;
        m_Material.shader.hideFlags = HideFlags.HideAndDontSave;
    }

    // メッシュから頂点の配列を作成
    void CreateVtxArray() {
        if(null == m_Mesh) return;

        Vector3[] vertices = m_Mesh.vertices;
        int[] triangles = m_Mesh.triangles;

        print("triangles.Length = " + triangles.Length);
        m_lineVtxArray = new Vector3[triangles.Length];
        for (int i = 0; i < triangles.Length / 3; i++) {
            m_lineVtxArray[i * 3 + 0] = vertices[triangles[i * 3 + 0]];
            m_lineVtxArray[i * 3 + 1] = vertices[triangles[i * 3 + 1]];
            m_lineVtxArray[i * 3 + 2] = vertices[triangles[i * 3 + 2]];
        }
    }

    // 線分の描画
    void DrawLine() {
        Vector3 vPos = Vector3.zero;
        Quaternion qRot = Quaternion.identity;
        Matrix4x4 mtx = Matrix4x4.TRS(vPos, qRot, Vector3.one); 
        
        m_Material.SetPass(0);

        GL.PushMatrix();
        GL.MultMatrix(mtx);
        
        GL.Begin(GL.LINES);
        GL.Color(m_lineColor);

        for (int i = 0; i < m_lineVtxArray.Length / 3; i++) {
            GL.Vertex(m_lineVtxArray[i * 3]);
            GL.Vertex(m_lineVtxArray[i * 3 + 1]);

            GL.Vertex(m_lineVtxArray[i * 3 + 1]);
            GL.Vertex(m_lineVtxArray[i * 3 + 2]);

            GL.Vertex(m_lineVtxArray[i * 3 + 2]);
            GL.Vertex(m_lineVtxArray[i * 3]);
        }
        GL.End();
        GL.PopMatrix();
    }
}

2012年4月7日土曜日

Unity WWW (2)

UnityのWWWで、ローカルホストにアクセスするテスト

サーバーにAIMLを実装したJ-Aliceを使用


ボット同士の会話

TestWWW2.cs

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

// テキストフィールドに入力した文字列を、Sendボタンでサーバーに送信
public class TestWWW2 : MonoBehaviour {
    public int  m_nPortNo = 8000;       // ポート番号
    public TestWWW2     m_objTalkTo;    // 話し相手
    
    string      m_InputTxt = "";        // 聞いた内容
    string      m_OutputTxt = "";       // 話した内容
    GameObject  m_objCamera;            // 描画用のカメラ

    public void Start() {
        // カメラを取得
        m_objCamera = GameObject.Find("Main Camera");
    }

    // 話したテキストをセット 話し相手側から呼びだす
    public void SetTaledTxt(string txt) {
        m_InputTxt = txt;
        StartCoroutine( ConnectToLocal( m_InputTxt ) );
    }

    // ローカルサーバーのJ-Aliceに接続
    IEnumerator ConnectToLocal(string inputTxt) {
        // URL引数
        string arg = "?input=" + WWW.EscapeURL(inputTxt);
        // URL
//        string url = "http://localhost:" + m_nPortNo.ToString() + arg;
        string url = "http://127.0.0.1:" + m_nPortNo.ToString() + arg;

        // WWWでURLに接続
        WWW www = new WWW(url);
        yield return www;

        // ShiftJisのエンコーディングを取得
        int codepage = 932;
        Encoding enc = Encoding.GetEncoding( codepage );

        // WWWから文字列を取得
        string str = enc.GetString( www.bytes );

        // J-Aliceからの応答部分の文字列を切り取り 仮
        int nStartIndex = str.IndexOf(":");
        int nEndIndex = str.IndexOf("<p>");
        int nLen = nEndIndex - nStartIndex - 2;
        str = str.Substring(nStartIndex + 2, nLen);

        m_OutputTxt = str;          // 描画するテキストをセット

        // 表示フラグ変更用のウェイト開始
        StartCoroutine( WaitOutputTxt() ); 
    }

    IEnumerator WaitOutputTxt() {
        yield return new WaitForSeconds(3.0f);  // ウェイト

        if(null != m_objTalkTo) {
            // 話相手に話した内容をセット
            m_objTalkTo.SetTaledTxt( m_OutputTxt );
        }
    }

    void OnGUI () {
        // ワールド座標をスクリーン座標に変換
        Vector3 pos = transform.position;
        Vector3 screenPos = m_objCamera.camera.WorldToScreenPoint( pos );

        // 入力文字列編集用のテキストフィールド
        string outTxt = GUI.TextField( new Rect(screenPos.x - 64.0f, 10.0f, 128.0f, 18.0f), m_InputTxt);
        if(0 != outTxt.CompareTo(m_InputTxt)) {
            m_InputTxt = outTxt;
        }

        // 送信ボタン
        if(GUI.Button(new Rect(screenPos.x - 64.0f + 140.0f, 10.0f, 64.0f, 18.0f), "Send")) {
            // コルーチンの開始
            StartCoroutine( ConnectToLocal( m_InputTxt ) );
        }
        // 応答テキストを表示
        GUI.TextArea( new Rect(screenPos.x - 100.0f, 60.0f, 200.0f, 64.0f), m_OutputTxt);
    }
}

2012年4月1日日曜日

Unity ギズモの描画と編集

空のゲームオブジェクトにTestGizmo.csを追加

ギズモを選択、編集タイプに応じて移動、サイズ変更がシーンウィンドウで行える

Assets/Script/TestGizmo.cs

using UnityEngine;

// ギズモのテスト用クラス
public class TestGizmo : MonoBehaviour {
  // 編集タイプの種類
  public enum EditType {
    Invalid,
    BoundCenter,
    BoundSize
  }

  // 編集タイプ
  public EditType editType = EditType.Invalid;

  // ギズモの形状
  public Bounds   bound = new Bounds(Vector3.zero, Vector3.one);

  // ギズモの描画
  void OnDrawGizmos () {
    Gizmos.color = Color.magenta;
    Gizmos.DrawWireCube(bound.center, bound.size);
  }
}

Assets/Editor/EditorTestGizmo.cs

using UnityEngine;
using UnityEditor;

// TestGizmoの編集用クラス
[CustomEditor( typeof(TestGizmo) )]     // ←編集対象のクラスを指定
public class EditorTestGizmo : Editor {

  // Editor.OnSceneGUI シーンウィンドウ上のGUI処理
  void OnSceneGUI () {
    // 編集対象を取得
    TestGizmo t = target as TestGizmo;

      switch(t.editType) {
      case TestGizmo.EditType.BoundCenter:
          // 位置の変更
          t.bound.center = Handles.PositionHandle(t.bound.center, 
                                      Quaternion.identity);
          break;
      case TestGizmo.EditType.BoundSize:
          // サイズの変更
          t.bound.size = Handles.ScaleHandle(t.bound.size, 
                           t.bound.center, Quaternion.identity, 5.0f);
          break;
      }
      if (GUI.changed) {
//          Debug.Log("GUI.changed");
      }
  }
}

2012年3月25日日曜日

C# ビープ音 (1)


// 救急車のサイレン音を再生
// ↓コンパイル方法
// csc /out:TestBeep.exe TestBeep.cs
class TestBeep
{
 public static void Main()
 {
  int loopNum = 2; // ループ回数
  for(int i = 0; i < loopNum; i++) {
   System.Console.Beep(988, 900); // シー
   System.Console.Beep(784, 900); // ソー
  }
  for(int i = 0; i < loopNum; i++) {
   System.Console.Beep(932, 900); // シ♭ー
   System.Console.Beep(740, 900); // ソ♭ー
  }
  for(int i = 0; i < loopNum; i++) {
   System.Console.Beep(880, 900); // ラー
   System.Console.Beep(698, 900); // ファー
  }
 }
}

2012年3月24日土曜日

Unity エディットウィンドウ(2) 三角形の描画

エディットウィンドウで三角形を描画するテスト
GLを使用すると描画できた
Editor/EditWindowD.cs


using UnityEngine;
using UnityEditor;

public class EditWindowD : EditorWindow {
    Material    m_Material;    // マテリアル
    Vector2 []  m_VecArray;    // 頂点の配列
    int         m_VecNum = 3;  // 頂点数

    // メニューに追加
    [MenuItem ("Window/EditWindowD")]
    static void Init() {
        EditWindowD window = (EditWindowD)EditorWindow.GetWindow( typeof (EditWindowD) );
        window.Show();
    }

    // スクリプトのロード時に呼ばれる ScriptableObject.OnEnable()
    void OnEnable() {
        CreateVertexArray();
        CreateMaterial();
    }
    
    // エディタウィンドウのGUI処理をここに記述 EditorWindow.OnGUI()
    void OnGUI() {
        // 再描画イベント時に描画処理を行う
        if (EventType.Repaint != Event.current.type) return;

        // 実行するとウィンドウが真っ白
        //GL.Clear(false, true, Color.white);

        m_Material.SetPass(0);
        DrawLine();
    }

    // マテリアルの作成
    void CreateMaterial() {
        m_Material = new Material( "Shader \"Lines/Colored_Blended\" {" +
            "SubShader { Pass { " +
            "    Blend SrcAlpha OneMinusSrcAlpha " +
            "    ZWrite Off Cull Off Fog { Mode Off } " +
            "    BindChannels {" +
            "      Bind \"vertex\", vertex" + 
            "      Bind \"color\", color" +
            "} } } }" );
        m_Material.hideFlags = HideFlags.HideAndDontSave;
        m_Material.shader.hideFlags = HideFlags.HideAndDontSave;
    }

    // 頂点の配列を作成
    void CreateVertexArray() {
        m_VecArray = new Vector2[m_VecNum];
        m_VecArray[0] = new Vector2(50, 10);
        m_VecArray[1] = new Vector2(10, 60);
        m_VecArray[2] = new Vector2(90, 60);
    }

    // 線分の描画
    void DrawLine() {
        GL.Color(Color.blue);
        GL.Begin( GL.LINES );
        for(int i = 0; i < m_VecNum; i++) {
            int idx0 = i;
            int idx1 = (i == m_VecNum - 1) ? 0 : idx0 + 1;
            GL.Vertex(m_VecArray[idx0]);
            GL.Vertex(m_VecArray[idx1]);
        }
        GL.End();
    }
}

2012年3月20日火曜日

Redis Cygwin上で使用


Redis v2.4.9 をDL
makeするとエラー発生
 redis.c の setupSignalHandlers() SA_ONSTACK が未定義らしい
 テストなので、SA_ONSTACKを削除して make -> OK

デフォルト設定でサーバー起動
./redis-server

設定ファイルを指定してサーバー起動
./redis-server redis.conf

クライアントを起動
./redis-cli


データの追加、取得を行ってみる
> SET key value1  # キーと値を設定
> GET key         # キーの値を取得
> OK


#設定ファイル redis.conf
# ↓TODO
loglevel notice
maxmemory 1mb

MAXScript 形状のブール演算


-- メッシュのブール演算のテスト
fn Test5 = (
 -- 形状を作成
 s1 = box width:150 height:5
 
 s2 = sphere radius:20
 s2.pos.x = 50

 s3 = pyramid depth:55
 s3.pos.x = -50
 s3.pos.z = 2.5
 
 -- 減算
 s1 = s1 - s2
 
 -- 加算
 s1 += s3
 
 delete s2
 delete s3
 s1
)

Test5()

MAXScript 配列とビット配列


-- .NETオブジェクトの ArrayList を使用するテスト
fn TestArray1 = (
 -- .NET のArrayListオブジェクトを取得
 arrayList = dotNetObject "System.Collections.ArrayList"
 
 -- ArrayListに要素を追加
 arrayList.Add("A")
 arrayList.Add("BC")
 arrayList.Add("D")
 
 -- 配列の要素数を出力
 format "arrayList.Count = %\n" arrayList.Count
 
-- format "%\n" arrayList[1] -- ERROR
 
 str = arrayList.ToString()
 format "str = %\n" str
 
 item1 = arrayList.Item(1)
 format "%\n" item1
 
 for i = 0 to arrayList.Count - 1 do (
  --  ↓ ERROR発生
--  format "arrayList[%] = %\n" i arrayList[i] -- ERROR
  -- 指定したインデックスの要素を取得
  item = arrayList.Item(i)
  format "arrayList[%] = %\n" i item
 )

-- arrayList.Item(1) = "bc"
 
 item1 = arrayList.Item(1)
 format "item1 = %\n" item1

 for i = 0 to arrayList.Count - 1 do (
  --  ↓ get_Item()が出力される
  format "arrayList[%] = %\n" i arrayList.Item(i)
 )
)

-- 配列とビット配列のテスト
fn TestArray2 = (
 -- 空の配列を作成
 a = #()

 -- 配列に値を追加
 append a 1
 append a 2

 format "a = %\n" a

 -- 配列の要素を削除
 deleteItem a 2
 --deleteItem a 1

 format "a = % a.count = %\n" a a.count

 -- 空のビット配列を作成
 b0 = #{}
 b1 = #{}

 --b0[0] = true -- ERROR インデックスは1から開始
 b0[1] = false
 b0[20] = true
 b0[32] = true
 
 b1[8] = true

 format "b0 = % b0.count = %\n" b0 b0.count
 format "b1 = % b1.count = %\n" b1 b1.count
 
 b2 = b0 + b1 -- OR演算
 b3 = b0 * b1 -- AND演算
 
 format "b0 + b1 = %\n" b2
 format "b0 * b1 = %\n" b3
 
 b4 = -b1  -- ビットの反転
 format "-b1 = %\n" b4
 
 b1[20] = true
 b5 = b0 - b1 -- 差
 format "b0 - b1 = %\n" b5
 
 b6 = #{1..7, 16}
 format "b6 = % b6.numberSet = %\n" b6 b6.numberSet
)

TestArray2()

2012年3月4日日曜日

2012年2月29日水曜日

MAXScript メッシュの作成(2)

ポリラインの作成

--  制御点の配列からポリラインを作成
fn CreatePolyLineFromPosArray posArray lineWidth = (

    ss = SplineShape pos:posArray[1]    -- posArray[1]にSplineShapeを作成
    idx = addNewSpline ss                   -- スプライン曲線を追加
    format "NewSpline idx = %\n" idx
    
    for i = 1 to posArray.Count do (
        addKnot ss idx #corner #line posArray[ i ]  
    )
    -- シェイプの更新
    updateShape ss  

    -- [ビューポートを有効]チェックボックスをオン
    ss.render_displayRenderMesh = true
    -- 矩形断面モードにする
--  ss.render_viewport_rectangular = true
    ss.render_rectangular = true

    -- 矩形断面の設定値
--  ss.render_length  = 5.0
    ss.render_width = lineWidth

--  ss.render_viewport_length = 1.0
--  ss.render_viewport_width = lineWidth
    
    -- メッシュに変換
    convertToMesh ss
    format "ss.numfaces %\n" ss.numfaces
    
    -- アップベクトル
    vUp = [0, 0, 1]
    -- 削除する面のインデックスの配列
    faceIdxArray = #()
    
    for f = 1 to ss.numfaces do (
        -- 面の法線を取得
        n = getFaceNormal ss f
        -- アップベクトルと面の法線の内積
        d = dot vUp n
    
--      if d <= 0.0 do (        -- 削除されない面がある
        if d <= 0.01 do (       
            -- 削除する面のインデックスを追加
            append faceIdxArray f
        )
    )
    
    -- 道路以外のメッシュを削除
    meshop.deleteFaces ss faceIdxArray delIsoVerts:false
    
    -- UVWMapモディファイアの追加
    -- maptype 0 - 6
    addModifier ss (UVWMap maptype:5) -- maptype 0:Planar 4:Box 5: Face
    ss
)
-- CreatePolyLineFromPosArrayのテスト
-- 制御点の配列
gPosArray1 = #()
gPosArray2 = #()
-- 制御点を追加
append gPosArray1 [0, 0, 0] 
append gPosArray1 [200, 0, 0]
append gPosArray1 [200, 50, 0]
append gPosArray1 [250, 250, 0]
append gPosArray1 [300, 450, 0]
append gPosArray1 [50, 500, 0]

append gPosArray2 [0,  -50, 0]  
append gPosArray2 [0, 100, 0]

-- 線の幅
lineWidth = 25.0

-- メッシュを作成
newSpline1 = CreatePolyLineFromPosArray gPosArray1 lineWidth
classof newSpline1
newSpline2 = CreatePolyLineFromPosArray gPosArray2 lineWidth

-- メッシュの加算
newSpline1 = newSpline1 + newSpline2
-- 追加したメッシュを削除
delete newSpline2

2012年2月26日日曜日

Unity 処理時間計測 (2)

C#版

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

using UnityEngine;

class TestObject {
 int n;
 string name;

 public TestObject() {
  n = 0;
  name = "abc";
 }
}

// テスト用のクラス
public class TestClass : MonoBehaviour {

 const int ArrayNum = 5000;  // 配列数

 float fBaseTime = 0.0f;
 float fCurTime = 0.0f;

 int [] array; // 配列
 
 System.Collections.ArrayList al0;
 System.Collections.ArrayList al1;
 System.Collections.ArrayList al2;
 System.Collections.ArrayList al3;

 void Start() {
  TestArray();
 }

 void Update() {
  if(Input.GetKeyDown(KeyCode.Alpha1)) {
   StartCoroutine( WaitFunc(1.0F) );
  }
  if(Input.GetKeyDown(KeyCode.Alpha2)) {
   StartCoroutine( WaitFunc(1.5F) );
  }

  if(Input.GetKeyDown(KeyCode.Alpha4)) {
   TestArray();
  }
 }

 // 配列のテスト
 void TestArray() {
  // 配列の作成
  array = new int [ ArrayNum ];

  al0 = new ArrayList();
  al1 = new ArrayList();
  al2 = new ArrayList();
  al3 = new ArrayList();

  // Test1 何もしない
  fBaseTime = Time.realtimeSinceStartup;
  fCurTime = Time.realtimeSinceStartup;
  Debug.Log("Test1 time = " + ((fCurTime - fBaseTime) * 1000.0f).ToString()+"(ms)");

  // Test2 配列に値セット
  fBaseTime = Time.realtimeSinceStartup;
  for(int i = 0; i < ArrayNum; i++) {
   array[i] = i;
  }
  fCurTime = Time.realtimeSinceStartup;
  Debug.Log("Test2 time = " + ((fCurTime - fBaseTime) * 1000.0f).ToString()+"(ms)");


  // Test3 配列に整数を追加
  fBaseTime = Time.realtimeSinceStartup;
  for(int i = 0; i < ArrayNum; i++) {
   al0.Add( i );
  }
  fCurTime = Time.realtimeSinceStartup;

  Debug.Log("Test3 time = " + ((fCurTime-fBaseTime) * 1000.0f).ToString()+"(ms)");
  Debug.Log("al0.Count = " + al0.Count);

  // Test4 配列に整数を追加
  fBaseTime = Time.realtimeSinceStartup;
  for(int i = 0; i < ArrayNum; i++) {
   al1.Add( 9876 );
  }
  fCurTime = Time.realtimeSinceStartup;
  Debug.Log("Test4 time = " + ((fCurTime-fBaseTime) * 1000.0f).ToString()+"(ms)");

  // Test5 配列に文字列を追加
  fBaseTime = Time.realtimeSinceStartup;
  for(int i = 0; i < ArrayNum; i++) {
   al2.Add( "abcdefghijklmnopqrstu" );
  }
  fCurTime = Time.realtimeSinceStartup;
  Debug.Log("Test5 time = " + ((fCurTime-fBaseTime) * 1000.0f).ToString()+"(ms)");

  // Test5 配列にクラスを追加
  fBaseTime = Time.realtimeSinceStartup;
  for(int i = 0; i < ArrayNum; i++) {
   TestObject o = new TestObject();
   al3.Add( o );
  }
  fCurTime = Time.realtimeSinceStartup;
  Debug.Log("Test6 time = " + ((fCurTime-fBaseTime) * 1000.0f).ToString()+"(ms)");
 }

 IEnumerator WaitFunc(float t) {
  fBaseTime = Time.realtimeSinceStartup;
  yield return new WaitForSeconds( t );
  fCurTime = Time.realtimeSinceStartup;
  Debug.Log("Test6 time = " + ((fCurTime-fBaseTime) * 1000.0f).ToString()+"(ms)");
 }
}


Unity 処理時間計測 (1)

Time.realtimeSinceStartup を使用
JavaScript版

private var nArrayNum : int = 5000;
private var numArray : int[];
private var arr0 : Array;

private var fBaseTime : float = 0.0f;
private var fCurTime : float = 0.0f;

function Start() {
 TestArray();
}

function Update() {
 if(Input.GetKeyDown(KeyCode.Keypad4)) {
  TestArray();
 }
}

// 配列のテスト
function TestArray() {
 var i : int = 0;
 numArray = new int[ nArrayNum ];
 arr0 = new Array();
 
 // Test1
 fBaseTime = Time.realtimeSinceStartup;
 for(i = 0; i < nArrayNum; i++) {
  numArray[i] = i;
 }
 fCurTime = Time.realtimeSinceStartup;
 Debug.Log("Test1 time = " + ((fCurTime - fBaseTime) * 1000.0f).ToString() + "(ms)");

 // Test2
 fBaseTime = Time.realtimeSinceStartup;
 for(i = 0; i < nArrayNum; i++) {
  arr0.Push( i );
 }
 fCurTime = Time.realtimeSinceStartup;
 Debug.Log("Test2 time = " + ((fCurTime - fBaseTime) * 1000.0f).ToString() + "(ms)");

}

2012年2月18日土曜日

MAXScript メッシュの作成 (1)

SplineShapeを作成 -> 押し出して何かするテスト

-- 制御点の配列
gPosArray = #()
append gPosArray [20,  10,  0]
append gPosArray [20, -10, 0]
append gPosArray [-20,-20, 0]
append gPosArray [-20, 25, 0]

-- シンプルなメッシュの作成
-- SplineShapeを作成して押し出す
-- posArray 制御点の配列
-- Height       SplineShapeを押し出す高さ
-- Outline      輪郭の押し出し値
fn CreateSimpleMesh posArray Height Outline= (
    
    -- SplineShapeを作成
    local sp = splineShape()
    idx = addnewSpline sp
    for i = 1 to posArray.Count do (
        addKnot sp idx #corner #line posArray[ i ]
    )
    close sp idx
    updateShape sp

    -- メッシュに変換
    convertToMesh sp

    -- 全面の押し出し
    meshop.extrudeFaces sp #{ 1.. sp.numfaces } Height Outline

    -- メッシュの面のマテリアルIDを変更
    newMtlID = 2
    setFaceMatID sp 1 newMtlID  -- Face 1
    setFaceMatID sp 2 newMtlID  -- Face 2
/*  
    -- 面のマテリアルIDを取得
    for i = 1 to sp.numfaces do (
        format "Face % Mtl ID = %\n" i ( getFaceMatID sp i )
    )
*/
    -- UVWMapモディファイアの追加
    addModifier sp (UVWMap maptype:4) -- maptype 4:Box
    
    sp
)

-- メッシュを作成
mesh1 = CreateSimpleMesh gPosArray 100.0 -2.0
mesh1.pos = [100, 0, 0]

mesh2 = CreateSimpleMesh gPosArray 50.0 0.0
mesh2.pos = [0, 50, 0]

mesh3 = CreateSimpleMesh gPosArray 25.87 15.0
mesh3.pos = [-50, -80, 0]

MAXScript ストリングストリーム

StringStream

-- テストその1
fn TestStringStream1 = (
    -- 空のStringStreamを作成
    ss1 = stringStream ""
--  ss1 = stringStream      -- ERROR
    
    -- ss1に出力
    format "ABC %" "123456789" to:ss1
    
    -- シーク位置を先頭にする
    seek ss1 0
    -- 読み込んだ行を出力   シーク位置が進む
    format "%\n" ( readLine ss1 )
    
    -- ストリームの終了チェック
    isEnd = eof ss1
    format "isEnd = %\n" isEnd  -- true
)

-- テストその2
fn TestStringStream2 = (
    -- .NETクラスを取得
    dnDayTime = dotNetClass "System.DateTime"
    dnTimeZone = dotNetClass "System.TimeZone"
    
    -- 日付を取得
    currentDate = dnDayTime.Now
    currentYear = currentDate.Year

    -- 空のStringStreamを作成
    ss = stringStream ""

    -- ssに書き込む
    format "Current Year = %\n" currentYear to:ss
    format "Month = %\n" currentDate.Month to:ss
    format "Day = %" currentDate.Day to:ss
    
    -- ssの内容を出力
    seek ss 0
    while not eof ss do (
        format "%\n" (readLine ss)
    )

--  print (readLine ss)
--  while not eof ss do print ( readLine ss )
)

TestStringStream1()
TestStringStream2()

2012年2月17日金曜日

MAXScript マテリアルエディタの操作 (2) マルチ


マルチマテリアルを作成するスクリプト

・作成するスロット番号を選択
・サブマテリアル数を選択
・Createボタンを押す
・画像選択ダイアログで画像選択


-- dropdownlist作成用の配列
slotNoArray = #()
subMtlNumArray = #()

-- デフォルト値
defaultSlotNo = 1           -- スロット番号
defaultSubMtlNum = 2        -- サブマテリアル数

-- 初期化処理
fn Init = (
    -- スロット番号
    for i = 1 to 24 do (
        append slotNoArray ( i as string )
    )
    -- サブマテリアル数
    for i = 1 to 10 do (
        append subMtlNumArray ( i as string )
    )
)

-- マルチマテリアルを作成
-- slotNo: スロット番号
-- subMtlNum: サブマテリアル数
fn CreateMultiMtl slotNo subMtlNum = (

    -- モードのセット
    MatEditor.mode = #basic

    -- 状態取得
    isOpen = MatEditor.isOpen()
    
    -- マテリアルエディタを開く
    if false == isOpen do ( MatEditor.Open() )

    -- マルチマテリアルを作成
    newMtl = multimaterial ()
    
    -- 画像を読み込む
    for i = 1 to subMtlNum do (
        -- Captionの文字列
        ss = stringStream ""
        format "Select SubMtl Texture %" i to:ss
        seek ss 0
        str = ( readLine ss )

        -- 画像を選択
        local img = selectBitMap caption:str
        if undefined == img do ( return undefined )
        
        -- 選択画像からBitmapTextureを作成
        local bmTex = BitmapTexture bitmap:img

        -- マテリアルを作成
        local mtl = standardMaterial diffuseMap:bmTex showInViewport:true
        
        newMtl[i] = mtl
    )
    -- マテリアルをスロットにセット
    setMeditMaterial slotNo newMtl
)
-- ロールアウト
rollout RolloutMtl "CreateMultiMaterial" 
(
    -- スロット数選択用
    dropdownlist dSlotNo "Slot No:" pos:[16, 16] \
            items:slotNoArray width:80

    -- サブマテリアル数選択用
    dropdownlist dNumSubMtl "Sub Material Num:" pos:[120, 16] \
            items:subMtlNumArray width:80 selection:defaultSubMtlNum

    -- 作成ボタン
    button btnCreate "Create" width:96 height:24    pos:[64, 64]
    
    on  btnCreate pressed do (
        CreateMultiMtl dSlotNo.selection dNumSubMtl.selection
    )
)
Init()
createDialog RolloutMtl width:240 height:100

MAXScript マテリアルエディタの操作 (1)


-- マテリアルエディタの操作テスト
fn TestMedit = (
    -- モード取得
    format "Medit mode = %\n" MatEditor.mode
    
    -- マテリアルエディタを開く
    MatEditor.Open()
    
    isOpen = MatEditor.isOpen()
    format "isOpen = %\n" isOpen
    
    -- スロットからマテリアルを取得
    
    mtl1 = getMeditMaterial 1
    format "mtl1.name = %\n" mtl1.name

    -- マテリアルのプロパティの変更
    mtl1.diffuse = yellow
    
    
    -- スロットにマテリアルを設定
    
    -- 画像を読み込む
    img = selectBitMap ()
    if undefined == img do return undefined

    -- 選択画像からBitmapTextureを作成
    bmTex = BitmapTexture bitmap:img

    -- スロットにマテリアルをセット
    newMtl = standardMaterial diffuseMap:bmTex
    setMeditMaterial 2 newMtl

    format "newMtl.name = %\n" newMtl.name
    
--  newMtl = standardMaterial diffuseMap:( checker() )
--  setMeditMaterial 3 newMtl

    -- マテリアルエディタを閉じる
--  MatEditor.Close()
)

TestMedit()

2012年2月15日水曜日

MAXScript xmlのテスト

dotNetObjectを使う

-- Xml Test 文字列
xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
   <rootElem ver = \"2.1\">
    <childElemA str = \"A\" num = \"123\"/>
    <childElemA str = \"A\" num = \"456\"/>
    <childElemB str = \"B\"/>
   </rootElem>"

-- XmlElementの属性値を取得
fn GetAttrib elem elemName = (
 if true == elem.HasAttribute( elemName ) then (
  return elem.GetAttribute( elemName )
 )
 return undefined
)


-- System.Xml.XmlDocument オブジェクトを作成
xmlDoc = dotNetObject "System.Xml.XmlDocument"
xmlDoc.LoadXml xmlString  -- 文字列からXMLを読み込む
xmlDoc.LocalName

-- ルートXmlElementを取得
rootElem = xmlDoc.DocumentElement

-- 属性値を取得
GetAttrib rootElem "ver"   -- "2.1"
GetAttrib rootElem "Ver"   -- undefined

-- 子ノードの属性値を取得
elemList = rootElem.GetElementsByTagName("childElemA");
for i = 1 to elemList.Count do (
 n = elemList.ItemOf (i - 1)  -- ノードを取得
 format "v = %\n" ( GetAttrib n "num" )
 format "v = %\n" ( GetAttrib n "Num" )  -- undefined
)

2012年2月12日日曜日

Unity WWW (1)


(笑)の略ではなくWorld Wide Web
System.Web.HttpUtility.UrlEncodeが使えない
WWW.EscapeURL()の結果がおかしい?

指定したurlにアクセスして受信結果をテキストファイルに保存するテスト


using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
//using System.Web;     // ERROR System.Webが無い
using UnityEngine;

public class TestWWW : MonoBehaviour
{
 public IEnumerator Start() {

        // URLエンコードを行う 結果が"abc+123"
        print(WWW.EscapeURL("abc 123"));

        string url = "http://www.google.co.jp/";

        WWW www = new WWW(url);
        yield return www;
        
        // ShiftJisのエンコーディングを取得
        int codepage = 932;
        Encoding enc = Encoding.GetEncoding( codepage );

        // 受信結果をファイルに保存     ファイルはプロジェクトフォルダにある
        StreamWriter sw = new StreamWriter("./result.html", false, enc);
//        sw.Write(www.text);           // 文字化けしている
        // wwwのバイト配列から文字列を取得
        string strShiftJis = enc.GetString( www.bytes );
        sw.Write(strShiftJis);
        sw.Close();

        print("Start() end");
 }
}

2012年2月11日土曜日

MAXScript ノードのプロパティを変更


/*
 vFromベクトルからvToベクトルまでの角度を取得
*/
fn GetAngle vFrom vTo =
(
 vFrom = normalize vFrom
 vTo = normalize vTo
 
 rotDot = dot vFrom vTo
 
 rotAngle = acos rotDot -- 角度は度
)

/*
 座標がノードの右側に位置するか判定

 nodeMtx ノードの行列
 pos 判定する座標
*/
fn IsRightSide nodeMtx pos =
(
 toPos = pos - nodeMtx.translation
 right = -nodeMtx.row1 -- ノードのRightベクトル
 
 d = dot right toPos
 if d > 0.0 do ( return true )
 return false
)

-- MAXWrapperのプロパティを変更するテスト
fn Test1 =
(
 -- ターゲット 
 target = mesh vertices:#([0,0,0],[10,0,40],[-10,0,40]) \
     faces:#([1,2,3]) materialIDS:#(1)
 target.pos = [-25, 75, 0]
 target.name = "Target"
 
 -- オブジェクトの作成
 -- 三角形のメッシュを作成
 tri = mesh vertices:#([0,-20,0],[10,10,0],[-10,10,0]) \
     faces:#([1,2,3]) materialIDS:#(1)

 -- オイラー角を作成
 rotAngle = eulerAngles 0.0 0.0 -45.0

 -- 回転の変更
-- tri.rotation = rotAngle as quat

 -- 位置の変更
 tri.pos = [0, 0, 0]

 -- スケールの変更
 tri.scale = [1, 2, 1]

 -- 選択状態の変更
 tri.isSelected = true

 -- ノードの行列
 format "mtx %\n" tri.transform
 
 -- ノードのローカルのZ方向
 format "dir %\n" tri.dir
 
 -- オブジェクトからターゲットまでのベクトル
 vToTarget = target.pos - tri.pos
 
 -- オブジェクトの進行方向
 vFwd = -tri.transform.row2
 
 -- ターゲットに向ける角度を取得
 rotAngle = GetAngle vFwd vToTarget
 format "rotAngle %\n" rotAngle
 
 -- ターゲットの座標がオブジェクトの右側か判定
 isRight = IsRightSide tri.transform target.pos
 format "isRight %\n" isRight
 
 if isRight == false do ( rotAngle = -rotAngle )
 
 -- オブジェクトの正面がターゲットを向くように回転させる
 rotAngle = eulerAngles 0.0 0.0 rotAngle
 tri.rotation = rotAngle as quat 
)

Test1()

2012年2月7日火曜日

OpenCVでペイント

OpenCVのテスト用

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

cv::Mat g_Canvas; // キャンバス
cv::Mat g_Palette; // 描画色
cv::Size g_CanvasWndSize(640, 480); // キャンバスサイズ
const char* g_CanvasWndName = "window";
const char* g_PalWndName = "palette";
bool g_bLBtnDown = false;
int g_TrackBarValue[3] = { 0 };  // トラックバーの値

// 指定座標にピクセル描画
void DrawPixel(cv::Mat* pMat, int x, int y, int pixelSize)
{
 cv::Scalar color(g_TrackBarValue[2], g_TrackBarValue[1], g_TrackBarValue[0]);
 cv::Point p0(x - pixelSize, y - pixelSize); 
 cv::Point p1(x + pixelSize, y + pixelSize); 
 cv::rectangle(*pMat, p0, p1, color, -1, CV_AA);
}

// マウスイベントの処理
static void onMouse(int event, int x, int y, int flag, void* ptr)
{
 switch(event) {
 case cv::EVENT_MOUSEMOVE:
  if(g_bLBtnDown) {
   // キャンバスにピクセル描画
   DrawPixel(&g_Canvas, x, y, 4);

   // 変更を反映
   cv::imshow(g_CanvasWndName, g_Canvas);
  }
  break;
 case cv::EVENT_LBUTTONDOWN:
  g_bLBtnDown = true;
  break;
 case cv::EVENT_LBUTTONUP:
  g_bLBtnDown = false;
  break;
 }
}

// 指定色で塗りつぶす
void FillColor(cv::Mat* pMat, int r, int g, int b)
{
 *pMat = cv::Scalar(b, g, r);
}

// トラックバーのイベントハンドラ
void onTrackbarRed(int val, void* ptr)
{
 g_TrackBarValue[0] = val;
 FillColor(&g_Palette, g_TrackBarValue[0], g_TrackBarValue[1], g_TrackBarValue[2]);
 cv::imshow(g_PalWndName, g_Palette);
}
void onTrackbarGreen(int val, void* ptr)
{
 g_TrackBarValue[1] = val;
 FillColor(&g_Palette, g_TrackBarValue[0], g_TrackBarValue[1], g_TrackBarValue[2]);
 cv::imshow(g_PalWndName, g_Palette);
}
void onTrackbarBlue(int val, void* ptr)
{
 g_TrackBarValue[2] = val;
 FillColor(&g_Palette, g_TrackBarValue[0], g_TrackBarValue[1], g_TrackBarValue[2]);
 cv::imshow(g_PalWndName, g_Palette);
}

int main( int argc, char **argv )
{
 // Matを作成
 g_Canvas = cv::Mat(g_CanvasWndSize.height, g_CanvasWndSize.width, CV_8UC3);
 g_Palette = cv::Mat(64, 512, CV_8UC3);
 FillColor(&g_Palette, g_TrackBarValue[0], g_TrackBarValue[1], g_TrackBarValue[2]);

 // ウィンドウ作成
 cv::namedWindow(g_CanvasWndName, CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO);
 cv::namedWindow(g_PalWndName, CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO);
 
 // マウスのコールバック関数をセット
 cv::setMouseCallback(g_CanvasWndName, onMouse, NULL);
 
 // トラックバーをウィンドウに作成
 cv::createTrackbar("Red", g_PalWndName, &g_TrackBarValue[0], 255, onTrackbarRed, 0);
 cv::createTrackbar("Green", g_PalWndName, &g_TrackBarValue[1], 255, onTrackbarGreen, 0);
 cv::createTrackbar("Blue", g_PalWndName, &g_TrackBarValue[2], 255, onTrackbarBlue, 0);

 // ウィンドウにMatを表示
 cv::imshow(g_CanvasWndName, g_Canvas);
 cv::imshow(g_PalWndName, g_Palette);

 // キー入力待ち
 cv::waitKey(0);
 return 0;
}

2012年2月4日土曜日

Unity ボーン行列の変更(1)


MonoBehaviour.LateUpdate()内で
変更処理を実行すると描画に反映される

/*
ボーンのTransform
インスペクタ上で変更するボーンを指定
or GameObject.Find("...")でボーンを取得
*/
public Transform    testBone;

/*
MonoBehaviour.LateUpdate
MonoBehaviour.Update 後に呼ばれる
*/
public void LateUpdate () {
 /*
 ボーンの位置を変更
 子のボーンにも変更が適用される
 */
 testBone.position = new Vector3(0.0f, 0.5f, 0.0f);
}

2012年1月31日火曜日

MAXScript ハイトマップからメッシュの作成(1)

Bmp, Jpeg画像のハイトマップから地形を作成するスクリプト

-- ビットマップ
gBitmap = undefined
-- 平面のサイズ
gPlaneSizeX = 500.0
gPlaneSizeY = 500.0
-- 平面のセグメント数
gNumSegX = 25
gNumSegY = 25
-- 最大の高さ
gHeightMax = 25.0

-- メッシュの作成
fn CreatePlaneMesh len wid segX segY = 
(
 m = mesh length:len width:wid lengthsegs:segY widthsegs:segX
 return m
)

-- セグメントのインデックスからピクセルのインデックスを取得
fn GetPixIdx segIdx segNum pixNum =
(
 segIdxF = segIdx as float
 segNumF = segNum as float
 
 f = segIdxF / segNumF
 pixIdx = f * (pixNum - 1)
 return pixIdx as integer
)

-- メッシュの指定したインデックスの頂点に高さをセット
fn SetHeight m idx height =
(
 v = patch.getVert m idx
 v.z = height
 patch.setVert m idx v
)

-- メッシュにハイトマップの高さをセット
fn Mesh_SetHeightMap m nSegX nSegY bm =
(
 -- 高さをセットするメッシュの頂点のインデックス
 idx = 1
 bmWidth = bm.width
 bmHeight = bm.height

 for y = 0 to nSegY do (
  pixY = GetPixIdx y nSegY bmHeight
  pixY = pixY as integer

  for x = 0 to nSegX do (
   pixX = GetPixIdx x nSegX bmWidth
   pixX = pixX as integer
   
   -- ビッドマップからピクセルの配列を取得
   pixArray = getPixels bm [pixX, pixY] 1
   
   -- 高さ
   h = pixArray[1].r / 255.0
   h = h * gHeightMax
   
   SetHeight m idx h
   idx = idx + 1
  )
 )
)

-- ハイトマップからメッシュを作成
fn CreateMeshFromHeightmap =
(
 -- ハイトマップを開く
 fPath = getOpenFileName caption:"Open Heightmap:" \
  types:"Bmp(*.bmp)|*.bmp|Jpeg(*.jpg)|*.jpg"
 if fPath == undefined then return -1

 gBitmap = openBitMap fPath
 format "w = % h = %\n" gBitmap.width gBitmap.height

 -- メッシュを作成
 m = CreatePlaneMesh gPlaneSizeX gPlaneSizeY gNumSegX gNumSegY
 
 -- パッチに変換
 convertTo m Editable_Patch
 
 -- 高さをセット
 Mesh_SetHeightMap m gNumSegX gNumSegY gBitmap
)
-- テスト
CreateMeshFromHeightmap()

MAXScript ビットマップの作成


-- ビットマップサイズ
gBitmapWidth = 256
gBitmapHeight = 8

-- グラデーションビットマップを作成
fn CreateGradBitmap =
(
 b_width = gBitmapWidth
 b_height = gBitmapHeight
 
 -- ビットマップを作成
 b = bitmap b_width b_height

 -- 列のループ
 for h = 0 to (b_height - 1) do
 (
  -- 行のピクセル配列を収集
  row = for w = 0 to (b_width - 1) collect
  (
   -- 補間係数
   t = w as float / (b_width - 1)
   
   -- rowにカラー値を追加
   if undefined != gSpline then
   (
    -- スプラインから座標を取得
    pos = interpCurve3D gSpline gSplineIdx t
    white * (pos.y / 100.0)
   )else (
    white * t
   )
  )
  -- 収集したピクセル配列をセット
  setpixels b [0, h] row
 )
 return b
)

-- ビットマップを作成
b = CreateGradBitmap()
-- ビットマップを表示
if undefined != b then display b

MAXScript ベジェ曲線の作成


gSpline = undefined
gSplineIdx = 0

-- スプラインシェイプを作成
fn CreateSpline =
(
 if undefined != gSpline then return -1 
 
 -- シェイプの作成
 ss = splineShape()
 -- シェイプにスプライン曲線を追加
 idx = addnewSpline ss

 -- addKnotのパラメータ
 param3 = #bezier 
 param4 = #curve

 -- bezier曲線の制御点のイン、アウトベクトルの座標
 inPos0 = [0, 0, 0]
 outPos0 = [0, 0, 0]
 inPos1 = [30, 10, 0]
 outPos1 = [70, 40, 0]
 inPos2 = [100, 100, 0]
 outPos2 = [100, 100, 0]

 -- 制御点の追加
 addKnot ss idx param3 param4 [0, 0, 0] inPos0 outPos0
 addKnot ss idx param3 param4 [50, 20, 0] inPos1 outPos1
 addKnot ss idx param3 param4 [100, 100, 0] inPos2 outPos2
 
 -- シェイプの更新
 updateShape ss
 
 -- コピー
 gSpline = ss
 gSplineIdx = idx
 return 0
)

-- 形状データ取得テスト
fn GetShapeDataTest ss idx =
(
 -- セグメント数
 nSeg = numSegments ss idx
 format "nSeg %\n" nSeg
 
 -- 曲線の座標
 for t = 0.0 to 1.0 by 0.1 do
 (
  pos = interpCurve3D ss idx t
  format "t = % pos = %\n" t pos
 )
)

CreateSpline()
GetShapeDataTest gSpline gSplineIdx

2012年1月28日土曜日

MAXScript ルートボーンの移動アニメを変更してみる(2)

あるモデルのルートボーンの移動アニメを無効にしたい
/*
 選択したボーンの全フレームの座標変更
 pos: セットする座標

    使用方法
 トラックビュー選択ダイアログが表示されるので
 変更したいボーンの"Transform : Position/Rotation/Scale"
 を選択してOKボタンを押す
 */
fn SetSelectBonePosAllKey pos =
(
 -- ダイアログ表示オプション
 dlgOpt = 0
 dlgOpt = bit.set dlgOpt 1 true --アニメトラックのみ
-- dlgOpt = bit.set dlgOpt 3 true   --選択したノードのみ

 -- ダイアログを表示
 tvp = trackview.pickTrackDlg options:dlgOpt

 if tvp == undefined then return -1 -- 未選択
 
 format "tvp.name %\n" tvp.name -- 選択した項目の名前
 if "Transform" != tvp.name then return 1
 
 c0 = tvp.client -- 選択項目の親のMAXWrapper
 if c0 != undefined then
 (
  cname = getClassName c0
  format "c0.className %\n" cname
  if cname != "Bone" then return 2
 )
 
 -- 選択項目のサブアニメを取得
 subAni = tvp.anim
 if subAni == undefined  then return 3

 -- サブアニメ数
 format "subAni.numSubs %\n" subAni.numSubs
 ret = 4
 for i = 1 to subAni.numSubs do
 (
  -- サブアニメの名前
  n =  getSubAnimName subAni i
  format "subAnim name %\n" n

  -- Positionのみ変更
  if 0 != stricmp n "position" then continue
   
  -- コントローラーの取得
  c = subAni[i].Controller
  if c == undefined  then continue

  -- コントローラーからキーの配列を取得
  keys = c.keys
  -- キーフレーム数
  format "key_array count %\n" keys.count
    
  -- 全キーフレームの座標を変更
  for j = 1 to keys.count do
  (
   keys[j].value = pos
  )
  ret = 0
 )
 return ret
)

gPos = [0, 0, 0] -- セットする座標
SetSelectBonePosAllKey gPos

Android カメラデバイスを使用(1)


AndroidManifest.xmlのmanifestタグ内に以下の記述を追加
 <uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />

ActivityのonCreateでセットするコンテキストビューを変更
 //setContentView(R.layout.main);
 setContentView(new CameraPreview(this));

カメラプレビュー用のクラスを作成
 // カメラ数を取得 カメラが無いと0?
 int camNum = Camera.getNumberOfCameras();
 Log.d(LogTag, "nNumCamera = " + camNum);

 // カメラの作成
 int id = 0; // 0:Out, 1:Inカメラだった
 camera = Camera.open(id);

 // カメラにSurfaceHolderをセット
 camera.setPreviewDisplay(holder);

 // プレビューの開始
 camera.startPreview();

 // カメラの停止
 camera.stopPreview();
 camera.release();

2012年1月27日金曜日

ghostTown

街生成スクリプトが 0.31にバージョンアップしていた
以前のバージョンを実行、使い方が?? ど忘れ・・・

Show Guideボタンでガイド表示
平面などを配置して
Setupボタン -> Buildボタンで街生成

生成結果

エラーが出る場合、Materialタブの Update GTMatLibボタンを押す

描画結果

SQLiteのRTreeを使用してみる

sqliteからソースを取得
プリプロセッサの定義に SQLITE_ENABLE_RTREE を追加してライブラリを作成

#include <stdio.h>
#include <sqlite3.h>

// SELECTのコールバック関数
static int SelectCallbackFunc(void* option, int columnCount, char** columnValues, char** columnNames) {
    for(int i = 0; i < columnCount; ++i) {
        printf("| %s %s |", columnNames[i], columnValues[i]);
    }
    printf("\n");
    return 0;
}

// SQL文の実行
int ExecSQL(sqlite3* db, const char* sql, sqlite3_callback cb) {
    char* pStr = NULL;

    if(sqlite3_exec(db, sql, cb, NULL, &pStr) != SQLITE_OK) {
        fprintf(stderr, "Error %s %d: %s %s\n", __FILE__, __LINE__, pStr, sql);
        return -1;
    }
    return 0;
}

int main(int argc, char* argv[]) {
    sqlite3* pDB = NULL;

    const char* fname = ":memory:";     // メモリに作成
//  const char* fname = "data.db";      // ファイルに作成

    // DBを開く
    if(sqlite3_open(fname, &pDB)) {
        fprintf(stderr, "Error %s %d: %s\n", __FILE__, __LINE__, sqlite3_errmsg(pDB));
        sqlite3_close(pDB);
        return -1;
    }

    // テーブルの作成 RTreeを使用
    ExecSQL(pDB, "CREATE VIRTUAL TABLE tbl_index USING rtree( id, minX, maxX, minY, maxY, minZ, maxZ );", NULL);

    // テーブルにデータを追加
    ExecSQL(pDB, "INSERT INTO tbl_index VALUES( 1, -100.0, -50.0, 30.0, 50.0, -50.0, -20.0 );", NULL);
    ExecSQL(pDB, "INSERT INTO tbl_index VALUES( 2, -50.0, -10.0, 30.0, 31.35, -50.0, -40.0 );", NULL);
    ExecSQL(pDB, "INSERT INTO tbl_index VALUES( 3, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );", NULL);
    ExecSQL(pDB, "INSERT INTO tbl_index VALUES( 4, 100.0, 110.0, 40.0, 56.2, -50.0, -20.0 );", NULL);
    ExecSQL(pDB, "INSERT INTO tbl_index VALUES( 5, 112.0, 119.0, 35.0, 36.51, 10.0, 18.0 );", NULL);

    // データの検索
    ExecSQL(pDB, "SELECT id FROM tbl_index WHERE minX>=100.0 AND maxX<=110.0;", SelectCallbackFunc);
    ExecSQL(pDB, "SELECT id FROM tbl_index WHERE minX>=-5.0 AND maxX<=5.0 AND minZ>=-5 AND minZ<=5;", SelectCallbackFunc);
    ExecSQL(pDB, "SELECT id FROM tbl_index WHERE minX>=150.0;", SelectCallbackFunc);

    // DBを閉じる
    sqlite3_close(pDB);

    return 0;
}

実行結果
| id 4 |
| id 3 |

2012年1月26日木曜日

MAXScript ノードの列挙


g_tabnum = 0    -- タブ数

-- タブ文字列を取得する num: タブ数
fn GetTab num = 
(
 t = ""
 for i = 1 to num do
 (
  t += "\t"
 )
 return t
)

-- 再帰関数でノードを列挙する
fn EnumNode n =
(
 t = GetTab g_tabnum
 g_tabnum += 1
 
 for n in n.children do
 (
  -- クラス名の取得
  cname = getClassName n
--  format "%className: %\n" t cname
  if cname == "Bone" then
  (
   -- ボーン名を出力する
   format "%boneName: %\n" t n.name
  )
  
  EnumNode n  -- 再帰処理
 )
 g_tabnum -= 1
)

-- ノードの列挙
EnumNode rootNode

MAXScript ファイルにバイナリ形式のデータを書き出す


-- Floatの大きな値
BIG_FLOAT = 1.0e32

-- AABB
struct AABB
(
 vMin,
 vMax
)

-- AABBを取得
fn GetAABB =
(
 local v = AABB()
 v.vMin = [ BIG_FLOAT, BIG_FLOAT, BIG_FLOAT ]
 v.vMax = [-BIG_FLOAT, -BIG_FLOAT, -BIG_FLOAT]
 return v
)

-- binStreamにPoint3を書き込む
fn WritePoint3 bstream v =
(
 WriteFloat bstream v.x
 WriteFloat bstream v.y
 WriteFloat bstream v.z
)

-- ファイルにAABBの値を書き込む
fn WriteAabbToFile filePath aabb =
(
 file = fopen filePath "wb"
 
 WritePoint3 file aabb.vMin
 WritePoint3 file aabb.vMax 
 
 fclose file
)


-- ファイルにデータを書き込むテスト
fname = "test.bin"   -- ファイル名
fdir = (GetDir #export)  -- ファイルを書き込むディレクトリ

fpath = fdir + "\\" + fname

aabb = GetAABB()

aabb.vMin.x = 8.0
aabb.vMax.z = 0.0

WriteAabbToFile fpath aabb

2012年1月25日水曜日

MAXScript ルートボーンの移動アニメを変更してみる


/*
    トラック内のキーの値を変更してみるテスト
 */
fn Test_TrackView =
(
 format "Test start\n"

 -- トラック選択ダイアログを表示する
 theInt = 0    -- ダイアログのオプション用変数
 theInt = bit.set theInt 1 true       --animated tracks only
-- theInt = bit.set theInt 3 true       --display selected nodes only

 -- Track View Pick Dialogを表示
 tvp = trackview.pickTrackDlg options:theInt

 if tvp == undefined then return undefined

 -- 選択ノードのsubAnimを取得
 a = tvp.anim 
 if a == undefined  then return undefined


 -- Transformを選択してOKクリックだと3 Transform/Positionを選択した場合0
 format "a.numSubs %\n" a.numSubs -- 選択ノードの子ノード数が返った

 for i = 1 to a.numSubs do
 (
  -- 子ノードの名前の取得
  n =  getSubAnimName a i
  format "name %\n" n

  -- コントローラーの取得
  c = a[i].Controller
  if c != undefined  then
  (
   -- コントローラーからキーの配列を取得
   k = c.keys
   --kp = k[#position]      -- ERROR
   --format "kp %\n" kp[3].value

   format "k.count %\n" k.count   -- キーフレーム数が返った

   -- MAXKey
   --format "MaxKey %\n" k[2]

   --if n == "#position" then
--   if 0 == stricmp n "#position" then  -- 実行されない
   if 0 == stricmp n "position" then  -- #がいらない
   (
    format "POSITION\n"
    -- 移動アニメを無効にしてみるテスト  変更できた
    for j = 1 to k.count do
    (
     k[j].value.z = 0.0
    )
   )

   format "key value %\n" k[2].value  -- キーの値が出力された
  )
 )

 format "tvp.name %\n" tvp.name  -- 選択したオブジェクトの名前?

 format "tvp.subNum %\n" tvp.subNum -- subAnimの数

 format "Test end\n"
)

-- Test関数の実行
Test_TrackView()


Unity キーフレームアニメ


 // 空のアニメーションカーブを作成
 AnimationCurve animCurve = new AnimationCurve();

 // キーフレームの追加
 animCurve.AddKey( new Keyframe(0.0f, 1.0f) );
 animCurve.AddKey( new Keyframe(2.0f, 0.1f) );

 // アニメーションカーブの値を取得
 print(animCurve.Evaluate(0.0f)); // 1.0
 print(animCurve.Evaluate(1.25f)); // 0.3847657
 print(animCurve.Evaluate(2.0f)); // 0.1
 print(animCurve.Evaluate(2.5f)); // 0.1


KeyframeのinTangentとoutTangentの値は0