带有Three.js的WebGL –第1课

WebGL With Three.js - Lesson 1
WebGL With Three.js - Lesson 1

WebGL With Three.js – Lesson 1 As we have promised – it is time to start our new series of articles devoted to the WebGL. This is our first lesson, where we consider the main basic functions: creating a scene, camera, renderer, controls (OrbitControls). We will also create the simplest directional light, add a dozen objects (of different geometry) with shadows. In order to make things went faster, we decided to take one of the most popular webgl frameworks – three.js. Why use Three.js? Besides the fact that it is open source JavaScript framework, it is also the most rapidly growing and discussed engine. Here already implemented really many possibilities, from low-level work with points and vectors, to work with ready scenes, shaders and even stereoscopic effects.

带有Three.js的WebGL –第1课正如我们所承诺的–现在是时候开始撰写有关WebGL的新系列文章了。 这是我们的第一课,其中考虑了主要的基本功能:创建场景,相机,渲染器,控件(OrbitControls)。 我们还将创建最简单的定向光,并添加带有阴影的十二个对象(不同几何形状)。 为了使事情更快,我们决定采用一种最受欢迎​​的webgl框架– three.js。 为什么要使用Three.js? 除了它是开源JavaScript框架外,它还是发展最快和讨论最广泛的引擎。 在这里,已经实现了很多可能性,从使用点和矢量的低级工作到准备好场景,着色器甚至是立体效果。

现场演示

HTML (HTML)

We could omit this step, but, habitually, we do it at every lesson. So here’s the html structure of our lesson:

我们可以省略此步骤,但是习惯上,我们在每节课中都这样做。 因此,这是我们课程的html结构:


<!DOCTYPE html>
<html lang="en" >
    <head>
        <meta charset="utf-8" />
        <meta name="author" content="Script Tutorials" />
        <title>WebGL With Three.js - Lesson 1 | Script Tutorials</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
        <link href="css/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <script src="js/three.min.js"></script>
        <script src="js/THREEx.WindowResize.js"></script>
        <script src="js/OrbitControls.js"></script>
        <script src="js/stats.min.js"></script>
        <script src="js/script.js"></script>
    </body>
</html>

<!DOCTYPE html>
<html lang="en" >
    <head>
        <meta charset="utf-8" />
        <meta name="author" content="Script Tutorials" />
        <title>WebGL With Three.js - Lesson 1 | Script Tutorials</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
        <link href="css/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <script src="js/three.min.js"></script>
        <script src="js/THREEx.WindowResize.js"></script>
        <script src="js/OrbitControls.js"></script>
        <script src="js/stats.min.js"></script>
        <script src="js/script.js"></script>
    </body>
</html>

In this code, we just connect all the libraries that we are going to use today.

在这段代码中,我们只连接了今天要使用的所有库。

Java脚本 (Javascript)

I hope that you have already seen our demo and imagine what the basic elements it is composed, we will consider the creation of each item step-by-step.

我希望您已经看过我们的演示并想象它的基本元素,我们将逐步考虑每个项目的创建。

骨架 (Skeleton)

Abstractly, our scene looks like this:

抽象地,我们的场景如下所示:


var lesson1 = {
    scene: null,
    camera: null,
    renderer: null,
    container: null,
    controls: null,
    clock: null,
    stats: null,
    init: function() { // Initialization
    }
};
// Animate the scene
function animate() {
    requestAnimationFrame(animate);
    render();
    update();
}
// Update controls and stats
function update() {
    lesson1.controls.update(lesson1.clock.getDelta());
    lesson1.stats.update();
}
// Render the scene
function render() {
    if (lesson1.renderer) {
        lesson1.renderer.render(lesson1.scene, lesson1.camera);
    }
}
// Initialize lesson on page load
function initializeLesson() {
    lesson1.init();
    animate();
}
if (window.addEventListener)
    window.addEventListener('load', initializeLesson, false);
