今回は ビルボードになります。
ビルボードとは何なのか、まったく知識が無い状態で始めたので
このテストもゼロからの構築となりました。
ビルボードは比較的Web上に多く情報があった為参考になりました。
今回参考になったサイトは以下です。
①「指定の形状が視線方向を向くようにしたい (スクリプト)」
Shade3Dというプラットフォームでの実装ですが、
自分が最も望んでいる内容でした。途中で切り上げてしまった為
ちゃんと動作は確認していません。いずれしたいと思っています。
// ビルボードの表示テスト
HOUZMETHOD_VD text_out_effect_t::billboard_main_test( const ID3D11DeviceContextPtr& device_context)
{
try
{
// テストの為にビルボード化+回転されたボックスを表示させます。
// 回転させる為の角度の変数です。
static float_t s_angle = -1.0; // 回転用の角度
s_angle = s_angle > 360 ? 0 : s_angle + 1; // 0 ~ 360
// カメラの位置を取得します。
// これはGPUのエフェクト変数として別途用意しており、それを流用しています。
cvector4_t view_position_W = zero();
if( m_h_view_position_W)
m_h_view_position_W->GetFloatVector( (float32_t*)view_position_W.get_block_ptr(0)); // GPU制限の為、GPUのfloat精度をfloat32固定にします。
// カメラの位置を示すベクトルを求めます。
// 「カメラの位置 - ボックスの位置」で求めることが出来ます。
const cvector4_t v_object_center_pos_inW = initv( 0, 5, 0, 0); // ボックスの位置
const cvector3_t v_eye_dir = normalize( view_position_W - v_object_center_pos_inW);
// カメラの位置を示すベクトルが上を向きすぎて
// 上ベクトルと近づくと、ベクトルの誤差が増え映像が破綻します。
// そうならないように処置を加えます。(ただし完璧ではありません。ちょっとマシになる程度・・)
cvector3_t v_up = initv( 0, 1, 0);
const float_t dot_v = abs( dot( v_eye_dir, v_up));
if( dot_v >= 0.98)
v_up = initv( 0, 0, 1);
// カメラの位置を示すベクトルから正規直交行列を作ります。
// これは、X軸はY軸とZ軸の外積、Y軸はUP方向、Z軸はカメラの位置を示すベクトル(v_eye_dir)の
// 回転行列になります。
// ボックスにこの行列を掛けると、ボックスの正面がカメラの位置を示すベクトル(v_eye_dir)になるよう
// 回転されます。
const rmatrix4x4_t m_diff = to_orthonormal_basis( v_eye_dir, v_up);
// ワールド行列を作ります。
rmatrix4x4_t world = identity();
world = scaling< 4 >(cvector3_t(initv( 1.0, 1.0, 0.1)) ); // ボックスの半径
// X軸で回転するケースです。(可能な限り表示しています。すぐに破綻してしまいます。。)
//world = transpose( mul( world, transpose( rmatrix4x4_t( rotate_x( to_radian(s_angle)) ) ) ) );
//world = mul( transpose( m_diff ), world);
// Y軸で回転するケースです。(可能な限り表示しています。すぐに破綻してしまいます。。)
//world = transpose( mul( world, transpose( rmatrix4x4_t( rotate_y( to_radian(s_angle)) ) ) ) );
//world = mul( transpose( m_diff ), world);
// Z軸で回転するケースです。これは正常に表示できます。これがデフォルトになります。
world = mul( transpose( m_diff ), world);
world = mul( world, rotate_z( to_radian(s_angle)) );
// ボックスの位置を適用します。
cvector3_t v_translation = initv(0,+5,0); // 上のボックスの位置と同じ値であること。
rmatrix4x4_t translation = translate< 3 >( v_translation);
world = mul( translation, world );
// ボックスを表示します。
// 今回のテストでは独自のライブラリを使って表示していますが、
// 普通に表示させて問題はありません。
// 視錐台の頂点データをアップする為にバーテックスバッファをマップ(Open)します。
get_D3D11_geometric_shape_effect_ptr()->map_vb_shape_orders(device_context); // geometric_shape_effect_tオブジェクトを静的操作する拡張。(2024/2/25)
// ボックスを表示させる関数。引数は左から、形状の種類(球やボックスなどを選択)、ワールド行列、色、ワイヤーフレームの有無になります。
get_D3D11_geometric_shape_effect_ptr()->push_draw_shape_order( shape_order_type_box, world, color_t(1,0,0,1), false);
// バーテックスバッファをアンマップ(Close)します。
get_D3D11_geometric_shape_effect_ptr()->unmap_vb_shape_orders(device_context); // geometric_shape_effect_tオブジェクトを静的操作する拡張。(2024/2/25)
}
catch( const general_exception&)
{
throw;
}
}
// 以降はto_orthonormal_basis()のコードです。
// 見づらいですので参考程度でお願い致します。
template< uint_t row, typename traits_type, typename storage_type >
HOUZ_FORCE_INLINE packed_matrix< 4, 4, traits_type, matrix_row_major, matrix_storage_value > HOUZCALL to_orthonormal_basis ( /*[in]*/const packed_vector< row, traits_type, matrix_col_major, storage_type >& front)
{
typedef packed_matrix< 4, 4, traits_type, matrix_row_major, matrix_storage_value > matrix_type;
typedef matrix_type::rvector_type rvector_type;
typedef matrix_type::element_type element_type;
rvector_type tangent, binormal, normal;
normal = normalize( transpose(front));
const rvector_type abs_normal = abs( normal);
const element_type normal_min = min( abs_normal);
if( abs_normal(0) == normal_min)
binormal = initv(1,0,0);
else
if( abs_normal(1) == normal_min)
binormal = initv(0,1,0);
else
binormal = initv(0,0,1);
tangent = normalize( cross( binormal, normal));
binormal = normalize( cross( normal, tangent));
assert( abs( dot( tangent, binormal)) < 0.1f);
assert( abs( dot( binormal, normal)) < 0.1f);
assert( abs( dot( normal, tangent)) < 0.1f);
return initv( tangent, binormal, normal, last(1));
}
template< uint_t row, typename traits_type, typename storage_type0, typename storage_type1 >
HOUZ_FORCE_INLINE packed_matrix< 4, 4, traits_type, matrix_row_major, matrix_storage_value > HOUZCALL to_orthonormal_basis ( /*[in]*/const packed_vector< row, traits_type, matrix_col_major, storage_type0 >& front,
/*[in]*/const packed_vector< row, traits_type, matrix_col_major, storage_type1 >& up)
{
typedef packed_matrix< 4, 4, traits_type, matrix_row_major, matrix_storage_value > matrix_type;
typedef matrix_type::rvector_type rvector_type;
typedef matrix_type::element_type element_type;
static const rvector_type zero_ = zero();
static const element_type threshold = 0.7f; // 0.7 ≒ cos(π/4)
const rvector_type binormal = normalize( transpose(up));
const rvector_type normal = normalize( transpose(front));
if( abs( dot( binormal, normal)) < threshold)
{
const rvector_type tangent = normalize( cross( binormal, normal));
return initv( tangent, cross( normal, tangent), normal, last(1));
}
else
return to_orthonormal_basis( front);
}