亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Three.js渲染模型卡頓問題的一些優(yōu)化辦法

 更新時間:2024年02月04日 10:27:47   作者:小樓窗外的細(xì)雨  
用ThreeJS加載大模型總要遇到性能問題,性能優(yōu)化一般包括加載性能優(yōu)化、渲染幀率優(yōu)化、內(nèi)存優(yōu)化等,下面這篇文章主要給大家介紹了關(guān)于Three.js渲染模型卡頓問題的一些優(yōu)化辦法,需要的朋友可以參考下

事先說明

優(yōu)化方法是根據(jù)chatGPT的回答下,我這里記錄一下,有的方法進(jìn)行了嘗試,有的還沒有。

1、模型面數(shù)過多導(dǎo)致渲染卡頓

可以通過減少面數(shù)來優(yōu)化,也可以使用LOD技術(shù)(Level of Detail)在不同距離下使用不同的模型細(xì)節(jié)來優(yōu)化。

使用LOD技術(shù)可以在不同距離下使用不同的模型細(xì)節(jié)來優(yōu)化three.js渲染性能,下面是具體步驟:

  • 創(chuàng)建多個模型,每個模型的面數(shù)和細(xì)節(jié)不同,這些模型應(yīng)該是同一個對象的不同版本。

  • 將這些模型按照從低到高的細(xì)節(jié)順序添加到同一個LOD(Level of Detail)對象中,如下所示:

const lod = new THREE.LOD();
const lowDetailModel = ... // 低細(xì)節(jié)模型
const midDetailModel = ... // 中細(xì)節(jié)模型
const highDetailModel = ... // 高細(xì)節(jié)模型
lod.addLevel(lowDetailModel, 0); // 添加低細(xì)節(jié)模型,距離為0
lod.addLevel(midDetailModel, 100); // 添加中細(xì)節(jié)模型,距離為100
lod.addLevel(highDetailModel, 200); // 添加高細(xì)節(jié)模型,距離為200
  • LOD對象添加到場景中。
scene.add(lod);
  • 在渲染循環(huán)中,根據(jù)相機(jī)與LOD對象的距離,自動選擇當(dāng)前需要顯示的模型細(xì)節(jié)等級??梢允褂?code>THREE.LOD對象的update方法來實現(xiàn)。
function render() {
  requestAnimationFrame(render);
  lod.update(camera);
  renderer.render(scene, camera);
}

2、材質(zhì)貼圖過大導(dǎo)致渲染卡頓

可以通過減小貼圖尺寸,壓縮貼圖格式,使用紋理集(Texture Atlas)等方式來優(yōu)化。

使用紋理集(Texture Atlas)可以將多張小紋理圖合并成一張大紋理圖,從而減少渲染時的紋理切換次數(shù),優(yōu)化three.js渲染性能,下面是具體步驟:

  • 創(chuàng)建一張大紋理圖,并將多張小紋理圖拼接在一起,這些小紋理圖應(yīng)該是同一對象的不同部分,如下所示:
const texture = new THREE.TextureLoader().load('atlas.png');
const material = new THREE.MeshBasicMaterial({ map: texture });
  • 將每個物體的UV坐標(biāo)映射到對應(yīng)的小紋理圖區(qū)域,需要根據(jù)小紋理圖在大紋理圖中的位置和大小計算出UV坐標(biāo),如下所示:
const geometry = new THREE.BoxGeometry(1, 1, 1);
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
  const u = uvAttribute.getX(i);
  const v = uvAttribute.getY(i);
  // 根據(jù)小紋理圖在大紋理圖中的位置和大小計算出UV坐標(biāo)
  uvAttribute.setXY(i, u * smallTextureWidth / bigTextureWidth + smallTextureX / bigTextureWidth, v * smallTextureHeight / bigTextureHeight + smallTextureY / bigTextureHeight);
}
  • 在渲染循環(huán)中,更新大紋理圖的偏移和縮放值。
function render() {
  requestAnimationFrame(render);
  const time = Date.now() * 0.001;
  texture.offset.x = time * 0.1; // x方向偏移量
  texture.offset.y = time * 0.2; // y方向偏移量
  texture.repeat.set(2, 2); // 橫向和縱向縮放值
  renderer.render(scene, camera);
}

3、著色器復(fù)雜度過高導(dǎo)致渲染卡頓

可以通過簡化著色器,使用預(yù)編譯的著色器,使用Instancing等方式來優(yōu)化。

使用Instancing(實例化)可以將多個相同的物體復(fù)用同一個幾何體和材質(zhì),并在渲染時進(jìn)行一次性繪制,從而減少渲染調(diào)用次數(shù),優(yōu)化three.js渲染性能,下面是具體步驟:

  • 創(chuàng)建一個幾何體和材質(zhì),將它們分別作為多個物體的原型。
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
  • 創(chuàng)建一個InstancedBufferGeometry對象,并將原型幾何體的屬性復(fù)制到它的屬性中。
const instances = 10000; // 實例數(shù)量
const instancedGeometry = new THREE.InstancedBufferGeometry();
instancedGeometry.copy(geometry); // 復(fù)制幾何體屬性
const translations = new Float32Array(instances * 3); // 實例位置數(shù)組
for (let i = 0; i < instances; i++) {
  translations[i * 3] = Math.random() * 100 - 50;
  translations[i * 3 + 1] = Math.random() * 100 - 50;
  translations[i * 3 + 2] = Math.random() * 100 - 50;
}
instancedGeometry.setAttribute('translation', new THREE.InstancedBufferAttribute(translations, 3));
  • 創(chuàng)建一個InstancedMesh對象,并將原型材質(zhì)和實例化幾何體作為它的參數(shù)。
