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);
}