pixijs + webgl 实现城市交通模拟 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
flyPig9527
V2EX    V2EX

pixijs + webgl 实现城市交通模拟

  •  1
     
  •   flyPig9527 2022-10-24 17:05:05 +08:00 1965 次点击
    这是一个创建于 1082 天前的主题,其中的信息可能已经有所发展或是发生改变。

    交通模拟器

    汽车的行驶以及等红绿灯的场景进行模拟,使用了pixiwebgl去实现的。
    webgl 主要是用在 pixi 中 spite 的着色器的编写。

    预览

    github 预览地址
    gitee 预览地址
    网速慢的慢的话建议gitee 预览地址,效果会更好
    如果感觉不错的话,给 star

    界面

    功能

    功能

    功能标注 右侧区域:

    • 可以看到当前的帧率
    • 暂停按钮可以让动画暂停,再次点击即可继续动画

    左侧区域: 汽车的模式目前是有四种:原始模式多彩模式多彩闪光模式简笔画模式

    • 多彩模式是可以让原始的汽车颜色进行更换多种颜色的更换
    • 多彩闪光模式是让汽车颜色一直随机变
    • 简笔画模式是让汽车是简笔画的形态 这三部分是通过pixisprite用的webgl来写了一部分sharder完成的。

    车辆管理区域:
    目前就两款车型,可以控制道路上行驶的车辆类型,禁用可以让该类型的车辆不在道路上行驶,启用则是相反,允许该车辆行驶。

    技术实现

    首先车辆的行驶方向是上下左右四个方向,这四个方向的车辆我这里是采用了链表的数据结构。
    为什么要使用链表这种数据结构呢?
    回答:老子乐意!!!
    其实是平时只有刷算法题的时候才用到链表,平时工作用不到,所以就想用用链表来实现。当然用数组也能实现。由于车辆要不断地删除添加的操作所以链表的效率会更高一些。这个项目中用到的链表也挺不难,就是链表的添加和删除,会这两个就能进行车辆的添加和删除。

    车辆添加

    车辆是pixijssprite,每种类型的车辆都是分为上下左右四张图片。

    未命名.png

    添加车辆就是在链表的最后添加上 sprite ,存储数据是 carData,它是个 useRef 。是分为left right top bottom四个字段,代表四个方向,每个字段都是一个链表,是每个方向的车辆。根据每个方向要对 sprite 进行 x ,y 点进行初始化,根据前一个链表节点的 x 和 y ,计算添加车辆的 x 和 y 。

    // direction: 方向 WIDTH 画布的宽度 HEIGHT 画布的高度 ROADWIDTH 道路的宽度 // 该链表如果存在节点最后添加节点,没有节点直接放入 if (carData.current[direction]) { let current = carData.current[direction]!; // 拿到最后一个节点 while (current.next) { current = current.next!; } // 根据最后一个节点计算出要添加节点的位置 switch (direction) { case 'left': sprite.y = (HEIGHT - ROADWIDTH) / 2 + ROADWIDTH / 4; if (current.val.x >= WIDTH - CARLENGTH / 2) { sprite.x = current.val.x + CARLENGTH * 1.5; } else { sprite.x = WIDTH - CARLENGTH / 2; } break; case 'right': sprite.y = HEIGHT / 2 + ROADWIDTH / 4; if (current.val.x <= -CARLENGTH / 2) { sprite.x = current.val.x - CARLENGTH * 1.5; } else { sprite.x = -CARLENGTH / 2; } break; case 'top': sprite.x = WIDTH / 2 + ROADWIDTH / 4; if (current.val.y >= HEIGHT + CARLENGTH / 2) { sprite.y = current.val.y + CARLENGTH * 1.5; } else { sprite.y = HEIGHT + CARLENGTH / 2; } break; case 'bottom': sprite.x = WIDTH / 2 - ROADWIDTH / 4; if (current.val.y <= -CARLENGTH / 2) { sprite.y = current.val.y - CARLENGTH * 1.5; } else { sprite.y = -CARLENGTH / 2; } break; } current.next = new ListNode(sprite); } else { if (direction === 'left') { // 向左行驶的车辆位置 sprite.y = (HEIGHT - ROADWIDTH) / 2 + ROADWIDTH / 4; sprite.x = WIDTH - CARLENGTH / 2; } else if (direction === 'right') { // 向右行驶的车辆位置 sprite.y = HEIGHT / 2 + ROADWIDTH / 4; sprite.x = -CARLENGTH / 2; } else if (direction === 'top') { // 向上行驶的车辆位置 sprite.x = WIDTH / 2 + ROADWIDTH / 4; sprite.y = HEIGHT + CARLENGTH / 2; } else if (direction === 'bottom') { // 向下行驶的车辆位置 sprite.x = WIDTH / 2 - ROADWIDTH / 4; sprite.y = -CARLENGTH / 2; } carData.current[direction] = new ListNode(sprite); } 

    车辆行驶

    车辆行驶需要考虑几点:

    • 当前面红灯怎么办?
    • 后面的车辆要撞到前一个车辆怎么办?
    • 为了灵活性,汽车什么时候加速,什么时候减速?

    下面一一解答:

    • 当为红灯的时候,下一步就要闯红灯了,这时需要让车辆停止,位置一直保持为原来的位置
    • 后面的车要撞到前面的车,有两种情况:一种是前面的车在等红绿灯,另一种是都是行驶状态,后面车的车速大于前面车的车速。这时候需要设置一个阈值 min,当后车与前车的距离小于这个min的时候,需要让后车相对于前车速度进行减速,如果减速还是会小于这个min的话,说明前车在等红绿灯,这时候后车的位置等于这个min就行了,保证不小于这个min
    • 上面说设置一个车距之间的最小阈值 min,是为了让车减速,加速则是要设置车距之间的最大阈值 max,车距超过这个max就进行加速操作。
      代码就不展示了,主要是链表的遍历去对每辆车进行计算。

    车辆模式

    因为pixijs默认是使用webgl去进行渲染的,sprite支持使用 webgl 编写着色器的。根据选择的不同模式进行着色器 sharder 的编写完成的。

    多彩模式:生成一个随机的 rgb三个通道的值,然后到通过uniform传入到片元着色器与当前的色值进行相乘,深色部分打算是保留下来的,所以设置一个阈值,超过这个阈值代表浅色,浅色部分会去跟随机 rgb 进行相乘。

    多彩闪光模式:和多彩模式实现是一样的,区别是动画每帧都会使用多彩,所以有了多彩闪光的一个效果。

    简笔画模式:这个是我写多彩模式的 sharder 无意间实现出来的,原理也是很简单的,将浅色部分都变成白色,只留下深色部分,就是简笔画的效果。

    /** * 汽车颜色滤镜 * @param sprite */ export const carFilterColor = (sprite: Sprite, type?: number) => { const fragStr = ` varying vec2 vTextureCoord; uniform sampler2D uSampler; uniform vec2 size; uniform vec3 secondaryColor; uniform float type; void main(void){ vec2 uv = size; vec4 color = texture2D(uSampler, vTextureCoord); // 阈值 float num = 0.3; if(type != 0.0){ if(color.r > num || color.g >= num || color.b >= num){ if(type == 1.0 || type == 2.0 ){ / 多彩或多彩闪光模式 color.rgb *= secondaryColor; }else if (type == 3.0){ // 简笔画模式 color.rgb = vec3(1.0); } } color.rgb = clamp(vec3(0.0),color.rgb,vec3(1.0)); } gl_FragColor = color; } `; let filter = new PIXI.Filter(undefined, fragStr, { secondaryColor: [ Math.random() + 0.6, Math.random() + 0.6, Math.random() + 0.6, ], type: type || 0, }); sprite.filters = [filter]; }; 

    还有一些细节点就不一一赘述了,如:交通灯的设计和控制、车辆类型的控制等等。

    第 1 条附言    2022-10-25 09:58:14 +08:00

    项目的GitHub地址忘了发出来了, https://github.com/dearDreamWeb/traffic_simulator.github.io
    喜欢的话,请给个star

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3587 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 00:46 PVG 08:46 LAX 17:46 JFK 20:46
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86