首页 > 解决方案 > 在 JMonkeyEngine 中,如何在场景前拥有 FPS 风格的武器

问题描述

Aka 我可以在主场景前面有一个 3d 场景而没有被剪裁。

Aka 我的武器前部一直被我游戏中的场景隐藏

情况

我有一个由 JMonkey 渲染的 3d 场景,另外还有玩家持有的 3d 武器。此外,玩家可能会站在离墙壁很近的地方,以至于他们可能(如果实际处理的话)将枪头穿过墙壁。这意味着如果枪“通过航位推算”放置在场景中,使其看起来正确,枪的末端会被剪掉并且看起来很愚蠢。

因为这是一个 3d 对象(可以旋转或移动),所以我不能只使用 2d 图像并将其放入 gui 层

标签: javajmonkeyengine

解决方案


创建额外的相机和视口来支持这些额外的图形

在 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 不要进行任何深度测试


推荐阅读