2012年05月17日

トイ

こんにちはひらめき
シュンスケですぴかぴか(新しい)


突然ですが、トイカメラという言葉をご存じでしょうかサーチ(調べる)
明確な定義まで把握してませんが、トイカメラ自体は新しいものでは無く、
安価な材料や仕組みで作られたカメラ製品全般の事ですカメラ

その為、撮影した写真の品質に大きくバラつきが出るのが特徴で、
撮るごとに写り具合が変わり、味があって趣があるとして、好きな人も
多いようです目

今ではデジタルカメラが普及していますが、機能としてトイカメラ風の写真が
撮れたり、そういったエフェクトがかけられるカメラが多く出てきています。
そういうカメラはトイデジと言うそうですね映画

そんなトイカメラですが、iPhoneを使ってトイカメラ風の写真が撮れるという
アプリがありますCD

無料だと、「Instagram」というアプリが有名です携帯電話

トイカメラの特徴である、変わった色調やぼかしなどのエフェクトがかけられ、
ミニチュア風な風景や、レトロな雰囲気も出せまするんるん

カメラについては全くの素人ですが、会社の近くを少し撮影してみましたビル
ぱちり
20120517_img4.JPG20120517_img2.JPG


こうやって色々とエフェクトをかけていると、ゲーム画面に様々なエフェクトを
かける場面を思い出しました晴れ被写界深度やカラーフィルタ、ブラーなどなど。
どういったエフェクトをどういった具合にかければどんな見え方をするのか、
このカメラから学べる事も多そうです決定

人口総カメラマンの時代に、少し趣を変えた写真を撮ってみてはいかがでしょうかわーい(嬉しい顔)


posted by 管理人 at 23:30 | ソフトウェア紹介

2012年05月16日

メモリイメージ

日に日に気温も上昇し汗ばむ季節になってきましたね晴れ
汗かきなので既に薄着になりつつある「オクダ」です。
皆さんは夏に向けてのカラダ作りは大丈夫ですか?
今年はプロジェクトが佳境を迎えるのであきらめムードですふらふら

今回はプログラマ向けの少しディープな話をしてみようと思います。
テーマは「メモリ」です。
皆さんがPCを使ったりプログラムをしている時にメモリを意識する事は少ないかもしれませんが、
メモリとうまく付き合っていく事で、更に上位レベルのプログラマになれると思います。
プログラムの最適化や言語仕様の理解、デバッグに役立つと思います。

C言語(C++)を基準に解説していきますが、他の言語でも共通する考え方だと思います。
OSやライブラリはの大部分はC(C++)で作られているのでほとんどの言語がCのメモリ管理を踏襲しています。
CPUやコンパイラによる細かな違いもありますが、大きくは変わらないでしょう。


プログラムがシステムからメモリ上にロードされ動作を開始するタイミングでは大きく分けて4つのメモリ領域が確保(割り当て)されます。

1プログラムの命令部分
CPUはここに書かれた命令を一つずつ順番に処理していきます。
稀に、この領域に固定の値が含まれる事があります。(関数のstatic constなローカル変数など)

2固定された値
constな変数がここに分類されます。
固定のテーブルなどはココです。
この領域の内容が書き変わる事は無いハズですね。

3変数領域
globalな変数の領域です。
関数内のstatic変数やC++のstaticなクラスメンバもココになります。
関数内のstatic変数はコンパイラや最適化具合によって1の内部に分散格納される場合もありますが、場所の問題であって意図としては同じです。


4スタック
謎の領域「スタック」です。
基本的に固定された領域ですが、使い方がトリッキーで詳しく説明されない事も多いです。
次回はココにスポットを当てたいと思います。

更に実行時に割り当てられるメモリがあります。

5ヒープ領域
mallocやnewなどで実行時に動的に割り当てられるメモリ領域です。
mallocの場合はメモリ確保のイメージがあると思いますが、
newの場合はメモリ確保している印象は希薄だと思います。
また、関数内で宣言したクラスは宣言タイミングでヒープからメモリ確保され、スコープを抜けるタイミングで解放されます。
constructor,destructor(new,delete)がその都度呼ばれている事に注意しないと痛い目を見ます。

自分がプログラムの中で書いたコードや確保したメモリが
どういった役割を持っていて、どのような場所に確保されているか、、、
少しだけイメージできたでしょうか?
値が変更される可能性があるのか無いのか。
静的に確保されるのか動的に確保されるのか。
このあたりの違いがカギになっているようです。
バグが発生した場合の解決の糸口になる事もあるので、少しだけ意識してみるといいでしょう。

さて、今まで説明してきた中で触れていないモノがあります。
「staticでないローカル変数」です。
最適化された場合にはメモリではなくレジスタに割り当てられることも多いですが、
実は4のスタックに確保されることがほとんどです。
また、レジスタに割り当てられたとしてもスタックと無縁ではありません。
むしろ密接に関係しています。
次回はこの「スタック」の役割と仕組み、動作にスポットを当てたいと思います。
乞うご期待!


posted by 管理人 at 16:19 | プログラミング

2012年05月15日

視点

こんにちは。さいやん、こと齊藤です。

