HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2023
0803
youdaiHGIMG4で投影テクスチャシェーダーを実装したいです12解決


youdai

リンク

2023/8/3(Thu) 18:49:32|NO.99856

HGIMG4で投影テクスチャシェーダーを実装したいです。

シェーダーの方は以下のようなものでいいと思うのですが、肝心の行列部分の演算で躓いてしまいました。

u_projTextureMatrixの部分のHSP3側での演算です。

シェーダー部分

projShader.vert


// attribute attribute vec4 a_position; // uniform uniform mat4 u_worldViewProjectionMatrix; uniform mat4 u_projTextureMatrix;//この行列で投影化したい。これはプロジェクションをカメラに見立てたu_worldViewProjectionMatrixだと思う // varying varying vec4 v_projTexCoord; // main void main() { v_projTexCoord = u_projTextureMatrix * a_position; gl_Position = u_worldViewProjectionMatrix * a_position; }

projShader.frag


// sampler2D uniform sampler2D u_projTexture; // varying varying vec4 v_projTexCoord; void main() { // texture2DProjはこうやって使うのだと思うが、詳しいことは分からない gl_FragColor = texture2DProj(u_projTexture, v_projTexCoord); }

HSP3側部分

(途中まで作ったのですが、躓いてしまったので製作途中です。
 これはあくまでイメージだと思ってください。全く正しくない可能性があります)

main.hsp


#include "hgimg4.as" #define M3DMTX_PARAMETERS fov,aspect,near,far,sw,theta,divisor,factor,f_n #define M3DMTX_MATRIXS lookat_mtx,view_mtx #define M3DMTX_ETC projPos, projAng, projQuat, projScale #module mod_m3dmtx M3DMTX_PARAMETERS, M3DMTX_MATRIXS, M3DMTX_ETC ;gpcameraのfov,aspect,near,far,swと同じ。 #modinit double u_fov, double u_aspect, double u_near, double u_far, double u_sw set_viewMat thismod, u_fov, u_aspect, u_near, u_far, u_sw return ; カメラに見立てたプロジェクションの位置 #modfunc set_projPos double u_x, double u_y, double u_z projPos.0 = u_x projPos.1 = u_y projPos.2 = u_z return ; カメラに見立てたプロジェクションの回転(オイラー角) #modfunc set_projAng double u_x, double u_y, double u_z projAng.0 = u_x projAng.1 = u_y projAng.2 = u_z return ; カメラに見立てたプロジェクションの回転(クォータニオン角) #modfunc set_projQuat double u_x, double u_y, double u_z, double u_w projQuat.0 = u_x projQuat.1 = u_y projQuat.2 = u_z projQuat.3 = u_w return ; カメラに見立てたプロジェクションのスケール #modfunc set_proScale double u_x, double u_y, double u_z projScale.0 = u_x projScale.1 = u_y projScale.2 = u_z return ; オイラー角版 #modfunc set_worldMat array u_pos, array u_ang, array u_scale set_projPos thismod, u_pos.0, u_pos.1, u_pos.2 set_projAng thismod, u_ang.0, u_ang.1, u_ang.2 set_projScale thismod, u_scale.0, u_scale.1, u_scale.2 return ; クォータニオン角版 #modfunc set_worldMat array u_pos, array u_quat, array u_scale set_projPos thismod, u_pos.0, u_pos.1, u_pos.2 set_projQuat thismod, u_quat.0, u_quat.1, u_quat.2, u_quat.3 set_projScale thismod, u_scale.0, u_scale.1, u_scale.2 ; ここでワールドマトリックスの計算をするつもりだった return #modfunc set_projectionMat ; ここで投影マトリックスの計算をするつもりだった return #modfunc set_viewMat double u_fov, double u_aspect, double u_near, double u_far, double u_sw /* ここではviewMatrixを作成している「つもり」である。 これで本当に正しいかは分からない。 githubのOpenHSP/src/hsp3dish/gameplay/src/Matrix.cppを参考にしている。 */ ; mod変数として保存する fov = u_fov aspect = u_aspect near = u_near far = u_far sw = u_sw ; float theta = MATH_DEG_TO_RAD(fieldOfView) * 0.5f; ; float divisor = tan(theta); ; float factor = 1.0f / divisor; theta = deg2rad(fov) * 0.5 divisor = tan(theta) factor = 1.0 / divisor ; float f_n = 1.0f / (zFarPlane - zNearPlane); f_n = 1.0 / ( far - near ) if sw == 0 { ; Perspective view_mtx(0, 0) = ( 1.0 / aspect ) * factor ; dst->m[0] view_mtx(1, 0) = factor ; dst->m[5] view_mtx(2, 0) = ( 0.0 - ( far + near ) ) * f_n ; dst->m[10] view_mtx(2, 1) = -1.0 ; dst->m[11] view_mtx(2, 4) = -2.0 * far * near * f_n ; dst->m[14] } else { } return #modfunc get_worldViewProjectionMatrix array u_res ; ここからworldViewProjectionMatrixを返すつもりだった return #global #const WAITTIME 1000 / 60 gosub *setup gosub *create_projTextureMatrix gosub *set_projTextureMatrix goto *main *setup screen 0, 800, 600 gpreset gpnull camera ; カメラの設定はどのようであっても構いません ; このカメラは通常のカメラであって、プロジェクション用のカメラとは関係ありません gpcamera camera,45.0, 1.333333, 0.5, 768.0, 0 gpnull model gpload model, "chara.gpb", "", "" ; modelのマテリアルIDを取得 gpnodeinfo materialID, model, GPNODEINFO_MATERIAL return *create_projTextureMatrix ddim res, 4, 4; 出力用の変数を作成する /* 投影テクスチャとは、 「テクスチャをステンドグラスのように対象オブジェクトへ投影させること(ただしテクスチャは裏表に対して貫通しているような状態)」 だと思います。 プロジェクションシェーダー用行列は、 プロジェクションの座標等をカメラに見立てた u_worldViewProjectionMatrixを使います。 プロジェクションシェーダーのシェーダーの仕組みそのものは非常に単純で、 頂点シェーダーで「v_projTexCoord = u_projTextureMatrix * a_position;」して、 フラグメントシェーダーで「gl_FragColor = texture2DProj(u_projTexture, v_projTexCoord);」するだけです。 ただし、このu_projTextureMatrixを導き出すのが大変で、 要はu_projTextureMatrixとはプロジェクションをカメラに見立てた、仮想のカメラのu_worldViewProjectionMatrixのことです。 */ ; gpcameraのfov,aspect,near,far,swと同じ。 fov = 45.0 aspect = 1.0 ; 正方形のテクスチャ near = 0.5 far = 768.0 sw = 1 ; ここでは平行カメラとする。0のパースペクティブ版も実装したい newmod ptm, mod_m3dmtx, fov, aspect, near, far, sw ; モジュールにプロジェクション用のカメラ設定を送る return *set_projTextureMatrix ; プロジェクションをカメラに見立てた色々な要素 ; この部分は実際には動的に変化するが、今回は固定する projPos = 0.0, 0.0, 0.0 ; 位置 projAng = 0.0, 0.0, 0.0 ; 回転(ここではオイラー角だが、本当はクォータニオン角の方がいい) projScale = 1.0, 1.0, 1.0 ; スケール set_projPos ptm, projPos.0, projPos.1, projPos.2 ; モジュールに位置を送る set_projAng ptm, projAng.0, projAng.1, projAng.2 ; モジュールに回転を送る set_projScale ptm, projScale.0, projScale.1, projScale.2 ; モジュールにスケールを送る ; 計算したworldViewProjectionMatrixを取得する get_worldViewProjectionMatrix ptm, res ; 取得したマテリアルIDに対してresを送る gpmatprm16 materialID, "u_projTextureMatrix", res return *main gsel 0 redraw 0 pos 0, 0 : color $40, $40, $80 : boxf gpdraw redraw 1 addang model, 0.0, 0.005, 0.0 await WAITTIME goto *main

