(转)Three.JS学习 9:WEBVR 入门demo

摘要:
引用的文件描述是three.min.js:Treejs库StereoEffect。js:允许我们转换常见的三个js,将其分为两个显示场景并一起显示。这是VR体验的基本要求。设备方向控制。js:告诉三。js表示设备的方向和方向。e、 alpha){return;}}创建灯光varlight=newTHREE。PointLight;灯光位置。设置场景添加varlightScene=新三个。PointLight;lightScene.position。设置场景添加创建floor varfloorTexture=三。ImageUtils。loadTexture;floorTexture.wrapS=三。重复包装;floorTexture.wrapT=三。重复包装;floorTexture.repeat=newTHREE。矢量2;floorTexture各向异性=渲染器。getMax各向异性();//我们的地板需要纹理和材质,其中材质控制着我们的地板如何随光线变化//我们使用MeshPhoneMaterial使对象在灯光效果下看起来更舒适。varfloorMaterial=newTHREE。MeshPhongMaterial;定义几何体vargeometry=newTHREE。PlaneBufferGeometry;添加floor varfloor=newTHREE。场景中的网格;floor.rotation.x=-数学。PI/2;场景添加要将粒子放在一起,首先定义一些与粒子相关的公共变量,然后创建一个粒子对象来存储浮动粒子。稍后将详细解释这些变量。

原文地址:http://blog.csdn.net/xundh/article/details/54564657

本文参考文档主要来源: 
https://www.sitepoint.com/bringing-vr-to-web-google-cardboard-three-js/

本文内容是介绍基于Three.js创建一个可以使用谷歌眼镜演示的WEB虚拟现实网页。

准备工作

首先需要准备一些js 
下载项目: 
https://github.com/sitepoint-editors/VRWeatherParticles

使用自己熟悉的开发环境创建一个web项目,把上面下载项目里的/js 、 /textures放到项目里,新建一个index.html文件。 
这里写图片描述

下载的项目里有完整的源码,本文基本是对其程序说明做简单翻译。

引用的文件说明

  • three.min.js : Threejs库
  • StereoEffect.js:允许我们把普通的Three.js分成两个显示的场景合并到一起显示,这是VR体验的基本需求
  • DeviceOrientationControls.js:告诉Three.js设备的朝向、向哪移动。
  • OrbitControls.js:允许我们通过拖动、点击事件来控制场景(在DeviceOrientation事件无效的时候,比如电脑模拟时适用)
  • helvetiker_regular.typeface.js:将在Three.js显示文本用到的字体

下面是init()函数,其中有一些内容在前几章已有提及,这里不会完全详述。

        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.001, 700);
            camera.position.set(0, 15, 0);
            scene.add(camera);
            /*
            我们需要一个元素来画场景,这里定义一个renderer,并且给HTML元素webglviewer声明一个变量
            */
            renderer = new THREE.WebGLRenderer();
            element = renderer.domElement;
            container = document.getElementById('webglviewer');
            container.appendChild(element);
            //为了有VR双屏的视图,需要StereoEffect
            effect = new THREE.StereoEffect(renderer);

            //控制摄像机
            controls = new THREE.OrbitControls(camera, element);
            controls.target.set(
              camera.position.x + 0.15,
              camera.position.y,
              camera.position.z
            );
            controls.noPan = true;
            controls.noZoom = true;
            //加入设备事件,该事件返回的结果有三个属性值
            window.addEventListener('deviceorientation', setOrientationControls, true);
            //如果没有设备支持DeviceOrientation特性,还要给controls变量加上OrbitControls对象,并
            //且使用我们自己的DeviceOrientationControls对象替换它
            //接下来运行connect和update函数
            controls = new THREE.DeviceOrientationControls(camera, true);
            controls.connect();
            controls.update();
            //鼠标点击、全屏,这样在google cardboard里看起来效果更好
            element.addEventListener('click', fullscreen, false);
            //删除deviceorientation事件,因为已经定义了我们自己的DeviceOrientationControls对象
            window.removeEventListener('deviceorientation', setOrientationControls, true);


        }
        function setOrientationControls(e) {
            //通过alpha属性来确保监测的是我们需要的事件
            if (!e.alpha) {
                return;
            }
        }

