まず前回の自分のgpusecameraについてのアドバイスですが、これは間違っていました。
gpusecameraについてですが、これは単純に「作ったカメラ設定を切り替える命令」のようです。
前回自分は
gpusecamera camera1
gpload オブジェクト1
gpload オブジェクト2
gpusecamera camera2
gpload オブジェクト3
gpload オブジェクト4
とするとcamera1にはオブジェクト1と2が表示され、camera2にはオブジェクト3と4が表示されると書きましたが、
そうではありませんでした。
これは主にgpuselightのカレントライトに関する設定で適用される概念でした。
gpuselight light1, 1
gpload オブジェクト1
gpload オブジェクト2
gpuselight light2, 1
gpload オブジェクト3
gpload オブジェクト4
混乱させたことをお詫びします。
●「gmode 1だと透過指定していないオブジェクトでも、くり抜いたように透過される現象」について
今回の「gmode 1だと透過指定していないオブジェクトでも、くり抜いたように透過される現象」について研究を進めていくにつれ、
いくつかの事柄が分かってきました。
検証するために、普段自分が組んでいるスクリプトの構造にできるだけ近づけるため、0から書き直しました。
#include "hgimg4.as"
#enum SCID_MAIN = 0 ; メインのスクリーン
#enum SCID_BUF0 ; バッファ0番
#enum SCID_BUF1 ; バッファ1番
#enum SCID_BUF2 ; バッファ0番と1番を結合する用のバッファ
#const FPS_AWAIT 1000 / 60
gosub *setup ; 準備処理
goto *main ; 繰り返し処理
;-------------------------------------------------------------------------------
; 準備処理
*setup
; スクリーンやカメラ等の設定
screen_width = 800
screen_height = 600
bairitu = 0.5
fov = 48
aspect = 1.33333333333333333333 ; 4 : 3 のアスペクト比
near = 0.5
far = 768.0
sw = 0
gosub *create_screen
gosub *create_camera
gosub *create_obj
return
*create_screen
setreq SYSREQ_VSYNC, 1 ; VSYNC同期ON
setreq SYSREQ_CLSMODE, 0 ; 背景を自動で消去しない(手動で行う)
setreq SYSREQ_LOGWRITE, 0 ; log出力をしない
gpreset
screen SCID_MAIN, screen_width, screen_height ; メインのスクリーン
buffer SCID_BUF0, screen_width, screen_height, screen_offscreen ; オフスクリーンバッファ
buffer SCID_BUF1, screen_width / 2, screen_height / 2, screen_offscreen ; オフスクリーンバッファ
buffer SCID_BUF2, screen_width, screen_height, screen_offscreen ; オフスクリーンバッファ
return
; カメラを作成
*create_camera
; 今回の処理の場合、1台だけで良い
gpnull id_camera
gpcamera id_camera, fov, aspect, near, far, sw
setpos id_camera, 0.0, 0.0, 0.0
setang id_camera, 0.0, 0.0, 0.0
; カメラの位置と角度はblender基準と同一にしてある
; HGIMG4のsample等でよく見る座標基準とは異なることに注意
camera1_pos = 7.3589, -6.39258, 4.9583
camera1_angZ = deg2rad(63.6), deg2rad(0.0), deg2rad(46.7)
camera2_pos = -0.18266, 1.0128, 11.476
camera2_angZ = deg2rad(-5.24), deg2rad(0.0), deg2rad(13.1)
;lookat_target = 0.0, 0.3, 0.0
return
; 通常のオブジェクトを作成
*create_obj
gpusecamera id_camera
; id_cameraの状態に対して、以下のオブジェクトを生成する
gpnull id_gpb
; tamane2バージョン
gpload id_gpb, "res/tamane2", ""
setobjmode
setpos id_gpb, 0.0, 0.0, -3.0
; tamane2はスケールが大きすぎるため、調整する
setscale id_gpb, 0.025, 0.025, 0.025
; tamane2はBlenderと同じ角度を入力すると倒れているため、角度を調整する
setangZ id_gpb, deg2rad(90.0), 0.0, 0.0
; duckバージョン
/*
gpload id_gpb, "res/duck", ""
setpos id_gpb, 0.0, 0.0, 0.0
setangZ id_gpb, deg2rad(90.0), 0.0, 0.0
setscale id_gpb, 1.0, 1.0, 1.0
*/
/*
gpnull id_floor
gpfloor id_floor, 8.0, 8.0, $00ffff
setpos id_floor, 0.0, 0.0, 0.0
*/
return
; 終了処理
*escape
stick key,15
if key&128 : end
return
*sub_draw
gosub *buf0_draw
gosub *buf1_draw
gosub *ketugou
;gosub *ketugou_nashi ; 結合なし版
return
*buf0_draw
gsel SCID_BUF0
; カメラの位置と向きを変更
setpos id_camera, camera1_pos.0, camera1_pos.1, camera1_pos.2
setangZ id_camera, camera1_angZ.0, camera1_angZ.1, camera1_angZ.2
;gplookat id_camera, lookat_target.0, lookat_target.1, lookat_target.2
redraw 0
; 背景の手動消去
rgbcolor $808080
boxf
; 通常のgpdraw
gpdraw
return
*buf1_draw
gsel SCID_BUF1
; カメラの位置と向きを変更
setpos id_camera, camera2_pos.0, camera2_pos.1, camera2_pos.2
setangZ id_camera, camera2_angZ.0, camera2_angZ.1, camera2_angZ.2
;gplookat id_camera, lookat_target.0, lookat_target.1, lookat_target.2
redraw 0
; 背景の手動消去
; 意図的に色は変えてあります。こちらは赤で表示されます
rgbcolor $800000
boxf
; シーンのみ描写する。自動移動等はしない
gpdraw GPDRAW_OPT_DRAWSCENE
return
*ketugou
gsel SCID_BUF2
redraw 0
gmode 0
pos 0, 0
celput SCID_BUF0
pos 200, 100
gmode 1
celput SCID_BUF1
return
*ketugou_nashi
gsel SCID_BUF2
redraw 0
gmode 0
pos 0, 0
celput SCID_BUF0
return
*main_copy
gsel SCID_MAIN
redraw 0
pos 0, 0
gmode 0
; この場合、このcelputそのものが画面初期化になる
celput SCID_BUF2
redraw 1 ; この地点で全て一度に描画される
return
*action
addang id_gpb, 0.0, 0.02, 0.0
return
;-------------------------------------------------------------------------------
; 繰り返し処理
*main
gosub *escape
gosub *action
gosub *sub_draw
gosub *main_copy
await FPS_AWAIT
goto *main
(上記のスクリプトはsample/hgimg4フォルダに入れれば動くようになっています)
まず、GENKIさんの最初のスクリプトを再現するに当たって、カメラは1台で済むことは予め分かっていたので、1台で組みました。
gplookatについては角度によっては「不自然な捻じれ」現象が起こりやすいので、今回は検証の厳密さが必要ですから使いませんでした。
バッファについては0番と1番を描画して、その0番と1番を結合するためのバッファを作りました。
そして、その結合したバッファをメインスクリーンへコピーします。
わざわざ結合用のバッファを作成し、そこからメインスクリーンへコピーする理由はチラつき防止と、
スクリプト上で整理整頓がしやすいからです。
加えて、今回は行いませんでしたが、この方がポストエフェクトが掛けやすいからです。
現象をわかりやすくするために、小さいバッファの方の背景は赤で表示してあります。
それで「gmode 1だと透過指定していないオブジェクトでも、くり抜いたように透過される現象」ですが、
その現象はduckでは分かりやすく全体が透過されますが、tamane2では当該の現象は起きませんでした。
もしかしたらもっとよく見ればどこかに起きているのかもしれませんが、パッと見て、どこにも起きていないように見えます。
スカートの裏面が消えていますが、それは元々の仕様だと思うので今回の問題とは無関係な現象です。
tamane2とduckの違いは、シェーダーの違いかもとも思ったのですが、
tamane2もduckも共にtexturedのシェーダーしか使っていませんでした。
次にマテリアルの設定を確かめてみたのですが、
tamane2のdefinesにはDIRECTIONAL_LIGHT_COUNT 1が設定されていなくて、
duckの方には設定されていました。
そこでtamane2にDIRECTIONAL_LIGHT_COUNT 1を設定してみましたが、この場合tamane2もgmode 1でduckのように透過されました。
次にduckのDIRECTIONAL_LIGHT_COUNT 1を削除してみましたが、今度はduckがtamane2のように正常に表示されました。
つまり、今回の現象はDIRECTIONAL_LIGHT_COUNTと関係する現象のようです。
gpboxやgpfloorですが、もしかしたらこちらもDIRECTIONAL_LIGHT_COUNTのマテリアル設定をすれば、
gmode 1で透過現象が起きるかもしれません。
現状の現象をあえて言い換えるなら「gmode 1は、ライト設定をしたマテリアルだけ、くり抜くモード」と
言えるのかもしれません。