hinekure.net が http://hspdev-wiki.net/ から自動クローリングした結果を表示しています。画像やリソースなどのリンクが切れています。予めご了承ください。
3Dモデル表示 - HSP開発wiki
トップ    編集凍結 差分バックアップ添付複製名前変更リロード   新規一覧単語検索最終更新   最終更新のRSS

小ワザ#b74199c7

3Dモデルの表示

3Dモデルを表示するJavaアプレットの作成
http://codezine.jp/a/article/aid/38.aspx
三谷 純著

aahe2.png

3Dの表示原理の勉強のため、上のソースをHSPに書き直してみました。
流用は問題なしとのことで、汚いスクリプトですが公開してみます [ojigi]
仕組みはリンクをたどって下さい。java読めるならリンク先の方が読みやすいです。

スクリプト

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#module
//モデルデータの初期化
#deffunc modelInit
dim vertex_data, 3, 6
vertex_data(0,0) = -1,0,0
vertex_data(0,1) = 0,1,0
vertex_data(0,2) = 0,0,-1
vertex_data(0,3) = 1,0,0
vertex_data(0,4) = 0,0,1
vertex_data(0,5) = 0,-1,0
 
dim face_data, 3, 8
face_data(0,0) = 1,4,2
face_data(0,1) = 1,0,4
face_data(0,2) = 1,2,0
face_data(0,3) = 3,2,4
face_data(0,4) = 0,5,4
face_data(0,5) = 4,5,3
face_data(0,6) = 3,5,2
face_data(0,7) = 2,5,0
return
//face_data読み出し
#defcfunc face int p1, int p2
re = face_data(p2,p1)
return re
//vertex_data読み出し
#defcfunc vertex int p1, str p2
if p2 = "x" {
xyz = 0
}else:if p2 = "y" {
xyz = 1
}else{
xyz = 2
}
re = vertex_data(xyz, p1)
return double(re)
//配列サイズ読み出し
#defcfunc arraySize str p1
if p1 = "vertex" {
re = length2(vertex_data)
}else:if p1 = "face" {
re = length2(face_data)
}
return re
#global
 
#define PI 3.14159265
 
*init
modelInit //モデルデータの初期化
center_x = ginfo(12) / 2 //中心座標
center_y = ginfo(13) / 2
scale = ginfo(12) / 4 //描画の大きさ
theta = 0.0 //x軸の回転角
phi = 0.0 //y軸の回転角
mouseLog_x = 0.0
mouseLog_y = 0.0
dim rx, arraySize("vertex") //計算後の頂点座標
dim ry, arraySize("vertex")
//==================
// MAIN
*main
gosub *setScreenPos
repeat
//----------------------
color 255,255,255 : boxf
stick key, 256+512, 1 //左(256 右(512 のクリックに対応
if key & 256 : gosub *mouseClick
keyLog = key
gosub *drawImage
//----------------------
wait 1
loop
 
*mouseClick
if keyLog = 0 {
// mouseLogの更新
mouseLog_x = double(ginfo(0))
mouseLog_y = double(ginfo(1))
}
if key & 512 {
// scaleの変更
scale += ginfo(0) - mouseLog_x
}else{
//回転角の更新
theta += (double(ginfo(0)) - mouseLog_x) * 0.01
phi += (double(ginfo(1)) - mouseLog_y) * 0.01
 
// phiの範囲指定
if phi >= PI/2 {
phi = PI/2
}else:if phi <= (PI*-1)/2{
phi = (PI*-1)/2
}
}
// mouseLogの更新
mouseLog_x = double(ginfo(0))
mouseLog_y = double(ginfo(1))
 
gosub *setScreenPos
 
return
*drawImage
repeat arraySize("face")
i = cnt
repeat 3
x0 = center_x + rx(face(i,cnt)) * scale
y0 = center_y - ry(face(i,cnt)) * scale
x1 = center_x + rx(face(i,(cnt+1)\3)) * scale
y1 = center_y - ry(face(i,(cnt+1)\3)) * scale
color 0,0,0 : line x0, y0, x1, y1
loop
loop
return
*setScreenPos
repeat arraySize("vertex")
// 回転後の座標値
rx(cnt) = vertex(cnt, "x")*cos(theta) + vertex(cnt, "z")*sin(theta)
ry(cnt) = vertex(cnt, "x")*sin(phi)*sin(theta) + vertex(cnt, "y")*cos(phi) - vertex(cnt, "z")*sin(phi)*cos(theta)
loop
return

スクリプト(モジュール変数Ver.)ellerさん

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#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
 
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 {
// 描画する必要があるときのみ実行
color 255, 255, 255 : boxf
drawModel vertices, faces
if draging == 0 : needToDraw = 0
}
return
 
*set
newmod vertices, vertexModule, -1, 0, 0
newmod vertices, vertexModule, 0, 1, 0
newmod vertices, vertexModule, 0, 0, -1
newmod vertices, vertexModule, 1, 0, 0
newmod vertices, vertexModule, 0, 0, 1
newmod vertices, vertexModule, 0, -1, 0
 
newmod faces, faceModule, vertices(1), vertices(4), vertices(2)
newmod faces, faceModule, vertices(1), vertices(0), vertices(4)
newmod faces, faceModule, vertices(1), vertices(2), vertices(0)
newmod faces, faceModule, vertices(3), vertices(2), vertices(4)
newmod faces, faceModule, vertices(0), vertices(5), vertices(4)
newmod faces, faceModule, vertices(4), vertices(5), vertices(3)
newmod faces, faceModule, vertices(3), vertices(5), vertices(2)
newmod faces, faceModule, vertices(2), vertices(5), vertices(0)
return

コメント

  • javaのソースを書き直すのは、結構大変ですね。。オブジェクト指向のすごさが身にしみます [sad2] -- Charlotte 2007-05-06 (日) 15:48:06
  • これは面白いですね。モジュール変数を利用できないか試してみます。 -- eller 2007-05-06 (日) 19:40:59
  • STEP4まで移植してみました。GDIの勉強もできて楽しかったです [bsmile2]
    UPして益になるかは不明ですが、とりあえずUPしておきます↓(行数約2倍です…)
    モジュール変数を使えばオブジェクト指向もそこそこ実現できるみたいです。メソッドの書き方が不自然ですが……。 -- eller 2007-05-07 (月) 21:00:00
  • ほむほむ [bsmile2] モジュール変数なるものができたんですか!今知りました。。ちょっとクラスに似てるのかなぁ便利そうです
    モジュール変数利用版も隠してないで上に載せときましょっ [smile4] -- Charlotte 2007-05-08 (火) 00:55:42
  • ハッ!目立つトコに移されている!? [a] しかも名前付きですか。完全な移植ではないし見づらいし、ちょっと緊張します。 [rajya]
    モジュール変数はモジュールをクラスに見立てるとするとインスタンス変数のようなもの…だと思います。hsp3/モジュール変数とかを参考にさせていただきました。 -- eller 2007-05-08 (火) 06:03:15
トップ    編集凍結 差分バックアップ添付複製名前変更リロード   新規一覧単語検索最終更新   最終更新のRSS
Last-modified: 2007-07-05 (木) 03:01:41 (2348d)