昨今の円高で日本のものづくりの危機が叫ばれていますがく〜(落胆した顔)
日本でものを作っても、円高では海外に売る場合に
利益を圧迫することになるからです。
 1$ = 100円のときに80円の原価でものを作って1$で売れば
 日本円にして100円で売れるので20円の利益が出ますが、
 1$ = 80円(円高)のときに80円の原価でものを作って1$で売っても、
 日本円にして80円にしかならず、利益は出ないからです。
 円高前から輸出で利益を上げていた企業は利益が出なくなって
 きていることが分かると思います。

すなわち、円高の現状では今までの商売が成り立たなくなってきますあせあせ(飛び散る汗)
さて、どうすればいいのでしょうか。
価格競争ではなく他には真似できない技術で勝負し、
オンリーワンの価値ぴかぴか(新しい)を売り込めるようになるといいのではないでしょうか。
では、オンリーワンの価値はどうやって生み出せばいいのでしょうexclamation&question
この問いに簡単に答えられれば苦労しません…ふらふら
しかし、ヒントひらめきはあります。

最近では「生物模倣」と言われる手法で様々なものが生まれています。
トンボの羽を模して作られた風車は極微風でもとらえることができ、
効率よく回ることから従来以上の効率的な風力発電が可能になりました。
蚊の口を模して作られた注射針は痛みを大幅に軽減することが
可能になりました。

世の中の事象で、「どうしてだろう?」と疑問を持つことは
非常に大切だと思います。
生物模倣は生物の構造を研究し、学ぶことで新しい技術に
昇華させることですが、身近なことでも、
「あの人はどうしてあんなに仕事ができるんだろう」
「あの会社はどうしてあんなに儲かっているんだろう」
「あのゲームはどうしてあんなに面白いんだろう」
と疑問を持って研究することで、見えてくるもの目があると思います。

少し視点を変えるだけで、他者とは違った結論にたどり着く。
そこから生まれる独自性に価値が生まれたとき、
イノベーションとともに新たな領域に踏み出せるパンチのではないでしょうか。

専門家として、ある一点を掘り下げることも大切ですが、
視点を変えることで見えることも大切にしていきたいと思いますexclamation


posted by 管理人 at 11:18 | いいモノづくり道

2012年05月14日

へこたれそうなとき読んでみて!

初めまして!大阪デザイナーの阿部ですかわいい

ヘキサとご縁があり半年とちょっと、もうそんなに時間が経ったのかと驚いております。時計

さて、このブログは学生さんが多く閲覧されているということで、学生さんに向けてのお話を書きます。

皆さんは夢を叶える上で一番大切なことは何だと思いますか?
才能?経験?学歴?
いえいえ、一番最初に必要なのは
「夢を持つこと」
え?!何それ?!当然じゃないの?!ちっ(怒った顔)ってなるようなお話なのですが
夢を持つこと、持ち続けることは実はとても難しいことなのです。

夢を叶えるために起こす行動の中には、上手くいかないこともあるでしょう。
むしろ、上手くいかないことの方が多いぐらいです。
そんな中で、「この夢をあきらめてしまおうか」「もっと楽な道にしてしまおうか」等々
誘惑は数知れず、そんな誘惑に負けて「行動することを止めてしまう」そしてその内「夢」が本当に「ただの夢」になって、「そんな夢もあったなぁ」とただ思い出すだけになってしまうのです。

文中でさらりと流しましたが「夢を持つこと」の次に大事なのが
「行動すること」そしてその次が「行動を続けること」

夢に向かって行動し続けること、それを一言で言うと「努力」になりますね。
才能も大事ですが、努力ができなければそれも台無しになってしまいます。
その大事な「努力」の一番最初に来るのが「夢を持つこと」なのです。


以上のこと、別に私が考えたことではなくて

この本から学びました

「思考は現実化する」


とても有名な本なのでご存じの方も多いかと思いますが
未読の方は是非読んでみて下さい。プレゼント
へこたれそうなとき、もうちょっと頑張ってみようと元気が出ますよ!手(グー)

ではでは!





posted by 管理人 at 16:36 | 日記

2012年05月11日

PSS

こんにちはわーい(嬉しい顔)
今月頭の暖かさに乗じて冬服を片付けて夏服を引っ張り出して来たものの、最近また冷え込んできている為朝晩は震えているがく〜(落胆した顔)マイキーですexclamation
流石に上着はカムバックしてもらいましたブティック
*-*-*

さて、少し前の話になりますがPlaystation.comにてDeveloper Programに含まれる開発リソースのベータバージョンが公開されました
こちらはPC向けの各種開発用アプリケーションとライブラリ、サンプルコード等が含まれる「PlayStationSuite SDK」と、それらを用いて作成したアプリケーションをPlaystationVitaや一部Andoroid端末で動作させる為の「PlayStationSuite Development Assistant」が含まれます。
また、開発者同士で目情報交換耳を行う為のフォーラム「PlayStationSuite Developer Forums」も用意されています。
これを初めて見たとき、思わず
お家でこれだけの開発環境が使えるなんて、なんて素敵なんでしょうぴかぴか(新しい)
と声には出しませんでしたが、非常に興味をそそられました。

