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

白云哥

身披半件長工衣,懷揣一顆地主心

 

War3ArtTools學(xué)習(xí)筆記

    War3ArtTools是Blizzard官方發(fā)布的制作War3 Mod的工具集,雖然其模型導(dǎo)出工具只支持Max4,不過我們的目的也不是為了拿它來給War3做模型。通過War3ArtTools附帶的文檔,了解War3制作的一些技術(shù)細(xì)節(jié),也是很不錯的。

 

    其實在差不多三年前歷時很短的一段3D開發(fā)經(jīng)歷里就參考過這玩意,對照War3ArtTools的工具集及相關(guān)功能,實現(xiàn)了一套我們需要的美術(shù)制作工具,包括模型導(dǎo)出插件、專用材質(zhì)編輯插件、模型預(yù)覽插件,不過當(dāng)時還未涉及到粒子(Partical)與帶子(Ribbon)。

 

    閑話少說,讓我們來看看War3ArtTools里空間都有哪些東西吧。

 

war3arttools_0

 

    這是War3ArtTools的工具集列表,當(dāng)然除此之外還有一篇pdf文檔加幾個max model和tga texture samples。應(yīng)該來說,有了這套工具,再加上War3本身強(qiáng)大的Editor,完全可以做出一個全新的Mod來。

    War3ModelExp.dle 模型導(dǎo)出工具

    War3bmtls.dlt 材質(zhì)編輯工具

    War3Preview.dlu 模型預(yù)覽工具

    War3UserProp.dlu 自定義屬性編輯工具

    War3BlizardPart.dlo 粒子編輯工具

    War3Ribbon.dlo 帶子編輯工具

 

    要想在Max中為War3制作模型,首先第一步要確定的是比例尺問題。文檔中也是一開始就說明了,War3中一個單位等于Max中一年inch(也就是0.0254米),一個農(nóng)民的身高是70個單位(也就是1.778米),這樣看來也是按照現(xiàn)實比例來進(jìn)行設(shè)計的。然后約定了最高的建筑物大約為300個單位(約等于7.62米),一個尋路塊(Pathing Cell)寬度為32單位,而一個地形塊(Terrain Cell)寬度為128單位。

    另外在Max中做好的模型原點就是導(dǎo)出的對象的原點,編輯器和游戲中會始終以原點位置來擺放對象。所以一般情況下我們會把原點設(shè)在人物的腳底下,建筑物的話也就要設(shè)在地板上。

    然后是模型的初始朝向,War3要求在Max中制作時,前視圖中的模型應(yīng)該正對著你。

 

    使用工具集中的預(yù)覽工具,可以隨時在制作的過程中看到游戲中的效果,這個工具對美術(shù)來說相當(dāng)方便,不需要先導(dǎo)出,再啟動游戲編輯器加載導(dǎo)出的模型。而且即使這樣做了,有時候游戲編輯器中看到的效果與最終的游戲效果也還是有差異。這是War3ArtTools的模型預(yù)覽工具的外觀:

 

war3arttools_1

 

對貼圖和材質(zhì)的要求

    貼圖必須使用Diffuse Color Map Channal, 只能使用24bit或32bit的tga文件,文件大小必須是2的整數(shù)次冪,最大支持512 * 512的貼圖,長寬(或?qū)掗L)比例最大不能超過8:1。

    在貼圖的alpha通道上可以繪制團(tuán)隊顏色(Team Color),或者為模型創(chuàng)建透明區(qū)域。白色(1)為完全不透明,黑色(0)為完全透明。

    材質(zhì)類型只支持自定義的Warcraft III類型和混合材質(zhì)類型。一個Geometry只支持一張材質(zhì),但可以使用組合材質(zhì)來實現(xiàn)多層效果。

 

    在材質(zhì)工具的參數(shù)設(shè)置中也做了一些規(guī)則限制,比如某些參數(shù)必須使用哪些項,等等。然后還有一些War3自定義的材質(zhì)屬性,用來實現(xiàn)游戲特殊需求,比如Replaceable Texture, Unshadered, No Depth Set, No Depth Test, 2-Sided, UnFogged, UnSelectable等等。

 

