亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

jMonkeyEngine譯文 FlagRush3——創建地形

系統 2252 0

注:本系列教程全部翻譯完之后可能會以 PDF 的形式發布。

如果有什么錯誤可以留言或 EMAIL kakashi9bi@gmail.com 給我。

jME 版本 jME_2.0.1_Stable

開發工具: MyEclipse8.5

操作系統: Window7/Vista

這個向導中我們涉及到一些好玩的,我們將為我們的游戲加載地形(下文將使用 Terrain 代替)。這里對于我想要的類型的 terrain 有一些要求:

l 每次隨機

l 不需太多三角形

l 為了跳躍“崎嶇”

l 對于快速的交通工具足夠大

我們將在第二課中的框架上構建。首先,由清除 Sphere 渲染代碼開始。我們不再需要這個例子。你現在應該有相當干凈的框架用于工作。現在,我們將創建的地形會相當大。所以我想改變 Camera 的位置保證地形在視野里面。因此,在 initSystem 中作出如下改變:

Vector3f loc = new Vector3f(0.0f,0.0f,25.0f);

改為:

Vector3f loc = new Vector3f(500f,150f,500f);

這向上、遠、后移動,確保我們對地形有恰當的視野。

現在,在 initGame 方法里面我們將加入一個對新方法的調用,這為這個 scene 增加一個 TerrainBlock 。這個 TerrainBlock 叫做 tb 并應該在類頂部定義。這個新的方法叫做 buildTerrain 并應該在增加 tb scene 之前調用。你應該像下面一樣:

protected void initGame() {

scene = new Node( "Scene Graph Node" );

buildTerrain();

scene .attachChild( tb );

// 更新 scene 用于渲染

scene . updateGeometricState (0.0f, true );

scene .updateRenderState();

}

這引導我們到這個向導的核心, buildTerrain

這里有我們 terrain 創建的核心:

1、 創建一個 heightmap

2、 heightmap 生成網格(下文將以 Mesh 代替)

3、 生成基于高度的紋理

3.1 、創建一個 heightmap

AbstractHeightMap 定義了一個方法用于保存高度數據。在它的核心,主要是一個二維矩陣的數據,任何一個點( X,Z )的高度 Y 。然而這不允許創建復雜 terrain (窯洞、懸崖等等)。它提供了很基礎的方形 terrain ,然而這正是我們 FlagRush 中所需要的。

我們將創建一個 MidPointHeightMap ,它使用中點取代不規則碎片。這將允許地形足夠有趣和真實,為我們提供了一些顛簸和跳躍。

創建這個 heightmap 很直截了當,在我們 buildTerrain 方法中的第一行:

/**

* 創建 heightmap terrainBlock

*/

private void buildTerrain() {

// 生成隨機地形數據

MidPointHeightMap heightMap = new MidPointHeightMap(64,1f);

……

}

我們調用 MidPointHeightMap 的構造方法創建一個新的 heightMap 對象。它只需要 2 個參數:大小和粗糙程度。

MidPointHeightMap 的大小必須是 2 的冪。那就是 2 4 8 16 32 64 等等。在我們的例子中,我們選擇 64 。這正好符合我們的需要(我們的行為將被局限在一個相當小的舞臺)。粗糙程度才是有趣的東西。這個值越低,則 terrain 越粗糙,反之越平滑。我們先選擇它為 1 ,讓 terrain 看起來像地獄般凹凸還帶著尖刺。然而,我們還沒設置完,這些尖刺將被調下來。

我們將定義一個 terrain 縮放因數。這將簡單拉伸或擠壓 mesh 以滿足我們的需求。所以,增加:

// 縮放數據

Vector3f terrainScale = new Vector3f(20, .5f, 20);

buildTerrain 方法。這意味著:我們將拉伸 terrain X Z 的值 20 。這將讓 terrain 感覺更大(實際上大了 20 倍)。然而與此同時,我們讓 Y 值減少了一半。這將得到我們想要的凹凸感,但讓它們處于一個合理的值(不會太突然)。

3.2 、生成 Terrain Mesh

現在,我們已經設置好了數據,我們能真正創建 mesh 。我們將創建一個 TerrainBlock ,它是一個簡單的 Geometry 。這個將增加到 scene 里,就像我們之前增加 Sphere 那樣。