else if (window.attachEvent)
    window.attachEvent('onload', initializeLesson);
else window.onload = initializeLesson;

var lesson1 = {
    scene: null,
    camera: null,
    renderer: null,
    container: null,
    controls: null,
    clock: null,
    stats: null,
    init: function() { // Initialization
    }
};
// Animate the scene
function animate() {
    requestAnimationFrame(animate);
    render();
    update();
}
// Update controls and stats
function update() {
    lesson1.controls.update(lesson1.clock.getDelta());
    lesson1.stats.update();
}
// Render the scene
function render() {
    if (lesson1.renderer) {
        lesson1.renderer.render(lesson1.scene, lesson1.camera);
    }
}
// Initialize lesson on page load
function initializeLesson() {
    lesson1.init();
    animate();
}
if (window.addEventListener)
    window.addEventListener('load', initializeLesson, false);
else if (window.attachEvent)
    window.attachEvent('onload', initializeLesson);
else window.onload = initializeLesson;

This is common structure of application built with three.js. Almost everything will be created in the ‘init’ function.

这是用three.js构建的应用程序的通用结构。 几乎所有内容都将在“ init”函数中创建。

场景,相机和渲染器的创建 (Creation of scene, camera and renderer)

They are the main elements of our scene, they following code creates an empty scene with perspective camera and renderer with enabled shadow map:

它们是场景的主要元素,下面的代码使用启用了阴影贴图的透视相机和渲染器创建一个空场景:


    // create main scene
    this.scene = new THREE.Scene();
    var SCREEN_WIDTH = window.innerWidth,
        SCREEN_HEIGHT = window.innerHeight;
    // prepare camera
    var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 10000;
    this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
    this.scene.add(this.camera);
    this.camera.position.set(-1000, 1000, 0);
    this.camera.lookAt(new THREE.Vector3(0,0,0));
    // prepare renderer
    this.renderer = new THREE.WebGLRenderer({antialias:true, alpha: false});
    this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    this.renderer.setClearColor(0xffffff);
    this.renderer.shadowMapEnabled = true;
    this.renderer.shadowMapSoft = true;
    // prepare container
    this.container = document.createElement('div');
    document.body.appendChild(this.container);
    this.container.appendChild(this.renderer.domElement);
    // events
    THREEx.WindowResize(this.renderer, this.camera);

    // create main scene
    this.scene = new THREE.Scene();
    var SCREEN_WIDTH = window.innerWidth,
        SCREEN_HEIGHT = window.innerHeight;
    // prepare camera
    var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 10000;
    this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
    this.scene.add(this.camera);
    this.camera.position.set(-1000, 1000, 0);
    this.camera.lookAt(new THREE.Vector3(0,0,0));
    // prepare renderer
    this.renderer = new THREE.WebGLRenderer({antialias:true, alpha: false});
    this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    this.renderer.setClearColor(0xffffff);
    this.renderer.shadowMapEnabled = true;
    this.renderer.shadowMapSoft = true;
    // prepare container
    this.container = document.createElement('div');
    document.body.appendChild(this.container);
    this.container.appendChild(this.renderer.domElement);
    // events
    THREEx.WindowResize(this.renderer, this.camera);

We set the camera at an angle of 45 degrees, set the full screen size and white cleanup color for WebGLRenderer, added our scene in the HTML document, and also connected THREEx.WindowResize to control the renderer and the camera when resizing the window (of browser).

我们将相机设置为45度角,设置WebGLRenderer的全屏尺寸和白色清理颜色,在HTML文档中添加场景,并连接THREEx.WindowResize以在调整窗口大小时控制渲染器和相机。浏览器)。

轨道控制和统计 (OrbitControls and Stats)

In order to be able to somehow control the camera – three.js gives us the possibility to use ready-made controls. One of these is OrbitControls, which provides the ability to rotate the scene around its axis. Also it will be helpful to see the statistics (FPS) of our scene – a very small class Stats will help us (stats.min.js).

