方法 : Direct3D オブジェクトを変換する
更新 : 2007 年 11 月
ワールド変換を使用すると、シーン内の Direct3D オブジェクトを移動できます。
メモ : |
---|
マネージ Direct3D モバイル アプリケーションでは、Windows Mobile Version 5.0 Software for Pocket PC と Windows Mobile Version 5.0 Software for Smartphone が必要です。Windows Mobile ソフトウェアおよび SDK については、「.NET Compact Framework の外部資料」を参照してください。 |
ワールド空間は、すべての方向に無限に伸びる 3 次元のデカルト空間に似ています。ビュー変換でワールド空間からスクリーン空間にオブジェクトを変換する前に、ワールド空間内に配置する Direct3D オブジェクトの位置をワールド変換で定義します。ワールド変換を使用すると、Direct3D オブジェクトを変換 (移動)、回転、およびサイズ調整できます。
1 つのオブジェクトに対する複数のワールド変換を結合するには、それらの変換行列を掛け合わせる必要があります。次の例では、Multiply メソッドを使用して回転行列と平行移動行列を掛け合わせます。目的の結果を得るには、行列を正しい順序で変換する必要があります。たとえば、回転行列と平行移動行列を掛け合わせるには、次の例に示すように、平行移動の前に回転を変換する必要があります。
使用例
次の例は、船を表す基本的な四角形のメッシュをアニメーション表示します。この例は、次のオブジェクトが含まれた完全なフォームを提供します。
船を表す基本的な Mesh オブジェクト。
建物を表す基本的な Mesh オブジェクトのセット。
光を表示するいくつかの Light オブジェクト。これらのオブジェクトの 1 つは、船のエンジンからの光を表します。
Device オブジェクト。
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports Microsoft.WindowsMobile.DirectX
Imports Microsoft.WindowsMobile.DirectX.Direct3D
Class MatrixTransformsHowTo
Inherits Form
' Mesh representing the ship.
Private shipMesh As Mesh = Nothing
' Meshes representing buildings.
Private wallMeshes(2) As Mesh
Private meshColor As Color = Color.Goldenrod
' Description of the Direct3D light.
Private lightData As Light
Private device As Device
Private Enum ShipStatus
SS_LIFTOFF = 1
SS_TURNING = 2
SS_ENGINEON = 3
End Enum
Private myShipStatus As ShipStatus = ShipStatus.SS_LIFTOFF
Private firstTick As Integer = 0
Private newTick As Integer = 0
Private yVal As Single = - 2F
Private zVal As Single = 2F
Private Const midAltitude As Integer = 85
Private yCameraPosition As Single = - 1
Private xCameraPosition As Single = - 2
Private startAngle As Single = 0F
Private angle As Single = 0.1F
Private lastIncrement As Single = 0F
Private isEngineFired As Boolean = False
Private isShipDeparted As Boolean = False
Private isNewRotationOperation As Boolean = True
Public Sub New()
Dim present As PresentParameters
Me.Text = "Flying Ship"
' Enable the form to be closed.
' Required so that Hwnd of the form changes.
Me.MinimizeBox = False
present = New PresentParameters()
present.Windowed = True
present.AutoDepthStencilFormat = DepthFormat.D16
present.EnableAutoDepthStencil = True
present.SwapEffect = SwapEffect.Discard
device = New Device(0, DeviceType.Default, Me, CreateFlags.None, present)
AddHandler device.DeviceReset, AddressOf OnDeviceReset
Dim i As Integer
For i = 0 To wallMeshes.Length
wallMeshes(i) = Nothing
Next i
OnDeviceReset(Nothing, EventArgs.Empty)
End Sub
Private Sub OnDeviceReset(ByVal sender As Object, ByVal e As EventArgs)
' Meshes must be recreated whenever the device
' is reset, no matter which pool they are created in.
' Instead of loading a mesh from a file,
' this sample uses primitive box meshes
' to represent the ship and the buildings.
shipMesh = Mesh.Box(device, 0.8F, 0.18F, 2.2F)
wallMeshes(0) = Mesh.Box(device, 0.5F, 3.6F, 1F)
wallMeshes(1) = Mesh.Box(device, 0.5F, 1.8F, 2F)
wallMeshes(2) = Mesh.Box(device, 0.2F, 1F, 0.75F)
device.RenderState.Ambient = Color.White
' Provides main directional lighting.
device.Lights(0).Type = LightType.Directional
device.Lights(0).Direction = New Vector3(0.3F, - 0.5F, 0.2F)
device.Lights(0).Diffuse = Color.LightBlue
device.Lights(0).Update()
' Provides frontal lighting.
device.Lights(1).Type = LightType.Directional
device.Lights(1).Direction = New Vector3(0F, - 1F, - 3F)
device.Lights(1).Diffuse = Color.DarkSlateGray
device.Lights(1).Update()
' Turn on the lights.
device.Lights(0).Enabled = True
device.Lights(1).Enabled = True
' Turn off the light representing the engine.
device.Lights(2).Enabled = False
' For the projection matrix, set up a perspective transform (which
' transforms geometry from 3-D view space to 2-D viewport space, with
' a perspective divide that makes objects smaller in the distance). To build
' a perspective transform, you need the field of view (1/4 PI is common),
' the aspect ratio, and the near and far clipping planes (which define at
' the distances at which geometry should be no longer be rendered).
device.Transform.Projection = Matrix.PerspectiveFovLH(System.Convert.ToSingle(Math.PI) / 4F, System.Convert.ToSingle(Me.ClientSize.Width) / System.Convert.ToSingle(Me.ClientSize.Height), 1F, 80F)
End Sub
Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)
' Do nothing.
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Dim material As New Material()
Dim engineMaterial As New Material()
' Begin the scene and clear the back buffer to black.
device.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, Color.Black, 1F, 0)
device.BeginScene()
material.Diffuse = Color.WhiteSmoke
' Specifies the ambient color for the engines.
engineMaterial.Ambient = Color.White
SetupMatrices()
device.Material = material
' Draw ship on the screen.
shipMesh.DrawSubset(0)
SetupMovingLight()
If isEngineFired Then
device.Material = engineMaterial
device.Lights(2).Enabled = True
' Bind the vertex buffers of the primitive
' mesh to the Device object.
device.SetStreamSource(0, shipMesh.VertexBuffer, 0)
' Redraw the face of the ship representing the engine.
' A Box mesh has 4 vertices per face. The 20th vertex
' is the first vertex representing the engine. To use
' adjacent triangles, set the type to Primitive.TriangleFan.
device.DrawPrimitives(PrimitiveType.TriangleFan, 20, 2)
End If
material.Diffuse = Color.GhostWhite
device.Material = material
' Draw buildings, providing coordinates to locate each
' building on the x, y, and z planes. Because the camera is placed
' "behind" the scene initially (at a positive z-axis value in
' the call to Matrix.LookAtLH), positive z-axis values draw
' objects closer to the camera. In addition, positive x-axis
' values draw objects farther to the left instead of to the right.
' Draw the tall building.
device.Transform.World = Matrix.Translation(0.75F, - 0.2F, - 2F)
wallMeshes(0).DrawSubset(0)
' Draw the medium-sized buildings.
device.Transform.World = Matrix.Translation(- 1F, - 0.9F, 0F)
wallMeshes(1).DrawSubset(0)
device.Transform.World = Matrix.Translation(0F, - 0.9F, 0F)
wallMeshes(1).DrawSubset(0)
device.Transform.World = Matrix.Translation(1F, - 0.9F, 0F)
wallMeshes(1).DrawSubset(0)
device.Transform.World = Matrix.Translation(2F, - 0.9F, 0F)
wallMeshes(1).DrawSubset(0)
' Draw the small buildings.
device.Transform.World = Matrix.Translation(- 2F, - 1.5F, 5F)
wallMeshes(2).DrawSubset(0)
device.Transform.World = Matrix.Translation(- 1.25F, - 1.5F, 5F)
wallMeshes(2).DrawSubset(0)
device.Transform.World = Matrix.Translation(- 0.5F, - 1.5F, 5F)
wallMeshes(2).DrawSubset(0)
device.Transform.World = Matrix.Translation(0.75F, - 1.5F, 5F)
wallMeshes(2).DrawSubset(0)
' Finish the scene and present it on the screen.
device.EndScene()
device.Present()
' Repaint the scene.
Me.Invalidate()
End Sub
Private Sub SetupMatrices()
' Set the transformation matrices.
Dim fAngle As Single = angle
' To render the ship, combine a rotation on the y-axis with a
' translation (move) using the Matrix.Multiply method.
device.Transform.World = Matrix.Multiply(Matrix.RotationY(fAngle + startAngle), Matrix.Translation(- 0.5F, yVal, zVal))
' Set up the view matrix. You can define a view matrix with a camera position,
' a point to look at (camera target), and an "up" direction.
' First vector passed to LookAtLH is the camera position.
' Second vector passed to LookAtLH is the camera target.
' Third vector passed to LookAtLH defines the "up" direction.
' In this example, you set the camera seven units up along the z-axis ("behind"
' the scene), down one unit, and left two units. You then point the camera
' just above the origin and define "up" to be in the y-direction.
If Not isShipDeparted Then
device.Transform.View = Matrix.LookAtLH(New Vector3(- 2, - 1, 7), New Vector3(0, 1, 0), New Vector3(0, 1, 0))
Else
' Handles movement of camera after
' the ship "fires" the main engines.
device.Transform.View = Matrix.LookAtLH(New Vector3(xCameraPosition, yCameraPosition, 7), New Vector3(0, 1, 0), New Vector3(0, 1, 0))
xCameraPosition += 0.01F
yCameraPosition += 0.01F
End If
' Use the system time to control the animation.
' The high-resolution timer, if present for
' the hardware, could be used instead.
Dim tick As Integer = System.Environment.TickCount
If newTick = 0 Then
firstTick = tick / 100
End If
newTick = tick / 100 - firstTick + 1
' Use the tick count to change the current
' ship status. Animation is then
' dependent on the current status.
If newTick <= 10 Then
myShipStatus = ShipStatus.SS_LIFTOFF
ElseIf newTick <= midAltitude Then
myShipStatus = ShipStatus.SS_TURNING
Else
myShipStatus = ShipStatus.SS_ENGINEON
End If
Select Case myShipStatus
Case ShipStatus.SS_LIFTOFF
yVal += 0.015F
Case ShipStatus.SS_TURNING
yVal += 0.015F
angle = SetRotation(angle, 180F)
Case ShipStatus.SS_ENGINEON
isEngineFired = True
zVal = zVal - 0.04F
yVal = yVal + 0.005F
angle = SetRotation(angle, 180F)
If newTick > midAltitude + 30 Then
isShipDeparted = True
End If
End Select
End Sub
Private Function SetRotation(ByVal tempAngle As Single, ByVal rotationThreshold As Single) As Single
' SetRotation manipulates rotation values to simulate a vessel that
' gradually increases in turning speed, and then slows to
' a stop. rotationThreshold should be <= 180 degrees.
If isNewRotationOperation Then
' Reset values if this is a new rotation operation.
' Starting angle of ship must be added back in
' before the call to Matrix.RotationY.
tempAngle = 0.1F
isNewRotationOperation = False
End If
rotationThreshold = DegreesToRadians(rotationThreshold)
If tempAngle < rotationThreshold Then
Dim increment As Single = tempAngle
' Provide a gradual but increasing turning speed.
tempAngle *= 1.015F
lastIncrement = tempAngle - increment
Return tempAngle
Else
' Provide a gradual slowing to a stop.
tempAngle += lastIncrement * 0.75F
lastIncrement = lastIncrement * 0.75F
Return tempAngle
End If
End Function
Private Function DegreesToRadians(ByVal degrees As Single) As Single
Dim radians As Single = degrees *(3.141593F / 180F)
Return radians
End Function
Private Sub SetupMovingLight()
device.Lights(2).Type = LightType.Point
lightData = device.Lights(2)
device.Lights(2).Diffuse = Color.White
device.Lights(2).Range = 200F
If Not device.DeviceCaps.VertexProcessingCaps.SupportsPositionalLights Then
If device.LightsFixed(2).Type = LightType.Point Then
device.LightsFixed(2).Type = LightType.Directional
End If
End If
' Handle positioning for the light that emanates
' from the ship, representing the light from
' the main engines.
Select Case device.Lights(2).Type
Case LightType.Point
device.Lights(2).Position = New Vector3(0, yVal, zVal)
device.Lights(2).Attenuation1 = 0.2F
Case LightType.Directional
End Select ' Not implemented.
device.Lights(2).Update()
End Sub
Shared Sub Main()
Try
Dim d3dApp As New MatrixTransformsHowTo()
System.Windows.Forms.Application.Run(d3dApp)
Catch
MessageBox.Show("Your device does not have the needed 3-D " + "support to run this sample")
Catch
MessageBox.Show("Your device does not have the needed 3-D " + "support to run this sample")
Catch e As Exception
MessageBox.Show("The sample has run into an error and needs" + "to close: " + e.Message)
End Try
End Sub
End Class
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.WindowsMobile.DirectX;
using Microsoft.WindowsMobile.DirectX.Direct3D;
namespace MatrixTransforms
{
class MatrixTransformsHowTo : Form
{
// Mesh representing the ship.
Mesh shipMesh = null;
// Meshes representing buildings.
Mesh[] wallMeshes = new Mesh[3];
Color meshColor = Color.Goldenrod;
// Description of the Direct3D light.
private Light lightData;
Device device;
private enum ShipStatus
{
SS_LIFTOFF = 1,
SS_TURNING = 2,
SS_ENGINEON = 3
}
ShipStatus myShipStatus = ShipStatus.SS_LIFTOFF;
int firstTick = 0;
int newTick = 0;
float yVal = -2.0f;
float zVal = 2.0f;
const int midAltitude = 85;
float yCameraPosition = -1;
float xCameraPosition = -2;
float startAngle = 0.0f;
float angle = 0.1f;
float lastIncrement = 0.0f;
bool isEngineFired = false;
bool isShipDeparted = false;
bool isNewRotationOperation = true;
public MatrixTransformsHowTo()
{
PresentParameters present;
this.Text = "Flying Ship";
// Enable the form to be closed.
// Required so that Hwnd of the form changes.
this.MinimizeBox = false;
present = new PresentParameters();
present.Windowed = true;
present.AutoDepthStencilFormat = DepthFormat.D16;
present.EnableAutoDepthStencil = true;
present.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Default, this,
CreateFlags.None, present);
device.DeviceReset += new EventHandler(OnDeviceReset);
for (int i = 0; i < wallMeshes.Length; i++)
{
wallMeshes[i] = null;
}
OnDeviceReset(null, EventArgs.Empty);
}
private void OnDeviceReset(object sender, EventArgs e)
{
// Meshes must be recreated whenever the device
// is reset, no matter which pool they are created in.
// Instead of loading a mesh from a file,
// this sample uses primitive box meshes
// to represent the ship and the buildings.
shipMesh = Mesh.Box(device, .8f, 0.18f, 2.2f);
wallMeshes[0] = Mesh.Box(device, 0.5f, 3.6f, 1.0f);
wallMeshes[1] = Mesh.Box(device, 0.5f, 1.8f, 2.0f);
wallMeshes[2] = Mesh.Box(device, .2f, 1.0f, 0.75f);
device.RenderState.Ambient = Color.White;
// Provides main directional lighting.
device.Lights[0].Type = LightType.Directional;
device.Lights[0].Direction = new Vector3(0.3f, -0.5f, 0.2f);
device.Lights[0].Diffuse = Color.LightBlue;
device.Lights[0].Update();
// Provides frontal lighting.
device.Lights[1].Type = LightType.Directional;
device.Lights[1].Direction = new Vector3(0.0f, -1.0f, -3.0f);
device.Lights[1].Diffuse = Color.DarkSlateGray;
device.Lights[1].Update();
// Turn on the lights.
device.Lights[0].Enabled = true;
device.Lights[1].Enabled = true;
// Turn off the light representing the engine.
device.Lights[2].Enabled = false;
// For the projection matrix, set up a perspective transform (which
// transforms geometry from 3-D view space to 2-D viewport space, with
// a perspective divide that makes objects smaller in the distance). To build
// a perspective transform, you need the field of view (1/4 PI is common),
// the aspect ratio, and the near and far clipping planes (which define at
// the distances at which geometry should be no longer be rendered).
device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4.0F,
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0f, 80.0f);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do nothing.
}
protected override void OnPaint(PaintEventArgs e)
{
Material material = new Material();
Material engineMaterial = new Material();
// Begin the scene and clear the back buffer to black.
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black,
1.0f, 0);
device.BeginScene();
material.Diffuse = Color.WhiteSmoke;
// Specifies the ambient color for the engines.
engineMaterial.Ambient = Color.White;
SetupMatrices();
device.Material = material;
// Draw ship on the screen.
shipMesh.DrawSubset(0);
SetupMovingLight();
if (isEngineFired)
{
device.Material = engineMaterial;
device.Lights[2].Enabled = true;
// Bind the vertex buffers of the primitive
// mesh to the Device object.
device.SetStreamSource(0, shipMesh.VertexBuffer, 0);
// Redraw the face of the ship representing the engine.
// A Box mesh has 4 vertices per face. The 20th vertex
// is the first vertex representing the "engine." To use
// adjacent triangles, set the type to Primitive.TriangleFan.
device.DrawPrimitives(PrimitiveType.TriangleFan, 20, 2);
}
material.Diffuse = Color.GhostWhite;
device.Material = material;
// Draw buildings, providing coordinates to locate each
// building on the x, y, and z planes. Because the camera is placed
// "behind" the scene initially (at a positive z-axis value in
// the call to Matrix.LookAtLH), positive z-axis values draw
// objects closer to the camera. In addition, positive x-axis
// values draw objects farther to the left instead of to the right.
// Draw the tall building.
device.Transform.World = Matrix.Translation(.75f, -0.2f, -2.0f);
wallMeshes[0].DrawSubset(0);
// Draw the medium-sized buildings.
device.Transform.World = Matrix.Translation(-1.0f, -0.9f, 0.0f);
wallMeshes[1].DrawSubset(0);
device.Transform.World = Matrix.Translation(0.0f, -0.9f, 0.0f);
wallMeshes[1].DrawSubset(0);
device.Transform.World = Matrix.Translation(1.0f, -0.9f, 0.0f);
wallMeshes[1].DrawSubset(0);
device.Transform.World = Matrix.Translation(2.0f, -0.9f, 0.0f);
wallMeshes[1].DrawSubset(0);
// Draw the small buildings.
device.Transform.World = Matrix.Translation(-2.0f, -1.5f, 5.0f);
wallMeshes[2].DrawSubset(0);
device.Transform.World = Matrix.Translation(-1.25f, -1.5f, 5.0f);
wallMeshes[2].DrawSubset(0);
device.Transform.World = Matrix.Translation(-0.5f, -1.5f, 5.0f);
wallMeshes[2].DrawSubset(0);
device.Transform.World = Matrix.Translation(0.75f, -1.5f, 5.0f);
wallMeshes[2].DrawSubset(0);
// Finish the scene and present it on the screen.
device.EndScene();
device.Present();
// Repaint the scene.
this.Invalidate();
}
private void SetupMatrices()
{
// Set the transformation matrices.
float fAngle = angle;
// To render the ship, combine a rotation on the y-axis with a
// translation (move) using the Matrix.Multiply method.
device.Transform.World = Matrix.Multiply(Matrix.RotationY(fAngle + startAngle), Matrix.Translation(-0.5f, yVal, zVal));
// Set up the view matrix. You can define a view matrix with a camera position,
// a point to look at (camera target), and an "up" direction.
// First vector passed to LookAtLH is the camera position.
// Second vector passed to LookAtLH is the camera target.
// Third vector passed to LookAtLH defines the "up" direction.
// Here, you set the camera seven units up along the z-axis ("behind"
// the scene), down one unit, and left two units. You then point the camera
// just above the origin and define "up" to be in the y-direction.
if (!isShipDeparted)
{
device.Transform.View = Matrix.LookAtLH(new Vector3(-2, -1, 7),
new Vector3(0, 1, 0), new Vector3(0, 1, 0));
}
else
{
// Handles movement of camera after
// the ship "fires" the main engines.
device.Transform.View = Matrix.LookAtLH(new Vector3(xCameraPosition,
yCameraPosition, 7), new Vector3(0, 1, 0), new Vector3(0, 1, 0));
xCameraPosition += 0.01f;
yCameraPosition += 0.01f;
}
// Use the system time to control the animation.
// The high-resolution timer, if present for
// the hardware, could be used instead.
int tick = System.Environment.TickCount;
if (newTick == 0) { firstTick = tick / 100; }
newTick = (tick / 100) - firstTick + 1;
// Use the tick count to change the current
// ship status. Animation is then
// dependent on the current status.
if (newTick <= 10) { myShipStatus = ShipStatus.SS_LIFTOFF; }
else if (newTick <= midAltitude) { myShipStatus = ShipStatus.SS_TURNING; }
else { myShipStatus = ShipStatus.SS_ENGINEON; }
switch (myShipStatus)
{
case ShipStatus.SS_LIFTOFF:
yVal += 0.015f;
break;
case ShipStatus.SS_TURNING:
yVal += 0.015f;
angle = SetRotation(angle, 180.0f);
break;
case ShipStatus.SS_ENGINEON:
isEngineFired = true;
zVal = zVal - 0.04f;
yVal = yVal + 0.005f;
angle = SetRotation(angle, 180.0f);
if (newTick > midAltitude + 30) { isShipDeparted = true; }
break;
}
}
private float SetRotation(float tempAngle, float rotationThreshold)
{
// SetRotation manipulates rotation values to simulate a vessel that
// gradually increases in turning speed, and then slows to
// a stop. rotationThreshold should be <= 180 degrees.
if (isNewRotationOperation)
{
// Reset values if this is a new rotation operation.
// Starting angle of ship must be added back in
// before the call to Matrix.RotationY.
tempAngle = 0.1f;
isNewRotationOperation = false;
}
rotationThreshold = DegreesToRadians(rotationThreshold);
if (tempAngle < rotationThreshold)
{
float increment = tempAngle;
// Provide a gradual but increasing turning speed.
tempAngle *= 1.015f;
lastIncrement = tempAngle - increment;
return tempAngle;
}
else
{
// Provide a gradual slowing to a stop.
tempAngle += (lastIncrement * 0.75f);
lastIncrement = lastIncrement * 0.75f;
return tempAngle;
}
}
private float DegreesToRadians(float degrees)
{
float radians = degrees * (3.141592654f / 180.0f);
return radians;
}
private void SetupMovingLight()
{
device.Lights[2].Type = LightType.Point;
lightData = device.Lights[2];
device.Lights[2].Diffuse = Color.White;
device.Lights[2].Range = 200.0f;
if(!device.DeviceCaps.VertexProcessingCaps.SupportsPositionalLights)
{
if (device.LightsFixed[2].Type == LightType.Point)
device.LightsFixed[2].Type = LightType.Directional;
}
// Handle positioning for the light that emanates
// from the ship, representing the light from
// the main engines.
switch (device.Lights[2].Type)
{
case LightType.Point:
device.Lights[2].Position = new Vector3(0,
yVal, zVal);
device.Lights[2].Attenuation1 = 0.2f;
break;
case LightType.Directional:
// Not implemented.
break;
}
device.Lights[2].Update();
}
static void Main()
{
try
{
MatrixTransformsHowTo d3dApp = new MatrixTransformsHowTo();
System.Windows.Forms.Application.Run(d3dApp);
}
catch(NotSupportedException)
{
MessageBox.Show("Your device does not have the needed 3-D " +
"support to run this sample");
}
catch(DriverUnsupportedException)
{
MessageBox.Show("Your device does not have the needed 3-D " +
"support to run this sample");
}
catch(Exception e)
{
MessageBox.Show("The sample has run into an error and needs" +
"to close: " + e.Message);
}
}
}
}
コードのコンパイル方法
この例では、次の名前空間への参照が必要です。
参照
処理手順
概念
.NET Compact Framework に関する「方法」トピック