制作動畫序列

    War3使用Max Track View中的”Note track” Key來定義動畫序列的相關(guān)屬性,比如長度、時間、是不是循環(huán)播放、動畫出現(xiàn)的概率等等,一個3ds max文件包含了該模型所有的動畫序列。比如一個”Note track” key可能是這樣的:

Stand – 2”

rantity 3

 

    上面的”Stand – 2”就是動畫名,War3ArtTools對動畫名也做了一定的規(guī)則限制。動畫名由一個或多個由空格分隔的單詞構(gòu)成,如果有多個部分,則必須用引號將動畫名括起來。完整的動畫名包括主名和次名,比如”Stand Ready”。

 

    引擎內(nèi)部有一套動畫名稱匹配規(guī)則,用來選擇最合適的動畫進(jìn)行播放。比如一個對象進(jìn)入攻擊行為,這時要播放攻擊動畫,在兩次攻擊動畫中間會有一個暫停,這時引擎會查詢這個模型是否有”Stand Ready”動畫序列,如果有就播放,如果沒有則會回退到”Stand”動畫序列,引擎內(nèi)的動畫規(guī)則包括各種各樣可能的動畫組合。

 

    “Note track”的參數(shù)中有一項Move Speed,定義了unit的移動速度。一般的對象移動速度在250~400個單位之間,也就是6.35~10.16米之間,也是人的正常跑步速度。這個參數(shù)在War3中只是給預(yù)覽工具用的,游戲中不會使用這個數(shù)據(jù)。

    移動速度的調(diào)整關(guān)系到unit移動時是否會出現(xiàn)滑步,這個速度與動畫播放速度之間要協(xié)調(diào)好。比如一個unit,根據(jù)其模型的大小基本上可以確定這個模型每跨出一步所移動的距離,也就是步長,假設(shè)為x,這樣在給定的移動速度s之下,便可以計算出一秒內(nèi)需要跨出s/x步,這個步數(shù)包括了左右兩只腳的步數(shù)。然后再根據(jù)動畫播放幀速率,在Max中默認(rèn)為30幀每秒,便可以計算出一個跨步動作需要在幾幀之內(nèi)播完,也就是動畫的播放速度應(yīng)該有多快。

    以后在游戲過程中如果想要加快或減慢unit的移動速度,不僅是加減其位移的變化速度,還要讓動畫播放速度也做相應(yīng)比例的改變,也就是讓這個unit的動畫在一秒內(nèi)不是播放30幀,這樣來避免出現(xiàn)滑步現(xiàn)象。

 

    然后還有一個Rarity參數(shù)。當(dāng)相同的動畫名稱出現(xiàn)多個時,可以用此數(shù)值來表示該動畫出現(xiàn)的概率。也就是一個休閑站立動作美術(shù)可能做了好幾種,程序在播放的時候會隨機(jī)選擇一種來播,隨機(jī)選擇的依據(jù)就從這個Rarity參數(shù)來。

 

 

    War3使用的MDX模型因為實現(xiàn)的比較早,所以對動作制作方面的限制比較多,一些較新的技術(shù)都不能使用,比如IK與bipped動畫。

    另外每個unit必須有兩個骨骼:bone_head和bone_chest,War3編輯器會用到這兩個骨骼,類似的,turreted buildings必須有bone_turret骨骼。

    Position/Rotation/Scale控制器必須使用Bezier, Linear或TCB,并且Rotation控制器兩個關(guān)鍵幀之間的角度差必須小于90度。

 

掛載點設(shè)置

    掛載點制作時就是綁定了一個box在骨骼上,這個box不需要設(shè)置材質(zhì),但需要在自定義屬性編輯面板上標(biāo)注為Attachment Point。這些box不會被渲染,在它們上也不應(yīng)該有動畫數(shù)據(jù)。

    與骨骼類似,掛載點也有一些是必須定義的,如下所示:

 

war3arttools_2

 

    相對于目前越來越復(fù)雜的MMO來說,War3的掛載點信息還是比較少的。

 

 

模型的優(yōu)化

    War3ArtTools定義了一個表格,指導(dǎo)模型制作者對各種類型的模型其面數(shù),貼圖大小,骨骼數(shù)和帶動畫的Geoset數(shù)量做了規(guī)定。

 

