ラベル 3D の投稿を表示しています。 すべての投稿を表示
ラベル 3D の投稿を表示しています。 すべての投稿を表示

2007年12月20日木曜日

3D画像ビューア サンプル

Flashなどでありそうな3Dの画像ビューア。のサンプル。
マウスのホイールに連動して回転します。
#include "d3m.hsp"
#include "hspmath.as"
#const TILE_NUM 16
#const SHIFT_TURN 5
#const BUFFER_WIDTH 200
#const BUFFER_HEIGHT 200

    // タイルを表示するための配列変数
    tile_x = 100, 300, 300, 100
    tile_y =   0,   0,   0,   0
    tile_z = 200, 200,   0,   0

    // タイル用のバッファを作成
    repeat TILE_NUM, 1
        buffer cnt, BUFFER_WIDTH, BUFFER_HEIGHT
        color , 255 : boxf
        color 255, 255, 255
        font msgothic, 32, font_bold
        mes cnt
    loop

    // メイン画面の初期化・カメラ設定
    screen 0, 240, 200, screen_normal
    title "ホイールで回転"
    d3setcam -250,-300,100, 250,0,100

    // 各種初期化作業
    gmode GMODE_ALPHA, , , 128
    theta_shift = 0.0                   // タイルの回転量
    theta_add = 0.0                     // タイルの角速度
    moving = 0                          // 回転中フラグ
    need_to_draw = 1                    // 描画フラグ

// ★メインループ
*main
    gosub *move
    gosub *draw
    wait 5
    goto *main

// 移動計算
*move
    mw = mousew
    if moving > 0 {
        // 移動中
        moving--
        theta_shift += theta_add
    } else : if mw != 0 {
        // 静止中かつホイールが動いたとき
        moving = SHIFT_TURN             // SHIFT_TURN回動く
        need_to_draw = 1                // 描画フラグON

        // 角速度を決定
        theta_add = M_PI * 2.0 * sgn(mw) / SHIFT_TURN / TILE_NUM
    }
    return

// 描画処理
*draw
    if need_to_draw == 0 : return
    if moving == 0 : need_to_draw = 0

    redraw 0
    color : boxf

    vect_x = cos(theta_shift)
    vect_y = sin(theta_shift)
    // 2.0 * M_PI / TILE_NUMだけ角度(位置)を変えながら、タイルをTILE_NUM個描画
    repeat TILE_NUM
        d3rotate vect_x, vect_y, vect_x, vect_y, 2.0 * M_PI / TILE_NUM
        d3setlocal 0,0,0, vect_x,vect_y,0, -vect_y,vect_x,0, 0,0,1
        d3texture tile_x, tile_y, tile_z, cnt + 1, 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT, 1
    loop

    redraw 1
    return

2007年7月27日金曜日

円柱のHSV色空間


最近文字列ばかりだったので、一息入れる意味で3D。

奥行きの計算は厳密なものではなく近似したものです。

#include "d3m.hsp"
#include "hspda.as"

#const H_MAX      12
#const S_MAX      4
#const V_MAX      7
#const PANEL_MAX  H_MAX * S_MAX * V_MAX
#const PANEL_SIZE 150                   // パネル一辺の長さ
#const PANEL_DIST 200                   // 同じ角度上のパネル同士の距離(左下の座標の間)
#const OBSERVER_R 2000                  // 観測者の中心からの距離

#const double PI        3.1415
#const double ANG_SPEED 0.04            // 観測者の角速度

    ct = 0.0
    d3setcam OBSERVER_R, 0, V_MAX * 100,  0, 0, V_MAX * 100

*init
    dim  panel_h,   PANEL_MAX : dim  panel_s,   PANEL_MAX : dim  panel_v,   PANEL_MAX  // 色(HSV指定)
    dim  panel_r,   PANEL_MAX : ddim panel_t,   PANEL_MAX : dim  panel_z,   PANEL_MAX  // パネルの位置 円柱座標系(パネルの左下の座標)
    ddim panel_far, PANEL_MAX   // 奥行き

    repeat H_MAX : cnt1 = cnt
        h = 191 * cnt / H_MAX                       // HSV の H
        t = PI * 2.0 * cnt / H_MAX                  // 角度
        repeat S_MAX : cnt2 = cnt
            s = 256 * cnt / S_MAX                   // HSV の S
            r = cnt * PANEL_DIST + PANEL_DIST / 2   // 中心からの距離
            repeat V_MAX
                v = 256 * cnt / V_MAX               // HSV の V

                i = cnt1 * S_MAX * V_MAX + cnt2 * V_MAX + cnt
                panel_h( i ) = h : panel_s( i ) = s : panel_v( i ) = v
                panel_r( i ) = r : panel_t( i ) = t : panel_z( i ) = cnt * PANEL_DIST
            loop
        loop
    loop
    observer_t = 0.0

