I’ve written this code which is running very smoothly in Safari (30fps on a 4K screen & 2018 Intel MacBook Pro). It also runs 60fps on my iPhone, and on Chrome for Windows. It’s also running at 60fps on Chrome on an M1 MacBook.
However, when I try to run it on Chrome (105.0.5195.125) on my Intel Mac, it basically hangs!
I’ve seen plenty of old 1m+ particle demos that run fine on Chrome, so I’m assuming I’ve done something dumb? I did try to downgrade to webGL1.0 and it ran about 20fps on Chrome. I also tried Chrome Canary, but it still hangs.
Can anyone please help me?
Here is my code:
import * as THREE from "three";
import Stats from "three/examples/jsm/libs/stats.module.js";
const canvas = document.querySelector("canvas");
const w = document.documentElement.clientWidth;
const h = document.documentElement.clientHeight;
const scene = new THREE.Scene();
const stats = new Stats();
document.body.appendChild(stats.dom);
//RENDERER
const renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: false});
renderer.powerPreference = "high-performance";
renderer.setSize(w, h);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0x000000, 1);
//CAMERA
const camera = new THREE.PerspectiveCamera(45, 1, 1, 1000);
camera.position.set(0, 0, 2);
camera.lookAt(new THREE.Vector3(0, 0, 0));
camera.fov = 2 * (180/Math.PI) * Math.atan(1 / 4);
camera.aspect = w / h;
camera.updateProjectionMatrix();
scene.add(camera);
// const mat = new THREE.MeshBasicMaterial({color: 0xff0000});
// const geo = new THREE.PlaneGeometry(camera.aspect, 1);
// const mesh = new THREE.Mesh(geo, mat);
// scene.add(mesh);
//SHADER
const shaderVert = `
precision mediump float;
uniform float time;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
attribute vec4 offset;
attribute vec2 uv;
varying vec3 vPosition;
varying float vTime;
void main ()
{
vPosition = offset.xyz;
vTime = sin(time + offset.w);
float scale = 0.001;
//BILLBOARD
gl_Position = projectionMatrix * (modelViewMatrix * vec4(vPosition, 1.0) + vec4(position.xy * scale, 0.0, 0.0));
}
`;
const shaderFrag = `
precision mediump float;
varying float vTime;
void main ()
{
vec4 color = vec4(vTime, vTime, vTime, 1.0);
gl_FragColor = color;
}
`;
//BUFFERGEOMETRY
const COUNT = 1000 * 1000;
const TAU = Math.PI * 2;
let step = 0;
const positions = [];
const uvs = [];
const offsets = [];
positions.push( 0.5, -0.5, 0.0);
positions.push( 0.5, 0.5, 0.0);
positions.push(-0.5, 0.5, 0.0);
positions.push( 0.5, -0.5, 0.0);
positions.push(-0.5, 0.5, 0.0);
positions.push(-0.5, -0.5, 0.0);
uvs.push(1.0, 0.0);
uvs.push(1.0, 1.0);
uvs.push(0.0, 1.0);
uvs.push(1.0, 0.0);
uvs.push(0.0, 1.0);
uvs.push(0.0, 0.0);
for (let i = 0; i < COUNT; i++)
{
//Create offsets
offsets.push(
Math.random() - 0.5,
Math.random() - 0.5,
Math.random() - 0.5,
Math.random() * TAU
);
}
const geometry = new THREE.InstancedBufferGeometry();
geometry.instanceCount = COUNT;
geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));
geometry.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2));
geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(new Float32Array(offsets), 4));
//MATERIAL
const material = new THREE.RawShaderMaterial(
{
uniforms: {
"time": { type: "f", value: 1.0 }
},
vertexShader: shaderVert,
fragmentShader: shaderFrag
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
//RENDER LOOP
function render ()
{
step += 0.1;
material.uniforms["time"].value = step;
renderer.render(scene, camera);
stats.update();
requestAnimationFrame(render);
}
render();