빠른 WebGL/3js 3D 그래픽 및 Offscreencavas 및 네트워크 작업자
10761 단어 webdevjavascripttutorialopensource
Three.js 라이브러리를 사용하여 복잡한 장면을 만들 때 WebGL 성능을 향상시키는 방법을 알아보려면 렌더링을 주 스레드에서
OffscreenCanvas
을 사용하는 웹 워크맨으로 이동하는 것이 좋습니다.로우엔드 장치에서는 3D 효과가 더 좋고 평균 성능도 향상됩니다.내 personal website에 지구의 3D WebGL 모형을 만든 후에 나는 내가 Google Lighthouse에서 즉시 5%의 손실을 보았다는 것을 발견했다.
본고에서 크로스 브라우저 호환성을 희생하지 않고 성능을 다시 얻을 수 있는 방법을 보여 드리며, 이를 위해 작성한 소형 라이브러리를 사용합니다.
문제.
세 개.복잡한 WebGL 장면을 쉽게 만들 수 있습니다.불행히도, 이것은 대가가 있는 것이다.세 개.js는 js 패키지 크기를 약 563 KB 증가시킵니다. (구조상 실제 나무가 흔들리지 않습니다.)
평균 배경 이미지가 같은 500KB가 있을 수 있다고 말할 수 있다.그러나 천 바이트당 자바스크립트가 사이트 전체 성능에 미치는 영향은 천 바이트의 이미지 데이터보다 크다.만약 당신의 목표가 빠른 사이트라면, 지연과 대역폭은 유일하게 고려해야 할 일이 아니다. CPU가 당신의 내용을 처리하는 데 얼마나 많은 시간을 들일지 고려하는 것도 중요하다.로우엔드 디바이스에서 리소스를 다운로드하는 것보다 처리하는 데 더 많은 시간이 걸릴 수 있습니다.
3.5초 170KB JS, 0.1초 170KB JPEG 처리.Addy Osmani
브라우저가 세 개의 500KB 데이터를 처리할 때, 당신의 웹 페이지는 효과적으로 동결될 것입니다.JavaScript를 실행하는 데 주 스레드가 사용되기 때문에 js 코드입니다.장면을 완전히 렌더링하기 전에는 페이지와 상호 작용할 수 없습니다.
인터넷 종사자와 스크린 아웃도어
WebWorkers는 JS가 실행되는 동안 페이지가 동결되지 않도록 하는 솔루션입니다.이것은 일부 JavaScript 코드를 개별 스레드로 이동하는 방법입니다.
불행히도 다중 루틴 프로그래밍은 매우 어렵다.작업을 단순화하기 위해 웹 작업자는 DOM에 액세스할 수 없습니다.이 액세스 권한은 주 JavaScript 스레드에만 있습니다.하지만 세 가지가 있다.js는 DOM에 있는
<canvas>
노드에 접근해야 합니다.OffscreenCanvas
은 이 문제의 해결 방안이다.Web Worker로 캔버스 액세스를 이동할 수 있습니다.이 솔루션을 선택하면 주 스레드가 <canvas>
에 접근할 수 없기 때문에 여전히 스레드가 안전합니다.Google의 기본은 덮어썼지만 문제는 화면 밖의 캔버스 API는 Google Chrome에서만 지원된다는 점입니다.
2019년 4월, 외부 캔버스를 지원하는 브라우저는 Can I Use
그러나 우리의 주요 적, 크로스 브라우저 문제에 직면해도 우리는 두려워하지 않는다.점진적 향상: Chrome과 향후 브라우저의 성능을 향상시킬 것입니다.기타 세 가지 브라우저가 실행됩니다.js는 기본 JavaScript 스레드에서 이전 방식을 사용합니다.
우리는 두 개의 서로 다른 환경을 위해 파일을 작성하는 방법을 생각해 내야 한다. 많은 DOM API가 웹 워커에서 일할 수 없다는 것을 기억해야 한다.
솔루션
모든 해커 공격을 숨기고 코드의 가독성을 유지하기 위해 나는 작은 offscreen-canvas JS 라이브러리 (400바이트만) 를 만들었다.아래의 예는 그것에 의존할 것이지만, 나는 그것이 어떻게 엔진 뚜껑 아래에서 작동하는지 설명할 것이다.
먼저 프로젝트에
offscreen-canvas
npm 패키지를 추가합니다.npm install offscreen-canvas
웹 워커에 대해 별도의 JS 파일을 제공해야 합니다.웹 팩 또는 Parcel 구성에서 별도의 JS 패키지를 만듭니다. entry: {
'app': './src/app.js',
+ 'webgl-worker': './src/webgl-worker.js'
}
Bundler는 제품에 bundle의 파일 이름에 캐시 버스터를 추가합니다.주 JS 파일에서 이 이름을 사용하려면 preload 태그를 추가합니다.구체적인 코드는 HTML을 생성하는 방법에 따라 달라집니다. <link type="preload" as="script" href="./webgl-worker.js">
</head>
이제 우리는 주 JS 파일에서 캔버스 노드와 작업 URL을 얻어야 한다.import createWorker from 'offscreen-canvas/create-worker'
const workerUrl = document.querySelector('[rel=preload][as=script]').href
const canvas = document.querySelector('canvas')
const worker = createWorker(canvas, workerUrl)
createWorker
에서 canvas.transferControlToOffscreen
을 찾아 OffscreenCanvas
지원을 테스트합니다.브라우저가 지원하는 경우 라이브러리는 JS 파일을 웹 워커로 로드합니다.그렇지 않으면 JS 파일이 일반 스크립트로 로드됩니다.이제
webgl-worker.js
을 열겠습니다.import insideWorker from 'offscreen-canvas/inside-worker'
const worker = insideWorker(e => {
if (e.data.canvas) {
// Here we will initialize Three.js
}
})
insideWorker
웹 워커에 로드되었는지 확인합니다.환경에 따라 주선과 서로 다른 방식으로 통신할 것이다.라이브러리는 주 라인에서 온 모든 메시지에 대한 리셋을 실행합니다.
createWorker
에서 온 첫 번째 메시지는 항상 { canvas, width, height }
이 화포를 초기화하는 대상이다.+ import {
+ WebGLRenderer, Scene, PerspectiveCamera, AmbientLight,
+ Mesh, SphereGeometry, MeshPhongMaterial
+ } from 'three'
import insideWorker from 'offscreen-canvas/inside-worker'
+ const scene = new Scene()
+ const camera = new PerspectiveCamera(45, 1, 0.01, 1000)
+ scene.add(new AmbientLight(0x909090))
+
+ let sphere = new Mesh(
+ new SphereGeometry(0.5, 64, 64),
+ new MeshPhongMaterial()
+ )
+ scene.add(sphere)
+
+ let renderer
+ function render () {
+ renderer.render(scene, camera)
+ }
const worker = insideWorker(e => {
if (e.data.canvas) {
+ // canvas in Web Worker will not have size, we will set it manually to avoid errors from Three.js
+ if (!canvas.style) canvas.style = { width, height }
+ renderer = new WebGLRenderer({ canvas, antialias: true })
+ renderer.setPixelRatio(pixelRatio)
+ renderer.setSize(width, height)
+
+ render()
}
})
장면의 초기 상태를 만들 때, 우리는 세 가지 측면에서 오류 메시지를 찾을 수 있다.js.모든 DOM API를 웹 워커에서 사용할 수 있는 것은 아닙니다.예를 들어, SVG 텍스쳐를 로드할 document.createElement
이 없습니다.Web Worker와 일반 스크립트 환경에 대해 다른 로드 프로그램이 필요합니다.worker.isWorker
을 통해 환경을 감지할 수 있습니다. renderer.setPixelRatio(pixelRatio)
renderer.setSize(width, height)
+ const loader = worker.isWorker ? new ImageBitmapLoader() : new ImageLoader()
+ loader.load('/texture.png', mapImage => {
+ sphere.material.map = new CanvasTexture(mapImage)
+ render()
+ })
render()
우리는 장면의 초기 상태를 과장했다.그러나 대부분의 WebGL 장면은 사용자 작업에 반응해야 합니다.그것은 아마도 마우스로 카메라를 회전시킬 것이다.또는 canvas
의 창 크기를 업데이트합니다.불행하게도 웹 워커는 DOM 이벤트에 액세스할 수 있는 권한이 없습니다.주 스레드에서 이벤트를 수신하고 작업 스레드에 메시지를 보내야 합니다. import createWorker from 'offscreen-canvas/create-worker'
const workerUrl = document.querySelector('[rel=preload][as=script]').href
const canvas = document.querySelector('canvas')
const worker = createWorker(canvas, workerUrl)
+ window.addEventListener('resize', () => {
+ worker.post({
+ type: 'resize', width: canvas.clientWidth, height: canvas.clientHeight
+ })
+ })
const worker = insideWorker(e => {
if (e.data.canvas) {
if (!canvas.style) canvas.style = { width, height }
renderer = new WebGLRenderer({ canvas, antialias: true })
renderer.setPixelRatio(pixelRatio)
renderer.setSize(width, height)
const loader = worker.isWorker ? new ImageBitmapLoader() : new ImageLoader()
loader.load('/texture.png', mapImage => {
sphere.material.map = new CanvasTexture(mapImage)
render()
})
render()
- }
+ } else if (e.data.type === 'resize') {
+ renderer.setSize(width, height)
+ render()
+ }
})
결과는요
OffscreenCanvas
을 사용하여 Chrome로 개인 웹 사이트의 UI 동결을 수정했고 Google Lighthouse에서 100점 만점을 받았습니다.나의 WebGL 장면은 모든 다른 브라우저에서 정상적으로 작동할 수 있다.결과: demo과 main thread, worker의 원본 코드를 검사할 수 있습니다.
과 OffscreenCanvas 구글 등대의 성능 비율이 95에서 100으로 높아졌다
Reference
이 문제에 관하여(빠른 WebGL/3js 3D 그래픽 및 Offscreencavas 및 네트워크 작업자), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/evilmartians/faster-webgl-three-js-3d-graphics-with-offscreencanvas-and-web-workers-43he텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)