*main
    gosub *calc
    gosub *draw
    wait 2
    goto *main

*calc
    // 観測者の回転
    observer_t += ANG_SPEED
    if ( PI * 2.0 < observer_t ) : observer_t -= PI * 2.0
    d3setlocal 0,0,0, cos( observer_t ),sin( observer_t ),0, -sin( observer_t ),cos( observer_t ),0, 0,0,1

    // 奥行きを計算。遠くにあるものほどpanel_farは小さくなる
    repeat PANEL_MAX
        panel_far( cnt ) = cos( panel_t( cnt ) - observer_t ) * panel_r( cnt )
    loop
    // 小さい順(昇順)に並べ替え
    sortval panel_far, 0
    return

*draw
    redraw 0
    hsvcolor 0, 0, ( sin( observer_t )  + 1.0 ) * 128 : boxf
    repeat PANEL_MAX
        sortget i, cnt // 奥から数えてcnt番目のパネルのインデックス
        x = cos( panel_t( i ) ) * panel_r( i ), cos( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), cos( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), cos( panel_t( i ) ) * panel_r( i )
        y = sin( panel_t( i ) ) * panel_r( i ), sin( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), sin( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), sin( panel_t( i ) ) * panel_r( i )
        z = panel_z( i ) + PANEL_SIZE, panel_z( i ) + PANEL_SIZE, panel_z( i ), panel_z( i )
        hsvcolor panel_h( i ), panel_s( i ), panel_v( i )
        d3square x, y, z
    loop
    redraw 1
    return

2007年7月16日月曜日

波紋のエフェクト(3次元ver.)

d3moduleを利用した波紋のエフェクトの3次元版。波の高さによって明るさが変わるようにもなっています。
#include "d3m.hsp"
#define  ctype round(%1) double(strf("%%0.0f", %1)) // 四捨五入(hspmathより抜粋)
#const   CONST_A     0.1 // 定数その1。波長を決定付ける。
#const   CONST_B     7   // 定数その2。屈折の程度を決定付ける。

    buffer 1
    onclick goto *start

*start
    onclick 0
    dialog "jpg;*.gif;*.bmp", 16
    if stat == 0 : end
    gsel 1 : picload refstr
    sizeX = ginfo_winx
    sizeY = ginfo_winy
    centerX = ginfo_winx / 2
    centerY = ginfo_winy / 2

    screen 0, sizeX, sizeY, SCREEN_NORMAL
    gmode GMODE_GDI, sizeX, sizeY
    gcopy 1, 0, 0
    d3setcam sizeX/2, -300, sizeY/4, sizeX/2, 0, sizeY/2
    redraw 0
    boxf
    gmode GMODE_MEM, 1, 1
    repeat sizeY : targetY = cnt
        title "変換中…" + str(100 * cnt / sizeY) + "%"
        repeat sizeX : targetX = cnt
            // 中心から見た座標を算出。
            d3getpos vx, vy, targetX, 0, targetY
            dx = vx - centerX
            dy = centerY -vy

            // 中心から見た角度と距離を算出。
            theta = atan(dy, dx)
            dist  = sqrt(dx * dx + dy * dy)

            // ここがポイント。sinで屈折する距離を決めています。
            // ラスタースクロールのスクリプトのほうが分かりやすいかもしれません。
            copyX = centerX + round(cos(theta) * (dist + sin(dist * CONST_A) * CONST_B))
            copyY = centerY + round(sin(theta) * (dist + sin(dist * CONST_A) * CONST_B))

            pos targetX, targetY
            gmode GMODE_ALPHA, 1, 1, absf(sin(dist * CONST_A)) * 64 + 192
            gcopy 1, copyX, copyY
        loop
        await 10
    loop
    redraw 1
    title "変換終了 - クリックで再開"
    onclick 1
    stop

2007年5月8日火曜日

3Dモデルの表示

3Dモデルの表示。
CODEZINEを参考にHSP3へ移植させていただきました。

参考




