青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

不會飛的鳥

2010年12月10日 ... 不鳥他們!!! 我要用自己開發的分布式文件系統、分布式調度系統、分布式檢索系統, 做自己的搜索引擎!!!大魚有大志!!! ---楊書童

#

[linux]ld.so.conf 和 ldconfig

今天重新編譯以前的一個程序,里面用到iconv庫:gcc test.cc -liconv
運行時:a.out:error while loading shared libraries: libiconv.so.2: cannot open shared object file: No such file or directory
以前編譯運行是可以的,可能是不久前升級了iconv庫影響。在/usr/local/lib下可以找到libiconv.so.2,把/usr/local/lib加到路徑中也不行。
google了一下,解決了:在/etc/ld.so.conf中加一行/usr/local/lib,運行ldconfig。再運行a.out,行了。
ld.so.conf和ldconfig是維護系統動態鏈接庫的。真不明白為什么iconv庫安裝時不把這一步也做了。



//注意
如果你不是root,ldconfig也運行不了的,解決的方法就是,設置環境變量 LDFLAGS=-L/usr/local/lib

posted @ 2009-09-24 12:46 不會飛的鳥 閱讀(493) | 評論 (0)編輯 收藏

例解 autoconf 和 automake 生成 Makefile 文件

本文介紹了在 linux 系統中,通過 Gnu autoconf 和 automake 生成 Makefile 的方法。主要探討了生成 Makefile 的來龍去脈及其機理,接著詳細介紹了配置 Configure.in 的方法及其規則。

引子

無論是在Linux還是在Unix環境中,make都是一個非常重要的編譯命令。不管是自己進行項目開發還是安裝應用軟件,我們都經常要用到make或 make install。利用make工具,我們可以將大型的開發項目分解成為多個更易于管理的模塊,對于一個包括幾百個源文件的應用程序,使用make和 makefile工具就可以輕而易舉的理順各個源文件之間紛繁復雜的相互關系。

但是如果通過查閱make的幫助文檔來手工編寫Makefile,對任何程序員都是一場挑戰。幸而有GNU 提供的Autoconf及Automake這兩套工具使得編寫makefile不再是一個難題。

本文將介紹如何利用 GNU Autoconf 及 Automake 這兩套工具來協助我們自動產生 Makefile文件,并且讓開發出來的軟件可以像大多數源碼包那樣,只需"./configure", "make","make install" 就可以把程序安裝到系統中。





回頁首


模擬需求

假設源文件按如下目錄存放,如圖1所示,運用autoconf和automake生成makefile文件。


圖 1文件目錄結構
圖 1文件目錄結構

假設src是我們源文件目錄,include目錄存放其他庫的頭文件,lib目錄存放用到的庫文件,然后開始按模塊存放,每個模塊都有一個對應的目錄,模塊下再分子模塊,如apple、orange。每個子目錄下又分core,include,shell三個目錄,其中core和shell目錄存放.c文件,include的存放.h文件,其他類似。

樣例程序功能:基于多線程的數據讀寫保護(聯系作者獲取整個autoconf和automake生成的Makefile工程和源碼,E-mail:normalnotebook@126.com)。





回頁首


工具簡介

所必須的軟件:autoconf/automake/m4/perl/libtool(其中libtool非必須)。

autoconf是一個用于生成可以自動地配置軟件源碼包,用以適應多種UNIX類系統的shell腳本工具,其中autoconf需要用到 m4,便于生成腳本。automake是一個從Makefile.am文件自動生成Makefile.in的工具。為了生成Makefile.in,automake還需用到perl,由于automake創建的發布完全遵循GNU標準,所以在創建中不需要perl。libtool是一款方便生成各種程序庫的工具。

目前automake支持三種目錄層次:flat、shallow和deep。

1) flat指的是所有文件都位于同一個目錄中。

就是所有源文件、頭文件以及其他庫文件都位于當前目錄中,且沒有子目錄。Termutils就是這一類。

2) shallow指的是主要的源代碼都儲存在頂層目錄,其他各個部分則儲存在子目錄中。

就是主要源文件在當前目錄中,而其它一些實現各部分功能的源文件位于各自不同的目錄。automake本身就是這一類。

3) deep指的是所有源代碼都被儲存在子目錄中;頂層目錄主要包含配置信息。

就是所有源文件及自己寫的頭文件位于當前目錄的一個子目錄中,而當前目錄里沒有任何源文件。 GNU cpio和GNU tar就是這一類。

flat類型是最簡單的,deep類型是最復雜的。不難看出,我們的模擬需求正是基于第三類deep型,也就是說我們要做挑戰性的事情:)。注:我們的測試程序是基于多線程的簡單程序。





回頁首


生成 Makefile 的來龍去脈

首先進入 project 目錄,在該目錄下運行一系列命令,創建和修改幾個文件,就可以生成符合該平臺的Makefile文件,操作過程如下:

1) 運行autoscan命令

2) 將configure.scan 文件重命名為configure.in,并修改configure.in文件

3) 在project目錄下新建Makefile.am文件,并在core和shell目錄下也新建makefile.am文件

4) 在project目錄下新建NEWS、 README、 ChangeLog 、AUTHORS文件

5) 將/usr/share/automake-1.X/目錄下的depcomp和complie文件拷貝到本目錄下

6) 運行aclocal命令

7) 運行autoconf命令

8) 運行automake -a命令

9) 運行./confiugre腳本

可以通過圖2看出產生Makefile的流程,如圖所示:


圖 2生成Makefile流程圖
圖 2生成Makefile流程圖




回頁首


Configure.in的八股文

當我們利用autoscan工具生成confiugre.scan文件時,我們需要將confiugre.scan重命名為confiugre.in文件。confiugre.in調用一系列autoconf宏來測試程序需要的或用到的特性是否存在,以及這些特性的功能。

下面我們就來目睹一下confiugre.scan的廬山真面目:


# Process this file with autoconf to produce a configure script.
            AC_PREREQ(2.59)
            AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
            AC_CONFIG_SRCDIR([config.h.in])
            AC_CONFIG_HEADER([config.h])
            # Checks for programs.
            AC_PROG_CC
            # Checks for libraries.
            # FIXME: Replace `main' with a function in `-lpthread':
            AC_CHECK_LIB([pthread], [main])
            # Checks for header files.
            # Checks for typedefs, structures, and compiler characteristics.
            # Checks for library functions.
            AC_OUTPUT
            

每個configure.scan文件都是以AC_INIT開頭,以AC_OUTPUT結束。我們不難從文件中看出confiugre.in文件的一般布局:


AC_INIT
            測試程序
            測試函數庫
            測試頭文件
            測試類型定義
            測試結構
            測試編譯器特性
            測試庫函數
            測試系統調用
            AC_OUTPUT
            

上面的調用次序只是建議性質的,但我們還是強烈建議不要隨意改變對宏調用的次序。

現在就開始修改該文件:


$mv configure.scan configure.in
            $vim configure.in
            

修改后的結果如下:


            #                                -*- Autoconf -*-
            # Process this file with autoconf to produce a configure script.
            AC_PREREQ(2.59)
            AC_INIT(test, 1.0, normalnotebook@126.com)
            AC_CONFIG_SRCDIR([src/ModuleA/apple/core/test.c])
            AM_CONFIG_HEADER(config.h)
            AM_INIT_AUTOMAKE(test,1.0)
            # Checks for programs.
            AC_PROG_CC
            # Checks for libraries.
            # FIXME: Replace `main' with a function in `-lpthread':
            AC_CHECK_LIB([pthread], [pthread_rwlock_init])
            AC_PROG_RANLIB
            # Checks for header files.
            # Checks for typedefs, structures, and compiler characteristics.
            # Checks for library functions.
            AC_OUTPUT([Makefile
            src/lib/Makefile
            src/ModuleA/apple/core/Makefile
            src/ModuleA/apple/shell/Makefile
            ])
            

其中要將AC_CONFIG_HEADER([config.h])修改為:AM_CONFIG_HEADER(config.h), 并加入AM_INIT_AUTOMAKE(test,1.0)。由于我們的測試程序是基于多線程的程序,所以要加入AC_PROG_RANLIB,不然運行automake命令時會出錯。在AC_OUTPUT輸入要創建的Makefile文件名。

由于我們在程序中使用了讀寫鎖,所以需要對庫文件進行檢查,即AC_CHECK_LIB([pthread], [main]),該宏的含義如下:



其中,LIBS是link的一個選項,詳細請參看后續的Makefile文件。由于我們在程序中使用了讀寫鎖,所以我們測試pthread庫中是否存在pthread_rwlock_init函數。

由于我們是基于deep類型來創建makefile文件,所以我們需要在四處創建Makefile文件。即:project目錄下,lib目錄下,core和shell目錄下。

Autoconf提供了很多內置宏來做相關的檢測,限于篇幅關系,我們在這里對其他宏不做詳細的解釋,具體請參看參考文獻1和參考文獻2,也可參看autoconf信息頁。





回頁首


實戰Makefile.am

Makefile.am是一種比Makefile更高層次的規則。只需指定要生成什么目標,它由什么源文件生成,要安裝到什么目錄等構成。

表一列出了可執行文件、靜態庫、頭文件和數據文件,四種書寫Makefile.am文件個一般格式。


表 1Makefile.am一般格式
表 1Makefile.am一般格式

對于可執行文件和靜態庫類型,如果只想編譯,不想安裝到系統中,可以用noinst_PROGRAMS代替bin_PROGRAMS,noinst_LIBRARIES代替lib_LIBRARIES。

Makefile.am還提供了一些全局變量供所有的目標體使用:


表 2 Makefile.am中可用的全局變量
表 2 Makefile.am中可用的全局變量

在Makefile.am中盡量使用相對路徑,系統預定義了兩個基本路徑:


表 3Makefile.am中可用的路徑變量
表 3Makefile.am中可用的路徑變量

在上文中我們提到過安裝路徑,automake設置了默認的安裝路徑:

1) 標準安裝路徑

默認安裝路徑為:$(prefix) = /usr/local,可以通過./configure --prefix=<new_path>的方法來覆蓋。

其它的預定義目錄還包括:bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc等等。

2) 定義一個新的安裝路徑

比如test, 可定義testdir = $(prefix)/test, 然后test_DATA =test1 test2,則test1,test2會作為數據文件安裝到$(prefix)/ /test目錄下。