war3arttools_3

 

其他

    每個unit模型可以帶一個頭像模型,只需要在名稱后加一個_Portrait即可,另外頭像模型上必須帶一個攝像機(jī)。

    小物件可以成組,這樣在War3編輯器中刷小物件的時候可以隨機(jī)的刷出各種物件來,只要在命名時將其名稱設(shè)為一樣,同時在后面加上數(shù)字即可,如ModelName0.mdx, ModelName1.mdx, ……

 

動畫列表

    如前面所說,War3中有一套動畫替換規(guī)則,每個unit和building也都定義了一些動畫名,有些是必須要有的,有些是可選的,美術(shù)在制作的時候必須要有的可以先做,可選動畫可以在后期慢慢加入,下表是幾個動畫名及其描述:

 

war3arttools_4

 

可替換的貼圖ID

TeamColor

    用于顯示團(tuán)隊顏色,通常情況下,一個”underpainting”貼圖被應(yīng)用于模型的一部分或者整個模型上,并且這個貼圖被設(shè)置為Team Color,然后模型的Skin再被附加一層帶alpha“空洞”的貼圖,通過這些“空洞”把下面的Team Color顯示出來。

Team Glow

    用Billboard實現(xiàn)的,可以讓英雄單位或英雄所帶的武器發(fā)光的一種貼圖方式。

Trees

    被標(biāo)記為Tree的可替換貼圖在游戲中會被替換為適合當(dāng)前tileset的Tree貼圖。

 

 

注:以上內(nèi)容大部分未經(jīng)驗證,屬于個人理解,小心被誤導(dǎo)

posted @ 2009-08-09 00:45 白云哥 閱讀(1541) | 評論 (1)編輯 收藏

魔獸mdx文件導(dǎo)出為Ogre Mesh的小進(jìn)展

    最近一直在試圖把魔獸3的mdx文件轉(zhuǎn)為Ogre Mesh,學(xué)習(xí)一下基礎(chǔ)的3D編程。Ogre Mesh的導(dǎo)出在很久之前也曾試圖做過,并且還把WOW的m2模型以及WMO模型導(dǎo)入到了Max中,但是只做到了骨架的導(dǎo)入,動畫數(shù)據(jù)始終出不來,于是放棄。

 

    這次依然是碰到這里的問題,導(dǎo)出靜態(tài)的Mesh很快就完成,包括模型與材質(zhì),代碼也比較簡單。

 

