我正在研究一个大约60,000个顶点的点云。
如果我渲染云“查看它很小”,性能还可以,但是当我“放大”并且我在屏幕上看到大精灵/飞机/点时,性能会下降。
使用PointsMaterial
或RawShaderMaterial
,Points
对象或instancedBufferGeometry
网格会发生这种情况。
看起来当渲染覆盖大部分画布的单个大型形状时,性能下降。
如果点具有透明纹理,性能会下降。
我记得在处理过程中渲染大的重叠透明图像时遇到了类似的问题。
答案 0 :(得分:3)
正如Sedenion所说,你最有可能填补率。这意味着您要绘制太多像素。
GPU只能如此快速地绘制。平均非游戏玩家GPU每秒只能以60帧的速度绘制6-10个像素。如果你绘制的像素多于它,那么即使这些像素是简单像素,它也会运行得太慢(换句话说,即使你有简单的着色器)。对于普通3D场景,通常会启用深度测试。通过首先绘制最接近的东西,深度缓冲区将防止绘制后面的东西,这有助于加快速度。对于精灵,虽然通常不使用深度测试。这意味着即使它们重叠,也会绘制每个精灵中的每个像素。如果你加上绘制的像素数,你会发现你很快就会画出太多的像素。
这是一个简单的例子,它只绘制一个2048x2048 POINT
的纯色,没有纹理。一个非常简单的着色器。向右拖动滑块可绘制更多点。在我的2014 Macbook Pro中它只能在该尺寸上绘制大约12个点,然后才能以60fps运行。不同的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('');
}
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;
};
<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>
没有“简单”的解决方案。你需要找到一种方法来以某种方式绘制更少的像素。打开深度测试并使您的点不混合可能会在解决方案上提供帮助。在开启深度测试后,前后对点进行排序也会有所帮助。
答案 1 :(得分:2)
这与Three.js没有直接关系,更多与WebGL有关,更普遍与GPU有关......您会观察到与OpenGL或DirectX类似的行为。简单的答案是:你的GPU需要计算然后绘制一些东西,这需要时间。
现在让我们来看看一些细节。我无法保证您的减速问题与我所解释的问题直接相关,但这是一些线索:
GPU必须绘制的像素越多,花费的时间就越多,这意味着如果一个简单的点精灵覆盖整个画布区域,则需要更长的时间来绘制,而不是3或4像素宽。
由于您尝试绘制&#34; clouds&#34;,我怀疑您禁用了深度测试,以允许通过透明度将所有精灵绘制在前一个精灵上方。这意味着GPU必须多次在画布上绘制相同的像素,每次都使用混合方程,用于覆盖画布一部分的每个精灵。
如果每个精灵都有纹理,则添加到点1和2.纹理处理,纹理过滤,mipmap等。
你必须自己测试主要瓶颈在哪里。有时候,你无能为力,你必须在硬件限制内,通过减少精灵数量等来构建。