我們首先需要在工程頂層目錄下(即project/)創建一個Makefile.am來指明包含的子目錄:


SUBDIRS=src/lib src/ModuleA/apple/shell src/ModuleA/apple/core
            CURRENTPATH=$(shell /bin/pwd)
            INCLUDES=-I$(CURRENTPATH)/src/include -I$(CURRENTPATH)/src/ModuleA/apple/include
            export INCLUDES
            

由于每個源文件都會用到相同的頭文件,所以我們在最頂層的Makefile.am中包含了編譯源文件時所用到的頭文件,并導出,見藍色部分代碼。

我們將lib目錄下的swap.c文件編譯成libswap.a文件,被apple/shell/apple.c文件調用,那么lib目錄下的Makefile.am如下所示:


noinst_LIBRARIES=libswap.a
            libswap_a_SOURCES=swap.c
            INCLUDES=-I$(top_srcdir)/src/includ
            

細心的讀者可能就會問:怎么表1中給出的是bin_LIBRARIES,而這里是noinst_LIBRARIES?這是因為如果只想編譯,而不想安裝到系統中,就用noinst_LIBRARIES代替bin_LIBRARIES,對于可執行文件就用noinst_PROGRAMS代替bin_PROGRAMS。對于安裝的情況,庫將會安裝到$(prefix)/lib目錄下,可執行文件將會安裝到${prefix}/bin。如果想安裝該庫,則Makefile.am示例如下:


bin_LIBRARIES=libswap.a
            libswap_a_SOURCES=swap.c
            INCLUDES=-I$(top_srcdir)/src/include
            swapincludedir=$(includedir)/swap
            swapinclude_HEADERS=$(top_srcdir)/src/include/swap.h
            

最后兩行的意思是將swap.h安裝到${prefix}/include /swap目錄下。

接下來,對于可執行文件類型的情況,我們將討論如何寫Makefile.am?對于編譯apple/core目錄下的文件,我們寫成的Makefile.am如下所示:


noinst_PROGRAMS=test
            test_SOURCES=test.c
            test_LDADD=$(top_srcdir)/src/ModuleA/apple/shell/apple.o $(top_srcdir)/src/lib/libswap.a
            test_LDFLAGS=-D_GNU_SOURCE
            DEFS+=-D_GNU_SOURCE
            #LIBS=-lpthread
            

由于我們的test.c文件在鏈接時,需要apple.o和libswap.a文件,所以我們需要在test_LDADD中包含這兩個文件。對于Linux下的信號量/讀寫鎖文件進行編譯,需要在編譯選項中指明-D_GNU_SOURCE。所以在test_LDFLAGS中指明。而test_LDFLAGS只是鏈接時的選項,編譯時同樣需要指明該選項,所以需要DEFS來指明編譯選項,由于DEFS已經有初始值,所以這里用+=的形式指明。從這里可以看出,Makefile.am中的語法與Makefile的語法一致,也可以采用條件表達式。如果你的程序還包含其他的庫,除了用AC_CHECK_LIB宏來指明外,還可以用LIBS來指明。

如果你只想編譯某一個文件,那么Makefile.am如何寫呢?這個文件也很簡單,寫法跟可執行文件的差不多,如下例所示:


noinst_PROGRAMS=apple
            apple_SOURCES=apple.c
            DEFS+=-D_GNU_SOURCE
            

我們這里只是欺騙automake,假裝要生成apple文件,讓它為我們生成依賴關系和執行命令。所以當你運行完automake命令后,然后修改apple/shell/下的Makefile.in文件,直接將LINK語句刪除,即:


…….
            clean-noinstPROGRAMS:
            -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
            apple$(EXEEXT): $(apple_OBJECTS) $(apple_DEPENDENCIES)
            @rm -f apple$(EXEEXT)
            #$(LINK) $(apple_LDFLAGS) $(apple_OBJECTS) $(apple_LDADD) $(LIBS)
            …….
            

通過上述處理,就可以達到我們的目的。從圖1中不難看出為什么要修改Makefile.in的原因,而不是修改其他的文件。

posted @ 2009-06-21 16:25 不會飛的鳥 閱讀(243) | 評論 (0)編輯 收藏

實戰Makefile.am

實戰Makefile.am

Makefile.am是一種比Makefile更高層次的規則。只需指定要生成什么目標,它由什么源文件生成,要安裝到什么目錄等構成。

表一列出了可執行文件、靜態庫、頭文件和數據文件,四種書寫Makefile.am文件個一般格式。


表 1Makefile.am一般格式


 

對于可執行文件和靜態庫類型,如果只想編譯,不想安裝到系統中,可以用noinst_PROGRAMS代替bin_PROGRAMS,noinst_LIBRARIES代替lib_LIBRARIES。

Makefile.am還提供了一些全局變量供所有的目標體使用:

表 2 Makefile.am中可用的全局變量

在Makefile.am中盡量使用相對路徑,系統預定義了兩個基本路徑:

表 3Makefile.am中可用的路徑變量

在上文中我們提到過安裝路徑,automake設置了默認的安裝路徑:

1)標準安裝路徑

默認安裝路徑為:$(prefix) = /usr/local,可以通過./configure --prefix=<new_path>的方法來覆蓋。

其它的預定義目錄還包括:bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc等等。

2) 定義一個新的安裝路徑

比如test, 可定義testdir = $(prefix)/test, 然后test_DATA =test1 test2,則test1,test2會作為數據文件安裝到$(prefix)/ /test目錄下。

我們首先需要在工程頂層目錄下(即project/)創建一個Makefile.am來指明包含的子目錄:

SUBDIRS=src/lib src/ModuleA/apple/shell src/ModuleA/apple/core

CURRENTPATH=$(shell /bin/pwd)

INCLUDES=-I$(CURRENTPATH)/src/include -I$(CURRENTPATH)/src/ModuleA/apple/include

export INCLUDES

由于每個源文件都會用到相同的頭文件,所以我們在最頂層的Makefile.am中包含了編譯源文件時所用到的頭文件,并導出,見藍色部分代碼。

我們將lib目錄下的swap.c文件編譯成libswap.a文件,被apple/shell/apple.c文件調用,那么lib目錄下的Makefile.am如下所示:

noinst_LIBRARIES=libswap.a

libswap_a_SOURCES=swap.c

INCLUDES=-I$(top_srcdir)/src/includ

細心的讀者可能就會問:怎么表1中給出的是bin_LIBRARIES,而這里是noinst_LIBRARIES?這是因為如果只想編譯,而不想安裝到系統中,就用noinst_LIBRARIES代替bin_LIBRARIES,對于可執行文件就用noinst_PROGRAMS代替bin_PROGRAMS。對于安裝的情況,庫將會安裝到$(prefix)/lib目錄下,可執行文件將會安裝到${prefix}/bin。如果想安裝該庫,則Makefile.am示例如下:

bin_LIBRARIES=libswap.a

libswap_a_SOURCES=swap.c

INCLUDES=-I$(top_srcdir)/src/include

swapincludedir=$(includedir)/swap

swapinclude_HEADERS=$(top_srcdir)/src/include/swap.h

最后兩行的意思是將swap.h安裝到${prefix}/include /swap目錄下。

接下來,對于可執行文件類型的情況,我們將討論如何寫Makefile.am?對于編譯apple/core目錄下的文件,我們寫成的Makefile.am如下所示:

noinst_PROGRAMS=test

test_SOURCES=test.c

test_LDADD=$(top_srcdir)/src/ModuleA/apple/shell/apple.o $(top_srcdir)/src/lib/libswap.a

test_LDFLAGS=-D_GNU_SOURCE

DEFS+=-D_GNU_SOURCE

#LIBS=-lpthread

由于我們的test.c文件在鏈接時,需要apple.o和libswap.a文件,所以我們需要在test_LDADD中包含這兩個文件。對于Linux下的信號量/讀寫鎖文件進行編譯,需要在編譯選項中指明-D_GNU_SOURCE。所以在test_LDFLAGS中指明。而test_LDFLAGS只是鏈接時的選項,編譯時同樣需要指明該選項,所以需要DEFS來指明編譯選項,由于DEFS已經有初始值,所以這里用+=的形式指明。從這里可以看出,Makefile.am中的語法與Makefile的語法一致,也可以采用條件表達式。如果你的程序還包含其他的庫,除了用AC_CHECK_LIB宏來指明外,還可以用LIBS來指明。

如果你只想編譯某一個文件,那么Makefile.am如何寫呢?這個文件也很簡單,寫法跟可執行文件的差不多,如下例所示:

noinst_PROGRAMS=apple

apple_SOURCES=apple.c

DEFS+=-D_GNU_SOURCE

我們這里只是欺騙automake,假裝要生成apple文件,讓它為我們生成依賴關系和執行命令。所以當你運行完automake命令后,然后修改apple/shell/下的Makefile.in文件,直接將LINK語句刪除,即:

…….

clean-noinstPROGRAMS:

    -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)

apple$(EXEEXT): $(apple_OBJECTS) $(apple_DEPENDENCIES)

    @rm -f apple$(EXEEXT)

#$(LINK) $(apple_LDFLAGS) $(apple_OBJECTS) $(apple_LDADD) $(LIBS)

…….

posted @ 2009-06-21 16:19 不會飛的鳥 閱讀(897) | 評論 (0)編輯 收藏

帶你輕松接觸PowerDesigner中的反向工程

Power Designer是Sybase公司的CASE工具集,使用它可以方便地對管理信息系統進行分析設計,它幾乎包括了數據庫模型設計的全過程。利用Power Designer可以制作數據流程圖、概念數據模型、物理數據模型,可以生成多種客戶端開發工具的應用程序,還可為數據倉庫制作結構模型,也能對團隊設計模型進行控制。

Power Designer的4種模型:概念數據模型 (CDM)物理數據模型 (PDM) 面向對象模型 (OOM) 業務程序模型 (BPM) 我主要介紹一下PDM。

PDM 敘述數據庫的物理實現,幫助你考慮真實的物理實現的細節。你能通過修正PDM來適合你的表現或物理約束。主要目的是把CDM中建立的現實世界模型生成特定的DBMS腳本,產生數據庫中保存信息的儲存結構,保證數據在數據庫中的完整性和一致性。