// 模型數(shù)據(jù)
bool ModelLoaderMdx::loadGeosets(Ogre::MeshPtr model, MdxDataStreamPtr dataStream, int size)
{
    unsigned int index = 0;
    while(size > 0)
    {
        int geosetSize = dataStream->read<int>();
        size -= geosetSize;

        Ogre::String meshName = m_modelName + Ogre::String("_sub_") + Ogre::StringConverter::toString(index++);
        Ogre::SubMesh* subMesh = model->createSubMesh(meshName);
    
        // 硬件緩沖編號
        // 分別為頂點坐標(biāo) 法線 貼圖坐標(biāo)
#define HARDWARE_BUFFER_SOURCE_VERTEX 0
#define HARDWARE_BUFFER_SOURCE_NORMAL 1
#define HARDWARE_BUFFER_SOURCE_TEXPOS 2


        //
        // 頂點數(shù)據(jù)
        //
        if(!expectTag(dataStream, 'VRTX')) 
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect VRTX data for geoset",
                "ModelLoaderMdx::loadGeosets");
        }

        unsigned int vertexCount = dataStream->read<unsigned int>();

        // 不使用共享頂點數(shù)據(jù)
        // 每個SubMesh都創(chuàng)建自己的VertexData
        subMesh->useSharedVertices = false;
        subMesh->vertexData = OGRE_NEW Ogre::VertexData();

        subMesh->vertexData->vertexStart = 0;
        subMesh->vertexData->vertexCount = vertexCount;

        subMesh->vertexData->vertexDeclaration->addElement(
            HARDWARE_BUFFER_SOURCE_VERTEX, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);

        size_t vertexSize = sizeof(float) * 3;
        assert(subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_VERTEX) == vertexSize);
        if (subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_VERTEX) != vertexSize)
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "VertexSize error", 
                "ModelLoaderMdx::loadGeoset");
        }

        Ogre::HardwareVertexBufferSharedPtr vertexBuffer;
        vertexBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
            vertexSize,
            vertexCount,
            Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
        void* vertexBufferData = vertexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);

        unsigned int vertexBufferDataPos = 0;
        for (unsigned int i = 0; i < vertexCount; ++i)
        {
            Ogre::Vector3 data(
                dataStream->read<float>(),
                dataStream->read<float>(),
                dataStream->read<float>()
                );
            transformCoord(data);
            memcpy((char*)vertexBufferData + vertexBufferDataPos, &data, sizeof(Ogre::Vector3));
            vertexBufferDataPos += sizeof(Ogre::Vector3);
        }

        vertexBuffer->unlock();
        subMesh->vertexData->vertexBufferBinding->setBinding(HARDWARE_BUFFER_SOURCE_VERTEX, vertexBuffer);


        //
        // 法線數(shù)據(jù)
        //
        if(!expectTag(dataStream, 'NRMS'))
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect NRMS data for material",
                "ModelLoaderMdx::loadGeosets");
        }

        unsigned int normalCount = dataStream->read<unsigned int>();
        if(normalCount != vertexCount)
        {
            std::stringstream stream;
            stream << "Normal count mismatch, " << normalCount << " normals for " << vertexCount << " vertices)!";
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, stream.str(), 
                "ModelLoaderMdx::loadGeoset");
        }

        subMesh->vertexData->vertexDeclaration->addElement(
            HARDWARE_BUFFER_SOURCE_NORMAL, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);

        size_t normalSize = sizeof(float) * 3;
        assert(subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_NORMAL) == normalSize);
        if (subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_NORMAL) != normalSize)
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "NormalSize error", 
                "ModelLoaderMdx::loadGeoset");
        }

        Ogre::HardwareVertexBufferSharedPtr normalBuffer;
        normalBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
            normalSize,
            normalCount,
            Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
        void* normalBufferData = normalBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);

        unsigned int normalBufferDataPos = 0;
        for (unsigned int i = 0; i < normalCount; ++i)
        {
            Ogre::Vector3 data(
                dataStream->read<float>(),
                dataStream->read<float>(),
                dataStream->read<float>()
                );
            transformCoord(data);
            memcpy((char*)normalBufferData + normalBufferDataPos, &data, sizeof(Ogre::Vector3));
            normalBufferDataPos += sizeof(Ogre::Vector3);
        }

        normalBuffer->unlock();
        subMesh->vertexData->vertexBufferBinding->setBinding(HARDWARE_BUFFER_SOURCE_NORMAL, normalBuffer);


…………
        //
        // 頂點索引
        //
        if(!expectTag(dataStream, 'PVTX')) 
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect PVTX data for geoset",
                "ModelLoaderMdx::loadGeosets");
        }

        unsigned int indexCount = dataStream->read<unsigned int>();
        assert(totalIndexCount == indexCount);
        if (totalIndexCount != indexCount)
        {
            std::stringstream stream;
            stream << "indexCount is " << indexCount << ", but totalIndexCount for all faces is " << totalIndexCount;
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, stream.str(), 
                "ModelLoaderMdx::loadGeoset");
        }

        subMesh->indexData->indexStart = 0;
        subMesh->indexData->indexCount = indexCount;

        Ogre::HardwareIndexBufferSharedPtr indexBuffer;
        indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
            Ogre::HardwareIndexBuffer::IT_16BIT,
            indexCount,
            Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);

        void* indexBufferData = indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
        dataStream->read(indexBufferData, indexCount * sizeof(unsigned short));

        // 三角形反轉(zhuǎn), 將原來的反面朝外
        unsigned short* tmpData = (unsigned short*)indexBufferData;
        for (unsigned int i = 0; i < indexCount; i += 3)
        {
            unsigned short tmp = tmpData[i + 1];
            tmpData[i + 1] = tmpData[i + 2];
            tmpData[i + 2] = tmp;
        }

        indexBuffer->unlock();


        subMesh->indexData->indexBuffer = indexBuffer;
        subMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;


