C#は電気羊の夢を見るか?(引っ越し中)

dtiブログが閉鎖とのことでhttp://tanocs.blog.fc2.com/へ引っ越します。

anchorとサイズの挙動

解決してみればなんということはないハマリだが、
これが意外と調べてもなかなかと答えが見つからなかったのでメモ。


アンカーを使ってコントールのサイズを自動的に決定する場合、
アンカーによって変更されたサイズをサイズプロパティからは取得できない。
(デザイナの初期設定値を平然と返す)

そこで、SizeChangedイベントからサイズを取得し、
そいつをわざわざ入れてやる必要がある。


なんで、見た目変わってるのにサイズプロパティを更新しないのだろうか・・・不思議。


private void pictureBox1_SizeChanged(object sender, EventArgs e)
{
Control control = (Control)sender;

pictureBox1.Width = control.Size.Width;
pictureBox1.Height = control.Size.Height;
}
このエントリーをはてなブックマークに追加
LINEで送る

お蔵入り

よし!forを自作してやる!と無茶苦茶なことを考え、一つの関数を作ってみた。

自然数N
希望するループ回数X

i= N - X + 0.4f; //0Divを避けるために小数を下駄として使用 0.4なのは浮動小数点での扱いが有利だから。
i = (i * abs(i) + pow(i, 2)) / (pow(i, 2) * 2); //0〜Nの時1を出力し、負の値を入力すると0が出力される関数
result += [iを利用した希望する式] * i;

あとはXを気合で手打ちするだけ。

i = InputWidth - 31.6f;
i = (i * abs(i) + pow(i, 2)) / (pow(i, 2) * 2); // 1 or 0
result += tex2D(SceneSampler, texCoord + float2((InputWidth - 32.0f) / InputWidth, 0)) * i;

i = InputWidth - 30.6f;
i = (i * abs(i) + pow(i, 2)) / (pow(i, 2) * 2); // 1 or 0
result += tex2D(SceneSampler, texCoord + float2((InputWidth - 31.0f) / InputWidth, 0)) * i;

i = InputWidth - 29.6f;
i = (i * abs(i) + pow(i, 2)) / (pow(i, 2) * 2); // 1 or 0
result += tex2D(SceneSampler, texCoord + float2((InputWidth - 30.0f) / InputWidth, 0)) * i * 100;

    ・
    ・
    ・

i = InputWidth - 1.6f;
i = (i * abs(i) + pow(i, 2)) / (pow(i, 2) * 2); // 1 or 0
result += tex2D(SceneSampler, texCoord + float2((InputWidth - 2.0f) / InputWidth, 0)) * i * 100;

i = InputWidth - 0.6f;
i = (i * abs(i) + pow(i, 2)) / (pow(i, 2) * 2); // 1 or 0
result += tex2D(SceneSampler, texCoord + float2((InputWidth - 1.0f) / InputWidth, 0)) * i * 100;


ちなみに、サンプルは前回からやってるあれだったりするのだが、
見事にHLSLのなんかの上限にぶち当たったため断念。

これで128*128がやりたかったんだけど、どうやら駄目だった模様。
なんかの一次元ループにゃ使い道が・・・ないか(´・ω・)


動かなかったソースは続きに一応置いときます。
このエントリーをはてなブックマークに追加
LINEで送る

続きを読む »

GPUを使って計算した結果をCPUに戻す[ちょっと便利で速い版]

二日前の記事のHLSLのみ書き換えた版

これで前回255回が上限だったループが4095回まで拡張できた。
ただ、もしかするとグラボによっては動かない可能性もあるので注意が必要。


このソースの検証時にようやく気がついたのだが、
GPUさんは浮動小数点の誤差に結構弱いことを思い出した。
0.1fを512個とか加算してくと顕著に現れてくる。

この辺はゲームだったら、
このぐらいの誤差はそれほど気にならないから的な理由だったと思う。

利用目的次第だが、誤差が気になる場合は計算する前の値に*10とか*100とかしてやり
0.1fとか苦手な小数を1.0fなどの整数にかえて計算してやってから/10してやると誤差はなくなる。

*10とか*100とかの下駄のはかせ具合は利用する際の目的や予想される数値次第なので、
使う人それぞれでご対応くだされ。


■HLSL

