2008/09/26

整合 google services

google phone 都出來了,是要怎樣?我一直想做這樣的產品,可惜沒機會,就弄了個頁面聊表自己的心意一下,有興趣的人可以參考整合幾個 google apis 的範例,畫面如下:


您可以自行前往示範網頁觀看並下載原始碼,不過要先說一下,解析度適合 1024x768 按 F11 以全螢幕看,並且只適用 Firefox, 而且會要你裝 google earth plugin,若你肯乖乖裝的話就可以用地球。

有心要寫這樣的頁面的人,可以參考
http://code.google.com/apis/maps/
http://code.google.com/apis/ajax/
http://code.google.com/apis/ajaxfeeds/
等等

2008/09/16

The sample code by using Papervision3D 2.0

要使用 Papervision3D 的話,papervision3D 基礎-1是不錯的入門。底下是包含了各種基本物件的範例:


package{
import flash.display.Sprite;

import org.papervision3d.cameras.Camera3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;

// import extra modules
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.Cone;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.objects.primitives.Cylinder;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.objects.primitives.Sphere;
// end of extra modules

public class Panorama extends Sprite{
private var viewport:Viewport3D;
private var scene:Scene3D;
private var camera:Camera3D;
private var renderer:BasicRenderEngine;

public function Panorama()
{
initPapervision3D();
}

private function initPapervision3D():void
{
viewport = new Viewport3D();
addChild(viewport);

scene = new Scene3D();
camera = new Camera3D();
renderer = new BasicRenderEngine();

/* body of the example code */

// Plane
var m:WireframeMaterial = new WireframeMaterial();
var plane:Plane = new Plane(m, 800, 800, 2, 2);
scene.addChild(plane);

// Cone
var m2:WireframeMaterial = new WireframeMaterial(0xFF5600);
var cone:Cone = new Cone(m2, 100, 100, 8, 6);
cone.rotationY = 40;
cone.rotationX = -30;
cone.moveRight(300);
scene.addChild(cone);

// Sphere
var sphere:Sphere = new Sphere();
scene.addChild(sphere);

// Cylinder
var cylinder:Cylinder = new Cylinder(m2, 100, 100, 8, 6, -1);
cylinder.moveUp(300);
scene.addChild(cylinder);

// Cube
var materialsList:MaterialsList = new MaterialsList();
var cube:Cube;
/*
var frontMaterial:WireframeMaterial = new WireframeMaterial(0x00FF56);
var backMaterial:WireframeMaterial = new WireframeMaterial(0x00FF56);
var leftMaterial:WireframeMaterial = new WireframeMaterial(0x00FF56);
var rightMaterial:WireframeMaterial = new WireframeMaterial(0x00FF56);
var topMaterial:WireframeMaterial = new WireframeMaterial(0x00FF56);
var bottomMaterial:WireframeMaterial = new WireframeMaterial(0x00FF56);

materialsList.addMaterial(frontMaterial, "front");
materialsList.addMaterial(backMaterial, "back");
materialsList.addMaterial(leftMaterial, "left");
materialsList.addMaterial(rightMaterial, "right");
materialsList.addMaterial(topMaterial, "top");
materialsList.addMaterial(bottomMaterial, "bottom");
cube = new Cube(materialsList,500,500,500,1,1,1,Cube.ALL);
*/
var allM:WireframeMaterial = new WireframeMaterial();
materialsList.addMaterial(allM, "all");

cube = new Cube(materialsList,500,500,500,1,1,1,Cube.ALL);
cube.moveLeft(400);
cube.moveForward(200);

scene.addChild(cube);

/* end of the body of the example code */

renderer.renderScene(scene, camera, viewport);
}
}
}

show pictures on a sphere using Papervision3D 2.0

底下是採用 Papervision3D 2.0(GreatWhite)用來展示圖片在一顆球上的程式,galleries.xml 也附在後面當註解。


