blog.Ring.idv.tw

2009 December

移軸攝影(Tilt-shift Photography)

臺北市立美術館

後製移軸攝影效果

上面兩張圖是用來呈現何謂移軸攝影(Tilt-shift photography),上圖是之前用LX3所拍攝的一般廣角影像,而下圖是筆者用photoshop後製移軸效果的影像,兩者看上去~ 下圖所呈現的效果有一種很像假的真影像,如同小人國般的感覺,而這就是移軸攝影。

不過這不是移軸攝影的主要原理和目的,真正的原理是當使用廣角鏡頭要取景的時候,如果我們將鏡頭朝上或朝下傾斜,這會造成相機內的感光元件沒有和要拍攝物體的平面保持平行進而導致變形,所以需要有一種鏡頭來處理這樣的現象,而這類的鏡頭就稱為「透視控制(Perspective Control Lens)」又稱「移軸鏡頭」,Nikon在去年就發表了一顆「Nikon PC-E Nikkor 24mm移軸鏡頭」,這顆鏡頭大約要NT$60,000吧... Orz

如果你想要有這樣的效果,但又不想買這類型的鏡頭,而又沒學過後製的話... 沒關係!

有好心人士用Adobe AIR開發了一個「TiltShift Generator」,或者如果你不想裝軟體的話,還有一個線上版的可以用「tiltshiftmaker.com

相關資源

冷門鏡頭PC-E Nikkor 24mm f/3.5D ED

移軸鏡攝影

移軸攝影與短片

40張很有fu的移軸攝影

2009-12-27 19:49:58 | Add Comment

Flash® Professional CS5 beta will not be published!

昨天早上就收到這封信了,前幾天還在想說Adobe官方不是強調今年年底會公佈「 Flash® Professional CS5 beta」嗎?難道要給這些設計師或開發人員一個聖誕禮物?結果... 筆者想太多了!

官方的說法是,有「太多」的開發人員對於用Flash CS5來開發iPhone應用程式很感興趣,所以決定不發佈beta version,希望此舉能讓正式版更早釋出。

呃... 說白話一點的就是,要在Flash CS5上開發iPhone應用程式就是沒有免費版可以先體驗就是了!!

相關資訊

There will not be a beta for Flash Professional CS5

What happened to the Flash CS5 beta?

2009-12-19 10:34:03 | Add Comment

Hadoop - 探討RunJar

通常要執行一個Hadoop Job時,會透過下述的指令來達成:

${HADOOP_HOME}/bin/hadoop jar your.jar mainClass args

當送出上述指令之後,透過「jps」指令可以觀察到有一個「org.apache.hadoop.util.RunJar」的程式正在執行:

19141 RunJar

而該「org.apache.hadoop.util.RunJar」的程式就是透過「${HADOOP_HOME}/bin/hadoop」shell來執行對應的Command「jar」,並啟動「org.apache.hadoop.util.RunJar」來進行Hadoop Job的第一步。

hadoop shell (lines:228-229)

elif [ "$COMMAND" = "jar" ] ; then
  CLASS=org.apache.hadoop.util.RunJar

main method開始來看,它會從你所執行的「your.jar」來試著取得manifest的Main-Class屬性用來當作mainClassName,如果沒有指定的話就從參數取得。

RunJar.java (lines:94-107)

Manifest manifest = jarFile.getManifest();
    if (manifest != null) {
      mainClassName = manifest.getMainAttributes().getValue("Main-Class");
    }
    jarFile.close();

    if (mainClassName == null) {
      if (args.length < 2) {
        System.err.println(usage);
        System.exit(-1);
      }
      mainClassName = args[firstArg++];
    }
    mainClassName = mainClassName.replaceAll("/", ".");

