当前位置: 首页 > article >正文

Three.js 快速入门教程【三】渲染器

请添加图片描述

系列文章目录

Three.js 快速入门教程【一】开启你的 3D Web 开发之旅
Three.js 快速入门教程【二】透视投影相机
Three.js 快速入门教程【三】渲染器
Three.js 快速入门教程【四】三维坐标系
Three.js 快速入门教程【五】动画渲染循环
Three.js 快速入门教程【六】相机控件 OrbitControls
Three.js 快速入门教程【七】常见几何体类型


文章目录

  • 系列文章目录
  • 一、前言
  • 二、创建渲染器(WebGLRenderer)
  • 三、设置背景色和透明度
  • 四、设置渲染器的像素比
  • 五、设置渲染区域尺寸
  • 六、渲染器渲染生成画布(canvas)
  • 七、画布添加到页面
  • 八、响应式处理
  • 九、释放资源
  • 十、截屏
  • 十一、牛刀小试
  • 总结


一、前言

      在Three.js的世界里,渲染器(Renderer)就像一位技艺高超的魔术师,负责将抽象的3D数据转化为屏幕上跃动的视觉盛宴。其中,WebGLRenderer 是 Three.js 中用于在网页上渲染 3D 场景最常用渲染器,本文将带你逐步了解如何使用 WebGLRenderer。


二、创建渲染器(WebGLRenderer)

new THREE.WebGLRenderer(parameters)

其中,parameters 是一个可选的配置对象,包含了渲染器的各种配置选项。

省略参数:

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();

设置参数:

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer({
 alpha: true,//开启渲染器画布的透明度通道
 antialias: true, //启用抗锯齿功能
 powerPreference: "high-performance" // 高性能模式
});

parameters 常用参数:

参数名类型说明默认值
alphaBoolean渲染器的画布是否包含一个透明度通道。如果设置true这意味着你可以将渲染器的背景设置为透明,从而使网页的背景透过画布显示出来false
antialiasBoolean是否启用抗锯齿功能。抗锯齿可以使渲染的图形边缘更加平滑,减少锯齿状的外观,但可能会降低一些性能。false
canvasHTMLCanvasElement指定渲染器使用的 元素。如果不提供该参数,渲染器会自动创建一个新的 元素_
powerPreferenceString指定渲染器的性能偏好,“default”:默认设置,由浏览器决定使用何种性能模式。“high-performance”:优先使用高性能模式,适合需要处理复杂场景的情况,但可能会消耗更多的电量。“low-power”:优先使用低功耗模式,适合对性能要求不高的场景,以节省电量。default
precisionString指定着色器的精度,“highp”:高精度,适合大多数情况,但在一些旧设备上可能不支持。“mediump”:中精度,在大多数设备上都能正常工作。“lowp”:低精度,可能会导致颜色和位置的计算出现误差,但可以提高性能。highp
preserveDrawingBufferBoolean是否保留画布的绘制缓冲区,如果设置为true允许你使用 canvas.toDataURL() 等方法将画布内容保存为图像。但这可能会降低性能,因为需要额外的内存来保存缓冲区。false

不通过构造函数传入配置,也可以通过渲染器属性设置

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
 //启用抗锯齿功能
renderer.antialias = true,


三、设置背景色和透明度

renderer.setClearColor(color:Integer|String|THREE.Color,alpha: Float )

设置渲染器颜色和透明度,第一个参数颜色值,第二个参数透明度

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer({
 alpha: true,//开启渲染器画布的透明度通道
});
//设置黑色背景和透明度0.6
renderer.setClearColor(0x000000, 0.6);

四、设置渲染器的像素比

renderer.setPixelRatio(devicePixelRatio:Number )

renderer.setPixelRatio() 方法用于设置渲染器的像素比,像素比决定了渲染的分辨率。在不同设备上,屏幕的物理像素和 CSS 像素的比例可能不同。例如,在视网膜屏幕(如苹果的 Retina 显示屏)上,一个 CSS 像素可能对应多个物理像素。通过设置合适的像素比,可以让渲染的 3D 场景在高分辨率屏幕上显示得更加清晰和锐利。

