three - 3 - 基础知识(1. three渲染结构,2.对canvas 进行响应式布局,3.让canvas 画布自适应设备分辨率 )

本章节分为3点:

  • 理解three.js 的渲染结构
  • 对canvas 进行响应式布局
  • 让canvas 画布自适应设备分辨率
  • canvas 画布的css尺寸和像素尺寸

1.three.js 的渲染结构

接下来我们对这个渲染过程做一个详细解释。

Three.js 封装了场景、灯光、阴影、材质、纹理和三维算法,让你不必再直接用WebGL 开发项目。

当然,我刚才说的是“不必再直接用WebGL”,有的时候我们会间接用到WebGL,比如自定义着色器。

three.js 在渲染三维场景时,需要创建很多对象,并将它们关联在一起。

下图便是一个基本的three.js 渲染结构。
请添加图片描述
解释一下上面的示意图:

  • Render渲染器:

Render是threejs的主要对象。当你讲一个场景Scene和一个摄像机Camera传递到渲染器的渲染方法中,渲染器便会将摄像机视椎体中三维场景渲染成一个二维图像显示在canvas画布中。

  • Scene场景对象

场景对象是树状结构的,其中包含了三维对象Object3D和灯光对象Light。

Object3D可以看作是直接被渲染出来的,Object3D是网格对象Mesh和集合对象Group的基类。

场景对象可以定义场景的背景色和雾效。

在场景对象的树状结构中,每个对象的变换信息都是相对的。

比如汽车和汽车里的人,人的位置是相对于汽车而言的,当汽车移动了,人的本地坐标位坐标位虽然不变,但其世界坐标位已经变了。

  • Camera相机

按理说相机对象是咋在场景里面的,但是相机对象不在它所看的场景里面,这就像我们自己看不见自己的眼睛一样。

因此相机对象可以独立于场景之外。

相机对象可以看到其他三维对象的子对象,这样相机就会随其父对象同步变换。

  • Mesh网格对象

网格对象由几何体(Geometry)和材质(Material)2部分组成,Geometry负责塑形状,Material负责着色。

Geometry和Material可以被多个Mesh网格对象复用。

比如要绘制两个一模一样的立方体,那只需要实例化两个Mesh 即可,Geometry 和Materia可以使用一套。

  • Geometry几何体对象

几何体对象负责塑形状,存储了顶点相关的数据,比如:顶点点位,顶点索引,uv坐标等。

threejs中内置了许多基本几何体,我么也可以自定义几何体,或者从外部的模型文件里加载几何体。

  • Material材质对象

材质对象负责着色,绘制几何体的表面属性,比如:漫反射,镜面反射,光泽度,凹凸等。

  • Texture纹理对象

纹理对象就是一张图像。纹理图像的图像源可以是image图片,canvas画布,video视频等。

  • Light光源对象

Light对象不像Object3D那样依托于顶点,它更多的是像Object3D里面的材质Material,作用于物体的样式。

Light对象可以理解为:在几何体添加了材质之后,再利用光效配合材质对几何体的样式进行二次加工。

2-示例-绘制多个立方体

绘制一个立方体:
效果如下图:
请添加图片描述

渲染结构如下:
请添加图片描述

代码:
RenderStructure.tsx

import React, {
    useRef, useEffect } from "react";
import {
    BoxGeometry, DirectionalLight, Mesh, MeshNormalMaterial, MeshPhongMaterial, PerspectiveCamera, Scene, WebGLRenderer } from "three";

const {
    innerWidth, innerHeight } = window;

const scene = new Scene();
const camera = new PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 1000);
camera.position.z = 5;

const renderer = new WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);

const geometry = new BoxGeometry();
const material = new MeshNormalMaterial();
const cube = new Mesh(geometry, material);
scene.add(cube);

function animate() {
   
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}

const RenderStructure: React.FC = (): JSX.Element => {
   
  const divRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
   
    const {
    current } = divRef;
    if (current) {
   
      current.innerHTML = "";
      current.append(renderer.domElement);
      //  执行渲染动画
      animate();
    }
    
  }, []);
  return <div ref={
   divRef}></div>;
};

export default RenderStructure;

在上面的代码中,我没有直接建立 ,而是在WebGLRenderer 对象的实例化方法里建立的,在其源码可以找到相关逻辑:

function WebGLRenderer( parameters = {
    } ) {
   
	const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement()
	……
  this.domElement = _canvas;
  ……
}

通过WebGLRenderer 对象建立了canvas后,再在react的函数组件的useEffect hook 中,将canvas 添加到div 中。

const RenderStructure: React.FC = (): JSX.Element => {
  const divRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const { current } = divRef;
    current && current.append(renderer.domElement);
    animate();
  }, []);
  return <div ref={divRef}></div>;
};

当前这个立方体的材质是MeshNormalMaterial,并不受光照影响。

2.如果想受光源的影响则给立方体换个MeshPhongMaterial 材质,再添加光源。

const geometry = new BoxGeometry();

// 受光源的影响的材质
const material = new MeshPhongMaterial({
    color: 0x44aa88 });

const cube = new Mesh(geometry, material);
scene.add(cube);

// 光的颜色
const color = 0xffffff;

// 光照强度
const intensity = 1;

// 实例化平行光
const light = new DirectionalLight(color, intensity);

// 设置光源的位置(x,y,z)
light.position.set(-1, 2, 4);

//光添加到场景中。
scene.add(light);

渲染效果如下:
请添加图片描述

请添加图片描述

  1. 在场景中添加2个一摸一样的立方体,可以发现:几何体和材质可被多个Mesh 对象共享。

共享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值