【问题标题】:BufferGeometry indices issueBufferGeometry 索引问题
【发布时间】:2016-02-04 00:04:22
【问题描述】:

我正在尝试将我在 openFrameworks 中制作的一些代码移植到 THREE.JS 中。该代码使用柏林噪声生成景观。我这样做是为了首先创建一个静态索引数组,然后将顶点的位置放置在一个方形网格中,每个网格都位移一个指定的距离。这样可以移动阵列中顶点的位置(上、下、左或右),以便当相机移动时,可以更新风景并根据相机移动的方向生成新的风景条。

对于每个顶点,将 6 个索引添加到索引数组中,它们引用两个相邻的三角形。我不想浪费内存为每个三角形存储每个顶点的副本。

例如,例如

v12  v11  v10
*----*----*
|\   |\   |
| \  | \  |
|  \ |  \ |
|   \|   \|
*----*----*
v02  v01  v00

例如在顶点 v00 处,添加索引 {v00, v10, v11} 和 {v00, v11, v01} 等。

在我的 openFrameworks 代码中,这一切都很完美!经过很多麻烦后,我终于在 THREE.js 中工作了,但是我注意到,一旦我增加顶点的数量,一切都开始变得奇怪 - 三角形连接(看起来)到处都是,还有一大块的顶点开始被跳过。目前,任何高达并包括 256*256 网格大小的东西都可以正常工作,但是一旦我增加任何更高的值,我就会开始看到所有的人工制品。

我认为这可能是偏移的问题,但我真的不明白这意味着什么,或者如何用我的代码实现它。我见过其他人在按顺序定义索引时成功使用它 (0, 1, 2, 3, ... ),而是为每个三角形使用 3 个单独的顶点(并按顺序为每个三角形添加三个顶点) .我似乎无法让同样的事情发挥作用。

有什么想法吗?我在下面有我的代码以防万一。你可以看到我注释掉偏移的部分。

