zoukankan      html  css  js  c++  java
  • 利用贝塞尔曲线和着色器来写一个飞线

    为了加深自己对着色器语言的认识,于是就着手写了一个简版的"飞线"。

    做3D的或者做可视化的应该对这个词不陌生,一般会用在地理方面的3D需求上,废话不多说,先上今天的demo的gif图示:

    看完效果,让我们继续一步一步地看是怎么实现的

    一、写在着色器之前

    三部分:

    1⃣️地球

        // 添加地球
        var globeMesh;
        function addglobe() {
            var globeTextureLoader = new THREE.TextureLoader();
            globeTextureLoader.load('../texture/earth.jpeg', function (texture1) {
                console.log(texture1)
                var globeGgeometry = new THREE.SphereGeometry(60, 100, 100);
                var globeMaterial = new THREE.MeshStandardMaterial({map: texture1});
                globeMesh = new THREE.Mesh(globeGgeometry, globeMaterial);
                scene.add(globeMesh);
            });
        }

    地球的旋转,直接在每次渲染的时候改rotation就好了,这里不啰嗦。

    2⃣️路径线

        var flyline;
        function addline(){
            var curve = new THREE.CubicBezierCurve3(
                new THREE.Vector3( -70, 0, 0 ),
                new THREE.Vector3( -35, 100, 0 ),
                new THREE.Vector3( 35, 100, 0 ),
                new THREE.Vector3( 70, 0, 0 )
            );
            var points = curve.getPoints( 50 );
    
            var geometry = new THREE.BufferGeometry().setFromPoints( points );
            var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
            flyline = new THREE.Line( geometry, material );
    
            scene.add(flyline);
        }

    利用three.js提供的贝塞尔曲线类结合材质生成了上面你所看到的贝塞尔曲线。

    3⃣️夜空背景

        var scene;
        function initScene() {
            scene = new THREE.Scene();
            var bgTexture = new THREE.TextureLoader().load("../texture/starfiled.jpeg");
            scene.background = bgTexture;
        }

    不难看出是给场景添加了一个背景贴图。

    二、线条的材质替换成shader材质

    我们可以看到,目前线条的材质是带有特定颜色的 THREE.LineBasicMaterial 材质。现在我们要将其换成shader材质。

        //创建ShaderMaterial纹理的函数
        function createMaterial(vertexShader, fragmentShader) {
            var vertShader = document.getElementById(vertexShader).innerHTML; //获取顶点着色器的代码
            var fragShader = document.getElementById(fragmentShader).innerHTML; //获取片元着色器的代码
    
            //配置着色器里面的attribute变量的值
            var attributes = {};
            //配置着色器里面的uniform变量的值
            var uniforms = {
                time: {type: 'f', value: 1.0}
            };
    
            var meshMaterial = new THREE.ShaderMaterial({
                uniforms: uniforms,
                defaultAttributeValues : attributes,
                vertexShader: vertShader,
                fragmentShader: fragShader,
                transparent: true
            });
            return meshMaterial;
        }
        

    这段生成shader材质的代码其实很简单,注释都有,就不啰嗦了,因为这个简要的demo所用到的动画只需要一个参数,那么我们就只传一个参数吧(time)。

    顶点着色器代码:

    <!-- 顶点着色器 -->
    <script id="vertex-shader" type="x-shader/x-vertex">
    
        void main(){
            vec3 posChanged = position;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0);
        }
    
    </script>

    代码只做了一件事,将物体顶点进行了矩阵变换,转化为屏幕上的点(上一篇博客也有)。

    片元着色器代码:

    <script id="fragment-shader-7" type="x-shader/x-fragment">
        uniform float time;
    void main( void ) { float start = time; float end = start + 20.0; float opacity = 0.0;
    if(gl_FragCoord.x > start && gl_FragCoord.x < end){ opacity = 1.0; } gl_FragColor = vec4(1.0,1.0,1.0,opacity); } </script>

    因为片元着色器逐点绘制,所以对于gl_FragCoord这个内置变量,表示的就是屏幕上的点(一个window下,iframe下也是一个单独window);

    gl_FragCoord 坐标是以左下角为(0,0),右上角为(屏宽,屏高),拿上述iframe来说,右上角就是(966,772);其实更准确的说法请参照下面这段话:

    但今天不是来研究这些的,我们继续看着色器代码。

    因为视图是每一帧绘制一次,假如现在是第199帧(time+=1.0 了199次,此时是200.0)

    void main( void ) {
            float start = time;  //200
            float end = start + 20.0;  //220
    
            float opacity = 0.0;
    
            if(gl_FragCoord.x > start && gl_FragCoord.x < end){
                opacity = 1.0;
            }
            gl_FragColor = vec4(1.0,1.0,1.0,opacity);
    
        }

    那么,上述曲线显示的部分,左端点的x轴就是200像素点,右端点的x轴就是220像素点。针对着色器传过来的顶点(逐个遍历),顶点x不在该范围内的顶点的颜色透明度都是0,也就是看不到,

    到了下一帧(time值变化),这个可视区域的范围就又就变了,于是一帧一帧合起来就重现了我们刚开始看到的那张gif图:

  • 相关阅读:
    数组添加元素到特定位置
    jquery $().each,$.each的区别
    JSON字符串 与 JSON对象 互转
    js 获取 url 参数
    js 获取随机数 Math.random()
    js中的|| 与 &&
    js立即执行函数
    css 蒙层
    css 多行文本的溢出显示省略号(移动端)
    移动端利用-webkit-box水平垂直居中(旧弹性盒)
  • 原文地址:https://www.cnblogs.com/eco-just/p/11186440.html
Copyright © 2011-2022 走看看