此刻,我有一个旋转的动画地球仪,地球仪上的点随机改变颜色。它可以正常工作,但如果留在后台,则会大大减慢我的笔记本电脑的速度。我是否可以进行任何更改以减少正在使用的内存量?
在Chrome的任务管理器中,该选项卡处于活动状态时,我看到它正在使用12%的CPU和128MB的GPU内存。 Three.js正常吗?还是需要更改代码?
ngAfterViewInit() {
if(this.enabled) {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.rotateSpeed = 0.5;
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.5;
this.controls.rotationSpeed = 0.3;
this.controls.enableZoom = false;
this.controls.autoRotate = true;
this.controls.autoRotateSpeed = -1;
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.rendererContainer.nativeElement.appendChild(this.renderer.domElement);
this.animate();
const timerId = setInterval(() => this.updateColor(), 650);
}
}
private get enabled(): boolean {
if(this._enabled!==undefined) {
return this._enabled;
}
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
this._enabled = gl && gl instanceof WebGLRenderingContext;
return this._enabled;
}
private initGlobe(): void {
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
this.camera.position.set(0, 5, 15);
this.camera.lookAt(this.scene.position);
this.renderer = new THREE.WebGLRenderer({
antialias: true
});
this.renderer.setClearColor('rgb(55, 44, 80)');
this.geom = new THREE.SphereBufferGeometry(6, 350, 90);
this.colors = [];
this.color = new THREE.Color();
this.colorList = ['rgb(123, 120, 194)'];
for (let i = 0; i < this.geom.attributes.position.count; i++) {
this.color.set(this.colorList[THREE.Math.randInt(0, this.colorList.length - 1)]);
this.color.toArray(this.colors, i * 3);
}
this.geom.addAttribute('color', new THREE.BufferAttribute(new Float32Array(this.colors), 3));
this.geom.addAttribute('colorRestore', new THREE.BufferAttribute(new Float32Array(this.colors), 3));
this.loader = new THREE.TextureLoader();
this.loader.setCrossOrigin('');
this.texture = this.loader.load('/assets/globe-dot.jpg');
this.texture.wrapS = THREE.RepeatWrapping;
this.texture.wrapT = THREE.RepeatWrapping;
this.texture.repeat.set(1, 1);
const oval = this.loader.load('/assets/circle.png');
this.points = new THREE.Points(this.geom, new THREE.ShaderMaterial({
vertexColors: THREE.VertexColors,
uniforms: {
visibility: {
value: this.texture
},
shift: {
value: 0
},
shape: {
value: oval
},
size: {
value: 0.4
},
scale: {
value: 300
}
},
vertexShader: `
uniform float scale;
uniform float size;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vUv = uv;
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4( position, 0.99 );
gl_PointSize = size * ( scale / length( mvPosition.xyz )) * (0.3 + sin(uv.y * 3.1415926) * 0.35 );
gl_Position = projectionMatrix * mvPosition;
}
// `,
fragmentShader: `
uniform sampler2D visibility;
uniform float shift;
uniform sampler2D shape;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vec2 uv = vUv;
uv.x += shift;
vec4 v = texture2D(visibility, uv);
if (length(v.rgb) > 1.0) discard;
gl_FragColor = vec4( vColor, 0.9 );
vec4 shapeData = texture2D( shape, gl_PointCoord );
if (shapeData.a < 0.0625) discard;
gl_FragColor = gl_FragColor * shapeData;
}
`,
transparent: false
}));
this.points.sizeAttenuation = false;
this.scene.add(this.points);
this.globe = new THREE.Mesh(this.geom, new THREE.MeshBasicMaterial({
color: 'rgb(65, 54, 88)', transparent: true, opacity: 0.5
}));
this.globe.scale.setScalar(0.99);
this.points.add(this.globe);
this.scene.add(this.globe);
}
animate() {
this.controls.update();
this.renderer.render(this.scene, this.camera);
this.animationQueue.push(this.animate);
window.requestAnimationFrame(_ => this.nextAnimation());
}
nextAnimation() {
try {
const animation = this.animationQueue.shift();
if (animation instanceof Function) {
animation.bind(this)();
}
} catch (e) {
console.error(e);
}
}
updateColor() {
for (let i = 0; i < this.usedIndices.length; i++) {
let idx = this.usedIndices[i];
this.geom.attributes.color.copyAt(idx, this.geom.attributes.colorRestore, idx);
}
for (let i = 0; i < this.pointsUsed; i++) {
let idx = THREE.Math.randInt(0, this.geom.attributes.color.count - 1);
if (idx%5 == 0 && idx%1 == 0) {
this.geom.attributes.color.setXYZ(idx, 0.9, 0.3, 0);
}
else {
this.geom.attributes.color.setXYZ(idx, 1, 1, 1);
}
this.usedIndices[i] = idx;
}
this.geom.attributes.color.needsUpdate = true;
我查看了其他建议合并网格的问题,但不确定在这里是否可行。谢谢!
答案 0 :(得分:1)
这取决于您所说的“背景”
如果用“背景”表示“不是最前面的选项卡”,那么,如果您使用的是requestAnimationFrame
,那么您的页面不是浏览器的最前面的选项卡,或者如果您将页面最小化,浏览器窗口浏览器将停止向您发送动画帧事件,并且您的页面应完全停止。
如果通过“背景”来表示前选项卡,但是它是未最小化且也不是前窗口的窗口,则可以使用blur
和focus
事件来完全停止页面。
示例:注意:模糊事件在iframe中似乎不起作用,因此在下面的代码段中将不起作用,但是如果将其复制到文件中,它将起作用
let requestId;
function start() {
if (!requestId) {
requestId = requestAnimationFrame(animate);
}
}
function stop() {
console.log('stop');
if (requestId) {
cancelAnimationFrame(requestId);
requestId = undefined;
}
}
const ctx = document.querySelector("canvas").getContext('2d');
function animate(time) {
requestId = undefined;
ctx.save();
ctx.translate(
150 + 150 * Math.cos(time * 0.001),
75 + 75 * Math.sin(time * 0.003),
);
ctx.scale(
Math.cos(time * 0.005),
Math.cos(time * 0.007),
);
ctx.fillStyle = `hsl(${time % 360},100%,50%)`;
ctx.fillRect(-50, 50, 100, 100);
ctx.restore();
start();
}
start();
window.addEventListener('blur', stop);
window.addEventListener('focus', start);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<canvas></canvas>
当然,除了完全停止blur
之外,您还可以控制自己的应用。仅每第5帧渲染一次或渲染更少的东西,等等...