首先,我目前仍在使用Three.js r71(目前升级到最新版本会很痛苦)。也就是说,对于我的问题,我并没有想到太多改变,所以希望仍有希望。
我试图弄清楚如何在BufferGeometry中使用索引和drawcalls。我认为我98%,但有些事情没有点击。我创建了我的BufferGeometry,并用一行包含70000个顶点填充它(位置数组有210000个项目,颜色数组有210000个项目,索引数组有139998个项目((70000 - 1) * 2 = 139998 ✓)
)。
我知道我无法引用65535以上的索引,因此我使用geometry.drawcalls
将项目添加到BufferGeometry.addDrawCall
。那些对象是:
[{"start":0,"count":65535,"index":0},{"start":65535,"count":4465,"index":65535}]
现在,当我运行65535个顶点的示例(链接和代码)时,一切都按预期工作:出现红色螺旋。但是当我尝试使用70000顶点时,会发生奇怪的事情:我在控制台中看到一个错误(下面),并且出现较小的螺旋。
控制台错误:
GL错误:GL_INVALID_OPERATION:glDrawElements:尝试访问属性0中超出范围的顶点
我尝试重新对齐索引(从第56行开始的评论部分),但它遇到了同样的问题。我错过了一步吗?我需要填充一些其他开关或属性吗?
脚注:我尝试使用UInt32Array作为索引,但WebGL会引发类型错误。
JSFiddle: Line Indexing Test
代码:
var numVerts = 70000; // works with 65535
var hostDiv, scene, renderer, camera, controls, light;
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
function init() {
hostDiv = document.createElement('div');
hostDiv.setAttribute('id', 'host');
document.body.appendChild(hostDiv);
renderer = new THREE.WebGLRenderer({ antialias: true, preserverDrawingBuffer: true });
renderer.setSize(WIDTH, HEIGHT);
hostDiv.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 250;
controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.rotateSpeed = 5.0;
controls.dynamicDampingFactor = 0.5;
light = new THREE.PointLight(0xffffff, 1, Infinity);
light.position.copy(camera.position);
scene = new THREE.Scene();
scene.add(camera);
scene.add(light);
scene.add(createSpiral());
debugger;
animate();
}
function createSpiral(){
var positions = [],
indices = [],
colors = [];
var vec = new THREE.Vector3(1, 0, 0),
rotVec = new THREE.Vector3(0, 0, 1);
for(var idx = 0, fakeIdx = 0; idx < numVerts; ++idx){
// update position vector
vec.setLength((idx + 1) / 1000); // slowly spiral outward
vec.applyAxisAngle(rotVec, 0.01); // spin around the z-axis
positions.push(vec.x, vec.y, vec.z);
if(idx + 1 < numVerts){
indices.push(idx, idx + 1);
}
//if((idx % 65535) + 1 < numVerts){
// indices.push((idx % 65535), (idx % 65535) + 1);
//}
if(idx > 65535){
colors.push(0, 1, 0); // GREEN!
}
else{
colors.push(1, 0, 0); // RED!
}
}
bg = new THREE.BufferGeometry();
if(numVerts > 65535){
var remainingVerts = numVerts,
start = 0,
count = 0,
index = 0;
while(remainingVerts > 0){
count = (remainingVerts < 65535)? remainingVerts : 65535;
bg.addDrawCall(start, count, start);
start += 65535;
remainingVerts -= 65535;
}
}
bg.addAttribute('index', new THREE.BufferAttribute(new Uint16Array( indices ), 1));
bg.addAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3));
bg.addAttribute('color', new THREE.BufferAttribute(new Float32Array(colors), 3));
var mat = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors });
var spiral = new THREE.Line(bg, mat, THREE.LinePieces);
spiral.name = "SPIRAL";
debugger;
return spiral;
}
function render() {
light.position.copy(camera.position);
renderer.render(scene, camera);
controls.update();
}
function animate() {
requestAnimationFrame(animate);
render();
}
init();
&#13;
html *{
padding: 0;
margin: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
#host {
width: 100%;
height: 100%;
}
&#13;
<script src="https://rawgithub.com/mrdoob/three.js/f73593b00e3b2c927bb1a3236240cea5597166ec/build/three.js"></script>
<script src="http://threejs.org/examples/js/controls/TrackballControls.js"></script>
&#13;
答案 0 :(得分:1)
在r73中使用UInt32Array
对我来说很好。
在r73中,他们不会在材料中使用THREE.LineStrip
和THREE.LinePieces
,但有两个不同的类THREE.Line
和THREE.LineSegments
用于连续或分段绘制线条。
我做了一些其他的改变。我改为使用连续线而不是段,因为它节省了一半的索引量。我认为这也可能是你的问题之一。由于您为每个线段插入了2个索引,这意味着绘制32768个线段,您已达到最大65536个索引。
Here a fiddle,我更新了r73
请注意我的更改重要更改:
indices.push(idx);
bg.setIndex( new THREE.BufferAttribute( new Uint32Array( indices ), 1 ) );
var spiral = new THREE.Line(bg, mat);
我删除了不需要的代码行。
有趣的是,我只是注意到你甚至不需要索引。它作为非索引THREE.BufferGeometry
完全正常。如果我没有弄错的话,这可以为您节省所有麻烦,并且几乎可以让您拥有无限分......
Here another fiddle表明它没有大量的分数就能完全正常。
这也适用于 r71 。检查出here