Three.js-打造梦幻海岛(1)

最近指导新入职的前端同事进行threejs的学习,一开始找了threejs的文档,还有一些网上较好的教程和例子给他们看,一段时间后,发现学习进展不是很理想。可能是因为网上的教程比较零散,有些概念对于新手来说比较高深,不太容易掌握和运用。

前两天的中午,我决定从零开始构建一个自己喜欢的场景,这样学习起来也比较有趣,也足够有挑战,对于前端来说,用代码实现它,也足够有成就感。

这将是一个长期更新的文章,我尽量以浅显的思路和一些简单的方法来实现,同时也兼顾运用到threejs的各种基础类,循序渐进,一步步尝试、学习和完善。

我不愿意称之为教程,因为也是对自己学习threejs大半年的心得和记录,文中的错误、更好的实现方法,希望和大家一起探讨。在实现的过程中,能够对初次接触threejs的朋友有一些帮助,用代码写出自己的梦幻场景。

制作前准备

我喜欢的场景之一是海岛,之前玩过很长时间的海岛奇兵。
中午回到办公室,找到了一些可供参考的素材。


01-02.jpeg
01-01.jpeg
01-03.jpeg

我的梦幻海岛的框架应该是这样的:
大海、海岛、岩石、沙滩、树林、椰子树、螃蟹……想想就流口水~

开始制作基础场景

  • 引入必要的库

three.js
OrbitControls.js

  • 构建three场景
// html
<div id="map"></div>
// javascript
function init () {
      const HEIGHT = window.innerHeight
      const WIDTH = window.innerWidth
      const mainCanvas = document.getElementById('map')
      let scene
      let renderer
      let camera
      let controls

      // 创建Scene
      function createScene () {
        scene = new THREE.Scene()
        camera = new THREE.PerspectiveCamera(75, WIDTH / HEIGHT, 0.1, 10000)
        camera.position.set(5, 5, 5)
        camera.lookAt(0, 0, 0)
        renderer = new THREE.WebGLRenderer({
          alpha: true,
          antialias: true
        })
        renderer.setSize(WIDTH, HEIGHT)
        mainCanvas.appendChild(renderer.domElement)

        renderer.setAnimationLoop(() => {
          renderer.render(scene, camera)
        })
      }

      // 创建灯光
      function createLight () {
        const AmbientLight = new THREE.AmbientLight(0xcccccc)
        scene.add(AmbientLight)
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.08)
        directionalLight.position.set(10, 10, 0)
        scene.add(directionalLight)
      }

      // 创建控制器
      function createControl () {
        controls = new THREE.OrbitControls(camera, mainCanvas)
        controls.target.set(0, 0, 0)
        controls.update()
      }

      // 屏幕调整事件
      function onWindowResize () {
        camera.aspect = window.innerWidth / window.innerHeight
        camera.updateProjectionMatrix()
        renderer.setSize(window.innerWidth, window.innerHeight)
      }

      // 创建窗口调整事件
      function createEvent () {
        window.addEventListener('resize', onWindowResize, false)
      }
     
     // 创建海岛场景
      function createIsland () {
      }


      // 初始化
      createScene()
      createLight()
      createControl()
      createEvent()
      createIsland()
    }

init()

  • 创建海水

在function init () {} 中加入以下代码

// 海面
function sea (width, height, segments) {
  const sea = {
    width: width,
    height: height,
    segments: segments,
    mesh: null,
    init: function() {
      const geometry = new THREE.PlaneBufferGeometry(this.width, this.height, this.segments
, this.segments);
      const material = new THREE.MeshBasicMaterial({
        color: 0xcccccc,
        side: THREE.DoubleSide,
        wireframe: true
      });
      this.mesh = new THREE.Mesh(geometry, material); 
    }
   }
   sea.init();
   return sea;
}

修改function createIsland () {}

 function createIsland () {
    const mySea = new sea(90, 90, 100);
    mySea.mesh.rotation.x = Math.PI / 2;
    scene.add(mySea.mesh);
}
  • 创建小岛
// 岛
function island (width, height, segments) {
  const island = {
    width: width,
    height: height,
    segments: segments,
    mesh: null,
    init: function() {
      const geometry = new THREE.PlaneGeometry(this.width, this.height, this.segments, this.segments); 
      const material = new THREE.MeshPhongMaterial({
        color: 0xcc6699,
        side: THREE.DoubleSide,
        wireframe: true
      });
      this.mesh = new THREE.Mesh(geometry, material);
    }
  }
  island.init();
  return island;
}

继续修改function createIsland () {}

function createIsland () {
  const mySea = new sea(90, 90, 100);
  mySea.mesh.rotation.x = Math.PI / 2;
  scene.add(mySea.mesh);

  const myIsland = new island(8, 8, 8);
  myIsland.mesh.rotation.x = Math.PI / 2;
  scene.add(myIsland.mesh);
}

第一课完成,虽然有点丑,但我们有了海和海岛:

01-06.png

全部代码见这里 》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容

  • Threejs中文文档 郭隆邦技术博客 2018-09-21 20:40:17 关注 Three.js中文文档 今...
    情人波阅读 14,033评论 0 7
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,771评论 2 17
  • Threejs介绍 Demo查看 threejs 最早是 Ricardo Cabello(一个西班牙小伙) 在 G...
    风铭阅读 1,178评论 0 1
  • 偶遇雨的一个下雨天 雨告诉了我它的秘密 它恋上了大地 每到思念的最深处 就下一场相思的雨 大地感动雨如此痴情 每次...
    枫林听雨_4e72阅读 960评论 28 35
  • 这是一个微信群传过的一种流行的算术,把自然数所有的位上的值不断加到就剩一位, 但不能使用循环。 Given a n...
    SweetBecca阅读 272评论 0 1