// 創建一個 terrain block

tb = new TerrainBlock(

"terrain" ,

heightMap.getSize(),

terrainScale,

heightMap.getHeightMap(),

new Vector3f(0, 0, 0)

);

tb . setModelBound ( new BoundingBox());

tb .updateModelBound();

TerrainBlock 接受一些參數,大多數都很直接。首先,是 terrain 的名字。 heightMap 的大小,接著是我們之前所設的 terrain 的縮放值。接著給出 heightMap 真正的數據。下一個參數定義了 terrain 的起點。我們這里沒有理由設置一些奇怪的值,因此設置了基本的( 0 0 0 )。

我們接著設置了 terrain BoundingVolume

你現在或許能繼續并運行游戲,看到類似下面的一些東西:

jMonkeyEngine譯文 FlagRush3——創建地形

這里并不能看到很多東西,因為 terrain 僅是一大塊白色。我們需要應用 texture 去讓它有一點層次感。

3.3 、生成 Texture

創建一個 Texture 將通過使用 ProceduralTextureGenerator 。這個類將生成一個基于 heightmap 的高度的紋理,并在多個 texture 間混合。一個 texture 被指定到一個高度區域,而它們之后混合進單一的 texture map 。這允許我們很容易創建一個看起來相當真實的 Terrain 。在我們的例子中,我們將使用 3 texture ,一個用于低區域的草地 texture ,中部的巖石和高處的雪。

// 通過三個紋理生成地形紋理

ProceduralTextureGenerator pt =

new ProceduralTextureGenerator(heightMap);

pt.addTexture(

new ImageIcon(

getClass().getClassLoader()

.getResource( "res/grassb.png" )

),

-128, 0, 128

);

pt.addTexture(

new ImageIcon(

getClass().getClassLoader()

.getResource( "res/dirt.jpg" )

),

0, 128, 256

);

pt.addTexture(

new ImageIcon(

getClass().getClassLoader()

.getResource( "res/highest.jpg" )

),

128, 256, 374

);

pt.createTexture(32);

你將注意到每個 Texture 3 個值。這描述了這個 texture 將被應用到低的,最佳的和高的海拔。例如( dirt.jpg )將混合從海拔 0-256 heightmap 生成從 0-256 的值。所以這意味著 dirt 128 將更強烈(看得更多),然后向 0 256 混合其它的 texture 。同時其它的 2 texture 被填充在低和高的區域。

addTexture 接受 ImageIcon 對象去定義 texture 數據。在這個例子中,我們通過我們的類的 getResource 方法獲取到的 URL 創建 ImageIcon 。這個在 classpath 里面搜索 images 。這當然不是一定要這么做, ImageIcon 能在其它某個地方被創建,它將適用于你應用程序。

createTexture 真正創建了我們需要使用的 texture 。在這個例子中,我讓它生成一個 32X32 像素的 texture 。雖然這個看起來很小,但是我并不需要它的細節。這只是用于基礎顏色,之后我們將創建更詳細的 texture 和對象。

例如:在運行游戲期間,我保存了一個生成的 texture 。它看起來像這樣:

你能看到三個 texture grassb dirt highest )是怎樣被混合為一個單一的 texture 。白色的區域將會是 terrain 的高點,而 grass 將是 terrain 的低點。

現在我們已經生成了 Terrain ,我們把它放入一個 TextureState 并把它應用到 terrain

// 將紋理賦予地形

ts = display .getRenderer().createTextureState();

Texture t1 = TextureManager. loadTexture (

pt.getImageIcon().getImage(),

Texture.MinificationFilter. Trilinear ,

Texture.MagnificationFilter. Bilinear ,

true

);

ts .setTexture(t1, 0);

tb .setRenderState( ts );

通過這樣, terrain 就能正常工作了。你現在能運行游戲并看到類似下面的:

jMonkeyEngine譯文 FlagRush3——創建地形

注意: 我一直說類似,因為我們使用的是隨機方法去生成 terrain 。所以它每次都將不同。