package
{
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.net.URLLoader;
import flash.net.URLRequest;

import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.render.BasicRenderEngine;

import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;

[SWF(width="640", height="480", frameRate="60")]

public class Panorama extends Sprite
{
private var container :Viewport3D;
private var scene :Scene3D;
private var camera :Camera3D;
private var renderer :BasicRenderEngine;

private var assetArray :Array;

private var cC :Array;

private var count :Number;

private var flying :DisplayObject3D;

private var front:BitmapMaterial;
private var back:BitmapMaterial;
private var bottom:BitmapMaterial;
private var right:BitmapMaterial;
private var left:BitmapMaterial;
private var top:BitmapMaterial;

private var movementFactor:Number = 100;
// set the key actions
private var keyRight:Boolean = false;
private var keyLeft:Boolean = false;
private var keyForward:Boolean = false;
private var keyBackward:Boolean = false;

private var forwardFactor:Number = 0;
private var sideFactor:Number = 0;
private var inertia:Number = 5;

public function Panorama()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
init3D();
stage.quality = StageQuality.LOW;
}

private function init3D():void
{
container = new Viewport3D(640,480,false,true);
scene = new Scene3D();
camera = new Camera3D();

container.buttonMode = true;
addChild( container );

renderer = new BasicRenderEngine();
flying = new DisplayObject3D();
var myurl:URLLoader = new URLLoader(new URLRequest("galleries.xml"));
myurl.addEventListener(Event.COMPLETE, loadAssets);
}

private function loadAssets(event:Event):void
{
var loader:URLLoader = event.target as URLLoader;
var xml:XML = XML(loader.data);

count = 0;
assetArray = new Array();
for each (var pic:XML in xml..photo) {
assetArray.push(pic.source);
}

loadOne();
}

private function loadOne():void
{
var loaD:Loader = new Loader();
loaD.contentLoaderInfo.addEventListener(Event.COMPLETE, progfin);
var urlreq:URLRequest = new URLRequest(assetArray[count]);
loaD.load(urlreq);
}

private function progfin(e:Event):void
{
var bmm:BitmapData = e.target.content.bitmapData;

count++;
if(count < assetArray.length) {
var doublePlane:DisplayObject3D = new DisplayObject3D();
var frontPlane:Plane = new Plane(new BitmapMaterial(bmm));
var rearPlane:Plane = new Plane(new BitmapMaterial(bmm));
rearPlane.rotationY = 180;

doublePlane.addChild(frontPlane);
doublePlane.addChild(rearPlane);

doublePlane.rotationX = Math.random() * 360;
doublePlane.rotationY = Math.random() * 360;

doublePlane.moveForward(1000);

flying.addChild(doublePlane);

loadOne();
} else {
createSphere();
addEventListeners();
};
}

private function createSphere():void
{
flying.z = 1000;

scene.addChild( flying);
}

private function addEventListeners():void
{
addEventListener(Event.ENTER_FRAME, render);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

// if key is pressed do this event listerners pay attention to the key press
private function onKeyDown(e:KeyboardEvent):void
{
switch(e.keyCode) {
case "W" .charCodeAt():
case Keyboard.UP:
keyForward = true;
keyBackward = false;
break;

case "S" .charCodeAt():
case Keyboard.DOWN:
keyForward = false;
keyBackward = true;
break;

case "A" .charCodeAt():
case Keyboard.LEFT:
keyLeft = true;
keyRight = false;
break;

case "D" .charCodeAt():
case Keyboard.RIGHT:
keyLeft = false;
keyRight = true;
break;

}
}

// this second function determines the keyup false
private function onKeyUp(e:KeyboardEvent):void
{
switch(e.keyCode) {
case "W" .charCodeAt():
case Keyboard.UP:
keyForward = false;
break;

case "S" .charCodeAt():
case Keyboard.DOWN:
keyBackward = false;
break;

case "A" .charCodeAt():
case Keyboard.LEFT:
keyLeft = false;
break;

case "D" .charCodeAt():
case Keyboard.RIGHT:
keyRight = false;
break;

}
}

private function onEnterFrame(e:Event):void
{
if (keyForward) {
forwardFactor += 10;
}

if (keyBackward) {
forwardFactor += -10;
}

if (keyLeft) {
sideFactor += -10;
}

if (keyRight) {
sideFactor += 10;
}

forwardFactor += ( 0 - forwardFactor ) / inertia;
sideFactor += ( 0 - sideFactor ) / inertia;

if ( forwardFactor > 0) {
camera.moveForward(forwardFactor);
}else {
camera.moveBackward( - forwardFactor );
}

if (sideFactor > 0) {
camera.moveRight( sideFactor );
}else {
camera.moveLeft( -sideFactor );
}
}

private function render(e:Event):void {
renderer.renderScene(scene, camera, container);
flying.yaw(1);
}
}
}
/* galleries.xml
<galleries>
<photo>
<source>pic.jpg</source>
</photo>
<photo>
<source>text.jpg</source>
</photo>
</galleries>
*/