…………

        // 材質(zhì)ID
        unsigned int materialID = dataStream->read<unsigned int>();
        Ogre::String materialName = m_modelName + Ogre::String("_") + boost::lexical_cast<Ogre::String>(materialID);
        subMesh->setMaterialName(materialName);

…………

        //
        // 貼圖坐標(biāo)
        //
        if(!expectTag(dataStream, 'UVBS')) 
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect UVBS data for geoset",
                "ModelLoaderMdx::loadGeosets");
        }

        unsigned int texturePositionCount = dataStream->read<unsigned int>();
        if(texturePositionCount != vertexCount)
        {
            std::stringstream stream;
            stream << "Texture position count mismatch, " << texturePositionCount << " texture positions for " << vertexCount << " vertices)!";
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, stream.str(), 
                "ModelLoaderMdx::loadGeoset");
        }

        // TextureCoord Data
        subMesh->vertexData->vertexDeclaration->addElement(
            HARDWARE_BUFFER_SOURCE_TEXPOS, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);

        size_t texPosSize = sizeof(float) * 2;
        assert(subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_TEXPOS) == texPosSize);
        if (subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_TEXPOS) != texPosSize)
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "TexturePositionSize error", 
                "ModelLoaderMdx::loadGeoset");
        }

        Ogre::HardwareVertexBufferSharedPtr texPosBuffer;
        texPosBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
            texPosSize,
            texturePositionCount,
            Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
        void* texPosBufferData = texPosBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
        dataStream->read(texPosBufferData, texPosSize * texturePositionCount);
        texPosBuffer->unlock();
        subMesh->vertexData->vertexBufferBinding->setBinding(HARDWARE_BUFFER_SOURCE_TEXPOS, texPosBuffer);
    }

    return true;
}

 

    但是到了動畫數(shù)據(jù)這里問題又出來了,而且mdx模型與m2模型還有些差別,mdx模型中沒有骨骼數(shù)據(jù),只有max中最簡單的三種變換數(shù)據(jù),Ogre中只有MorphAnimation能夠?qū)崿F(xiàn)此種動畫。

 

    Ogre的MorphAnimation的第一個KeyFrame必須帶有完整的頂點信息,而mdx模型中旋轉(zhuǎn)、縮放與位移是分開的,也就是一個KeyFrame上可能只有一種變換,或者多種。而實際上在max中制作動畫的時候這三種變換也是獨立開的,Ogre的論壇上找到一篇討論有人提到了這個問題,可惜制作者的回復(fù)是MorphAnimation只實現(xiàn)到這樣……

 

    也確實,現(xiàn)在除了一些小物件的動畫外,主角,怪物的動畫都用skeleton了,也許MorphAnimation就快退出歷史的舞臺,在Ogre中看不到了,也不能指望會有什么改進(jìn)。

 

    繼續(xù)實現(xiàn)之,那就只能在有KeyFrame的地方把三種變換都計算一次,然后取得最終變換后的位置數(shù)據(jù),也就是做人工的動畫幀采樣。在War3EditorSource的基礎(chǔ)上做了些修改,終于,一幀幀的動畫計算出來了。

 

mdx2mesh_anim

 

    不過問題依然還有很多,比如mdx模型,尤其是怪物和角色模型中大量用到了ReplacableTexture,這些需要通過讀配置文件來獲取可用的貼圖,另外模型上附帶的粒子特效、紋理動畫等都還沒有導(dǎo)出,看看這個沒有貼圖的攻擊中的蝎子,前面的路仍然很遠(yuǎn)。

 

mdx2mesh_anim_attack

posted @ 2009-08-07 22:42 白云哥 閱讀(2341) | 評論 (0)編輯 收藏

讓對象在Unity3D中動起來

    讓對象動起來有兩步:

    1。在場景中移動對象

    2。讓對象播放動畫

    我們一步步來實現(xiàn)這個目標(biāo)。

 

    移動對象需要用到UnityScript,不過這里我們只是想要簡單的移動,拿“Script Tutorial”中的例子稍改改就行:

