Three.js PointsMaterial 性能缓慢 - 大精灵/形状会降低性能

stm*_*lli 0 javascript performance webgl three.js

我正在处理大约 60,000 个顶点的点云。

如果我渲染云“查看它很小”,性能还可以,但是当我“放大”并在屏幕上看到大精灵/平面/点时,性能会下降。

这是使用 aPointsMaterial或 a RawShaderMaterialPoints对象或instancedBufferGeometry网格来实现的。

看起来,当渲染覆盖大部分画布的单个大形状时,性能会下降。

如果点具有透明纹理,性能会下降得更糟。

我记得在处理中渲染大的重叠透明图像时遇到了类似的问题。

gma*_*man 5

正如 Sedenion 提到的,您很可能会受到填充率限制。这意味着您绘制了太多像素。

GPU 的绘制速度有限。一般的非游戏玩家 GPU 只能以每秒 60 帧的速度绘制 6-10 个充满像素的屏幕。如果您绘制的像素多于该数量,即使这些像素是简单的像素(换句话说,即使您有简单的着色器),它也会运行得太慢。对于普通 3D 场景,通常会启用深度测试。通过首先绘制最近的物体,深度缓冲区将防止绘制后面的物体,这有助于加快速度。对于精灵来说,通常不使用深度测试。这意味着每个精灵的每个像素都会被绘制,即使它们重叠。如果您将绘制的像素数量加起来,您会发现您很快就绘制了太多像素。

POINT这是一个简单的示例,仅以纯色绘制 2048x2048 ,没有纹理。一个极其简单的着色器。向右拖动滑块可绘制更多点。在我的 2014 年 Macbook Pro 中,它只能以该尺寸绘制大约 12 个点,然后就无法再以 60 fps 运行。不同的 GPU 能够绘制或多或少的图像。

const vs = `
void main() {
  gl_Position = vec4(0, 0, 0, 1);
  gl_PointSize = 4000.0;
}
`
const fs = `
void main() {
  gl_FragColor = vec4(1./256., 0, 0, 1./256.);
}
`;

const gl = document.querySelector("canvas").getContext("webgl");
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

let numPoints = 1;
const inputElem = document.querySelector('input');
const numPointsElem = document.querySelector('#numpoints');
const fpsElem = document.querySelector('#fps');
const numPixElem = document.querySelector('#numpix');
const pointSizeElem = document.querySelector('#ps');
const pointSize = Math.min(2048, gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE)[1]);
pointSizeElem.textContent = `${pointSize}x${pointSize}`;


inputElem.addEventListener('input', (e) => {
  updateValue(e.target.value);
});

function updateValue(value) {
  numPointsElem.textContent = value;
  numPixElem.textContent = frmt(value * pointSize * pointSize);
  numPoints = value;
};

updateValue(1);

let then = 0;
function render(now) {
  const deltaTime = now - then;
  then = now;
  const fps = 1000 / deltaTime;
  fpsElem.textContent = fps.toFixed(1);
  
  gl.enable(gl.BLEND);
  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  gl.useProgram(programInfo.program);
  gl.drawArrays(gl.POINTS, 0, numPoints);

  requestAnimationFrame(render);
}
requestAnimationFrame(render);

function frmt(v) {
  return [].map.call(v.toString(), a => a).reverse().map((a, n) => { return a + (n % 3 === 0 && n > 1 ? ',' : ''); }).reverse().join('');
}
Run Code Online (Sandbox Code Playgroud)
html { box-sizing: border-box; }
*, *:after, *:before { box-sizing: inherit; }
body {  margin: 0; font-family: monospace; }
canvas { width: 100vw; height: 100vh; display: block; }
#ui { 
  padding: 1em;
  position: absolute; 
  top: 0; 
  left: 0; 
  color: white; 
  background: rgba(0,0,0,0.9); 
  width: 100vw;
};
Run Code Online (Sandbox Code Playgroud)
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<canvas width="2048" height="2048"></canvas>
<div id="ui">
  <div><input type="range" min="1" max="500" value="1"></div>
  <div>number of points: <span id="numpoints">1</span></div>
  <div>point size: <span id="ps"></span></div>
  <div>number of pixels being drawn per frame: <span id="numpix"></span></div>
  <div>frames per second: <span id="fps"></span></div>
</div>
Run Code Online (Sandbox Code Playgroud)

没有“简单”的解决方案。您需要找到一种方法来以某种方式绘制更少的像素。打开深度测试并让你的观点不混合可能是有帮助的解决方案。打开深度测试后从前到后对你的点进行排序也会有所帮助。