PlayStation Mobile Studio
 PlayStation(R)Mobile SDK 1.21.01

■Playstation Mobile 3Dメッシュローダー Prev Top Next
関連ページ:なし


今回は3Dメッシュローダーです。といっても拡張ライブラリを使用してるのではっきりいって手抜きネタです。
とはいえそのまま使用すると、シェーダーが固定機能パイプラインになってしまうので微妙に変更してます。

ということでまずは拡張ライブラリを使用できるようにプロジェクトを設定します。
ソリューションウィンドウの参照で右クリックすると、「Edit References」ウィンドウが表示されます。

この中のSce.PlayStation.HighLevel.Modelをチェックして「OK」をクリックします。

次に3Dメッシュファイルをバイナリファイルに変換します。もとのテキストファイルのままでは読み込み時にエラーになるので注意が必要です。
サンプルを見るとCOLLADAフォーマットの3Dメッシュファイルを ModelConverter.exe という実行ファイルを使用して変換するバッチファイルがあります。
ですのでバッチファイルを作成して変換します。
ModelConverter.exe は、PlayStation Mobile Studioをインストールしたルートフォルダ\SCE\PSM\tools\ModelConverter フォルダ内にあります。
変換後のファイルの拡張子はmdxです。ファイル名は -o オプションで指定します。
作成したファイルをApplication\resourcesフォルダ内にテクスチャーと一緒においてください。
作成したmdxファイルはテクスチャーと同様にソリューションエクスプローラーに追加してください。
追加の手順についてはここにまとめてありますので必要であれば参考にしてください。

それとテクスチャー画像のバイナリデータは、mdxファイル内に含まれるようです。
したがってテクスチャー画像を修正してもmdxファイル自体がもとのままの場合、テクスチャー画像のデータは変わらないので注意してください。


Common.cs 共通クラスとか
Sprite.vcg バーテックスシェーダーのcgファイル
Sprite.fcg フラグメントシェーダーのcgファイル
Sprite.cs スプライトシェーダークラス
SpriteMesh.cs スプライトメッシュクラス
DebugFont.cs デバッグフォントクラス
Lambert.vcg ランバートシェーダーのバーテックスシェーダーのcgファイル
Lambert.fcg ランバートシェーダーのフラグメントシェーダーのcgファイル
Lambert.cs ランバートシェーダークラス
AppMain.cs main関数があるソースファイル


---Lambert.vcg---  ↑

// バーテックスシェーダー

void main( float3 in a_Position  : POSITION,
           float3 in a_Normal    : NORMAL,
           float2 in a_Texel     : TEXCOORD,
           float4 out v_Position : POSITION,
           float3 out v_Normal   : TEXCOORD0,
           float2 out v_Texel    : TEXCOORD1,
           uniform float4x4 WorldViewProj
                  )
{
   v_Position = mul( float4( a_Position, 1 ), WorldViewProj );
   v_Normal = a_Normal;
   v_Texel = a_Texel;
}

---Lambert.fcg---  ↑


// フラグメントシェーダー

void main( float3 in v_Normal : TEXCOORD0,
           float2 in v_Texel  : TEXCOORD1,
           uniform float3 DirectionalLightDir,
           uniform sampler2D s_Texture : TEXUNIT0,
           float4 out Color   : COLOR )
{
   float lambert = dot( -DirectionalLightDir, v_Normal );
   lambert = lambert * 0.5f + 0.5f;

   Color = tex2D( s_Texture, v_Texel ) * lambert;
}

さんざんやってるハーフランバート

---Lambert.cs---  ↑


using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;

public class Lambert : IDisposable
{
   private ShaderProgram shader;
   private Matrix4 projMatrix;
   private Matrix4 viewMatrix;
   private Vector3 directionalLightDir;
   private GraphicsContext graphics;

   public Lambert ()
   {
      this.shader = new ShaderProgram("/Application/shaders/Lambert.cgx" );

      // BasicModelクラスの VertexBuffer の format を確認すると以下の通りになっているっぽい
      // 固定で問題ないかは不明...
      this.shader.SetAttributeBinding( 0, "a_Position" );
      this.shader.SetAttributeBinding( 1, "a_Normal" );
      this.shader.SetAttributeBinding( 3, "a_Texel" );

      this.shader.SetUniformBinding( 0, "WorldViewProj" );
      this.shader.SetUniformBinding( 1, "DirectionalLightDir" );
   }

   public void Dispose()
   {
      shader.Dispose();
   }

   public void Begin( GraphicsContext Graphics, Matrix4 ProjMatrix, Matrix4 ViewMatrix, Vector3 DirectionalLightDir )
   {
      this.graphics = Graphics;
      this.projMatrix = ProjMatrix;
      this.viewMatrix = ViewMatrix;
      this.directionalLightDir = DirectionalLightDir;
   }

   public int GetMaxPass()
   {
      return 1;
   }

