2023-03-15 webgl绘制影像瓦片

129 阅读1分钟

一、结果

image.png

二、代码

根据瓦片行列号计算单个瓦片范围

/**
 * 根据行列号计算瓦片
 * @param {*} x 
 * @param {*} y 
 * @param {*} zoom 
 */
export function computeBound(x, y, zoom) {
  //根据级别计算当前有多少瓦片
  const xNumber = Math.pow(2, zoom)
  const yNumber = Math.pow(2, zoom - 1)
  //计算每个瓦片经纬度宽度
  const xWidth = 360 / xNumber
  const yWidth = 180 / yNumber

  const minLng = tile2lng(x, zoom)
  const maxLng = tile2lng(x + 1, zoom)
  const minLat = tile2lat(y, 4)
  const maxLat = tile2lat(y + 1, 4)
  return {
    minLng,
    maxLng,
    minLat,
    maxLat
  }
}


// 墨卡托下瓦片编号转经纬度
function tile2lng(x, z) {
  return (x / Math.pow(2, z) * 360 - 180);
}


function tile2lat(y, z) {
  var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
  return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
}

构建mesh


import { BufferGeometry } from './BufferGeometry.js'
import { computeBound } from '../core/Math.js'
import { Cartesian3 } from '../core/Math.js'
export default class TileGeometry extends BufferGeometry {
  constructor({
    x,
    y,
    zoom,
  }) {
    super()
    this._bound = computeBound(x, y, zoom)
    console.log(this._bound)
    this.initGeometry()
  }


  initGeometry() {
    //划分为16*16的 格子
    //计算每个格子宽度
    const rangeLng = (this._bound.maxLng - this._bound.minLng) / 16
    const rangeLat = (this._bound.maxLat - this._bound.minLat) / 16

    const rangeUV = 1.0 / 16

    const positions = []
    const uvs = []
    const indexes = []
    for (let i = 0; i < 17; i++) {
      const lat = this._bound.maxLat - rangeLat * i
      const v = 1 - rangeUV * i
      //行数
      for (let j = 0; j < 17; j++) {
        const lng = this._bound.minLng + rangeLng * j
        const position = Cartesian3.fromDegrees(lng, lat, 0.001)
        positions.push(position.x, position.y, position.z)
        const u = rangeUV * j
        uvs.push(u, v)
        if (i < 16 && j < 16) {
          const current = i * 17 + j
          indexes.push(current, current + 17, current + 1)
          indexes.push(current + 1, current + 17, current + 18)
        }

      }
    }

    console.log(positions, uvs, indexes)
    super.create({ positions, indexes, uvs }, gl.TRIANGLES)

  }






}

调用代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport"
    content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>绘制线</title>
  <style>
    body {
      margin: 0px;
      padding: 0px;
      text-align: center;
    }

    #canvas {
      margin: 0;
      position: absolute;
      width: 100%;
      height: 100%;
      left: 0px;
      top: 0px;
    }
  </style>
  <script src="/lib/webgl-utils.js"></script>
  <script src="/lib/webgl-debug.js"></script>
  <script src="/lib/cuon-utils.js"></script>
  <script src="/lib/cuon-matrix.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.js"></script>
</head>

<body>

  <canvas id="canvas"></canvas>

</body>


<script type="module">
  import { SphereGeometry } from "/geometry/SphereGeometry.js"

  import { Texture2D } from './texture/Texture2D.js'
  import { Program } from './core/Program.js'
  import { toRadian, Cartesian3 } from './core/Math.js'
  import { Material } from './material/Material.js'
  import { Control } from './core/Control.js'
  import { Object3D } from './core/Object3D.js'
  import { Scene } from './core/Scene.js'
  import { Camera } from './core/Camera.js'
  import { Renderer } from './core/Renderer.js'
  import { earthVS, earthFS } from './material/shaders/Earth.js'

  import TileGeometry from './geometry/TileGeometry.js'

  const VS =/*glsl*/`
    attribute vec3 a_Position;
    attribute vec2 a_Uv;
    uniform mat4 u_ModelMatrix;
    uniform mat4 u_ViewMatrix;
    uniform mat4 u_ProjectMatrix;
    varying vec2 v_Uv;
    void main(){
      mat4 mvpMatrix=u_ProjectMatrix*u_ViewMatrix*u_ModelMatrix;
      v_Uv=a_Uv;
      gl_Position=mvpMatrix*vec4(a_Position,1.0);
    }
  `

  const FS = /*glsl*/`
  #ifdef GL_ES
  precision mediump float;
  #endif
  uniform sampler2D u_Texture;
  
  varying vec2 v_Uv;

  void main(){
  
    
      vec4 baseColor=texture2D(u_Texture,v_Uv);
          
      gl_FragColor=baseColor;
  
  }`;


  //声明js需要的相关变量
  var canvas = document.getElementById("canvas");

  canvas.width = canvas.clientWidth;
  canvas.height = canvas.clientHeight;
  window.gl = getWebGLContext(canvas);



  const scene = new Scene()
  const camera = new Camera(30, canvas.width / canvas.height, 0.1, 10)
  // var projMatrix = camera.projectMatrix
  //设置视角矩阵的相关信息(视点,视线,上方向)
  var viewMatrix = camera.viewMatrix
  const renderer = new Renderer()

  main()

  async function main() {

    if (!gl) {
      console.log("你的浏览器不支持WebGL");
      return;
    }



    const earthProgram = new Program(earthVS, earthFS)
    //绘制球形
    const sphereGeometry = new SphereGeometry(gl, 1, 180, 90)

    //绘制纹理
    const texture = Texture2D.initTexture('./image/earth.jpg', 0)
    const sphereMaterial = new Material({
      program: earthProgram,
      uniforms: {
        texture: texture,
        normalTexture: null,
        test: 1.0
      },
    })

    const earth = new Object3D(sphereGeometry, sphereMaterial)
    scene.add(earth)




    const program = new Program(VS, FS)

    for (let i = 11; i <= 14; i++) {
      for (let j = 7; j <= 8; j++) {
        const tileGeomtry = new TileGeometry({
          x: i,
          y: j,
          zoom: 4
        })
        //绘制纹理
        const texture1 = Texture2D.initTexture(`./image/tiles/4-${j}-${i}.jpg`, 0)
        const tileMaterial = new Material({
          program: program,
          uniforms: {
            texture: texture1,
          },
        })
        const tile = new Object3D(tileGeomtry, tileMaterial)
        scene.add(tile)
      }
    }








    const control = new Control(viewMatrix, canvas)
    var tick = function () {
      //设置底色
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      control.update()

      renderer.render(scene, camera)
      requestAnimationFrame(tick)
    }
    tick()


    // Control.registerMouseEvent(canvas)
  }




</script>

</html>