PDM是適合于系統設計階段的工具。簡單說:就是PDM可以自動生成諸如''create table''之類的sql腳本.在數據建模過程中,我們建立概念數據模型,通過正向工程生成物理數據模型,生成數據庫建庫腳本,最后將物理數據模型生成關系數據庫。

系統數據庫設計人員希望能夠將數據庫設計和關系數據庫生成無縫地集成起來,如何保證物理數據模型與其對應數據庫之間的雙向同步成為數據建模非常關鍵的一點。

Powerdesigner作為強大的Case工具,為我們提供了方便的逆向工程特性。可以將目前所有流行的后端數據庫(包括Sybase、DB2、Oracle等)的結構信息通過逆向工程加入到PowerDesigner的物理數據模型和概念數據模型中,包括表、索引、觸發器、視圖等。

用PowerDesigner進行逆向工程

◆1.我用的數據庫是oracle9i,我為了訪問oracle數據庫,在我的機器上安裝了oracle客戶端(提供了oracle客戶端的驅動程序,而精簡客戶端則不可以),配置一個名稱為mylcl的服務:MYLCL = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.3.106)(PORT = 1521)) ) (CONNECT_DATA = (SID = pwsc) ) )用戶名為:testuser,密碼為test。

◆2.在pd中,新建一個pdm,選擇數據庫為oracle9i。

◆3.選擇Database->configure connections,轉到system dsn標簽,點擊"添加",選擇驅動程序,由于我的數據庫是oracle,所以我選擇"oracle in oraclient10g_home1"(安裝了oracle客戶端才有這個驅動,而精簡客戶端沒有此驅動)。

◆4.在data source name 中,可以隨便命名一個"ora-test",在tns-server name中選擇第一步中的服務名稱:mylcl.點擊"test connection",輸入用戶名密碼,connection ok!

◆5.點擊database->reverse engineer database ,選擇odbc datasource:ora-test.然后點擊確定。(責任編輯:盧兆林)

posted @ 2009-05-28 06:44 不會飛的鳥 閱讀(927) | 評論 (0)編輯 收藏

linux c 一個autotools的最簡單例子

     摘要:   1、準備:        需要工具autoscan aclocal autoheader automake autoconf make 等工具.  2、測試程序編寫:         &...  閱讀全文

posted @ 2009-05-14 17:31 不會飛的鳥 閱讀(2040) | 評論 (1)編輯 收藏

游戲引擎基礎(一)(渲染和構造3D世界)

     摘要:  本系列轉自:http://www.shnenglu.com/orlando/archive/2007/12/03/37734.html 謝謝作者有這么好的文章與大家共享!代表所有有幸閱讀到次書的讀者謝謝先!第1部分: 游戲引擎介紹, 渲染和構造3D世界介紹  自Doom游戲時代以來我們已經走了很遠。 DOOM不只是一款偉大的游戲,它同時也開創了一種新的游戲編程模式: 游戲 "引...  閱讀全文

夢在天涯 2007-12-04 13:14 發表評論

posted @ 2009-04-10 10:44 不會飛的鳥 閱讀(128) | 評論 (0)編輯 收藏

游戲引擎基礎(二)(3D環境的光照和紋理)

2部份: 3D環境的光照和紋理


世界的燈光
  在變換過程中, 通常是在稱為觀察空間的坐標空間中, 我們遇到了最重要的運算之一: 光照計算。 它是一種這樣的事情, 當它工作時,你不關注它,但當它不工作時, 你就非常關注它了。有很多不同的光照方法,從簡單的計算多邊形對于燈光的朝向,并根據燈光到多邊形的方向和距離加上燈光顏色的百分比值,一直到產生邊緣平滑的燈光貼圖疊加基本紋理。而且一些 API 實際上提供預先建造的光照方法。舉例來說,OpenGL 提供了每多邊形,每頂點,和每像素的光照計算。

  在頂點光照中,你要決定一個頂點被多少個多邊形共享,并計算出共享該頂點的所有多邊形法向量的均值(稱為法向量),并將該法向量賦頂點。一個給定多邊形的每個頂點會有不同的法向量,所以你需要漸變或插值多邊形頂點的光照顏色以便得到平滑的光照效果。 你沒有必要用這種光照方式查看每個單獨的多邊形。 這種方式的優點是時常可以使用硬件轉換與光照(T & L)來幫助快速完成。 不足之處是它不能產生陰影。 舉例來說,即使燈光是在模型的右側,左手臂應該在被身體投影的陰影中,而實際上模型的雙臂卻以同樣的方式被照明了。

  這些簡單的方法使用著色來達到它們的目標。 當用平面光照繪制一個多邊形時, 你讓渲染(繪制)引擎把整個多邊形都著上一種指定的顏色。這叫做平面著色光照。 (該方法中,多邊形均對應一個光強度,表面上所有點都用相同的強度值顯示,渲染繪制時得到一種平面效果,多邊形的邊緣不能精確的顯示出來)

  對于頂點著色 ( Gouraud 著色) ,你讓渲染引擎給每個頂點賦予特定的顏色。 在繪制多邊形上各點投影所對應的像素時,根據它們與各頂點的距離,對這些頂點的顏色進行插值計算。 (實際上Quake III 模型使用的就是這種方法, 效果好的令人驚奇)

  還有就是 Phong 著色。如同 Gouraud 著色,通過紋理工作,但不對每個頂點顏色進行插值決定像素顏色值, 它對每個頂點的法向量進行插值,會為每個頂點投影的像素做相同的工作。對于 Gouraud 著色,你需要知道哪些光投射在每個頂點上。對于 Phong 著色,你對每個像素也要知道這么多。

  一點也不令人驚訝, Phong 著色可以得到更加平滑的效果,因為每個像素都需要進行光照計算,其繪制非常耗費時間。平面光照處理方法很快速, 但比較粗糙。Phong 著色比 Gouraud 著色計算更昂貴,但效果最好,可以達到鏡面高光效果("高亮") 這些都需要你在游戲開發中折衷權衡。


不同的燈光
  接著是生成照明映射,你用第二個紋理映射(照明映射)與已有的紋理混合來產生照明效果。這樣工作得很好, 但這本質上是在渲染之前預先生成的一種罐裝效果。如果你使用動態照明 (即,燈光移動, 或者沒有程序的干預而打開和關閉),你得必須在每一幀重新生成照明映射,按照動態燈光的運動方式修改這些照明映射。燈光映射能夠快速的渲染,但對存儲這些燈光紋理所需的內存消耗非常昂貴。你可以使用一些壓縮技巧使它們占用較少的的內存空間,或減少其尺寸大小, 甚至使它們是單色的 (這樣做就不會有彩色燈光了),等等。 如果你確實在場景中有多個動態燈光, 重新生成照明映射將以昂貴的CPU周期而告終。

  許多游戲通常使用某種混合照明方式。 Quake III為例,場景使用照明映射, 動畫模型使用頂點照明。 預先處理的燈光不會對動畫模型產生正確的效果 -- 整個多邊形模型得到燈光的全部光照值 -- 而動態照明將被用來產生正確的效果。 使用混合照明方式是多數的人們沒有注意到的一個折衷,它通常讓效果看起來"正確" 這就是游戲的全部做一切必要的工作讓效果看起來"正確",但不必真的是正確的。

  當然,所有這些在新的Doom引擎里面都不復存在了,但要看到所有的效果,至少需要 1GHZ CPU GeForce 2 顯卡。是進步了,但一切都是有代價的。

  一旦場景經過轉換和照明, 我們就進行裁剪運算。 不進入血淋淋的細節而,剪斷運算決定哪些三角形完全在場景 (被稱為觀察平截頭體) 之內或部份地在場景之內。完全在場景之內的三角形被稱為細節接受,它們被處理。對于只是部分在場景之內的三角形, 位于平截頭體外面的部分將被裁剪掉,余下位于平截頭體內部的多邊形部分將需要重新閉合,以便其完全位于可見場景之內。 (更多的細節請參考我們的 3D 流水線指導一文)

  場景經過裁剪以后,流水線中的下一個階段就是三角形生成階段(也叫做掃描 線轉換),場景被映射到2D 屏幕坐標。到這里,就是渲染(繪制)運算了。


紋理與MIP映射
  紋理在使3D場景看起來真實方面異常重要,它們是你應用到場景區域或對象的一些分解成多邊形的小圖片。多重紋理耗費大量的內存,有不同的技術來幫助管理它們的尺寸大小。紋理壓縮是在保持圖片信息的情況下,讓紋理數據更小的一種方法。紋理壓縮占用較少的游戲CD空間,更重要的是,占用較少內存和3D 顯卡存儲空間。另外,在你第一次要求顯卡顯示紋理的時候,壓縮的(較小的) 版本經過 AGP 接口從 PC 主存送到3D 顯卡, 會更快一些。紋理壓縮是件好事情。 在下面我們將會更多的討論紋理壓縮。


MIP
映射(多紋理映射)
  游戲引擎用來減少紋理內存和帶寬需求的另外一個技術就是 MIP 映射。 MIP 映射技術通過預先處理紋理,產生它的多個拷貝紋理,每個相繼的拷貝是上一個拷貝的一半大小。為什么要這樣做?要回答這個問題,你需要了解 3D 顯卡是如何顯示紋理的。最壞情況,你選擇一個紋理,貼到一個多邊形上,然后輸出到屏幕。我們說這是一對一的關系,最初紋理映射圖的一個紋素 (紋理元素) 對應到紋理映射對象多邊形的一個像素。如果你顯示的多邊形被縮小一半,紋理的紋素就每間隔一個被顯示。這樣通常沒有什么問題 -- 但在某些情況下會導致一些視覺上的怪異現象。讓我們看看磚塊墻壁。 假設最初的紋理是一面磚墻,有許多磚塊,磚塊之間的泥漿寬度只有一個像素。如果你把多邊形縮小一半, 紋素只是每間隔一個被應用,這時候,所有的泥漿會突然消失,因為它們被縮掉了。你只會看到一些奇怪的圖像。

  使用 MIP 映射,你可以在顯示卡應用紋理之前,自己縮放圖像,因為可以預先處理紋理,你做得更好一些,讓泥漿不被縮掉。當 3D 顯卡用紋理繪制多邊形時,它檢測到縮放因子,說,"你知道,我要使用小一些的紋理,而不是縮小最大的紋理,這樣看起來會更好一些。" 在這里, MIP 映射為了一切,一切也為了 MIP 映射。


