实践[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);
}

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

相关推荐
郝学胜-神的一滴5 天前
[简化版 GAMES 101] 计算机图形学 12:可见性与 Z‑Buffer 深度缓存
unity·godot·图形渲染·three.js·opengl·unreal
VcB之殇6 天前
[Three.js] 实现两个3D模型之间的粒子化切换
前端·javascript·three.js
郝学胜-神的一滴9 天前
中级OpenGL教程 008:精准控制高光光斑大小与强度
c++·unity·godot·three.js·图形学·opengl·unreal
xier12345612 天前
three-instance-batch 开发笔记
javascript·three.js
一根数据线14 天前
从几何压缩到KTX2纹理压缩:轻装3D的Three.js场景优化进阶
3d模型轻量化·three.js·3d模型·ktx2·轻装3d·纹理压缩
一根数据线15 天前
一键解决ThreeJS3D场景卡顿问题!轻装3D的几何体实例化与合并
3d模型轻量化·three.js·3d模型·轻装3d·实例化渲染·几何体合并
一根数据线16 天前
ThreeJS模型加载卡顿怎么办,用轻装3D来做模型压缩和LOD分级
3d模型轻量化·three.js·lod·3d模型优化·draco压缩·轻装3d
来自上海的这位朋友16 天前
用 Three.js 做一个 Web 3D 非对称追猎 Demo:从场景、角色到手感调试
后端·游戏开发·three.js
来自上海的这位朋友16 天前
Spring Boot + MySQL 搭一个多人游戏后端:登录、房间、匹配、对局和成长系统
前端·后端·three.js
郝学胜-神的一滴16 天前
中级OpenGL教程 007:解决背面光照异常高光问题
c++·unity·游戏引擎·three.js·opengl·unreal