function Update () {
    transform.position.x+= 0.02;
}

    在Unity3D中運行看看效果,我們將這個腳本綁定到一個球上,球開始向x軸方向移動了。

 

    接下來再看看如何播放動畫。

    手冊上說,如果想用max來做動畫,必須將其導(dǎo)出為fbx文件。

    沒經(jīng)驗就是沒經(jīng)驗,我裝的3ds max9,從Autodesk網(wǎng)站上下載了個FBX插件For max 2009,結(jié)果死活加載不了,最后想想弄個低版本的插件試試,結(jié)果進(jìn)去一找,怎么還有個For max9的?敢情max9跟max2009不是一回事啊!而且,這max9都已經(jīng)這么老了,中間還隔了個max2008,再加上最新的max2010……

 

    在max中做了個簡單的球,和幾幀簡單的動畫,導(dǎo)出到Unity3D中,需要手動添加動畫,效果如下:

ball_animation

    結(jié)合上面的移動腳本,最后試運行了下,球開始邊轉(zhuǎn)邊跑了 :)

 

    還有幾個問題:

    1。當(dāng)在max做多個動畫時,在Unity3D中添加進(jìn)來,第二個動畫的播放位置有問題,不管擺到哪兒,播動畫的時候這個GameObject都會跑到場景原點去。

    2。手冊中說只支持Animation與Bone Based Animation。不會做動畫,不知道m(xù)ax的骨骼動畫導(dǎo)出來是怎樣,另外,biped動畫是否能導(dǎo)出?需要試驗一下。

 

-------------------

 

    費了半天勁找比例尺,原來是max中單位設(shè)置不正確。

    方法:Customize – Unit Setup – System Unit Setup

    用cm做單位,這樣做一個 100 * 100 * 100 單位的box放到Unity3D中正好占據(jù)一個Unity3D單位。

    在手冊的某處也說到了,只是不太明顯:Unity’s physics system expects 1 meter in the game world to be 1 unit in the imported file.

    所以,也根本用不著我來假設(shè)一個Unity3D單位等于現(xiàn)實世界中的一米……

posted @ 2009-07-29 22:12 白云哥 閱讀(4165) | 評論 (2)編輯 收藏

Unity3D地形的制作

  Unity3D手冊中介紹了兩種地形制作方法:

  一、在SceneView中使用height tools直接繪制

  二、使用外部工具制作的heightmaps

 

  直接繪制地形很簡單,不過只適合小面積地圖的制作,對于真實游戲項目來說,這樣拉地形實在太復(fù)雜,一般我們都會使用外部工具,比如PS,比如max來制作高度圖,然后導(dǎo)出為一張灰度圖,在引擎中將其轉(zhuǎn)換為地形。

  Unity3D也支持了這種做法,即導(dǎo)入HeightMap的方式,不過對HeightMap的格式有一個限定,必須是16bit的RAW格式灰度圖,但是除此之外手冊中再沒有更多的描述。

  沒關(guān)系,Unity3D提供了將地形導(dǎo)出為HeightMap的方法,我們可以做一張小地圖將其導(dǎo)出來,看一看就知道了。

  如下圖所示,將地形長寬高都設(shè)定為2個單位,地形精度設(shè)定為33,這個數(shù)值是能夠設(shè)置的最小值了。這樣就表示在一個單位內(nèi)會有17個高度值,即16條邊。然后把這個地形導(dǎo)出為16bit Raw格式文件。

heightmap_resolusion

  按照上面的數(shù)據(jù),這個raw文件將會由33 * 33個16bit數(shù)據(jù)構(gòu)成,所以文件大小應(yīng)為 16 * 16 * 2 = 2178字節(jié)。導(dǎo)出來的文件也確實如此,證明我們的推斷是正確的。

  注意這里的Heightmap Resolution一定是2的n次冪加1,至于為什么會這樣,找一個介紹HeightMap的文檔看一下就明白了。

 

  既然驗證了我們的推斷是正確的,那試著在PS中創(chuàng)建一張HeightMap放到Unity3D中看看。我們創(chuàng)建的HeightMap大小為129 * 129象素,如果我們讓一個Unity3D單位由4個象素點構(gòu)成,那么地圖大小則為 (129 – 1) / 4 = 32,即32 * 32,高度值不需要太大,高為12就夠了。

  導(dǎo)入到Unity3D中后刷上一層Texture,再種上幾棵樹,最終的效果看上去是這樣:

