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

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

相关推荐
KallkaGo5 小时前
threejs复刻原神渲染(三)
前端·webgl·three.js
刘皇叔code2 天前
如何给Three.js中ExtrudeGeometry的不同面设置不同材质
webgl·three.js
vivo互联网技术2 天前
拥抱新一代 Web 3D 引擎,Three.js 项目快速升级 Galacean 指南
前端·three.js
你真的可爱呀6 天前
5.Three.js 学习(基础+实践)
学习·three.js
战场小包8 天前
弟弟想看恐龙,用文心快码3.5S快速打造恐龙乐园,让弟弟看个够
前端·three.js·文心快码
入秋8 天前
Three.js后期处理实战:镜头颜色、色差、点阵与颜色管道的深度解析
前端·three.js
Becauseofyou1379 天前
如果你刚入门Three.js,这几个开源项目值得你去学习
前端·three.js
Jedi Hongbin11 天前
Three.js shader内置矩阵注入
前端·javascript·three.js