ThreeJs学习笔记——渲染(render)分析

一、前言

ThreeJs 封装了 WebGL 进行渲染时所涉及到的相关概念,如光照,材质,纹理以及相机等。除此之外,其还抽象了场景(Scene)以及用于渲染的渲染器(WebGLRenderer)。这些相关概念都被封装成了一个对象,那么它们是如何协作的呢,关系又是如何呢?这篇文章主要就是来分析一下 ThreeJs 中核心中的核心,即场景,物体,光照,材质,纹理以及相机这些对象是如何渲染的。

下面截取了一个渲染效果图,看起来还不错是不是。这是 ThreeJs 的官方 demo lights / spotlights 的渲染效果图。这个 demo 中就基本涉及到了上面所提的核心对象,下面我将基于此 demo 来分析这些核心对象是如何被组织在一起进行渲染的。

二、demo 解析

Demo 有一点点长,对于不熟悉 ThreeJs 的人来说会有一点点难度,因此这里主要分析了构建、初始化以及渲染 3 个部分来分别说明。

1.构建

// 构建渲染器 WebGLRenderer            
var renderer = new THREE.WebGLRenderer();
// 设置显示比例
renderer.setPixelRatio( window.devicePixelRatio );
// 构建一个透视投影的相机
var camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 2000 );
// 构建一个轨道控制器,主要就是通过鼠标来控制相机沿目标物体旋转,从而达到像在旋转场景一样,可以从各个不同角度观察物体
var controls = new THREE.OrbitControls( camera, renderer.domElement );
// 构建场景
var scene = new THREE.Scene();
// 构建Phong网格材质MeshPhongMaterial,该材质可以模拟具有镜面高光的光泽表面,一个用于接收阴影的平面,一个用于场景中的物体 Box
var matFloor = new THREE.MeshPhongMaterial();
var matBox = new THREE.MeshPhongMaterial( { color: 0xaaaaaa } );
// 构建几何体,同样分别用于 平面 和 Box
var geoFloor = new THREE.PlaneBufferGeometry( 2000, 2000 );
var geoBox = new THREE.BoxBufferGeometry( 3, 1, 2 );
// 构建平面网格 mesh
var mshFloor = new THREE.Mesh( geoFloor, matFloor );
mshFloor.rotation.x = - Math.PI * 0.5;
// 构建 box 网格 mesh
var mshBox = new THREE.Mesh( geoBox, matBox );
// 构建环境光
var ambient = new THREE.AmbientLight( 0x111111 );
// 构建 3 个不同颜色的 聚光灯(SpotLight)
var spotLight1 = createSpotlight( 0xFF7F00 );
var spotLight2 = createSpotlight( 0x00FF7F );
var spotLight3 = createSpotlight( 0x7F00FF );
// 声明用于描述聚光灯的 3 个不同光束帮助器
var lightHelper1, lightHelper2, lightHelper3;
复制代码

上面代码中,基本上每一行都添加了详细的注释,其中有调用了一个内部的函数 createSpotlight() ,如下。

 function createSpotlight( color ) {

	var newObj = new THREE.SpotLight( color, 2 );

	newObj.castShadow = true;
	newObj.angle = 0.3;
	newObj.penumbra = 0.2;
	newObj.decay = 2;
	newObj.distance = 50;

	newObj.shadow.mapSize.width = 1024;
	newObj.shadow.mapSize.height = 1024;

	return newObj;

}
复制代码

这个方法,主要就是根据指定的颜色构建一个聚光灯并设置好相应的参数。这里不管是相机、光照、材质还是物体,其详细的参数并不打算在这里一一讲述,有需要的话再进一步说明。

2.初始化

function init() {
	......

    // 将平面,box,环境光以及光源辅助器等全部添加到 scene 中
	scene.add( mshFloor );
	scene.add( mshBox );
	scene.add( ambient );
	scene.add( spotLight1, spotLight2, spotLight3 );
	scene.add( lightHelper1, lightHelper2, lightHelper3 );

	document.body.appendChild( renderer.domElement );
	onResize();
	window.addEventListener( 'resize', onResize, false );

	controls.target.set( 0, 7, 0 );
	controls.maxPolarAngle = Math.PI / 2;
	controls.update();

}
复制代码

