黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

jMonkeyEngine譯文 FlagRush3——?jiǎng)?chuàng)建地形

系統(tǒng) 2749 0

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

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

jME 版本 jME_2.0.1_Stable

開(kāi)發(fā)工具: MyEclipse8.5

操作系統(tǒng): Window7/Vista

這個(gè)向?qū)е形覀兩婕暗揭恍┖猛娴模覀儗槲覀兊挠螒蚣虞d地形(下文將使用 Terrain 代替)。這里對(duì)于我想要的類(lèi)型的 terrain 有一些要求:

l 每次隨機(jī)

l 不需太多三角形

l 為了跳躍“崎嶇”

l 對(duì)于快速的交通工具足夠大

我們將在第二課中的框架上構(gòu)建。首先,由清除 Sphere 渲染代碼開(kāi)始。我們不再需要這個(gè)例子。你現(xiàn)在應(yīng)該有相當(dāng)干凈的框架用于工作。現(xiàn)在,我們將創(chuàng)建的地形會(huì)相當(dāng)大。所以我想改變 Camera 的位置保證地形在視野里面。因此,在 initSystem 中作出如下改變:

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

改為:

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

這向上、遠(yuǎn)、后移動(dòng),確保我們對(duì)地形有恰當(dāng)?shù)囊曇啊?

現(xiàn)在,在 initGame 方法里面我們將加入一個(gè)對(duì)新方法的調(diào)用,這為這個(gè) scene 增加一個(gè) TerrainBlock 。這個(gè) TerrainBlock 叫做 tb 并應(yīng)該在類(lèi)頂部定義。這個(gè)新的方法叫做 buildTerrain 并應(yīng)該在增加 tb scene 之前調(diào)用。你應(yīng)該像下面一樣:

protected void initGame() {

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

buildTerrain();

scene .attachChild( tb );

// 更新 scene 用于渲染

scene . updateGeometricState (0.0f, true );

scene .updateRenderState();

}

這引導(dǎo)我們到這個(gè)向?qū)У暮诵模? buildTerrain

這里有我們 terrain 創(chuàng)建的核心:

1、 創(chuàng)建一個(gè) heightmap

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

3、 生成基于高度的紋理

3.1 、創(chuàng)建一個(gè) heightmap

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

我們將創(chuàng)建一個(gè) MidPointHeightMap ,它使用中點(diǎn)取代不規(guī)則碎片。這將允許地形足夠有趣和真實(shí),為我們提供了一些顛簸和跳躍。

創(chuàng)建這個(gè) heightmap 很直截了當(dāng),在我們 buildTerrain 方法中的第一行:

/**

* 創(chuàng)建 heightmap terrainBlock

*/

private void buildTerrain() {

// 生成隨機(jī)地形數(shù)據(jù)

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

……

}

我們調(diào)用 MidPointHeightMap 的構(gòu)造方法創(chuàng)建一個(gè)新的 heightMap 對(duì)象。它只需要 2 個(gè)參數(shù):大小和粗糙程度。

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

我們將定義一個(gè) terrain 縮放因數(shù)。這將簡(jiǎn)單拉伸或擠壓 mesh 以滿(mǎn)足我們的需求。所以,增加:

// 縮放數(shù)據(jù)

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

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

3.2 、生成 Terrain Mesh

現(xiàn)在,我們已經(jīng)設(shè)置好了數(shù)據(jù),我們能真正創(chuàng)建 mesh 。我們將創(chuàng)建一個(gè) TerrainBlock ,它是一個(gè)簡(jiǎn)單的 Geometry 。這個(gè)將增加到 scene 里,就像我們之前增加 Sphere 那樣。

// 創(chuàng)建一個(gè) terrain block

tb = new TerrainBlock(

"terrain" ,

heightMap.getSize(),

terrainScale,

heightMap.getHeightMap(),

new Vector3f(0, 0, 0)

);

tb . setModelBound ( new BoundingBox());

tb .updateModelBound();

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

我們接著設(shè)置了 terrain BoundingVolume

你現(xiàn)在或許能繼續(xù)并運(yùn)行游戲,看到類(lèi)似下面的一些東西:

jMonkeyEngine譯文 FlagRush3——?jiǎng)?chuàng)建地形

這里并不能看到很多東西,因?yàn)? terrain 僅是一大塊白色。我們需要應(yīng)用 texture 去讓它有一點(diǎn)層次感。

3.3 、生成 Texture

創(chuàng)建一個(gè) Texture 將通過(guò)使用 ProceduralTextureGenerator 。這個(gè)類(lèi)將生成一個(gè)基于 heightmap 的高度的紋理,并在多個(gè) texture 間混合。一個(gè) texture 被指定到一個(gè)高度區(qū)域,而它們之后混合進(jìn)單一的 texture map 。這允許我們很容易創(chuàng)建一個(gè)看起來(lái)相當(dāng)真實(shí)的 Terrain 。在我們的例子中,我們將使用 3 texture ,一個(gè)用于低區(qū)域的草地 texture ,中部的巖石和高處的雪。

