メールありがとうございます、手元でも現象を確認できました
まず30FPSにしたところ予想した通り瞬時にカメラが移動した際のちらつきは抑えられました
次に30FPSより高いFPSにしたい場合ですが、VMDデータには「瞬時に移動するので補間はしない」などの
情報が無いようなので、少し無理矢理ですが「次のキーまでのフレーム数が1の場合は補間しない」という
処理を追加することで30FPSより高いFPSにしてもちらつかないようにすることができました
件のスレッドのサンプルプログラムをちらつかないように変更してみましたので、よろしければご覧ください
尚、今回の処理を実装するに当たって「再生時間からアニメーションのキー番号を割り出す」関数
MV1GetAnimKeyDataIndexFromTime を追加しましたので、下記のプログラムを実行する際は関数を追加した
こちらのバージョンをお使いください m(_ _)m
http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用
http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用
http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_DevCppTest.exe // Dev-C++ 用
http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_MinGWTest.exe // MinGW 用
http://homepage2.nifty.com/natupaji/DxLib/DxLibDotNet.zip // .NET用
http://homepage2.nifty.com/natupaji/DxLib/DxLibMakeTest.exe // ソース
(中身を既存のライブラリのファイルに上書きして、BCCをお使いの
場合は『再構築』を、VCをお使いの場合は『リビルド』を、
Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい)
#include "DxLib.h"
#define PI 3.1415926535897932384626433832795f
// 指定のキーと次のキーまでの時間を取得する
static float MV1CheckAnimKeyDataNextKeyTime( int MHandle, int AnimKeySetIndex, int KeyIndex )
{
// 最後のキーだった場合は次のキーまでの時間は0
if( MV1GetAnimKeySetDataNum( MHandle, AnimKeySetIndex ) - 1 == KeyIndex )
{
return 0.0f ;
}
// 次のキーまでの時間を返す
return MV1GetAnimKeyDataTime( MHandle, AnimKeySetIndex, KeyIndex + 1 ) -
MV1GetAnimKeyDataTime( MHandle, AnimKeySetIndex, KeyIndex ) ;
}
// MV1GetAnimKeyDataToVectorFromTime のキーとキーの間の時間が1の場合は補間しないラッピング関数
static VECTOR MV1GetAnimKeyDataToVectorFromTime_Rap( int MHandle, int AnimKeySetIndex, float Time )
{
int KeyIndex ;
// 指定の時間でのキー番号を取得
KeyIndex = MV1GetAnimKeyDataIndexFromTime( MHandle, AnimKeySetIndex, Time ) ;
// キーとキーの間の時間が 1.00001f より短かったら補間をしない
if( MV1CheckAnimKeyDataNextKeyTime( MHandle, AnimKeySetIndex, KeyIndex ) < 1.00001f )
{
return MV1GetAnimKeyDataToVector( MHandle, AnimKeySetIndex, KeyIndex ) ;
}
else
{
return MV1GetAnimKeyDataToVectorFromTime( MHandle, AnimKeySetIndex, Time ) ;
}
}
// MV1GetAnimKeyDataToLinearFromTime のキーとキーの間の時間が1の場合は補間しないラッピング関数
static float MV1GetAnimKeyDataToLinearFromTime_Rap( int MHandle, int AnimKeySetIndex, float Time )
{
int KeyIndex ;
// 指定の時間でのキー番号を取得
KeyIndex = MV1GetAnimKeyDataIndexFromTime( MHandle, AnimKeySetIndex, Time ) ;
// キーとキーの間の時間が 1.00001f より短かったら補間をしない
if( MV1CheckAnimKeyDataNextKeyTime( MHandle, AnimKeySetIndex, KeyIndex ) < 1.00001f )
{
return MV1GetAnimKeyDataToLinear( MHandle, AnimKeySetIndex, KeyIndex ) ;
}
else
{
return MV1GetAnimKeyDataToLinearFromTime( MHandle, AnimKeySetIndex, Time ) ;
}
}
// VMDカメラモーションからカメラのパラメータを抽出してDXライブラリの設定に反映させる
void SetupVMDCameraMotionParam( int CameraHandle, float Time )
{
MATRIX VRotMat, HRotMat, MixRotMat, TwistRotMat ;
VECTOR CamLoc, CamDir, CamUp ;
VECTOR Location, Rotation ;
float Length, ViewAngle ;
// カメラの注視点を取得
Location = MV1GetAnimKeyDataToVectorFromTime_Rap( CameraHandle, 0, Time ) ;
// カメラの回転値を取得
Rotation = MV1GetAnimKeyDataToVectorFromTime_Rap( CameraHandle, 1, Time ) ;
// カメラの注視点までの距離の符号を逆転したものを取得
Length = MV1GetAnimKeyDataToLinearFromTime_Rap( CameraHandle, 2, Time ) ;
// カメラの視野角を取得
ViewAngle = MV1GetAnimKeyDataToLinearFromTime_Rap( CameraHandle, 3, Time ) ;
// 垂直方向の回転行列を取得
VRotMat = MGetRotX( -Rotation.x ) ;
// 水平方向の回転行列を取得
HRotMat = MGetRotY( -Rotation.y ) ;
// 垂直方向の回転行列と水平方向の回転行列を合成
MixRotMat = MMult( VRotMat, HRotMat ) ;
// カメラの向きを算出
CamDir = VTransform( VGet( 0.0f, 0.0f, 1.0f ), MixRotMat ) ;
// 捻り回転行列を取得
TwistRotMat = MGetRotAxis( CamDir, -Rotation.z ) ;
// 捻り回転行列を合成行列に合成
MixRotMat = MMult( MixRotMat, TwistRotMat ) ;
// カメラの上方向の向きを算出
CamUp = VTransform( VGet( 0.0f, 1.0f, 0.0f ), MixRotMat ) ;
// カメラの座標を算出
CamLoc = VTransform( VGet( 0.0f, 0.0f, Length ), MixRotMat ) ;
CamLoc = VAdd( CamLoc, Location ) ;
// カメラの注視点を算出
Location = VAdd( CamLoc, CamDir ) ;
// 視野角をセット
SetupCamera_Perspective( ViewAngle / 180.0f * PI ) ;
// カメラの座標と注視点と上方向をセット
SetCameraPositionAndTargetAndUpVec( CamLoc, Location, CamUp ) ;
}
// WinMain
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
int ModelHandle, CameraHandle, AttachAnimIndex ;
float Time ;
// ウインドウモードで起動
ChangeWindowMode( TRUE );
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1;
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK );
// モデルを読み込み
ModelHandle = MV1LoadModel( "初音ミク_2.pmd" ) ;
if(ModelHandle == -1) return -1;
// カメラモーションの読み込み
CameraHandle = MV1LoadModel( "Camera_2.vmd" ) ;
if(CameraHandle == -1) return -1;
// モデルにアニメーションをアタッチ
AttachAnimIndex = MV1AttachAnim( ModelHandle, 0 ) ;
// 初期設定では Near クリップが遠すぎるのでクリップの範囲を変更
SetCameraNearFar( 1.0f, 1000.0f ) ;
// メインループ
Time = 0.0f ;
while( ProcessMessage() == 0 )
{
// 画面のクリア
ClearDrawScreen();
// モーションの時間を進める( モーションの時間に到達したら0に戻す )
Time += 30.0f / 60.0f ;
if( Time > MV1GetAttachAnimTotalTime( ModelHandle, AttachAnimIndex ) )
{
Time = 0.0f ;
}
MV1SetAttachAnimTime( ModelHandle, AttachAnimIndex, Time ) ;
// VMDカメラモーションのパラメータをDXライブラリの設定に反映させる
SetupVMDCameraMotionParam( CameraHandle, Time ) ;
// モデルを描画
MV1DrawModel( ModelHandle ) ;
// 再生時間の表示
DrawFormatString( 0, 0, GetColor( 255,255,255 ), "Time %.1f/%.1f", Time, MV1GetAttachAnimTotalTime( ModelHandle, AttachAnimIndex ) ) ;
// 裏画面の内容を表画面に反映
ScreenFlip();
}
// DXライブラリの後始末
DxLib_End();
// ソフトの終了
return 0;
}