// 设置渲染器的像素比为设备的像素比
renderer.setPixelRatio(window.devicePixelRatio);

五、设置渲染区域尺寸

renderer.setSize(width:Number, height:Number);

//设置three.js渲染区域的尺寸宽1000px,高600px
renderer.setSize(1000, 600); 

一般设置为窗口宽高

// 设置画布尺寸
renderer.setSize(window.innerWidth, window.innerHeight);

六、渲染器渲染生成画布(canvas)

renderer.render()

调用render()方法将生成一个canvas画布并把3d场景渲染到画布中

//执行渲染操作
renderer.render(scene, camera); 

七、画布添加到页面

render.domElement 获取canvas元素

上一步生成的canvas是一个HTML元素,需要插入到页面dom才能显示3D场景

通过render.domElement属性可获取到canvas

1、canvas插入页面body上(整个页面显示3D)

document.body.appendChild(renderer.domElement);

2、也可以插入任意HTML元素中 (局部显示3D)

<div id="container"></div>
document.getElementById('container').appendChild(renderer.domElement);

八、响应式处理

当窗口尺寸变化需要同步改变渲染区域大小从而保持3D场景响应式,同时不要忘记重新设置相机的宽高比

window.addEventListener('resize', () => {
  //重新设置渲染区域大小
  renderer.setSize(window.innerWidth, window.innerHeight);
  //重新设置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  //更新相机投影矩阵,改变相机参数需要调用才能生效
  camera.updateProjectionMatrix();
});

性能优化建议:可以加个防抖处理,防止频繁调用


九、释放资源

离开页面,销毁渲染器释放资源

// 销毁时释放资源
 renderer.dispose();
 renderer.forceContextLoss();
 renderer.domElement = null;

十、截屏

由上述我们知道3D渲染区域实际上是一个画布(canvas),而画布toDataURL方法可以把页面内容生成图片导出。

//导出前需要重新渲染,防止导出空白图片
renderer.render(scene, camera);
//截屏
renderer.domElement.toDataURL('image/png');

十一、牛刀小试

实现一个3D场景小案例:要求渲染层透明可看见页面底部背景图,支持窗口响应式、支持截屏功能。

以vue3为代码示例:

<template>
  <div class="container">
    <!-- 工具栏 -->
    <div class="toolbar">
      <button class="screenshot" @click="handleScreenshot">截图</button>
    </div>
    <!-- 3D区域 -->
    <div ref="threeViewRef" class="three-view"></div>
  </div>
</template>
<script setup>
import { nextTick, onMounted, ref } from "vue";
import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

//3d区域容器
const threeViewRef = ref();
//3d区域宽
const width = ref();
//3d区域高
const height = ref();

onMounted(() => {
  //设置宽高
  width.value = threeViewRef.value.clientWidth;
  height.value = threeViewRef.value.clientHeight;
  //初始化three.js
  init();
});

onUnmounted(() => {
  // 离开页面释放资源
  if (renderer) {
    renderer.dispose();
    renderer.forceContextLoss();
    renderer.domElement = null;
  }
});

//渲染器
let renderer = null;
//场景
let scene = null;
//相机
let camera = null;