初始化主要就是将平面,box ,光照这些都添加进场景中,但是要注意,相机并没有被添加进来。

3.渲染

function render() {

	TWEEN.update();

	if ( lightHelper1 ) lightHelper1.update();
	if ( lightHelper2 ) lightHelper2.update();
	if ( lightHelper3 ) lightHelper3.update();

	renderer.render( scene, camera );

	requestAnimationFrame( render );

}
复制代码

渲染函数 render() 中最关键的调用渲染器的 WebGLRenderer#render() 方法同时去渲染场景和相机。

根据上面的分析,以及对 ThreeJs 源码的分析,梳理出如下 2 个类图关系。

图中,渲染器负责同时渲染场景以及相机。而光照和网格都被添加到场景中。几何体以及材质都是网格的 2 个基本属性,也决定一个网格的形状和表面纹理。

该图是对上图的补充,说明光照,相机以及网格都属于 Object3D 对象。在 ThreeJs 中还有许多的类都是继承自 Object3D 的。

三、渲染分析

1.关于 WebGL 需要知道的基本知识

1.1 WebGL 的渲染管线

先来看一下 WebGL 的流水线渲染管线图,如下所示。这个是必须要了解的,我们可以不必完全理解渲染管线的每个步骤,但我们必须要知道渲染管线的这个流程。

渲染管线指的是WebGL程序的执行过程,如上图所示,主要分为 4 个步骤:

  1. 顶点着色器的处理,主要是一组矩阵变换操作,用来把3D模型(顶点和原型)投影到viewport上,输出是一个个的多边形,比如三角形。

  2. 光栅化,也就是把三角形连接区域按一定的粒度逐行转化成片元(fragement),类似于2D空间中,可以把这些片元看做是3D空间的一个像素点。

  3. 片元着色器的处理,为每个片元添加颜色或者纹理。只要给出纹理或者颜色,以及纹理坐标(uv),管线就会根据纹理坐标进行插值运算,将纹理或者图片着色在相应的片元上。

  4. 把3D空间的片元合并输出为2D像素数组并显示在屏幕上。

1.2 WebGL 一般的开发流程
  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将Three.js模型加载到场景中并渲染,可以遵循以下步骤: 1. 创建场景、相机和渲染器 ```javascript var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); ``` 2. 加载模型 使用`THREE.GLTFLoader()`或`THREE.OBJLoader()`加载模型文件。例如,使用GLTFLoader加载一个gltf文件: ```javascript var loader = new THREE.GLTFLoader(); loader.load('model.gltf', function (gltf) { scene.add(gltf.scene); }, undefined, function (error) { console.error(error); }); ``` 3. 设置模型的位置、旋转和缩放 ```javascript gltf.scene.position.x = 0; gltf.scene.position.y = 0; gltf.scene.position.z = 0; gltf.scene.rotation.x = 0; gltf.scene.rotation.y = 0; gltf.scene.rotation.z = 0; gltf.scene.scale.set(1, 1, 1); ``` 4. 添加光源 ```javascript var light = new THREE.AmbientLight(0x404040); // soft white light scene.add(light); ``` 5. 渲染场景 ```javascript function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate(); ``` 完整的代码示例: ```javascript var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); var loader = new THREE.GLTFLoader(); loader.load('model.gltf', function (gltf) { scene.add(gltf.scene); gltf.scene.position.x = 0; gltf.scene.position.y = 0; gltf.scene.position.z = 0; gltf.scene.rotation.x = 0; gltf.scene.rotation.y = 0; gltf.scene.rotation.z = 0; gltf.scene.scale.set(1, 1, 1); }, undefined, function (error) { console.error(error); }); var light = new THREE.AmbientLight(0x404040); // soft white light scene.add(light); function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值