<?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>webgl &#8211; 萧邦的博客</title>
	<atom:link href="https://www.zlhlab.top/tag/webgl/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>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>
