最后想给穿越机模拟器这个项目中的地图加上大学天气,先用个demo试验下,首先想到的就是用three.js的points来实现

第一步

  • 先用points显示个球体,把基本结构搭出来

主要代码

  • 顶点着色器中简单用下面这种方式实现简单的近大远小的透视效果

vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 400.0 / -mvPosition.z );
let boxGeometry = new THREE.SphereGeometry(100, 20, 20); 
const mergedGeometry = BufferGeometryUtils.mergeVertices(boxGeometry);
const positionAttribute = mergedGeometry.getAttribute('position');

const colors: number[] = [];
const sizes: number[] = [];

const color = new THREE.Color();

for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
    color.setRGB(1, 1, 0);
    color.toArray( colors, i * 3 );

    sizes[ i ] = PARTICLE_SIZE * 0.5;

}

const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', positionAttribute );
geometry.setAttribute( 'customColor', new THREE.Float32BufferAttribute( colors, 3 ) );
geometry.setAttribute( 'size', new THREE.Float32BufferAttribute( sizes, 1 ) );


const material = new THREE.ShaderMaterial( {

    uniforms: {
        color: { value: new THREE.Color( 0xffffff ) },
        alphaTest: { value: 0.9 }
    },
    vertexShader: `
        attribute float size;
        attribute vec3 customColor;

        varying vec3 vColor;

        void main() {
            vColor = customColor;
            vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
            gl_PointSize = size * ( 400.0 / -mvPosition.z );
            gl_Position = projectionMatrix * mvPosition;

        }
    `,
    fragmentShader: `
        uniform vec3 color;
        uniform float alphaTest;
        varying vec3 vColor;
        void main() {
            gl_FragColor = vec4( color * vColor, 1.0 );
            gl_FragColor = gl_FragColor ;
            if ( gl_FragColor.a < alphaTest ) discard;
        }
    `

} );

第二步

  • 将雪花贴图换上去

  • 主要就是修改材质那部分,增加一个变量pointTexture

const material = new THREE.ShaderMaterial( {

    uniforms: {
        color: { value: new THREE.Color( 0xffffff ) },
        pointTexture: { value: new THREE.TextureLoader().load( 'textures/snow.png' ) },
        alphaTest: { value: 0.9 }
    },
    vertexShader: `
        attribute float size;
        attribute vec3 customColor;
        varying vec3 vColor;
        void main() {
            vColor = customColor;
            vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
            gl_PointSize = size * ( 400.0 / -mvPosition.z );
            gl_Position = projectionMatrix * mvPosition;
        }
    `,
    fragmentShader: `
        uniform vec3 color;
        uniform float alphaTest;
        uniform sampler2D pointTexture;
        varying vec3 vColor;
        void main() {
            gl_FragColor = vec4( color * vColor, 1.0 );
            gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
            if ( gl_FragColor.a < alphaTest ) discard;
        }
    `
} );

第三步

  • 引入噪声模拟雪花生成规律

    • 传统随机数生成器产生的噪声过于规律,无法模拟自然界的复杂变化。例如下面想实现的风里的效果就需要用到分形噪声

    • 这个实现过程其实没什么太多可记录的,shader层面还是用的上面示例中的,主要是雪花位置更新啊的一些操作

  • 效果如下,这里把雪花放大效果更明显