视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
jMonkeyEngine译文FlagRush8(2)增加随机的Flag
2020-11-09 07:43:20 责编:小采
文档


8.6 、为旗杆增加布 我想要让 Flag 看起来像 很好,像 Flag 。为了这么做,我们需要模拟一个布的 Flag , attach 到旗杆。有什么更好的方式完成这件事,还是使用 jME 的 ClothPatch 功能。这将允许我们去创建一个弹簧( spring )点的 matrix ,它们由不同方

8.6、为旗杆增加布

我想要让Flag看起来像…很好,像Flag。为了这么做,我们需要模拟一个布的Flag,attach到旗杆。有什么更好的方式完成这件事,还是使用jME的ClothPatch功能。这将允许我们去创建一个弹簧(spring)点的matrix,它们由不同方向的外力(force)调整(引力和风力)。我已经为这个向导创建了我自己的风力,而我们将在下面讨论。

首先,增加对象到Flag类。

//用于制作Flag的Cloth

private ClothPatch cloth;

//风的参数

privatefloatwindStrength = 15f;

private Vector3f windDirection = new Vector3f(0.8f, 0, 0.2f);

private SpringPointForce gravity,wind;

在Flag的构造参数中,我们将创建一个ClothPatch。这个Cloth将是25*25的matrix,给它一个相当详细的cloth。cloth上的点越多,它运行得越慢,所以你应该在flag的视觉外观和它对游戏的影响之间选个平衡点。25*25给我一个可接受的性能和外观的比例。在创建cloth之后,我们将增加我们的force。我们增加的第一个force是我们为这个向导创建的自定义的force,叫做RandomFlagWindForce。我们也将增加一个默认的重力它是由ClothUtils创建的,这将在风减小的时候把Flag拉下来。

//创建一个cloth patch 将处理我们flag

cloth = new ClothPatch("cloth", 25, 25, 1f, 10);

//将我们自定义的风力增加到cloth

wind = new RandomFlagWindForce(windStrength, windDirection);

cloth.addForce(wind);

//增加一个简单的重力

gravity = ClothUtils.createBasicGravity();

cloth.addForce(gravity);

由于cloth是标准的jME Spatial,我们和平常一样应用RenderState。我们将为Flag增加texture,使用jME monkey的logo。这个是一个让monkey的头在你脑海留下烙印的企图。

//创建一个将flag显示的texture,一起推进jME发展!

TextureState ts = DisplaySystem.getDisplaySystem()

.getRenderer().createTextureState();

ts.setTexture(

TextureManager.loadTexture(

Flag.class.getClassLoader()

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

Texture.MinificationFilter.Trilinear,

Texture.MagnificationFilter.Bilinear

)

);

cloth.setRenderState(ts);

当我开始增加一个flag到场景时,我对light非常不满意,因为flag大部分时间都是阴影。因此,我决定增加一个light,它只影响flag。这个light应该跟着Flag移动,并且根据Flag定位自己。因此,使用一个LightNode是最好的解决方案。LightNode允许你对待一个light就像scene中的其它元素一样,通过移动light的父亲node移动它。

//我们将使用一个LightNode去给Flag增加light,使用Node

//是因为它允许light随着FLag移动

//首先创建light

PointLight dr = new PointLight();

dr.setEnabled(true);

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

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

dr.setLocation(new Vector3f(0.5f, -0.5f, 0));

//接下来是state

LightState lightState = DisplaySystem.getDisplaySystem()

.getRenderer().createLightState();

lightState.setEnabled(true);

lightState.setTwoSidedLighting(true);

lightState.attach(dr);

setRenderState(lightState);

//最后是结点

LightNode lightNode = new LightNode("light");

lightNode.setLight(dr);

lightNode.setLocalTranslation(new Vector3f(15,0,0));

attachChild(lightNode);

cloth.setRenderState(lightState);

Flag有一点和前面不同,那就是我们想看到它所有面的三角形。前面,我们设置了scene的CullState去剔除所有背后的三角形。因此,我们将增加另一个CUllState给cloth,让它不要剔除任何三角形。它将看到所有的三角形。

//我们想看flag所有的面,所以我们将关闭Cull

CullState cs = DisplaySystem.getDisplaySystem()

.getRenderer().createCullState();

cs.setCullFace(CullState.Face.None);

cloth.setRenderState(cs);

this.attachChild(cloth);

下一步,我们需要为cloth创建一些点去固定它。如果我们不这么做,整个cloth将在force应用于它身上时被“吹走”。我们需要在旗杆上attach一些点去保住cloth。我们通过设置点的质量为无穷大来这么做。因此,没有任何force能移走它。为了模拟这个方法,一个flag被attach到一个旗杆,flag上边缘的一些和旗杆接触的点将被attach,下面的也是。这些点被设置在一个基础的二维matrix中,所以我们将attach点(0,1,2,3,4)到旗杆,点(500,525,550,575,600)也一样。我们也调整这些点在y的位置让它们偏移,从而让cloth形成一点褶皱。

//我们需要attach一些点到旗杆,这些点不应该被移动。

//因此,我们将attach顶部和底部的5个点去让它们足够高而