多重紋理與凹凸映射
  單一紋理映射給整個3D 真實感圖形帶來很大的不同, 但使用多重紋理甚至可以達到一些更加令人難忘的效果。過去這一直需要多遍渲染(繪制),嚴重影響了像素填充率。 但許多具有多流水線的3D 加速卡,如ATI's Radeon nVidia's GeForce 2及更高級的顯卡,多重紋理可以在一遍渲染(繪制)過程中完成。 產生多重紋理效果時, 你先用一個紋理繪制多邊形,然后再用另外一個紋理透明地繪制在多邊形上面。這讓你可以使紋理看上去在移動,或脈動, 甚至產生陰影效果 (我們在照明一節中描述過)。繪制第一個紋理映射,然后在上面繪制帶透明的全黑紋理,引起一種是所有的織法黑色的但是有一個透明分層堆積過它的頂端 這就是 -- 即時陰影。 該技術被稱為照明映射 ( 有時也稱為 暗映射),直至新的Doom ,一直是Id引擎里關卡照明的傳統方法。

  凹凸貼圖是最近涌現出來的一種古老技術。幾年以前 Matrox 第一個在流行的 3D 游戲中發起使用各種不同形式的凹凸貼圖。就是生成紋理來表現燈光在表面的投射,表現表面的凹凸或表面的裂縫。 凹凸貼圖并不隨著燈光一起移動 -- 它被設計用來表現一個表面上的細小瑕疵,而不是大的凹凸。 比如說,在飛行模擬器中,你可以使用凹凸貼圖來產生像是隨機的地表細節,而不是重復地使用相同的紋理,看上去一點趣味也沒有。

  凹凸貼圖產生相當明顯的表面細節,盡管是很高明的戲法,但嚴格意義上講,凹凸貼圖并不隨著你的觀察角度而變化。比較新的 ATI nVidia 顯卡片能執行每像素運算,這種缺省觀察角度的不足就真的不再是有力而快速的法則了。 無論是哪一種方法, 到目前為止,沒有游戲開發者太多的使用; 更多的游戲能夠且應該使用凹凸貼圖。


高速緩存抖動 = 糟糕的事物
  紋理高速緩存的管理游戲引擎的速度至關重要。 和任何高速緩存一樣,緩存命中很好,而不命中將很糟糕。如果遇到紋理在圖形顯示卡內存被頻繁地換入換出的情況,這就是紋理高速緩存抖動。發生這種情況時,通常API將會廢棄每個紋理,結果是所有的紋理在下一幀將被重新加載,這非常耗時和浪費。對游戲玩家來說,當API重新加載紋理高速緩存時,會導致幀速率遲鈍。

  在紋理高速緩存管理中,有各種不同的技術將紋理高速緩存抖動減到最少這是確保任何 3D 游戲引擎速度的一個決定性因素。 紋理管理是件好事情這意味著只要求顯卡使用紋理一次,而不是重復使用。這聽起來有點自相矛盾,但效果是它意謂著對顯卡說,"看, 所有這些多邊形全部使用這一個紋理,我們能夠僅僅加載這個紋理一次而不是許多次嗎?" 這阻止API ( 或圖形驅動軟件) 上傳多次向顯卡加載紋理。象OpenGL這樣的API實際上通常處理紋理高速緩存管理,意謂著,根據一些規則,比如紋理存取的頻率,API決定哪些紋理儲存在顯卡上,哪些紋理存儲在主存。 真正的問題來了:a) 你時常無法知道API正在使用的準確規則。 b)你時常要求在一幀中繪制更多的紋理,以致超出了顯卡內存空間所能容納的紋理。

  另外一種紋理高速緩存管理技術是我們早先討論的紋理壓縮。很象聲音波形文件被壓縮成 MP3 文件,盡管無法達到那樣的壓縮比率,但紋理可以被壓縮。 從聲音波形文件到MP3的壓縮可以達到 11:1的壓縮比率,而絕大多數硬件支持的紋理壓縮運算法則只有 4:1 的壓縮比率,盡管如此,這樣能產生很大的差別。 除此之外,在渲染(繪制)過程中,只有在需要時,硬件才動態地對紋理進行解壓縮。這一點非常棒,我們僅僅擦除即將可能用到的表面。

  如上所述,另外一種技術確保渲染器要求顯卡對每個紋理只繪制一次。確定你想要渲染(繪制)的使用相同紋理的所有多邊形同時送到顯卡,而不是一個模型在這里,另一個模型在那里,然后又回到最初的紋理論。僅僅繪制一次,你也就通過AGP接口傳送一次。Quake III 在其陰影系統就是這么做的。處理多邊形時,把它們加入到一個內部的陰影列表,一旦所有的多邊形處理完畢,渲染器遍歷紋理列表,就將紋理及所有使用這些紋理的多邊形同時傳送出去。

  上述過程在使用顯卡的硬件 T & L(如果支持的話)時,并不怎么有效。你面臨的結局是,滿屏幕都是使用相同紋理的大量的多邊形小群組,所有多邊形都使用不同的變換矩陣。這意謂著更多的時間花在建立顯卡的硬件 T & L 引擎 ,更多的時間被浪費了。 無論如何,因為他們有助于對整個模型使用統一的紋理,所以它對實際屏幕上的模型可以有效地工作。但是因為許多多邊形傾向使用相同的墻壁紋理,所以對于世界場景的渲染,它常常就是地獄。通常它沒有這么嚴重,因為大體而言,世界的紋理不會有那么大,這樣一來API的紋理緩存系統將會替你處理這些,并把紋理保留在顯卡以備再次使用。

  在游戲機上,通常沒有紋理高速緩存系統(除非你寫一個)。在 PS2 上面,你最好是遠離"一次紋理" 的方法。在 Xbox 上面, 這是不重要的,因為它本身沒有圖形內存(它是 UMA 體系結構),且所有的紋理無論如何始終保留在主存之中。

  事實上,在今天的現代PC FPS 游戲中,試圖通過AGP接口傳送大量紋理是第二個最通常的瓶頸。最大的瓶頸是實際幾何處理,它要使東西出現在它應該出現的地方。在如今的3D FPS 游戲中,最耗費時間的工作,顯然是那些計算模型中每個頂點正確的世界位置的數學運算。如果你不把場景的紋理保持在預算之內,僅居其次的就是通過AGP接口傳送大量的紋理了。然而,你確實有能力影響這些。 通過降低頂層的 MIP 級別(還記得系統在哪里不斷地為你細分紋理嗎?) 你就能夠把系統正在嘗試送到顯卡的紋理大小減少一半。你的視覺質量會有所下降-- 尤其是在引人注目的電影片斷中--但是你的幀速率上升了。這種方式對網絡游戲尤其有幫助。實際上,Soldier of Fortune IIJedi Knight II: Outcast這兩款游戲在設計時針對的顯卡還不是市場上的大眾主流顯卡。為了以最大大小觀看他們的紋理,你的3D 顯卡至少需要有128MB的內存。這兩種產品在思想上都是給未來設計的。

  上面就是第 2 部份。在下面章節中,我們將介紹許多主題,包括內存管理,霧效果,深度測試, 抗鋸齒,頂點著色,API等。



夢在天涯 2007-12-04 13:16 發表評論

posted @ 2009-04-10 10:44 不會飛的鳥 閱讀(222) | 評論 (0)編輯 收藏

游戲引擎基礎(三)(內存使用,特效和API)

3部份: 內存使用,特效和API