3Dモデルファイル :
v 0.0 1.0 0.0
v 0.7 -1.0 0.7
v 1.0 -1.0 0.0
v 0.7 -1.0 -0.7
v 0.0 -1.0 -1.0
v -0.7 -1.0 -0.7
v -1.0 -1.0 0.0
v -0.7 -1.0 0.7
v 0.0 -1.0 1.0
v 0.0 -1.0 0.0
f 1 2 3
f 1 3 4
f 1 4 5
f 1 5 6
f 1 6 7
f 1 7 8
f 1 8 9
f 1 9 2
f 10 3 2
f 10 4 3
f 10 5 4
f 10 6 5
f 10 7 6
f 10 8 7
f 10 9 8
f 10 2 9
#include "hspda.as"
#include "gdi32.as"

#const global NUM_OF_VERTICES   6       // 頂点の数
#const global NUM_OF_FACES      8       // 面の数
#const global PI                3.14159 // 円周率

// **[↓VertexModule]*************************************************

#module VertexModule x, y, z
// 頂点の登録
#modinit double d1, double d2, double d3
    x = d1 : y = d2 : z = d3
    return

#modfunc _getRotX
    return x*cos(theta) + z*sin(theta)
#modfunc _getRotY
    return x * sin(phi) * sin(theta) + y * cos(phi) - z * sin(phi) * cos(theta)
#modfunc _getRotZ
    return -x * cos(phi) * sin(theta) + y * sin(phi) + z * cos(phi) * cos(theta)
// 回転後の頂点座標を返す関数群
#defcfunc getRotX var modVar
    _getRotX modVar : return refdval
#defcfunc getRotY var modVar
    _getRotY modVar : return refdval
#defcfunc getRotZ var modVar
    _getRotZ modVar : return refdval
// 画面上の頂点座標を返す関数群
#defcfunc getScreenX var modVar
    _getRotX modVar : return int( refdval * scale + centerX)
#defcfunc getScreenY var modVar
    _getRotY modVar : return int(-refdval * scale + centerY)

// 角度・倍率を設定
#define global setArgs(%1 = 0, %2 = 0) _setArgs %1, %2
#define global setScale(%1 = 0) _setScale %1
#deffunc _setArgs double d1, double d2
    phi = limitf(d2, -PI/2, PI/2)
    theta = d1
    return
#deffunc _setScale double d1
    if d1 {
        scale = d1
    } else {
        scale = 0.8 * ginfo_winx / 2
    }
    return

// 角度・倍率に加算
#deffunc addArgs double d1, double d2
    phi = limitf(phi + d2, -PI/2, PI/2)
    theta += d1
    return
#deffunc addScale double d1
    scale = limitf(scale + d1, 10.0, 200)
    return

// 中心座標と角度・倍率の初期化
#deffunc vInit
    centerX = ginfo_winx / 2
    centerY = ginfo_winy / 2
    setArgs : setScale
    return
#global

// **[end of VertexModule]********************************************

// **[↓FaceModule]***************************************************

#module FaceModule vertex, z, nx, ny, nz
// 面を登録
#modinit var v1, var v2, var v3
    vertex = v1, v2, v3
    return

// 面の重心の奥行き と 法線ベクトルを再計算
#modfunc renewData
    z = getRotZ(vertex(0)) + getRotZ(vertex(1)) + getRotZ(vertex(2))

    v1_v0_x = getRotX(vertex(1)) - getRotX(vertex(0))
    v1_v0_y = getRotY(vertex(1)) - getRotY(vertex(0))
    v1_v0_z = getRotZ(vertex(1)) - getRotZ(vertex(0))
    v2_v0_x = getRotX(vertex(2)) - getRotX(vertex(0))
    v2_v0_y = getRotY(vertex(2)) - getRotY(vertex(0))
    v2_v0_z = getRotZ(vertex(2)) - getRotZ(vertex(0))

    nx = v1_v0_y * v2_v0_z - v1_v0_z * v2_v0_y
    ny = v1_v0_z * v2_v0_x - v1_v0_x * v2_v0_z
    nz = v1_v0_x * v2_v0_y - v1_v0_y * v2_v0_x

    len = sqrt(nx*nx + ny*ny + nz*nz)
    nx /= len : ny /= len : nz /= len
    return

// i5番目の辺の画面上の座標を返す
#modfunc getLine var v1, var v2, var v3, var v4, int i5
    v1 = getScreenX(vertex(i5))
    v2 = getScreenY(vertex(i5))
    v3 = getScreenX(vertex((i5 + 1) \ 3))
    v4 = getScreenY(vertex((i5 + 1) \ 3))
    return

