运用three.js写的漂浮立方

这是本人在CSDN上的第一篇文章,因为刚刚写了一个three.js的Demo,就传上来了,参考的是国外Karim Maaloul这位大佬的飞机游戏,给了我比较大的启发,和小伙伴们分享下。


three.js

three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。 —— [ 百度百科 ]

个人感觉这个库还是比较给力的,运用了图形建模的许多思想,一些在3D建模里的相机、灯光、贴图都被运用到three里,他的引用库文件可以在GitHub上面找到并下载,格式是zip的,解压后在build文件夹的就是,一个压缩,一个没压缩,在练习阶段建议用没压缩的,点进去它的结构一步了然,方便理解原理.

Demo图

漂浮立方静态图

漂浮立方Demo展示

HTML

页面的HTML部分需要引入three.js的库文件:

<script type="text/javascript" src="js/three.js"></script>

下面是HTML部分完整的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>漂浮立方</title>
    <style type="text/css">
        *{
            margin: 0;
            padding: 0;
        }
        #world{
            width:100%;
            height: 100%;
            position: absolute;
            overflow: hidden;
            background: linear-gradient(#A4D3EE,#AEEEEE);
        }
    </style>
</head>
<body>
<div id="world"></div>

</body>
<script type="text/javascript" src="js/three.min.js"></script>

</html>

上面的代码在body里嵌套了一层div,three会在这个div里自动添加canvas,我们所有效果就在这里面,在css样式中,使用了两种背景色,作为渐变效果

JavaScript

注意three.js有四大核心要素:场景、相机、渲染器、模型对象,这四样要素缺一不可

  • 场景
    场景可以理解为舞台,是所有元素运作的环境,所有事物添加到场景中最终才能被我们看到,新建一个场景代码如下:
var scene = new THREE.Scene();

在创建好每个模型后往往用如下方法将模型置入场景中:

scene.add(e);
  • 相机

相机有正交、透视、通用三种,可以理解为我们的眼睛,这里我们使用透视相机,代码如下:

var camera = new THREE.PerspectiveCamera(a1,a2,a3,a4);

四个参数:
视角:setFov(fov)设置视角的角度
宽高比:相机所看到的宽和高的比例
near:相机的近视角
far:表示相机的远视角

  • 渲染器
    三维空间里的物体映射到二维平面的过程被称为三维渲染。 一般来说我们都把进行渲染操作的软件叫做渲染器,渲染器需要加载到DOM节点中,创建渲染器代码如下:
//新建渲染器
var renderer = new THREE.WebGLRenderer();
//body中加载渲染引擎
document.body.appendChild(renderer.domElement);
  • 模型对象
    对象模型是一种事物的组合:几何体、材质、网格,three使用网格系统来建立几何模型,我们创建一个物体通常先创建相应的几何体,再设置材质,把他们添加到网格中,形成物体,在下面会具体讲解

漂浮立方

首先我们创建一个初始化init()函数,它使得冗长的代码能够以清晰的结构呈现出来,我们主要的函数都会在init里加载

window.addEventListener('load',init,false);
function init(){
    //场景布局
    createScene();

    //灯光
    createLight();

    //场中的对象

    //海
    createEarth();
    //带云的天空
    createSky();

    //循环函数
    loop();
}
  • 场景布局

场景,相机,渲染器都是在createScene函数中创建,这是我们着手构造“世界”的准备工作,代码如下:

var scene,renderer,camera;

function createScene(){
    //新建场景
    scene = new THREE.Scene();
    //新建渲染器(允许透明度、抗锯齿、允许投影)
    renderer = new THREE.WebGLRenderer({alpha: true,antialias:true,shadowMapEnabled:true});
    //重置画板大小
    renderer.setSize(window.innerWidth,window.innerHeight);


    //相机(60度角,满屏宽高,视区1到10000)
    camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,10000);
    camera.position.set(0,300,600);
    camera.lookAt(Sea);
    camera.lookAt(scene.position);
    scene.add(camera);
    //在场景中添加雾效果
    scene.fog = new THREE.Fog(0xf7d9aa, 100, 950);

    //world中加载渲染引擎
    var world = document.getElementById('world');
    world.appendChild(renderer.domElement);

    //屏幕监听,在调整视窗时更新渲染器及相机
    window.addEventListener('resize',handleWindowResize,false);
}

我们通过一个handleWindowResize函数来使得渲染器自适应窗口的大小,在改变视窗时渲染器更新渲染,代码如下:

function handleWindowResize(){
    renderer.setSize(window.innerWidth,window.innerHeight);
    camera.aspect = window.innerWidth/window.innerHeight;
    camera.updateProjectionMatrix();
}
  • 灯光