//初始化
const init = () => {
  //创建场景
  scene = new THREE.Scene();
  //创建一个正方体
  const geometry = new THREE.BoxGeometry(10, 10, 10);
  //创建一个基础材质
  const material = new THREE.MeshBasicMaterial({ color: "#409EFF" });
  //创建一个网格对象
  const mesh = new THREE.Mesh(geometry, material);
  //设置网格对象位置
  mesh.position.set(0, 0, 0);
  //添加到场景中
  scene.add(mesh);

  //创建相机
  camera = new THREE.PerspectiveCamera(
    75,
    width.value / height.value,
    0.1,
    1000
  );
  //设置相机位置
  camera.position.set(0, 10, 30);
  //相机默认看向网格对象
  camera.lookAt(mesh.position);

  //创建渲染器
  renderer = new THREE.WebGLRenderer({
    alpha: true, //开启渲染器画布的透明度通道
  });
  //设置黑色背景和透明度0.6
  renderer.setClearColor(0x000000, 0.6);

  //设置渲染器尺寸为父元素宽高
  renderer.setSize(width.value, height.value);

  // 设置渲染器的像素比为设备的像素比
  renderer.setPixelRatio(window.devicePixelRatio);

  //将渲染器的 DOM 元素添加到父元素中
  threeViewRef.value.appendChild(renderer.domElement);

  // 新建一个相机控件
  const controls = new OrbitControls(camera, renderer.domElement);
  // 启用阻尼(惯性效果)
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
  // 动画循环
  function animate() {
    // 定时刷新
    requestAnimationFrame(animate);
    // 更新控制器,必须调用以应用阻尼效果
    controls.update();
    //重新渲染
    renderer.render(scene, camera);
  }
  // 执行动画
  animate();

  //响应式处理
  window.addEventListener("resize", () => {
    nextTick(() => {
      if (threeViewRef.value) {
        width.value = threeViewRef.value.clientWidth;
        height.value = threeViewRef.value.clientHeight;
        //重新设置渲染区域大小
        renderer.setSize(width.value, height.value);
        //重新设置相机宽高比
        camera.aspect = width.value / height.value;
        //更新相机投影矩阵,改变相机参数需要调用才能生效
        camera.updateProjectionMatrix();
      }
    });
  });
};

//截屏
const handleScreenshot = () => {
  //导出前需要重新渲染,防止导出空白图片
  renderer.render(scene, camera);
  // 将 canvas 内容转换为 Base64 编码的图片数据
  const dataURL = renderer.domElement.toDataURL("image/png");
  // 创建一个链接元素
  const link = document.createElement("a");
  link.href = dataURL;
  link.download = "threejs_scene.png";
  // 模拟点击链接进行下载
  link.click();
};
</script>
<style  scoped>
.container {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #f2f2f2;
  padding: 10px;
  box-sizing: border-box;
}
.toolbar {
  height: 60px;
  background-color: #fff;
  display: flex;
  align-items: center;
  border-radius: 10px;
  padding-left: 10px;
  box-sizing: border-box;
}
.screenshot {
  background-color: rgb(35, 119, 230);
  color: #fff;
}
.three-view {
  margin-top: 12px;
  flex: 1;
  height: 0;
  background: url("https://img0.baidu.com/it/u=1288055865,1854912761&fm=253&fmt=auto&app=138&f=JPEG?w=1204&h=800")
    no-repeat center/100% 100%;
  border-radius: 10px;
}
</style>

运行效果:

请添加图片描述

需要注意的是:截屏前必须重新调用renderer.render(scene, camera)更新画布内容,防止导出空白图片。


总结

      通过本文的学习,相信你已经掌握了Three.js渲染器的核心用法。要记住,优秀的渲染配置需要在画面质量与性能之间找到最佳平衡点。建议在实际项目中通过Chrome Performance面板进行实时性能分析,找到最适合你项目的配置方案。

更多three.js入门知识点请关注该系列教程后续的更新。


http://www.kler.cn/a/555472.html

相关文章:

  • kubernetes1.28部署mysql5.7主从同步,使用Nfs制作持久卷存储,适用于centos7/9操作系统,
  • Deepseek 与 ChatGPT:AI 浪潮中的双子星较量
  • JavaScript 开发秘籍:日常总结与实战技巧-1
  • postgresql实时同步数据表mysql
  • HttpSession类的对象session:保存的数据谁有权限读取?
  • 面试基础-如何设计一个短链接系统
  • 使用 Docker-compose 部署 MySQL
  • Openai Dashboard可视化微调大语言模型
  • C++游戏开发流程图
  • idea从远程gitee拉取项目
  • SVN服务器搭建【Linux】
  • Node os模块
  • Android开发-深入解析Android中的AIDL及其应用场景
  • SpringCloud系列教程:微服务的未来(二十四)Direct交换机、Topic交换机、声明队列交换机
  • 蓝桥杯备赛 Day15 动态规划
  • STM32 HAL库UART串口数据接收实验
  • Golang访问Google Sheet
  • Java 中的内存泄漏问题及解决方案
  • PDF 分割与合并 工具资源分享
  • 合规数助力律师专业工作,开启法律科技新篇