three.js光效掃描

 所需的js文件,可以再該網站取得

https://www.wellyyss.cn/ysThree/main/app.html

相較於原文,簡化了一些shader,方便初學者理解

smoothstep函數的功能可以再shadertoy上進行測試

<script src="../../plugins/ys/ys.min.js"></script>
<script src="../../plugins/threeLibrary/three.min.js"></script>
<script src="../../plugins/threeLibrary/js/controls/OrbitControls.js"></script>
<script src="../../plugins/createJs/tween.min.js"></script>
<script src="../../plugins/threeLibrary/js/libs/stats.min.js"></script>
<script src="../../plugins/ysThree/ysThree-1.0.1.js"></script>

<script>
    const el = document.getElementById('box')

    const app = new YsThree(el,{
        gridHelper:true,//網格參考線
        axes:true,//座標輔助
        clearColor:'#000'//畫布顏色
    })
    const camera = app.camera
    const renderer = app.renderer
    const scene = app.scene
    const controls = app.initOrbitControls()
    const clock = new THREE.Clock()

    //add light
    const directionalLight = new THREE.DirectionalLight( '#fff' )
    directionalLight.position.set( 30, 30, 30 ).normalize()
    scene.add( directionalLight )
    const ambientLight = new THREE.AmbientLight('#fff',0.3) // obj 唯一 id
    scene.add(ambientLight)

    /*  **** **** ****   ****/


    app.initStatus(Stats)
    var vertexShader=[
        'varying vec3 vColor;',
        'varying vec3	vVertexNormal;',
        "varying vec2 vUv;",
        'varying float v_pz; ',
        'void main(){',
        '   v_pz = position.y; ',   //獲取頂點位置的y
        '	vVertexNormal	= normal;', //頂點法向量---內置  http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/renderers/webgl/WebGLProgram
        '   vColor = color;',  //頂點顏色
        '	gl_Position	= projectionMatrix * modelViewMatrix * vec4(position, 1.0);',//頂點位置
        '}'
    ].join('\n')
    var fragmentShader= [
        'uniform float	boxH;',        //立方體高度,uniform傳入
        'varying vec3	vVertexNormal;',  //頂點法向量,由頂點着色器傳入--插值
        'varying vec3 vColor;',       //頂點顏色,由頂點着色器傳入--插值
        "varying vec2 vUv;",         //紋理座標,頂點着色器傳入
        'varying float v_pz; ',      //y的值,頂點着色器傳入
        'float plot ( float pct){',//pct是box的高度,v_pz是y的值
        'return  smoothstep( pct-8.0, pct, v_pz) -',  //(smoothstep(edge1,edge2,x))smoothstep函數定義從0到1之間由edge1和edge2上下邊界,x爲輸入值,返回插值
        'smoothstep( pct, pct+0.02, v_pz);',   //不在0-1範圍內的數會被歸一化到0和1內,越界會被設爲0/1
        '}',
        'void main(){',
        'float f1 = plot(boxH);',    //以當前盒子的高度(光效),和y的值計算出顏色
        'vec4 b1 = mix(vec4(1.0,1.0,1.0,1.0),vec4(f1,f1,f1,1.0),0.8);',
        'gl_FragColor = mix(vec4(vColor,1.0),b1,f1);',//混合兩種顏色
        'gl_FragColor = vec4(gl_FragColor.r,gl_FragColor.g,gl_FragColor.b,0.9);',//重新設置片元顏色
        '}'
    ].join('\n')

    const  ShaderBar = {
        uniforms: {
            boxH: { value: -10.0 },
        },
        vertexShader: vertexShader,
        fragmentShader: fragmentShader
    }
    const material = new THREE.ShaderMaterial({
        uniforms: ShaderBar.uniforms,
        vertexShader: ShaderBar.vertexShader,
        fragmentShader: ShaderBar.fragmentShader,
         vertexColors: ShaderBar,  //暫時未理解該處作用
    });
    material.needsUpdate = true

    function addCube() {
        for (let i = 0 ;i<100;i++){
            const h =  Math.random()*6 + 5
            const  cubeGeo = new THREE.BoxBufferGeometry(1, h, 1);
            cubeGeo.setAttribute('color', new THREE.BufferAttribute(new Float32Array(24 * 3), 3)); // setAttribute 以前是.addAttribute
            // 相當於在 shader中創建了 attribute vec4 position
            const colors1 = cubeGeo.attributes.color;
            for (let i = 0; i < 24; i+=2) {
                let r = Math.random()*0.8,g=Math.random()*0.7,b=Math.random()*0.5;
                colors1.setXYZ(i, r, g, b);
                colors1.setXYZ(i+1,r, g, b);
            }
            const k = 2;
            colors1.setXYZ(k * 4 + 0, .0, 1.0, 1.0);
            colors1.setXYZ(k * 4 + 1, .0, 1.0, 1.0);
            colors1.setXYZ(k * 4 + 2, .0, 1.0, 1.0);
            colors1.setXYZ(k * 4 + 3, .0, 1.0, 1.0);
            const cube = new THREE.Mesh( cubeGeo,material)


            cube.position.set(Math.random()*100 - 50,h / 2,Math.random()*100 - 50)
            scene.add(cube)
        }
    }
    addCube()
    /*  **** **** ****   ****/
    function render() {
        controls.update(clock.getDelta())
        renderer.render( scene,camera)
        TWEEN.update()
        app.staus.update()
        ShaderBar.uniforms.boxH.value =  ShaderBar.uniforms.boxH.value + 0.1
        if( ShaderBar.uniforms.boxH.value > 30){
            ShaderBar.uniforms.boxH.value =  -10.0
        }
        requestAnimationFrame(render)
    }
    render()
</script>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章