December 15, 2011

[Silverlight]Silverlight5の3Dプロジェクト(2)

[Silverlight]Silverlight5の3Dプロジェクト(1)の続きの記事です

Sceneクラスが描画処理の実態です



Scene.cs
using System.Windows.Controls;
using System;
using System.Windows.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Silverlight3dApp
{
public class Scene : IDisposable
{
#region Fields

readonly DrawingSurface _drawingSurface;
readonly ContentManager contentManager;
readonly Cube cube;

float aspectRatio;
float rotationAngle;

#endregion

#region Properties

public ContentManager ContentManager
{
get
{
return contentManager;
}
}

public GraphicsDevice GraphicsDevice
{
get
{
return GraphicsDeviceManager.Current.GraphicsDevice;
}
}

#endregion

#region Creation

public Scene(DrawingSurface drawingSurface)
{
_drawingSurface = drawingSurface;

// Register for size changed to update the aspect ratio
// ★画面サイズが変わった時のアスペクト比の計算
_drawingSurface.SizeChanged += _drawingSurface_SizeChanged;

// Get a content manager to access content pipeline
contentManager = new ContentManager(null)
{
RootDirectory = "Content"
};

// Initializing variables
cube = new Cube(this, 1.0f);
}

#endregion

#region Methods

void _drawingSurface_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
aspectRatio = (float)(_drawingSurface.ActualWidth / _drawingSurface.ActualHeight);
}

public void Draw()
{
// ★透視変換の部分
// Clear surface
GraphicsDeviceManager.Current.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Color(0.2f, 0.2f, 0.2f, 1.0f), 1.0f, 0);

// Compute matrices
Matrix world = Matrix.CreateRotationX(rotationAngle) * Matrix.CreateRotationY(rotationAngle);
Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, -5.0f), Vector3.Zero, Vector3.UnitY);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(0.85f, aspectRatio, 0.01f, 1000.0f);

// Update per frame parameter values
cube.World = world;
cube.WorldViewProjection = world * view * projection;

// Drawing the cube
cube.Draw();

// Animate rotation
rotationAngle += 0.05f;
}

public void Dispose()
{
_drawingSurface.SizeChanged -= _drawingSurface_SizeChanged;
}


#endregion
}
}

Scene.csは描画関係でした
次のCube.csはモデル関係です
今回の場合は、立方体(キューブ)の作成です


Cube.cs
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Silverlight3dApp
{
public class Cube
{
#region Fields

readonly Scene scene;
readonly GraphicsDevice graphicsDevice;
readonly VertexBuffer vertexBuffer;
readonly IndexBuffer indexBuffer;
readonly SilverlightEffect mySilverlightEffect;
readonly SilverlightEffectParameter worldViewProjectionParameter;
readonly SilverlightEffectParameter worldParameter;
readonly SilverlightEffectParameter lightPositionParameter;

#endregion

#region Properties

public int VerticesCount { get; private set; }
public int FaceCount { get; private set; }

public Matrix World
{
set
{
worldParameter.SetValue(value);
}
}

public Matrix WorldViewProjection
{
set
{
worldViewProjectionParameter.SetValue(value);
}
}

public Vector3 LightPosition
{
set
{
lightPositionParameter.SetValue(value);
}
}

#endregion

#region Creation

public Cube(Scene scene, float size)
{
this.scene = scene;
this.graphicsDevice = scene.GraphicsDevice;
this.mySilverlightEffect = scene.ContentManager.Load("CustomEffect");

// Cache effect parameters
worldViewProjectionParameter = mySilverlightEffect.Parameters["WorldViewProjection"];
worldParameter = mySilverlightEffect.Parameters["World"];
lightPositionParameter = mySilverlightEffect.Parameters["LightPosition"];

// Init static parameters
this.LightPosition = new Vector3(1, 1, -10);

// Temporary lists
List vertices = new List();
List indices = new List();

// A cube has six faces, each one pointing in a different direction.
Vector3[] normals =
{
new Vector3(0, 0, 1),
new Vector3(0, 0, -1),
new Vector3(1, 0, 0),
new Vector3(-1, 0, 0),
new Vector3(0, 1, 0),
new Vector3(0, -1, 0)
};

// Create each face in turn.
foreach (Vector3 normal in normals)
{
// Get two vectors perpendicular to the face normal and to each other.
Vector3 side1 = new Vector3(normal.Y, normal.Z, normal.X);
Vector3 side2 = Vector3.Cross(normal, side1);

// Six indices (two triangles) per face.
indices.Add((ushort)vertices.Count);
indices.Add((ushort)(vertices.Count + 1));
indices.Add((ushort)(vertices.Count + 2));

indices.Add((ushort)vertices.Count);
indices.Add((ushort)(vertices.Count + 2));
indices.Add((ushort)(vertices.Count + 3));

// Four vertices per face.
Vector4 color = new Vector4(0, 1, 0, 1);
vertices.Add(new VertexPositionColorNormal((normal - side1 - side2) * size / 2, normal, color));
vertices.Add(new VertexPositionColorNormal((normal - side1 + side2) * size / 2, normal, color));
vertices.Add(new VertexPositionColorNormal((normal + side1 + side2) * size / 2, normal, color));
vertices.Add(new VertexPositionColorNormal((normal + side1 - side2) * size / 2, normal, color));
}

// Create a vertex buffer, and copy our vertex data into it.
vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionColorNormal.VertexDeclaration, vertices.Count, BufferUsage.None);

vertexBuffer.SetData(0, vertices.ToArray(), 0, vertices.Count, VertexPositionColorNormal.Stride);

// Create an index buffer, and copy our index data into it.
indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, indices.Count, BufferUsage.None);

indexBuffer.SetData(0, indices.ToArray(), 0, indices.Count);

// Statistics
VerticesCount = vertices.Count;
FaceCount = indices.Count / 3;
}

