我想只绘制相机可以看到的物体

时间:2015-09-24 19:10:28

标签: javascript three.js

我正在使用THREEJS建立一个基于perlin噪音发生器的动态生成的“我的世界”世界。

以下是我现在的距离:Block World

到目前为止,一切都很顺利,只有当我达到大约7,000个左右的'对象'时,我注意到极端的性能(帧率)问题。 当我将尺寸设置为最大64 * 64 * 6时,我的电路板通常会产生大约12-14万个对象(Perlin地图显然只使用了一部分最大块)。

我“想”我想要的只是绘制相机可以看到的块。我认为我会为其他块后面的块设置mesh.visible = false(从相机隐藏)。每一帧我都会检查以查看相机可见的块并设置它们的mesh.visible = true。

无论如何,我认为我想要完成的事情被称为“遮挡剔除”,但我找不到任何有关如何在ThreeJS中执行此操作的实例。

我有一个想法是对光线跟踪屏幕上的每个像素,并寻找与第一个对象的交叉点:

raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );

我认为即使我把它想出来,反正也可能会很慢。

我的另一个想法是将所有网格合并为一个。那很棒。我从中获得了令人难以置信的帧速率。不幸的是,我失去了单独操纵特定块的能力,它们独特的纹理也丢失了。我需要一种能够在合并的几何体中引用,更改材料和移除块的方法。 我不认为这是解决方案。

老实说,我希望有人可以解释我如何隐藏所有不可见的网格,因为它们完全落后于其他对象。

由于

编辑:关于建议实施截头剔除,我已经尝试了这个

            var counter = 0;
            //
            // Only draw objects that you can see... I think
            frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
            for (var i=0; i<world.length; i++) {
                for (var j=0; j<world[i].length; j++) {
                    for (var d=0; d<world[i][j].length; d++) {
                        if ( world[i][j][d].type !== -1 ) {
                            if ( frustum.intersectsObject( world[i][j][d].block ) ) {
                                world[i][j][d].block.visible = true;
                                counter++;
                            }
                        }
                    }
                 }
             }
            console.log(counter);

计数器表示任何时候可见块的数量明显低于块总数。然而,我的帧率由于使用这个并且试图在场景中移动而直线下降是无法忍受的。

1 个答案:

答案 0 :(得分:0)

private View focusedViewOnActionDown; private boolean touchWasInsideFocusedView; @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: focusedViewOnActionDown = getCurrentFocus(); if (focusedViewOnActionDown != null) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; focusedViewOnActionDown.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + focusedViewOnActionDown.getWidth(), coordinates[1] + focusedViewOnActionDown.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); touchWasInsideFocusedView = rect.contains(x, y); } break; case MotionEvent.ACTION_UP: if (focusedViewOnActionDown != null) { // dispatch to allow new view to (potentially) take focus final boolean consumed = super.dispatchTouchEvent(ev); final View currentFocus = getCurrentFocus(); // if the focus is still on the original view and the touch was inside that view, // leave the keyboard open. Otherwise, if the focus is now on another view and that view // is an EditText, also leave the keyboard open. if (currentFocus.equals(focusedViewOnActionDown)) { if (touchWasInsideFocusedView) { return consumed; } } else if (currentFocus instanceof EditText) { return consumed; } // the touch was outside the originally focused view and not inside another EditText, // so close the keyboard InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( focusedViewOnActionDown.getWindowToken(), 0); focusedViewOnActionDown.clearFocus(); return consumed; } break; } return super.dispatchTouchEvent(ev); }

如果您想以60 FPS绘制相当数量的立方体,这是唯一的解决方案。但是,不是将所有立方体合并为一个巨大的网格,而是将多维数据集组合并为一个块,并有多个块来代表您的世界。

Another idea I had was to merge all of the meshes together into one. That was great. I got incredible frame rates from this.

假设你有块系统设置,那么不要在多维数据集上进行单独操作,而是在块级别上进行操作。每当块中的多维数据集发生更改时,生成一个新的块网格数据并将该网格上传到GPU中。

Unfortunately I lost the ability to individually manipulate the specific blocks, and their unique textures were also lost. I'd need a way to be able to still reference, change materials for and remove blocks within that merged geometry. I don't think this is the solution.

你不能。使用基于CPU的剔除@ 60 FPS非常非常困难(在JS中不可能?)。你可以做的最好的是一个块 - 平截头体测试,以查看块是否在视口中。然后将其余部分留给GPU及其深度测试。