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年12月20日木曜日
3D画像ビューア サンプル
2007年7月27日金曜日
円柱のHSV色空間
#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



