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
0 件のコメント:
コメントを投稿