float InputWidth;
float4 result;

texture SceneTexture;
sampler SceneSampler : register(s0) = sampler_state
{
Texture = (SceneTexture);
};

float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
InputWidth %= 4096;
int i;
int j;
int Loop1 = InputWidth / 64;
Loop1 %= 64;
result = 0;

for (j = 0; j < Loop1; j++) {
for (i = 0; i < 64; i++) {
result += tex2D(SceneSampler, texCoord + float2(1.0f / InputWidth * (j * 64 + i), 0)) * 100.0f;
}
}

for (j = 0; j < InputWidth % 64; j++){
result += tex2D(SceneSampler, texCoord + float2(1.0f / InputWidth * (Loop1 * 64 + j), 0)) * 100.0f;
}

return result / 100.0f;
}

technique CulculateTechnique
{
pass Pass1
{
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
このエントリーをはてなブックマークに追加
LINEで送る

GPUを使って計算した結果をCPUに戻す[便利で遅い版]

とりあえずで完成した物を配置


これなら簡単にforが上限なしで使える!しかもPS2.0で良い!
と思ったものの、この実装だとあまりGPUを活用出来ていない気がする・・・


次回は高速な処理のままforの上限をもう少し伸ばしたバージョンを作成予定


■メインソース

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1 {
public class Game1 : Microsoft.Xna.Framework.Game {
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

Texture2D inputTexture;
Texture2D initTexture;
RenderTarget2D result;
Effect additionCalculator;

float[] culcurate;
float[] resultBuffer = new float[1];

public Game1() {
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}

protected override void Initialize() {
culcurate = new float[] { 1.0f, 0.1f, 0.2f, 0.3f };
base.Initialize();
}

protected override void LoadContent() {
spriteBatch = new SpriteBatch(this.GraphicsDevice);

inputTexture = new Texture2D(GraphicsDevice, culcurate.Length, 1, 0, TextureUsage.None, SurfaceFormat.Single);
inputTexture.SetData(culcurate);

initTexture = new Texture2D(GraphicsDevice, 1, 1, 0, TextureUsage.None, SurfaceFormat.Single);
initTexture.SetData(new float[]{0.0f});

result = new RenderTarget2D(GraphicsDevice, 1, 1, 0, SurfaceFormat.Single);


additionCalculator = Content.Load("AdditionCalculator");
}

protected override void UnloadContent() {
inputTexture.Dispose();
result.Dispose();
}

protected override void Update(GameTime gameTime) {
Window.Title = resultBuffer[0].ToString();
base.Update(gameTime);
}

protected override void Draw(GameTime gameTime) {
GraphicsDevice.SetRenderTarget(0, result);
spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
spriteBatch.Draw(initTexture, Vector2.Zero, Color.White);
spriteBatch.End();

additionCalculator.CurrentTechnique = additionCalculator.Techniques["CulculateTechnique"];

for (int i = 0; i < culcurate.Length; i++){
GraphicsDevice.SetRenderTarget(0, null);
additionCalculator.Parameters["SrcMap"].SetValue(result.GetTexture());
additionCalculator.Parameters["InputWidth"].SetValue(1.0f / culcurate.Length * i);

GraphicsDevice.SetRenderTarget(0, result);

spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
additionCalculator.Begin();
additionCalculator.CurrentTechnique.Passes[0].Begin();

spriteBatch.Draw(inputTexture, Vector2.Zero, Color.White);

additionCalculator.CurrentTechnique.Passes[0].End();
additionCalculator.End();
spriteBatch.End();
}

GraphicsDevice.SetRenderTarget(0, null);

result.GetTexture().GetData(resultBuffer);

base.Draw(gameTime);
}
}
}


■HLSL

float InputWidth;

texture SceneTexture;
sampler SceneSampler : register(s0) = sampler_state
{
Texture = (SceneTexture);
};

texture SrcMap;
sampler SrcSamp = sampler_state
{
Texture = ;
};

float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
return tex2D(SrcSamp, float2(0.5f, 0.5f)) + tex2D(SceneSampler, texCoord + float2(InputWidth, 0));
}

technique CulculateTechnique
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
このエントリーをはてなブックマークに追加
LINEで送る

GPUを使って計算した結果をCPUに戻す[かってに改蔵]

GPUを利用した計算はおそらくCUDAの方が優れてるんじゃないかと思う。
しかしながら、今までさんざんHLSLでやっている訳で、
さらにそれほど時間もないのでHLSLにて実装してみる。


元はMemeplexesさんところの以下の記事
[XNA] GPUを使って計算した結果をCPUに戻す


改造点としては
・とりあえず配列で渡せるようにしてみた。
・GPUから値を戻す時の余分なバッファを削除
・ソース省略の目的でVertexPositionTextureを使わずにスプライトバッチで描画する方法を採用

問題点としては
・スプライトバッチでの処理速度への影響はプラスなのかマイナスなのか良く解らない。
・hlslなのにforとか使っていてかなりカッチョ悪い
・ピクセルシェーダー3.0じゃないとバッファ食いつぶす問題がある
・配列数が256を超えられない(これについては後日改訂予定)

昔、GPUで2D処理は遅いようなことをチラッと聞いたことがあるが、
内部的にはどうせ3Dだろ?と思うと、ソースコードが読みやすい方を正義と見たい。

全ソースコードは以下のとおり

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame1 {
public class Game1 : Microsoft.Xna.Framework.Game {
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

Texture2D inputTexture;
RenderTarget2D result;
Effect additionCalculator;

float[] culcurate;
float[] resultBuffer = new float[1];

public Game1() {
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}

protected override void Initialize() {
culcurate = new float[] { 0.3f, 0.4f, 0.7f, 0.5f };
base.Initialize();
}

protected override void LoadContent() {
spriteBatch = new SpriteBatch(this.GraphicsDevice);

inputTexture = new Texture2D(GraphicsDevice, culcurate.Length, 1, 0, TextureUsage.None, SurfaceFormat.Single);
inputTexture.SetData(culcurate);

result = new RenderTarget2D(GraphicsDevice, 1, 1, 0, SurfaceFormat.Single);

additionCalculator = Content.Load("AdditionCalculator");
}

protected override void UnloadContent() {
inputTexture.Dispose();
result.Dispose();
}

protected override void Update(GameTime gameTime) {
Window.Title = resultBuffer[0].ToString();
base.Update(gameTime);
}

protected override void Draw(GameTime gameTime) {
GraphicsDevice.SetRenderTarget(0, result);

additionCalculator.CurrentTechnique = additionCalculator.Techniques["CulculateTechnique"];
additionCalculator.Parameters["InputWidth"].SetValue(culcurate.Length);

spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
additionCalculator.Begin();
additionCalculator.CurrentTechnique.Passes[0].Begin();

spriteBatch.Draw(inputTexture, Vector2.Zero, Color.White);

additionCalculator.CurrentTechnique.Passes[0].End();
additionCalculator.End();
spriteBatch.End();

GraphicsDevice.SetRenderTarget(0, null);

result.GetTexture().GetData(resultBuffer);

base.Draw(gameTime);
}
}
}



んでHLSLが以下のとおり

float InputWidth;

texture SceneTexture;
sampler SceneSampler : register(s0) = sampler_state
{
Texture = (SceneTexture);
};

float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
int limit = InputWidth % 256;
float4 result = 0;
for(int i = 0; i < limit; i++) {
result += tex2D(SceneSampler, texCoord + float2(1.0f / InputWidth * i, 0));
}
return result;
}