3.4 、創建燈光( Light

盡管使用了 texture ,我們依然很難辨別出 terrain 。那是因為沒有燈光和陰影幫助我們辨別 terrain 的部分。所以,讓我們繼續并增加一個“太陽”。增加一個 buildLighting 到你的 initGame 。我們將增加一個 DirectionalLight 去照耀 terrain 。增加 light 2 部分。首先,創建 DirectionalLight ,然后把它增加到 LightState

private void buildLighting() {

/* 設置一個基礎、默認燈光 */

DirectionalLight light = new DirectionalLight();

light.setDiffuse( new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));

light.setAmbient( new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));

light.setDirection( new Vector3f(1, -1, 0));

light.setEnabled( true );

LightState lightState =

display .getRenderer().createLightState();

lightState.attach(light);

scene .setRenderState(lightState);

}

這個 DirectionalLight 被設置于照耀( 1 -1 0 )那個方向(向下和向右)。它接著被增加到 LightState 并應用到 scene

這為 terrain 增加了一些層次感,而你能更好辨認出地形特征。

jMonkeyEngine譯文 FlagRush3——創建地形

3.5 、總結

我們現在擁有了一個可以在上面奔跑的平面。然而,那還是存在令人討厭的黑色背景。下一節課我們將適當關注個問題。

3.6 、源碼

import javax.swing.ImageIcon;

import com.jme.app.BaseGame;

import com.jme.bounding.BoundingBox;

import com.jme.image.Texture;

import com.jme.input.KeyBindingManager;

import com.jme.input.KeyInput;

import com.jme.light.DirectionalLight;

import com.jme.math.Vector3f;

import com.jme.renderer.Camera;

import com.jme.renderer.ColorRGBA;

import com.jme.scene.Node;

import com.jme.scene.state.LightState;

import com.jme.scene.state.TextureState;

import com.jme.system.DisplaySystem;

import com.jme.system.JmeException;

import com.jme.util.TextureManager;

import com.jme.util.Timer;

import com.jmex.terrain.TerrainBlock;

import com.jmex.terrain.util.MidPointHeightMap;

import com.jmex.terrain.util.ProceduralTextureGenerator;

public class Lesson3 extends BaseGame{

private int width , height ;

private int freq , depth ;

private boolean fullscreen ;

// 我們的 camera 對象,用于觀看 scene

private Camera cam ;

protected Timer timer ;

private Node scene ;

private TextureState ts ;

private TerrainBlock tb ;

public static void main(String[] args) {

Lesson3 app = new Lesson3();

java.net.URL url = app.getClass().getClassLoader()

.getResource( "res/logo.png" );

app.setConfigShowMode(ConfigShowMode. AlwaysShow ,url);

app.start();

}

/*

* 清除 texture

*/

protected void cleanup() {

ts .deleteAll();

}

protected void initGame() {

scene = new Node( "Scene Graph Node" );

buildTerrain();

buildLighting();

scene .attachChild( tb );

// 更新 scene 用于渲染

scene .updateGeometricState(0.0f, true );

scene .updateRenderState();

}

private void buildLighting() {

/* 設置一個基礎、默認燈光 */

DirectionalLight light = new DirectionalLight();

light.setDiffuse( new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));

light.setAmbient( new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));

light.setDirection( new Vector3f(1, -1, 0));

light.setEnabled( true );

LightState lightState =

display .getRenderer().createLightState();

lightState.attach(light);

scene .setRenderState(lightState);

}

/**

* 創建 heightmap terrainBlock

*/

private void buildTerrain() {

// 生成隨機地形數據

MidPointHeightMap heightMap = new MidPointHeightMap(64,1f);

// 縮放數據

Vector3f terrainScale = new Vector3f(20, .5f, 20);

// 創建一個 terrain block

tb = new TerrainBlock(

"terrain" ,

heightMap.getSize(),

terrainScale,

heightMap.getHeightMap(),

new Vector3f(0, 0, 0)

);

tb .setModelBound( new BoundingBox());

tb .updateModelBound();

// 通過三個紋理生成地形紋理

ProceduralTextureGenerator pt =

new ProceduralTextureGenerator(heightMap);

pt.addTexture(

new ImageIcon(

getClass().getClassLoader()

.getResource( "res/grassb.png" )

),

-128, 0, 128

);

pt.addTexture(

new ImageIcon(

getClass().getClassLoader()

.getResource( "res/dirt.jpg" )

),

0, 128, 256

);

pt.addTexture(

new ImageIcon(

getClass().getClassLoader()

.getResource( "res/highest.jpg" )

),

128, 256, 374

);

pt.createTexture(32);

// 將紋理賦予地形

ts = display .getRenderer().createTextureState();

Texture t1 = TextureManager. loadTexture (

pt.getImageIcon().getImage(),

Texture.MinificationFilter. Trilinear ,

Texture.MagnificationFilter. Bilinear ,

true

);

ts .setTexture(t1, 0);

tb .setRenderState( ts );

}