灯光使得我们的物体能被看见,同样使用createLight函数来创建灯光,代码如下:

var hemisphereLight,shadowLight;

function createLight(){
    //创建半球灯对象
    hemisphereLight = new THREE.HemisphereLight(0xaaaaaa,0x000000,0.9);
    //创建平行光对象
    shadowLight = new THREE.DirectionalLight(0xffffff,0.9);

    shadowLight.position.set(150,350,350);
    shadowLight.castShadow = true;

    scene.add(hemisphereLight);
    scene.add(shadowLight);
}

记得将创建好的组件都添加到场景scene中,有时候我们在检查效果时,往往发现组件并没有被使用,相机的位置与视角也是影响效果的重要因素,我们事先都需要设置好

  • 场中的对象
    我们使用构造函数Earth来构造出场景中的地球类,现在我们开始构造,代码如下:
Earth = function(){
    //创建圆(上下半径600、高800、半径数40、垂直段数10)
    var geom = new THREE.SphereGeometry(600,80,60);
    //在x轴上旋转圆柱
    geom.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI/2));

    //创造材质
    var mat = new THREE.MeshPhongMaterial({
        color:'#104E8B',
        transparent:true,
        opacity:0.8,
        shading:THREE.FlatShading
    });
    //创建网格
    this.mesh = new THREE.Mesh(geom,mat);
    //允许接受阴影
    this.mesh.receiveShadow = true;


    //通过合并定点保证波的连续性
    geom.mergeVertices();
    //得到顶点数量
    var l = geom.vertices.length;

    //建立一个数组储存与每个顶点相关的新数据
    this.waves = [];

    for (var i = 0;i<l;i++){
        //得到每个顶点
        var v = geom.vertices[i];
        //存储与之相关的数据
        this.waves.push({
            x: v.x,
            y: v.y,
            z: v.z,
            //随机角
            ang:Math.random()*Math.PI*2,
            //随机距离
            amp:5 + Math.random()*15,
            //0.016到0.048间速度
            speed:0.016 + Math.random*0.032
        });
    }

}

为了使得地球看上去更加有意思一点我们使它的的表面凹凸不平,所以我们为它增加一个方法moveWaves,这里用到了原型继承的知识,代码如下:

Earth.prototype.moveWaves = function(){

    //得到顶点
    var verts = this.mesh.geometry.vertices;
    var l = verts.length;
    for (var i=0; i<l; i++){
        var v = verts[i];

        //获取相关的波数据
        var vprops = this.waves[i];

        //更新顶点的位置
        v.x = vprops.x + Math.cos(vprops.ang)*vprops.amp;
        v.y = vprops.y + Math.sin(vprops.ang)*vprops.amp;

        //增加下一帧的角度
        vprops.ang += vprops.speed;
    }

    earth.mesh.rotation.z += 0.0005;
}

moveWaves方法会在循环函数中调用,一次来对每一帧进行渲染,就能模拟出地球表面凹凸不平的效果

下面我们使用createEarth函数来实例化地球类,并设置其位置,代码如下:

var earth;

function createEarth(){
    earth = new Earth();
    //让海洋圆柱在屏幕下方位置
    earth.mesh.position.y = -600;
    earth.mesh.position.z = 500;

    scene.add(earth.mesh);
}

我们用简单的随机立方体来模拟漂浮在天空中的云朵,接下来我们创建Cloud的构造函数,来创建云朵类,代码如下:

Cloud = function(){
    //创建一个3D对象用作容器
    this.mesh = new THREE.Object3D();
    //创建立体几何,用来复制云
    var geom = new THREE.BoxGeometry(20,20,20);
    //材质
    var mat = new THREE.MeshPhongMaterial({
        color:'#FFFFFF'
    });
    //复制几何,次数随机,造云
    //最大6、最小3
    var nBlocs = 3 + Math.floor(Math.random()*3);
    for (var i = 0;i<nBlocs;i++){
        //复制网格,用来创建几何图形
        var m = new THREE.Mesh(geom,mat);
        //设置每个方块的位置和旋转量,随机
        m.position.x = i*15;
        m.position.y = Math.random()*10;
        m.position.z = Math.random()*10;
        m.rotation.z = Math.random()*Math.PI*2;
        m.rotation.y = Math.random()*Math.PI*2;

        //设置方块大小,随机
        var s = 0.2 + Math.random()*0.3;
        m.scale.set(s,s,s);

        //允许每个方块投影并接受阴影
        m.castShadow = true;
        m.receiveShadow = true;

        this.mesh.add(m);
    }
}

云朵在天空中是看似随机有规律的的运动着的,我们还需要创建一个天空的构造函数来对云进行分布,代码如下:

Sky = function(){
    //3D容器
    this.mesh = new THREE.Object3D();
    //在天空中选择一些云
    this.nClouds = 20;

    //规定统一角度放置云
    var stepAngle = Math.PI*2 / this.nClouds;

    //创建云
    for (var i = 0;i<this.nClouds;i++){
        //实例化一个云对象
        var c = new Cloud();

        //设置每片云的位置和旋转
        //利用简单的三角学知识
        var a = stepAngle*i;//云的最后一个角度
        var h = 650 + Math.random()*100;//轴中心和云的距离(云高),700到950之间

        //运用三角函数知识(以轴心为原点r边为h,y = sin(x轴夹角度)*h)
        //把极坐标转换成笛卡尔坐标
        c.mesh.position.y = Math.sin(a)*h;
        c.mesh.position.x = Math.cos(a)*h;

        //根据位置旋转云
        c.mesh.rotation.z = a + Math.PI/2;

        //随机云的深度
        c.mesh.position.z = -400 - Math.random()*400;

        //为每片云设置随机规模比例
        var s = 1 + Math.random()*2;
        c.mesh.scale.set(s,s,s);


        this.mesh.add(c.mesh);


    }
}

从上面的代码中我们使用了三角函数的知识,这需要我们有良好的数学基础,实际上我们在编写的算法就是数学运算,如果在这方面有所欠缺,应该要补一补啦,但建议缺哪里补哪里

下面对天空的构造函数进行实例化,使我们的漂浮立方呈现出来,代码如下:

function createSky(){
    sky = new Sky();
    sky.mesh.position.y = -600;
    sky.mesh.position.z = 700;
    scene.add(sky.mesh);
}

写到这里我们的工作基本完成的差不多了,现在我们的立方还不是真正意义上的“漂浮”,我们需要场景里的对象运动起来,所以我们要编写一个loop函数来使得渲染器循环渲染我们的每一帧,我们要是用一个requestAnimationFrame函数来调用渲染器的循环渲染,相当于递归,代码如下:

function loop(){
    earth.moveWaves();
    sky.mesh.rotation.z += 0.0008;

    //渲染
    renderer.render(scene,camera);

    //调用循环渲染函数
    requestAnimationFrame(loop);
}

现在我们的所有的代码已经完成了,具体的效果点击链接可以查看>漂浮立方

这是我在CSDN里的第一篇微博文章,不知道有什么地方写的不好,有很多细节可能都没有写清楚,不过难懂的地方都加了注释,也可以留言我,其实写这篇微博体现最多的就是我们在编写three的效果时的一些实现思路和结构思路,个人认为这是非常重要的事情,这能让我在编写实现时不会发生思维混乱,以至于写着写着就不知道写到哪里,结构化的编程思路是我们需要学习的一种思维,这会让我在理解实现上受益不菲。

three.js是一个用于创建3D图形的JavaScript库。它提供了丰富的功能和工具,可以轻松地在Web浏览器中创建交互式的3D场景和动画效果。 渐变圆边立方体是指一个立方体,其边缘呈现出渐变的圆形效果。在three.js中,可以通过以下步骤来创建渐变圆边立方体: 1. 创建一个立方体的几何体(BoxGeometry)并设置其大小和位置。 2. 创建一个渐变材质(MeshBasicMaterial)并设置其颜色属性为渐变色。 3. 将几何体和材质结合起来创建一个网格(Mesh)对象。 4. 将网格对象添加到场景中。 5. 创建一个渲染器(WebGLRenderer)并将其连接到HTML文档中的一个元素上。 6. 在每一帧中更新场景和相机,并使用渲染器进行渲染。 下面是一个示例代码,展示了如何使用three.js创建一个渐变圆边立方体: ```javascript // 创建场景 var scene = new THREE.Scene(); // 创建相机 var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 5; // 创建渲染器 var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 创建立方体几何体 var geometry = new THREE.BoxGeometry(1, 1, 1); // 创建渐变材质 var material = new THREE.MeshBasicMaterial({ color: new THREE.Color(0xff0000), // 起始颜色 vertexColors: THREE.VertexColors // 使用顶点颜色 }); // 设置顶点颜色 geometry.faces.forEach(function(face) { var color = new THREE.Color(Math.random(), Math.random(), Math.random()); face.vertexColors.push(color, color, color); }); // 创建立方体网格 var cube = new THREE.Mesh(geometry, material); // 将立方体添加到场景中 scene.add(cube); // 渲染函数 function render() { requestAnimationFrame(render); // 旋转立方体 cube.rotation.x += 0.01; cube.rotation.y += 0.01; // 渲染场景和相机 renderer.render(scene, camera); } // 开始渲染 render(); ``` 这是一个基本的示例,你可以根据自己的需求进行修改和扩展。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值