记录---模仿 SU7 网页特效 实现3D旋转地球
<h1 data-id="heading-0">🧑💻 写在开头</h1><p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<blockquote>
<p>随着小米 SU7 的发布,不少网友发现了一个小米su7的展示网页,那是相当的酷炫:</p>
</blockquote>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202504/2149129-20250402165026699-2064320548.png" alt="" loading="lazy"></p>
<blockquote>
<p>当你体验一遍后,会看到各种炫酷的效果</p>
<p>包括隧道穿梭、波浪动画等,并且还有些细节也值得注意,如地面的反射效果。</p>
</blockquote>
<div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202504/2149129-20250402165051910-1111019481.png" alt="" loading="lazy"></p>
<p> </p>
<div>
<div>
<p><strong>原网页:gamemcu.com/su7/</strong></p>
<p>那么这个网页是用哪个技术实现的呢?答案是<code>three.js</code>,不论是从控制台,还是一些技术解析插件都能得知。</p>
<p>现在,前端开发不再局限于2D图形和静态页面。随着WebGL和JavaScript库如Three.js的发展,创建复杂且互动性高的3D内容变得更加简单。今天,我们将一起探索如何使用Three.js创建一个交互式的3D地球,并了解这个过程中涉及到的关键概念和技术。</p>
<h3 data-id="heading-0">要创建3D地球就要用下面到2D的地球图片</h3>
</div>
</div>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202504/2149129-20250402165124126-1878993155.png" alt="" loading="lazy"></p>
<p> </p>
<h2 data-id="heading-1">准备工作环境</h2>
<p>首先,我们需要确保我们的HTML文档已经正确设置了<code><canvas></code>标签,它将作为Three.js渲染3D内容的目标。同时,我们引入了Three.js库,这是实现3D效果的核心:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;"><script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
<canvas id="webglcanvas"></canvas>
</pre>
</div>
<p> </p>
<h2 data-id="heading-2">创建场景、相机和渲染器</h2>
<p>接下来,我们要初始化场景(Scene)、相机(Camera)以及渲染器(Renderer)。这些元素共同构成了3D空间的基础框架,允许我们在网页上展示3D物体。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">function init() {
canvas = document.getElementById('webglcanvas'); // 获取Canvas DOM元素
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 500; // 设置相机位置
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff); // 设置背景颜色为白色
renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染尺寸
}</pre>
</div>
<h2 data-id="heading-3">init函数:初始化 3D 场景</h2>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">function init() {
canvas = document.getElementById('webglcanvas'); // DOM
camera = new THREE.PerspectiveCamera(60,
window.innerWidth / window.innerHeight, 1, 2000); // 实例化 相机
// 相机离scene场景
camera.position.z = 500;
scene = new THREE.Scene(); // 实例化 场景
scene.background = new THREE.Color(0xffffff); // 背景色
group = new THREE.Group();// 组
scene.add(group);
// 纹理加载器
let loader = new THREE.TextureLoader(); // 简单的加载器
loader.load('land_ocean_ice_cloud_2048.jpg', function(texture) {
let geometry = new THREE.SphereGeometry(200, 20, 20); // 球体
let material = new THREE.MeshBasicMaterial({ // 材质
map: texture
});
let mesh = new THREE.Mesh(geometry, material); // 网格
group.add( mesh );
// 渲染器 目标是canvas
renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.render(scene, camera);
document.addEventListener('mousemove', onDocumentMouseMove, false);
})
}</pre>
</div>
<div>
<div>
<ul>
<li>首先,通过document.getElementById获取到页面中的元素并赋值给canvas变量,建立起 JavaScript 与 HTML 页面元素的连接,后续操作才有了具体的 “画板”。</li>
</ul>
<ul>
<li>接着创建PerspectiveCamera实例,参数60是视野角度,类似人眼视角范围,window.innerWidth / window.innerHeight是相机的宽高比,保证画面不变形,1和2000分别是近裁剪面和远裁剪面距离,划定可见范围。将camera.position.z = 500,把相机拉远到合适距离,能完整呈现 3D 地球全貌。</li>
</ul>
<ul>
<li>创建Scene实例,设置白色背景,为后续添加的 3D 对象提供干净整洁的展示环境。</li>
</ul>
<ul>
<li>实例化Group并添加到scene,为组织 3D 元素做准备。</li>
</ul>
<ul>
<li>关键的纹理加载环节,使用TextureLoader加载地球纹理图片,当图片加载成功回调函数内:</li>
</ul>
<ul>
<li>
<ul>
<li>用SphereGeometry构建球体几何形状,半径200,20和20分别是经度和纬度方向的分段数,分段越多球体越圆润。</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>结合加载的纹理创建MeshBasicMaterial材质,将纹理映射到球体表面。</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>最后通过Mesh把几何形状与材质组合成 3D 地球模型,并添加到group中。</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>同时创建WebGLRenderer实例,关联canvas,开启抗锯齿让画面更平滑,设置渲染尺寸与窗口一致,并添加鼠标移动事件监听器,为交互埋下伏笔。</li>
</ul>
</li>
</ul>
<h2 data-id="heading-4">onDocumentMouseMove函数:捕捉鼠标移动</h2>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}</pre>
</div>
<div>
<div>
<p>这个函数简洁明了,每次鼠标在页面移动时,它获取鼠标当前位置clientX和clientY,减去窗口中心坐标windowHalfX和windowHalfY,得到鼠标相对窗口中心的偏移量,实时更新mouseX和mouseY变量,后续用于控制相机移动实现交互。</p>
<h2 data-id="heading-5">animate和render函数:让 3D 地球动起来</h2>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:bash;gutter:true;">function animate() {
// 递归 屏幕的刷帧率60帧/s
requestAnimationFrame(animate)
render()
}
function render() {
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y += (mouseY - camera.position.y) * 0.05;
camera.lookAt(scene.position);
// camera.lookAt(scene.position)
group.rotation.y -= 0.005;
renderer.render(scene, camera);
}</pre>
</div>
<div>
<div>
<p>animate函数利用requestAnimationFrame以每秒 60 帧的频率递归调用自身,形成流畅的动画循环。每次循环调用render函数:</p>
<ul>
<li>在render函数里,根据鼠标偏移量,以一定系数0.05缓慢调整相机位置,让相机跟随鼠标移动,仿佛我们转动头部观察地球;</li>
</ul>
<ul>
<li>同时让group(包含地球模型)绕 y 轴以-0.005的速度缓慢旋转,模拟地球自转;</li>
</ul>
<ul>
<li>
<p>最后通过renderer.render将实时更新的 3D 场景绘制到canvas上,呈现出动态逼真的 3D 地球效果。</p>
<p><strong>最终效果如下</strong></p>
</li>
</ul>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202504/2149129-20250402165256912-119333147.png" alt="" loading="lazy"></p>
<p> 总之,WebGL和Three.js 的结合为前端开发注入了强大动力,赋予了我们创造神奇 3D 世界的能力,开启了无限可能的创意空间。无论是构建沉浸式的游戏场景、逼真的数字孪生模型,还是打造令人惊叹的可视化数据展示,它们都能胜任。希望大家都能深入探索。</p>
<div>
<h2>本文转载于:https://juejin.cn/post/7452197418593566770</h2>
</div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></p>
</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/18806275
頁:
[1]