// 通過(guò)三個(gè)紋理生成地形紋理

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);

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

addTexture 接受 ImageIcon 對(duì)象去定義 texture 數(shù)據(jù)。在這個(gè)例子中,我們通過(guò)我們的類(lèi)的 getResource 方法獲取到的 URL 創(chuàng)建 ImageIcon 。這個(gè)在 classpath 里面搜索 images 。這當(dāng)然不是一定要這么做, ImageIcon 能在其它某個(gè)地方被創(chuàng)建,它將適用于你應(yīng)用程序。

createTexture 真正創(chuàng)建了我們需要使用的 texture 。在這個(gè)例子中,我讓它生成一個(gè) 32X32 像素的 texture 。雖然這個(gè)看起來(lái)很小,但是我并不需要它的細(xì)節(jié)。這只是用于基礎(chǔ)顏色,之后我們將創(chuàng)建更詳細(xì)的 texture 和對(duì)象。

例如:在運(yùn)行游戲期間,我保存了一個(gè)生成的 texture 。它看起來(lái)像這樣:

你能看到三個(gè) texture grassb dirt highest )是怎樣被混合為一個(gè)單一的 texture 。白色的區(qū)域?qū)?huì)是 terrain 的高點(diǎn),而 grass 將是 terrain 的低點(diǎn)。

現(xiàn)在我們已經(jīng)生成了 Terrain ,我們把它放入一個(gè) TextureState 并把它應(yīng)用到 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 );

通過(guò)這樣, terrain 就能正常工作了。你現(xiàn)在能運(yùn)行游戲并看到類(lèi)似下面的:

jMonkeyEngine譯文 FlagRush3——?jiǎng)?chuàng)建地形

注意: 我一直說(shuō)類(lèi)似,因?yàn)槲覀兪褂玫氖请S機(jī)方法去生成 terrain 。所以它每次都將不同。

3.4 、創(chuàng)建燈光( Light

盡管使用了 texture ,我們依然很難辨別出 terrain 。那是因?yàn)闆](méi)有燈光和陰影幫助我們辨別 terrain 的部分。所以,讓我們繼續(xù)并增加一個(gè)“太陽(yáng)”。增加一個(gè) buildLighting 到你的 initGame 。我們將增加一個(gè) DirectionalLight 去照耀 terrain 。增加 light 2 部分。首先,創(chuàng)建 DirectionalLight ,然后把它增加到 LightState

private void buildLighting() {

/* 設(shè)置一個(gè)基礎(chǔ)、默認(rèn)燈光 */

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);

}

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

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

jMonkeyEngine譯文 FlagRush3——?jiǎng)?chuàng)建地形

3.5 、總結(jié)

我們現(xiàn)在擁有了一個(gè)可以在上面奔跑的平面。然而,那還是存在令人討厭的黑色背景。下一節(jié)課我們將適當(dāng)關(guān)注個(gè)問(wèn)題。

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 對(duì)象,用于觀看 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() {

/* 設(shè)置一個(gè)基礎(chǔ)、默認(rèn)燈光 */

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);

}

/**

* 創(chuàng)建 heightmap terrainBlock

*/

private void buildTerrain() {

// 生成隨機(jī)地形數(shù)據(jù)

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

// 縮放數(shù)據(jù)

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

// 創(chuàng)建一個(gè) terrain block

tb = new TerrainBlock(

"terrain" ,

heightMap.getSize(),

terrainScale,

heightMap.getHeightMap(),

new Vector3f(0, 0, 0)

);

tb .setModelBound( new BoundingBox());

tb .updateModelBound();

// 通過(guò)三個(gè)紋理生成地形紋理

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);

}

// 設(shè)置背景為黑色

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

// 初始化攝像機(jī)

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);

// 將攝像機(jī)移到正確位置和方向

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

// 我們改變自己的攝像機(jī)位置和視錐的標(biāo)志

cam .update();

// 獲取一個(gè)高分辨率用于 FPS 更新

timer = Timer. getTimer ();

display .getRenderer().setCamera( cam );

KeyBindingManager. getKeyBindingManager ().set(

"exit" ,

KeyInput. KEY_ESCAPE

);

}

/*

* 如果分辨率改變將被調(diào)用

*/

protected void reinit() {

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

}

/*

* 繪制場(chǎng)景圖

*/

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();

// 當(dāng) Escape 被按下時(shí),我們退出游戲

if (KeyBindingManager. getKeyBindingManager ()

.isValidCommand( "exit" )

){

finished = true ;

}

}

}

jMonkeyEngine譯文 FlagRush3——?jiǎng)?chuàng)建地形


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

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

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論