• webgl像机世界


    本来打算接下来的webgl相关都用原生来写的,但发现时间上并不允许我这么做(诸多原因)

    接下来的webgl相关博文,可能都是基于three来写了。

    用了three后发觉它简化了n多n多n多的步骤。不过并不是意味着就放弃学习原生了,有些东西依然需要原生,比如shaderMaterial,不懂着色器你玩毛= =

    再说了,没有原生的基础也并不能把框架/库 发挥的淋漓精致!

    这篇实现 ↓

    拖拽鼠标处理相机的旋转,wsad四个按键处理前后左右运动。

    这个世界中几个平台,每个平台都要处理与相机的碰撞,最大的主平台上有2个箭头的区域,如果检测到进入该区域,就会传送至上方小平台中,上方的小平台也可通过箭头区域再传送回主平台。

    主要就是上面这些东西扯到了摄像机的操作。

    在摄像机系统中,要知道摄像机的位置、观察方向、还有几个互相垂直的向量。

    摄像机的位置最简单不过了, camera.position.set(0,1,1) 完事。

    观察方向可以指向z轴的反方向,如果位置是(0,1,1),那么lookAt就是(0,1,0)。

    然后要确定那几个互相垂直的向量,那几个向量可以用来处理摄像机的运动。wsad就是前后左后4个方向的向量,那么上方和下方的向量可以通过叉乘得到了。

    接着要处理摄像机的转向,目的就是为了旋转那几个互相垂直的向量,相机需要朝着那些方向向量运动,但是这里要忽略y轴的方向,这里仅考虑xz方向即可(对于这个demo来说)。

    我这里使用欧拉角来处理旋转的,通过旋转俯仰角和偏航角,确定那几个方向向量。

    这就是lookAt单位向量

    this.v3_look = new Vec(sin(θ)*sin(φ),cos(θ),sin(θ)*cos(φ));

    加上相机位置得出最终的lookAt

    //...
    const v = this.v3_camera.add(this.v3_look);
    camera.lookAt(new THREE.Vector3(v.x,v.y,v.z));

    对Walk对象 添加wsad

    Walk.add('w',()=>{
                _.v3_speed = _.v3_look.clone();
                const v = _.v3_speed.scale(_.speed.front);
                x += v.x , z+=v.z;
                
            });
            Walk.add('s',()=>{
                _.v3_speed = _.v3_look.clone().scale(-1);
                const v = _.v3_speed.scale(_.speed.back);
                x += v.x,z += v.z;
            });
            Walk.add('d',()=>{
                _.v3_speed = _.v3_look_right.clone();
                const v = _.v3_speed.scale(_.speed.right);
                x += v.x,z += v.z;
            });
            Walk.add('a',()=>{
                _.v3_speed = _.v3_look_right.clone().scale(-1);
                const v = _.v3_speed.scale(_.speed.left);
                x += v.x,z += v.z;
            });

    增减两方位角

    el.addEventListener('mousemove',e=>{
                if(!behavior.rotate) return;
                if(!bx || !by) return;
                delta_x = (e.pageX-bx)*-.2,delta_y = (e.pageY-by)*.3;
                bx = e.pageX,by = e.pageY;
                _.φ += delta_x,_.θ += delta_y;
            });

    到这儿已经可以操作一个可转动的相机,并且让它运动起来了~

    相机动起来后,可能就会与物体发生碰撞,需要做碰撞检测。其实在three中做物体碰撞检测是很简单的,一些几何问题已经帮我们做了。相机与物体碰撞,其实就是检测lookat那条射线是否与物体的某个面相交,只要解决这个问题就好了。

    three中有Raycaster类,我们只要提供射线向量和需检测的物体们就可以了。当检测到碰撞后还需要响应,这里没有考虑什么真实物理效果,我就简单的给出一个推动向量,让相机往后移一下。。

    当摄像机运动到了那些检测区域,需要自动的往目标方向转动,随后还需沿着路径运动。

    关于转动,这里我用的是slerp插值。如下:

    如果v0和v1沿着圆弧运动,其中的插值向量是v(t)

    因为有v(t)=av0+bv1

    再对它们同时做叉乘

    v0 × v(t)= bv0 × v1

    v(t) × v1 = av0 × v1

    转换为模的形式

    |v0||v(t)|sin(1-c) = b|v0||v1|sin(c)

    |v1||v(t)|sin((1-t)c) = a|v0||v1|sin(c)

    化简求出a b

    a = sin((1-t)c)/sin(c)

    b = sin(tc)/sin(c)

    所以最终如下

    slerp(v0,v1,t) =  [sin((1-t)c)/sin(c)] v0 + [sin(tc)/sin(c)] v1 

    这里相机沿着一条直线在运动,lookat就是这条直线,非常的简单。相机还可以是曲线路径,比如下图这样。这个就有点麻烦了,需要求出梯度,终值和初值的lookat要与两平台平行。

    整个demo关于相机的东西就这些了~

    这篇还有额外的两个东西,一个是全景图,还一个是点光源,这俩之前的博文有提到过,这里稍微有点不同。

    之前的全景图是用css3实现的。这篇用的是three,如果用原生webgl的话,应该使用samplerCube 而不是 samper2D。

    点光源和平行光是差不多的,平行光对于每个顶点的光照方向都是一致的,而点光源需要为每个顶点计算出不同的光线,就多出这一步,其他基本一样。

    在之前平行光的基础上改改就好 ,如下

    void main(){
              vec4 smp = texture2D(u_smp, v_texture);
          
          //...
          //..
          //.. vec3 normal
    = normalize(v_normal);
          //关键 计算各个点的光线向量 vec3 li_di
    = normalize(light1-v_position); float nn = max(dot(li_di,normal ),0.01);  // gl_FragColor = smp*vec4(light2,1.0) +smp*nn*vec4(light1_co,1.0); }

    有没感觉目前整个场景空荡荡的?

    之后会慢慢丰富起来的,我设想在每个平台上都存在一些关键技巧,比如模型的选中、模型的动画、自定义着色器、 粒子化等。。。

    这些以后再慢慢添加吧。

     bye bye

  • 相关阅读:
    javaee 第六周作业
    javaee 第五周作业
    javaee 第四周作业
    第三周作业
    第二周作业xml学习情况
    javaWeb 中http请求 get 与 post的区别
    第八周
    第七周
    第六周
    第五周
  • 原文地址:https://www.cnblogs.com/daidaidai/p/5995679.html
Copyright © 2020-2023  润新知