java - 在 JMonkeyEngine 中,如何在场景前拥有 FPS 风格的武器
问题描述
Aka 我可以在主场景前面有一个 3d 场景而没有被剪裁。
Aka 我的武器前部一直被我游戏中的场景隐藏
情况
我有一个由 JMonkey 渲染的 3d 场景,另外还有玩家持有的 3d 武器。此外,玩家可能会站在离墙壁很近的地方,以至于他们可能(如果实际处理的话)将枪头穿过墙壁。这意味着如果枪“通过航位推算”放置在场景中,使其看起来正确,枪的末端会被剪掉并且看起来很愚蠢。
因为这是一个 3d 对象(可以旋转或移动),所以我不能只使用 2d 图像并将其放入 gui 层
解决方案
创建额外的相机和视口来支持这些额外的图形
在 JMonkeyEngine 中,可以有多个视口并将它们叠加在一起以提供所描述的效果。每个视口在内部都是 3d 的,但视口本身是相互叠加的。
代码示例
设置东西的主类
public class Example extends SimpleApplication {
public static void main(String[] args){
Example app = new Example();
app.start(); // start the game
}
@Override
public void simpleInitApp() {
//this represents the "real world" in this example
Box b = new Box(1, 1, 1);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
geom.setMaterial(mat);
rootNode.attachChild(geom);
this.stateManager.attach(new UnderGui());
}
}
UnderGui 层,在 gui 层和主 3d 场景之间有一个 3d 场景
/**
* The under gui is for things like the held tool. Things that are kind of 3d but also want to be "over" everything
* else
*/
public class UnderGui extends AbstractAppState {
private Node root;
public UnderGui() {
}
@Override
public void initialize(AppStateManager stateManager, Application app )
{
root = new Node( "Under gui viewport Root" );
Camera originalCam = app.getCamera();
Camera cam = new Camera(originalCam.getWidth(), originalCam.getHeight());
//the default camera is an orthoganal camera, use the main cam to copy sensible camera properties
cam.setParallelProjection(originalCam.isParallelProjection());
cam.setFrustum(originalCam.getFrustumNear(), originalCam.getFrustumFar(), originalCam.getFrustumLeft(), originalCam.getFrustumRight(),originalCam.getFrustumTop(), originalCam.getFrustumBottom() );
cam.setFov(originalCam.getFov());
//camera is looking in a +Z direction. -X is right, +X is left. +Y is up
ViewPort view = app.getRenderManager().createMainView("Under gui ViewPort", cam);
view.setEnabled(true);
view.setClearFlags(false, true, false);
view.attachScene( root );
root.attachChild(createWeapon(app.getAssetManager()));
}
/**
* This just creates a red box to be a "weapon" as an example
* @return
*/
private Geometry createWeapon(AssetManager assetManager){
Box b = new Box(1, 1, 1); // create cube shape
Geometry geom = new Geometry("Box", b); // create cube geometry from the shape
Material mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md"); // create a simple material
mat.setColor("Color", ColorRGBA.Blue); // set color of material to blue
geom.setMaterial(mat); // set the cube's material
geom.setLocalTranslation(-2,0,2);
return geom;
}
@Override
public void render(RenderManager rm) {
root.updateGeometricState();
}
@Override
public void update( float tpf ) {
root.updateLogicalState(tpf);
}
}
这也可以用于任何“看穿墙壁的能力”覆盖
替代不良解决方案;设置深度测试
您也可以将武器放在主场景中并设置geometry.getMaterial().getAdditionalRenderState().setDepthTest(false);
。然而,这是一个不太好的选择,因为它要求武器随着摄像机位置和方向的变化而不断移动,并且只能处理“简单”的 3D 叠加,就好像武器的一部分在另一部分前面(例如枪托)在触发器前面)渲染的位是随机的,因为您已要求 JME 不要进行任何深度测试
推荐阅读
- java - 仅从测试套件而不是单个类运行 Junit 测试用例
- ios - 如何更改 LAContext 的状态栏样式
- java - 如何知道Android手机上是否启用了数据保护程序
- python - 如何获得 100 个数字列表,每个列表包含 5 个浮动数字,范围从 1 到 5,但每个列表中没有重复
- mysql - SQL 查询报表内连接
- wordpress - Wordpress 将旧 URL 重定向到新 URL
- android - 如何从列表中删除“”[]
- excel - 使用 Selenium 引用打开的 Chrome 窗口
- reactjs - NextJS Router & Jest:如何模拟路由器更改事件
- c - 取消引用 NULL 指针 'head' ,'tail