hinekure.net が http://hspdev-wiki.net/ から自動クローリングした結果を表示しています。画像やリソースなどのリンクが切れています。予めご了承ください。 |
3Dモデルを表示するJavaアプレットの作成
http://codezine.jp/a/article/aid/38.aspx
三谷 純著
3Dの表示原理の勉強のため、上のソースをHSPに書き直してみました。
流用は問題なしとのことで、汚いスクリプトですが公開してみます 。
仕組みはリンクをたどって下さい。java読めるならリンク先の方が読みやすいです。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123#module//モデルデータの初期化#deffunc modelInitvertex_data(0,0) = -1,0,0vertex_data(0,1) = 0,1,0vertex_data(0,2) = 0,0,-1vertex_data(0,3) = 1,0,0vertex_data(0,4) = 0,0,1vertex_data(0,5) = 0,-1,0face_data(0,0) = 1,4,2face_data(0,1) = 1,0,4face_data(0,2) = 1,2,0face_data(0,3) = 3,2,4face_data(0,4) = 0,5,4face_data(0,5) = 4,5,3face_data(0,6) = 3,5,2face_data(0,7) = 2,5,0return//face_data読み出し#defcfunc face int p1, int p2re = face_data(p2,p1)return re//vertex_data読み出し#defcfunc vertex int p1, str p2if p2 = "x" {xyz = 0}else:if p2 = "y" {xyz = 1}else{xyz = 2}re = vertex_data(xyz, p1)return double(re)//配列サイズ読み出し#defcfunc arraySize str p1if p1 = "vertex" {re = length2(vertex_data)}else:if p1 = "face" {re = length2(face_data)}return re#global#define PI 3.14159265*initmodelInit //モデルデータの初期化center_x = ginfo(12) / 2 //中心座標center_y = ginfo(13) / 2scale = ginfo(12) / 4 //描画の大きさtheta = 0.0 //x軸の回転角phi = 0.0 //y軸の回転角mouseLog_x = 0.0mouseLog_y = 0.0dim ry, arraySize("vertex")//==================// MAIN*maingosub *setScreenPosrepeatredraw 0//----------------------if key & 256 : gosub *mouseClickkeyLog = keygosub *drawImage//----------------------redraw 1wait 1loop*mouseClickif 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.01phi += (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 *setScreenPosreturn*drawImagerepeat arraySize("face")i = cntrepeat 3x0 = center_x + rx(face(i,cnt)) * scaley0 = center_y - ry(face(i,cnt)) * scalex1 = center_x + rx(face(i,(cnt+1)\3)) * scaley1 = center_y - ry(face(i,(cnt+1)\3)) * scalelooploopreturn*setScreenPosrepeat 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)loopreturn
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242#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 d3x = d1 : y = d2 : z = d3return#modfunc _getRotXreturn x*cos(theta) + z*sin(theta)#modfunc _getRotYreturn x * sin(phi) * sin(theta) + y * cos(phi) - z * sin(phi) * cos(theta)#modfunc _getRotZreturn -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 d2phi = limitf(d2, -PI/2, PI/2)theta = d1return#deffunc _setScale double d1if d1 {scale = d1} else {scale = 0.8 * ginfo_winx / 2}return// 角度・倍率に加算#deffunc addArgs double d1, double d2phi = limitf(phi + d2, -PI/2, PI/2)theta += d1return#deffunc addScale double d1scale = limitf(scale + d1, 10.0, 200)return// 中心座標と角度・倍率の初期化#deffunc vInitcenterX = ginfo_winx / 2centerY = ginfo_winy / 2setArgs : setScalereturn#global// **[end of VertexModule]********************************************// **[↓FaceModule]***************************************************#module FaceModule vertex, z, nx, ny, nz// 面を登録#modinit var v1, var v2, var v3vertex = v1, v2, v3return// 面の重心の奥行き と 法線ベクトルを再計算#modfunc renewDataz = 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_yny = v1_v0_z * v2_v0_x - v1_v0_x * v2_v0_znz = v1_v0_x * v2_v0_y - v1_v0_y * v2_v0_xlen = sqrt(nx*nx + ny*ny + nz*nz)nx /= len : ny /= len : nz /= lenreturn// i5番目の辺の画面上の座標を返す#modfunc getLine var v1, var v2, var v3, var v4, int i5v1 = getScreenX(vertex(i5))v2 = getScreenY(vertex(i5))v3 = getScreenX(vertex((i5 + 1) \ 3))v4 = getScreenY(vertex((i5 + 1) \ 3))return// 面を構成する頂点の画面上座標を配列に格納して返す#modfunc getPoints array v1repeat 3v1(cnt * 2) = getScreenX(vertex(cnt)), getScreenY(vertex(cnt))loopreturn// 重心のZ座標を返す関数#modfunc _getZofFacereturn z#defcfunc getZofFace var modVar_getZofFace modVar : return refdval// 法線ベクトルのZ座標を返す関数#modfunc _getNormalZofFacereturn nz#defcfunc getNormalZofFace var modVar_getNormalZofFace modVar : return refdval#global// **[end of FaceModule]**********************************************// **[↓Draw3dModule]*************************************************#module Draw3dModule// 初期化(各種変数の準備)#deffunc init3dvInitCreatePen 0, 1, 0x000000hPen = statSelectObject hDC, hPendim arr, NUM_OF_FACESdim iPoint, NUM_OF_VERTICESreturn#deffunc drawModel array vertices, array faces, local x0, local x1, local y0, local y1i = 0foreach(faces)renewData faces(cnt)arr(i) = int(getZofFace(faces(cnt)) * 1000) // sortvalが実数を扱えないため、整数に変換i++loopsortval@ arr, 0foreach(arr)sortget@ i, cnt// 塗りつぶし&線の描画nz = getNormalZofFace(faces(i))if nz < 0 : continuegetPoints faces(i), iPointCreateSolidBrush ginfo_r | (ginfo_g << 8) | (ginfo_b << 16)hBrush = statSelectObject hDC, hBrushPolygon hDC, varptr(iPoint), 3DeleteObject hBrushloopreturn#deffunc _creanUp onexitDeleteObject hPenreturn#global// **[end of Draw3dModule]********************************************// **[↓メインスクリプト]*********************************************// 各種初期化init3d // モジュールの初期化title "3Dモデルを表示する"gosub *set // 点と面の登録needToDraw = 1 // 描画フラグ:まず最初は描画する必要がある*maingosub *draggosub *drawawait 10goto *main*dragif key & 256 {if draging {getkey shiftIsPushed, 16if shiftIsPushed { // Shiftを押した状態では倍率の変更addScale 1.0 * (ginfo(1) - logY)} else { // 押していない時は回転addArgs 0.01 * (ginfo(0) - logX), 0.01 * (ginfo(1) - logY)}} else {needToDraw = 1draging = 1}logX = ginfo(0) : logY = ginfo(1)} else {draging = 0}return*drawif needToDraw {// 描画する必要があるときのみ実行redraw 0drawModel vertices, facesredraw 1if draging == 0 : needToDraw = 0}return*setreturn