<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>three.js &#8211; 萧邦的博客</title>
	<atom:link href="https://www.zlhlab.top/tag/three-js/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.zlhlab.top</link>
	<description>If not me who, If not now when</description>
	<lastBuildDate>Wed, 30 Jul 2025 07:30:44 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.6</generator>
	<item>
		<title>普拉多Prado 3D展示</title>
		<link>https://www.zlhlab.top/%e6%99%ae%e6%8b%89%e5%a4%9aprado-3d%e5%b1%95%e7%a4%ba/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Fri, 23 Feb 2018 14:05:07 +0000</pubDate>
				<category><![CDATA[H5]]></category>
		<category><![CDATA[案例]]></category>
		<category><![CDATA[3D]]></category>
		<category><![CDATA[three.js]]></category>
		<category><![CDATA[webgl]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=574</guid>

					<description><![CDATA[这是一个web 3D的项目，主要实现了汽车3D模型外观、内饰展示，实现开关车门、汽车开动动画。]]></description>
										<content:encoded><![CDATA[<h4>项目介绍</h4>
<p>这是一个web 3D的项目，主要实现了汽车3D模型外观、内饰展示，实现开关车门、汽车开动动画。</p>
<p>项目预览地址： <a href="http://wx.bjczxda.com/prado3D20180202/index.html" title="普拉多全景展示" target="_blank">普拉多全景展示</a></p>
<p>手机预览地址：</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/02/84a871a677929aa7c170b71f347c772e.png" alt=""></p>
<h4>项目过程</h4>
<p>研究three.js和webgl有一段时间了，踩过各种坑，也尝试多种方法解决问题，实现了基本功能。主要涉及功能：<br />
1、舞台场景搭建；<br />
2、添加光照（环境光、点光源、炫光）<br />
3、相机控制 (角度控制、位置)<br />
4、场景点击事件<br />
5、模型加载(fbx、obj以及obj转js)<br />
6、纹理贴图、法线贴图、凹凸贴图，以及环境贴图<br />
7、材质（玻璃材质、纹理材质）<br />
8、着色器材质（glsl）<br />
9、动画（fbx动画、轮胎动画、相机动画、tween.js）</p>
<h4>项目待优化</h4>
<p>1、项目整体设计感<br />
2、交互流畅度<br />
3、材质渲染，增加整体质感</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>three.js 着色器学习笔记</title>
		<link>https://www.zlhlab.top/three-js-%e7%9d%80%e8%89%b2%e5%99%a8%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Tue, 20 Feb 2018 12:14:39 +0000</pubDate>
				<category><![CDATA[技术]]></category>
		<category><![CDATA[three.js]]></category>
		<category><![CDATA[着色器Shader]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=527</guid>

					<description><![CDATA[着色器顾名思义就是给物体增加颜色的工具。我们也知道，创建物体时可以设置该物体的材质，材质决定了物体的外观。]]></description>
										<content:encoded><![CDATA[<p>着色器顾名思义就是给物体增加颜色的工具。我们也知道，创建物体时可以设置该物体的材质，材质决定了物体的外观。</p>
<p>其实使用着色器，就是给物体设置一种特殊的材质，这个材质是由着色器来决定显示效果。</p>
<p>下面以实际代码来展示不同材质的效果。</p>
<h4>基本材质</h4>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">function init () {
    // 创建渲染器
    const renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById('main')
    })
    const width = window.innerWidth
    const height = window.innerHeight
    renderer.setClearColor(0xffffff)            
    renderer.setSize(width, height)

    // 创建场景
    const scene = new THREE.Scene()

    // 原点
    const origin = new THREE.Vector3(0, 0, 0)

    // 创建照相机
    const camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000)
    camera.position.set(0, 10, 10)
    camera.lookAt(origin)
    scene.add(camera)

    // 创建光源
    const light = new THREE.DirectionalLight(0xffffff, 0.8)
    light.position.set(0, 10, 10)
    scene.add(light)

    // 创建基本材质的球体
    const baseSphere = new THREE.Mesh(new THREE.SphereGeometry(1, 20, 20),
        new THREE.MeshBasicMaterial({
            color: 0xff0000
        })
    )
    scene.add(baseSphere)

    renderer.render(scene, camera)
}

init()
</code></pre>
<p>代码很简单，渲染出了一个基本材质<code>MeshBasicMaterial</code>的球体。</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/02/3531509-48b1d518e1050237.png" alt=""></p>
<h4>Lambert材质</h4>
<p>同样增加一个球体，其他参数相同仅仅是材质不同。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">// 创建 Lambert 材质球体
const lambertSphere = new THREE.Mesh(new THREE.SphereGeometry(1, 20, 20),
                                     new THREE.MeshLambertMaterial({
    color: 0xff0000
})
                                    )
// 将该球体放置在基本材质球体的左边
lambertSphere.position.set(-3, 0, 0)
scene.add(lambertSphere)
</code></pre>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/02/3531509-4182a85d75f24ed8.png" alt=""></p>
<p>在基本材质的左边可以看到一个新的小球，这就是 Lambert 材质的小球。</p>
<h4>Phong材质</h4>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">// 创建 Phong材质 材质球体
const phongSphere = new THREE.Mesh(new THREE.SphereGeometry(1, 20, 20),
                                   new THREE.MeshPhongMaterial({
    color: 0xff0000
})
                                  )
phongSphere.position.set(3, 0, 0)
scene.add(phongSphere)
</code></pre>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/02/3531509-35a45747d6cd7d74.png" alt=""></p>
<p>除了上面三种外，还可以贴图。下面就开始进入正题，着色器，或者说着色器材质？</p>
<h4>着色器</h4>
<p>着色器分为顶点着色器与片元着色器，这里也不具体介绍，因为导师的书籍和博客都已经介绍得非常清楚了。</p>
<p>重点在这两句话：</p>
<ul>
<li>顶点着色器就是每个顶点调用一次的程序。在顶点着色器中，可以访问到顶点的三维位置、颜色、法向量等信息。可以通过修改这些值，或者将其传递到片元着色器中，实现特定的渲染效果。</li>
<li>片元着色器就是每个片元调用一次的程序。在片元着色器中，可以访问到片元在二维屏幕上的坐标、深度信息、颜色等信息。通过改变这些值，可以实现特定的渲染效果。</li>
</ul>
<p>OK，话不多说，再新建一个小球，这次先不设置材质，看看会怎么样。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">// 没有材质的球体
const shaderSphere = new THREE.Mesh(new THREE.SphereGeometry(1, 20, 20))
shaderSphere.position.set(0, 3, 0)
scene.add(shaderSphere)
</code></pre>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/02/3531509-2db8b331f46f8d37.png" alt=""></p>
<p>而且刷新会有一个随机的颜色，因为似乎默认使用了基本材质？</p>
<p>使用基本材质（BasicMaterial）的物体，渲染后物体的颜色始终为该材质的颜色，而不会由于光照产生明暗、阴影效果。如果没有指定材质的颜色，则颜色是随机的。</p>
<p>接下来就来添加材质。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">// 新建着色器材质
    var material = new THREE.ShaderMaterial({
        vertexShader: `
            uniform vec3 color;
            uniform vec3 light;

            varying vec3 vColor;
            varying vec3 vNormal;
            varying vec3 vLight;

            void main()
            {
                // pass to fs
                vColor = color;
                vNormal = normalize(normalMatrix * normal);

                vec4 viewLight = viewMatrix * vec4(light, 1.0);
                vLight = viewLight.xyz;

                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }`,
        fragmentShader: `
            varying vec3 vColor;
            varying vec3 vNormal;
            varying vec3 vLight;

            void main() {
                float diffuse = dot(normalize(vLight), vNormal);
                if (diffuse &gt; 0.8) {
                    diffuse = 1.0;
                }
                else if (diffuse &gt; 0.5) {
                    diffuse = 0.6;
                }
                else if (diffuse &gt; 0.2) {
                    diffuse = 0.4;
                }
                else {
                    diffuse = 0.2;
                }

                gl_FragColor = vec4(vColor * diffuse, 1.0);
            }`,
        uniforms: {
            color: { 
                type: 'v3', // 指定变量类型为三维向量
                value: new THREE.Color('#ff0000') // 要传递给着色器的颜色值
            },
            light: {       
                type: 'v3',
                value: light.position // 光源位置
            }
        }
    })
</code></pre>
<p>这样就新建了一个材质，并且该材质的显示效果由<code>vertexShader</code>和<code>fragmentShader</code>两个着色器决定。</p>
<p>将该材质用在我们没有材质的小球上。</p>
<pre class="prism-highlight line-numbers" data-start="1"><code class="language-null">shaderSphere.material = material
</code></pre>
<p>再看看浏览器，发现和之前完全不同了。</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/02/3531509-b70fcd846d303b0b.png" alt=""></p>
<p>可以看到上面的球体颜色有很明显的变化，上面颜色浅下面深，因为光是从顶上照射下来，所以有这种效果，如果改变光照方向，效果也不一样。</p>
<p>实现了需要的效果没有太大意义，更需要的是理解为什么会有这种效果。</p>
<h4>顶点着色器</h4>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">uniform vec3 color;
uniform vec3 light;

varying vec3 vColor;
varying vec3 vNormal;
varying vec3 vLight;

void main() {
    // pass to fs
    vColor = color;
    vNormal = normalize(normalMatrix * normal);

    vec4 viewLight = viewMatrix * vec4(light, 1.0);
    vLight = viewLight.xyz;

    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</code></pre>
<p>一开始看的时候也完全不明白写的是什么，以学习另一种语言的心理再来看就慢慢能够理解了。</p>
<p><code>uniform</code>和<code>varying</code>就是和 js 中的 var、let一样，用来声明变量的。所以这段代码一开始就声明了五个变量</p>
<ul>
<li>color</li>
<li>light</li>
<li>vColor</li>
<li>vNormal</li>
<li>vLight</li>
</ul>
<p>使用<code>uniform</code>声明的变量将会从我们的 js 代码中传递过来，所以<code>color</code>就是<code>#ff0000</code>，light就是光源位置。</p>
<p>然后是<code>main()</code>函数，表示会执行这里面的代码，第一行<code>vColor = color;</code>很简单就是一个赋值操作。<br />
接下来就复杂了。。。</p>
<pre class="prism-highlight line-numbers" data-start="1"><code class="language-null">vNormal = normalize(normalMatrix * normal);
</code></pre>
<p>虽然能知道是给<code>vNormal</code>变量赋值，但是<code>normalize</code>、<code>normalMatrix</code>和<code>normal</code>都是哪里来的？</p>
<p>回头看看之前说的重点，顶点着色器，也就是这段代码能够访问到顶点的三维位置、颜色、法向量等信息。<code>normalMatrix</code>和<code>normal</code>就是顶点信息，而<code>normalize</code>则是全局方法。</p>
<p>OK，现在知道变量是怎么来的，但是为啥要这么做呢？。。。。<br />
竟无语凝噎，还是看导师的博客吧。</p>
<ul>
<li>算法理解</li>
</ul>
<p>总之，就是得到了 <code>vNormal</code>、<code>vColor</code>和<code>vLight</code>这三个变量并传递给片元着色器。</p>
<h4>片元着色器</h4>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">varying vec3 vColor;
varying vec3 vNormal;
varying vec3 vLight;

void main() {
    float diffuse = dot(normalize(vLight), vNormal);
    if (diffuse &gt; 0.8) {
        diffuse = 1.0;
    }
    else if (diffuse &gt; 0.5) {
        diffuse = 0.6;
    }
    else if (diffuse &gt; 0.2) {
        diffuse = 0.4;
    }
    else {
        diffuse = 0.2;
    }

    gl_FragColor = vec4(vColor * diffuse, 1.0);
}
</code></pre>
<p>最为核心的代码就是<code>main()</code>函数中的第一句：</p>
<pre class="prism-highlight line-numbers" data-start="1"><code class="language-null">float diffuse = dot(normalize(vLight), vNormal);
</code></pre>
<p>调用<code>normalize</code>方法得到的结果，与<code>vNormal</code>作为参数再传入dot方法，最后得到的结果是片元的亮度值。</p>
<p>并且，将亮度值固定为<code>1.0</code>、<code>0.6</code>、<code>0.4</code>和<code>0.2</code>这四个值，所以，最终渲染出来的结果肯定只有四种颜色。</p>
<p>如果不将亮度值规定为四个值，而是直接使用，又是什么效果呢？</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/02/3531509-b70fcd846d303b0b.png" alt=""></p>
<p>结果和预想的一样，diffuse是一个0 ~ 1的值，并且是逐渐变化的。</p>
<h4>总结</h4>
<p>物体的外观是由材质决定的，three.js 中有提供现成的材质，也可以自己使用着色器来自定义材质。</p>
<p>着色器分为顶点着色器与片元着色器，这两种着色器其实本质上就是以另一种语言实现的函数方法。由于是另一种语言所以也是有自己的变量声明规则以及全局方法，同时 three.js 也能够传递变量给着色器。</p>
<p>重点在于着色器中能够直接取到关于物体的顶点信息与片元信息，正是借助这些信息才能够定制显示效果。</p>
<h4>参考</h4>
<ul>
<li><a href="http://zhangwenli.com/blog/2017/03/05/cartoon-shading-1/" title="卡通渲染（上）" target="_blank">卡通渲染（上）</a></li>
</ul>
<p>本文仅作webgl学习技术参考，点击<a href="http://ife.baidu.com/note/detail/id/928" title="阅读原文" target="_blank">阅读原文</a>。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>一汽丰田一键认证 关怀备至H5</title>
		<link>https://www.zlhlab.top/%e4%b8%80%e6%b1%bd%e4%b8%b0%e7%94%b0%e4%b8%80%e9%94%ae%e8%ae%a4%e8%af%81%e5%85%b3%e6%80%80%e5%a4%87%e8%87%b3%e6%9c%8b%e5%8f%8b%e5%9c%88%e5%b9%bf%e5%91%8a%e6%8a%95%e6%94%bev1-0/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Mon, 06 Nov 2017 09:56:55 +0000</pubDate>
				<category><![CDATA[H5]]></category>
		<category><![CDATA[3D]]></category>
		<category><![CDATA[three.js]]></category>
		<category><![CDATA[精灵图]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=460</guid>

					<description><![CDATA[一汽丰田一键认证 关怀备至]]></description>
										<content:encoded><![CDATA[<h4>项目简介：</h4>
<p>这是给一汽丰田做的用于朋友圈投放的H5，主题是&#8221;一键认证  关怀备至&#8221;。整个H5动效包含车辆出场动效、3D俯瞰、3D旋转动效、奖品展示跑马灯效果、车辆360度展示（精灵帧动画）、二维码光效动画。整体设计偏科技风。</p>
<h4>核心技术点：</h4>
<p>整个H5制作下来，有以下几个核心技术点：</p>
<ol>
<li>遵循腾讯广告投放的制作规范，控制整体文件包2M以内；</li>
<li>使用Animate.css实现基本的过场动画；</li>
<li>采用three.js进行obj模型和刻度图片加载，并进行纹理贴图，然后控制展示俯瞰图，以及过场动画；</li>
<li>采用zepto.js中的swipe方法，控制模型左右转动；</li>
<li>采用PS制作精灵图，实现普拉多线框车型360度展示；</li>
<li>制作奖品展示跑马灯效果，采用setInterval进行精灵图切换；</li>
<li>制作二维码覆盖层动效，采用<code>pointer-events:none;</code>属性实现图片覆盖二维码情况下，还能够长按识别二维码。</li>
</ol>
<h4>待优化的地方：</h4>
<p>整个H5程序端制作花了2-3天制作时间，通过客户验收并上线。后期腾讯方反馈加载时间偏长，用户绑定偏少，广告投放单用户成本偏高。</p>
<p><strong>程序方面以下几点思考：</strong></p>
<ol>
<li>整个H5制作包1.9M，其中素材1M，three.js相关库文件600K左右。整体素材文件偏大，由于需要3D过渡场景和3D操作，3D库文件是必须的。</li>
<li>
<p>由于等待时间和点击事件太多，用户触达留资页面花费时间太多，会造成用户过程中用户流失；</p>
</li>
</ol>
<p><strong>解决方案：</strong></p>
<ol>
<li>资源素材再深度压缩；</li>
<li>增加Loading页面，减少用户白屏等待时间；</li>
<li>减少点击交互，多使用滑屏或者一屏滚动页面。</li>
</ol>
<h4>设计和制作效果预览：</h4>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/11/yijianrenzheng-1.jpg" alt=""></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Threejs学习笔记(一) 基础篇</title>
		<link>https://www.zlhlab.top/threejs%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b8%80-%e5%9f%ba%e7%a1%80%e7%af%87/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Sat, 21 Oct 2017 14:12:43 +0000</pubDate>
				<category><![CDATA[技术]]></category>
		<category><![CDATA[推荐]]></category>
		<category><![CDATA[three.js]]></category>
		<category><![CDATA[webgl]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=383</guid>

					<description><![CDATA[一个完整的3D环境包含以下元素:场景(Scene)、相机（Camera）、物体对象（Mesh）、光源（Light）、渲染器（Renderer）、控制器(Control)]]></description>
										<content:encoded><![CDATA[<h3><strong>基本概念</strong></h3>
<hr>
<p>一个完整的3D环境包含以下元素:</p>
<blockquote><p>
  1.场景(<strong>Scene</strong>)：是物体、光源等元素的容器，<br />
  2.相机（<strong>Camera</strong>）：控制视角的位置、范围以及视觉焦点的位置,一个3D环境中只能存在一个相机<br />
  3.物体对象（<strong>Mesh</strong>）：包括二维物体（点、线、面）、三维物体、粒子<br />
  4.光源（Light）：包括全局光、平行光、点光源<br />
  5.渲染器（<strong>Renderer</strong>）:指定渲染方式，如webGL\canvas2D\Css2D\Css3D等。<br />
  6.控制器(<strong>Control</strong>): 相机控件，可通过键盘、鼠标控制相机的移动
</p></blockquote>
<h3><strong>场景(Scene)</strong></h3>
<hr>
<p>物体、光源、控制器的添加必须使用<code>secen.add(object)</code>添加到场景中才能渲染出来。<br />
一个3D项目中可同时存在多个scene，通过切换render的scene来切换显示场景</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">var scene = new THREE.Scene();
var mesh=scene.getObjectByName("sky");//获取场景中name=sky的物体；
</code></pre>
<h3><strong>相机（Camera）</strong></h3>
<hr>
<p>相机根据投影方式分两种：正交投影相机和透视投影相机</p>
<blockquote><p>
  正交投影相机:THREE.OrthographicCamera(left, right, top, bottom, near, far),大小不因远近而变化<br />
  透视投影相机:THREE.PerspectiveCamera(fov, aspect, near, far)，遵循近大远小的空间规则
</p></blockquote>
<p>一般情况下，我们使用的是透视投影相机，其参数为：</p>
<blockquote><p>
  <strong>fov</strong>: 垂直方向夹角<br />
  <strong>aspect</strong>:可视区域长宽比 width/height<br />
  <strong>near</strong>:渲染区域离摄像机最近的距离<br />
  <strong>far</strong>:渲染区域离摄像机最远的距离，3仅在距离摄像机near和far间的区域会被渲染到 canvas中
</p></blockquote>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/10/3120010351.png" alt=""></p>
<p>相机有两个重要的参数：</p>
<blockquote><p>
  <strong>camera.position</strong>：控制相机在整个3D环境中的位置（取值为3维坐标对象-THREE.Vector3(x,y,z)）<br />
  <strong>camera.lookAt</strong>：控制相机的焦点位置，决定相机的朝向（取值为3维坐标对象-THREE.Vector3(x,y,z)）
</p></blockquote>
<p><strong>主要应用</strong></p>
<hr>
<p>1.设置相机焦点位置为原点坐标或某物体的位置坐标：<code>camera.lookAt(new THREE.Vector3(0,0,0))</code>，循环改变<code>camera.position</code>的位置，可以实现围绕物体旋转 360度观看物体的动画。</p>
<p>2.同时循环设置<code>camera.lookAt</code>和<code>camera.position</code>,可以实现以第一人称视角在空间自由移动的动画</p>
<h3><strong>物体（Mesh）</strong></h3>
<hr>
<p>一个完整的物体对象<strong>mesh</strong>包括形状<strong>Geometry</strong>和材质<strong>Material</strong></p>
<ul>
<li><strong>Mesh</strong>：三维物体，包括<code>Geometry</code>、<code>Material</code>，设置其name属性可以通过<code>scene.getObjectByName(name)</code>获取该物体对象;</li>
<li><strong>Geometry</strong>：包括平面<code>Plane</code>、圆形<code>Circle</code>、立方体<code>Cube</code>、球体<code>Sphere</code>、圆柱<code>Cylinder</code>、多面体<code>Polyhedron</code>等，拥有以下属性：</li>
<li><strong>Material</strong>：包括基础材质<code>MeshBasicMaterial</code>，<code>深度材质MeshDepthMaterial</code>、法向材质<code>MeshNormalMaterial</code>、<code>面材质MeshFacelMaterial</code>、朗柏材质<code>MeshLambertMaterial</code>、phone材质<code>MeshPhongMaterial</code>、着色器材质<code>ShaderMaterial</code></li>
</ul>
<p>以下代码以创建name为sky一个立方体为例，使用6张图片作为材质贴到立方体内部</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">var path = "resource/sky/";
var format = '.jpg';
var urls = [
        path + 'px' + format, path + 'nx' + format,
        path + 'py' + format, path + 'ny' + format,
        path + 'pz' + format, path + 'nz' + format
    ];
var materials = []; 
for (var i = 0; i &lt; urls.length; ++i) {
    var loader = new THREE.TextureLoader();
    loader.setCrossOrigin( this.crossOrigin );
    var texture = loader.load( urls[i], function(){}, undefined, function(){} );
    materials.push(new THREE.MeshBasicMaterial({
        map: texture, 
        overdraw: true,
        side: THREE.BackSide,
        //transparent: true,
        //needsUpdate:true
    })
    ); 
} 
var cube = new THREE.Mesh(new THREE.CubeGeometry(9000,9000,9000), new THREE.MeshFaceMaterial(materials)); 
cube.name="sky";
scene.add(cube);
</code></pre>
<p>记住以下几点：</p>
<ol>
<li>物体<code>mesh</code>的大小是由构成三维物体形状的顶点坐标<code>mesh.geometry.vertices</code>和缩放级别<code>mesh.scale(vector3)</code>决定的,初始化创建物体时由传入的参数确定了形状顶点坐标<code>mesh.geometry.vertices</code>，后面需要修改物体大小使用mesh.scale进行缩放</li>
<li>物体的透明度是材质的透明度属性<code>mesh.material.opacity</code>决定的，若需要设置透明度，需将材质的是否支持半透明属性<code>mesh.material.transparent</code>设置为true</li>
<li>在页面运行期间需要改变物体的材质或属性需要同步设置<code>mesh.material.needsUpdate=true</code></li>
<li>若物体使用了<code>THREE.MultiMaterial</code>材质（如上面的例子如果多张图作为贴图材质），则会将所有材质放到<code>mesh.meterials</code>数组中，修改材质需要对每一个材质<code>mesh.materials.material</code>进行单独修改</li>
<li>修改<code>mesh.rotation</code>、<code>mesh.position</code>、<code>mesh.visible</code>可设置物体旋转角度、位置、可见性。注意将物体的visible从false改成true,可能会造成画面卡顿</li>
</ol>
<h3><strong>光源（Light）</strong></h3>
<hr>
<blockquote><p>
  <strong>全局光</strong>：THREE.AmbientLight，影响整个scene的光源，一般是为了弱化阴影或调整整体色调，可设置光照颜色，以颜色的明度确定光源亮度<br />
  <strong>平行光</strong>：THREE.DirectionalLight，模拟类似太阳的光源，所有被照射的区域亮度是一致的，可设置光照颜色、光照方向（通过向量确定方向），以颜色的明度确定光源亮度<br />
  <strong>点光源</strong>：THREE.PointLight：单点发光，照射所有方向，可设置光照强度，光照半径和光颜色
</p></blockquote>
<p>以下分别在 scene中添加了全局光，1个平行光及5个点光源，项目中平行光作为主要光源、点光源主要用于暗部补光。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">var ambient = new THREE.AmbientLight( 0xcccccc );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xcccccc );
directionalLight.position.set( -2, 9, 1).normalize();//设置平行光方向
scene.add( directionalLight );
var pointlight = new THREE.PointLight(0xffffff, 1, 3000); 
pointlight.position.set(0, 0, 2000);//设置点光源位置
scene.add( pointlight );
var pointlight2 = new THREE.PointLight(0xffffff, 1, 2000);
pointlight2.position.set(-1000, 1000, 1000);
scene.add( pointlight2 );
var pointlight_back = new THREE.PointLight(0xffffff, 1, 2000); 
pointlight_back.position.set(0, 0, -2000);
scene.add( pointlight_back );
var pointlight_left = new THREE.PointLight(0xffffff, 1, 2000); 
pointlight_left.position.set( -2000, 0,0);
scene.add( pointlight_left );
var pointlight_right = new THREE.PointLight(0xffffff, 1, 2000); 
pointlight_right.position.set(0,  -2000, 0);
scene.add( pointlight_right );
</code></pre>
<h3><strong>渲染器(Renderer)</strong></h3>
<hr>
<p>一般情况下我们使用的是WebGL渲染器。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">var renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );//设置canvas的像素比为当前设备的屏幕像素比，避免高分屏下模糊
renderer.setSize( _container.offsetWidth, _container.offsetHeight );//设置渲染器大小,即canvas画布的大小
container.appendChild( renderer.domElement );//在页面中添加canvas
</code></pre>
<h3><strong>控制器（Controls）</strong></h3>
<hr>
<blockquote><p>
  <strong>FlyControls</strong>:飞行控制，用键盘和鼠标控制相机的移动和转动<br />
  <strong>OrbitControls</strong>::轨道控制器，模拟轨道中的卫星，绕某个对象旋转平移，用键盘和鼠标控制相机位置<br />
  <strong>PointerLockControls</strong>:指针锁定，鼠标离开画布依然能被捕捉到鼠标交互，主要用于游戏<br />
  <strong>TrackballControls</strong>：轨迹球控制器，通过键盘和鼠标控制前后左右平移和缩放场景<br />
  <strong>TransformControls</strong>:变换物体控制器，可以通过鼠标对物体的进行拖放等操作
</p></blockquote>
<p>示例：</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset="UTF-8"&gt;
        &lt;title&gt;&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
    &lt;div id="space"&gt;&lt;/div&gt;  
    &lt;script   src="https://code.jquery.com/jquery-1.12.4.min.js"   integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="   crossorigin="anonymous"&gt;&lt;/script&gt;
    &lt;script src="../js/lib/threejs/three.js"&gt;&lt;/script&gt;

    &lt;script src="../js/lib/threejs/OrbitControls.js"&gt;&lt;/script&gt;
    &lt;script&gt;


            var container, stats;

            var camera, scene, renderer;

            var mouseX = 0, mouseY = 0;

            var windowHalfX = window.innerWidth / 2;
            var windowHalfY = window.innerHeight / 2;


            init();
            animate();
            var mesh;

            function init() {

                container = document.getElementById("space")
                camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 5000 );
                camera.position.set(0, 0, 1500);

                scene = new THREE.Scene();

                var ambient = new THREE.AmbientLight( 0xffffff );
                scene.add( ambient );


                var directionalLight = new THREE.DirectionalLight( 0xffffff );
                directionalLight.position.set( -5, 5, 5).normalize();
                scene.add( directionalLight );

                var pointlight = new THREE.PointLight(0x63d5ff, 1, 200); 
                pointlight.position.set(0, 0, 200);
                scene.add( pointlight );                
                var pointlight2 = new THREE.PointLight(0xffffff, 1, 200); 
                pointlight2.position.set(-200, 200, 200);
                scene.add( pointlight2 );
                var pointlight3 = new THREE.PointLight(0xffffff, 1.5, 200); 
                pointlight3.position.set(-200, 200, 0);
                scene.add( pointlight3 );

                var controls = new THREE.OrbitControls(camera,container);
            //controls.maxPolarAngle=1.5;
            //controls.minPolarAngle=1;
            controls.enableDamping=true;
            controls.enableKeys=false;
            controls.enablePan=false;
            controls.dampingFactor = 0.1;
            controls.rotateSpeed=0.1;
    //      controls.enabled = false;
            //controls.minDistance=1000;
            //controls.maxDistance=3000;



                var path = "../resource/sky/";
                var format = '.jpg';
                var urls = [
                        path + 'px' + format, path + 'nx' + format,
                        path + 'py' + format, path + 'ny' + format,
                        path + 'pz' + format, path + 'nz' + format
                    ];
                var skyMaterials = []; 
                for (var i = 0; i &lt; urls.length; ++i) {
                    var loader = new THREE.TextureLoader();
                    loader.setCrossOrigin( this.crossOrigin );
                    var texture = loader.load( urls[i], function(){}, undefined, function(){} );

                    skyMaterials.push(new THREE.MeshBasicMaterial({
                        //map: THREE.ImageUtils.loadTexture(urls[i], {},function() { }), 
                        map: texture, 
                        overdraw: true,
                        side: THREE.BackSide,
                        //transparent: true,
                        //needsUpdate:true,
                        premultipliedAlpha: true
                        //depthWrite:true,

        //              wireframe:false,
                    })
                    ); 

                } 

                var cube = new THREE.Mesh(new THREE.CubeGeometry(500, 500,500), new THREE.MeshFaceMaterial(skyMaterials)); 
                cube.name="sky";
                scene.add(cube);
                renderer = new THREE.WebGLRenderer();
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                container.appendChild( renderer.domElement );

                document.addEventListener( 'mousemove', onDocumentMouseMove, false );
                window.addEventListener( 'resize', onWindowResize, false );

            }

            function onWindowResize() {

                windowHalfX = window.innerWidth / 2;
                windowHalfY = window.innerHeight / 2;

                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize( window.innerWidth, window.innerHeight );

            }

            function onDocumentMouseMove( event ) {

                mouseX = ( event.clientX - windowHalfX ) / 2;
                mouseY = ( event.clientY - windowHalfY ) / 2;

            }

            //

            function animate() {

                requestAnimationFrame( animate );
                render();

            }

            function render() {

//              camera.position.x += ( mouseX - camera.position.x ) ;
//              camera.position.y += ( mouseY - camera.position.y ) ;

                camera.lookAt( scene.position );

                renderer.render( scene, camera );

            }

    &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>手机阅读请扫描下方二维码：</p>
<p><a href="https://www.zlhlab.top/wp-content/uploads/2017/10/%E4%B8%8B%E8%BD%BD.png" target="_blank"><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/10/%E4%B8%8B%E8%BD%BD.png" alt=""></a></p>
<p>本文仅供技术分享。原文链接地址： <a href="http://feg.netease.com/archives/266.html" title="http://feg.netease.com/archives/266.html" target="_blank">http://feg.netease.com/archives/266.html</a></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