//且没有任何forece能移动它。我也稍微移动这些点的位置去

//形成褶皱让它更真实。

for(int i=0; i<5; i++){

cloth.getSystem().getNode(i*25).position.y *= .8f;

cloth.getSystem().getNode(i*25)

.setMass(Float.POSITIVE_INFINITY);

}

for(int i=24; i>19; i--){

cloth.getSystem().getNode(i*25).position.y *= .8f;

cloth.getSystem().getNode(i*25)

.setMass(Float.POSITIVE_INFINITY);

}

最后,我创建自定义风力。为了模仿旗杆上flag的效果,我们也随机化风向。风向将基于它之前的位置

/**

* 在每次update cloth时调用。将轻微调整风向和强度、

*/

publicvoid apply(float dt, SpringPoint node) {

windDirection.x += dt * (FastMath.nextRandomFloat() - .5f);

windDirection.z += dt * (FastMath.nextRandomFloat() - .5f);

windDirection.normalize();

float tStr = FastMath.nextRandomFloat() * strength;

node.acceleration.addLocal(

windDirection.x * tStr,

windDirection.y * tStr,

windDirection.z * tStr

);

}

通过那样,我们现在有一个看起来真实的flag,而且我们以自己的方式去为我们游戏中添加元素。下一课,我们只需能获取flag。

8.7、源码

import java.io.IOException;

import java.net.URL;

import java.util.HashMap;

import javax.swing.ImageIcon;

import com.jme.app.BaseGame;

import com.jme.bounding.BoundingBox;

import com.jme.image.Texture;

import com.jme.input.ChaseCamera;

import com.jme.input.InputHandler;

import com.jme.input.KeyBindingManager;

import com.jme.input.KeyInput;

import com.jme.input.thirdperson.ThirdPersonMouseLook;

import com.jme.light.DirectionalLight;

import com.jme.math.FastMath;

import com.jme.math.Vector3f;

import com.jme.renderer.Camera;

import com.jme.renderer.ColorRGBA;

import com.jme.renderer.Renderer;

import com.jme.scene.Node;

import com.jme.scene.Skybox;

import com.jme.scene.shape.Box;

import com.jme.scene.state.CullState;

import com.jme.scene.state.LightState;

import com.jme.scene.state.TextureState;

import com.jme.scene.state.ZBufferState;

import com.jme.system.DisplaySystem;

import com.jme.system.JmeException;

import com.jme.util.TextureManager;

import com.jme.util.Timer;

import com.jme.util.export.binary.BinaryImporter;

import com.jmex.model.converters.MaxToJme;

import com.jmex.terrain.TerrainBlock;

import com.jmex.terrain.util.MidPointHeightMap;

import com.jmex.terrain.util.ProceduralTextureGenerator;

publicclass Lesson8 extends BaseGame{

privateintwidth,height;

privateintfreq,depth;

privatebooleanfullscreen;

//我们的camera对象,用于观看scene

private Camera cam;

protected Timer timer;

private Node scene;

private TextureState ts;

private TerrainBlock tb;

private ForceFieldFence fence;

private Skybox skybox;

private Vehicle player;

private ChaseCamera chaser;

private InputHandler input;

//保存terrain的任何一个给出点的法向

private Vector3f normal = new Vector3f();

privatefloatagl;

private Flag flag;

publicstaticvoid main(String[] args) {

Lesson8 app = new Lesson8();

java.net.URL url = app.getClass().getClassLoader().getResource("res/logo.png");

app.setConfigShowMode(ConfigShowMode.AlwaysShow,url);

app.start();

}

/*

* 清除texture

*/

protectedvoid cleanup() {

ts.deleteAll();

}

protectedvoid initGame() {

display.setTitle("Flag Rush");

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

ZBufferState buf = display.getRenderer().createZBufferState();

buf.setEnabled(true);

buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);

scene.setRenderState(buf);

buildTerrain();

buildFlag();

buildLighting();

buildEnvironment();

createSkybox();

buildPlayer();

buildChaseCamera();

buildInput();

CullState cs = display.getRenderer().createCullState();

cs.setCullFace(CullState.Face.Back);

scene.setRenderState(cs);

//更新scene用于渲染

scene.updateGeometricState(0.0f, true);

scene.updateRenderState();

}

privatevoid buildFlag() {

flag = new Flag(tb);

scene.attachChild(flag);

flag.placeFlag();

}

privatevoid buildInput() {

input = new FlagRushInputHandler(

player,

settings.getRenderer()

);

}

privatevoid buildChaseCamera() {

HashMap props = new HashMap();

props.put(ThirdPersonMouseLook.PROP_MAXROLLOUT, "6");

props.put(ThirdPersonMouseLook.PROP_MINROLLOUT, "3");

props.put(

ThirdPersonMouseLook.PROP_MAXASCENT,

""+45*FastMath.DEG_TO_RAD

);

props.put(

ChaseCamera.PROP_INITIALSPHERECOORDS,

new Vector3f(5,0,30*FastMath.DEG_TO_RAD)

);

chaser = new ChaseCamera(cam, player, props);

chaser.setMaxDistance(8);

chaser.setMinDistance(2);

}

