实践[threejs] 实现一个地球+飞线

这个是突发奇想的一个成品,目的是保持自己对threejs的熟练程度,现在公司不使用threejs进行开发了。

上述效果总共分为3大块,分别是 地球,飞线,目标点

创建地球

首先我们在创建地球时准备好地球的贴图

然后我们创建一个几何球体

ts 复制代码
const geometry = new THREE.SphereGeometry(6, 100, 100);

const material = new THREE.MeshBasicMaterial({color:"#ffffff"})

const mesh = new THREE.Mesh(geometry, material);

如何将球体和贴图绑定在一起呢?

我们使用的是SphereGeometry着色器纹理将图像与几何体进行渲染

我们首先确定着色器需要的变量

我们这里只需要传入贴图即可,代码如下

ts 复制代码
const material = new THREE.ShaderMaterial({
    uniforms: {
        u_texture: {
            value: new THREE.TextureLoader().load(
                "/img/8k_earth_daymap.jpg"          // 图片路径
            ),
        },
    },
    fragmentShader: fs,
    vertexShader: vs,
});

片元着色器

首选我们通过sampler2D获取到传入的贴图,然后获取贴图的颜色,并进行归一化获取RGB颜色的点积。并对x进行判断,不同的区间使用不同的色值。

c 复制代码
// 纹理
uniform sampler2D u_texture;
varying vec2 v_uv;

float snoise(vec3 v);
void main() {
    vec3 color = texture2D(u_texture,v_uv).xyz;
    color = normalize(color);
    if(color.x<=0.5) {
        color = vec3(0.6f, 0.22f, 0.71f);
    } else {
        color = vec3(0.93f, 0.72f, 0.98f);
    };

    gl_FragColor = vec4(color, 1.0);
}

顶点着色器

顶点着色器获取每个色值的rgb,并将将其叠加在当前坐标的法向*0.2倍率,实现凹凸效果

c 复制代码
uniform sampler2D u_texture;
varying vec3 v_position;
varying vec3 v_normal;
varying vec2 v_uv;
void main() {
    v_position = position;
    v_normal = normal;
    v_uv = uv;
    
    vec3 color = texture2D(u_texture, uv).xyz;

    vec3 new_position = position + (normal * color) * 0.2;
    
    vec4 modelViewPosition = modelViewMatrix * vec4(new_position, 1.0);
    vec4 projectPosition = projectionMatrix * modelViewPosition;
    gl_Position = projectPosition;
}

到此地球就创建完毕了

创建飞线

在threejs中线条是无法实现分段效果的,也许是我还没接触到可以分段的方法,我们这里使用管道几何体TubeGeometry,并将几何体分为20段,并利用向量实现飞线抬升的效果,利用样条曲线实现弧度,来实现飞线效果。

c 复制代码
getCurve(p1: THREE.Vector3, p2: THREE.Vector3) {
    const v1 = new THREE.Vector3(p1.x, p1.y, p1.z);
    const v2 = new THREE.Vector3(p2.x, p2.y, p2.z);
    const points: THREE.Vector3[] = [];
    Array.from({length: 20}).forEach((_,i)=>{
        const p = new THREE.Vector3().lerpVectors(v1, v2, i / 20);
        p.multiplyScalar(1 + Math.abs(0.3 * Math.sin((Math.PI * i) / 20)));
        points.push(p);
    })
    const path = new THREE.CatmullRomCurve3(points);
    
    const geometry = new THREE.TubeGeometry(path, 20, 0.02, 50, false);
    const material = new THREE.ShaderMaterial({
        uniforms: {
            u_time: {
                value: 0,
            },
        },
        fragmentShader: pfs,
        vertexShader: pvs,
        side: THREE.DoubleSide,
    });
    return new THREE.Mesh(geometry, material);
}

片元着色器

利用sin函数和当前顶点的坐标+u_time实现飞线流动效果

c 复制代码
uniform float u_time;
varying vec3 v_normal;
varying vec2 v_uv;

void main() {
    float dash = sin((v_uv.x + u_time) * 50.);
    if(dash < 0.3)
        discard;
    gl_FragColor = vec4(vec3(1.0, 1.0, 1.0), 1.0);
}

到此,地球和飞线都已经创建完毕了,并实现了飞线流动效果。

相关推荐
烛阴13 小时前
3D字体TextGeometry
前端·webgl·three.js
全栈王校长18 小时前
Three.js 开发快速入门
three.js
全栈王校长18 小时前
Three.js 环境搭建与开发初识
three.js
DaMu1 天前
Dreamcore3D ARPG IDE “手搓”游戏引擎,轻量级实时3D创作工具,丝滑操作,即使小白也能轻松愉快的创作出属于你自己的游戏世界!
前端·架构·three.js
烛阴3 天前
从“无”到“有”:手动实现一个 3D 渲染循环全过程
前端·webgl·three.js
烛阴4 天前
拒绝配置地狱!5 分钟搭建 Three.js + Parcel 完美开发环境
前端·webgl·three.js
XiaoYu20027 天前
第9章 Three.js载入模型GLTF
前端·javascript·three.js
XiaoYu20028 天前
第8章 Three.js入门
前端·javascript·three.js
AlanHou17 天前
Three.js:Web 最重要的 3D 渲染引擎的技术综述
前端·webgl·three.js
一颗烂土豆20 天前
🚴‍♂️ Vue3 + Three.js 实战:如何写一个“不晕车”的沉浸式骑行播放器 🎥
vue.js·游戏·three.js