關于內存使用的思考
  讓我們想一想,在今天實際上是如何使用3D 顯卡內存的以及在將來又會如何使用。 如今絕大多數3D顯卡處理32位像素顏色,8位紅色, 8位藍色,8 位綠色,和 8 位透明度。這些組合的紅,藍和綠256個色度,可以組成 167 百萬種顏色-- 那是你我可以在一個監視器上看見的所有顏色。

  那么,游戲設計大師John Carmack 為什么要求 64 位顏色分辨率呢? 如果我們看不出區別,又有什么意義呢? 意義是: 比如說, 有十幾個燈光照射模型上的點,顏色顏色各不相同。 我們取模型的最初顏色,然后計算一個燈光的照射,模型顏色值將改變。 然后我們計算另外的一個燈光, 模型顏色值進一步改變。 這里的問題是,因為顏色值只有8位,在計算了4個燈光之后,8位的顏色值將不足以給我們最后的顏色較好的分辨率和表現。分辨率的不足是由量化誤差導致的,本質原因是由于位數不足引起的舍入誤差。

  你能很快地用盡位數,而且同樣地,所有的顏色被清掉。每顏色16 32 位,你有一個更高分辨率,因此你能夠反復著色以適當地表現最后的顏色。這樣的顏色深度很快就能消耗大量的存儲空間。我們也應提到整個顯卡內存與紋理內存。這里所要說的是,每個3D 顯卡實際只有有限的內存,而這些內存要存儲前端和后端緩沖區,Z 緩沖區,還有所有的令人驚奇的紋理。最初的 Voodoo1 顯卡只有2MB顯存,后來 Riva TNT提高到16MB顯存。然后 GeForce ATI Rage32MB顯存, 現在一些 GeForce 2 4的顯卡和 Radeons 帶有 64MB 128MB 的顯存。 這為什么重要? 好吧,讓我們看一些數字

  比如你想讓你的游戲看起來最好,所以你想要讓它以32位屏幕, 1280x1024分辨率和32 Z- 緩沖跑起來。 好,屏幕上每個像素4個字節,外加每個像素4字節的Z-緩沖,因為都是每像素32位。我們有1280x1024 個像素也就是 1310720個像素。基于前端緩沖區和Z-緩沖區的字節數,這個數字乘以8,是 10485760字節。包括一個后端緩沖區,這樣是 1280x1024x12 也就是 15728640 字節, 15MB 在一個 16MB 顯存的顯卡上,就只給我們剩下1MB 來存儲所有的紋理。 現在如果最初的紋理是真32 位或 4字節寬,那么我們每幀能在顯卡上存儲 1MB/4字節每像素 = 262144個像素。這大約是4 256x256 的紋理頁面。

  很清楚,上述例子表明,舊的16MB 顯卡沒有現代游戲表現其絢麗畫面所需要的足夠內存。很明顯,在它繪制畫面的時候,我們每幀都必須重新把紋理裝載到顯卡。實際上,設計AGP總線的目的就是完成這個任務,不過, AGP 還是要比 3D 掀卡的幀緩沖區慢,所以你會受到性能上的一些損失。很明顯,如果紋理由32位降低到16位,你就能夠通過AGP以較低的分辨率傳送兩倍數量的紋理。如果你的游戲以每個像素比較低的色彩分辨率跑, 那么就可以有更多的顯示內存用來保存常用的紋理 (稱為高速緩存紋理) 但實際上你永遠不可能預知使用者將如何設置他們的系統。如果他們有一個在高分辨率和顏色深度跑的顯卡,那么他們將會更可能那樣設定他們的顯卡。



  我們現在開始講霧,它是某種視覺上的效果。如今絕大多數的引擎都能處理霧, 因為霧非常方便地讓遠處的世界淡出視野,所以當模型和場景地理越過觀察體后平面進入視覺范圍內時,你就不會看見它們突然從遠處跳出來了。 也有一種稱為體霧的技術。這種霧不是隨物體離照相機的距離而定,它實際上是一個你能看見的真實對象,并且可以穿越它,從另外一側出去 -- 當你在穿越對象的時候,視覺上霧的可見程度隨著變化。想象一下穿過云團 -- 這是體霧的一個完美例子。體霧的一些好的實現例子是Quake III一些關卡中的紅色霧,或新的Rogue Squadron II Lucas Arts GameCube 版本。其中有一些是我曾經見過的最好的云--大約與你能看見的一樣真實。

  在我們討論霧化的時候,可能是簡短介紹一下 Alpha 測試和紋理Alpha混合的好時機。當渲染器往屏幕上畫一個特定像素時,假定它已經通過 Z- 緩沖測試 (在下面定義),我們可能最后做一些Alpha測試。我們可能發現為了顯示像素后面的某些東西,像素需要透明繪制。這意味著我們必須取得像素的已有值,和我們新的像素值進行混和,并把混合結果的像素值放回原處。這稱為讀-修改-寫操作,遠比正常的像素寫操作費時。

  你可以用不同類型的混合,這些不同的效果被稱為混合模式。直接Alpha混合只是把背景像素的一些百分比值加到新像素的相反百分比值上面。還有加法混合,將舊像素的一些百分比,和特定數量(而不是百分比)的新像素相加。 這樣效果會更加鮮明。 (Kyle's Lightsaber Jedi Knight II 中的效果)

  每當廠商提供新的顯卡時,我們可以得到硬件支持的更新更復雜的混合模式,從而制作出更多更眩目的效果。GF3+4和最近的Radeon顯卡提供的像素操作,已經到了極限。


模板陰影與深度測試
  用模板產生陰影效果,事情就變得復雜而昂貴了。這里不討論太多細節(可以寫成一篇單獨的文章了),其思想是,從光源視角繪制模型視圖,然后用這個把多邊形紋理形狀產生或投射到受影響的物體表面。

  實際上你是在視野中投射將會在其他多邊形上面的光體。最后你得到看似真實的光照,甚至帶有視角在里面。因為要動態創建紋理,并對同一場景進行多遍繪制,所以這很昂貴。

  你能用眾多不同方法產生陰影,情形時常是這樣一來,渲染質量與產生效果所需要的渲染工作成比例。有所謂的硬陰影或軟陰影之分,而后者較好,因為它們更加準確地模仿陰影通常在真實世界的行為。 通常有一些被游戲開發者偏愛的足夠好的方法。如要更多的了解陰影,請參考 Dave Salvator 3D 流水線一文。


深度測試
  現在我們開始討論深度測試, 深度測試丟棄隱藏的像素,過度繪制開始起作用。過度繪制非常簡單在一幀中,你數次繪制一個像素位置。它以3D場景中Z(深度)方向上存在的元素數量為基礎,也被稱為深度復雜度。如果你常常太多的過度繪制, -- 舉例來說, 符咒的眩目視覺特效,就象Heretic II,能讓你的幀速率變得很糟糕。當屏幕上的一些人們彼此施放符咒時,Heretic II設計的一些最初效果造成的情形是,他們在一幀中對屏幕上每個相同的像素畫了40! 不用說,這必須調整,尤其是軟件渲染器,除了將游戲降低到象是滑雪表演外,它根本不能處理這樣的負荷。深度測試是一種用來決定在相同的像素位置上哪些對象在其它對象前面的技術,這樣我們就能夠避免繪制那些隱藏的對象。

  看著場景并想想你所看不見的。 換句話說,是什么在其他場景對象前面,或者隱藏了其他場景對象? 是深度測試作出的這個決定。

  我將進一步解釋深度深度如何幫助提高幀速率。想像一個很瑣細的場景,大量的多邊形 (或像素)位于彼此的后面,在渲染器獲得他們之間沒有一個快速的方法丟棄他們。對非Alpha混合的多邊形分類排序( Z- 方向上),首先渲染離你最近的那些多邊形,優先使用距離最近的像素填充屏幕。所以當你要渲染它們后面的像素(由Z或者深度測試決定)時,這些像素很快被丟棄,從而避免了混合步驟并節省了時間。如果你從后到前繪制,所有隱藏的對象將被完全繪制,然后又被其他對象完全重寫覆蓋。場景越復雜,這種情況就越糟糕,所以深度測試是個好東西。


抗鋸齒
  讓我們快速的看一下抗鋸齒。當渲染單個多邊形時,3D 顯卡仔細檢查已經渲染的,并對新的多邊形的邊緣進行柔化,這樣你就不會得到明顯可見的鋸齒形的像素邊緣。兩種技術方法之一通常被用來處理。 第一種方法是單個多邊形層次,需要你從視野后面到前面渲染多邊形,這樣每個多邊形都能和它后面的進行適當的混合。如果不按序進行渲染,最后你會看見各種奇怪的效果。在第二種方法中,使用比實際顯示更大的分辯率來渲染整幅幀畫面,然后在你縮小圖像時,尖銳的鋸齒形邊緣就混合消失了。這第二種方法的結果不錯,但因為顯卡需要渲染比實際結果幀更多的像素,所以需要大量的內存資源和很高的內存帶寬。

  多數新的顯卡能很好地處理這些,但仍然有多種抗鋸齒模式可以供你選擇,因此你可以在性能和質量之間作出折衷。對於當今流行的各種不同抗鋸齒技術的更詳細討論請參見Dave Salvator 3D 流水線一文。


頂點與像素著色
  在結束討論渲染技術之前,我們快速的說一下頂點和像素著色,最近它們正引起很多關注。頂點著色是一種直接使用顯卡硬件特征的方式,不使用API。舉例來說,如果顯卡支持硬件 T & L ,你可以用DirectXOpenGL編程,并希望你的頂點通過 T & L 單元 (因為這完全由驅動程序處理,所以沒有辦法確信),或者你直接利用顯卡硬件使用頂點著色。它們允許你根據顯卡自身特征進行特別編碼,你自己特殊的編碼使用T & L 引擎,以及為了發揮你的最大優勢,顯卡必須提供的其他別的特征。 事實上,現在nVidia ATI 在他們大量的顯卡上都提供了這個特征。

  不幸的是,顯卡之間表示頂點著色的方法并不一致。你不能象使用DirectX或者OpenGL 那樣,為頂點著色編寫一次代碼就可以在任何顯卡上運行,這可是個壞消息。然而,因為你直接和顯卡硬件交流,它為快速渲染頂點著色可能生成的效果提供最大的承諾。( 如同創造很不錯的特效 -- 你能夠使用頂點著色以API沒有提供的方式影響事物)。事實上,頂點著色正在真的將3D 圖形顯示卡帶回到游戲機的編碼方式,直接存取硬件,最大限度利用系統的必須知識,而不是依靠API來為你做一切。對一些程序員來說,會對這種編碼方式感到吃驚,但這是進步代價。

  進一步闡述,頂點著色是一些在頂點被送到顯卡渲染之前計算和運行頂點效果程序或者例程。你可以在主CPU上面用軟件來做這些事情,或者使用顯卡上的頂點著色。 為動畫模型變換網格是頂點程序的主選。

  像素著色是那些你寫的例程,當繪制紋理時,這些例程就逐個像素被執行。你有效地用這些新的例程推翻了顯卡硬件正常情況做的混合模式運算。這允許你做一些很不錯的像素效果, 比如,使遠處的紋理模糊,添加炮火煙霧, 產生水中的反射效果等。一旦 ATI nVidia 能實際上就像素著色版本達成一致( DX9's 新的高級陰影語言將會幫助促進這一目標), 我一點不驚訝DirectX OpenGL采用Glide的方式-- 有幫助開始, 但最終不是把任何顯卡發揮到極限的最好方法。我認為我會有興趣觀望將來。


最后(In Closing...
  最終,渲染器是游戲程序員最受評判的地方。在這個行業,視覺上的華麗非常重要,因此它為知道你正在做的買單。對于渲染器程序員,最壞的因素之一就是3D 顯卡工業界變化的速度。一天,你正在嘗試使透明圖像正確地工作;第二天 nVidia 正在做頂點著色編程的展示。而且發展非常快,大致上,四年以前為那個時代的 3D 顯卡寫的代碼現在已經過時了,需要全部重寫。 甚至John Carmack 這樣描述過,他知道四年以前為充分發揮那個時期顯卡的性能所寫的不錯的代碼,如今很平凡 -- 因此他產生了為每個新的id項目完全重寫渲染器的欲望。Epic Tim Sweeney贊同 -- 這里是去年他給我的評論:

  我們已經足足花費了9個月時間來更換所有的渲染代碼。最初的 Unreal 被設計為軟件渲染和后來擴展為硬件渲染。下一代引擎被設計為 GeForce 及更好的圖形顯示卡,且多邊形吞吐量是Unreal Tournament100倍。

  這需要全部替換渲染器。很幸運,該引擎模塊化程度足夠好,我們可以保持引擎的其余部分編輯器,物理學,人工智能,網絡--不改動,盡管我們一直在以許多方式改進這些部分。

  搭配長篇文章的短篇報導(Sidebar):API -- 祝福和詛咒
  那么什么是API? 它是應用程序編程接口,將不一致的后端用一致的前端呈現出來。舉例來說,很大程度上每種3D顯示卡的3D實現方式都有所差別。然而,他們全部都呈現一個一致的前端給最終使用者或者程序員,所以他們知道他們為X 3D顯示卡寫的代碼將會在Y 3D顯示卡上面有相同的結果。好吧,不管怎樣理論上是那樣。 大約在三年以前這可能是相當真實的陳述,但自那以后,在nVidia 公司的引領下,3D顯卡行業的事情發生了變化。

  如今在PC領域,除非你正計劃建造自己的軟件光柵引擎,使用CPU來繪制你所有的精靈,多邊形和粒子 -- 而且人們仍然在這樣做。跟Unreal一樣,Age of Empires II: Age of Kings有一個優秀的軟件渲染器否則你將使用兩種可能的圖形APIOpenGL或者 DirectX 之一。OpenGL是一種真正的跨平臺API (使用這種API寫的軟件可以在LinuxWindowsMacOS上運行。) 而且有多年的歷史了,為人所熟知,但也開始慢慢地顯示出它的古老。 大約在四年以前,定義OpenGL驅動特征集一直是所有顯示卡廠商工作的方向。

  然而,一旦在目標達成以后,沒有預先制定特征工作方向的路線圖,這時候,所有的顯卡開發商開始在特征集上分道揚鑣,使用OpenGL擴展。

  3dfx 創造了T- 緩沖。 nVidia 努力尋求硬件變換和光照計算。Matrox努力獲取凹凸貼圖。等等。 我以前說過的一句話,"過去幾年以來,3D顯示卡領域的事情發生了變化。"委婉地說明了這一切。

  無論如何,另一個可以選擇的API DirectX。這受Microsoft公司控制,且在PC Xbox 上被完美地支持。由于明顯的原因,DirectX 沒有Apple或者 Linux 版本。因為Microsoft控制著 DirectX,大體上它容易更好地集成在Windows里面。

  OpenGLDirectX之間的基本差別是前者由社區擁有,而后者由Microsoft擁有。如果你想要 DirectX 為你的 3D 顯示卡支持一個新的特征,那么你需要游說微軟,希望采納你的愿望,并等待新的 DirectX發行版本。對于OpenGL,由于顯示卡制造商為3D顯示卡提供驅動程序,你能夠通過OpenGL擴展立即獲得顯示卡的新特征。這是好,但作為游戲開發者,當你為游戲編碼的時候,你不能指望它們很普遍。它們可能讓你的游戲速度提升50%,但你不能要求別人有一塊GeForce 3 來跑你的游戲。好吧,你可以這么做,但如果你想來年還在這個行業的話,這是個相當愚蠢的主意。

  這是對這個問題極大的簡單化,對我所有描述的也有各種例外情況,但這里一般的思想是很確實的。對于DirectX ,在任何既定時間你容易確切地知道你能從顯示卡獲得的特征,如果一個特征不能獲得,DirectX 將會用軟件模擬它(也不總是一件好事情,因為這樣有時侯非常的慢,但那是另外一回事)。對于OpenGL,你可以更加貼近顯示卡的特征,但代價是不能確定將會獲得的準確特征。



夢在天涯 2007-12-04 13:17 發表評論

posted @ 2009-04-10 10:44 不會飛的鳥 閱讀(103) | 評論 (0)編輯 收藏

游戲引擎基礎(四)(模型與動畫,細節級別)

4部份: 模型與動畫,細節級別


角色建模與動畫
  你的角色模型在屏幕上看起來怎么樣,怎樣容易創建它們,紋理,以及動畫對于現代游戲試圖完成的`消除不可信`因素來說至關重要。角色模型系統逐漸變得復雜起來, 包括較高的多邊形數量模型, 和讓模型在屏幕上移動的更好方式。

  如今你需要一個骨骼模型系統,有骨架和網格細節層次,單個頂點骨架的評估,骨架動畫忽略,以及比賽中停留的角度忽略。而這些甚至還沒有開始涉及一些你能做的很好的事情,像動畫混合,骨架反向運動學(IK),和單個骨架限制,以及相片真實感的紋理。這個清單還能夠繼續列下去。但是真的,在用專業行話說了所有這些以后,我們在這里真正談論的是什么呢?讓我們看看。

  讓我們定義一個基于網格的系統和一個骨骼動畫系統作為開始。在基于網格的系統,對于每一個動畫幀,你要定義模型網格的每個點在世界中的位置。舉例來說,你有一個包含200 個多邊形的手的模型,有 300 個頂點(注意,在頂點和多邊形之間通常并不是3個對1個的關系,因為大量多邊形時常共享頂點使用條形和扇形,你能大幅減少頂點數量)。如果動畫有 10 幀,那么你就需要在內存中有300個頂點位置的數據。 總共有300 x 10 = 3000 頂點,每個頂點由xyz和顏色/alpha信息組成。你能看見這個增長起來是多么的快。Quake III III 都使用了這種系統,這種系統確實有動態變形網格的能力,比如使裙子擺動,或者讓頭發飄動。

  相比之下,在骨骼動畫系統,網格是由骨架組成的骨骼( 骨架是你運動的對象) 網格頂點和骨架本身相關,所以它們在模型中的位置都是相對于骨架,而不是網格代表每個頂點在世界中的位置。因此,如果你移動骨架,組成多邊形的頂點的位置也相應改變。這意謂著你只必須使骨骼運動,典型情況大約有 50 個左右的骨架很明顯極大地節省了內存。


骨骼動畫附加的好處
  骨骼動畫的另一個優點是能夠根據影響頂點的一些骨架來分別估價每個頂點。例如,雙臂的骨架運動,肩,脖子而且甚至軀干都能在肩中影響網格。當你移動軀干的時候,網格就活像一個角色一樣移動。總的效果是3D角色能夠實現的動畫更加流暢和可信,且需要更少的內存。每個人都贏了。

  當然這里的缺點是,如果你想要使有機的東西運動且很好,比如說頭發,或者披肩,為了讓它看起來自然,你最后不得不在里面放置數量驚人的骨架,這會抬高一些處理時間。

  基于骨骼的系統能帶給你的一些其他事情是忽略特定層次骨架的能力 -- ,"我不關心動畫想要對這塊骨架所做的事情,我想要讓它指向世界中的一個特定點"。這很棒。你能讓模型著眼于世界中的事件,或者使他們的腳在他們站著的地面保持水平。這一切非常微妙,但它可以幫助帶給場景附加的真實感。

  在骨骼系統,你甚至可以指定"我需要把這個特別的動畫用於模型的腿,而一個不同的攜槍或射擊動畫在模型軀干上播放,且那家伙(角色)叫喊的不同動畫效果在模型的頭部播放"。非常妙。Ghoul2 ( Soldier of Fortune II: Double Helix and Jedi Knight I: Outcast中使用了Raven的動畫系統 ) 擁有所有這些好東西,且特別被設計為允許程序員使用所有這些忽略能力。這對動畫的節省像你一樣難以相信。像你一樣的動畫上的這次救援不相信. Raven有一個角色行走的動畫和一個站立開火的動畫,并在它同時行走和開火形下把這兩個動畫合并,而不是需要一個動畫表示角色行走并開火。


More Skeletons in the Closet
  先前描述的效果可以通過具有層次的骨骼系統來完成。這是什么意思呢?意思是每塊骨架實際上的位置相對于它的父親,而不是每個骨架直接位于空間中的地方。這意謂著如果你移動父親骨架,那么它所有的子孫骨架也跟著移動,在代碼上不需要任何額外的努力。這是讓你能夠在任何骨架層次改變動畫,而且通過骨骼其余部分向下傳遞的東西。

  創建一個沒有層次的骨骼系統是可能的 -- 但那時你不能忽略一個骨架并且預期它工作。你所看到的只是身體上的一個骨架開始了新動畫,除非你實現了某種向下傳遞信息的系統,否則在該骨架下面的其它骨架保持原來的動畫。首先由一個層次系統開始,你就自動地獲得這些效果。

  許多今天的動畫系統中正開始出現一些比較新的特征,如動畫混合,從一個正在播放的動畫轉變到另外一個動畫需要經過一小段時間,而不是立即從一個動畫突然轉變到另外一個。舉例來說,你有個角色在行走,然后他停了下來。你不是僅僅突然地轉變動畫,讓他的腿和腳停在無效位置,而是一秒鐘混合一半,這樣腳似乎自然地移到了新的動畫。不能夠過高的評價這種效果 -- 混合是一個微妙的事情,但如果正確的運用,它真的有些差別。


反向運動學
  反向運動學 (IK) 是被許多人們丟棄的一個專業術語,對它的真實含義沒有多少概念。IK 是如今游戲里面一個相對比較新的系統。使用 IK ,程序員能夠移動一只手,或一條腿, 模型的其余關節自動重新定位,因此模型被正確定向。而且有模型的關節新位置的其馀者他們自己,因此模型正確的被定向。比如,你將會說,"好,手 , 去拾起桌子上的那個杯子"并指出杯子在世界中的位置。手就會移動到那里,且它后面的身體會調節其自身以便雙臂移動,身體適當彎曲,等等。

  也有和IK相反的事情,叫做前向運動學,本質上與 IK 工作的次序相反。想像一只手,手附著在手臂上,手臂附著在身體上。現在想像你重重地擊中了身體。通常手臂像連迦般抽動,且手臂末梢的手隨之振動。 IK 能夠移動身體,并讓其余的四肢自己以真實的方式移動。基本上它需要動畫師設定每種工作的大量信息 -- 像關節所能通過的運動范圍,如果一塊骨架前面的骨架移動,那么這塊骨架將移動多少百分比,等等。

  和它現在一樣,盡管很好,它是一個很大的處理問題,不用它你可以有不同的動畫組合而脫身。值得注意的是,真正的 IK 解決辦法需要一個層次骨骼系統而不是一個模型空間系統 -- 否則它們都耗時太多以致無法恰當地計算每個骨架。


LOD
幾何系統
  最后,我們應當快速討論一下與縮放模型幾何復雜度相關的細節級別(LOD)系統(與討論MIP映射時使用的LOD相對照)。假定如今絕大多數PC游戲支持的處理器速度的巨大范圍,以及你可能渲染的任何給定可視場景的動態性質(在屏幕上有一個角色還是12個?) 你通常需要一些系統來處理這樣的情況,比如,當系統接近極限試圖同時在屏幕上繪制出12個角色,每個角色有3000個多邊形,并維持現實的幀速率。 LOD 被設計來協助這樣的情景中。最基本的情況,它是在任何給定時間動態地改變你在屏幕上繪制的角色的多邊形數量的能力。面對現實吧,當一個角色走遠,也許只有十個屏幕像素高度,你真的不需要3000個多邊形來渲染這個角色 -- 或許300個就夠了,而且你很難分辨出差別。

  一些 LOD 系統將會需要你建立模型的多個版本,而且他們將會依靠模型離觀察者的接近程度來改變屏幕上的LOD級別, 以及多少個多邊形正被同時顯示。更加復雜的系統實際上將會動態地減少屏幕上的多邊形數量,在任何給定時間,任何給定的角色,動態地 -- MessiahSacrifice包括了這種風格的技術,盡管在CPU方面并不便宜。你必須確信,與首先簡單地渲染整個事物相比,你的 LOD 系統沒有花較多的時間計算出要渲染那些多邊形(或不渲染)。 任一方式都將會工作,由于如今我們試圖要在屏幕上繪制的多邊形數量,這是件非常必要的事情。注意, DX9 將會支持硬件執行的自適應幾何縮放(tessellation)

  歸結起來是,得到一個運動流暢,其表現和移動在視覺上可信,屏幕上看起來逼真的模型。流暢的動畫時常是通過手工建造動畫和運動捕捉動畫的組合得到。有時你僅僅手工建立了一個給定的動畫 -- 當你在為一個模型做一些你在現實生活中不能做到的事情的動畫時, 你傾向于這樣做 -- 舉例來說,你確實不能向后彎腰,或像Mortal Kombat 4中的Lui Kang那樣在行進的腳踏車上踢腿,通常運動捕捉這時候就出局了! 通常運動捕捉動畫 -- 實際上視頻捕捉活生生的演員貫穿于你想在屏幕上所看到的動畫 -- 是得到逼真的東西的方式。真實感的東西能使一款普通游戲看起來很棒,而且能掩飾許多事情。比如 NFL Blitz,屏幕上的模型大約有 200 個多邊形。它們在靜止站立時看起來可怕的斑駁,一旦這些模型跑動起來它們就有快速流暢的動畫,模型自身的許多丑陋消失了。眼睛容易看見的是 '逼真的' 動畫而不是模型自身的結構。 一個不錯的模型設計師能夠掩飾大多數模型缺陷。

  我希望這些帶給你對模型和動畫問題的洞察力。在第五部份中,我們將會更加深入3D世界的建造,討論一些物理,運動和效果系統的東西。



夢在天涯 2007-12-04 13:18 發表評論

posted @ 2009-04-10 10:44 不會飛的鳥 閱讀(129) | 評論 (0)編輯 收藏

游戲引擎基礎(六)(聲音系統,音頻APIs)

6部分: 聲音系統,音頻APIs


聲音系統
  由于人們玩的游戲在種類和技術上的進步,聲音和音樂近幾年來在游戲中正逐漸變得重要起來(聲音是一個實際游戲的可玩特點,比如在Thief和其它同類游戲中的聽覺提示)。現在四聲道環繞系統在游戲玩家的寶庫中是負擔得起的和平常的事。給定空間的聲音,噪音的障礙和閉塞,和動態的音樂,如今許多游戲使用這些提高玩家情緒上的反應,更多的關注投入到這個領域就不足為奇了。

  現在在PC競技場中,游戲玩家實際上只有一種聲音卡可以選擇 -- PC聲卡制造商創新公司(Creative Labs)的Sound Blaster Live 從舊的時間個人計算機聲音卡片制造業者有創造力的中心. 多年來創新公司已經為DirectX提供了他們的EAX聲音擴展,并且他們是發起新的OpenAL(開放音頻庫Open Audio Library)的創立者。就如同OpenGL是一個圖形API一樣,OpenAL,像它起來聽一樣,是一個聲音系統的APIOpenAL 被設計為支持大多數通常聲卡的許多特征,而且在一個特定的硬件特征不可得時提供一個軟件替代。

  為了更好的定義 OpenAL,我向創新公司的Garin Hiebert詢問了其定義:

  "這里借用我們的 " OpenAL 規格和叁考" 的一個定義:

  OpenAL 是對音頻硬件的一個軟件接口,給程序員提供一個產生高質量多通道輸出的能力。OpenAL 是在模擬的三維環境里產生聲音的一種重要方法。它想要跨平臺并容易使用,在風格和規范上與OpenGL相似。任何已經熟悉OpenGL的程序員將發現OpenAL非常熟悉。

  OpenAL API能容易地被擴展適應插件技術.創新公司已經把EAX支持加入到這套API了,程序員可以用來給他們的聲音環境增加復雜的反響,比賽和障礙效果。

  如同Jedi Knight II: Outcast 一樣,連同Eagle 世界/聲音特征編輯器,Soldier of Fortune II 以這個新系統為特征。什么是Eagle 在介紹這個以前,讓我們討論一些其他的系統,并定義一些聲音術語。


  另外的一個系統是Miles聲音系統。Miles是一家公司,它為你的代碼生產插件,在充分利用每塊聲卡時處理所有必須的到特定聲音卡的說話(比如Sound Blaster Live!系列,或者老的A3D聲卡)。它非常像一個API前端,捆綁了一些額外的特征在里面。 在其他事物當中Miles讓你存取一些事物像MP3解壓縮。 它是很好的解決方案,但像任何事一樣,它花費金錢并是你的代碼和硬件之間的額外一層。雖然對於快速的聲音系統制造,它非常有用,而且他們有段時間了,因此他們的確精通自己的業務。


聲音術語
  讓我們開始障礙和閉塞。它們聽起來一樣,但不是這樣。閉塞基本上意謂著一個聲音在播放時聽者在他們之間有一些閉合的障礙物。

  比如說,在NOLF2的一個屏幕鏡頭上你聽到房子里面壞蛋的聲音。你能聽到他們,但是他們的聲音相當低沉而沙啞。障礙是相似的,但是你和聲音之間的障礙物并不是閉合的。一個好的例子就是在你和聲源之間有一根柱子。由于房間中的回聲你仍然聽得到這個聲音,但是它和聲音直接傳遞到你的耳朵里是不同的。當然這確實依賴于知道在你的耳朵和聲源之間的直線上是什么。而且根據房間的大小,聲源到你的距離等等,需要的處理能變得相當耗時。后面我們將會談到跟蹤--足可以說它時常是比較慢的幀速率的原因。Quake III 里面的A3D 代碼做了這些事情,關閉這些選項通常能夠提高幀速率。Tribe 2 是這種弊病的另外一個受害者。關閉3D聲音選項則你的幀速率立即好轉,這在你考慮Tribes世界有多大和你能看見多遠時有意義。

  接著是聲音物質的特征。大部分聲卡可以讓你能夠用可定義的過濾器作用于聲音從而修正播放的聲音。例如,在水下,或者在一個布料遮蓋的房間中,或者在一個長的走廊中,或者在歌劇院,聽到的聲音有著很大的不同。能夠根據你所處的環境改變你聽到聲音的方式是相當不錯的。

  我們回到Eagle… 這是一個編輯器,允許多數第一人稱射擊游戲地圖設計者將他們的地圖導入到這個工具,然后構造簡化的幾何形體來為實際游戲引擎中的EAX代碼產生一個聲音地圖。其思想是你不需要一個真實的圖形地圖的復雜幾何形體來模擬聲音環境。你也能夠給產生的簡化地圖分配聲音物質,這樣聲音環境就能夠動態地改變。我親眼目睹了這在Soldier of FortuneUnreal Tournament上的示范,確實相當引人注目。 我這在財富和 Unreal 巡回賽和它的軍人上真的對示范是證人相當醒目. 當你跳入水中時,聽到所有的聲音改變,這是一個非常令人沉浸的經歷。

  好,讓我們繼續吧。

  對于游戲機,由于靜態的硬件,你的各種可能性會更受限制盡管在PlayStation 2Xbox上,硬件相當不錯。我說的限制,僅僅是指擴展,而不是它所能夠做的。我一點也不會感到驚訝看到這些游戲機上的游戲很快支持杜比數字5.1Dolby Digital 5.1)輸出。Xbox ,由于它的 MCP 音頻處理器,能夠將任何游戲音頻編碼為5.1,并且游戲不需要特別編碼就能利用這個特征。杜比(Dolby)把ProLogic II 帶到了 PS2 上,并與Factor 5合作為GameCube游戲實現了ProLogic II。在 Xbox 之上,Halo, Madden 2002 Project Gotham Racing等游戲都有5.1杜比數字音頻內容。DTS最近也為 PS2 游戲開發者發布了SDK,為這個平臺上的游戲帶來了降低了比特率的DTS音頻版本。


位置的聲音--一個復雜的世界
  現在有一些很少有處理的聲音空間化問題。我說的是把聲音放在一個真實的3D世界中。有四個揚聲器在你周圍是一個很棒的開始,但這仍然只是在二維方向。在你的上方和下方沒有揚聲器,你沒有真正獲得3D聲音。有一些聲音調制過濾器試圖解決這個問題,但實際上沒有真實東西的代替物。當然真實地大多數游戲多半只是在二維方向上,因此這仍然不是太大的問題。

  實際上任何聲音系統最重要的特征之一是把聲音混合在一起。根據你所處的位置,空間中聲音的位置,每個聲音的音量大小,一旦你決定了實際上你能夠聽到的聲音,然后你必須混合這些聲音。通常聲音卡自己處理這些,這首先是聲音卡存在的主要原因。然而,外面有一些引擎決定首先用軟件做一次預混合。直到你著眼于一點點歷史以前,這并沒有真正地帶來多大的意義。

  當聲音卡最初問世的時候,有許多不同的混合方法。一些聲卡可以混合8種聲音,一些單位16種,一些32種,等等。 如果你總想聽到16種可能的聲音,但你不知道聲音卡是否能夠處理,那么你回到了嘗試和試驗的道路上 就是你自己用軟件混合。這實際上是Quake III聲音系統的工作方式,但提一個問題:"Quake III是為A3DSound Blaster Live!聲卡世界發布的,這比以前更加標準化,為什么還這樣做?" 這是個好問題。實際上Quake III的聲音系統幾乎每行代碼都和Quake II中的聲音系統一樣。而且Quake I,甚至Doom也是這樣。你想一想,向上直到 A3D 聲卡和 SB Live! 聲卡,許多年來聲音系統的需求沒有真正地改變過。兩個揚聲器,二維方向,音量簡單地隨著距離減小。從Doom一直到Quake III沒有發生太大變化。而且在游戲行業中,如果不是迫不得已,別理會它。

  通常你會僅僅使用DirectSound為你做聲音混合,因為它會可以使用的聲音硬件,或者轉而依靠軟件,很多地方就像DirectX3D顯示卡所做的一樣。在 90% 的聲音情形中,依靠軟件混合對你的幀速率沒有真正發生太多不同。當DirectSound在一些狂熱的編碼者眼中甚至還不是一絲光線時,Doom引擎就已經產生了。它從來沒有得到更新過,因為它從來就沒有真的需要更新。

  當然,你可以使用 SoundBlaster Live!聲卡的一些聰明特征,例如房間的回聲特性: 一塊石窟,或一個禮堂,一個巨穴, 一個足球體育館等。而且你真的應該使用由硬件提供的混合器,畢竟,那是它存在的目的。這種方法的一個不足之處是程序本身時常無法獲得混合結果,因為混合是在聲卡內部完成而不是在主存。如果由于某種原因你需要看到產生的音量,你是運氣不好。


Music Tracks in Games
(游戲中的音軌)
  我們沒有過多的談到游戲中的音樂生成。傳統的有兩種方法,一種是簡單的音樂 .wav 文件(或同等物)。它被預先制作做好,準備運行,和最小忙亂。然而,這些在內存和回放時間方面很昂貴。第二種方式用預設的樣本編碼MIDI音軌。這時常比較節省內存,但缺點是必須同時把一些聲音混合在一起,因而會把聲音通道用光。

  動態音樂就是根據在游戲中目睹的行動改變你的音樂的能力,比如探險用慢節奏的音樂,戰斗用快節奏的音樂。預先制作的音樂的一個困難之處是要合拍,因此你可以從一段音樂漸弱到另一段音樂,這對于MIDI音軌比較容易。盡管時常你足夠快速地淡出,或者一段音樂在播放另一段音樂之前已經消失了,你能僥幸不被察覺。

  在我們離開這個主題之前,順便說一下,值得一提的是存在一些公司專門為你的游戲創作特定意義的音樂。FatMan(www.fatman.com) 就是一家這樣的公司。音樂可能比其他別的東西更加容易外包,這是他們存在的方式。

  最后,游戲現在的事情自然是MP3格式,允許巨大的11 1的聲音樣本壓縮,然而在送到聲音卡之前只花費CPU很少的時間解壓縮。當我在Rave Software工作時,在Star Trek Voyager: Elite Force 中,我們設法用MP3在一張CD上面完全支持三種語言,仍然為較多的圖形留有空間。主要地,我們 MP3 只用于非玩家角色(NPC)的語音,由于游戲的全部音頻效果MP3流和動態解壓縮超出了硬件的處理能力,雖然在將來這是肯定可能的。比較新的格式,如來自 Dolby AAC 和來自微軟的WMA,以將近兩倍MP3的壓縮率提供了相等或者更高的音頻質量(實際上一半的比特率),可能應用到將來的游戲中。

  以上是這一章節的內容,下面將是網絡和連線游戲環境的開發。



夢在天涯 2007-12-04 13:20 發表評論

posted @ 2009-04-10 10:44 不會飛的鳥 閱讀(318) | 評論 (0)編輯 收藏

僅列出標題
共9頁: 1 2 3 4 5 6 7 8 9 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲人成在线观看网站高清| 日韩午夜激情| 亚洲免费人成在线视频观看| 国产欧美日韩不卡免费| 久久网站热最新地址| 免费成人av在线| 亚洲一区二区三区精品在线观看 | 欧美激情亚洲国产| 黑人巨大精品欧美黑白配亚洲| 这里只有精品电影| 国产精品最新自拍| 欧美在线视频在线播放完整版免费观看 | 欧美日韩国产免费观看| 99国产精品一区| 亚洲欧美自拍偷拍| 91久久久久久久久| 午夜精品在线观看| 日韩午夜免费视频| 久久久久久夜精品精品免费| 亚洲小说欧美另类社区| 久久综合九色欧美综合狠狠| 亚洲欧美日韩在线播放| 欧美xart系列在线观看| 欧美在线视频日韩| 欧美日韩在线不卡| 欧美黑人在线播放| 红桃视频欧美| 午夜视频一区二区| 亚洲免费视频网站| 欧美精品国产一区| 免费日韩精品中文字幕视频在线| 国产欧美日韩91| 在线天堂一区av电影| 亚洲精选在线| 欧美成人国产va精品日本一级| 久久精品国产精品亚洲| 国产精品久久久久免费a∨大胸| 亚洲国产日日夜夜| 国产欧美精品日韩精品| 一本色道久久综合狠狠躁篇怎么玩| 亚洲精选国产| 欧美激情国产日韩精品一区18| 久久躁狠狠躁夜夜爽| 国产日韩视频| 欧美伊人影院| 久久久久久久综合日本| 国产精品资源| 午夜精品视频在线| 欧美综合77777色婷婷| 国产免费亚洲高清| 新狼窝色av性久久久久久| 校园激情久久| 国产亚洲精品bv在线观看| 先锋影音网一区二区| 久久久综合激的五月天| 黄网站色欧美视频| 久久伊人精品天天| 亚洲高清免费在线| 一本色道久久精品| 国产精品成人久久久久| 亚洲在线国产日韩欧美| 欧美一级淫片播放口| 国产日韩欧美精品一区| 香蕉久久夜色| 狂野欧美激情性xxxx| 噜噜噜久久亚洲精品国产品小说| 日韩一级免费| 欧美性色综合| 亚洲一区二区在线免费观看| 久久国产精品第一页| 在线观看欧美成人| 欧美高清在线| 亚洲视频1区2区| 久久成人精品无人区| 悠悠资源网久久精品| 欧美精品电影在线| 香蕉久久夜色精品| 亚洲电影在线| 亚洲欧美日韩久久精品| 国产一区二区三区在线免费观看 | 亚洲免费久久| 国产精品久久久久av| 欧美在线啊v| 欧美激情一区二区三区| 亚洲一区精品视频| 激情五月***国产精品| 蜜臀99久久精品久久久久久软件| 亚洲欧洲综合| 久久久国产精品亚洲一区| 亚洲国产一二三| 国产精品福利在线观看网址| 欧美一区二区网站| 亚洲人妖在线| 久久久久久色| 亚洲一本视频| 一区二区三区在线免费播放| 欧美日本精品| 久久久久国产精品麻豆ai换脸| 日韩午夜激情av| 欧美99久久| 欧美一区二区精美| 99精品欧美一区| 狠狠综合久久| 国产精品一区久久| 欧美日韩国产成人在线| 久久久久一区二区三区| 中日韩高清电影网| 亚洲国内精品在线| 美国成人直播| 午夜精品久久久久久久99热浪潮| 亚洲人成小说网站色在线| 国产一区成人| 国产精品日韩久久久久| 欧美久久久久久| 免费亚洲电影在线| 久久国产精品久久精品国产| 亚洲永久精品国产| 亚洲日本aⅴ片在线观看香蕉| 蜜桃av一区| 久久动漫亚洲| 欧美亚洲三级| 亚洲男同1069视频| 一二三区精品| 亚洲精品网站在线播放gif| 好吊色欧美一区二区三区四区| 国产精品网站在线观看| 欧美偷拍一区二区| 欧美日韩在线观看一区二区三区| 蜜臀av一级做a爰片久久 | 午夜精品久久久久久久久久久久| 一本大道久久精品懂色aⅴ| 亚洲国产欧美不卡在线观看| 国模精品一区二区三区色天香| 国产精品主播| 国产免费亚洲高清| 国产欧美一区二区精品秋霞影院 | 久久夜色精品| 久久精品亚洲乱码伦伦中文 | 香港成人在线视频| 亚洲伊人网站| 一本久道综合久久精品| 99精品免费网| 亚洲午夜精品久久久久久浪潮| 99视频一区二区三区| 一区二区三区毛片| 亚洲视屏在线播放| 亚洲永久免费精品| 午夜亚洲精品| 欧美在线看片| 久久亚洲春色中文字幕久久久| 久久综合网色—综合色88| 免费看亚洲片| 亚洲激情图片小说视频| 亚洲精选大片| 亚洲午夜精品国产| 欧美一区二区三区在线看| 久久精品欧美日韩精品| 久久综合国产精品| 欧美激情国产精品| 国产精品激情av在线播放| 国产欧美日韩| 在线观看亚洲视频| 日韩视频在线一区| 亚洲免费一在线| 久久久久久久高潮| 亚洲黄色在线看| 亚洲香蕉成视频在线观看| 欧美在线综合| 免费亚洲电影在线| 国产精品久久一区二区三区| 国产一区二区中文字幕免费看| 亚洲国产影院| 亚洲欧美日韩国产一区二区三区 | 国产欧美日韩免费看aⅴ视频| 激情久久五月| 一区二区三区欧美激情| 久久丁香综合五月国产三级网站| 欧美成人a视频| 一区二区三区视频在线观看| 久久精品视频在线播放| 欧美精品一区二区三区视频| 国产精品视频久久久| 亚洲高清二区| 亚洲欧美日韩一区二区三区在线观看| 久久人人爽人人爽爽久久| 亚洲精品久久久久久久久| 午夜天堂精品久久久久| 欧美国产精品v| 国产偷国产偷精品高清尤物| 日韩视频免费观看高清在线视频| 久久er99精品| 亚洲精品在线视频观看| 久久美女性网| 国产欧美在线播放| 亚洲视频在线看| 亚洲电影av在线| 欧美专区在线观看| 国产精品免费一区豆花| 亚洲精品免费网站| 久久综合久久美利坚合众国|