为什么threejs渲染此html文件太慢?

时间:2020-01-11 17:35:25

标签: javascript three.js

你好,我尝试了Threejs脚本,试图制作像我的世界这样的游戏。但是我失败了。这是我的HTML文件:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link rel="icon" type="image/png" href="https://i.ibb.co/gzfRWD5/minecraft-2-icon.png">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.js"></script>
    <script src="../../scripts/perlin.js"></script>
    <script src="../../scripts/localStorageDB.js"></script>
    <title>Minecraft 2 - V13 (Pre-Alpha)</title>
    <nav class="navbar navbar-dark bg-dark">
      <div id="linkslot_214396"><script src="https://linkslot.ru/bancode.php?id=214396" async></script></div>
      <a class="navbar-brand"href="#">
        Options:
        <input class="btn btn-primary" type="button" value="Show"id="showMenu">
        <input class="btn btn-danger" type="button" value="Hide"id="hideMenu">
      </a>
      <div id="linkslot_214398"><script src="https://linkslot.ru/bancode.php?id=214398" async></script></div>
    </nav>
    <nav class="navbar navbar-dark bg-dark"id="optionsNav"style="position:absolute;top:-9999px">
      <a class="navbar-brand" href="#">
        Render distance:
        <input class="form-control" id="render_distance_input" placeholder="Enter here.">
        <input class="btn btn-primary" type="button" value="increase"id="increaseRender">
        <input class="btn btn-danger" type="button" value="decrease"id="decreaseRender">
      </a>
      <a class="navbar-brand" href="#">
        Mouse sensivity:
        <input class="form-control" id="mouse_sensivity_input" placeholder="Enter here.">
        <input class="btn btn-primary" type="button" value="increase"id="increaseSensivity">
        <input class="btn btn-danger" type="button" value="decrease"id="decreaseSensivity">
      </a>
      <a class="navbar-brand" href="#">
        Camera field of view:
        <input class="form-control" id="fov_input" placeholder="Enter here.">
        <input class="btn btn-primary" type="button" value="increase"id="increaseField">
        <input class="btn btn-danger" type="button" value="decrease"id="decreaseField">
      </a>
      <a class="navbar-brand" href="#">
        Fog distance with respect the render distance:
        <input class="form-control" id="fog_input" placeholder="Enter here.">
        <input class="btn btn-primary" type="button" value="increase"id="increaseFog">
        <input class="btn btn-danger" type="button" value="decrease"id="decreaseFog">
      </a>
    </nav>
    <script>
    setTimeout(()=>{
      localStorage.clear()
      w=Math.floor(Math.random()*1000000)
      cube={}
      xa=0
      ya=0
      m=[]
      k=[]
      render_distance_input.value=4
      mouse_sensivity_input.value=1
      fov_input.value=50
      fog_input.value=0
      onmousemove=(event)=>{
        mouseX=event.clientX
        mouseY=event.clientY
        if(document.pointerLockElement===renderer.domElement||
        document.mozPointerLockElement===renderer.domElement){
          xa-=0.01*event.movementX*mouse_sensivity_input.value
          if(-1.5<ya&&0<event.movementY){
            ya-=0.01*event.movementY*mouse_sensivity_input.value
          }
          if(ya<1.5&&event.movementY<0){
            ya-=0.01*event.movementY*mouse_sensivity_input.value
          }
        }
      }
      onmousedown=onmouseup=(e)=>{
        m[e.button]=e.type=="mousedown"
        if(
          document.pointerLockElement===renderer.domElement
          ||
          document.mozPointerLockElement===renderer.domElement
        ){
        }else{
          if(200<mouseY&&optionsNav.style.top=="-9999px"){
            renderer.domElement.requestPointerLock()
          }
        }
      }
      onkeydown=onkeyup=(e)=>{k[e.keyCode]=e.type=="keydown"}
      box=new THREE.BoxGeometry(1,1,1)
      box_texture=new THREE.TextureLoader().load("../../images/textures/box.jpg")
      brick_texture=new THREE.TextureLoader().load("../../images/textures/brick.jpg")
      stone_texture=new THREE.TextureLoader().load("../../images/textures/stone.jpg")
      leaves_texture=new THREE.TextureLoader().load("../../images/textures/leaves.jpg")
      dirt_texture=new THREE.TextureLoader().load("../../images/textures/dirt.jpg")
      trunk_texture=new THREE.TextureLoader().load("../../images/textures/trunk.jpg")
      grass_texture=new THREE.TextureLoader().load("../../images/textures/grass.jpg")
      limestone_texture=new THREE.TextureLoader().load("../../images/textures/limestone.jpg")
      granite_texture=new THREE.TextureLoader().load("../../images/textures/granite.png")
      magma_texture=new THREE.TextureLoader().load("../../images/textures/magma.jpg")
      box_material=new THREE.MeshPhysicalMaterial({map:box_texture})
      bricks_material=new THREE.MeshPhysicalMaterial({map:brick_texture})
      stone_material=new THREE.MeshPhysicalMaterial({map:stone_texture})
      leaves_material=new THREE.MeshPhysicalMaterial({map:leaves_texture})
      dirt_material=new THREE.MeshPhysicalMaterial({map:dirt_texture})
      trunk_material=new THREE.MeshPhysicalMaterial({map:trunk_texture})
      grass_material=new THREE.MeshPhysicalMaterial({map:grass_texture})
      limestone_material=new THREE.MeshPhysicalMaterial({map:limestone_texture})
      granite_material=new THREE.MeshPhysicalMaterial({map:granite_texture})
      magma_material=new THREE.MeshPhysicalMaterial({map:magma_texture})
      document.body.style.margin=0
      renderer=new THREE.WebGLRenderer()
      document.body.appendChild(renderer.domElement)
      renderer.domElement.requestPointerLock=renderer.domElement.requestPointerLock||renderer.domElement.mozRequestPointerLock
      camera=new THREE.PerspectiveCamera()
      camera.xs=0
      camera.ys=0
      camera.zs=0
      camera.near=0.1
      camera.far=10000
      seed=Math.floor(Math.random()*Math.pow(10,10))
      scene=new THREE.Scene()
      render()
      directionalLight=new THREE.DirectionalLight("rgb(255,255,255)",1)
      scene.add(directionalLight)
      dlya=0.5
      directionalLight.castShadow=true
      directionalLight.receiveShadow=true
      directionalLight.position.set(0,1,0)
      directionalLight.target.position.set(0,0,0)
      scene.background=new THREE.Color("rgb(0,150,250)")
      fog1=new THREE.Fog("rgb(0,150,250)",0.01,100)
      scene.fog=fog1
      light=new THREE.HemisphereLight("rgb(255,255,255)","rgb(100,100,100)",0.25)
      scene.add(light)
      camera.position.set(0,noise.simplex2(seed,0)*100+5,0)
      all=new THREE.Geometry()
      all_figure=new THREE.Mesh(all)
      scene.add(all_figure)
    },1)
    g=(x,y,z,obj)=>{
      i1=Math.random()
      if(obj=="box"){
        cube[i1]=new THREE.Mesh(box,box_material)
      }
      if(obj=="leaves"){
        cube[i1]=new THREE.Mesh(box,leaves_material)
      }
      if(obj=="brick"){
        cube[i1]=new THREE.Mesh(box,bricks_material)
      }
      if(obj=="stone"){
        cube[i1]=new THREE.Mesh(box,stone_material)
      }
      if(obj=="dirt"){
        cube[i1]=new THREE.Mesh(box,dirt_material)
      }
      if(obj=="grass"){
        cube[i1]=new THREE.Mesh(box,grass_material)
      }
      if(obj=="trunk"){
        cube[i1]=new THREE.Mesh(box,trunk_material)
      }
      if(obj=="limestone"){
        cube[i1]=new THREE.Mesh(box,limestone_material)
      }
      if(obj=="granite"){
        cube[i1]=new THREE.Mesh(box,granite_material)
      }
      if(obj=="magma"){
        cube[i1]=new THREE.Mesh(box,magma_material)
      }
      cube[i1].position.set(x,y,z)
      scene.add(cube[i1])
    }
    distance_to_object=(x,y,z,x2,y2,z2)=>{
      return Math.pow(((x-x2)*(x-x2)+(y-y2)*(y-y2)+(z-z2)*(z-z2)),0.5)
    }
    check_into_object=(x,y,z,x2,y2,z2)=>{
      if(
        (x-0.4<x2+0.4&&x+0.4>x2-0.4)
        &&
        (y-0.4<y2+0.4&&y+0.4>y2-0.4)
        &&
        (z-0.4<z2+0.4&&z+0.4>z2-0.4)
      ){
        return true
      }else{
        return false
      }
    }
    check_into_square=(x,y,z,x2,y2,z2,r)=>{
      if(
        (x-r<x2+r&&x+r>x2-r)
        &&
        (y-r<y2+r&&y+r>y2-r)
        &&
        (z-r<z2+r&&z+r>z2-r)
      ){
        return true
      }else{
        return false
      }
    }
    check_object=(x,y,z)=>{
      checked=false
      for(i1 in cube){
        if(check_into_object(x,y,z,cube[i1].position.x,cube[i1].position.y,cube[i1].position.z)){
          checked=true
        }
      }
      return checked
    }
    check_id=(x,y,z)=>{
      id=0
      for(i1 in cube){
        if(check_into_object(x,y,z,cube[i1].position.x,cube[i1].position.y,cube[i1].position.z)){
          id=i1
        }
      }
      return id
    }
    
    //DON'T USE!!!
    //render_distance_input.value=4
    //mouse_sensivity_input.value=1
    //fov_input.value=50
    
    increaseRender.onclick=()=>{
      render_distance_input.value=eval(eval(render_distance_input.value)+1)
    }
    decreaseRender.onclick=()=>{
      render_distance_input.value=eval(eval(render_distance_input.value)-1)
    }
    
    increaseSensivity.onclick=()=>{
      mouse_sensivity_input.value=eval(eval(mouse_sensivity_input.value)+0.1)
      mouse_sensivity_input.value=Math.floor(mouse_sensivity_input.value*10)/10
    }
    decreaseSensivity.onclick=()=>{
      mouse_sensivity_input.value=eval(eval(mouse_sensivity_input.value)-0.1)
      mouse_sensivity_input.value=Math.floor(mouse_sensivity_input.value*10)/10
    }
    
    increaseField.onclick=()=>{
      fov_input.value.value=eval(eval(fov_input.value)+1)
    }
    decreaseField.onclick=()=>{
      fov_input.value.value=eval(eval(fov_input.value)-1)
    }
    
    showMenu.onclick=()=>{
      optionsNav.style.top=eval(64+8)+"px"
    }
    hideMenu.onclick=()=>{
      optionsNav.style.top="-9999px"
    }
    
    increaseFog.onclick=()=>{
      fog_input.value=eval(eval(fog_input.value)+1)
    }
    decreaseFog.onclick=()=>{
      fog_input.value=eval(eval(fog_input.value)-1)
    }
    
    render=()=>{
      //This sinchronize the scene.
      renderer.shadowMap.enabled=true
      renderer.shadowMap.type=THREE.BasicShadowMap
      renderer.setSize(innerWidth,innerHeight-128)
      camera.aspect=innerWidth/(innerHeight-128)
      camera.updateProjectionMatrix()
      requestAnimationFrame(render)
      renderer.render(scene,camera)
      //This update the player.
      camera.fov=fov_input.value
      if(-1.5>ya){ya=-1.5}
      if(1.5<ya){ya=1.5}
      camera.position.x+=camera.xs
      camera.position.y+=camera.ys
      camera.position.z+=camera.zs
      camera.xs*=7/8
      //camera.ys*=7/8
      camera.zs*=7/8
      if(-0.2<camera.ys){camera.ys-=0.01}
      camera.lookAt(
        camera.position.x+Math.sin(xa)*Math.cos(ya),
        camera.position.y+Math.sin(ya),
        camera.position.z+Math.cos(xa)*Math.cos(ya)
      )
      //Walk.
      if(k[65]){
        camera.xs+=0.005*Math.cos(xa)
        camera.zs-=0.005*Math.sin(xa)
      }
      if(k[87]){
        camera.xs+=0.005*Math.sin(xa)
        camera.zs+=0.005*Math.cos(xa)
      }
      if(k[68]){
        camera.xs-=0.005*Math.cos(xa)
        camera.zs+=0.005*Math.sin(xa)
      }
      if(k[83]){
        camera.xs-=0.005*Math.sin(xa)
        camera.zs-=0.005*Math.cos(xa)
      }
      //Jump.
      if(k[32]){
        //camera.ys+=0.005
        if(check_object(camera.position.x,camera.position.y-1.6,camera.position.z)){camera.ys=0.15}
      }
      if(k[88]){
        //camera.ys-=0.005
      }
      //This makes the solid collision.
      if(
        check_object(camera.position.x+camera.xs,camera.position.y-0.5,camera.position.z)
        ||
        check_object(camera.position.x+camera.xs,camera.position.y-1.5,camera.position.z)
      ){
        camera.xs=0
      }
      if(
        check_object(camera.position.x,camera.position.y+camera.ys-0.5,camera.position.z)
        ||
        check_object(camera.position.x,camera.position.y+camera.ys-1.5,camera.position.z)
      ){
        camera.ys=0
      }
      if(
        check_object(camera.position.x,camera.position.y-0.5,camera.position.z+camera.zs)
        ||
        check_object(camera.position.x,camera.position.y-1.5,camera.position.z+camera.zs)
      ){
        camera.zs=0
      }
      //This updates the render distance properties.
      render_distance=Math.floor(eval(render_distance_input.value))
      try{
        fog1.far=eval(render_distance+eval(fog_input.value)-1.5)
      }catch(e){}
      fixed_x=Math.floor(camera.position.x)
      fixed_y=Math.floor(camera.position.y)
      fixed_z=Math.floor(camera.position.z)
      //Player click.
      if(
        m[0]&&
        document.pointerLockElement===renderer.domElement||
        document.mozPointerLockElement===renderer.domElement
      ){
        for(i=0;i<2;i+=0.1){
          save(
            w+
            "x"+Math.floor(0.5+camera.position.x+Math.sin(xa)*Math.cos(ya)*i)+
            "y"+Math.floor(0.5+camera.position.y+Math.sin(ya)*i)+
            "z"+Math.floor(0.5+camera.position.z+Math.cos(xa)*Math.cos(ya)*i)
          ,0)
        }
      }
    }
    
    setInterval(()=>{
      //This updates the generation.
      for(x=fixed_x-render_distance;x<fixed_x+render_distance;x++){
        for(y=fixed_y-render_distance;y<fixed_y+render_distance;y++){
          for(z=fixed_z-render_distance;z<fixed_z+render_distance;z++){
            if(read(w+"x"+x+"y"+y+"z"+z)=="NaN"||read(w+"x"+x+"y"+y+"z"+z)==null){
              //If is into the render distance and there is not data in the database.
              val=0
              surface=noise.simplex2(x/500+seed,z/500)*100
              //Layer of magma.
              if(surface-150<y&&y<surface-100){
                val=10
              }
              //Second layer of granite & magma.
              if(surface-125<y&&y<surface-100){
                if(Math.random()<0.5){
                  val=9
                }else{
                  val=10
                }
              }
              //Second layer of granite & magma.
              if(surface-100<y&&y<surface-75){
                if(Math.random()<0.75){
                  val=9
                }else{
                  val=10
                }
              }
              //First layer of granite & magma.
              if(surface-75<y&&y<surface-50){
                if(Math.random()<0.9){
                  val=9
                }else{
                  val=10
                }
              }
              //Layer of granite.
              if(surface-50<y&&y<surface-25){val=9}
              //Layer of limestone and granite.
              if(surface-25<y&&y<surface-20){
                if(Math.random()<0.5){
                  val=9
                }else{
                  val=8
                }
              }
              //Layer of limestone.
              if(surface-20<y&&y<surface-10){val=8}
              //Layer of dirt and limestone.
              if(surface-10<y&&y<surface-5){
                if(Math.random()<0.5){
                  val=8
                }else{
                  val=5
                }
              }
              //Layer of dirt.
              if(surface-5<y&&y<surface-1){val=5}
              //Layer of grass.
              if(surface-1<y&&y<surface){val=6}
              //Bushes.
              if(surface<y&&y<surface+1&&Math.random()<0.05){val=4}
              //Top leaves.
              if(surface+5<y&&y<surface+20&&Math.random()<0.5){val=4}
              save(w+"x"+x+"y"+y+"z"+z,val)
              //Trees.
              if(surface-1<y&&y<surface&&Math.random()<0.02){
                for(i=0;i<15;i++){
                  y2=y+i
                  save(w+"x"+eval(x+1)+"y"+y2+"z"+z,7)
                  save(w+"x"+eval(x-1)+"y"+y2+"z"+z,7)
                  save(w+"x"+x+"y"+y2+"z"+eval(z+1),7)
                  save(w+"x"+x+"y"+y2+"z"+eval(z-1),7)
                }
              }
            }else{
              //If a block has been cleared.
              if(read(w+"x"+x+"y"+y+"z"+z)==0){
                if(check_object(x,y,z)){
                  i1=check_id(x,y,z)
                  scene.remove(cube[i1])
                  delete cube[i1]
                }
              }
              //If is data into the database and there is not blocks.
              if(read(w+"x"+x+"y"+y+"z"+z)==1){
                if(!check_object(x,y,z)){
                  g(x,y,z,"box")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==2){
                if(!check_object(x,y,z)){
                  g(x,y,z,"brick")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==3){
                if(!check_object(x,y,z)){
                  g(x,y,z,"stone")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==4){
                if(!check_object(x,y,z)){
                  g(x,y,z,"leaves")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==5){
                if(!check_object(x,y,z)){
                  g(x,y,z,"dirt")
              }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==6){
                if(!check_object(x,y,z)){
                  g(x,y,z,"grass")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==7){
                if(!check_object(x,y,z)){
                  g(x,y,z,"trunk")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==8){
                if(!check_object(x,y,z)){
                  g(x,y,z,"limestone")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==9){
                if(!check_object(x,y,z)){
                  g(x,y,z,"granite")
                }
              }
              if(read(w+"x"+x+"y"+y+"z"+z)==10){
                if(!check_object(x,y,z)){
                  g(x,y,z,"magma")
                }
              }
            }
          }
        }
      }
      for(i1 in cube){
        //Make all use shadow.
        cube[i1].castShadow=true
        cube[i1].receiveShadow=true
        //If it are blocks outer the render distance.
        if(
          check_into_square(fixed_x,fixed_y,fixed_z,cube[i1].position.x,cube[i1].position.y,cube[i1].position.z,render_distance+1000)
          &&
          !(check_into_square(fixed_x,fixed_y,fixed_z,cube[i1].position.x,cube[i1].position.y,cube[i1].position.z,render_distance/2))
        ){
          scene.remove(cube[i1])
          delete cube[i1]
        }
      }
    },200)
    
    read=(obj)=>{
      // Read.
      return localStorage.getItem(obj)
    }
    
    save=(obj,val)=>{
      // Save.
      localStorage.setItem(obj,val)
    }
    </script>

所以...当我执行此操作时,为什么脚本渲染太慢?我知道很难,但请帮助我。我听说过voxel.js,但未在我的计算机上加载。是的,我也使用localStorage将多维数据集存储到存储内存中。有谁能够帮助我?谢谢您的帮助。

1 个答案:

答案 0 :(得分:1)

很难说为什么合并网格对您不起作用。

与单个多维数据集一样,您现在正在做什么,这意味着在事情变慢之前,您最多可以获取大约100个多维数据集。为了加快速度,您需要做很多事情。

首先..通过将所有纹理合并到一个BIG纹理中,使所有多维数据集使用相同的纹理..称为纹理图集..然后使用每个立方体的UV来确定它们将渲染纹理图集的哪一部分。然后,您需要将每个32x32x32的多维数据集块合并为一个网格。这样,您将32768个立方体渲染为一个网格,并具有1个drawcall。权衡是要更改一个多维数据集,您将需要重建整个32x32x32 ..的整个块。因此,您必须使该超高效。

这将为您带来巨大的速度提升。

接下来,您将需要在每个块网格上设置“ .matrixAutoUpdate = false”,这是在您第一次创建mesh.updateMatrixWorld()之后。这告诉THREEJS您不会在每一帧移动该块,因此它可以跳过每个块上的某些矩阵计算。

这可能会极大地提高速度。

从那里..您可能还想探索“实例化”,它可以让您为每个多维数据集绘制一个具有单个数字的多维数据集类型的多维数据集。这可以使您提高速度10倍。

这是我对我玩的Minecraft娱乐机的看法。它不是最佳代码,但是如果我没记错的话,它确实会进行分块处理和纹理贴图处理,尽管我是前一段时间写的..所以我的记忆很朦胧:

http://vectorslave.com/minecraft-viewer-thrax/index.html