var 风景 = { 大小:0, 块大小:21845, 距离:0, 几何:空, 网格:空, 职位:空, 法线:空, 颜色:空, 指数:空,

generateVertex: function( r, c )
{
    var pos, color;

    // Set position
    pos = new THREE.Vector3();
    pos.x = this.distance * c;
    pos.z = this.distance * r;
    pos.y = -2 + 5*simplex.noise2D( 0.1*pos.x, 0.1*pos.z );

    // Set color
    color = new THREE.Color();
    color.setRGB( Math.random(1), 0, 0 );

    this.vertices.setXYZ( r * this.size + c, pos.x, pos.y, pos.z );
    this.colors.setXYZ( r * this.size + c, color.r, color.g, color.b );
},

generateIndices: function( i, r, c )
{
    this.indices[ i ] = ( r * this.size ) + c;
    this.indices[ i + 1 ] = ( ( r + 1 ) * this.size ) + c;
    this.indices[ i + 2 ] = ( ( r + 1 ) * this.size ) + ( c + 1 );

    this.indices[ i + 3 ] = ( r * this.size ) + c;
    this.indices[ i + 4 ] = ( ( r + 1 ) * this.size ) + ( c + 1 );
    this.indices[ i + 5 ] = ( r * this.size ) + ( c + 1 );

    /*this.indices[ i ] =  ( ( r * this.size ) + c ) % ( 3 * this.chunkSize );
    this.indices[ i + 1 ] = ( ( ( r + 1 ) * this.size ) + c ) % ( 3 * this.chunkSize );
    this.indices[ i + 2 ] = ( ( ( r + 1 ) * this.size ) + ( c + 1 ) ) % ( 3 * this.chunkSize );

    this.indices[ i + 3 ] = ( ( r * this.size ) + c ) % ( 3 * this.chunkSize );
    this.indices[ i + 4 ] = ( ( ( r + 1 ) * this.size ) + ( c + 1 ) ) % ( 3 * this.chunkSize );
    this.indices[ i + 5 ] = ( ( r * this.size ) + ( c + 1 ) ) % ( 3 * this.chunkSize ); */   
},

generatePoint: function( x, z )
{

},

generate: function( size, distance )
{        
    var sizeSquared, i;
    sizeSquared = size * size;
    i = 0;
    this.size = size;
    this.distance = distance;

    // Create buffer geometry
    this.geometry = new THREE.BufferGeometry();

    this.indices = new Uint16Array( 6*(size-1)*(size-1) );

    this.vertices = new THREE.BufferAttribute( new Float32Array( sizeSquared * 3 ), 3 );
    this.colors = new THREE.BufferAttribute( new Float32Array( sizeSquared * 3 ), 3 );

    // Generate points
    for( var r = 0; r < size; r = r + 1 )
    {
        for( var c = 0; c < size; c = c + 1 )
        {
            this.generateVertex( r, c );

            if( (r < size - 1) && (c < size - 1) )
            {
                this.generateIndices( i, r, c );
                i = i + 6;
            }
        }
    }

    // Set geometry
    this.geometry.addAttribute( 'index', new THREE.BufferAttribute( this.indices, 1 ) );
    this.geometry.addAttribute( 'position', this.vertices );
    this.geometry.addAttribute( 'color', this.colors );        

    //
    /*this.geometry.offsets = [];

    var triangles = 2 * ( size - 1 ) * ( size - 1 );
    var offsets = triangles / this.chunkSize;

    for( var j = 0; j < offsets; j = j + 1 )
    {
        var offset =
        {
            start: j * this.chunkSize * 3,
            index: j * this.chunkSize * 3,
            count: Math.min( triangles - ( j * this.chunkSize ), this.chunkSize ) * 3
        };

        this.geometry.offsets.push( offset );
    }*/

    var material = new THREE.MeshBasicMaterial( {vertexColors: THREE.VertexColors} );
    //var material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors });

    this.geometry.computeBoundingSphere();

    this.mesh = new THREE.Mesh( this.geometry, material );
    scene.add( this.mesh );

}

【问题讨论】:

    标签: javascript opengl-es three.js buffer-geometry


    【解决方案1】:

    WebGL 基于不支持 32 位索引缓冲区的 OpenGL ES 2.0,因此一旦您拥有超过 256 * 256 个顶点,索引缓冲区就无法再处理所有这些。

    来自OpenGL ES 2.0 Standard(第 2.8 节顶点数组):

    支持 ubyte 和 ushort 索引的索引支持。支持 OpenGL ES 2.0 不需要用于 uint 索引。如果 实现支持 uint 索引,它将导出 OES 元素 index - uint 扩展。

    假设这是您可以通过获取并检查 OES_element_index_uint extension 来启用 32 位索引缓冲区的问题。

    var uintExt = gl.getExtension("OES_element_index_uint");
    if (!uintExt) {
       alert("Sorry, this app needs 32bit indices and your device or browser doesn't appear to support them");
       return;
    }
    

    根据webglstats.com 93.5% 的机器支持扩展。


    您需要更改 generate 函数以创建 32 位数组:

    this.indices = new Uint16Array( 6*(size-1)*(size-1) );
    

    应该是:

    this.indices = new Uint32Array( 6*(size-1)*(size-1) );
    

    我对@9​​87654324@ 进行了快速研究,看起来它会检查索引数组的类型,如果您使用Uint32Array,它会将gl.UNSIGNED_INT 传递给glDrawElements

    【讨论】:

    • 感谢您的解释!是的,在 256 * 256 个顶点之后似乎确实发生了一些奇怪的事情。我尝试了一些代码,但它似乎不起作用,除非我必须进行一些其他更改。我不确定其他地方是否有问题,但已经看到人们索引偏移量来解决这个问题。但对于我的特定设置,它似乎不起作用,我不知道为什么。
    • 您的drawElements 电话是什么样的?要使用 32 位索引,您必须将 gl.UNSIGNED_INT 之类的东西作为第三个参数传递,但我认为 WebGL 没有它(虽然我不确定 - 我实际上并没有使用它)。
    • @gman 你知道你是否真的可以使用它吗?根据msdn.microsoft.com/en-us/library/ie/dn302396(v=vs.85).aspx,类型参数必须是gl.UNSIGNED_SHORT。我想你可以通过传入你自己的常量来避免它。在我的平台上,它被定义为 0x1405(十进制为 5125)。不确定它是否在所有地方都定义相同。
    • 正如我简要提到的,我正在使用 THREE.JS。我对它还不太熟悉,但似乎有很多抽象可以让事情变得更容易。我实际上并没有直接控制如何绘制任何东西。事实上,我什至没有一个draw call!您只需将所有内容添加到场景中,然后调用要渲染的场景。
    • @jacknkandy 我已经更新了答案,提供了一些可能有帮助的信息。
    猜你喜欢
    • 2018-10-09
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多