2008/09/06

using camera Adobe Papervision3D sphere 環境著球轉

最近想要建立 3D 的操作環境,安裝Flex Builder, 後來也找到Papervision3D,前者是 Adobe 的 Flash Integrated developing environment,後者是 based on actionscript for flash的 3D library, 顧名思義,用來在 "paper" 的視野上建立 3D 的運作,還算不錯,而且是 open source, 將來有機會也拿來應用在 mozilla 上,例如採用 Javascript + SVG|OpenGL|Canvas 上。

下面是一段移動 camera 環繞著球面轉動的運作的步驟:

1. Determine yAngle, the angle by which you want to rotate the camera up
2. Determine xAngle, the angle by which you want to rotate the camera right
3. Determine cameraDistance, the distance the camera is from the center of the sphere
4. Move the camera to the center of the sphere using the moveForward function: camera.moveForward(cameraDistance)
5. Tilt the camera up: camera.tilt(yAngle)
6. Pan the camera right: camera.pan(xAngle)
7. Move the camera back using the moveBackward function:
camera.moveBackward(cameraDistance)

2008/09/04

攝影學 digital camera theorem

引用來源來自這兒,覺得還不錯,回應的討論也很有深度,有興趣的人可以前往一觀,這邊貼上原內容講到的研究結果部份:

--

照相真實地重現了一個人眼見到的畫面,這個瞬間,攝影師所見到的畫面被定格,永遠的存下來。所以,照相機的功能不僅是在模擬人眼看到的景像,最後的輸出,也是要給人眼看的。在瞭解這點後,人眼的能力與照相機的能力的比較,以及相片中的影像如何被腦部解讀就成為了一個很有趣的課題。PopPhoto.com 整理了幾點人眼和相機的不同處,以及這些不同處對照相而言所代表的意義...

解析度

原則上:人眼的總可視角差不多有 120 度,總計約 5 億 7600 萬畫素(576mp)。
實作上:照相機的解析度(目前來說)遠遜於人眼。但人類的大腦是個很神奇的東西,會自動把解析度不足的部份自動用「補插點法」補足,因此普通 3mp 的照相機照出來的畫面顯示在螢幕上,我們也不會覺得解析度不夠。

景深

原則上:人眼的構造也和相機不太相同,因此不大能套用相同的理論來解釋,不過人眼的「焦段」大約在 22mm,「光圈」約為 f/3.5,視角幾近 180 度。有趣的是,人眼看到的範圍中,只有中間的 2 度左右是銳利的,其他是愈向外愈模糊。
實作上:這大概也是為什麼淺景深照片一般比較受喜愛的原因。因為人眼視線範圍中只有一點點是銳利的,自然將不重要的背景做糊焦處理,會有助於將人眼的視線(那窄窄的 2 度)集中在主體上。

感光度

原則上:人眼的感光度是會自動調整的。晚上的時候大約在 ISO 800 左右,大白天時則大約只有 ISO 1。但又一次的,人眼的運作原理和照相機有很大的不同 -- 人眼會自動將很多「格」的畫面疊加,來增強夜視能力。
實作上:因此照相機可以輕易地超過人眼的 ISO 極限,就算晚上從觀景窗看出去一抹黑,用 ISO 6400 仍然能拍出照片來也說不定。

動態範圍

原則上:人眼的動態範圍非常廣,從正午的太陽到午夜的星星都看得見,整體算下來大約有十億比一之譜,照相機就差得遠了。
實作上:技術上照相機可以用 HDR 的技術來模擬出人眼在某些環境下的高動態範圍,但即使如此,目前的呈現媒介(螢幕、照片)還是無法複製人間的動態範圍。只能說,有些真正的美景仍然是只能看在眼裡,記在心裡的。

線條

原則上:當畫面有線條時,人眼的視線會沿著線條走,並且短暫停留在轉角處。
實作上:線條不一定要是線,也可以是色彩間的變化、或是強對比產生的線條。應用在照片上,就是多拍地平線、多拍藍天白雲的意思。如果有重要的目標,可以放在線條交叉的地方,有助於引導觀看者在目標上停留。