privatevoid buildPlayer() {

Node model = null;

URL maxFile = Lesson8.class.getClassLoader()

.getResource("res/bike.jme");

try {

model = (Node)BinaryImporter.getInstance().load(

maxFile.openStream()

);

model.setModelBound(new BoundingBox());

model.updateModelBound();

model.setLocalScale(0.0025f);

} catch (IOException e1) {

e1.printStackTrace();

}

//设置Vehicle的属性(这些数字能被认为是单元/秒 Unit/S)

player = new Vehicle("Player Node",model);

player.setAcceleration(15);

player.setBraking(25);

player.setTurnSpeed(2.5f);

player.setWeight(25);

player.setMaxSpeed(25);

player.setMinSpeed(15);

player.setLocalTranslation(new Vector3f(100,0, 100));

player.updateWorldBound();

player.setRenderQueueMode(Renderer.QUEUE_OPAQUE);

scene.attachChild(player);

scene.updateGeometricState(0, true);

agl = ((BoundingBox)(player.getWorldBound())).yExtent;

}

privatevoid createSkybox() {

skybox = new Skybox("skybox",10,10,10);

Texture north = TextureManager.loadTexture(

Lesson8.class.getClassLoader()

.getResource("res/texture/north.jpg"),

Texture.MinificationFilter.BilinearNearestMipMap,

Texture.MagnificationFilter.Bilinear

);

Texture south = TextureManager.loadTexture(

Lesson8.class.getClassLoader()

.getResource("res/texture/south.jpg"),

Texture.MinificationFilter.BilinearNearestMipMap,

Texture.MagnificationFilter.Bilinear

);

Texture east = TextureManager.loadTexture(

Lesson8.class.getClassLoader()

.getResource("res/texture/east.jpg"),

Texture.MinificationFilter.BilinearNearestMipMap,

Texture.MagnificationFilter.Bilinear

);

Texture west = TextureManager.loadTexture(

Lesson8.class.getClassLoader()

.getResource("res/texture/west.jpg"),

Texture.MinificationFilter.BilinearNearestMipMap,

Texture.MagnificationFilter.Bilinear

);

Texture up = TextureManager.loadTexture(

Lesson8.class.getClassLoader()

.getResource("res/texture/top.jpg"),

Texture.MinificationFilter.BilinearNearestMipMap,

Texture.MagnificationFilter.Bilinear

);

Texture down = TextureManager.loadTexture(

Lesson8.class.getClassLoader()

.getResource("res/texture/bottom.jpg"),

Texture.MinificationFilter.BilinearNearestMipMap,

Texture.MagnificationFilter.Bilinear

);

skybox.setTexture(Skybox.Face.North, north);

skybox.setTexture(Skybox.Face.West, west);

skybox.setTexture(Skybox.Face.South, south);

skybox.setTexture(Skybox.Face.East, east);

skybox.setTexture(Skybox.Face.Up, up);

skybox.setTexture(Skybox.Face.Down, down);

skybox.preloadTextures();

scene.attachChild(skybox);

}

privatevoid buildEnvironment() {

fence = new ForceFieldFence("forceFieldFence");

//我们将手工做一些调整去让它更好适应terrain

//首先我们将实体“模型”放大

fence.setLocalScale(5);

//现在,让我们移动fence到terrain的高度并有一点陷入它里面

fence.setLocalTranslation(

new Vector3f(25,tb.getHeight(25,25)+10,25)

);

scene.attachChild(fence);

}

privatevoid 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.setEnabled(true);

lightState.attach(light);

scene.setRenderState(lightState);

}

/**

* 创建heightmap和terrainBlock

*/

privatevoid buildTerrain() {

//生成随机地形数据

MidPointHeightMap heightMap = new MidPointHeightMap(,1f);

//缩放数据

Vector3f terrainScale = new Vector3f(4, .0575f, 4);

//创建一个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, 384

);

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

//加载细节纹理并为2个terrain的texture设置组合模型

Texture t2 = TextureManager.loadTexture(

Lesson8.class.getClassLoader()

.getResource("res/Detail.jpg"),

Texture.MinificationFilter.Trilinear,

Texture.MagnificationFilter.Bilinear

);

ts.setTexture(t2, 1);

t2.setWrap(Texture.WrapMode.Repeat);

t1.setApply(Texture.ApplyMode.Combine);

t1.setCombineFuncRGB(Texture.CombinerFunctionRGB.Modulate);

t1.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);

t1.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);

t1.setCombineSrc1RGB(Texture.CombinerSource.PrimaryColor);

t1.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);

t2.setApply(Texture.ApplyMode.Combine);

t2.setCombineFuncRGB(Texture.CombinerFunctionRGB.AddSigned);

t2.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);

t2.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);

t2.setCombineSrc1RGB(Texture.CombinerSource.Previous);

t2.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);

tb.setRenderState(ts);

tb.setDetailTexture(1, 16);

tb.setRenderQueueMode(Renderer.QUEUE_OPAQUE);

scene.attachChild(tb var cpro_id = "u6292429";

下载本文
显示全文
专题