今回公開された開発環境は携帯端末携帯電話向けのものですから、手軽に多くの人に見せる事ができる、見せてもらうことが出来るのが魅力的ですね。
特にVitaで動作させることが出来る、つまり市販の携帯ゲーム機で動作させることが出来るという所に非常に惹きつけられます。
他にも、開発者同士で情報交換を行う場が用意されているのがありがたいです。
一般的に広く頒布されている開発環境は、諸々の情報が四散してしまっている事が多く、情報収集に時間を要してしまう事が多くありましたふらふら
ですが、今回のように初めからこのような場が提供されていれば、情報が集約されている事が期待出来そうですグッド(上向き矢印)グッド(上向き矢印)

思い返せば、自分の作った物を見せる為、PCの前まで人を連れてくるのに一苦労した覚えがあります。
相手がPCを持っていればデータを送りつけて遊んでもらう事も出来たのですが、私の場合「ゲームはするけどPCを持っていない」友人が大多数でしたので、色々と工夫をしなければなりませんでしたあせあせ(飛び散る汗)
先程書きましたように今回公開された開発リソースは携帯端末向けの物ですから、「見せる、遊んでもらう」という点において苦労する事は少なそうです。
プログラミングを嗜んでいてゲーム開発に興味のある方は、この機会にDeveloper Programに触れてみてはいかがでしょうかパンチ

posted by 管理人 at 21:47 | 日記

2012年05月10日

メールの確認術

こんにちはexclamation藤原です。

今年は梅雨入りが例年より早く、沖縄ではもう4月末に梅雨入りしましたね。雨
このままいけば大阪も5月の後半に梅雨入りしそうです。
湿気でジメジメしたのは苦手ですがふらふら雨は好きなので関西のアジサイ寺かわいい巡りでも
しようかと計画中です。グッド(上向き矢印)グッド(上向き矢印)


さて、今回は大量のメールを確認する術をご紹介したいと思います。
仕事をこなしていくにつれ大量の仕分けフォルダを作ったり、
何度もメールを確認したりした事は無いでしょうか?目

大量のメールに悩まされているアナタに贈る10のメール整理術
http://www.lifehacker.jp/2011/11/111102email-overload.html

Gmailに学ぶ――大量のメールに振り回されない基本テクニック
http://bizmakoto.jp/bizid/articles/0608/01/news014.html

紹介ページに書かれている内容は基本的な事が主ですが
その中でも私が参考にし普段心がけている事は

・受信トレイは空にする
・返信は素早く行う
・確認したメールは優先度で仕分け
 受信トレイ
  ├─アーカイブフォルダ
  ├─要対応フォルダ
  └─保留フォルダ

以上の3点になります。

これだけでメールをかなり整理でき、担当範囲の対応が遅れる事が無くなりました。ひらめき
色々な手法があると思いますが、以上一つの例として参考になればと思います。わーい(嬉しい顔)


posted by 管理人 at 14:05 | 日記

2012年05月09日

新たな暗算方法

先週のGWに、久しぶりに大学の友人に会ってきましたわーい(嬉しい顔)
アメリカからのお土産で本場テキサスのカウボーイハットをもらい
ガンマンの気分を味わいながら飲み明かしていましたビール
やはり、日頃はあまり会えない友人と飲むのは良いですねるんるん
お久しぶりです。マックスです。


さて、最近、このような記事を見かけました。
http://zasshi.news.yahoo.co.jp/article?a=20120425-00000001-president-bus_all

簡単に内容を説明すると、2桁×2桁の掛け算を暗算で行う方法が新たに提案されたという記事です。
その計算方法の名前は「ゴースト暗算」ですぴかぴか(新しい)

日本では学校で九九までを暗記し、インドでは19×19までの計算を暗算でできるそうですが
それよりも範囲の広い99×99までの暗算方法が提案されたということで話題になっていました耳

私も記事を見て気になり、実際にゴースト暗算を解説している本を購入してみました手(グー)

ゴースト暗算.jpg


このゴースト暗算では、プレートを頭の中にイメージし、その中に数値を入れ、計算します。
2桁×1桁のゴースト暗算に関しては、youtubeでも無料で公開されていますので
こちらを見るとプレートが何を意味しているのか理解しやすくなるかと思います。

  youtube: http://www.youtube.com/watch?v=R3T8kgclG6o

2桁×2桁の暗算では、このプレートの使い方を応用して暗算を行います。
詳細な暗算方法に関しては、ここで説明する訳にはいきませんので、書籍を購入して
ぜひ自分の目で確認してみてください目