为了能够以某种方式控制摄像机– three.js使我们可以使用现成的控件。 其中之一是OrbitControls,它提供了围绕场景轴旋转场景的功能。 查看场景的统计信息(FPS)也将很有帮助-很小的Stats类将对我们有所帮助(stats.min.js)。


    // prepare controls (OrbitControls)
    this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
    this.controls.target = new THREE.Vector3(0, 0, 0);
    // prepare clock
    this.clock = new THREE.Clock();
    // prepare stats
    this.stats = new Stats();
    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.bottom = '0px';
    this.stats.domElement.style.zIndex = 10;
    this.container.appendChild( this.stats.domElement );

    // prepare controls (OrbitControls)
    this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
    this.controls.target = new THREE.Vector3(0, 0, 0);
    // prepare clock
    this.clock = new THREE.Clock();
    // prepare stats
    this.stats = new Stats();
    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.bottom = '0px';
    this.stats.domElement.style.zIndex = 10;
    this.container.appendChild( this.stats.domElement );

Thus we have prepared four materials

因此,我们准备了四种材料

创造光与地面 (Creation of light and ground)

Light is one of the important elements of the scene, in our first tutorial we will create the most simple – directional light, since we are going to add basic shadows:

灯光是场景的重要元素之一,在我们的第一个教程中,我们将创建最简单的定向灯光,因为我们将添加基本的阴影:


    // add directional light
    var dLight = new THREE.DirectionalLight(0xffffff);
    dLight.position.set(1, 1000, 1);
    dLight.castShadow = true;
    dLight.shadowCameraVisible = true;
    dLight.shadowDarkness = 0.2;
    dLight.shadowMapWidth = dLight.shadowMapHeight = 1000;
    this.scene.add(dLight);
    // add particle of light
    particleLight = new THREE.Mesh( new THREE.SphereGeometry(10, 10, 10), new THREE.MeshBasicMaterial({ color: 0x44ff44 }));
    particleLight.position = dLight.position;
    this.scene.add(particleLight);
    // add simple ground
    var groundGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
    ground = new THREE.Mesh(groundGeometry, new THREE.MeshLambertMaterial({
        color: this.getRandColor()
    }));
    ground.position.y = 0;
    ground.rotation.x = - Math.PI / 2;
    ground.receiveShadow = true;
    this.scene.add(ground);

    // add directional light
    var dLight = new THREE.DirectionalLight(0xffffff);
    dLight.position.set(1, 1000, 1);
    dLight.castShadow = true;
    dLight.shadowCameraVisible = true;
    dLight.shadowDarkness = 0.2;
    dLight.shadowMapWidth = dLight.shadowMapHeight = 1000;
    this.scene.add(dLight);
    // add particle of light
    particleLight = new THREE.Mesh( new THREE.SphereGeometry(10, 10, 10), new THREE.MeshBasicMaterial({ color: 0x44ff44 }));
    particleLight.position = dLight.position;
    this.scene.add(particleLight);
    // add simple ground
    var groundGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
    ground = new THREE.Mesh(groundGeometry, new THREE.MeshLambertMaterial({
        color: this.getRandColor()
    }));
    ground.position.y = 0;
    ground.rotation.x = - Math.PI / 2;
    ground.receiveShadow = true;
    this.scene.add(ground);

When we create the light, we enabled two parameters (castShadow and shadowCameraVisible). This will allow us to visually see where is the light and we can understand the process of creating (and boundaries) of shadows.

创建灯光时,我们启用了两个参数(castShadow和shadowCameraVisible)。 这将使我们能够直观地看到光源在哪里,并且我们可以了解阴影的创建(和边界)过程。

You may also notice that immediately after the light, we have added a spherical object – it is for you, to be able to visually know in what position is our directional light source. In order to create the earth – we used the flat element (PlaneGeometry), to prepare it to receiveshadows – we set the ‘receiveShadow’ param to ‘true’.