创建灯光

var light = new THREE.PointLight(0x999999, 2, 100);
light.position.set(50, 50, 50);
scene.add(light);

var lightScene = new THREE.PointLight(0x999999, 2, 100);
lightScene.position.set(0, 5, 0);
scene.add(lightScene);

创建地板(加载材质)

var floorTexture = THREE.ImageUtils.loadTexture('textures/wood.jpg');
floorTexture.wrapS = THREE.RepeatWrapping;
floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat = new THREE.Vector2(50, 50);

floorTexture.anisotropy = renderer.getMaxAnisotropy();
//我们的地板需要texture和material,其中material控制我们的地板如何跟随灯光变化
//我们使用了MeshPhoneMaterial可以让对象跟随灯光效果看起来更舒适
var floorMaterial = new THREE.MeshPhongMaterial({
  color: 0xffffff,
  specular: 0xffffff,
  shininess: 20,
  shading: THREE.FlatShading,
  map: floorTexture
});

定义几何体

var geometry = new THREE.PlaneBufferGeometry(1000, 1000);

在场景里加入地板

var floor = new THREE.Mesh(geometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);

把粒子放到一起

先定义一些粒子相关的公用变量,并且创建了一个粒子对象,用来保存浮动的粒子,后面会详细讲解这些变量。

particles = new THREE.Object3D(),
totalParticles = 200,
maxParticleSize = 200,
particleRotationSpeed = 0,
particleRotationDeg = 0,
lastColorRange = [0, 0.3],
currentColorRange = [0, 0.3],

现在在一个比较高的水平上来整体看一下代码。我们把一个透明的png图”textures/particle.png”初始化为texture。上面定义了总粒子数量为totalParticles,如果想增加场景里的粒子数量,可以把这个值增大。

下面遍历粒子并把它们加入到了粒子对象里,我们需要把粒子对象升高以让它旋浮起来。

var particleTexture = THREE.ImageUtils.loadTexture('textures/particle.png'),
    spriteMaterial = new THREE.SpriteMaterial({
    map: particleTexture,
    color: 0xffffff
  });

for (var i = 0; i < totalParticles; i++) {
  // Code setting up all our particles!
}

particles.position.y = 70;
scene.add(particles);

接下来创建一个Three.js Sprite对象,并把spriteMaterial赋给它,然后把它缩放到64×64(与texture一样大)。我们希望粒子是围绕我们出现在随机的位置,所以把它设置有x和y值介于-0.5到0.5之间,z值在-0.75到0.25之间。关于为什么选取这些值,在一些实践之后,这些应该是最佳的实践值。

for (var i = 0; i < totalParticles; i++) {
  var sprite = new THREE.Sprite(spriteMaterial);

  sprite.scale.set(64, 64, 1.0);
  sprite.position.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.75);

把每个粒子的尺寸都限制0到maxParticleSize之间

sprite.position.setLength(maxParticleSize * Math.random());

让粒子看起来平滑的一个关键点是THREE.AdditiveBlending ,它是Three.js里的弯曲风格。这个会给texture赋给它后面一种texture的颜色,以让整个粒子系统看起来更平滑。

sprite.material.blending = THREE.AdditiveBlending;

  particles.add(sprite);
}

天气API

目前已经有了一个拥有地板、灯光的静态场景。现在添加一个OpenWeatherMap API获取各城市的天气以让demo显得更有趣。

OpenWeatherMap使用一个HTTP请求来获取多个城市天气。下面定义了cityIDs变量保存需要的各个城市,从网址: 
http://78.46.48.103/sample/city.list.json.gz
可以获取到城市列表。

