開発環境 |
Microsoft Visual C# 2010 Express (SP1) |
実行環境 |
Microsoft Windows XP Home Edition (SP3) |
プロジェクトの種類 |
Windows Game (4.0) |
プロジェクト名 |
XnaTexture2D |
参考
Game1.cs
/*
* XnaTexture2D4 正距方位図法
*
* プロジェクトのプロパティ
* [XNA Game Studio]タブ
* Use HiDef to access the complete API
*/
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace XnaTexture2D
{
class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
VertexBuffer vertexBuffer;
Effect effect;
BasicEffect basicEffect;
Texture2D texture;
VertexPositionColor[] cross;
EffectParameter fxLat;
EffectParameter fxLon;
EffectParameter fxAxis;
float lat = 35;
float lon = 135;
// fps
int fpsSec;
int fpsDraw = 0;
int fpsCount = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void LoadContent()
{
sprite = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("SpriteFont1");
texture = Content.Load<Texture2D>("earthmap1k");
effect = Content.Load<Effect>("Effect1");
effect.Parameters["EarthMap"].SetValue(texture);
effect.Parameters["aspect"].SetValue(GraphicsDevice.Viewport.AspectRatio);
fxLat = effect.Parameters["centerLatRad"];
fxLon = effect.Parameters["centerLonRad"];
fxAxis = effect.Parameters["axis"];
fxLat.SetValue(MathHelper.ToRadians(lat));
fxLon.SetValue(MathHelper.ToRadians(lon));
SetAxis();
basicEffect = new BasicEffect(GraphicsDevice);
// 地図
VertexPositionTexture[] vertices = new VertexPositionTexture[4];
vertices[0] = new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2(0, 0));
vertices[1] = new VertexPositionTexture(new Vector3(1, 1, 0), new Vector2(1, 0));
vertices[2] = new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0, 1));
vertices[3] = new VertexPositionTexture(new Vector3(1, -1, 0), new Vector2(1, 1));
vertexBuffer = new VertexBuffer(GraphicsDevice,
typeof(VertexPositionTexture), 4, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
// 照準
cross = new VertexPositionColor[4];
cross[0] = new VertexPositionColor(new Vector3(-0.05f, 0, 0), Color.White);
cross[1] = new VertexPositionColor(new Vector3(0.05f, 0, 0), Color.White);
cross[2] = new VertexPositionColor(new Vector3(0, -0.1f, 0), Color.White);
cross[3] = new VertexPositionColor(new Vector3(0, 0.1f, 0), Color.White);
base.LoadContent();
}
protected override void Update(GameTime gameTime)
{
float deltaLat = 0;
float deltaLon = 0;
bool modified = false;
KeyboardState kState = Keyboard.GetState();
if (kState.IsKeyDown(Keys.Escape)) Exit();
if (kState.IsKeyDown(Keys.Up)) deltaLat = 1;
if (kState.IsKeyDown(Keys.Down)) deltaLat = -1;
if (kState.IsKeyDown(Keys.Left)) deltaLon = -1;
if (kState.IsKeyDown(Keys.Right)) deltaLon = 1;
if (deltaLat != 0)
{
lat = MathHelper.Clamp(lat + deltaLat, -89.9f, 89.9f);
fxLat.SetValue(MathHelper.ToRadians(lat)); // -pi/2 - pi/2
modified = true;
}
if (deltaLon != 0)
{
lon += deltaLon;
if (lon <= -180) lon += 360;
if (180 < lon) lon -= 360;
fxLon.SetValue(MathHelper.ToRadians(lon)); // -pi - pi
modified = true;
}
if (modified)
{
SetAxis();
}
base.Update(gameTime);
}
void SetAxis()
{
float rad = MathHelper.ToRadians(lat);
float y = (float)Math.Sin(rad);
float r = (float)Math.Cos(rad);
rad = MathHelper.ToRadians(lon);
float z = (float)Math.Cos(rad) * r;
float x = (float)Math.Sin(rad) * r;
Vector3 v = new Vector3(x, y, z);
v.Normalize();
fxAxis.SetValue(v);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
GraphicsDevice.SetVertexBuffer(vertexBuffer);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
}
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, cross, 0, 2);
}
// fps
fpsDraw++;
if (gameTime.TotalGameTime.Seconds != fpsSec)
{
fpsCount = fpsDraw;
fpsDraw = 0;
fpsSec = gameTime.TotalGameTime.Seconds;
}
sprite.Begin();
string text = string.Format("fps={0} lat={1:f1} lon={2:f1}", fpsCount, lat, lon);
sprite.DrawString(font, text, new Vector2(0, 0), Color.Red);
sprite.End();
base.Draw(gameTime);
}
}
}
Effect1.fx
// XnaTexture2D4 正距方位図法
texture EarthMap;
float centerLatRad;
float centerLonRad;
float aspect;
float3 axis;
sampler TextureSampler = sampler_state
{
texture = <EarthMap>;
minfilter = linear;
magfilter = linear;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
output.Position = input.Position;
output.TexCoord = input.TexCoord;
return output;
}
float4 MulQ(float4 q1, float4 q2)
{
float4 q;
q.x = (q1.w * q2.x) + (q1.x * q2.w) + (q1.y * q2.z) - (q1.z * q2.y);
q.y = (q1.w * q2.y) + (q1.y * q2.w) + (q1.z * q2.x) - (q1.x * q2.z);
q.z = (q1.w * q2.z) + (q1.z * q2.w) + (q1.x * q2.y) - (q1.y * q2.x);
q.w = (q1.w * q2.w) - (q1.x * q2.x) - (q1.y * q2.y) - (q1.z * q2.z);
return q;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float x = input.TexCoord.x * 2.0f - 1.0f; // -1 - 1
float y = input.TexCoord.y * 2.0f - 1.0f; // -1 - 1
x *= aspect;
// 距離(=回転軸からの角度)0 - 1
float dist = sqrt(x * x + y * y);
if (1.0f < dist)
{
discard;
}
if (abs(dist - 0.5f) < 0.0015f)
{
return float4(1, 1, 0, 1);
}
// 方位角(=回転する角度)-pi - pi
float angleRad = atan2(x, -y);
// 回転する座標
float4 p;
float rad = centerLatRad + radians(dist * 180.0f);
p.y = sin(rad);
float r = cos(rad);
p.z = cos(centerLonRad) * r;
p.x = sin(centerLonRad) * r;
p.w = 0;
// 回転
float4 rot;
angleRad *= 0.5f;
rot.xyz = axis * sin(angleRad);
rot.w = cos(angleRad);
float4 conj;
conj.xyz = -rot.xyz;
conj.w = rot.w;
float4 q = MulQ(MulQ(conj, p), rot);
float lat = 90.0f - degrees(asin(q.y));
float lon = 180.0f + degrees(atan2(q.x, q.z));
float eps = 0.2f / (0.2f + dist);
if (lat % 10.0f < eps || lon % 15.0f < eps)
{
return float4(1, 1, 1, 1);
}
float2 t;
t.x = lon / 360.0f;
t.y = lat / 180.0f;
return tex2D(TextureSampler, t);
}
technique Technique1
{
pass Pass1
{
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
最終更新:2012年12月20日 12:21