接著該程式會將「your.jar」解壓縮在一個暫存的目錄裡面,該目錄的位置會取決於「hadoop.tmp.dir」的設定,從「${HAOOP_HOME}/src/core/core-default.xml」可以得知該設定的預設值為「/tmp/hadoop-${user.name}」,所以從下述的原始碼可得知,它一開始會試著建立「/tmp/hadoop-${user.name}」目錄(通常只有第一次執行時),然後再透過「File.createTempFile()」方法來建立一個「hadoop-unjar*」的暫存目錄,所以「your.jar」解壓縮後的class檔都會放在此目錄裡面,當執行結束之後也會一併刪除該目錄。

RunJar.java (lines:109-132)

File tmpDir = new File(new Configuration().get("hadoop.tmp.dir"));
    tmpDir.mkdirs();
    if (!tmpDir.isDirectory()) { 
      System.err.println("Mkdirs failed to create " + tmpDir);
      System.exit(-1);
    }
    final File workDir = File.createTempFile("hadoop-unjar", "", tmpDir);
    workDir.delete();
    workDir.mkdirs();
    if (!workDir.isDirectory()) {
      System.err.println("Mkdirs failed to create " + workDir);
      System.exit(-1);
    }
    
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
          try {
            FileUtil.fullyDelete(workDir);
          } catch (IOException e) {
          }
        }
      });
     
    unJar(file, workDir);

最後才會透過Reflection機制來達成動態載入「your.jar」的mainClass。

RunJar.java (lines:134-159)

ArrayList<URL> classPath = new ArrayList<URL>();
    classPath.add(new File(workDir+"/").toURL());
    classPath.add(file.toURL());
    classPath.add(new File(workDir, "classes/").toURL());
    File[] libs = new File(workDir, "lib").listFiles();
    if (libs != null) {
      for (int i = 0; i < libs.length; i++) {
        classPath.add(libs[i].toURL());
      }
    }
    
    ClassLoader loader =
      new URLClassLoader(classPath.toArray(new URL[0]));

    Thread.currentThread().setContextClassLoader(loader);
    Class<?> mainClass = Class.forName(mainClassName, true, loader);
    Method main = mainClass.getMethod("main", new Class[] {
      Array.newInstance(String.class, 0).getClass()
    });
    String[] newArgs = Arrays.asList(args)
      .subList(firstArg, args.length).toArray(new String[0]);
    try {
      main.invoke(null, new Object[] { newArgs });
    } catch (InvocationTargetException e) {
      throw e.getTargetException();
    }

2009-12-16 00:09:37 | Add Comment

談談Playfish

上面這張圖是Playfish所設計Bowling Buddies的遊戲畫面,然而,本文所要談的重點卻不在於遊戲本身,而是可以注意到上圖下方有一位「Amr Awadallah」(該作者的Blog)居然也玩過此遊戲!! Ok, 那位仁兄究竟是何許人也?是的~ 他是Cloudera公司的CTO,也就是提供Apache Hadoop相關服務的公司,到這裡為止我相信有玩過這款遊戲的人應該都知道,這款社交遊戲(Social Game)要玩到「190」分也不是一開始就能達到的,所以從另一個角度再來看Playfish公司,為何連「Amr Awadallah」都會玩?Playfish是什麼樣的公司?

從「Playfish - wiki」可以得知,Playfish是在2007年10月由Kristian Segerstrale、 Sebastien de Halleux、Sami Lababidi和Shukri Shammas四位共同創辦的,主要是開發一些在Social Networking平台上的社交遊戲,而該公司在2009年11月9日被「Electronic Arts」公司以2.75億美元所收購(We’re combining forces with EA!),為何短短兩年能有如此大的變化?我想這四位創辦人當初應該也是沒預料到的(純粹猜測),或許可以從Mr. 6網站在11月11日所發表的一篇「AdMob與Playfish被高價併購,變動時代中兩個32歲創業家所嶄露的成功特質」文章來參考與借鏡。

Mr.6在該文章中歸納出的下列四點結論:

一、鎖定一個自己喜歡的事情,就做那個做到永久。「做它做到死,在哪裡都可以。」

二、再找一個現在最新的平台、趨勢,在這個之上努力做第一點那件喜歡的事情。該跟風的時候就跟風,無論跟什麼風,核心依然是同一件事