function adjustToWeatherConditions() {
  var cityIDs = '';
  for (var i = 0; i < cities.length; i++) {
    cityIDs += cities[i][1];
    if (i != cities.length - 1) cityIDs += ',';
  }

我们的城市数组包括了名称和IDs,这样可以显示天气数据的时候也显示城市的名字。 
为了调用API,还需要一个API key,可以到网站http://openweathermap.org创建一个账号 
使用getURL()函数可以获取XMLHttpRequest请求。如果收到一个关于”crossorigin”错误,那需要改用JSONP。 
这是调用示例:

getURL('http://api.openweathermap.org/data/2.5/group?id=' + cityIDs + '&APPID=kj34723jkh23kj89dfkh2b28ey982hwm223iuyhe2c', function(info) {
  cityWeather = info.list;

当然天气服务并非本文重点,下面跳过一部分内容。

保存时间

clock = new THREE.Clock();

动起来

在init()函数里已经调用了animate。

我们还需要决定粒子要转动的方向,如果风力小于或等于180,那就顺时针转,否则就逆时针转。

function animate() {
  var elapsedSeconds = clock.getElapsedTime(),
      particleRotationDirection = particleRotationDeg <= 180 ? -1 : 1;

为了在Three.js动画的每一帧真实的旋转它们,我们需要计算动画已经运行了多少秒,乘上速度,这样计算出粒子y值。

particles.rotation.y = elapsedSeconds * particleRotationSpeed * particleRotationDirection;

同样我们还需要跟踪当前的和上次的颜色信息,这样我们知道在哪些帧里改变它们。这里新的光线值介于0.2到0.7之间。

if (lastColorRange[0] != currentColorRange[0] && lastColorRange[1] != currentColorRange[1]) {
  for (var i = 0; i < totalParticles; i++) {
    particles.children[i].material.color.setHSL(currentColorRange[0], currentColorRange[1], (Math.random() * (0.7 - 0.2) + 0.2));
  }

  lastColorRange = currentColorRange;
}

接下来循环动画:

requestAnimationFrame(animate);

最后让一切平滑连运动起来:

update(clock.getDelta())
render(clock.getDelta()) 
effect.render(scene, camera);
源码

其中去掉了天气部分

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Connecting up Google Cardboard to web APIs</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
      body {
        margin: 0px;
        overflow: hidden;
      }
      #webglviewer {
        bottom: 0;
        left: 0;
        position: absolute;
        right: 0;
        top: 0;
      }
    </style>
  </head>
  <body>
    <div id="webglviewer"></div>

    <script src="./js/three.min.js"></script>
    <script src="./js/StereoEffect.js"></script>
    <script src="./js/DeviceOrientationControls.js"></script>
    <script src="./js/OrbitControls.js"></script>
    <script src="./js/helvetiker_regular.typeface.js"></script>

    <script>
        var scene,
            camera,
            renderer,
            element,
            container,
            effect,
            controls,
            clock,

            // Particles
            particles = new THREE.Object3D(),
            totalParticles = 200,
            maxParticleSize = 200,
            particleRotationSpeed = 0,
            particleRotationDeg = 0,
            lastColorRange = [0, 0.3],
            currentColorRange = [0, 0.3],

            // City and weather API set up
            cities = [['Sydney', '2147714'], ['New York', '5128638'], ['Tokyo', '1850147'], ['London', '2643743'], ['Mexico City', '3530597'], ['Miami', '4164138'], ['San Francisco', '5391959'], ['Rome', '3169070']],
            cityWeather = {},
            cityTimes = [],
            currentCity = 0,
            currentCityText = new THREE.TextGeometry(),
            currentCityTextMesh = new THREE.Mesh();

        init();

        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.001, 700);
            camera.position.set(0, 15, 0);
            scene.add(camera);

            renderer = new THREE.WebGLRenderer();
            element = renderer.domElement;
            container = document.getElementById('webglviewer');
            container.appendChild(element);

            effect = new THREE.StereoEffect(renderer);

            // Our initial control fallback with mouse/touch events in case DeviceOrientation is not enabled
            controls = new THREE.OrbitControls(camera, element);
            controls.target.set(
              camera.position.x + 0.15,
              camera.position.y,
              camera.position.z
            );
            controls.noPan = true;
            controls.noZoom = true;

            // Our preferred controls via DeviceOrientation
            function setOrientationControls(e) {
                if (!e.alpha) {
                    return;
                }

                controls = new THREE.DeviceOrientationControls(camera, true);
                controls.connect();
                controls.update();

                element.addEventListener('click', fullscreen, false);

                window.removeEventListener('deviceorientation', setOrientationControls, true);
            }
            window.addEventListener('deviceorientation', setOrientationControls, true);

            // Lighting
            var light = new THREE.PointLight(0x999999, 2, 100);
            light.position.set(50, 50, 50);
            scene.add(light);

            var lightScene = new THREE.PointLight(0x999999, 2, 100);
            lightScene.position.set(0, 5, 0);
            scene.add(lightScene);

            var floorTexture = THREE.ImageUtils.loadTexture('textures/wood.jpg');
            floorTexture.wrapS = THREE.RepeatWrapping;
            floorTexture.wrapT = THREE.RepeatWrapping;
            floorTexture.repeat = new THREE.Vector2(50, 50);
            floorTexture.anisotropy = renderer.getMaxAnisotropy();

            var floorMaterial = new THREE.MeshPhongMaterial({
                color: 0xffffff,
                specular: 0xffffff,
                shininess: 20,
                shading: THREE.FlatShading,
                map: floorTexture
            });

            var geometry = new THREE.PlaneBufferGeometry(1000, 1000);

            var floor = new THREE.Mesh(geometry, floorMaterial);
            floor.rotation.x = -Math.PI / 2;
            scene.add(floor);

            var particleTexture = THREE.ImageUtils.loadTexture('textures/particle.png'),
                spriteMaterial = new THREE.SpriteMaterial({
                    map: particleTexture,
                    color: 0xffffff
                });

            for (var i = 0; i < totalParticles; i++) {
                var sprite = new THREE.Sprite(spriteMaterial);

                sprite.scale.set(64, 64, 1.0);
                sprite.position.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.75);
                sprite.position.setLength(maxParticleSize * Math.random());

                sprite.material.blending = THREE.AdditiveBlending;

                particles.add(sprite);
            }
            particles.position.y = 70;
            scene.add(particles);


            clock = new THREE.Clock();

            animate();
        }


        function animate() {
            var elapsedSeconds = clock.getElapsedTime(),
                particleRotationDirection = particleRotationDeg <= 180 ? -1 : 1;

            particles.rotation.y = elapsedSeconds * particleRotationSpeed * particleRotationDirection;

            // We check if the color range has changed, if so, we'll change the colours
            if (lastColorRange[0] != currentColorRange[0] && lastColorRange[1] != currentColorRange[1]) {

                for (

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Python脚本获取参数的方式Centos7.X安装impala(RPM方式)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

js Jquery字符UrlEncode 编码 C#(asp.net)解码 Server HttpUtility 区别 cookies存中文

一、Js asp.net 交互Url编码解码 C#(asp.net)编码:HttpUtility.UrlEncode(url) Jquery解码:decodeURIComponent(url); Jquery编码:encodeURIComponent(url); C#(asp.net)解码:HttpUtility.UrlDecode 二、asp.net(S...

The instance of entity type 'xxx' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked.

具体详细错误信息:The instance of entity type 'xxx' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities...

flutter json转字符串 字符串转json

一段json字符串 var jsonStr = '{"errorCode": "0", "message": "成功", "data": { "id": 25, "appLoginUuid": "9c64754d293b487aa16fa266bf6aa9cf", "userName":...

Linux中/usr与/var目录详解

Linux中/usr与/var目录详解 /usr文件系统  /usr 文件系统经常很大,因为所有程序安装在这里. /usr 里的所有文件一般来自Linux distribution;本地安装的程序和其他东西在/usr/local 下.这样可能在升级新版系统或新distribution时无须重新安装全部程序./usr/X11R6X Window系统的所有文件...

JS 正则处理 EAN_13%2C,CODE_128%2C,%2c 条形码 一维码格式

代码: var str = var str = EAN_13%2C69032 var sub = str.search(/%2C/) var s = str.substr(sub+3,str.length) console.log(s) //69032...

.net C#写钉钉上传图片素材接口解决返回系统繁忙问题

本片主要解决“type=file时是可行的,type=image时不知为何总是提示【系统繁忙】”的问题。 钉钉上传素材的API文档写的比较简单,尤其是http头那块完全没写,demo也没有.net的,杯具啊。 看了一位仁兄的帖子,原理写的很清楚,大家可以参考一下。 http://blog.csdn.net/xxdddail/article/details/...