プログラマという職業柄、計算とは離れられない関係にあります。
もちろん電卓などを用いて正確に計算することに越したことはないですが
ある程度の単純な計算は、暗算で行うことで少しでも作業の効率化につながるかと思います。
(ゴースト暗算は学校で習う筆算とは異なる方法で計算を行うため、個人的に慣れるにはまだ時間がかかりそうですが…ふらふら
これからも新しい発見や技術に目を向け、触れていくことができればと思いますパンチ
それではまた手(パー)


posted by 管理人 at 21:27 | 日記

2012年05月08日

ものづくりを楽しむ

おはようございます!マーシーです。

GW中、普段は時間の都合で中々会えない友人達と久しぶりに再会することができました。
仕事の業種は違うのですが、みな自分を高めるために努力していると聞き、
自分も負けられないと気が引き締まる思いでしたパンチ
友人達に自信をもって紹介できるゲームが作れるようにより一層頑張りますexclamation


私は本が好きなので、よく本屋さんへ行きます。
その場で気に入ってしまい、しばしば予定になかったものも買ってしまうのですが、
今回、また衝動買いをしてしまいました目

20120508_1.jpg

…はい、本じゃないです。
最近の大きな本屋さんでは、本以外も見かけるようになりましたよね。
これもその中の一つで、「nanoblock」と言うそうです。
名前の通り非常に小さなブロックで、一つのポッチが4mmx4mmしかありません。
子供が遊んでいるとすぐに失くしてしまいそうですふらふら
ですので、対象年齢は12才以上となっています。

写真は「セキセイインコ」で、
他にも「パンダ」や「アヒル」といった動物や、
「姫路城」や「東京スカイツリー」といった建物もあり、
本屋さんでは完成品が展示されていました。
(中には「サグラダファミリア」なんてものも!完成品?なのか…。

ブロックと言うと
昔は子供のおもちゃというイメージがありましたが、
今は「LEGO」を筆頭に大人も楽しめる娯楽になっているように思います。
実際自分で作ってみると、
童心に返ったかのようにブロックを積んでいました。

最近では「Minecraft」といったゲームもありますね。
このゲームもブロックを積み上げて、何かを作ることができるのですが、
ユーザーの中には、実際の町をブロックで再現しようとしている人もいるそうです。

思うに、完成させるのが目的であるのでしょうが、
作っている途中もやっぱり楽しいのでしょう。
それは子供だろうと大人だろうと変わらないのだと思いますわーい(嬉しい顔)

私達の仕事も物作りです。
最終的にはユーザーのみなさんに楽しんでもらえるゲームを作るのが目的ですが、
作っている最中、私達も楽しんで作っています。

楽しく作ったもので、
さらに多くの人に楽しんでもらえるのであれば
これほど嬉しいことはありません。

そんなことを考えながら、
「nanoblock」を作っていると
すぐに完成してしまいました。

20120508_2.jpg

これからも楽しく、そして楽しんでもらえるものを作っていきたいと思いまするんるん

posted by 管理人 at 12:58 | 日記

2012年05月07日

JavaScriptで3D

突然ですが、ベランダで野菜を育て始めましたクリスマス
少しずつではありますが、元気に育っていく野菜を見るのが楽しみなgood sun晴れこと山口です。

さて少し前からJavaScriptを話題にしているのですが、
今回は前回のドラッグ&ドロップを引き継ぎつつ、今までと違ったJavaScriptのサンプルを用意しました。
お待たせ致しました、ついにWebGL到来です!!
ついにブラウザだけの力で3D表示出来る時代の波に少しだけ乗っかってみました。
その為今回のサンプルが動作するブラウザは限られてしまいます。
推奨ブラウザはGoogle Chromeとなります。

サンプルはこちらから

今回のサンプルは実行されると四角い箱が回っていますプレゼント
ここにブラウザで使用可能な画像ファイル(.png等)をドラッグ&ドロップすることで、
画像をテクスチャとして貼ることが出来ます。
※簡単に試してみましたが、どうもjpegは白い画像になってしまうようです。。。pngでお試し下さい。

ドラッグ&ドロップについては
最後に掲載するソースコードのdropFileの部分を参照して下さい。
dropイベントを受け取って、
中身が画像であればテクスチャを作成しています。
実際に一連のソースコードがあると、
どのような流れで動いているのか分かりやすいのでは無いでしょうか。

今回サンプルを作っていて、昔Java3Dでブラウザに3D表示をしていた時の事を思い出したりしました。
いまではJavaScriptで3D表示が出来ておまけにシェーダが使えてしまうのですから、
技術の進歩は凄まじいものです。

更にJavaScript版COLLADAローダというのもあるようです。
頑張れば3Dモデルデータもブラウザにドラッグ&ドロップで表示出来るようになってしまいます!
これは益々目が離せない感じです目

WebGL入門も果たしブラウザ熱が上がってきたところで今回は終了とさせて頂きたいと思います。
次回もWebGLについて書ければ良いなぁと考えておりますが、予定は未定です。


最後に注意点及び、今回のサンプルのソースコードを掲載します。
まず注意点ですが、
このサンプル、Google Chromeではサーバにソースコードがある場合は問題なく動作しますが、
ソースをローカルにダウンロードして動作させようとした場合に通常はドラッグ&ドロップが働きません。
MacOSXの場合は以下のようなシェルスクリプト経由で起動させることでファイルのドラッグ&ドロップを受け付けるようになります。

#!/bin/sh
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --allow-file-access-from-files

そして以下が今回のサンプルのソースコードになります。
今回のサンプルは行列処理にNewBSDライセンスにて配布されているglMatrixを利用しています。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>javascriptサンプル</title>
<script type="text/javascript" src="http://glmatrix.googlecode.com/files/glMatrix-0.9.5.min.js"></script>
</head>
<body>
<canvas id="canvas" ondragover="scene.dragFile(event);" ondrop="scene.dropFile(event);"></canvas>
<script id="vshader" type="x-shader/x-vertex">
#ifdef GL_ES
precision highp float;
#endif

uniform mat4 mMatrix;
uniform mat4 vpMatrix;

attribute vec3 position;
attribute vec2 uv;

varying vec2 texCoord;

void main() {
gl_Position = vpMatrix * mMatrix * vec4(position, 1.0);
texCoord = uv;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D texture;

varying vec2 texCoord;

void main() {
gl_FragColor = texture2D(texture, texCoord);
}
</script>
<script type="text/javascript">
var scene;
var frame;
window.onload = function() {
frame = new Frame();
if(frame.enabled){
scene = new Scene(frame.context3d);
frame.drawFunc = function(context3d){scene.draw(context3d);}
frame.run(new Date());
}
}
</script>
</body>
<script type="text/javascript">
Screen = {
width:640,
height:480
};
//! カラー定義
function Color(r,g,b,a){
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
//! シェーダ
function Shader(context3d, vshaderSource, fshaderSource, attrNames, uniformNames){
this.vshader = null;
this.fshader = null;
this.program = null;
this.attributes = [];
this.uniforms = [];
// 頂点シェーダー
this.vshader = context3d.createShader(context3d.VERTEX_SHADER);
context3d.shaderSource(this.vshader, vshaderSource);
context3d.compileShader(this.vshader);
if(!context3d.getShaderParameter(this.vshader, context3d.COMPILE_STATUS)){
alert(context3d.getShaderInfoLog(this.vshader));
}
// フラグメントシェーダー
this.fshader = context3d.createShader(context3d.FRAGMENT_SHADER);
context3d.shaderSource(this.fshader, fshaderSource);
context3d.compileShader(this.fshader);
if(!context3d.getShaderParameter(this.fshader, context3d.COMPILE_STATUS)){
alert(context3d.getShaderInfoLog(this.fshader));
}

this.program = context3d.createProgram();
context3d.attachShader(this.program, this.vshader);
context3d.attachShader(this.program, this.fshader);

context3d.linkProgram(this.program);
if(!context3d.getProgramParameter(this.program, context3d.LINK_STATUS)){
alert(context3d.getProgramInfoLog(this.program));
}

for(var i = 0; i < attrNames.length; i++){
var attr = context3d.getAttribLocation(this.program, attrNames[i]);
this.attributes = this.attributes.concat(attr);
}

for(var i = 0; i < uniformNames.length; i++){
this.uniforms = this.uniforms.concat(context3d.getUniformLocation(this.program, uniformNames[i]));
}
}
//! ボックスデータを作る
function Box(context3d){
this.vbuffer = [];
this.ibuffer = null;
this.indexCount = 0;
this.initVertexBuffer(context3d);
this.initIndexBuffer(context3d);
}
Box.prototype.initVertexBuffer = function(context3d){
var position = [
[-1,-1,-1],
[ 1,-1,-1],
[-1,-1, 1],
[ 1,-1, 1],

[-1, 1,-1],
[ 1, 1,-1],
[-1, 1, 1],
[ 1, 1, 1],
];
var uv = [
[0,1],
[1,1],
[0,0],
[1,0]
];
// 頂点配列を組み立てる
var index = [[0,1,2,3],[0,1,4,5],[2,3,6,7],[0,2,4,6],[1,3,5,7],[4,5,6,7]];
var vertexPosition = [];
for(var i = 0; i < 6; i++){
for(var j = 0; j < 4; j++){
vertexPosition = vertexPosition.concat(position[index[i][j]]);
}
}
var vertexTexCoord = [];
for(var i = 0; i < 6; i++){
for(var j = 0; j < 4; j++){
vertexTexCoord = vertexTexCoord.concat(uv[j]);
}
}
// Buffer作成
var vbuffer = context3d.createBuffer();
context3d.bindBuffer(context3d.ARRAY_BUFFER, vbuffer);
context3d.bufferData(context3d.ARRAY_BUFFER, new Float32Array(vertexPosition), context3d.STATIC_DRAW);
vbuffer.itemSize = 3;
this.vbuffer = this.vbuffer.concat(vbuffer);

vbuffer = context3d.createBuffer();
context3d.bindBuffer(context3d.ARRAY_BUFFER, vbuffer);
context3d.bufferData(context3d.ARRAY_BUFFER, new Float32Array(vertexTexCoord), context3d.STATIC_DRAW);
vbuffer.itemSize = 2;
this.vbuffer = this.vbuffer.concat(vbuffer);

context3d.bindBuffer(context3d.ARRAY_BUFFER, null);
}
Box.prototype.initIndexBuffer = function(context3d){
var index = [];
var base = 0;
for(var i = 0 ; i < 6 ; i++) {
index = index.concat(base + 0);
index = index.concat(base + 1);
index = index.concat(base + 2);
index = index.concat(base + 2);
index = index.concat(base + 1);
index = index.concat(base + 3);
base += 4;
}
// バッファを作成
this.ibuffer = context3d.createBuffer(context3d);
context3d.bindBuffer(context3d.ELEMENT_ARRAY_BUFFER, this.ibuffer);
context3d.bufferData(context3d.ELEMENT_ARRAY_BUFFER, new Int16Array(index), context3d.STATIC_DRAW);
context3d.bindBuffer(context3d.ELEMENT_ARRAY_BUFFER, null);
this.indexCount = index.length;
}
Box.prototype.draw = function(context3d, shader){
context3d.enableVertexAttribArray(shader.attributes[0]);
context3d.bindBuffer(context3d.ARRAY_BUFFER, this.vbuffer[0]);
context3d.vertexAttribPointer(shader.attributes[0], this.vbuffer[0].itemSize, context3d.FLOAT, false, 0, 0);
context3d.enableVertexAttribArray(shader.attributes[1]);
context3d.bindBuffer(context3d.ARRAY_BUFFER, this.vbuffer[1]);
context3d.vertexAttribPointer(shader.attributes[1], this.vbuffer[1].itemSize, context3d.FLOAT, false, 0, 0);
context3d.bindBuffer(context3d.ELEMENT_ARRAY_BUFFER, this.ibuffer);
context3d.drawElements(context3d.TRIANGLES, this.indexCount, context3d.UNSIGNED_SHORT, 0);
}

//! 描画シーン
function Scene(context3d){
this.updateTexture = false;
this.image = null;
this.texture = this.createEmptyTexture(context3d);
this.shader = new Shader(
context3d,
window.document.getElementById("vshader").text,
window.document.getElementById("fshader").text,
["position", "uv"],
["mMatrix", "vpMatrix"]);
this.box = new Box(context3d);
this.viewMatrix = mat4.create();
mat4.identity(this.viewMatrix);
mat4.translate(this.viewMatrix, [0, 0, -8]);
this.projectionMatrix = mat4.create();
mat4.identity(this.projectionMatrix);
mat4.perspective(30, Screen.width / Screen.height, 0.1, 1000, this.projectionMatrix);

this.count = 0;
}
Scene.prototype.draw = function(context3d){
this.count++;
if(this.updateTexture){
this.updateTexture = false;
this.texture = this.createTexture(context3d, this.image);
}
context3d.disable(context3d.CULL_FACE);
context3d.useProgram(this.shader.program);
var matrix = mat4.create();
mat4.identity(matrix);
mat4.rotate(matrix, 10 * this.count * Math.PI / 180, [0, 1, 0]);

var camMatrix = mat4.create(this.projectionMatrix);
mat4.multiply(camMatrix, this.viewMatrix);

context3d.uniformMatrix4fv(this.shader.uniforms[0], false, matrix);
context3d.uniformMatrix4fv(this.shader.uniforms[1], false, camMatrix);

context3d.bindTexture(context3d.TEXTURE_2D, this.texture);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_MAG_FILTER, context3d.LINEAR);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_MIN_FILTER, context3d.LINEAR_MIPMAP_LINEAR);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_WRAP_S, context3d.CLAMP_TO_EDGE);
context3d.texParameteri(context3d.TEXTURE_2D, context3d.TEXTURE_WRAP_T, context3d.CLAMP_TO_EDGE);

this.box.draw(context3d, this.shader);
}
Scene.prototype.dragFile = function(event){
if (event.dataTransfer.types[0] == "Files"){
event.preventDefault();
}
}
Scene.prototype.dropFile = function(event){
var file = event.dataTransfer.files[0];
if(file.type.match(/image\/\w+/)){
var reader = new FileReader();
reader.filename = event.dataTransfer.files[0].fileName;
var _this = this;
// エンコード完了後のコールバック
reader.onloadend = function() {
_this.setupImage(reader);
}
// Base64URI変換
reader.readAsDataURL(file);
}
}
Scene.prototype.setupImage = function(reader){
if(reader.error){
return;
}
this.image = new Image();
this.image.src = reader.result;
this.image = this.checkSize(this.image);
this.updateTexture = true;
}
Scene.prototype.createEmptyTexture = function(context3d){
var canvas = document.createElement('canvas');
canvas.height = canvas.width = 8;
var context = canvas.getContext('2d');
context.fillStyle = "#ffffff";
context.fillRect(0, 0, canvas.width, canvas.height);

return this.createTexture(context3d, canvas);
}
Scene.prototype.createTexture = function(context3d, image){
var texture = context3d.createTexture();
context3d.bindTexture(context3d.TEXTURE_2D, texture);
context3d.texImage2D(context3d.TEXTURE_2D, 0, context3d.RGBA, context3d.RGBA, context3d.UNSIGNED_BYTE, image);
context3d.generateMipmap(context3d.TEXTURE_2D);
context3d.bindTexture(context3d.TEXTURE_2D, null);
return texture;
}
Scene.prototype.checkSize = function(image) {
var w = image.naturalWidth;
var h = image.naturalHeight;
var size = Math.pow(2, Math.log(Math.min(w, h)) / Math.LN2 | 0);
if (w !== h || w !== size) {
var canvas = document.createElement('canvas');
canvas.height = canvas.width = size;
canvas.getContext('2d').drawImage(image, 0, 0, w, h, 0, 0, size, size);
image = canvas;
}
return image;
}
//! フレーム管理クラス
function Frame(){
this.enabled = false;
// コンテキストの準備
this.canvas = window.document.getElementById("canvas");
var contextName = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
for(var i = 0; i < contextName.length; i++){
try{
this.context3d = this.canvas.getContext(contextName[i]);
}catch(e){
}
if(this.context3d){
break;
}
}
if(!this.context3d){
return;
}
this.canvas.width = Screen.width;
this.canvas.height = Screen.height;
this.context3d.viewport(0, 0, Screen.width, Screen.height);
this.context3d.enable(this.context3d.TEXTURE_2D);
this.clearColor = new Color(0.1,0.1,0.1,1);
this.clearDepth = 1000;
this.enabled = true;
this.drawFunc = null;
}
Frame.prototype.clear = function(){
var cc = this.clearColor;
this.context3d.clearColor(cc.r, cc.g, cc.b, cc.a);
this.context3d.clearDepth(this.clearDepth);
this.context3d.clear(this.context3d.COLOR_BUFFER_BIT | this.context3d.DEPTH_BUFFER_BIT);
}
Frame.prototype.run = function(lastTime){
// クリア
this.clear();
this.context3d.enable(this.context3d.DEPTH_TEST);
this.drawFunc(this.context3d);
this.context3d.flush();
//! 更新を行う
var nowTime = new Date();
// 20FPS
var nextTime = 50 - (nowTime.getTime() - lastTime.getTime());
if(nextTime <= 0){
nextTime = 1;
}
var _this = this;
setTimeout(function(){_this.run(nowTime);}, nextTime);
}
</script>
</html>


posted by 管理人 at 16:33 | プログラミング

2012年05月02日

浮動小数点のカラクリ5

晴れゴールデンウィークも終わり、今年入社した新人はそろそろ五月病を
発症している頃ではないでしょうか。私といえば季節の変わり目で
風邪を引き、病気に対して抵抗力が落ち込んでいるコンドウふらふらですバッド(下向き矢印)

さて第5回となりました浮動小数点シリーズですが、今回は四則演算最後の
除算について解説させていただきます。

最初から読まれていない方はまず、こちらからご覧いただきますとより理解が深まります。

浮動小数点のカラクリ
浮動小数点のカラクリ2
浮動小数点のカラクリ3
浮動小数点のカラクリ4


今回は除算です。除算は精度さえ気にしなければ除数の逆数での乗算に置き換える事ができます。
つまり、A÷B ⇒ A×(1÷B)に置き換えて計算すればいい訳です。
(逆数はニュートン法を用いると除算使わないで計算できます。)
しかし精度が必要な場合は除算がどうしても必要になります。
それでは除算方法について考えてみます。

除算は乗算に反対の処理を行う感じで進めます。
具体的な手順は以下の通りです。


@ 指数部同士を引く
A 仮数部同士を割る
B Aの結果を正規化し指数部に反映
C 符号の処理


順番に説明します。1540 ÷ 14 を使って計算します。


1540 = (1+0.50390625) x 210 = 指数部10、仮数部1.50390625
14 = (1+0.75) x 23 = 指数部3、仮数部1.75


@は+127のバイアスが入っているので実際には137(10+127)と130(3+127)になります。
指数部同士を単純に引くと137-130=7ととても小さくなるので、本来なら


  137-127=10 (バイアス引く)
  130-127=3 (バイアス引く)
  10-3=7 (指数部の引き算)
  7+127=134 (結果にバイアス足す)


という手続きになりますが、


  137-130=7 (バイアス引く前の段階で引く)
  7+127=134 (結果にバイアス分足す)


でも同じ結果になりますのでこちらの計算を採用します。


Aは仮数部を取り出した状態の時には+1が省略されているので加算の時と同じように+1します。


1540の仮数部 1.50390625 = C08000(16進数) = 110000001000000000000000(2進数)
14の仮数部 1.75 = E00000(16進数) = 111000000000000000000000(2進数)


このまま普通に除算してしまうと0か1にしかならなくなるので
本来は計算結果に対して23bit左シフト(小数点の位置が23bit目にあるので)するところを
計算前の被除数に対して23bit左シフトして精度を保ちます。

2進数で表記すると桁が多くなるので16進数で計算します。


(0xC08000<<23) / 0xE00000 =
0x604000000000 / 0xE00000 = 0x6E0000


Bですが、0x6E0000は0.859375で1未満となるので正規化の必要があります。
  仮数部 0x6E0000 << 1 = 0xDC0000
  指数部 134 - 1 = 133

最後にCの符号処理は乗算と同じく同じ符号であればプラスに、異なる符号ならマイナスになりますので
排他的論理和とれば簡単に再現できます。上記の場合はどちらもプラスなので結果もプラスになります。
結果は


  符号 0
  指数 133
  仮数 0x5C0000(1.0が加算されているので引いて、0xDC0000 - 0x800000 = 0x5C0000)


となり、(1+0.71875) x 2(133-127) = 110

と晴れて答えが求まりました。

いつものようにプログラム作ってみました。プログラムではGRSビットも考慮された処理になっています。
正規化処理は前回と同じです。



#define FRAC_LEN 23
#define GRS_LEN 3
#define BIAS 127

typedef unsigned __int64 uint64;
typedef signed __int64 sint64;

union FLOATING_VALUE{
float FloatValue;
struct {
unsigned int Fraction:FRAC_LEN;
unsigned int Exp:31-FRAC_LEN;
unsigned int Sign:1;
}s;
};

// 正規化
void normalize( int *exp, unsigned int *frac )
{
unsigned int value;
int Exp = *exp, Frac = *frac;
// 1.0〜1.99999…に収まるよう正規化
if(Frac == 0){ // 0?
Frac = 0;
Exp = 0;
}else{
if( Frac >= (1<<(FRAC_LEN+GRS_LEN+1))){ // 桁あふれ (2.0以上)
do{
value = Frac & 1; // シフトによって捨てられる値
Frac >>= 1;
Frac |= value; // スティッキーbitの補充
Exp++;
}while(Frac >= (1<<(FRAC_LEN+GRS_LEN+1)) && Exp < 255);

}else if(Frac < (1<<(FRAC_LEN+GRS_LEN))){ // 桁借り(1.0未満)
do{
value = Frac & 1;
Frac = (Frac - value) << 1;
Frac |= value; // スティッキーbitの補充
Exp--;
}while(Frac < (1<<(FRAC_LEN+GRS_LEN)) && Exp > 0);
}
if(Exp>=255){ // オーバーフロー?
// 無限大とする
Exp=255;
Frac=0;
}else if(Exp<0){ // アンダーフロー?
// 非正規値とする
Exp=0;
}
}
*exp = Exp;
*frac = Frac;
}

float FDiv(float a, float b)
{
FLOATING_VALUE va,vb,vc;
int value;

va.FloatValue = a;
vb.FloatValue = b;
unsigned int kasuuA,kasuuB;
// aが0なら計算せず0を返す
if(va.s.Fraction==0 && va.s.Exp==0){
vc.s.Fraction = 0;
vc.s.Exp = 0;
vc.s.Sign = va.s.Sign ^ vb.s.Sign; // 符号の処理
return vc.FloatValue;
}
// bが0なら計算せずエラーを返す(divied by 0)
if(vb.s.Fraction==0 && vb.s.Exp==0){
// 無限大を返す
vc.s.Fraction = 0;
vc.s.Exp = 255;
vc.s.Sign = va.s.Sign ^ vb.s.Sign; // 符号の処理
return vc.FloatValue;
}
kasuuA = va.s.Fraction + (1<<FRAC_LEN); // 省略されている1.0(1<<23)を加える
kasuuB = vb.s.Fraction + (1<<FRAC_LEN); // 省略されている1.0(1<<23)を加える
kasuuA <<= GRS_LEN; // GRSビット分桁上げ
kasuuB <<= GRS_LEN; // GRSビット分桁上げ
int exp = va.s.Exp - vb.s.Exp + BIAS; // 指数部の計算
// 仮数部の計算(GRSビット分底上げ)
uint64 kasuuL = (static_cast<uint64>(kasuuA)<<(FRAC_LEN+GRS_LEN)) / static_cast<uint64>(kasuuB);
kasuuA = static_cast<unsigned int>(kasuuL);
normalize( &exp, &kasuuA ); // 正規化
value = kasuuA & ((1<<GRS_LEN)-1); // GRSビット抽出
if(value >= 4){ // 0b100以上なら切り上げ、0b011以下なら切り下げ
kasuuA += 1<<GRS_LEN; // +1切り上げ
normalize( &exp, &kasuuA ); // 再度正規化
}
kasuuA >>= GRS_LEN; // GRSビット捨てる
// 結果を格納
vc.s.Fraction = kasuuA;
vc.s.Exp = exp;
vc.s.Sign = va.s.Sign ^ vb.s.Sign; // 符号の処理
return vc.FloatValue;
}


除数が0の場合、計算不能になるので事前に初期段階ではじいています。仮数部同士の除算では0チェック
していませんが、両方とも24bit目が必ず1になるので0チェックは省いています。
被除数が0の場合も除数の値に関わらず必ず0になるので、事前に0を返しています。






除算は加算や乗算のようにパイプライン化できない演算(同じ計算回路を何度も再利用しないといけない為)
なので非常に時間のかかる処理になってしまいます。しかもパイプライン構造でないので1回の除算が
完了するまで次の除算が計算できず待たされてしまうなどデメリットが非常に大きい計算です。
その為、可能であれば冒頭でも書きました逆数の乗算に置き換える等工夫する必要があります。
除算がどの位遅いかというとプロセッサにもよりますが乗算に比べると数倍〜十数倍(実計算時間)の差があります。
例えば透視変換で、XとYをZで割る処理の場合
  SX = X / Z;
  SY = Y / Z;
となりますが、これを
  INVZ = 1 / Z;
  SX = X * INVZ;
  SY = Y * INVZ;
に置き換えてもまだこっちの方が早かったりします。2個以上の除算は検討する必要がありますね。
最適化かけたCコンパイラなら定数の除数の場合は自動的に逆数の乗算などに置き換えてくれたりします。
しかし除数が変数の場合はそのまま除算命令になるので手動で最適化する必要があります。

さて5回に渡って浮動小数点の仕組みについて説明してきましたが、これらの計算部分はほとんど最適化
が施されていませんので実用的ではありません。あくまで浮動小数点の仕組みを理解する事が趣旨であり
分かりやすくした結果、速度が犠牲になっています。もしちゃんと実用的なロジックでシステムに組み込
みたいって思っている(よっぽど古いプロセッサ以外は必要ありませんが)方は是非gcc(gnuのcコンパイラ)
のソースを入手して解析してみて下さい。このシリーズでは説明していない浮動小数点⇒10進数表示など
も調べる事ができるかと思います。製作されるならビット長128bitなど超精度浮動小数点など面白いかも
しれませんね。
今回の浮動小数点ネタは私自身も深く理解する事が出来(資料作るにあたって色々調べました)とても楽しく
進める事ができました。またこのようなネタがありましたら私自身の勉強も兼ねて公表したいと思います。
次回も何かプログラムネタを探したいと思います。ではexclamation


posted by 管理人 at 14:22 | 研究・開発