|
|
|
2023/12/11(Mon) 14:23:08|NO.100811
皆さんコンニチワ。
chatGPTと激論を交わし、ビルボードについてシェーダーをこしらえたいと奮闘しました。
(失敗)
最終的に、Y軸を固定したビルボード(HGIMG3にあったやつ)をHGIMG4で実現したいと思っています。
とにかく、ビルボードとしてこっち向いてくれと思っているのですが、ダメです。
なんとなく、カメラをビルボードの横に動かすとこっちを向くのですが、上下移動すると、だめです。
改変してるうちに訳が分からなくなってきました。
MVP行列が嫌いになりそうです。どなたかたすけてくれませんか。。
マテリアルファイル
material textured
{
u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX
u_viewProjectionMatrix = VIEW_PROJECTION_MATRIX
u_worldMatrix = WORLD_MATRIX
u_worldViewMatrix = WORLD_VIEW_MATRIX
u_projectionMatrix = PROJECTION_MATRIX
u_viewMatrix = VIEW_MATRIX
sampler u_diffuseTexture
{//続く...
とりあえず、ユニフォーム変数をマテリアルで代入しまくってみる
頂点シェーダ―
///////////////////////////////////////////////////////////
// Uniforms
uniform mat4 u_worldViewProjectionMatrix;
uniform mat4 u_viewProjectionMatrix; // ビュープロジェクション行列
uniform mat4 u_worldViewMatrix;
uniform vec3 u_cameraPosition;
使いそうなユニフォームを宣言しまくる。
u_cameraPositionは、スクリプトから投げ込む。
//続く...
void main()
{
vec4 position = getPosition();
// ビルボードのモデル行列を単位行列に設定
mat4 modelMatrix = mat4(1.0);
// カメラの位置からビルボードの方向を計算
vec3 viewDirection = normalize(u_cameraPosition - position.xyz);//→ここがなんか問題か、ワールドカメラから、ローカル頂点引いてる?
// Y軸方向のベクトル
vec3 up = vec3(0.0, 1.0, 0.0);
// ビルボードの右方向を計算
vec3 right = normalize(cross(up, viewDirection));//upベクトルとカメラ方向ベクトルの外積が右方向
// ビルボードのモデル単位行列に方向ベクトルをセット⇒左上3×3が回転ベクトルと思いますが、配置関係がよくわかりません
modelMatrix[0] = vec4(right, 0.0);
modelMatrix[1] = vec4(up, 0.0);
modelMatrix[2] = vec4(viewDirection, 0.0);
modelMatrix[3] = vec4(0,0,0,1);
// ビルボードの座標変換
gl_Position = u_viewProjectionMatrix * modelMatrix * position;//→MVP行列自体をしっかり理解できていないのかもしれません
//(基本)world変換×ビュー変換×プロジェクション変換×ローカル頂点位置
//(ビルボード)⇒? ビュー変換×プロジェクション変換×モデル行列×ローカル頂点位置??何かがおかしい
}
数学はわからん。。。ので、優しく教えてください
| |
|
2023/12/11(Mon) 16:09:30|NO.100816
X軸に45度,Y軸に45度回転させたプレートを表示するには、下記のようにX45度の行列modelMatrixとY45度の行列modelMatrix_yを用意して、
最後に乗算すると、確かにXY軸それぞれに45度傾いたモデルが表示される。
ということは、やはりカメラの向きを計算するViewDirectionあたりが正しく計算できていないのかな。
参考リンク
https://lh3.googleusercontent.com/GVTiE30Oz_7x7kMfbh998ui5ieXgGizlLZ6FN1wDkte6jnhojqQCqyoGo07lnIESvsdBj52UZsjLpQ5tjyh-rIHAiny-0GbSqx_Y0C4yoMsfFxMXhH_yQqCK-bakTag=w1280
void main()
{
vec4 position = getPosition();
// ビルボードのモデル行列を単位行列に設定
mat4 modelMatrix = mat4(1.0);
// ビルボードのモデル行列にX軸方向ベクトルをセット
modelMatrix[0] = vec4(1,0,0,0);
modelMatrix[1] = vec4( 0,0.707106781,-0.707106781,0);
modelMatrix[2] = vec4(0,0.707106781, 0.707106781,0);
modelMatrix[3] = vec4(0,0,0,1);
mat4 modelMatrix_y = mat4(1.0);
// ビルボードのモデル行列にY軸方向ベクトルをセット
modelMatrix_y[0] = vec4( 0.707106781,0,0.707106781,0);
modelMatrix_y[1] = vec4( 0,1,0,0);
modelMatrix_y[2] = vec4(-0.707106781,0, 0.707106781,0);
modelMatrix_y[3] = vec4(0,0,0,1);
gl_Position = u_worldViewProjectionMatrix * modelMatrix * modelMatrix_y * position ;
|
|
2023/12/11(Mon) 16:11:15|NO.100817
|
|
2023/12/11(Mon) 17:32:17|NO.100818
なぜか、、動いているように感じます、、
ただ、ビルボードの上空を通過するとクルッと回転するのが不細工なようです。
しかし、ちょっと角度がずれているような気もする。
お気づきの点があれば、教えていただきたいです。
#ifndef DIRECTIONAL_LIGHT_COUNT
#define DIRECTIONAL_LIGHT_COUNT 0
#endif
#ifndef SPOT_LIGHT_COUNT
#define SPOT_LIGHT_COUNT 0
#endif
#ifndef POINT_LIGHT_COUNT
#define POINT_LIGHT_COUNT 0
#endif
#if (DIRECTIONAL_LIGHT_COUNT > 0) || (POINT_LIGHT_COUNT > 0) || (SPOT_LIGHT_COUNT > 0)
#define LIGHTING
#endif
///////////////////////////////////////////////////////////
// Atributes
attribute vec4 a_position;
#if defined(SKINNING)
attribute vec4 a_blendWeights;
attribute vec4 a_blendIndices;
#endif
attribute vec2 a_texCoord;
#if defined(LIGHTMAP)
attribute vec2 a_texCoord1;
#endif
#if defined(LIGHTING)
attribute vec3 a_normal;
#if defined(BUMPED)
attribute vec3 a_tangent;
attribute vec3 a_binormal;
#endif
#endif
///////////////////////////////////////////////////////////
// Uniforms
uniform mat4 u_worldViewProjectionMatrix;//デフォルト
uniform mat4 u_viewProjectionMatrix; // ビュープロジェクション行列
uniform mat4 u_worldViewMatrix;//使っていない
uniform vec3 u_cameraPosition;//スクリプトからxyzを代入する
#if defined(SKINNING)
uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
#endif
#if defined(LIGHTING)
uniform mat4 u_inverseTransposeWorldViewMatrix;
#if defined(SPECULAR) || (POINT_LIGHT_COUNT > 0) || (SPOT_LIGHT_COUNT > 0)
uniform mat4 u_worldViewMatrix;
#endif
#if defined(BUMPED) && (DIRECTIONAL_LIGHT_COUNT > 0)
uniform vec3 u_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];
#endif
#if (POINT_LIGHT_COUNT > 0)
uniform vec3 u_pointLightPosition[POINT_LIGHT_COUNT];
#endif
#if (SPOT_LIGHT_COUNT > 0)
uniform vec3 u_spotLightPosition[SPOT_LIGHT_COUNT];
#if defined(BUMPED)
uniform vec3 u_spotLightDirection[SPOT_LIGHT_COUNT];
#endif
#endif
#if defined(SPECULAR)
uniform vec3 u_cameraPosition;
#endif
#endif
#if defined(TEXTURE_REPEAT)
uniform vec2 u_textureRepeat;
#endif
#if defined(TEXTURE_OFFSET)
uniform vec2 u_textureOffset;
#endif
#if defined(CLIP_PLANE)
uniform mat4 u_worldMatrix;
uniform vec4 u_clipPlane;
#endif
///////////////////////////////////////////////////////////
// Varyings
varying vec2 v_texCoord;
#if defined(LIGHTMAP)
varying vec2 v_texCoord1;
#endif
#if defined(LIGHTING)
#if !defined(BUMPED)
varying vec3 v_normalVector;
#endif
#if defined(BUMPED) && (DIRECTIONAL_LIGHT_COUNT > 0)
varying vec3 v_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];
#endif
#if (POINT_LIGHT_COUNT > 0)
varying vec3 v_vertexToPointLightDirection[POINT_LIGHT_COUNT];
#endif
#if (SPOT_LIGHT_COUNT > 0)
varying vec3 v_vertexToSpotLightDirection[SPOT_LIGHT_COUNT];
#if defined(BUMPED)
varying vec3 v_spotLightDirection[SPOT_LIGHT_COUNT];
#endif
#endif
#if defined(SPECULAR)
varying vec3 v_cameraDirection;
#endif
#include "lighting.vert"
#endif
#if defined(SKINNING)
#include "skinning.vert"
#else
#include "skinning-none.vert"
#endif
#if defined(CLIP_PLANE)
varying float v_clipDistance;
#endif
void main()
{
vec4 position = getPosition();
// ビルボードのモデル行列を単位行列に設定
mat4 modelMatrix = mat4(1.0);
// カメラの位置からビルボードの方向を計算
vec3 viewDirection = normalize(u_cameraPosition - position.xyz);
// Y軸方向のベクトル
vec3 up = vec3(0.0, 1.0, 0.0);
// ビルボードの右方向を計算
vec3 right = normalize(cross(up, viewDirection));
// ビルボードの右方向と上方向を計算
//vec3 up = cross(vec3(0.0, 1.0, 0.0), viewDirection);
//vec3 right = cross(viewDirection, up);
// ビルボードのモデル行列に方向ベクトルをセット
modelMatrix[0] = vec4(right , 0);
modelMatrix[1] = vec4(up , 0);
modelMatrix[2] = vec4(viewDirection, 0);
modelMatrix[3] = vec4(0 , 0, 0, 1);
//gl_Position = u_worldViewProjectionMatrix * position;
// ビルボードの座標変換
gl_Position = u_worldViewProjectionMatrix * modelMatrix * position;
#if defined(LIGHTING)
vec3 normal = getNormal();
// Transform the normal, tangent and binormals to view space.
mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * normal);
#if defined(BUMPED)
vec3 tangent = getTangent();
vec3 binormal = getBinormal();
vec3 tangentVector = normalize(inverseTransposeWorldViewMatrix * tangent);
vec3 binormalVector = normalize(inverseTransposeWorldViewMatrix * binormal);
mat3 tangentSpaceTransformMatrix = mat3(tangentVector.x, binormalVector.x, normalVector.x, tangentVector.y, binormalVector.y, normalVector.y, tangentVector.z, binormalVector.z, normalVector.z);
applyLight(position, tangentSpaceTransformMatrix);
#else
v_normalVector = normalVector;
applyLight(position);
#endif
#endif
v_texCoord = a_texCoord;
#if defined(TEXTURE_REPEAT)
v_texCoord *= u_textureRepeat;
#endif
#if defined(TEXTURE_OFFSET)
v_texCoord += u_textureOffset;
#endif
#if defined(LIGHTMAP)
v_texCoord1 = a_texCoord1;
#endif
#if defined(CLIP_PLANE)
v_clipDistance = dot(u_worldMatrix * position, u_clipPlane);
#endif
}
| |
|
2023/12/12(Tue) 04:41:42|NO.100830
コンテストすごかったですねー。おめでとうございます。
ビルボードを出来る限りシンプルに、やさしく書いてみました。
簡単に言うと、MVP行列でのアフィン変換でビュー変換の回転をしなければ正面を向くわけですね。
ではどうやって、それをするかというと。。。
一例ですがどうぞ。
#include "hgimg4.as"
; ★最低限必要な物だけ抜粋
; ----------------------------
shader = {"
uniform mat4 u_worldViewProjectionMatrix;
uniform mat4 u_projectionMatrix;
uniform mat4 u_viewMatrix;
uniform mat4 u_worldMatrix;
attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main()
{
v_texCoord = a_texCoord;
// ★カメラの回転を無視する為、ビューから移動だけ抜き出す。(原点にMV行列を掛けると回転拡大は0なので)
vec4 viewPos = u_viewMatrix * u_worldMatrix * vec4(0,0,0,1);
// ★頂点のワールドの拡大回転だけ適応する。(行列の4番目は消す)
vec4 worldPos = mat4(mat3(u_worldMatrix)) * a_position;
// ★ビューのY軸成分だけ使う(いわゆる木など使うビルボード)
mat4 viewRot = mat4(1.0f);
viewRot[1] = u_viewMatrix[1]; /*★Y成分。ここの行コメントアウトすると常に正面*/
// ★上記を足し合わせると、View(カメラ)の回転を無視したMVが出来てしまう。(今回はY軸だけ掛ける)
viewPos += viewRot*worldPos;
// ★最後のプロジェクションを掛けスクリーン座標に
gl_Position = u_projectionMatrix * viewPos;
}
"}
bsave "my_billboard.vert", shader
shader = {"
uniform sampler2D u_diffuseTexture;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(u_diffuseTexture, v_texCoord); // ★今回はテクスチャ貼って、
if (gl_FragColor.a < 0.5) discard; // 透明なら書き込まないだけ。
}
"}
bsave "my_billboard.frag", shader
; ----------------------------
; ★ココから下は適当
gpreset:setcls CLSMODE_SOLID, 0
gpusermat id_mat, "my_billboard.vert","my_billboard.frag"
gpmatprmt id_mat, "u_diffuseTexture", dir_exe+"\\hsptv\\pronama.png"
gpplate id_obj, 2,2,,id_mat : setpos id_obj, 1, 1, 0
gpplate id_obj, 2,2,,id_mat : setpos id_obj, -1, 1, 0
gpplate id_obj, 2,2,,id_mat : setpos id_obj, 0, 1, 1
gpplate id_obj, 2,2,,id_mat : setpos id_obj, 0, 1, -1
chdir dir_exe+"\\sample\\hgimg4" : gpfloor id_obj, 3,3, $FF00
repeat : redraw 0
y = 0.02*(mousey-ginfo_winy/2)
time = 0.02+time
setpos GPOBJ_CAMERA, cos(time)*5, y, sin(time)*5
gplookat GPOBJ_CAMERA, 0,0,0
gpdraw
redraw 1 : await 1000/60 : loop
>ビルボードの上空を通過するとクルッと回転
おそらくカメラのY軸を元に外積でオイラー角的な計算で求めているからですかね。
gplookatカメラ回すとクルッと回転するのと同じです。(ジンバルロック)
クォータニオン的な方法が必要になるかと思います。
| |
|
2023/12/12(Tue) 19:47:50|NO.100835
改めて見直したら、分かりにくく、やさしくなかったかもしれませんので書き直しました。
こっちのほうがbuhioさんのソースの考えに近いかなぁ。。。
"mvBillboardMtx"とういうのがビルボード用のMV変換行列です。
各ステップのコメントアウトを順に外していくと分かりやすいかと考えてます。
#include "hgimg4.as"
; ★最低限必要な物だけ抜粋
; ----------------------------
shader = {"
uniform mat4 u_worldViewProjectionMatrix;
uniform mat4 u_projectionMatrix;
uniform mat4 u_viewMatrix;
uniform mat4 u_worldMatrix;
attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main()
{
v_texCoord = a_texCoord;
// ステップ1: 普通のMVP変換
// -------------------------------------------------------------------------
gl_Position = u_projectionMatrix * u_viewMatrix * u_worldMatrix * a_position;
// ステップ2: MV変換の回転拡大の要素を単位行列にすると正面を向く
// -------------------------------------------------------------------------
/*
mat4 mvMtx = u_viewMatrix * u_worldMatrix;
mat4 mvBillboardMtx = mat4(1.0f);
mvBillboardMtx[3] = mvMtx[3]; // ★平行移動要素だけ使う
gl_Position = u_projectionMatrix * mvBillboardMtx * a_position;
*/
// ステップ3: MV変換の拡大縮小の要素を抽出する (常に正面ビルボード)
// -------------------------------------------------------------------------
/*
mvBillboardMtx[0][0] = length(mvMtx[0].xyz);
mvBillboardMtx[1][1] = length(mvMtx[1].xyz);
mvBillboardMtx[2][2] = length(mvMtx[2].xyz);
gl_Position = u_projectionMatrix * mvBillboardMtx * a_position;
*/
// ステップ4: MV変換のY要素だけ適応する (Y軸ビルボード)
// -------------------------------------------------------------------------
/*
mvBillboardMtx[1] = mvMtx[1]; // ★Y軸要素だけ使う
gl_Position = u_projectionMatrix * mvBillboardMtx * a_position;
*/
}
"}
bsave "my_billboard.vert", shader
shader = {"
uniform sampler2D u_diffuseTexture;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(u_diffuseTexture, v_texCoord);
if (gl_FragColor.a < 0.5) discard;
}
"}
bsave "my_billboard.frag", shader
; ----------------------------
gpreset:setcls CLSMODE_SOLID, 0
gpusermat id_mat, "my_billboard.vert","my_billboard.frag"
gpmatprmt id_mat, "u_diffuseTexture", dir_exe+"\\hsptv\\pronama.png"
chdir dir_exe+"\\sample\\hgimg4" : gpfloor id_obj, 3,3, $FF00
repeat 4 : gpplate id,,,,id_mat : setpos id, cos(M_PI/2*cnt), 1, sin(M_PI/2*cnt) : setscale id, 2,2,2 : loop
repeat : redraw 0
y = 0.02*(mousey-ginfo_winy/2) : time = 0.02+time
setpos GPOBJ_CAMERA, cos(time)*5, y, absf(sin(time)*5)
gplookat GPOBJ_CAMERA, 0,0,0
gpdraw
redraw 1 : await 1000/60 : loop
| |
|
2023/12/13(Wed) 00:40:47|NO.100838
たびたびの連続投稿ですみません。
確認が1点抜けてました。
buhioさんシェーダー移植して同じスクリプトで試してみましたが、
たしかに上空でくるっとして、それと同時に拡縮する様でした。
おそらく通常のスクリプトでモデルを回転し正面を向けるような感じでシェーダーを
組んでいるので発生するのでは考えられました。
一例の「★ココから下は適当」の部分を以下の様にすると、
上空でくるっと回転するのが無い事が分かると思います。
これはMV行列を単位行列にするとスクリーンに対して平行になる
という所からのシェーダー的なアプローチです。
(何でこうなるかは、変換行列がどういう事をしているか順に調べると分かると思います)
gpreset:setcls CLSMODE_SOLID, 0
gpusermat id_mat, "my_billboard.vert","my_billboard.frag",,, GPOBJ_MATOPT_NOCULL
gpmatprmt id_mat, "u_diffuseTexture", dir_exe+"\\hsptv\\pronama.png"
chdir dir_exe+"\\sample\\hgimg4" : gpfloor id_obj, 3,3, $FF00
repeat 4 : gpplate id,,,,id_mat : setpos id, cos(M_PI/2*cnt), 1, sin(M_PI/2*cnt) : setscale id, 2,2,2 : loop
repeat : redraw 0
r = deg2rad(a)
setpos GPOBJ_CAMERA, 0, sin(r)*5, cos(r)*5
setang GPOBJ_CAMERA, -r
a++ : a\=360
gpdraw
redraw 1 : await 1000/60 : loop
以上、失礼いたしました。
|
|
2023/12/13(Wed) 12:30:50|NO.100840
>>usagi師匠 いつもいつも本当にありがとうございます!コンテストもお褒め頂き感無量です。
少し年末で本業があり、まださわれていません、、が、ものすごいヒントと解説を頂きましたので、解明していきます。
ありがとうございます。取り急ぎお礼申し上げます。
現在の試行錯誤
波頂点シェーダー(なんとか動いてる)
ビルボードY頂点シェーダー(←いまココ)
深度フォグシェーダー(なんとか動いてる。作ってから「shaders」に元々ありそうなのを発見して愕然)
UV移動シェーダー(なんとか動いてる)
デプスシャドウシェーダー(...これから)
なんとかマスターしていきたいと思います。
--------現時点のMVP行列基本理解-----------
アトリビュート a_position⇒頂点ごとのローカルの座標
×
ユニフォーム u_worldMatrix⇒オブジェクトごとの位置回転拡大行列(モデル又はワールド変換)
×
ユニフォーム u_viewMatrix⇒カメラの位置回転行列(ビュー変換)
×
ユニフォーム u_projectionMatrix⇒FOV、ニアクリップ、ファークリップの行列(プロジェクション変換)
↓
gl_position 画面表示へ
--------------------------------
この途中経過を変えたり、追加したり省略したりすることで、頂点を動かして頂点シェーダーは動く
|
|
2023/12/13(Wed) 20:10:32|NO.100841
いえいえ、何か参考になりMVP行列好きになって頂ければば幸いです。(便利ですから)
1回目の参考はちょっと分かりにくかったので忘れてくださいませ。
※皆さんネットで調べる事多いと思いますので、
説明が至らなかったら調べられるよう、検索した要素を取り入れてみたのですが、
私には合わず「逆にややこしないか?」と思ってやめました。
また、知っていたら申し訳ないですが、glslは列優先(column major)なので行列が縦に並んでます。
何か参考サイトを見る場合はそれを頭に入れておくと良いかと思いました。
取りあえず合ってるハズなのに何で。。。と
混乱したら掛算逆にしたり、転置(transpose関数)したりすれば上手くいくと思います。
説明用に長々と書いてしまいましたが、シンプルにまとめると以下になります。
mat4 mvMtx = u_viewMatrix * u_worldMatrix;
mat4 mvBillboardMtx = mat4(
vec4(length(mvMtx[0].xyz), 0, 0, 0),
mvMtx[1],
vec4(0, 0, length(mvMtx[2].xyz), 0),
mvMtx[3]
);
gl_Position = u_projectionMatrix * mvBillboardMtx * a_position;
|
|