三、不見得要到矽谷做,只要第二點的平台選對,在哪裡都可以很成功。

四、給自己無限次練習:上面的幾個點,是可以一年又一年的重覆去做的,無論是Omar或Kristian,在他們賺翻以前都曾經做另一個東西,因為做了那些東西,如果沒有做那些小點子,怎麼會「試」到網路上目前真正的「問題」?大致來看,我們的頭腦不會比人家聰明,唯一能「聰明過人」(out- wit)的方法,就是看到別人沒看到的東西,然後用一點點大腦,就可以完成它。當然還要更多一點點大腦在「執行」上面,但基本上只要看到別人沒看到的東西,就贏了一大半,唯一看到的方法就是要撥開那些遮簾,除了往前衝之外別無它法來撥開那些遮簾。

再從另一個技術的角度來看,為何短短兩年的公司如何負擔如此龐大的網路流量、儲存空間和電腦設備?(還沒加上電費等)除非它一開始就有大量的資金投入! 不過「好像」也沒有,或許筆者可以這麼說,因為該公司用了「雲端」服務(Playfish Case Study: Amazon Web Services),上述所提及的流量、空間和電腦設備等完全由Amazon所提供的服務一手包辦! 全部都用租的,以用多少算多少來計費,就算機器不夠負載時也只要上網增加即可,而當然也不用負擔機器的耗損,所以整個團隊可以「專注」在一件事,就是將全部的心力投入在完成打造一個好的作品,我想這也是他們成功的原因之一(成功的定義取決於每個人看法而有所不同,這裡指的是該作品能做到讓全世界的人都來使用),而未來呢?誰會是下一個Playfish?筆者不曉得~ 但,有一個結論:「能有一個團隊有向心力地在共同完成一件事是幸福的!!

2009.12.13 updated

從Playfish官方的招募網站可以得知,該公司得到Accel創投的支持並以「400萬美金」所成立的。

相關文章

《Restaurant City》換老闆 美商藝電收購Playfish 著眼新興遊戲領域

2009-12-13 01:30:07 | Add Comment

AS3 - Timeline_N

在上一篇「AS3在Document Class和Timeline」曾探討過將AS3程式寫在時間軸的時候,Flash編譯器會自動產生了一個Dynamic Class「MainTimeline」,那如果在Flash IDE建一個「MovieClip」,並在該元件的某個影格內加上「stop()」程式,而經由Flash CS4編譯器處理後會如何呢?

Decompiling:

package test_fla
{
    import flash.display.*;

    dynamic public class Timeline_1 extends MovieClip
    {
        public function Timeline_1()
        {
            addFrameScript(61, this.frame62);
            return;
        }
        function frame62()
        {
            stop();
            return;
        }
    }
}

如同上述的程式碼,在主時間軸的影格寫下AS3程式的話,Flash會產生「MainTimeline」Dynamic Class,若是在任一「MovieClip」內寫AS3程式,則會產生「Timeline_N」的Dynamic Class,而「N」整數就取決於Flash編譯器所決定的,不過我們也可以透過「getQualifiedClassName(this);」來取得該元件的類別名稱(如:Timeline_1),如此,既然知道該元件對應的類別是否就能如法泡製的複製一份呢?答案是肯定的,如下:

var rect:MovieClip = new Timeline_1();
rect.x = 100;
addChild(rect);

另外值得注意的是,就算只是寫下註解的字元「//」也會產生如下的程式碼:

package test_fla
{
    import flash.display.*;

    dynamic public class Timeline_1 extends MovieClip
    {

        public function Timeline_1()
        {
            addFrameScript(61, this.frame62);
            return;
        }
        function frame62()
        {
            return;
        }
    }
}

所以可見Flash編譯器在這部份未來仍然有值得改善的空間!

2009-12-10 23:25:15 | Comments (1)

Previous Posts
Copyright (C) Ching-Shen Chen. All rights reserved.

::: 搜尋 :::

::: 分類 :::

::: 最新文章 :::

::: 最新回應 :::

::: 訂閱 :::

Atom feed
Atom Comment