光線

原則上:科學家發現,當無法從畫面的光影判斷光線來向時,右撇子會自動認定光線來自畫面的左上方,而左撇子則會自動認定光線來自畫面右上方。
實作上:反過來說,拍攝時將光線設置為從左上方打入,會看起來最自然(抱歉了,左撇子們 XD)。

人臉

原則上:人類是完全被「臉」制約的生物。只要視線中有臉出現,視線幾乎毫無例外地會立刻被吸引過去,判斷對方是敵、是友、還是可能的交配對象 (!?)
實作上:看你是要拍什麼樣的照片囉?如果是拍景的話,那就要極力避免畫面中出現臉。如果是同時拍人和拍物的話,就要設法將物靠近臉,增加「曝光」的機會。如果實在不知道拍什麼好的話,拍帥哥正妹絕對是萬靈丹啦!

視線追移

原則上:如果畫面中的人眼不是對著鏡頭的話,看照片的人會自然地跟著畫面中視線的方向移動,試圖找出畫面中的人在看什麼。
實作上:讓畫面中的人(如果他不是主角的話)看著畫面中的重點。如此一來看照片的人的視線,就會自然從人臉移到物體上。

預期運動

原則上:當人眼追蹤移動中的物體時,會自然的把視線放在移動物體的前上一點點的位置,以避免追蹤時丟失了目標。
實作上:照相時在物體的前方稍微留一點白,會形成好像物體在移動的假像。

所以為什麼廠商喜歡找 Showgirl?為什麼 Showgirl 每次的 pose 就那麼幾個 -- 產品放臉旁邊、放胸前、放腰邊?其實答案是很簡單的,因為這些地方能吸引目光罷了。美眉先吸引著男人的目光,再把產品放在目光遊移處,自然就沒可能被忽略掉了。小薑自已是不會刻意拍這樣的照片,但看其他幾位科科們每次拍回來的照片都會引來「產品?產品在哪?」的感嘆,就能知道人眼和人腦對判讀一張照片而言,佔有多重要的地位了。

2008/09/01

用 Flex Builder 3 搭配 PaperVision3D 來產生立體展示

這問題是最近我工作上需要展示立體物件時,決定採用 PaperVision3D, 可是發現要用這個工具,必須有Adobe CS3或者是Flex Builder 3。個人認知上想來錯誤頗大,總之一句就是我決定採用 FlexBuilder3,卻因為陌生一直不知道要怎麼把 PV3D example code 編譯好,找半天,就Installing Papervision3D on Flash and Flex寫的最好,因此特來與大家分享。

原文為了適應各種狀況講的頗複雜,而我只需要 PaperVision3D 2.0, 因此請到PaperVision3D下載 2.0 beta 1, 或直接點此下載。假設你的系統已安裝 FlexBuilder3,先暫時先說點別的,因為 FlexBuilder3 是整合 eclipse, 很多教學文件都教你用 SVN, 問題是我在公司無法以 SVN 來安裝軟體,若您有此需求,解決方法就是跑到可以用 SVN 的網路環境,或者直接下載 zip 檔後解開,放到 FlexBuilder3 安裝目錄去,例如我下載subversive for eclipse要給 FlexBuilder3 用,解壓縮這個 .zip檔放到 C:\Program Files\Adobe\Flex Builder 3 即可在 Flex Builder 3 下使用 SVN。

上面講 SVN 跟主題其實是無關,算是題外話。在解壓Papervision3D_2.0_beta_1_src.zip之後,最重要的概念,就是把它當 Flex Library,做法為:

File > New > Flex Library 指定名稱,例如 「Papervision Library」(我是用 pv3d)


畫面中的右下角的 Folder 就填您解壓的目錄即可,這個目錄一般是用 SVN 取得最新的。至於要怎麼把人家寫好的 example code 在編譯時可以使用 PV3D library? File -> Import -> Flex Project 匯入 example code 之後,選取 Properties 的畫面如下:



在 ActionScript Build Path --> Library Path 中,利用 Add Project 將先前的 「Papervision Library」 加進來(我是用「pv3d」 而非「Papervision Library」)即可。