要はu_projTextureMatrix(プロジェクションをカメラに見立てたworldViewProjectionMatrix)を得るのが
自分には難しく、躓いてしまいました。
gameplay3DのworldViewProjectionMatrixの導き方と同じにすれば問題ないと思います。

githubのOpenHSP/src/hsp3dish/gameplay/src/Matrix.cppを参考にしていたのですが、
途中からわけわからない感じになってしまって、参考にしながらでも行き詰ってしまいました。

OpenHSP/src/hsp3dish/gameplay/src/Matrix
https://github.com/onitama/OpenHSP/blob/master/src/hsp3dish/gameplay/src/Matrix.cpp

アドバイスお願い致します。



この記事に返信する


usagi

リンク

2023/8/5(Sat) 18:29:24|NO.99864

こんにちわ、一例ですがどうぞ

・projShader.vert

attribute vec4 a_position; uniform mat4 u_worldViewProjectionMatrix; uniform mat4 u_worldMatrix; uniform mat4 u_projTextureMatrix; varying vec4 v_projTexCoord; void main() { v_projTexCoord = u_projTextureMatrix * u_worldMatrix * a_position; gl_Position = u_worldViewProjectionMatrix * a_position; }
・projShader.frag

uniform vec4 u_diffuseColor; uniform sampler2D u_projTexture; varying vec4 v_projTexCoord; void main() { gl_FragColor = u_diffuseColor; // クランプはしてないので、テクスチャ幅いっぱい使うのなら必要かも gl_FragColor.rgb *= texture2DProj(u_projTexture, v_projTexCoord).rgb; }
・デモ

; 37beta6で実行(gpmatprm16はbeta4まで設定バグあるので) #include "hgimg4.as" size = 512 : sizeh = size/2 screen 0, size, size : gpreset : setcls 1, 0x888888 buf_camera = 1 : buf_proj = 2 : buf_tex = 3 buffer 1, size, size, screen_offscreen : buffer 2, size, size, screen_offscreen ; 透視投影 fov = 45.0 : aspect = 1.0 : near = 0.5 : far = 768 ; メインカメラ gpnull camera_main gpcamera camera_main, fov, aspect, near, far setpos camera_main, 10, 10, 10 gplookat camera_main, 0, 2, 0 ; プロジェクターカメラ gpnull camera_proj gpcamera camera_proj, fov, aspect, near, far ; シェーダー gpusermat mat_proj,"projShader.vert","projShader.frag","" ; テクスチャ(仮) buffer buf_tex, size, size, screen_offscreen : rgbcolor $FFFFFF : boxf x = 50,462,462,50 : y = 50,50,462,462 : c = $FF0000, $00FF00, $0000FF, $FF00FF : gsquare -257, x,y,c line 50,50,size-50,size-50 : line 50,size-50,size-50,50 gpmatprmp mat_proj,"u_projTexture", GPOBJ_ID_SRCFLAG+buf_tex ;gpmatprmt mat_proj,"u_projTexture","tex.bmp" ; テクスチャ読み込む場合 gpmatprmf mat_proj,"wrap","clamp","u_projTexture" ; モデル gpbox model_box, 2,, mat_proj : setpos model_box, ,3 gpfloor model_floor1, 10, 10,, mat_proj : setpos model_floor1, -5,5, : setangr model_floor1,,,-64 gpfloor model_floor2, 10, 10,, mat_proj gpfloor model_floor3, 10, 10,, mat_proj : setpos model_floor3, ,5,-5 : setangr model_floor3,64 gpmatprm4 model_box, "u_diffuseColor", 1,1,1,1 ; テクスチャが分かりやすいように gpmatprm4 model_floor1, "u_diffuseColor", 1,0.5,0.5,1 ; とりあえず色つけた gpmatprm4 model_floor3, "u_diffuseColor", 0.5,1.0,0.5,1; gpmatprm4 model_floor2, "u_diffuseColor", 0.5,0.5,1.0,1; ; テクスチャ座標変換用行列 mtx_t.0 = 0.5, 0.0, 0.0, 0.5; x mtx_t.4 = 0.0, 0.5, 0.0, 0.5; y mtx_t.8 = 0.0, 0.0, 1.0, 0.0; z mtx_t.12 = 0.0, 0.0, 0.0, 1.0; w *MAIN ; ここは適当に移動 getreq timer, SYSREQ_TIMER : timer=0.001*timer cam_pos = sin(timer)*4.0, 6.0, 4.0 cam_at = 0.0, 3.0, 0.0 cam_up = 0.0, 1.0, 0.0 ; ★hgimg4はY上固定 ; プロジェクターカメラの位置と向き設定 setpos camera_proj, cam_pos.0, cam_pos.1, cam_pos.2 gplookat camera_proj, cam_at.0 , cam_at.1 , cam_at.2 ; 変換行列取得 createLookAt cam_pos, cam_at, cam_up, mtx_v ; ビュー変換行列 matrixTranspose mtx_v ; ★hgimg4のlookatは行列の入れ替えをしている。 createPerspective fov, aspect, near, far, mtx_p ; プロジェクション変換行列 ; 行列を掛け合わせてシェーダーパラメーターに設定 multiplyMatrixMM mtx_v, mtx_p, mtx_vp multiplyMatrixMM mtx_vp, mtx_t, mtx_vpt gpmatprm16 model_box, "u_projTextureMatrix", mtx_vpt gpmatprm16 model_floor1, "u_projTextureMatrix", mtx_vpt gpmatprm16 model_floor2, "u_projTextureMatrix", mtx_vpt gpmatprm16 model_floor3, "u_projTextureMatrix", mtx_vpt ;プロジェクタからの見た目 ------------------- gsel buf_proj : gpusecamera camera_proj : gpdraw ;メインカメラからの見た目 ------------------- gsel buf_camera : gpusecamera camera_main : gpdraw ;スクリーン描画 gsel 0 : redraw 0 : color 255,255,255 pos 0,0 : celput buf_camera pos 0,0 : celput buf_proj,,0.4,0.4 : mes "<- Pjoecter Camera", 4 mes "u_projTextureMatrix", 4 : s = "%+1.2f, %+1.2f, %+1.2f, %+1.2f" mes strf(s, mtx_vpt.0, mtx_vpt.1, mtx_vpt.2, mtx_vpt.3 ), 4 mes strf(s, mtx_vpt.4, mtx_vpt.5, mtx_vpt.6, mtx_vpt.7 ), 4 mes strf(s, mtx_vpt.8, mtx_vpt.9, mtx_vpt.10, mtx_vpt.11), 4 mes strf(s, mtx_vpt.12, mtx_vpt.13, mtx_vpt.14, mtx_vpt.15), 4 redraw 1 : await 16 goto *MAIN ; OpenHSPのコピペです移植しただけで特に変更はしてません。(最低限必要な関数) ; 元々ある関数だから、行列関係はhgimg4に追加してくれると嬉しいですねぇ。 #module #deffunc matrixIdentity array dst dst = 1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0 return #deffunc matrixTranspose array dst t = dst.0,dst.1,dst.2,dst.3,dst.4,dst.5,dst.6,dst.7,dst.8,dst.9,dst.10,dst.11,dst.12,dst.13,dst.14,dst.15 dst = t.0,t.4,t.8,t.12,t.1,t.5,t.9,t.13,t.2,t.6,t.10,t.14,t.3,t.7,t.11,t.15 return #deffunc multiplyMatrixMM array m1, array m2, array dst dst.0 = m1.0 * m2.0 + m1.4 * m2.1 + m1.8 * m2.2 + m1.12 * m2.3 dst.1 = m1.1 * m2.0 + m1.5 * m2.1 + m1.9 * m2.2 + m1.13 * m2.3 dst.2 = m1.2 * m2.0 + m1.6 * m2.1 + m1.10 * m2.2 + m1.14 * m2.3 dst.3 = m1.3 * m2.0 + m1.7 * m2.1 + m1.11 * m2.2 + m1.15 * m2.3 dst.4 = m1.0 * m2.4 + m1.4 * m2.5 + m1.8 * m2.6 + m1.12 * m2.7 dst.5 = m1.1 * m2.4 + m1.5 * m2.5 + m1.9 * m2.6 + m1.13 * m2.7 dst.6 = m1.2 * m2.4 + m1.6 * m2.5 + m1.10 * m2.6 + m1.14 * m2.7 dst.7 = m1.3 * m2.4 + m1.7 * m2.5 + m1.11 * m2.6 + m1.15 * m2.7 dst.8 = m1.0 * m2.8 + m1.4 * m2.9 + m1.8 * m2.10 + m1.12 * m2.11 dst.9 = m1.1 * m2.8 + m1.5 * m2.9 + m1.9 * m2.10 + m1.13 * m2.11 dst.10 = m1.2 * m2.8 + m1.6 * m2.9 + m1.10 * m2.10 + m1.14 * m2.11 dst.11 = m1.3 * m2.8 + m1.7 * m2.9 + m1.11 * m2.10 + m1.15 * m2.11 dst.12 = m1.0 * m2.12 + m1.4 * m2.13 + m1.8 * m2.14 + m1.12 * m2.15 dst.13 = m1.1 * m2.12 + m1.5 * m2.13 + m1.9 * m2.14 + m1.13 * m2.15 dst.14 = m1.2 * m2.12 + m1.6 * m2.13 + m1.10 * m2.14 + m1.14 * m2.15 dst.15 = m1.3 * m2.12 + m1.7 * m2.13 + m1.11 * m2.14 + m1.15 * m2.15 return #deffunc createLookAt array eye, array target, array up, array dst fvunit up zaxis = eye.0, eye.1, eye.2 : fvsub zaxis, target.0, target.1, target.2 : fvunit zaxis xaxis = up.0, up.1, up.2 : fvouter xaxis, zaxis.0, zaxis.1, zaxis.2 : fvunit xaxis yaxis = zaxis.0, zaxis.1, zaxis.2 : fvouter yaxis, xaxis.0, xaxis.1, xaxis.2 : fvunit yaxis m12 = xaxis.0, xaxis.1, xaxis.2 : fvinner m12, eye.0, eye.1, eye.2 m13 = yaxis.0, yaxis.1, yaxis.2 : fvinner m13, eye.0, eye.1, eye.2 m14 = zaxis.0, zaxis.1, zaxis.2 : fvinner m14, eye.0, eye.1, eye.2 dst.0 = xaxis.0, yaxis.0, zaxis.0, 0.0 dst.4 = xaxis.1, yaxis.1, zaxis.1, 0.0 dst.8 = xaxis.2, yaxis.2, zaxis.2, 0.0 dst.12 = -m12.0, -m13.0, -m14.0, 1.0 return #deffunc createPerspective double fov, double aspect, double near, double far, array dst f_n = 1.0 / (far - near) theta = deg2rad(fov) * 0.5 divisor = tan(theta) factor = 1.0 / divisor dst = 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0. dst.0 = (1.0 / aspect) * factor dst.5 = factor dst.10 = (-(far + near)) * f_n dst.11 = -1.0 dst.14 = -2.0 * far * near * f_n return #global



usagi

リンク

2023/8/5(Sat) 18:50:09|NO.99865

>アドバイスお願い致します。
アドバイス出来る程のものではないですが、気になったところとして

>gameplay3DのworldViewProjectionMatrixの導き方と同じにすれば問題ないと思います。
HSP側からどうgameplayを操作しているかの方もOpenHSPでソース追ってみると良いかと思いました。

今回は最低限必要そうな行列演算をgameplayから移植し、
HSPからの呼び出しを見ながら、ソースにしてみました。(★の部分)

>ここではviewMatrixを作成している「つもり」である。
ここはプロジェクション変換行列ですね。ビュー変換ではないのそこで混乱があったのかもしれません。

>ここからworldViewProjectionMatrixを返すつもりだった
HSPの頂点シェーダーで以下の部分があるかと思いますが、

u_worldViewProjectionMatrix * a_position;

HSPでデフォでバインドされている各行列におきかえます。(結果は同じなので、 プロジェクション*ビュー*ワールド(モデル))

u_projectionMatrix * u_viewMatrix * u_worldMatrix * a_position;

その後、個々の行列を自身で作成した行列に置き換えて確認すると
どの行列の作成が上手くいっていないのか、分かりやすいかと思いました。
(プロジェクションから順に)

>ただしテクスチャは裏表に対して貫通しているような状態
Zバッファ参照しないと難しいですね。。。今のHSPなら自前で深度値書き込むシェーダーは作れますが、
そういう描画オプションがあると今後のシェーダーで楽に作れそうですね。(セルフシャドウとか)



usagi

リンク

2023/8/6(Sun) 05:57:27|NO.99866

あっ抜けてました。 こうしないとニア変えたとき適応されないです。
createPerspective fov, aspect, near, far, mtx_p ; プロジェクション変換行列
matrixTranspose mtx_p; ★ココ抜けてる



youdai

リンク

2023/8/6(Sun) 14:53:33|NO.99872

アドバイスありがとうございます。
HSP3スクリプト側のコメントも含めて非常に参考になります。

テクスチャ座標変換用行列についてですが、コメント文から連想したのですが、もしかして
この数値を変更するとテクスチャの拡大縮小・回転・移動ができたりするのでしょうか?


; テクスチャ座標変換用行列 mtx_t.0 = 0.5, 0.0, 0.0, 0.5; x mtx_t.4 = 0.0, 0.5, 0.0, 0.5; y mtx_t.8 = 0.0, 0.0, 1.0, 0.0; z mtx_t.12 = 0.0, 0.0, 0.0, 1.0; w

試しに


; テクスチャ座標変換用行列 mtx_t.0 = 0.25, 0.0, 0.0, 0.5; x mtx_t.4 = 0.0, 0.25, 0.0, 0.5; y mtx_t.8 = 0.0, 0.0, 1.0, 0.0; z mtx_t.12 = 0.0, 0.0, 0.0, 1.0; w

とするとテクスチャの大きさが2倍になったので、おそらくそうなんじゃないかという気がしました。

この場合、


mtx_t.0 = 0.5(横幅の大きさに関係している?), 0.0, 0.0, 0.5; x mtx_t.4 = 0.0, 0.5(縦幅の大きさに関係している?), 0.0, 0.5; y

という感じがしました。

テクスチャ座標変換用行列でテクスチャの回転と移動はどうやったらいいのでしょうか?



usagi

リンク

2023/8/6(Sun) 15:55:23|NO.99873

はい、その通りです。
3Dの基本的な行列の考えとして”同時座標系”というのはご存じでしょうか?

任意の点にその行列を掛けると、回転拡大移動が同時にできる魔法の様な変換です。
説明が長くなってしまうのと書籍は沢山あるので、簡単に書くと
拡大縮小は行列の斜め、平行移動は右端です。

テクスチャに何でアフィン変換しているかと言うと
試しに頂点シェーダーを以下のようにして見てください。

v_projTexCoord = u_worldViewProjectionMatrix * a_position;//同じ行列にする。 gl_Position = u_worldViewProjectionMatrix * a_position;

テクスチャは4枚表示されませんか?

これはプロジェクション変換行列が、すべての3D空間を-1〜1に押し込める様に式が出来ているからです。
テクスチャの座標系は0〜1なので、4枚表示される訳です。

ですから半分にして半分移動したいので以下の行列を掛け合わせました。

↓ここの斜めが縮小 ↓ここの縦が移動 mtx_t.0 = 0.5, 0.0, 0.0, 0.5; x mtx_t.4 = 0.0, 0.5, 0.0, 0.5; y mtx_t.8 = 0.0, 0.0, 1.0, 0.0; z mtx_t.12 = 0.0, 0.0, 0.0, 1.0; w

この同時座標系を3D空間上の任意の点に
モデル*ビュー*プロジェクションとかけて
最終的に2Dのスクリーンに映し出す訳ですね。
これが理解できると、3D空間を自由に操れるわけです。

※掛算の交換法則は成り立ちませんから、
 使用するライブリに合わせて順番は意識してくださいませ。
 まぁ最初はなんか思った結果と違うなぁと思ったら逆にすればいいと思います。
 (数学警察に怒られるか)



usagi

リンク

2023/8/6(Sun) 15:58:25|NO.99874

誤字でした、”同次座標系"です。



youdai

リンク

2023/8/6(Sun) 17:04:06|NO.99876

>これはプロジェクション変換行列が、すべての3D空間を-1〜1に押し込める様に式が出来ているからです。
>テクスチャの座標系は0〜1なので、4枚表示される訳です。

>ですから半分にして半分移動したいので以下の行列を掛け合わせました

テクスチャ座標変換行列の部分で、同次座標変換で画像の位置と大きさを真ん中に合わせる処理をしているのですね。
この部分を調整することで他にも色々な変形が出来そうですね!

大変参考になりました!
自分だけじゃ分からないところが多かったので、質問して良かったです。
ありがとうございました。これを参考に研究していこうと思います。



usagi

リンク

2023/8/6(Sun) 17:51:07|NO.99877

こういうので遊んでみると、分かりやすいと思います。

*MAIN ; 四角系 100の大きさ ; x y z w p1 = -50.0, -50.0, 0.0, 1.0 p2 = 50.0, -50.0, 0.0, 1.0 p3 = 50.0, 50.0, 0.0, 1.0 p4 = -50.0, 50.0, 0.0, 1.0 ; ★ここを色々変えて遊ぶ ; |移動 |拡大 |回転 |出力 affineTransform 300,300, 0, 1, 1, 1, 0, 0, t, mtx t = 0.1+t ; 四角表示 multiplyMatrixVM p1, mtx, o1 : multiplyMatrixVM p2, mtx, o2 multiplyMatrixVM p3, mtx, o3 : multiplyMatrixVM p4, mtx, o4 x = int(o1.0), int(o2.0), int(o3.0), int(o4.0) y = int(o1.1), int(o2.1), int(o3.1), int(o4.1) color 255,128,128 : gsquare -1, x, y : color 255,255,255 : pos 0,0 ; 情報表示 mes "アフィン変換行列", 4 s = "%+1.2f, %+1.2f, %+1.2f, %+1.2f" mes strf(s, mtx.0, mtx.1, mtx.2, mtx.3 ), 4 mes strf(s, mtx.4, mtx.5, mtx.6, mtx.7 ), 4 mes strf(s, mtx.8, mtx.9, mtx.10, mtx.11), 4 mes strf(s, mtx.12, mtx.13, mtx.14, mtx.15), 4 redraw 1 : await 16 : redraw 0 : color 128,128,128 : boxf : goto *MAIN #module #deffunc affineTransform double mx, double my, double mz, double zx, double zy, double zz, double ax, double ay, double az, array dst ; 回転※面倒なのでx->y->z合成 sx = sin(ax) : sy = sin(ay) : sz = sin(az) cx = cos(ax) : cy = cos(ay) : cz = cos(az) r1 = cz*cy : r2 = cz*sy*sx - sz*cx : r3 = cz*sy*cx + sz*sx r5 = sz*cy : r6 = sz*sy*sx + cz*cx : r7 = sz*sy*cx - cz*sx r9 = -sy : r10 = cy*sx : r11 = cy*cx ;拡大移動 dst.0 = zx*r1, r2, r3, mx; x dst.4 = r5, zy*r6, r7, my; y dst.8 = r9, r10, zz*r11, mz; z dst.12 = 0.0, 0.0, 0.0, 1.0; w return #deffunc multiplyMatrixVM array v1, array m1, array dst dst.0 = v1.0*m1.0 + v1.1*m1.1 + v1.2*m1.2 + v1.3*m1.3 dst.1 = v1.0*m1.4 + v1.1*m1.5 + v1.2*m1.6 + v1.3*m1.7 dst.2 = v1.0*m1.8 + v1.1*m1.9 + v1.2*m1.10 + v1.3*m1.11 dst.3 = v1.0*m1.12 + v1.1*m1.13 + v1.2*m1.14 + v1.3*m1.15 return #global



usagi

リンク

2023/8/6(Sun) 19:20:47|NO.99879

あっ、合成しちゃってるのでこうでした。 なんどもすみません。
※拡大、回転、移動と、順々にかける場合は拡大は斜めで合ってます。

;拡大移動 dst.0 = r1*zx, r2*zy, r3*zz, mx; x dst.4 = r5*zx, r6*zy, r7*zz, my; y dst.8 = r9*zx, r10*zy, r11*zz, mz; z dst.12 = 0.0, 0.0, 0.0, 1.0; w



youdai

リンク

2023/8/7(Mon) 20:02:10|NO.99884

同次座標系についてアドバイスありがとうございます。
この行列で行列を操作するのだ、という概念はかなり広範囲に応用が効く感じを受けました。
これは相当色々なことができそうな概念だと思いました。



usagi

リンク

2023/8/10(Thu) 04:17:23|NO.99886

>広範囲に応用が効く感じを受けました。
そうですね。なんかもう3Dはコレで出来てるくらい何処にでも出てくるので、色々な事が出来ると思います。

ついでに裏に貫通しないバージョンも用意してみました。 見やすいように、影(少し暗く)つけてます。
※簡略化の為、平行になった時マッハバンド出てます。深度比較のバイアスを角度で変化させたり、周りのテクセルをサンプリングするといいと思います。
※シェーダー分けて書くのが面倒だったので、どこかにスクリプトコピーして実行頂くと、同じフォルダに書き出されます。(スペース消えちゃう泣)


; 37beta6で実行(gpmatprm16はbeta4まで設定バグあるので) ; ※1u_diffuseColorはモデル個別に設定できる。自作uniformはシェーダー共通の模様。(マテリアルには設定出来ない) s={" attribute vec3 a_position; attribute vec2 a_texCoord; varying vec2 v_texCoord; uniform mat4 u_projectionMatrix; void main() { gl_Position = u_projectionMatrix * vec4(a_position, 1); v_texCoord = a_texCoord; } "} notesel s : notesave "depthPreview.vert" s={" uniform sampler2D u_diffuseTexture; varying vec2 v_texCoord; float rgbaToDepth(vec4 RGBA){ return RGBA.r + (RGBA.g + (RGBA.b) / 256) / 256; } void main() { float depth = rgbaToDepth(texture2D(u_diffuseTexture, v_texCoord)); gl_FragColor = vec4(vec3(depth), 1); } "} notesel s : notesave "depthPreview.frag" s={" attribute vec4 a_position; uniform mat4 u_worldViewProjectionMatrix; uniform mat4 u_worldMatrix; uniform mat4 u_projTextureMatrix; uniform mat4 u_projViewProjectionMatrix; varying vec4 v_projTexCoord; varying vec4 v_projPosition; void main() { v_projTexCoord = u_projTextureMatrix * u_worldMatrix * a_position; v_projPosition = u_projViewProjectionMatrix * u_worldMatrix * a_position; gl_Position = u_worldViewProjectionMatrix * a_position; } "} notesel s : notesave "projShader.vert" s={" uniform vec4 u_diffuseColor; uniform sampler2D u_projTexture; uniform sampler2D u_depthTexture; uniform float u_drawMode; varying vec4 v_position; varying vec4 v_projTexCoord; varying vec4 v_projPosition; vec4 depthToRGBA(float depth){ float r = floor( depth * 256) / 256; float def = depth - r; float g = floor( def * 256 * 256 ) / 256; def = def * 256 - g; float b = floor( def * 256 * 256 ) / 256; return vec4(r, g, b, 1); } float rgbaToDepth(vec4 RGBA){ return RGBA.r + (RGBA.g + (RGBA.b) / 256) / 256; } bool inside(vec4 position){ vec2 p = position.xy / position.w; return (0<p.x && p.x<1 && 0<p.y && p.y<1) ? true : false; } vec4 depthDraw() { return depthToRGBA(v_projPosition.z / v_projPosition.w); } vec4 projDraw() { vec4 color = u_diffuseColor; // 深度 float projDepth = v_projPosition.z / v_projPosition.w; float texDepth = rgbaToDepth(texture2DProj(u_depthTexture, v_projTexCoord)); bool isShadow = (projDepth-0.005 > texDepth); // 色 vec4 projColor = texture2DProj(u_projTexture, v_projTexCoord); vec4 shadowColor = isShadow ? vec4(0.8, 0.8, 0.8, 1) : vec4(1); projColor *= isShadow ? 0 : 1; // 合成 color += projColor; // 今回は加算で遊ぶ。 color *= shadowColor; return inside(v_projTexCoord) ? color : u_diffuseColor; } void main() { gl_FragColor = (u_drawMode > 0.5) ? depthDraw() : projDraw(); } "} notesel s : notesave "projShader.frag" ;------------------------------------------------ #include "hgimg4.as" size = 512 screen 0, size, size : gpreset : setcls 1, $4488FF ; 設定 buf_camera = 1 : buf_proj = 2 : buf_tex = 3 fov = 45.0 : aspect = 1.0 : near = 3 : far = 80 ; テクスチャ座標変換用行列 mtx_t.0 = 0.5, 0.0, 0.0, 0.5; x mtx_t.4 = 0.0, 0.5, 0.0, 0.5; y mtx_t.8 = 0.0, 0.0, 1.0, 0.0; z mtx_t.12 = 0.0, 0.0, 0.0, 1.0; w ; メインカメラ用オフスクリーンバッファ buffer buf_camera, size, size, screen_offscreen ; デプステクスチャ gpusershader "depthPreview.vert", "depthPreview.frag", "" buffer buf_proj, size, size, screen_offscreen + screen_usergcopy ; メインカメラ gpnull camera_main gpcamera camera_main, fov, aspect, near, far setpos camera_main, 30, 30, 30 gplookat camera_main, 0, 0, 0 ; プロジェクターカメラ gpnull camera_proj gpcamera camera_proj, fov, aspect, near, far ; シェーダー gpusermat mat_proj,"projShader.vert","projShader.frag","" ; テクスチャ buffer buf_tex, size, size, screen_offscreen gpmatprmp mat_proj,"u_projTexture", GPOBJ_ID_SRCFLAG+buf_tex gpmatprmf mat_proj,"wrap","clamp","u_projTexture" gpmatprmp mat_proj,"u_depthTexture", GPOBJ_ID_SRCFLAG+buf_proj ; モデル gpbox model_box, 3,, mat_proj : setpos model_box, ,1.5 gpmatprm4 model_box, "u_diffuseColor", 0.3, 0.3, 0.3,1 repeat 12 gpbox model_rnd, 1,, mat_proj : r = deg2rad(cnt*30) setpos model_rnd, cos(r)*10, 1 ,sin(r)*10 hsvcolor cnt*16,164,230 : c = 0.004*ginfo_r,0.004*ginfo_g,0.004*ginfo_b gpmatprm4 model_rnd, "u_diffuseColor", c.0, c.1, c.2,1 loop gpfloor model_floor, 80,80,, mat_proj gpmatprm4 model_floor, "u_diffuseColor", 0.2, 0.5, 0.2,1 gpbox model_proj, 1,, mat_proj gpmatprm4 model_proj, "u_diffuseColor", 1.0, 0.0, 0.0,1 *MAIN getreq _timer, SYSREQ_TIMER : timer = 0.001 * _timer ; テクスチャ gsel buf_tex : color : boxf x = 0,512,512,0 : y = 0,0,512,512 : c = $FF0000, $00FF00, $0000FF, $FF00FF : gsquare -257, x,y,c repeat 12 t = timer+deg2rad(cnt*30) : r = powf(cos(timer),2)*224 : p = cos(t)*r+256, sin(t)*r+256 hsvcolor cnt*16,164,230 : circle p.0-16,p.1-16, p.0+16,p.1+16, loop ; 適当に移動 cam_pos = sin(timer)*10.0, 6.0, cos(timer)*10.0 cam_at = 0.0, 0.0, 0.0 cam_up = 0.0, 1.0, 0.0 ; プロジェクタの位置確認用 setpos model_proj, cam_pos.0, cam_pos.1, cam_pos.2 gplookat model_proj, cam_at.0, cam_at.1, cam_at.2 ; プロジェクターカメラの位置と向き設定 setpos camera_proj, cam_pos.0, cam_pos.1, cam_pos.2 gplookat camera_proj, cam_at.0, cam_at.1, cam_at.2 ; プロジェクターの行列 createLookAt cam_pos, cam_at, cam_up, mtx_v : matrixTranspose mtx_v createPerspective fov, aspect, near, far, mtx_p : matrixTranspose mtx_p multiplyMatrixMM mtx_v, mtx_p, mtx_vp multiplyMatrixMM mtx_vp, mtx_t, mtx_vpt gpmatprm16 model_box, "u_projViewProjectionMatrix", mtx_vp gpmatprm16 model_box, "u_projTextureMatrix", mtx_vpt ;プロジェクタからの見た目 gsel buf_proj : rgbcolor $FFFFFF : boxf gpmatprm1 model_box, "u_drawMode", 1; 深度書き込み gpusecamera camera_proj : gpdraw ;メインカメラからの見た目 gsel buf_camera gpmatprm1 model_box, "u_drawMode", 0; 通常描画に戻す gpusecamera camera_main : gpdraw gpcnvaxis p1.0, p1.1, _, cam_pos.0, cam_pos.1, cam_pos.2, 0 gpcnvaxis p2.0, p2.1, _, cam_at.0, cam_at.1, cam_at.2, 0 ;スクリーン描画 gsel 0 : redraw 0 : color 255,255,255 : gmode 0 pos 0, 0 : celput buf_camera, pos 0, 0 : mes "メインカメラ", 4 line p1.0, p1.1, p2.0, p2.1 pos p1.0, p1.1 : mes "プロジェクタ", 4 pos 0, 0.7*size : celput buf_tex,, 0.3, 0.3 pos 0, 0.7*size : mes "テクスチャ", 4 pos 0.7*size, 0.7*size : celput buf_proj,, 0.3, 0.3 pos 0.7*size, 0.7*size : mes "デプス", 4 redraw 1 : await 16 goto *MAIN ; 行列モジュール #module #deffunc matrixIdentity array dst dst = 1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0 return #deffunc matrixTranspose array dst t = dst.0,dst.1,dst.2,dst.3,dst.4,dst.5,dst.6,dst.7,dst.8,dst.9,dst.10,dst.11,dst.12,dst.13,dst.14,dst.15 dst = t.0,t.4,t.8,t.12,t.1,t.5,t.9,t.13,t.2,t.6,t.10,t.14,t.3,t.7,t.11,t.15 return #deffunc multiplyMatrixMM array m1, array m2, array dst dst.0 = m1.0 * m2.0 + m1.4 * m2.1 + m1.8 * m2.2 + m1.12 * m2.3 dst.1 = m1.1 * m2.0 + m1.5 * m2.1 + m1.9 * m2.2 + m1.13 * m2.3 dst.2 = m1.2 * m2.0 + m1.6 * m2.1 + m1.10 * m2.2 + m1.14 * m2.3 dst.3 = m1.3 * m2.0 + m1.7 * m2.1 + m1.11 * m2.2 + m1.15 * m2.3 dst.4 = m1.0 * m2.4 + m1.4 * m2.5 + m1.8 * m2.6 + m1.12 * m2.7 dst.5 = m1.1 * m2.4 + m1.5 * m2.5 + m1.9 * m2.6 + m1.13 * m2.7 dst.6 = m1.2 * m2.4 + m1.6 * m2.5 + m1.10 * m2.6 + m1.14 * m2.7 dst.7 = m1.3 * m2.4 + m1.7 * m2.5 + m1.11 * m2.6 + m1.15 * m2.7 dst.8 = m1.0 * m2.8 + m1.4 * m2.9 + m1.8 * m2.10 + m1.12 * m2.11 dst.9 = m1.1 * m2.8 + m1.5 * m2.9 + m1.9 * m2.10 + m1.13 * m2.11 dst.10 = m1.2 * m2.8 + m1.6 * m2.9 + m1.10 * m2.10 + m1.14 * m2.11 dst.11 = m1.3 * m2.8 + m1.7 * m2.9 + m1.11 * m2.10 + m1.15 * m2.11 dst.12 = m1.0 * m2.12 + m1.4 * m2.13 + m1.8 * m2.14 + m1.12 * m2.15 dst.13 = m1.1 * m2.12 + m1.5 * m2.13 + m1.9 * m2.14 + m1.13 * m2.15 dst.14 = m1.2 * m2.12 + m1.6 * m2.13 + m1.10 * m2.14 + m1.14 * m2.15 dst.15 = m1.3 * m2.12 + m1.7 * m2.13 + m1.11 * m2.14 + m1.15 * m2.15 return #deffunc createLookAt array eye, array target, array up, array dst fvunit up zaxis = eye.0, eye.1, eye.2 : fvsub zaxis, target.0, target.1, target.2 : fvunit zaxis xaxis = up.0, up.1, up.2 : fvouter xaxis, zaxis.0, zaxis.1, zaxis.2 : fvunit xaxis yaxis = zaxis.0, zaxis.1, zaxis.2 : fvouter yaxis, xaxis.0, xaxis.1, xaxis.2 : fvunit yaxis m12 = xaxis.0, xaxis.1, xaxis.2 : fvinner m12, eye.0, eye.1, eye.2 m13 = yaxis.0, yaxis.1, yaxis.2 : fvinner m13, eye.0, eye.1, eye.2 m14 = zaxis.0, zaxis.1, zaxis.2 : fvinner m14, eye.0, eye.1, eye.2 dst.0 = xaxis.0, yaxis.0, zaxis.0, 0.0 dst.4 = xaxis.1, yaxis.1, zaxis.1, 0.0 dst.8 = xaxis.2, yaxis.2, zaxis.2, 0.0 dst.12 = -m12.0, -m13.0, -m14.0, 1.0 return #deffunc createPerspective double fov, double aspect, double near, double far, array dst f_n = 1.0 / (far - near) theta = deg2rad(fov) * 0.5 divisor = tan(theta) factor = 1.0 / divisor dst = 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0. dst.0 = (1.0 / aspect) * factor dst.5 = factor dst.10 = (-(far + near)) * f_n dst.11 = -1.0 dst.14 = -2.0 * far * near * f_n return #global



youdai

リンク

2023/8/13(Sun) 13:50:25|NO.99908

貫通しないバージョンのサンプル見ました。
デプスシャドウの技術も応用されていて、非常に高度な技術だと思いました。
これもいろいろなことに応用が効くし、非常に参考になります。
これは自分だけじゃなくて、シェーダー初心者全員が見た方がいいサンプルだと思いました。



ONION software Copyright 1997-2023(c) All rights reserved.