const instancedMesh = new THREE.InstancedMesh(instancedGeometry, material, instances);
scene.add(instancedMesh);
  • 在渲染循環(huán)中,更新實例化幾何體的屬性,即實例的位置、旋轉(zhuǎn)和縮放等信息。
function render() {
  requestAnimationFrame(render);
  const time = Date.now() * 0.001;
  for (let i = 0; i < instances; i++) {
    const translation = instancedMesh.geometry.attributes.translation;
    translation.setXYZ(i, Math.sin(time + i * 0.5) * 5, Math.cos(time + i * 0.3) * 5, i * 0.1);
  }
  instancedMesh.geometry.attributes.translation.needsUpdate = true; // 更新實例位置屬性
  renderer.render(scene, camera);
}

4、不合理的渲染方式導(dǎo)致渲染卡頓

可以通過使用合適的渲染方式,如WebGL2渲染,使用Web Worker等方式來優(yōu)化。

Ⅰ、使用WebGL2可以在現(xiàn)代瀏覽器中利用新的圖形處理能力,優(yōu)化three.js渲染性能,下面是具體步驟:
① 在渲染器中啟用WebGL2。

const renderer = new THREE.WebGLRenderer({ canvas: canvas, context: canvas.getContext('webgl2') });

② 使用WebGL2支持的新特性,如transform feedback、instanced arrays等。
例如,以下代碼演示了如何使用transform feedback來記錄頂點(diǎn)位置的變化:

const transformFeedback = new THREE.WebGL2TransformFeedback();
const bufferGeometry = new THREE.BufferGeometry();
const positions = new Float32Array([0, 0, 0]);
bufferGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const shader = new THREE.ShaderMaterial({
  vertexShader: `
    out vec3 transformedPosition;
    void main() {
      transformedPosition = position;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    void main() {
      gl_FragColor = vec4(1.0);
    }
  `,
  transformFeedback: {
    // 將頂點(diǎn)位置記錄到transformedPosition變量中
    varyings: ['transformedPosition'],
    // 開啟transform feedback
    enabled: true,
    // 設(shè)置bufferGeometry的位置屬性為transform feedback的輸出屬性
    bufferGeometry: bufferGeometry
  }
});
const mesh = new THREE.Mesh(bufferGeometry, shader);
scene.add(mesh);
function render() {
  requestAnimationFrame(render);
  renderer.setRenderTarget(null);
  // 開始transform feedback
  transformFeedback.begin();
  renderer.render(scene, camera);
  // 結(jié)束transform feedback,并將變化后的頂點(diǎn)位置存儲到bufferGeometry中
  transformFeedback.end();
  // 更新頂點(diǎn)位置
  positions.set(bufferGeometry.getAttribute('position').array);
  bufferGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  renderer.render(scene, camera);
}

---------------------------------------------------------------分隔線-----------------------------------------------------------------

Ⅱ、使用Web Worker可以將計算密集型的任務(wù)分離到另一個線程中,從而避免主線程被阻塞,優(yōu)化three.js渲染性能,下面是具體步驟:

① 創(chuàng)建一個Web Worker,用于處理計算密集型的任務(wù)。

const worker = new Worker('worker.js');

② 在Web Worker中定義處理函數(shù)。

// worker.js
function process(data) {
  // 計算密集型的任務(wù)
  return result;
}
onmessage = function(event) {
  const result = process(event.data);
  postMessage(result);
};

③ 在主線程中將任務(wù)發(fā)送到Web Worker,并設(shè)置回調(diào)函數(shù)處理返回結(jié)果。

function render() {
  requestAnimationFrame(render);
  // 發(fā)送任務(wù)到Web Worker
  worker.postMessage(data);
  worker.onmessage = function(event) {
    const result = event.data;
    // 處理返回結(jié)果
  };
  renderer.render(scene, camera);
}

通過以上步驟,就可以使用Web Worker來將計算密集型的任務(wù)分離到另一個線程中,從而避免主線程被阻塞,優(yōu)化three.js渲染性能。需要注意的是,Web Worker中無法直接訪問主線程的DOM和three.js對象,需要通過消息傳遞來實現(xiàn)通信。

5、CPU和GPU資源不平衡導(dǎo)致渲染卡頓

可以通過分析性能監(jiān)控,優(yōu)化代碼邏輯,使用requestAnimationFrame等方式來平衡CPU和GPU資源占用。

使用requestAnimationFrame可以讓瀏覽器根據(jù)自身的渲染節(jié)奏調(diào)整動畫的幀率,從而避免過度渲染,優(yōu)化three.js渲染性能,下面是具體步驟:

  • 將渲染函數(shù)作為requestAnimationFrame的回調(diào)函數(shù)。
function render() {
  // 渲染代碼
  renderer.render(scene, camera);
  // 請求下一幀動畫
  requestAnimationFrame(render);
}
  • 在初始化時調(diào)用一次requestAnimationFrame,啟動動畫。
var animationId = requestAnimationFrame(render);
  • 在動畫結(jié)束時,記得停止requestAnimationFrame,以避免不必要的資源消耗。
function stop() {
  cancelAnimationFrame(animationId);
}

需要注意的是,使用requestAnimationFrame時需要避免在渲染循環(huán)中進(jìn)行過多的計算,以免影響渲染性能。

總結(jié) 

到此這篇關(guān)于Three.js渲染模型卡頓問題的一些優(yōu)化辦法的文章就介紹到這了,更多相關(guān)Three.js渲染模型卡頓內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論