|
|
|
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
アドバイスお願い致します。
| |
|
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
| |
|
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なら自前で深度値書き込むシェーダーは作れますが、
そういう描画オプションがあると今後のシェーダーで楽に作れそうですね。(セルフシャドウとか)
|
|
2023/8/6(Sun) 05:57:27|NO.99866
あっ抜けてました。 こうしないとニア変えたとき適応されないです。
createPerspective fov, aspect, near, far, mtx_p ; プロジェクション変換行列
matrixTranspose mtx_p; ★ココ抜けてる
|
|
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
という感じがしました。
テクスチャ座標変換用行列でテクスチャの回転と移動はどうやったらいいのでしょうか?
|
|
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空間を自由に操れるわけです。
※掛算の交換法則は成り立ちませんから、
使用するライブリに合わせて順番は意識してくださいませ。
まぁ最初はなんか思った結果と違うなぁと思ったら逆にすればいいと思います。
(数学警察に怒られるか)
|
|
2023/8/6(Sun) 15:58:25|NO.99874
誤字でした、”同次座標系"です。
|
|
2023/8/6(Sun) 17:04:06|NO.99876
>これはプロジェクション変換行列が、すべての3D空間を-1〜1に押し込める様に式が出来ているからです。
>テクスチャの座標系は0〜1なので、4枚表示される訳です。
>ですから半分にして半分移動したいので以下の行列を掛け合わせました
テクスチャ座標変換行列の部分で、同次座標変換で画像の位置と大きさを真ん中に合わせる処理をしているのですね。
この部分を調整することで他にも色々な変形が出来そうですね!
大変参考になりました!
自分だけじゃ分からないところが多かったので、質問して良かったです。
ありがとうございました。これを参考に研究していこうと思います。
|
|
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
| |
|
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
|
|
2023/8/7(Mon) 20:02:10|NO.99884
同次座標系についてアドバイスありがとうございます。
この行列で行列を操作するのだ、という概念はかなり広範囲に応用が効く感じを受けました。
これは相当色々なことができそうな概念だと思いました。
|
|
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
| |
|
2023/8/13(Sun) 13:50:25|NO.99908
貫通しないバージョンのサンプル見ました。
デプスシャドウの技術も応用されていて、非常に高度な技術だと思いました。
これもいろいろなことに応用が効くし、非常に参考になります。
これは自分だけじゃなくて、シェーダー初心者全員が見た方がいいサンプルだと思いました。
|
|