   public void BeginPass( Matrix4 WorldMatrix )
   {
      // ワールド、ビュー、射影行列を合成
      Matrix4 matWVP = this.projMatrix * this.viewMatrix * WorldMatrix;
      shader.SetUniformValue( 0, ref matWVP );

      // 平行光源をワールド行列の逆行列で行列変換( 平行移動は無視 )
      Vector3 v = WorldMatrix.Inverse().Transform( new Vector4( this.directionalLightDir, 0 ) ).Xyz.Normalize();
      shader.SetUniformValue( 1, ref v );
      this.graphics.SetShaderProgram( this.shader );
   }

   public void EndPass()
   {
   }

   public void End( GraphicsContext Graphics )
   {
      Graphics.SetShaderProgram( null );
   }
}

---AppMain.cs---  ↑


using System;
using System.Collections.Generic;

using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Environment;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Input;
using Sce.PlayStation.Core.Imaging;
using Sce.PlayStation.HighLevel.Model;

namespace PSM_Samples
{
   public class AppMain : IDisposable
   {
      private const int Width = 800;
      private const int Height = 480;

      private static GraphicsContext graphics;

      private static Lambert lambert;

      private static DebugFont debugFont;

      // 3Dメッシュ
      private static BasicModel model;

      static float rotationY = 0.0f;

      // 行列
      static Matrix4 projMatrix, viewMatrix;

      // 平行光源の方向ベクトル
      static Vector3 DirectionalLightDir;

      public static void Main (string[] args)
      {
         Initialize ();

         while (true) 
         {
            SystemEvents.CheckEvents ();
            Update ();
            Render ();
         }
      }

      // 初期化
      public static void Initialize ()
      {
         // フレームバッファの解像度はウィンドウの解像度と同じサイズにする
         graphics = new GraphicsContext( Width, Height, PixelFormat.Rgba, PixelFormat.Depth16, MultiSampleMode.None );

         lambert = new Lambert();

         debugFont = new DebugFont();

         model = new BasicModel( "/Application/resources/F14.mdx", 0 );

         // 射影行列
         projMatrix = Matrix4.Perspective( (float)FMath.PI / 5.0f, (float)Width / (float)Height, 10.0f, 1000.0f );

         // ビュー行列
         viewMatrix = Matrix4.Identity;

         // 平行光源の方向ベクトル
         DirectionalLightDir = new Vector3( -1, -1, -1 );
      }

      public void Dispose()
      {
         model.Dispose();
         debugFont.Dispose();
         lambert.Dispose();
         graphics.Dispose();
      }

      // フレーム更新処理
      public static void Update ()
      {
         // ワールド行列

         Matrix4 matScaling = Matrix4.Scale( new Vector3( 100.0f, 100.0f, 100.0f ) );

         rotationY += 0.01f;
         if( rotationY > (float)FMath.PI * 2.0f )
            rotationY -= (float)FMath.PI * 2.0f;
         Matrix4 matRotationY = Matrix4.RotationY( rotationY );

         Matrix4 matTranslation = Matrix4.Translation( 0.0f, 0.0f, -500.0f );

         Matrix4 matWorld = matTranslation * matRotationY * matScaling ;

         model.SetWorldMatrix( ref matWorld );
      }

      // レンダリング
      public static void Render ()
      {
         // カリングモードを有効にする
         graphics.Enable( EnableMode.CullFace, true );
         // 反時計回りで裏面となるポリゴンを描画しない
         graphics.SetCullFace( CullFaceMode.Back, CullFaceDirection.Ccw );

         // 深度テストを有効にする
         graphics.Enable( EnableMode.DepthTest, true );

         graphics.SetClearColor (0.2f, 0.2f, 1, 1 );
         graphics.Clear ();

         lambert.Begin( graphics, projMatrix, viewMatrix, DirectionalLightDir );
         lambert.BeginPass( model.WorldMatrix );
         {
            // 頂点バッファを設定
            graphics.SetVertexBuffer( 0, model.Parts[0].Arrays[0].VertexBuffer );

            // テクスチャーを設定する
            graphics.SetTexture( 0, model.Textures[0].Texture );

            // レンダリング
            graphics.DrawArrays( DrawMode.Triangles, 0, model.Parts[0].Arrays[0].VertexBuffer.IndexCount );
         }
         lambert.EndPass();
         lambert.End( graphics );

         debugFont.Draw( graphics, "" );

         // スワップ
         graphics.SwapBuffers ();
      }
   }
}

3Dメッシュの読み込みは BasicModelクラス を使用して行います。
このクラスは固定機能パイプラインである BasicProgramクラス と依存しているため、
3Dメッシュの読み込み処理部分だけを使用してレンダリング処理は独立させました。
当然無駄にメモリ領域を使用することになるので、本来であれば3Dメッシュローダーも自作すべきですが、めんどくさいのでやめました(笑)。
まあサンプルソースに BasicModelクラス のソースもありますのでやる気がある人は自作してみてください。


Prev Top Next
inserted by FC2 system