protected void initSystem() {

// 保存屬性信息

width = settings .getWidth();

height = settings .getHeight();

depth = settings .getDepth();

freq = settings .getFrequency();

fullscreen = settings .isFullscreen();

try {

display = DisplaySystem. getDisplaySystem (

settings .getRenderer()

);

display .createWindow(

width , height , depth , freq , fullscreen

);

cam = display .getRenderer().createCamera( width , height );

} catch (JmeException e){

e.printStackTrace();

System. exit (-1);

}

// 設置背景為黑色

display .getRenderer().setBackgroundColor(ColorRGBA. black );

// 初始化攝像機

cam .setFrustumPerspective(

45.0f,

( float ) width /( float ) height ,

1f,

1000f

);

Vector3f loc = new Vector3f(500f,150f,500f);

Vector3f left = new Vector3f(-1.0f,0.0f,0.0f);

Vector3f up = new Vector3f(0.0f,1.0f,0.0f);

Vector3f dir = new Vector3f(0.0f,0.0f,-1.0f);

// 將攝像機移到正確位置和方向

cam .setFrame(loc, left, up, dir);

// 我們改變自己的攝像機位置和視錐的標志

cam .update();

// 獲取一個高分辨率用于 FPS 更新

timer = Timer. getTimer ();

display .getRenderer().setCamera( cam );

KeyBindingManager. getKeyBindingManager ().set(

"exit" ,

KeyInput. KEY_ESCAPE

);

}

/*

* 如果分辨率改變將被調用

*/

protected void reinit() {

display .recreateWindow( width , height , depth , freq , fullscreen );

}

/*

* 繪制場景圖

*/

protected void render( float interpolation) {

// 清除屏幕

display .getRenderer().clearBuffers();

display .getRenderer().draw( scene );

}

/*

* update 期間,我們只需尋找 Escape 按鈕

* 并更新 timer 去獲取幀率

*/

protected void update( float interpolation) {

// 更新 timer 去獲取幀率

timer .update();

interpolation = timer .getTimePerFrame();

// Escape 被按下時,我們退出游戲

if (KeyBindingManager. getKeyBindingManager ()

.isValidCommand( "exit" )

){

finished = true ;

}

}

}

jMonkeyEngine譯文 FlagRush3——創建地形


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 狠狠操狠狠干 | 二性视频 | 日本韩国欧美一区 | 亚洲精品第四页中文字幕 | 国产成人精品久久免费动漫 | 亚洲视屏在线 | 国产精品美女在线 | 久久免费国产精品一区二区 | 91精品国产福利尤物免费 | 亚洲人成影院在线高清 | 四虎影视884a精品国产古代 | 我要看免费的毛片 | 亚洲国产精品a一区 | 美女天天干 | 国产成人精品视频免费大全 | 日本毛片大全 | 国产精品公开免费视频 | 日韩欧美亚洲每日更新网 | 国产精品久久久久久久久久免费 | 亚洲国产综合人成综合网站00 | 国产精品一区二 | 看黄色免费网站 | 亚洲精品国产第一综合99久久 | 波多结衣一区二区三区 | 婷婷欧美| 草草影院国产 | 国产乱人视频在线播放不卡 | 欧美一级毛片免费大全 | 日日撸夜夜干 | 天天插狠狠干 | 偷亚洲偷国产欧美高清 | 99久久99久久精品免费看子 | 国产人成午夜免视频网站 | 欧美综合图 | 精品一区 二区三区免费毛片 | 精品国产一区二区三区四区不 | 国产精品麻豆a啊在线观看 国产精品麻豆高清在线观看 | 99精品久久99久久久久 | 一区二区伦理 | 国产精品亚洲视频 | 国产精品亚洲欧美日韩一区在线 |