您可能还会注意到,在光线之后,我们立即添加了一个球形物体–正是为了您,它能够从视觉上知道我们的定向光源在哪个位置。 为了创建地球-我们使用了平面元素(PlaneGeometry),以使其准备好接收阴影-我们将'receiveShadow'参数设置为'true'。

色彩 (Colors)

Soon we will add additional objects in the scene. But, I prepared one additional function to generate a different color for our items. This function will randomly return a color from a predefined list of pastel colors.

不久,我们将在场景中添加其他对象。 但是,我准备了一个附加功能来为我们的商品生成不同的颜色。 此功能将从预定义的柔和颜色列表中随机返回一种颜色。


var colors = [
    0xFF62B0,
    0x9A03FE,
    0x62D0FF,
    0x48FB0D,
    0xDFA800,
    0xC27E3A,
    0x990099,
    0x9669FE,
    0x23819C,
    0x01F33E,
    0xB6BA18,
    0xFF800D,
    0xB96F6F,
    0x4A9586
];
getRandColor: function() {
    return colors[Math.floor(Math.random() * colors.length)];
}

var colors = [
    0xFF62B0,
    0x9A03FE,
    0x62D0FF,
    0x48FB0D,
    0xDFA800,
    0xC27E3A,
    0x990099,
    0x9669FE,
    0x23819C,
    0x01F33E,
    0xB6BA18,
    0xFF800D,
    0xB96F6F,
    0x4A9586
];
getRandColor: function() {
    return colors[Math.floor(Math.random() * colors.length)];
}

CircleGeometry / CubeGeometry / CylinderGeometry和ExtrudeGeometry (CircleGeometry / CubeGeometry / CylinderGeometry and ExtrudeGeometry)

Geometry is an object to hold all necessary data to describe any 3D model (points, vertices, faces etc). All the listed geometries are used to create such objects as: circle (plain), cube and cylinder. Extrude Geometry is used to extrude geometry from a path shape. We are going to extrude triangle:

几何是保存所有必要数据以描述任何3D模型(点,顶点,面等)的对象。 列出的所有几何图形均用于创建以下对象:圆形(普通),立方体和圆柱体。 挤压几何体用于从路径形状挤压几何体。 我们将挤压三角形:


    // add circle shape
    var circle = new THREE.Mesh(new THREE.CircleGeometry(70, 50), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    circle.rotation.x = - Math.PI / 2;
    circle.rotation.y = - Math.PI / 3;
    circle.rotation.z = Math.PI / 3;
    circle.position.x = -300;
    circle.position.y = 150;
    circle.position.z = -300;
    circle.castShadow = circle.receiveShadow = true;
    this.scene.add(circle);
    // add cube shape
    var cube = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    cube.rotation.x = cube.rotation.z = Math.PI * 0.1;
    cube.position.x = -300;
    cube.position.y = 150;
    cube.position.z = -100;
    cube.castShadow = cube.receiveShadow = true;
    this.scene.add(cube);
    // add cylinder shape
    var cube = new THREE.Mesh(new THREE.CylinderGeometry(60, 80, 90, 32), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    cube.rotation.x = cube.rotation.z = Math.PI * 0.1;
    cube.position.x = -300;
    cube.position.y = 150;
    cube.position.z = 100;
    cube.castShadow = cube.receiveShadow = true;
    this.scene.add(cube);
    // add extrude geometry shape
    var extrudeSettings = {
        amount: 10,
        steps: 10,
        bevelSegments: 10,
        bevelSize: 10,
        bevelThickness: 10
    };
    var triangleShape = new THREE.Shape();
    triangleShape.moveTo(  0, -50 );
    triangleShape.lineTo(  -50, 50 );
    triangleShape.lineTo( 50, 50 );
    triangleShape.lineTo(  0, -50 );
    var extrude = new THREE.Mesh(new THREE.ExtrudeGeometry(triangleShape, extrudeSettings), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    extrude.rotation.y = Math.PI / 2;
    extrude.position.x = -300;
    extrude.position.y = 150;
    extrude.position.z = 300;
    extrude.castShadow = extrude.receiveShadow = true;
    this.scene.add(extrude);

    // add circle shape
    var circle = new THREE.Mesh(new THREE.CircleGeometry(70, 50), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    circle.rotation.x = - Math.PI / 2;
    circle.rotation.y = - Math.PI / 3;
    circle.rotation.z = Math.PI / 3;
    circle.position.x = -300;
    circle.position.y = 150;
    circle.position.z = -300;
    circle.castShadow = circle.receiveShadow = true;
    this.scene.add(circle);
    // add cube shape
    var cube = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    cube.rotation.x = cube.rotation.z = Math.PI * 0.1;
    cube.position.x = -300;
    cube.position.y = 150;
    cube.position.z = -100;
    cube.castShadow = cube.receiveShadow = true;
    this.scene.add(cube);
    // add cylinder shape
    var cube = new THREE.Mesh(new THREE.CylinderGeometry(60, 80, 90, 32), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    cube.rotation.x = cube.rotation.z = Math.PI * 0.1;
    cube.position.x = -300;
    cube.position.y = 150;
    cube.position.z = 100;
    cube.castShadow = cube.receiveShadow = true;
    this.scene.add(cube);
    // add extrude geometry shape
    var extrudeSettings = {
        amount: 10,
        steps: 10,
        bevelSegments: 10,
        bevelSize: 10,
        bevelThickness: 10
    };
    var triangleShape = new THREE.Shape();
    triangleShape.moveTo(  0, -50 );
    triangleShape.lineTo(  -50, 50 );
    triangleShape.lineTo( 50, 50 );
    triangleShape.lineTo(  0, -50 );
    var extrude = new THREE.Mesh(new THREE.ExtrudeGeometry(triangleShape, extrudeSettings), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    extrude.rotation.y = Math.PI / 2;
    extrude.position.x = -300;
    extrude.position.y = 150;
    extrude.position.z = 300;
    extrude.castShadow = extrude.receiveShadow = true;
    this.scene.add(extrude);

Once the geometry is created, we can create a Mesh on the basis of this geometry. When you create a Mesh, we specify the material (as the second argument).

创建几何图形后,我们可以基于此几何图形创建网格。 创建网格时,我们指定材质(作为第二个参数)。

二十面体几何/八面体几何/ RingGeometry和ShapeGeometry (IcosahedronGeometry / OctahedronGeometry / RingGeometry and ShapeGeometry)

Now we will create the next four elements: icosahedron, octahedron, ring, and the object by a custom path (shape) using ShapeGeometry:

现在,我们将使用ShapeGeometry通过自定义路径(形状)创建接下来的四个元素:二十面体,八面体,环和对象:


    // add icosahedron shape
    var icosahedron = new THREE.Mesh(new THREE.IcosahedronGeometry(70), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    icosahedron.position.x = -100;
    icosahedron.position.y = 150;
    icosahedron.position.z = -300;
    icosahedron.castShadow = icosahedron.receiveShadow = true;
    this.scene.add(icosahedron);
    // add octahedron shape
    var octahedron = new THREE.Mesh(new THREE.OctahedronGeometry(70), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    octahedron.position.x = -100;
    octahedron.position.y = 150;
    octahedron.position.z = -100;
    octahedron.castShadow = octahedron.receiveShadow = true;
    this.scene.add(octahedron);
    // add ring shape
    var ring = new THREE.Mesh(new THREE.RingGeometry(30, 70, 32), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    ring.rotation.y = -Math.PI / 2;
    ring.position.x = -100;
    ring.position.y = 150;
    ring.position.z = 100;
    ring.castShadow = ring.receiveShadow = true;
    this.scene.add(ring);
    // add shape geometry shape
    var shapeG = new THREE.Mesh(new THREE.ShapeGeometry(triangleShape), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    shapeG.rotation.y = -Math.PI / 2;
    shapeG.position.x = -100;
    shapeG.position.y = 150;
    shapeG.position.z = 300;
    shapeG.castShadow = shapeG.receiveShadow = true;
    this.scene.add(shapeG);

    // add icosahedron shape
    var icosahedron = new THREE.Mesh(new THREE.IcosahedronGeometry(70), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    icosahedron.position.x = -100;
    icosahedron.position.y = 150;
    icosahedron.position.z = -300;
    icosahedron.castShadow = icosahedron.receiveShadow = true;
    this.scene.add(icosahedron);
    // add octahedron shape
    var octahedron = new THREE.Mesh(new THREE.OctahedronGeometry(70), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    octahedron.position.x = -100;
    octahedron.position.y = 150;
    octahedron.position.z = -100;
    octahedron.castShadow = octahedron.receiveShadow = true;
    this.scene.add(octahedron);
    // add ring shape
    var ring = new THREE.Mesh(new THREE.RingGeometry(30, 70, 32), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    ring.rotation.y = -Math.PI / 2;
    ring.position.x = -100;
    ring.position.y = 150;
    ring.position.z = 100;
    ring.castShadow = ring.receiveShadow = true;
    this.scene.add(ring);
    // add shape geometry shape
    var shapeG = new THREE.Mesh(new THREE.ShapeGeometry(triangleShape), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    shapeG.rotation.y = -Math.PI / 2;
    shapeG.position.x = -100;
    shapeG.position.y = 150;
    shapeG.position.z = 300;
    shapeG.castShadow = shapeG.receiveShadow = true;
    this.scene.add(shapeG);

球形几何/四面体几何/ TorusGeometry / TorusKnotGeometry和TubeGeometry (SphereGeometry / TetrahedronGeometry / TorusGeometry / TorusKnotGeometry and TubeGeometry)

Finally, we create a sphere, tetrahedron, torus, torus knot and tube:

最后,我们创建一个球体,四面体,圆环,圆环结和管形:


    // add sphere shape
    var sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 32, 32), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    sphere.rotation.y = -Math.PI / 2;
    sphere.position.x = 100;
    sphere.position.y = 150;
    sphere.position.z = -300;
    sphere.castShadow = sphere.receiveShadow = true;
    this.scene.add(sphere);
    // add tetrahedron shape
    var tetrahedron = new THREE.Mesh(new THREE.TetrahedronGeometry(70), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    tetrahedron.position.x = 100;
    tetrahedron.position.y = 150;
    tetrahedron.position.z = -100;
    tetrahedron.castShadow = tetrahedron.receiveShadow = true;
    this.scene.add(tetrahedron);
    // add torus shape
    var torus = new THREE.Mesh(new THREE.TorusGeometry(70, 20, 16, 100), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    torus.rotation.y = -Math.PI / 2;
    torus.position.x = 100;
    torus.position.y = 150;
    torus.position.z = 100;
    torus.castShadow = torus.receiveShadow = true;
    this.scene.add(torus);
    // add torus knot shape
    var torusK = new THREE.Mesh(new THREE.TorusKnotGeometry(70, 20, 16, 100), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    torusK.rotation.y = -Math.PI / 2;
    torusK.position.x = 100;
    torusK.position.y = 150;
    torusK.position.z = 300;
    torusK.castShadow = torusK.receiveShadow = true;
    this.scene.add(torusK);
    // add tube shape
    var points = [];
    for (var i = 0; i < 10; i++) {
        var randomX = -100 + Math.round(Math.random() * 200);
        var randomY = -100 + Math.round(Math.random() * 200);
        var randomZ = -100 + Math.round(Math.random() * 200);
        points.push(new THREE.Vector3(randomX, randomY, randomZ));
    }
    var tube = new THREE.Mesh(new THREE.TubeGeometry(new THREE.SplineCurve3(points), 64, 20), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    tube.rotation.y = -Math.PI / 2;
    tube.position.x = 0;
    tube.position.y = 500;
    tube.position.z = 0;
    tube.castShadow = tube.receiveShadow = true;
    this.scene.add(tube);

    // add sphere shape
    var sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 32, 32), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    sphere.rotation.y = -Math.PI / 2;
    sphere.position.x = 100;
    sphere.position.y = 150;
    sphere.position.z = -300;
    sphere.castShadow = sphere.receiveShadow = true;
    this.scene.add(sphere);
    // add tetrahedron shape
    var tetrahedron = new THREE.Mesh(new THREE.TetrahedronGeometry(70), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    tetrahedron.position.x = 100;
    tetrahedron.position.y = 150;
    tetrahedron.position.z = -100;
    tetrahedron.castShadow = tetrahedron.receiveShadow = true;
    this.scene.add(tetrahedron);
    // add torus shape
    var torus = new THREE.Mesh(new THREE.TorusGeometry(70, 20, 16, 100), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    torus.rotation.y = -Math.PI / 2;
    torus.position.x = 100;
    torus.position.y = 150;
    torus.position.z = 100;
    torus.castShadow = torus.receiveShadow = true;
    this.scene.add(torus);
    // add torus knot shape
    var torusK = new THREE.Mesh(new THREE.TorusKnotGeometry(70, 20, 16, 100), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    torusK.rotation.y = -Math.PI / 2;
    torusK.position.x = 100;
    torusK.position.y = 150;
    torusK.position.z = 300;
    torusK.castShadow = torusK.receiveShadow = true;
    this.scene.add(torusK);
    // add tube shape
    var points = [];
    for (var i = 0; i < 10; i++) {
        var randomX = -100 + Math.round(Math.random() * 200);
        var randomY = -100 + Math.round(Math.random() * 200);
        var randomZ = -100 + Math.round(Math.random() * 200);
        points.push(new THREE.Vector3(randomX, randomY, randomZ));
    }
    var tube = new THREE.Mesh(new THREE.TubeGeometry(new THREE.SplineCurve3(points), 64, 20), new THREE.MeshLambertMaterial({ color: this.getRandColor() }));
    tube.rotation.y = -Math.PI / 2;
    tube.position.x = 0;
    tube.position.y = 500;
    tube.position.z = 0;
    tube.castShadow = tube.receiveShadow = true;
    this.scene.add(tube);

Pay attention to the process of creating the pipe. TubeGeometry allows us to build a cylindrical object by the array of points.

注意创建管道的过程。 TubeGeometry允许我们通过点阵列来构建圆柱对象。

光的平稳运动 (Smooth movement of the light)

In order to smoothly move the light, we only need to add the following code in the ‘update’ function:

为了平稳地移动灯光,我们只需要在“更新”功能中添加以下代码:


    // smoothly move the particleLight
    var timer = Date.now() * 0.000025;
    particleLight.position.x = Math.sin(timer * 5) * 300;
    particleLight.position.z = Math.cos(timer * 5) * 300;

    // smoothly move the particleLight
    var timer = Date.now() * 0.000025;
    particleLight.position.x = Math.sin(timer * 5) * 300;
    particleLight.position.z = Math.cos(timer * 5) * 300;

现场演示

[sociallocker]

[社交储物柜]

打包下载

[/sociallocker]

[/ sociallocker]

结论 (Conclusion)

I think that we done enough for our first lesson. In addition to creating a scene, we also saw how to create a shadow, and even made a review of almost all possible geometries. See you at the next lesson!

我认为我们为第一堂课做了足够的工作。 除了创建场景之外,我们还了解了如何创建阴影,甚至还回顾了几乎所有可能的几何形状。 下节课见!

翻译自: https://www.script-tutorials.com/webgl-with-three-js-lesson-1/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值