heightmap_finalwork

  還不錯,其實我沒這么好的藝術(shù)細(xì)胞,在PS里擺弄了半天后,還是決定到網(wǎng)上去找一張現(xiàn)成的HeightMap (囧)

  好了,場景制作應(yīng)該不會有大問題了,下一步,看看怎么放兩個會動的東西進(jìn)去吧。

posted @ 2009-07-26 00:09 白云哥 閱讀(4340) | 評論 (0)編輯 收藏

Unity3D初探

  Unity3D官方給的Island示例效果確實很震撼,再加上其與web集成的特性讓我饒有興趣的想要試一試。

  場景制作的第一步,我們需要先確定比例尺。簡略地瀏覽了一遍手冊,沒有找到關(guān)于用max制作模型的細(xì)節(jié)描述,只好自己手動制作來找比例尺了。方法很簡單,在max中導(dǎo)出一個box放到Unity3D場景中觀察其大小,這樣就可以看出來max單位與Unity3D單位的比例關(guān)系。

  最后的結(jié)果是,40個單位的box正好占據(jù)一個Unity3D單位的范圍,如圖所示:



  在Unity3D中,默認(rèn)的First Person Controller高度為2個單位,我們可以假定一個Unity3D單位相當(dāng)于現(xiàn)實高度1米,一個人也就是兩米左右,當(dāng)然,實際制作時可以把人的高度調(diào)低一點。

  用這個比例尺來設(shè)計場景及物件大小,試著在場景中擺一張一平方米大小的小桌子,和一個10米高的柱子,來看看比例效果。

  對應(yīng)到max中桌子的大小就是40 * 1 = 40個單位,柱子的高度為40 * 10 = 400個單位。

  用程序員的腦子來控制鼠標(biāo)制作max模型還真是別扭,半天弄出來幾個立方塊,貼上了兩張圖,只有兩個字:難看!

  沒有辦法,從別的游戲中“偷”了一棵樹來裝點一下,模型導(dǎo)出用到了這里的工具,很強(qiáng)大的工具 :)

  最終的效果看起來還比較正常,如下圖:



  下一步,看看怎么生成地形吧。

posted @ 2009-07-25 23:05 白云哥 閱讀(2771) | 評論 (0)編輯 收藏

僅列出標(biāo)題
共3頁: 1 2 3 

導(dǎo)航

統(tǒng)計

常用鏈接

留言簿(4)

隨筆分類

隨筆檔案

相冊

