Babylon.js 第36章 动态变形网格

发布于:2022-12-21 ⋅ 阅读:(260) ⋅ 点赞:(0)

其实这是非常容易实现的。

  • 要创建可更新网格,必须在调用CreateXXX()方法时将其可更新参数设置为true 。
  • 要更新现有的参数形状,我们只需使用与构造它相同的CreateXXX方法。
  • 只有现有网格和与新位置相关的数据(路径、路径数组、点数组)必须传递给此方法,其他参数将被忽略。
  • 如果我们想变形网格,我们然后在渲染循环中使用CreateXXX()方法。
    在这种情况下,重要的是不要在每帧分配新内存:我们通过索引访问我们的数组,只是更改值而不是创建新数组,我们访问现有对象而不是实例化新对象等。我们还关注权重每个对象的数量(边数、顶点数等)。

例:如果我们需要在渲染循环中更新一个Lines网格,也就是说每帧更新points数组,最好改变每个数组元素的值(points[i].x = newXValue; points[i] .y = newYValue; points[i].z = newZValue; ) 在for循环中,而不是实例化一个新的points数组。

 

    //第一步,x,z的顶点数组
    var pathFun=k=>{
        let path=[]
        for(let i=0;i<60;i++){
            path.push(new BABYLON.Vector3(i-30,0,k))
        }
        return path
    }

    //第二布,创建y的顶点数组,k作为动态更新的参数
    var updatePath=function(path,k){
        //alert(path.lenght)
        for(let i=0;i<path.length;i++){
            path[i].x=path[i].x
            path[i].y=20*Math.sin(k+i/10)
            path[i].z=path[i].z
        }
    }

    //第三步,创建网,创建丝带
    var pathArry=[]
    for(let i=-20;i<20;i++){
        pathArry.push(pathFun(i*2))
    }
    let mesh=BABYLON.Mesh.CreateRibbon('rib',pathArry,false,
        false,0,scene,true,BABYLON.Mesh.BACKSIDE)
    mesh.material=mat

    //第四步,在渲染循环中更新k的值,然后改变丝带的数据
    scene.registerBeforeRender(()=>{
        for(let i=0;i<pathArry.length;i++){
            updatePath(pathArry[i],k)
        }
        mesh=BABYLON.Mesh.CreateRibbon(null,pathArry,
        null,null,null,null,null,null,mesh)
        k+=0.05
    )}
    

当然更新网格还可以使用meshBuilder,这样显得简洁:

mesh = BABYLON.MeshBuilder.CreateRibbon(null, 
    {pathArray: pathArray, instance: mesh});

曲线也是一样的道理:

    let path=[]
    for(let i=-100;i<100;i++){
        path.push(new BABYLON.Vector3(i/10,0,0))
    }

    let lines = BABYLON.Mesh.CreateLines("lines",path,scene,true);
    lines.color=new BABYLON.Color3.Red()
    function updateline(path,k){
        for(let i=0;i<path.length;i++){
            path[i].x=path[i].x
            path[i].y=Math.sin(i/10+k)
            path[i].z=Math.cos(i/10+k)
        }
        return path
    }
    let k=0
    camera.setTarget(new BABYLON.Vector3(0,0,0))
    //第四步,在渲染循环中更新k的值,然后改变丝带的数据
    scene.registerBeforeRender(()=>{
        updateline(path,k)
        lines=BABYLON.Mesh.CreateLines(null,path,null,null,lines);
        k+=0.1
    })

管子示例:

    let path=[]
    for(let i=0;i<20;i++){
        path.push(new BABYLON.Vector3(i*2,0,0))
    }
    let mesh=BABYLON.Mesh.CreateTube('tube',path,5,16,null,0,scene,true)
    let updatePath=function(path,k){
        for (var i = 0; i < path.length; i++) {
            path[i].y =5*Math.sin(i/10+k*2);
        }
    }
    let k=0
    scene.registerBeforeRender(()=>{
        let rad1=function(){
            return 2*Math.sin(k)
        }
        var rad2= function(i,distance) {
            return 1+2*Math.sin(i/2 +k);
          };
        updatePath(path,k)
        mesh=BABYLON.Mesh.CreateTube(null,path,rad1,null,rad2,
            null,null,null,null,mesh);
        k+=0.01
    })

对于盒子之类:

需要在更新顶点位置后使用updateMeshPositions()方法:

  var box = BABYLON.Mesh.CreateBox("box", 50, scene, true);
  box.material = mat;

  var angle = 0;

  scene.registerBeforeRender(function () {
	  var updatePositions = function (positions) {
		  var delta = angle;
		  for (var idx = 0; idx < positions.length; idx += 3) {
			  positions[idx + 0] += Math.sin(positions[idx + 1] / 6 + delta);
			  positions[idx + 2] += Math.sin(positions[idx + 0] / 12 + delta);
			  delta += 0.00005;
		  }
	  };
    pl.position = camera.position;
    box.updateMeshPositions(updatePositions);
    angle += 0.5;
  });

以前的CreateXXX()更新函数尝试尽可能多地优化以在渲染循环中快速运行。
但是,您可能出于任何原因需要更高的速度(例如,具有数十万个顶点的巨大网格)。
因此,如果您的网格不需要反射光(例如仅发射颜色),您可以跳过法线重新计算,这是一个消耗 CPU 的过程。
然后在创建网格后使用freezeNormals()方法需要重新设置法线计算过程,请使用一次unfreezeNormals()方法。

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到