technique CulculateTechnique
{
pass Pass1
{
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}



なんていうか、ここまでコメントがないソースも久しぶりに書いた・・

動作概要としては
culcurate = new float[] { 0.3f, 0.4f, 0.7f, 0.5f };
にて計算したい値をセット
Window.Title = resultBuffer[0].ToString();
にて計算結果をウィンドウのタイトルに設定しているだけ。

HLSL部はもっと綺麗に書く方法があると思うんだけどなぁ・・
動的な配列ってどう扱ったらいいんじゃろうねぇ。
このエントリーをはてなブックマークに追加
LINEで送る

XNAで動的コンテツを扱うときの注意点 その2

動的にインポートするコンテンツ事態は前回の方法でうまく行ったのだが、
読み込んだモデルをアニメーションさせるために
"SkinnedModelProcessor"を使用したいと思うとかなり苦労したのでメモ


ContentBuilder.csを配置しているプロジェクトにて
"Miscrosoft.Xna.Framework.Content.Pipeline.Processors"を参照設定に追加して

ContentBuilder.cs 内のメソッド CreateBuildProject() へ以下のように追記してやれば良い

// 任意のカスタム インポーターまたはプロセッサを登録します。
foreach(string pipelineAssembly in pipelineAssemblies) {
msBuildProject.AddNewItem("Reference", pipelineAssembly);
}

BuildItem item = msBuildProject.AddNewItem("Reference", typeof(SkinnedModelProcessor).AssemblyQualifiedName);
item.SetMetadata("SpecificVersion", "False");
item.SetMetadata("HintPath", typeof(SkinnedModelProcessor).Assembly.Location);


あとは用意したLoadModelメソッドにて

//contentBuilder.Add(fileName, "Model", null, "ModelProcessor");
contentBuilder.Add(fileName, "Model", null, "SkinnedModelProcessor");
とかって変更してやればOK


動的コンテンツの情報が日本に全然ない中、MMDXのソースはかなり参考になりました。
特に typeof(SkinnedModelProcessor) の記述は
海外のサンプルをいくらあさっても見つからなかったので、かなり助けられました。
このエントリーをはてなブックマークに追加
LINEで送る

XNAで動的コンテツを扱うときの注意点 その1

クリエータズクラブの奴はXNAというよりWinform側から作られていたので、
こいつをXNA側から作る時に、はまった内容のメモ。

利点は使い勝手が変わらないこと。
WinformからだとUpdate周りの処理をごっそり実装しなおす必要があって結構手間なので、
過去資産を活かす目的でXNA側からアプローチ

欠点としては、ちょうど昨年頭頃から課題として宙に浮いている入力周りが使えないこと。

まぁ、今回はゲームなのでデメリットは十分は無視できる。


んで、気をつける点。
まずファイルダイアログを呼ぶために『program.cs』に[STAThread]を記述する必要がある。

こんな感じ↓

using System;

namespace DaminzModelViewer {
static class Program {
[STAThread]
static void Main(string[] args) {
using(Game1 game = new Game1()) {
game.Run();
}
}
}
}


つぎに

"BuildContent" タスクは、アセンブリ "Microsoft.Xna.Framework.Content.Pipeline, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" からインスタンス化できませんでした。タスク アセンブリが、このコンピュータにインストールされているバージョンと同じバージョンの Microsoft.Build.Framework アセンブリを使用してビルドされたことを確認して下さい。型'Microsoft.Xna.Framework.ContentPipeline.Tasks.BuildContent' のオブジェクトを型'Microsoft.Build.Framework.ITask' にキャストできません。
"BuildContent"タスクが宣言されたか、正しく使用されなかったか、または作成中に失敗しました。タスク名とアセンブリ名のスペルを確認して下さい。

とかって糞長いエラーメッセージの解消方法。


ソリューションエクスプローラーからプロジェクトを右クリック
追加→アプリケーション構成ファイル
とするとApp.configが追加されるのでその内容を以下のようにする。


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="3.5.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>


あとは、参照設定に追加するMicrosoft.Build.EngineとMicrosoft.Build.Frameworkのバージョンを
3.5に欲張ると何故かうまくいかないので2.0を使うことぐらいかな。


あとは普通に参照設定にSystem.Windows.Fromsを追加して

using System.IO;
using System.Windows.Forms;


あたりを追加すればできるはず。
他に何かはまったらここに追記していくつもり。
このエントリーをはてなブックマークに追加
LINEで送る

新年あけましておめでとうございます。

昨年はいろいろあって、最終的には職が変わったりしたけど、
今年はより多くの実りある年にしたいですね。

一言で言えば「発信」の年にしていきたいと思う。
このエントリーをはてなブックマークに追加
LINEで送る

 | HOME | 

PAGE TOP ▲

Appendix

■春条

■春条

生息地は愛知
車と甘い物が好きな31歳
特技は無限昼寝

MONOからSharpDXを使う
変態的な手法で、
.NET Frameworkを使わずに
ゲーム作りやってます。

Search

Calender

« | 2011-01 | »
S M T W T F S
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -

Twitter

Recent Entries

DTIブログポータルへ
このブログを通報
Report Abuse

利用規約