我的鏈接

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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精品福利视频| 美女日韩欧美| 欧美日韩亚洲激情| 久久一区亚洲| 欧美视频在线播放| 理论片一区二区在线| 久久免费国产精品| 乱人伦精品视频在线观看| 亚洲综合精品一区二区| 国产欧美日韩一区二区三区| 欧美日韩1区| 牛人盗摄一区二区三区视频| 欧美激情精品久久久久| 夜夜嗨av一区二区三区| 亚洲黄网站在线观看| 亚洲欧洲综合| 欧美成人69av| 国产日韩欧美| 欧美视频在线一区二区三区| 亚洲欧美日韩在线一区| 久久成年人视频| 国产精品免费观看视频| 99国内精品久久| 亚洲影视在线播放| 欧美亚洲第一页| 免费欧美高清视频| 伊人久久男人天堂| 99re热这里只有精品视频| 国产美女一区二区| 欧美va亚洲va香蕉在线| 亚洲精品国产精品久久清纯直播| 亚洲午夜一级| 亚洲精品激情| 在线欧美影院| 国产精品日韩专区| 亚洲精品欧洲| 午夜精品免费在线| 欧美午夜影院| 亚洲色图综合久久| 亚洲久久成人| 免费中文字幕日韩欧美| 久久99在线观看| 性色一区二区三区| 亚洲国产精品久久91精品| 欧美日韩1234| 久久成年人视频| 免费日韩成人| 免费日韩av片| 亚洲精品久久久久久下一站| 欧美 日韩 国产一区二区在线视频| 91久久精品一区| 欧美在线看片| 国产精品视频yy9299一区| 一本久道久久综合狠狠爱| 一区二区高清视频| 欧美日韩一区二区三区在线观看免| 亚洲大片精品永久免费| 亚洲国产精品久久久久秋霞不卡| 老司机成人网| 日韩小视频在线观看| 亚洲午夜性刺激影院| 亚洲一区尤物| 欧美有码在线视频| 亚洲观看高清完整版在线观看| 亚洲在线日韩| 亚洲婷婷在线| 亚洲久久成人| 亚洲视频精品| 午夜日韩在线观看| 久久精品视频在线播放| 亚洲一区在线观看视频| 亚洲精品午夜精品| 午夜精品理论片| 狂野欧美激情性xxxx| 亚洲欧洲精品一区二区| 国产精品久久99| 久久久精品一区| 亚洲美女av网站| 久久久av水蜜桃| 一区二区欧美在线| 国语自产偷拍精品视频偷 | 在线看视频不卡| 欧美日韩不卡视频| 香蕉视频成人在线观看| 亚洲二区在线视频| 欧美在线播放一区二区| 亚洲美女黄网| 国产一区二区三区久久悠悠色av| 欧美极品在线视频| 久久精品免费电影| 一区二区三区四区五区视频| 免费一级欧美片在线播放| 亚洲在线观看视频网站| 亚洲精品乱码久久久久久蜜桃麻豆 | 久久综合一区二区| 亚洲永久免费精品| 最新日韩在线视频| 国产精品尤物福利片在线观看| 久热re这里精品视频在线6| 一区二区免费在线视频| 欧美成人蜜桃| 久久这里有精品15一区二区三区| 亚洲一区二区三区精品动漫| 亚洲精品美女在线| 在线免费观看日韩欧美| 国产婷婷色一区二区三区| 欧美日韩中文| 欧美日本亚洲视频| 欧美不卡视频一区发布| 久久久噜噜噜久久| 欧美资源在线| 欧美中在线观看| 性伦欧美刺激片在线观看| 亚洲在线观看| 亚洲女人小视频在线观看| 一区二区三区波多野结衣在线观看| 91久久精品日日躁夜夜躁欧美| 久久亚裔精品欧美| 久久香蕉国产线看观看av| 久久久久久亚洲综合影院红桃| 欧美自拍丝袜亚洲| 久久本道综合色狠狠五月| 性做久久久久久免费观看欧美| 亚洲自啪免费| 欧美中在线观看| 亚洲激情综合| 一本久久综合亚洲鲁鲁五月天| 欧美国产日韩a欧美在线观看| 久久美女性网| 麻豆精品一区二区综合av | 激情久久影院| 亚洲国产欧美一区| 亚洲精品国精品久久99热| 亚洲国产精品精华液2区45| 亚洲国产精品久久久久秋霞影院 | 日韩亚洲综合在线| 这里只有精品视频| 午夜影视日本亚洲欧洲精品| 西西人体一区二区| 久久青草久久| 欧美精品乱人伦久久久久久| 欧美日韩国产欧美日美国产精品| 欧美激情中文字幕一区二区 | 欧美伊人久久久久久久久影院| 欧美一级黄色录像| 久久精品国产69国产精品亚洲 | 久久精品国产一区二区三区| 久久在线免费观看视频| 欧美精品久久久久久久免费观看 | 欧美在线播放| 欧美国内亚洲| 中国成人黄色视屏| 久久久久久久久久久久久9999| 欧美国产成人在线| 国产精品网站在线观看| 在线观看亚洲a| 亚洲一级网站| 欧美成年人视频网站| 一个色综合av| 久久视频在线视频| 国产精品久久久久久久久久久久久久 | 91久久精品一区二区别| 一区二区成人精品 | 国产精品久久国产精麻豆99网站| 韩国久久久久| 亚洲一区影音先锋| 亚洲成在人线av| 午夜电影亚洲| 欧美日韩国产系列| 亚洲国产91精品在线观看| 香蕉久久夜色精品国产| 亚洲精品久久久久久久久久久| 欧美一区二区三区在线观看视频| 欧美精品国产精品日韩精品| 国内精品久久久久伊人av| 亚洲欧美日韩成人| 亚洲国产日韩欧美综合久久| 久久久久一区二区| 国产亚洲毛片| 性欧美精品高清| 99精品福利视频|