#endregion

#region Methods

public void Draw()
{
foreach (var pass in mySilverlightEffect.CurrentTechnique.Passes)
{
// Apply pass
pass.Apply();

// Set vertex buffer and index buffer
graphicsDevice.SetVertexBuffer(vertexBuffer);
graphicsDevice.Indices = indexBuffer;

// The shaders are already set so we can draw primitives
graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, VerticesCount, 0, FaceCount);
}
}

#endregion
}
}
この部分でモデルを作っています
色々3Dモデルの知識が必要な部分ですが
ポイントは赤字部分の読み込みの  SilverlightEffect  と言う新しいクラスです
今回のToolkitで導入されました

名前の通り、効果を設定することができ、XNAとほぼ同じ頂点シェーダー、ピクセルシェーダーが利用できます


CustomEffect.slfx
float4x4 WorldViewProjection;
float4x4 World;
float3 LightPosition;

// Structs
struct VS_INPUT
{
float4 position : POSITION;
float3 normal : NORMAL;
float4 color : COLOR0;
};

struct VS_OUTPUT
{
float4 position : POSITION;
float3 normalWorld : TEXCOORD0;
float3 positionWorld : TEXCOORD1;
float4 color : COLOR0;
};

// Vertex Shader
VS_OUTPUT mainVS(VS_INPUT In)
{
VS_OUTPUT Out = (VS_OUTPUT)0;

// Compute projected position
Out.position = mul(In.position, WorldViewProjection);

// Compute world normal
Out.normalWorld = mul(In.normal,(float3x3) WorldViewProjection);

// Compute world position
Out.positionWorld = (mul(In.position, World)).xyz;

// Transmit vertex color
Out.color = In.color;

return Out;
}

// Pixel Shader
float4 mainPS(VS_OUTPUT In) : COLOR
{
// Light equation
float3 lightDirectionW = normalize(LightPosition - In.positionWorld);
float ndl = max(0, dot(In.normalWorld, lightDirectionW));

// Final color
return float4(In.color.rgb * ndl, 1);
}

// Technique
technique MainTechnique
{
pass P0
{
VertexShader = compile vs_2_0 mainVS(); // Must be a non-parameter entry point
PixelShader = compile ps_2_0 mainPS(); // Must be a non-parameter entry point
}
}
XNAやってる人なら、Silverlightでも同じようなプログラムが描けることについて
とても興味深いですよねっ!ねっ!!

SilverlightのXNAフレームワークの利用については
また次回以降に記載していこうかなぁと

ひとまずは、次の 蜜葉たんにバトンタッチ!

haruka_sao at 09:14コメント(0)トラックバック(0)Silverlight | プログラミング 

トラックバックURL

コメントする

名前:
URL:
  情報を記憶: 評価:  顔   星
 
 
 
Sao's Tech Memo
mvp_logo_140

Microsoft MVP for Windows Development
[Jan,2016-Dec,2017]
Microsoft MVP for Windows
Platform Development
[Jan,2015-Dec,2015]
Microsoft MVP for
Client Development
[Jan,2014-Dec,2014]
Microsoft MVP for Client App Dev [Jan,2010-Dec,2013]
Recent Comments
訪問者数
  • 今日:
  • 昨日:
  • 累計:

記事検索