2011年11月28日月曜日

普通のHaskellプログラミング入門 ghc Glasgow Haskell Compiler, Version 7.2.2, stage 2 booted by GHC version 6.12.2

なにも知らなすぎるので、コンパイルできないと悩みまくる
ひとまず
 import Listは
 import Data.List
にする見たい。

パターンマッチの
 prefixp line = pattern `isPrefixOf` line
の`isPrefixOf`はshift+7の'では、もちろん無く
`(shift+@)のほうでした。。。

import Systemでコンパイルエラーが出る

ふつうのHaskellプログラミングのecho.hsのところで
import System
がコンパイル通らないのでググルと
http://tnomura9.exblog.jp/14966671/
import System.Environment (getArgs)
このように記述する旨書いてありました。
ghcのバージョンのせいなのか
The Glorious Glasgow Haskell Compilation System, version 7.2.2

なにがなんだか理解していませんが、ひとまず先に進めそうです。

よくみると

import System.Environment (getArgs)
じゃなくて

import System
の代わりに
import System.Environment
でいいっぽい

本の時代から
Systemが細分化されたのかな?

2011年11月17日木曜日

ふつうのHaskellプログラミングのUS-states.txt

US-states.txtに近いものを用意してみましたw

AK Alaska - Juneau
AL Alabama - Montgomery
AR Arkansas - Little Rock
AS American Samoa
AZ Arizona - Phoenix
CA California - Sacramento
CO Colorado - Denver
CT Connecticut - Hartford
DC District of Columbia, which is the seat of the Federal government
DE Delaware - Dover
FL Florida - Tallahassee
GA Georgia - Atlanta
GU Guam
HI Hawaii - Honolulu
IA Iowa - Des Moines
ID Idaho - Boise
IL Illinois - Springfield
IN Indiana - Indianapolis
KS Kansas - Topeka
KY Kentucky - Frankfort
LA Louisiana - Baton Rouge
MA Massachusetts - Boston
MD Maryland - Annapolis
ME Maine - Augusta
MI Michigan - Lansing
MN Minnesota - Saint Paul
MO Missouri - Jefferson City
MP Northern Mariana Islands, Commonwealth
MS Mississippi - Jackson
MT Montana - Helena
NC North Carolina - Raleigh
ND North Dakota - Bismarck
NE Nebraska - Lincoln
NH New Hampshire - Concord
NJ New Jersey - Trenton
NM New Mexico - Santa Fe
NV Nevada - Carson City
NY New York - Albany
OH Ohio - Columbus
OK Oklahoma - Oklahoma City
OR Oregon - Salem
PA Pennsylvania - Harrisburg
PR Puerto Rico, Commonwealth
RI Rhode Island - Providence
SC South Carolina - Columbia
SD South Dakota - Pierre
TN Tennessee - Nashville
TX Texas - Austin
UT Utah - Salt Lake City
VA Virginia - Richmond
VI the United States Virgin Islands
VT Vermont - Montpelier
WA Washington - Olympia
WI Wisconsin - Madison
WV West Virginia - Charleston
WY Wyoming - Cheyenne

2011年10月16日日曜日

マネージメント&ディレクション

直近のプロジェクトでプロジェクトの運用の方面に近い箇所を担当する事になって、今までプロジェクトを回してもらってきて不満に思っていた箇所がどういう事で発生するのかわかってきた気がします。 一番思ったことは、プロジェクトの方針がだんだんぼやけてくる事。 あれ?聞いていた事と違う事が発生している?と疑問に思うことが増えてくると、だんだん不信感が高まってきます。 運営側がすべてを隠蔽するくらいのものならばそれでいいのかもしれませんが、現場に叱咤激励を飛ばしてくる場合にだんだん失敗の尻拭いをさせられている気になってきます。 個人的に簡単で効果があることは、プロジェクトの現在の方針を細かいPDCのイテレーションのなかのPで更新共有することではないかと思います。 マネージメントなどを一人で行なっている場合にどうしてもPDDDDCになってしまいがちかと思います。 それを全員でPDCを共有することで抜けやミスをする機会を減らせるのでは無いかと思います。 そうすれば、結果的にPを忘れてんぞ!とかCして無いけどおかしいなとなってくるのではないかな。 結構現場ではCしてないってことには気がついているものです。 ほったらかされているのが、まさにCしていないってことです。 この際に、まあいいか。知らねー。なんでやらないのか!と心で思っているだけではなく、気づいた人からアクションを行えるようになったらいいな。と思います。 とにかく、何かの役割を人に背負わせるのは、その人が失敗したときに責めて終わりというわけには行きません。 意識していきたいなー。

2011年6月23日木曜日

SSAO僕にも出来たよ!

シェーダプログラムをやっておかないとなと思って、さしあたってSSAOにロマンを感じていたので挑戦してみました。
シェーダの前提が全然わからず、かなり辛かったのですがいろいろ協力いただいてひとまず表示までこぎつけました。

ランバートライティングのみで光源がちょうど反対側でしょうか。
のっぺりしているところを撮りました。
同じ角度でSSAOを利かせますと、陰影がディティール感出ますね。
実装方法です。初心者向けです。
まずフレームワークというかウインドウの初期化やDirectXの初期化は適当に済ませてください。
まるぺけさんのhttp://marupeke296.com/TIPS_UltraShortDirectXProg.htmlとかいいと思います。

プログラムの方は以下の雰囲気です。
ID3DXEffect* pEffect;
D3DXMATRIX View, Proj;
LPDIRECT3DSURFACE9       backbuffer;
LPDIRECT3DTEXTURE9       texColor;
LPDIRECT3DSURFACE9       surColor;
LPDIRECT3DTEXTURE9       texNormalDepth;
LPDIRECT3DSURFACE9       surNormalDepth;
LPDIRECT3DTEXTURE9       rayMap;

// エフェクトの読み込み
LPD3DXBUFFER pErr = NULL;
HRESULT hr = D3DXCreateEffectFromFile(
 d3ddev,
 _T("SSAO.fx"),
 NULL,
 NULL,
 D3DXSHADER_DEBUG,
 NULL,
 &pEffect,
 &pErr);
if( FAILED( hr ) )
{
 if( pErr != NULL )
 { // コンパイルエラー出力
  const char *err = (char*)pErr->GetBufferPointer();
  pErr->Release();
 }
}
// バックバッファを覚えとく
d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
// SSAOで使う。レイマップ/法線深度マップ/通常のカラーマップを作成します
// GetScreenWidth/GetScreenHeightはスクリーンサイズを取ってくるのを作ってください
d3ddev->CreateTexture(GetScreenWidth(), GetScreenHeight(), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT, &texColor, 0);
texColor->GetSurfaceLevel(0, &surColor);
d3ddev->CreateTexture(GetScreenWidth(), GetScreenHeight(), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A32B32G32R32F,D3DPOOL_DEFAULT, &texNormalDepth, 0);
texNormalDepth->GetSurfaceLevel(0, &surNormalDepth);

// 16x16のレイマップを作成しますmakeRayMapという
// コールバック関数を自分で用意してテクスチャに書き込んじゃいます
d3ddev->CreateTexture(16, 16, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_MANAGED, &rayMap, 0);
D3DXFillTexture(rayMap, makeRayMap, 0);

// ビュー変換・射影変換
D3DXMatrixPerspectiveFovLH( &Proj, D3DXToRadian(45), static_cast(GetScreenWidth())/static_cast(GetScreenHeight()), 1.0f, 10000.0f);
で初期化をしておきます。
makeRayMap関数は以下のとおりです。
コメントアウトしている方が本来のレイの作成方法なのですが、拾ってきたベクトル群の方が見た目いい感じだったので、そっちにしました。
static void WINAPI makeRayMap(D3DXVECTOR4* pOut, const D3DXVECTOR2* pTexCoord, const D3DXVECTOR2* pTexelSize, void* data)
{
/*
 float r = 1.0f * (float)rand() / (float)RAND_MAX;
 float t = 6.2831853f * (float)rand() / ((float)RAND_MAX + 1.0f);
 float cp = 2.0f * (float)rand() / (float)RAND_MAX - 1.0f;
 float sp = sqrt(1.0f - cp * cp);
 float ct = cos(t), st = sin(t);

 pOut->x = abs(r * sp * ct);
 pOut->y = abs(r * sp * st);
 pOut->z = abs(r * cp);
 pOut->w = 0;
*/
 static int i=0;

 D3DXVECTOR3 vec;
 switch(i%16)
 {
 case 0: vec = D3DXVECTOR3(0.53812504f, 0.18565957f, -0.43192f); break;
 case 1: vec = D3DXVECTOR3(0.13790712f, 0.24864247f, 0.44301823f); break;
 case 2: vec = D3DXVECTOR3(0.33715037f, 0.56794053f, -0.005789503f); break;
 case 3: vec = D3DXVECTOR3(-0.6999805f, -0.04511441f, -0.0019965635f); break;
 case 4: vec = D3DXVECTOR3(0.06896307f, -0.15983082f, -0.85477847f); break;
 case 5: vec = D3DXVECTOR3(0.056099437f, 0.006954967f, -0.1843352f); break;
 case 6: vec = D3DXVECTOR3(-0.014653638f, 0.14027752f, 0.0762037f); break;
 case 7: vec = D3DXVECTOR3(0.010019933f, -0.1924225f, -0.034443386f); break;
 case 8: vec = D3DXVECTOR3(-0.35775623f, -0.5301969f, -0.43581226f); break;
 case 9: vec = D3DXVECTOR3(-0.3169221f, 0.106360726f, 0.015860917f); break;
 case 10:vec = D3DXVECTOR3(0.010350345f, -0.58698344f, 0.0046293875f); break;
 case 11:vec = D3DXVECTOR3(-0.08972908f, -0.49408212f, 0.3287904f); break;
 case 12:vec = D3DXVECTOR3(0.7119986f, -0.0154690035f, -0.09183723f); break;
 case 13:vec = D3DXVECTOR3(-0.053382345f, 0.059675813f, -0.5411899f); break;
 case 14:vec = D3DXVECTOR3(0.035267662f, -0.063188605f, 0.54602677f); break;
 case 15:vec = D3DXVECTOR3(-0.47761092f, 0.2847911f, -0.0271716f); break;
 }
  // テクスチャなので0-1の値しか持てないので、-1,1を0,1へ変換
 pOut->x = (vec.x+1.f)*0.5f;
 pOut->y = (vec.y+1.f)*0.5f;
 pOut->z = (vec.z+1.f)*0.5f;
 pOut->w = 0.f;
 ++i;
}
毎フレのループが以下の感じです。
float f,l; // 毎フレ動かしたかったので適当な変数
struct d3dverts {
 float x, y, z, w;
 float u, v;
 enum { fvf = D3DFVF_XYZRHW | D3DFVF_TEX1 };
};

d3ddev->BeginScene();
f+=dt; // もちろん適当でdtはデルタタイムをどっかから持ってくる
l=sin(f)*2.f+300.f;

D3DXMATRIX mat;
D3DXMatrixLookAtLH( &View, &D3DXVECTOR3(l*sin(f),5.f,-l*cos(f)), &D3DXVECTOR3(0,0,0), &D3DXVECTOR3(0,1,0) );
D3DXMatrixIdentity( &mat );
mat = mat * View * Proj;
// シェーダ内で使う変数更新
pEffect->SetMatrix( "m_WVP", &mat );
pEffect->SetVector( "m_LightDir", &D3DXVECTOR4(1,1,1,0) );
pEffect->SetVector( "m_Ambient" , &D3DXVECTOR4(0.5,0.5,0.5,0));

// MRTをつかって普通のカラーレンダリングと法線と深度値のテクスチャを
// それぞれ surColor(texColor)/surNormalDepth(texNormalDepth)に出力する
d3ddev->SetRenderTarget(0, surColor);
d3ddev->SetRenderTarget(1, surNormalDepth);
d3ddev->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0, 1.0f, 0);

// 描画開始
pEffect->SetTechnique( "RenderScene0" );
UINT numPass;
pEffect->Begin( &numPass, 0 );

pEffect->BeginPass(0);
// ここはどうにかメッシュでもモデルデータを表示する処理を作っておいてください
for(auto ite = m_kMeshObjectList.begin(); m_kMeshObjectList.end()!=ite; ite++)
{
 (*ite)->Draw();
}
pEffect->EndPass();
// ここまででカラーと法線深度テクスチャの完成

// ここから上で作ったテクスチャをもとに画面に描画する
d3ddev->SetRenderTarget(0, backbuffer);
d3ddev->SetRenderTarget(1, NULL);  // これやらないと表示されない!!
d3ddev->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
// それぞれ0,1,2の順番でそれぞれのテクスチャを設定する
d3ddev->SetTexture(0, rayMap );
d3ddev->SetTexture(1, texNormalDepth );
d3ddev->SetTexture(2, texColor );
        
// SSAOはピクセルシェーダだけなのでバーテックスシェーダは走らせない
pEffect->BeginPass(1);
// 画面いっぱいに4角ポリゴンを表示してピクセルシェーダを走らせる
// この時 d3dverts で適宜した D3DFVF_XYZRHW がヴァーテックスシェーダ走らせなくても計算済みの頂点(4角ポリ)
// だよと定義するものらしいです。
d3ddev->SetFVF( d3dverts::fvf  );
const d3dverts quadverts[4] = {
{ -0.5f+0.f,   -0.5f,                   0.0f, 1.0f, 0.0f, 0.0f},
{ -0.5f+GetScreenWidth(), -0.5f,                   0.0f, 1.0f, 1.0f, 0.0f},
{ -0.5f+0.f,   -0.5f+GetScreenHeight(), 0.0f, 1.0f, 0.0f, 1.0f},
{ -0.5f+GetScreenWidth(), -0.5f+GetScreenHeight(), 0.0f, 1.0f, 1.0f, 1.0f},
};
d3ddev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quadverts, sizeof(d3dverts));
pEffect->EndPass();
pEffect->End();
d3ddev->EndScene();
d3ddev->Present( NULL, NULL, NULL, NULL );
以下がシェーダです。
これは
http://d.hatena.ne.jp/shuichi_h/20100318
から拝借したもので、コードの説明自体は同じことです。
SSAO.fx
はじめのバーテックスシェーダとピクセルシェーダは通常のモデル描画&カラー、法線深度値出力用

float4x4 m_WVP;
float4 m_LightDir;
float4 m_Ambient = 0.0f;
struct VS_OUTPUT
{
  float4 Pos   : POSITION;     //頂点の座標
  float4 Col   : COLOR0;       //頂点カラー
  float4 depth : COLOR1 ;
  float3 normal : COLOR2 ;
};
VS_OUTPUT VS( float4 Pos     : POSITION,   //頂点の座標
              float4 Normal  : NORMAL )    //法線ベクトル
{
   VS_OUTPUT Out = (VS_OUTPUT)0;
   Out.Pos    = mul( Pos, m_WVP );
   float3 L = -normalize( m_LightDir.xyz );
   float3 N = normalize( Normal.xyz );
   Out.Col = max( m_Ambient, dot(N, L) );
   // 深度値は座標そのもの
   Out.depth = Out.Pos;
   // 法線
   Out.normal = Normal.xyz;
   Out.normal = normalize(Out.normal);
   return Out;
}
struct SP_OUTPUT
{
  float4 Color  : COLOR0; // カラー
  float4 NormalDepth   : COLOR1; // 法線と深度
};
SP_OUTPUT PS( VS_OUTPUT In ): COLOR0
{  
  SP_OUTPUT Out = (SP_OUTPUT)0;
  Out.Color = In.Col;
  Out.NormalDepth.xyz = In.normal;    // xyzが法線で
  Out.NormalDepth.w = In.depth.z/In.depth.w;  // wに深度
  return Out;
}
float totStrength = 1.38;
float strength = 0.0007;
float offset = 18.0;
float falloff = 0.000002;
float rad = 0.03;

#define SAMPLES 16
const float invSamples = 1.0/SAMPLES;

sampler rayMap : register(s0) = sampler_state 
{ 
  MipFilter = NONE;
  MinFilter = POINT;
  MagFilter = POINT;
}; 
sampler normalMap : register(s1) = sampler_state
{
  MipFilter = NONE;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
};
sampler colorMap : register(s2) = sampler_state
{
  MipFilter = NONE;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
};
float4 SSAO( float2 uv : TEXCOORD0) : COLOR0
{
  float4 Output = (Float4)0;

  float4 currentPixelSample = tex2D(normalMap, uv);
  float currentPixelDepth = currentPixelSample.a;
  float3 norm = currentPixelSample.xyz * 2.0f - 1.0f;

  float bl = 0.0;
  float radD = rad / currentPixelDepth;

  float3 ray, occNorm;
  float2 se;
  float occluderDepth, depthDifference, normDiff;

  for(int i=0; i'<'SAMPLES; ++i)
  {
    float3 fres = tex2D(rayMap, float2(float(i)/16.f,0)).xyz*2.f-1.f;
    ray = radD * fres;
    se = uv + sign(dot(ray,norm)) * ray * float2(1.0f, -1.0f);
    float4 occluderFragment = tex2D(normalMap, se.xy);
    occNorm = occluderFragment.xyz * 2.0f - 1.0f;
    depthDifference = currentPixelDepth - occluderFragment.a;
    normDiff = (1.0 - dot(normalize(occNorm), normalize(norm)));
    bl += step(falloff, depthDifference) * normDiff * (1.0 - smoothstep(falloff, strength, depthDifference));
  }
  float ao = 1.0 - totStrength * bl * invSamples;
  Output = tex2D(colorMap, uv)*ao;
  return Output;

}
technique RenderScene0
{
  pass P0
  {
    VertexShader = compile vs_3_0 VS();
    PixelShader  = compile ps_3_0 PS();   
  }
  pass P1
  {
    PixelShader  = compile ps_3_0 RenderScenePS0();
  }
}

2011年6月10日金曜日

winmainの隠蔽工作

全体を通しての技術経験をつけたいと思い、
フレームワークを作っていこうと思います。
まずはじめに、プログラムを実行するにあたって一番初めに俺のフレームワークのエントリーポイント的なものを考えます。
マルチプラットホーム向けに作るつもりは無いのですが、ひとまずwinmainから書くのが嫌なので隠蔽します。
どこかのサイトで調べたのですが忘れたので、見つけたら改めて記述します。
こうすると出来るそうです。
まあ、動いています。

とにかく使い方です。
ヘッダファイルにクラス定義
class Prototype : public Framework
{
public:
 Prototype(void){}
 virtual ~Prototype(void){}
 virtual void MainLoop()
 {
 //ここに書いたものが自動で実行される
 }
}
cppファイル
Prototype theApp;


これで、
winmainなど書かなくても、自分のクラスのインスタンスをnewして誰かに渡さなくても、これだけでいきなりPrototypeのMainLoopが実行されるようになります。
からくりは以下です。
Prototypeは以下のFrameworkを継承しています。
こちらにはwinmainが書いてあり以下のようになっています。

ヘッダファイル
class Framework
{
public:
 static Framework* ms_pInstance;
 Framework(void);
 virtual ~Framework(void);
 int Boot();
}
cppファイル
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE , LPTSTR lpCmdLine, int nCmdShow)
{
 return Framework::ms_pInstance->Boot();
}

Framework* Framework::ms_pInstance = NULL;
Framework::Framework(void)
{
 ms_pInstance = this;
}
Framework::~Framework(void){}

int Framework::Boot()
{
 // おれのエントリーポイント
 MainLoop();
 return 0;
}

とにかくどこかにあるwinmainが呼ばれて起動します、そこでいきなり
Framework::ms_pInstance->Boot();
を呼ぶので継承したPrototypeのMainLoopまで来ます。
しかし、FrameworkはPrototypeが自分を継承していることがわからないのでwinmainで呼ばれるFrameworkは本来誰だかわからないはずです。
ですが、どこかで
Prototype theApp;
と記述しておくとグローバル定義のインスタンスになって、これはもちろんコンストラクタよりも早くメモリに存在するわけで。するともちろん、Prototypeのコンストラクタが動くので必然的に親クラスのコンストラクタが呼ばれ、そこでこれまたグローバルな
ms_pInstance = this;
Frameworkのポインタに継承した自分(Prototype theApp;で起動したコンストラクタから)のポインタが入って
めでたくこのグローバルなFrameworkのポインタは継承先のPrototypeを差してくれます。
なので、誰が継承したのか知らない親クラスが継承先のPrototypeに乗っ取られてうごきだしちゃいます。的なイメージでしょうか。
以降、Frameworkを継承したクラスだけ書けば勝手に動いてくれます。
めでたし。

ああ、思い出したMFCの実装がこれです。

2011年6月8日水曜日

SSDO Screen Space Directional Occlusion スクリーンスペース近似大域照明

http://www.mpi-inf.mpg.de/~ritschel/SSDO/

概要

リアルタイムで実現できる物理的に妥当な照明は、多くの場合近似を使って実現されています。
ひとつのポピュラーな例としてアンビエントオクルージョン(AO)があり、非常にシンプルでかつ効果的な実装は多くの製品で採用されています。
最近はスクリーンスペースでの近いジオメトリを使用したAOを近似する方法が採られています。

今回この論文で注目すべき点は、この手法が、スクリーンスペースで計算される遮蔽情報から、
例えば方向を考慮した影や間接的な色のにじみなど、より多くの影響を与える遮蔽情報を取得する為に使用することが出来ることです。

今回提案された手法は、スクリーンスペースで処理し従来のSSAOに比べてわずかなオーバーヘッドで直接光、単反射光を近似し、マクロ構造の過程をシミュレートするための別の手法と結合することができます。
そして、最悪のケースでも今回の手法を用いなかったSSAOと見た目的には同等になります。

この手法はスクリーンスペースでの処理になるため、ジオメトリ形状の複雑さに依存しません。
妥当な方向遮蔽と間接照明の効果はリアルタイムに、完全にランタイムで大規模なシーンを表現することが出来ます。

1はじめに

リアルタイムな大域照明は未だ、大規模で動的なシーンに於いて未解決の問題を持っています。
現在のところ十分なフレームレートを達成しているのは、近似を使う方法のみです。
そのような近似には、高速性と、実装の簡易さから映画やゲームなどに使われているAOがあります。

ただしAOは視界と照明を切り離しており、実際の照明の荒い近似のみをおこなっています。
AOは通常、空洞物の暗域を表現できますが、入射光の方向は無視されます。

今回Screen Space Directional Occlusion(SSDO)と名付けた、よりリアルな照明へ向けてSSAOを拡張しました。

本研究ではSSDOが
・どのように入射光の方向の集計を行うか
・どのように環境光の単反射を含むか
・どのように標準的なオブジェクトベースの大域照明の代わりをするか
・どのように少ない計算コストで済ませるか

の説明をしています。
構成は以下のとおりである。
まず、第2節で既存の動作を確認します。
第3節では、中央構造照明のAOの一般化を説明します。
第4節では、画質を向上させるための拡張機能について説明します。
第5節では完全なグローバルイルミネーションのシミュレーションと、本手法との統合が記載されています。
第6節で結果の提示。
第8章で結論づける前に第7章にて議論をしています。

2準備

物理的に妥当な照明は、全体の可視領域と照明の方向について計算をする時、 AOは可視領域と照明の2つの個別の積を積算します。
静的なシーンでは、AOは可視性を事前計算し、(頂点やテクスチャを使用して)表面上のスカラー場としてそれを保存することができます。

単純な乗算を使用した静的なAOと動的な照明の組み合わせは、高フレームレートで見た目に妥当な結果をもたらします。
AOフィールドの導入によってオブジェクトの並行移動、回転とアニメションキャラクターに特化した解決方法も存在します。

変形する面と間接光の反射は、Bunnell [2005]のディスクセットを使用したジオメトリの近似によって解決されます。
より堅牢なものはHoberock and Jia [2007]によって提示され、さらにChristensen [2008]によってポイントベースのアンビエントオクルージョンと相互反射に拡張されました。
Mendez et al. [2006]ジオメトリ周辺の平均アルベドを使用した単純な色にじみ効果を計算します。
この手法は表面の離散化もしくはレイトレーシングへのどちらかを使用しています。
これはゲームのような現在のインタラクティブなアプリケーションで使用される動的なジオメトリの量に比例して増大してしまいます。
したがって、最近の方法は代わりにスクリーンスペースの表面を使って近似された遮蔽を計算します。[Shanmugam and Arikan 2007; Mittring 2007; Bavoil et al. 2008; Filion and McNaughton 2008].

SSAOの好まれる点はその単純な実装とハイパフォーマンスにあります。
これは、出力が感覚的で、ポストプロセスとして処理され、追加データ(例えば、表面の定義、BVH、kD-trees、シャドウマップのような空間の表現に使われる構造)が必要なく、さまざまなタイプのジオメトリで動作します(例:ディスプレースメントや法線マップ、頂点またはジオメトリシェーダ、等値面の光線と平面の交点を求めるレイキャスティング)。
イメージ空間の手法はまた効率的に地下散乱をシミュレートすることができます。[Mertens et al. 2005].
同時にSSAOは様々な制限に対して近似を求められます。
これも今回の研究であり、後のセクションで詳しく説明します。

AOは一般的な光伝播に対しては粗い近似値になります。
例えば、PRT [Lehtinen and Kautz 2003]の指向性遮蔽(DO)と相互反射をサポートし、
事前計算では、しばしば空間や方向の解像度増大の制限のために圧縮形式のデータを大量に格納する必要が出てきてしまいます。
我々のアプローチは、非常に小さいサーフェイスの詳細、全方位の解像度のどちらも解決することができます:"無周波数"AO、全周波数イメージベースの照明やポイントライトからシャープな影。

PRTは広い照明範囲とそれなりの複雑さの静的なジオメトリとうまく動作しますが、
SSAOは妥協のないシンプルさがゆえに実際のアプリケーションに適応されています。

要約すると私たちの研究は、あらかじめ計算されている、
以前は動的には不可能だった最終的なリアリティーに影響する指向性遮蔽と間接的反射の2つ両方の近似計算をリアルタイムに、よりリッチなジオメトリに対してSSAOプロセス[Shanmugam and Arikan 2007] を用いることで活用しています。

3 イメージベースの近接場光伝搬

画像空間の光伝搬を計算するために、本手法は位置と法線のフレームバッファ[Segovia et al. 2006]を入力として使用しています。
フレームバッファは直接光及び間接バウンスの2つのレンダリングパス使用して照明ピクセルを出力します。

DOを用いた指向性照明

通常のSSAOは隣接するピクセルから、最初の計算で可視値の平均を求めピクセルの色を決定します。
この遮蔽の値はすべての入射方向からくる非遮蔽照明を乗算して求めます。

遮蔽と照明の関連性の低くさを取り除く処理を行う方法を次のように提案します。

3次元上に法線nの座標Pのピクセルがあり
方向ωiのN個のサンプリングから算出される直接光輝度をLdirとし、
均一に⊿ω=2π/Nで半球状に分散していると定義したとき

Ldir(P) = Σ(i:1->N)ρ/πLin(ωi)V(ωi)cosθi⊿ω.

各サンプルは、入射輝度Linと可視ベクトルVとディフューズBRDFρ/πの積を計算します。
我々は、Linを効率的にポイントライトや環境マップから計算することができることを前提としています。
スクリーンスペースで遮蔽物を近似する事で可視ベクトルVの算出に、レイトレーシング計算の使用を回避します。
点Pから方向ωiのランダムな距離λi [0...rmax]にあるすべてのサンプルを算出します。
rmaxは任意に定義した半径です。
これは結果、Pを中心とする半球に内包するサンプリング点P + λiωiと法線n方向との組みとなります。
続いて、3次元の点として点P周辺での局所的なサンプリングポイントを生成します。
そのうちのいくつかは表面の上、またいくつかは下に位置します。
サンプリングポイントが隣接するジオメトリの表面より下にあるものはすべて遮蔽物として近似の可視性判定として扱われます。

Fig.2:左 指向性遮蔽による直接光 互いのサンプル点は遮蔽物かどうかのテストに使われる。上記の例では、点Pは方向Cからのみ照明される。
右 間接光 直接光がフレームバッファに置いた、小さい範囲が互いの遮蔽物として表面上に配置されたものであり、対象点の輝度として使われる
Fig. 2 (左) はサンプリングポイントABCDのN=4の例です。サンプル点ABDは表面の下に位置している為点Pの遮蔽物として分類される、サンプル点Cは表面の上に位置しているので可視点として分類されます。
サンプル点が表面の下に位置するかテストして、イメージ上に投影されます。

今3次元の位置情報はポジションバッファから取得でき、その点がジオメトリの表面上に投影されます(赤の矢印)。
もし、このジオメトリ表面への投影によって観測点からサンプル点への距離が減少すれば、サンプル点は表面の下に位置すると分類することが出来ます。
例えば Fig. 2において点ABDは観測点に近づいたので表面の下に位置し、点Cは観測点から遠ざかります。
SSAOと対照的に、すべての点から照明の計算をせずに見えている方向(サンプル点C)からのみにします。
特に入射光照明が違う方向から、違う色でやってくる場合、この指向性の情報は結果を大幅に向上させることが出来ると言うことになります。
Fig.3の通り、SSAOでは単純にグレーカラーで影を表示するだけですが、こちらは正しい色で影を表示することが出来ます。
Fig3

Fig3

間接反射
1つ前のパスで、直接光がフレームバッファに書き込んだ単反射のライト情報を含むことで以下のことが可能になる。

遮蔽物として扱われる各サンプル点(ABD)に対応するピクセルカラーLpixelは表面上に配置される単位面の発光輝度として使用される。(Fig2右)
ここで発光単位面の裏側からの色漏れを避けるために発光側の法線を考慮する。

ジオメトリ周囲の付加輝度は以下の式で近似できます。

Lind(P) = Σ(i:1->N)ρ/πLpixel(1-V(ωi))(As cosθsi cosθri)/di^2

diは点Pと遮蔽物iとの距離(diは特異点問題を避けるために1でクランプする)
θsiとθriはそれぞれ発光者(sender)と受光者(receiver)の法線と透過方向の角度です。
Asは発光者単位面に関連する領域です。
単位面領域の前提値として半球内の平面を想定しています。
基礎円はN個の領域に分割されているので、As=πr^2max/Nの領域をお互いにカバーします。
半球内の斜面の分布に応じて、実際の値は高くすることが出来ます。
このパラメータを色にじみ強度の手動のコントロールとしてに使うことが出来ます。
例として、fig2において単位平面Aは裏を向いているために間接光計算は何も寄与していません。
単位平面Cは点Pの半球の反対側にありますのでこれもまた関与しません。
単位平面BCは点Pに対して間接光の発光者となります。
Fig3は間接光の反射を標示しています。

細部の実装
従来のSSAO [Shanmugam and Arikan 2007] は同様の手順と計算コストがかかります。
今回の手法は可視判定に相当するシェーディングモデルを判断する為により多くの計算を必要とします。
今回は太陽光のような既知の重要な光源には、スクリーンスペースでの手法ではなく、代わりにジオメトリの距離から影をキャプチャーするシャドウマップを適応する追加のサンプルを使います。  
N個の事前計算された食い違いの少ないサンプルλiωiのセットM個を格納するためにMxNのテクスチャを使います。
各ピクセルは実行時にMセット外の一つを使っています。
最後のパスでノイズを取り除くために微細なジオメトリブラー[Segovia et al. 2006]を適応します。
これはピクセルあたりのサンプルのリダクションによって提案されています。

4 マルチピクセル
Fig.4
スクリーンスペースでの処理なので、すべての遮蔽物や間接光源が見えているわけではありません。
Fig.4の例は間接照明の光源が遮蔽されていくにつれて、色のにじみがフェードアウトしていくのを示しています。
それらは、付属のビデオのとおり見た目にひどくがっかりするような見た目ではありません。しかし、実際の結果とは違っているのです。
この差異を減らす措置として、そのような照明結果を克服する2つのアプローチ、深度値の剥離と追加カメラを提示します

単一深度の限界
Fig.5
スクリーンスペースでの可視判定問題(左):可視判定のサンプル点Aは投映位置が観測位置に近いため遮蔽物として分類されます。サンプル点Bは表面の上にあるので、対応する方向は閉鎖されていても点Pはこの方向から誤って照明されてしまいます。
解決法(右): 2つのレイヤーを使用して深度乖離します。サンプル点Aは第一第二深度値の間にいないため可視と分類することが出来ます。B方向からのサンプル点を増やすことで、遮蔽物を見つける事が出来ます。
前のセクションで提示した遮蔽物テストは近似です。単一のフレームバッファでは、最初の深度値のみ知ることができ、遮蔽されたジオメトリ情報は失われてしまいます。
Fig. 5(左)に示すように、サンプリング点はそれゆえに間違って判断されます。
いくつかの状況では、入射光を乖離判定してしまったり、本来遮蔽されるべき方向を可視判定してしまういます。
サンプル点Bの遮蔽判定ミスは、この方向のサンプル点を増やすことよって訂正することが出来ますが、サンプル点Aの乖離(そして、反射光の入射位置を近くしてしまう)は単一の深度値z1の背後のシーンについての情報が無い為に単一の視点からでは訂正することができません。

深度値の剥離
剥離深度[Everitt 2001]は、nレンダリングパスのあとに互いにフレームバッファへ単一の深度値nが書き込まれます。
これは、このシーンに関してより多くの情報を持つことで遮蔽物判定を改善する猶予があります。
もしサンプル点が第一深度z1の背後にあるならば、そのまま判定せずに、第二の深度値z2の前にあるかテストをする。

第一第二深度はオブジェクトの表面と裏面にそれぞれ対応し、2つの集合管ジオメトリを使用する場合、2つの面の間のサンプルはこのオブジェクトの内側にしなければならない。(Fig.5右)
複雑さの高い深度のシーンのすべての影を再構築する為には、第3、第4深度値と連続する深度値のすべての組みは同じ方法で評価しなければならない[Lischinski and Rappoport 1998]

2011年6月4日土曜日

コンパイルタイム文字列ハッシュ化

こちらの記事に
http://d.hatena.ne.jp/yupo5656/20040613/p1
コンパイル時に文字列リテラルに指定のアルゴリズムによる計算を施し、整数に変換するには?
と言うのがあったので参考にしてみました。

template <std::size_t N> inline hash32 hashStringStatic(const char (&str)[N]) { return crc32(N-1, reinterpret_cast<const char (&)[N-1]>(str)); } template <std::size_t N> inline hash32 crc32(hash32 hash, const char (&str)[N]) { return crc32( (hash >> 8) ^ crctbl[(unsigned char)((hash & 0xff) ^ str[N-1])], reinterpret_cast<const char (&)[N-1]>(str) );< } template<> inline hash32 crc32<1>(hash32 hash, const char (&str)[1]) { return (hash >> 8) ^ crctbl[(unsigned char)((hash & 0xff) ^ str[0])]; } typedef unsigned int hash32; // ハッシュテーブル static const hash32 crctbl[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
です。
crc32の処理を再帰テンプレートで展開するわけなのですが、最適化でたしかに直値になっているかんじでした。
このアルゴリズムの都合のいいところは、単純な再帰型に出来たので楽でした。
他のハッシュアルゴリズムは展開できるか知りません。

ちなみにコンパイルタイムではないものも用意してみました。
inline hash32 hashStringDynamic(const std::string str)
{
const std::size_t len = str.length();
hash32 hash = len;
for ( std::size_t i = 0; i < len; i++ )
{
// static版に揃えるためけつから求める
const std::size_t index = len-1-i;
hash = (hash >> 8) ^ crctab[(unsigned char)((hash & 0xff) ^ str[index])];
}
return hash;
}
そんでですね、

ソース内に
 hash32 hash = hashStringStatic("sh/bokenasu.fx");
とかやっとくと数字になって入ってるみたいな。
こいつをフライウエイトのキーに使えば見やすく処理も速いのかなと思ったのです。
ただこれはもちろんリテラル文字にしか使えないので使うときにはどうなるのかとても注意が必要です。ただ、これだと、オリジナルの文字列が失われるので実際にファイル名等の文字列が必要なときに困ります。
そこで

struct hashString
{
hashString(hash32 hash_, char* str_)
: hash(hash_)
, str(str_)
{}
const hash32 hash;
const char* str;
};
#define HashString(x) hashString(hashStringStatic(x), x)

っつーのを作ってみたのですが、どうですか?
instance func(hashString hash)
{
 auto ite = m_kMap.find(hash.hash);
 if(m_kMap.end()!=ite) return ite->second;
 m_kMap[hash.hash]=new instance(hash.str);
 return m_kMap[hash.hash];
}
instance = func(HashString("sh/bokenasubi.fx"));
みたいな事やれば良いんじゃないでしょうか?

つか本当にアセンブラレベルで直値になっているかが重要なんですけど、どうなんですかね?

ぶっちゃけ、アセットなんかは全部外部の定義ファイルに書いて読み込む事になるので、リテラル文字限定ってのはまあ使えないわけですが。。。
外部ファイルから読み込む場合は予めもっとシノニムの起きづらいmd5で文字列をハッシュ化したものを文字列とペアで記述しておけばいいですかね。


2011年3月4日金曜日

bullet build for visual studio 2010

http://code.google.com/p/bullet/downloads/list
の最新版を取得して
http://www.cmake.org/
からCMAKE落としてインストールして
コマンドから

cmake . -G "Visual Studio 2010"
でOK。
BULLET_PHYSICS.sln
が出来上がっているので開く。
ALL_BUILDをビルドして
AppAllBulletDemos
をスタートアップにして起動する。

2011年2月13日日曜日

今度は5000万の連絡が来ました

今度は5000万くれるらしいです。

差出人 使用人頭/望月 (55歳)
受信日 2011/02/11 22:49:23
件名 5000万を数十分で入金致しますのでご連絡下さい。
内容 突然のメールお許し下さい。私は東城家に仕える「望月」と申します。この家の主である東城様より、ゲスト様、竹下様、ゲストちなつ様、もんど様の4名に5000万。計2億を振り込むよう仰せ使いました。何ゆえゲスト様を含めた4名の方が選ばれたのかまでお聞きしておりませんが、東城様がお選びになったのは深い理由があるからだと推測します。ゲスト様には東城様よりの5000万を早急に受け取り願いたくご連絡致しました。これから数十分後に受け取って頂けますので、私「望月」までご連絡をお願いします。

もうメール出来ないんです。
もう一生メール出来ないんです。
分かってくださいよ。

システムが変われば 無料でメール出来れば連絡します。
5000万円いただける前に 430円が払えないんです。
5000万いただけたら 430円払います!

2011年2月11日金曜日

ベビーカーを優先しよう

以下のようなやり取りがありました。

差出人ヒミコ (28歳)
受信日2011/02/09 16:48:43
件名明日の朝一番で銀行から引き出してください。
内容こんな事常識では考えられないとは思いますけど・・・いたって真面目に話ししてます。朝に絶対あなたの口座に振り込みます。今までにこのサイトで13人の方に受け取ってもらいました。金額は一人あたま200万円ですけど・・・私のいらなくなったお金をもらってください。愛人だった彼からの慰謝料なんです・・・口座だけで結構ですので送ってください。怪しいと思われてるでしょうから、必要ならちゃんと自己紹介もさせてもらいます。警戒されるのは覚悟のうえで連絡しました。本当に明日の朝には振り込み出来ます。受け取ってくれませんか?

件名常識で考えればそうですね。200万円もらってなんかありえない
内容いきなり連絡して、お金もらってくださいとか言われても恐いですよね?実際にもらった人いますよと言っても信じてはもらえないでしょうし、口座送れば悪用されると考えるのが普通だと思います。もし受け取りたくないならそれでいいです。別の人に連絡しようと思ってます。固執するのはあまり好きじゃないから・・・出来るだけ早く処分してしまいたいので、あなたがいらないなら他の人を探します。口座だけ送ってもらえれば絶対振り込みします。あなたが14人目になります。金額的に不安もあるでしょうけど・・・受け取ってくれますか?
件名実は・・・
内容彼からの慰謝料は全部で3000万円あってそれを最初はどこかに捨てようと思ったんです。それでこのサイトで出会った人に相談したら、捨てるなら200万円下さいって言われて・・・それで200万円振り込んだら、「そうやって欲しいという人がいればその人ににあげれば気が紛れるし、お金も意味があるもになるんじゃないか?」って言われから、今まで13人に方に振り込みしました。みなさん喜んでくれて・・・勘違いかも知れないけど良い事してるのかなって思えてきたんです。今、あなたともう一人の方に声かけてます。振り込んでもいいですか?

件名口座送るのは恐いですか?それだけでいいんです。
内容私が裕福だからこんな事言ってるんじゃないんです。ただ、愛人からの慰謝料・・・はっきり言えば手切れ金です。そんなお金あなたなら自分の手元においておきますか?捨てるならもらってくれた方が、私も楽になれるんです。勘違い女って思うかも知れませんけど・・・実際にその状況にならないと私の今の気持ちはわかってもらえないと思います。綺麗事で済ませる気はありません。でもあなたが必要としてくれるならそれは意味のある事に変わると思うんです。200万円では受け取る気にもなれませんか?

件名誰でもそんな反応にはなると思います。完全に無視
内容私もきっと同じ反応すると思います。納得出来ないとか以前にあやし過ぎますよね?でも、必ず振り込みはします。それだけは約束します。自分で間違った事をしてるとは思いません。むしろこうする事で少しでも幸せになれるなら、そして誰かが喜んでくれるなら私はそれが一番いい選択だと思ってます。実際は愛人からの手切れ金ですから、綺麗なお金ではありません。でもあなたが必要としてくれてるなら、あなたが綺麗なお金として使ってくれればいいと思うんです。私の考えって間違ってますか?人間として腐ってますか?

件名言われたんです。
内容はじめに振り込んだ方になんですけど、こんな話は誰も信じないしお金振り込むって言ってもそんな金額誰も受け取ってくれないよって・・・確かに・・・手切れ金の3000万円全部なら受け取ってくれたかも知れませんね。でも、残りも400万円しかありません・・・あなたが無理なら仕方ないと思ってます。覚悟は初めから出来てます。必要だって言ってくれる人に渡したほうがいいと思ってます。ただ私にも女の意地もありますし、決めてください。普通に振り込みするだけですから時間はかかりません。本当に受け取ってくれないんですか?

件名前のかたはすんなり話を理解してもらったので15分でした。
内容振り込みにかかったのは15分です。時間の問題じゃないのかも知れませんけど、あなたが急ぎでお金が必要な方だったら先に教えておいた方がいいかと思って・・・まだ受け取る気にはなりませんか?今までの方みなさん結構すんなり話を聞いてくれたので・・・あなたがどうして受け取ってくれないか余計に気になって・・・私の事をどうしても気に入らないか信じてもらえてないか・・・もう一人の方は返事してくれましたし、その方が受け取ったらあなたで全部終わりになります。200万円まとめて振り込みさせてもらえませんか?

件名もう一人の方から連絡あったので、今振り込みました。
内容残ったのはあなたに振り込もうと思っている200万円だけです。さっき振り込んだばかりだから、今なら振り込むのに時間かかりません。すぐ確認してくださって結構です。自分でいい事してると思ってるような人間ですけど・・・ここまで来るのに苦しい思いも沢山しました・・・慰謝料なんて受け取りたくもないでしょうけど・・・これで人生やり直そうと思ってます。振り込みした後に時間でもあったら少し話しでもしたいですね。このまま振り込みしますから、口座番号だけ教えてもらえますか?

件名口座だけでいいので本当にお願いします。ごめんなさい。
内容突然こんな連絡が届いてすごく不安にさせてしまってるかも知れませんけど・・・絶対あなたに迷惑かけません。200万円振り込みさせてください。受け取ってくれたのはあなただけじゃありません。これまでに13人の方に受け取ってもらいました。私の話をちゃんと聞いてくれて・・・15分で振り込み出来ました。あなたが口座を教えてくれたら朝には必ず振り込みします・・・どうかこのお金受け取ってもらえませんか?私の身元も全部お教えします。からかってる訳じゃないです。真剣にお願いしてるんです・・・お願いします。受け取ってください。

件名あなたの口座に必ず振り込みます。200万円は
内容もともとあってなかったようなお金です・・・それに慰謝料なんて私には嬉しくもなんともないお金なんです・・・こうやって何度も連絡する事自体迷惑だというのはわかってます。それに時間も時間ですから・・・常識で考えれば、頭がおかしいと思われて当然です・・・でもいたって真剣にお願いしてるんです。200万円受け取ったからってあなたに何か特別な事をお願いする事はしません・・・ただ振り込みさせてください。私からのお願いはそれだけです。自分で言った事はちゃんと守ります。朝には振り込みしますから受け取ってもらえませんか?

件名ネットバンキングもつかえます・・・今から
内容すぐに振り込みします。口座だけ教えてくれれば、愛人からの慰謝料を全部清算できるんです・・・口座を聞きたがってるから、悪用されるとか思われてますか?でも、全然そういうのじゃないですから・・・本当にあなたに迷惑のかかるような事は一切しません。ここにある200万円を振り込む事だけしか考えていません。他の13人の方はすぐに振り込みさせてもらえました。もちろん苦情とかもありません。本当にあなたが必要ないなら・・・あなたを諦めて他の方にこのお話させてもらいます・・・200万円あなたには必要なかったですか?

と言うメールが来ているよとの通知がスパムフォルダにありましたので、
連絡を致しました。

送信先相手ヒミコ (28歳歳)
受信日2011/02/10 20:12:10
件名ありがとうございます!
内容いい事を思いつきました
伊達直人として自動施設に振り込んでください!
お互い幸せな気分になれます!!


件名自動じゃなくて児童ですよね?
内容後から言う事でもないので先に言います。必ず振り込みますので、あなたも必ず受け取ってくださいね。それでお願いなんですけど・・・振り込んだのに連絡もなく受け取って頂けたかどうかもわからないのでは、安心出来ないですし・・・振込み終わった後に「受け取った」という連絡だけでいいですのでお願い出来ますか?


件名自動間違い
内容すみません。児童施設ですね。
児童施設は嫌ですか?
とっても良いと思うんです。


件名はい、こんなお金で
内容育てられる子がかわいそうです。


件名そんなコトないですよ!
内容違法って訳でも無いんですから
あなたが思い切って寄付してあげれば
とても助かる子供が大勢いるんですよ!
不幸(失礼かもしれませんが)なお金が 幸福に使われるんです。
勇気を出して!

件名いえ、私がいやなんです。
内容お願いします。受け取ってくれませんか?どうしてそんなに拒むんですか?


件名そんな事言わずに
内容勇気を出してください!
あなたのお金を待っている人がいるんです。
自分からもお願いします!

始めメールをチェックしていなかったので メールいただいている事に気がつきませんでした。
連絡をいただいてビックリしています。
嬉しかったので、いい事を思いつきました。
それが児童施設です。
良い案だと思うんですよ。
ありがとう!


件名いえ、いやです。受け取って下さい。
内容あなたがサクラではないなら。お願いします。


ここで、メール送信ができなくなりました。
どうも、メールを送信するためにポイントを使うようです。
自分は登録した覚えのサイトのサービスだったことに気が付きました。

どうも、一通480円のお金がかかるそうです。
初回はどうもはじめに何ポイントか入っているようです。

もう連絡が取れないんです。
でも、向こう様はそれに気がつかない勢いでメールを頂きます。
その後

差出人ライジングさん (41歳)
受信日2011/02/11 13:29:05
件名ポイント不足。相手をいつまでも待たせる。
内容これがどれほど相手を傷つけるのか、待たせる側には分かりません。私はさすらいのポイントハッカーです。ハッキングによりあなたにポイントを加算出来ます。どんな目的か、慈善事業への協力者を募ることです。ハッキングにより加算をし、加算されたポイントであなたには私の紹介する方と1日に1通程度で構いませんので連絡をして頂きます。ポイントのハッキングは犯罪ではありません。ご決断頂けますか?
などと、他の方から、どうにかポイントを取得するべきな情報をどしどしいただきます。


でも、もう連絡は取れないんです。

もし、このブログを見ていたら、是非児童施設に!
頑張れ!