// 面を構成する頂点の画面上座標を配列に格納して返す
#modfunc getPoints array v1
    repeat 3
        v1(cnt * 2) = getScreenX(vertex(cnt)), getScreenY(vertex(cnt))
    loop
    return

// 重心のZ座標を返す関数
#modfunc _getZofFace
    return z
#defcfunc getZofFace var modVar
    _getZofFace modVar : return refdval

// 法線ベクトルのZ座標を返す関数
#modfunc _getNormalZofFace
    return nz
#defcfunc getNormalZofFace var modVar
    _getNormalZofFace modVar : return refdval
#global

// **[end of FaceModule]**********************************************

// **[↓Draw3dModule]*************************************************

#module Draw3dModule
// 初期化(各種変数の準備)
#deffunc init3d
    vInit
    CreatePen 0, 1, 0x000000
    if stat == 0 : dialog "CreatePenが失敗しました", 1 : end
    hPen = stat
    SelectObject hDC, hPen

    dim arr,    NUM_OF_FACES
    dim iPoint, NUM_OF_VERTICES
    return

#deffunc drawModel array vertices, array faces, local x0, local x1, local y0, local y1
    i = 0
    foreach(faces)
        renewData faces(cnt)
        arr(i)  = int(getZofFace(faces(cnt)) * 1000)         // sortvalが実数を扱えないため、整数に変換
        i++
    loop

    color
    sortval@ arr, 0
    foreach(arr)
        sortget@ i, cnt
        // 塗りつぶし&線の描画
        nz = getNormalZofFace(faces(i))
        if nz < 0 : continue

        getPoints faces(i), iPoint

        hsvcolor 76, 128, nz * 255
        CreateSolidBrush ginfo_r | (ginfo_g << 8) | (ginfo_b << 16)
        if stat == 0 : dialog "CreateSolidBrushが失敗しました", 1 : end
        hBrush = stat
        SelectObject hDC, hBrush
        Polygon hDC, varptr(iPoint), 3
        DeleteObject hBrush
    loop
    return

#deffunc _creanUp onexit
    DeleteObject hPen
    return
#global

// **[end of Draw3dModule]********************************************

// **[↓メインスクリプト]*********************************************

    // 各種初期化
    screen 0, 300, 300
    init3d                              // モジュールの初期化
    title "3Dモデルを表示する"

    dimtype vertices, 5, NUM_OF_VERTICES// 頂点(モジュール変数)を格納する配列を宣言
    dimtype faces,    5, NUM_OF_FACES   // 面(モジュール変数)を格納する配列を宣言

    gosub *set                          // 点と面の登録
    needToDraw = 1                      // 描画フラグ:まず最初は描画する必要がある

*main
    gosub *drag
    gosub *draw
    await 10
    goto *main

*drag
    stick key, 256, 1
    if key & 256 {
        if draging {
            getkey shiftIsPushed, 16
            if shiftIsPushed {          // Shiftを押した状態では倍率の変更
                addScale 1.0 * (ginfo(1) - logY)
            } else {                    // 押していない時は回転
                addArgs 0.01 * (ginfo(0) - logX), 0.01 * (ginfo(1) - logY)
            }
        } else {
            needToDraw = 1
            draging = 1
        }
        logX = ginfo(0) : logY = ginfo(1)
    } else {
        draging = 0
    }
    return

*draw
    if needToDraw {
        // 描画する必要があるときのみ実行
        redraw 0
        color 255, 255, 255 : boxf
        drawModel vertices, faces
        redraw 1
        if draging == 0 : needToDraw = 0
    }
    return

*set
    dialog "txt", 16, "3Dモデルデータ(wavefront objフォーマット)"
    if stat == 0 : end
    fileName = refstr
    notesel data
    noteload fileName
    sdim prm, 16, 3

    repeat notemax
        noteget sLine, cnt
        i = 2
        repeat 3
            getstr prm(cnt), sLine, i, ' '
            i += strsize
        loop
        if peek(sLine, 0) == 'v' {
            newmod vertices, vertexModule, double(prm(0)), double(prm(1)), double(prm(2))
            continue
        }
        if peek(sLine, 0) == 'f' {
            newmod faces, faceModule, vertices(int(prm(0))-1), vertices(int(prm(1))-1), vertices(int(prm(2))-1)
            continue
        }
    loop
    sdim data, 4
    return