簡體   English   中英

WebGL 渲染形狀錯誤

[英]WebGL is rendering shapes wrong

我有一些代碼應該獲取一些已解析的雷達數據,並使用 WebGL 在 Mapbox GL JS 地圖上呈現它。 我已經能夠將一般雷達形狀渲染到地圖上,但渲染是錯誤的。 正在繪制的形狀不是應有的矩形,但只要地圖縮放,它們就會四處晃動。 以下是一些詳細說明問題的 GIF:

這是它應該如何呈現的:(我在這里只使用 GeoJSON,加載時間非常慢)

在此處輸入圖像描述

以下是它的實際渲染方式:(忽略調色板的變化)

在此處輸入圖像描述

如您所見,WebGL 版本非常簡陋,每次縮放都會弄亂形狀。 這里出了什么問題?

您可以在此處查看此問題的演示: https ://steepatticstairs.github.io/radar_rendering_tests/radar-demo.html 只需放大藍色標記,您就會看到問題。 您可以在此處找到源代碼: https ://github.com/SteepAtticStairs/radar_rendering_tests 但為方便起見,我將在此處添加代碼片段。

HTML:

<!doctype html>
<html>
  <head>
    <title>QuadWeather Radar</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no,width=device-width' />
    <meta name="Description" content="View 3D radar for severe storms." />
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <link href="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css" rel="stylesheet">
    <script src="https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js"></script>
    <link rel="stylesheet" href="css/radarstyle.css">
    <link href="https://fonts.googleapis.com/css?family=Oleo+Script&display=swap" rel="stylesheet">
  </head>
  <body>
    <canvas id="texturecolorbar" class="texturecolorbar"></canvas>
    <div id="map" class="mobilemap"></div>
    <script type="x-shader/x-vertex" id="vertexShader">
      //x: azimuth
      //y: range
      //z: value
      attribute vec2 aPosition;
      attribute float aColor;
      uniform mat4 u_matrix;
      varying float color;

      void main() {
        color = aColor;
        gl_Position = u_matrix * vec4(aPosition.x,aPosition.y,0.0,1.0);
      }
    </script>
    <script type="x-shader/x-fragment" id="fragmentShader">
      precision mediump float;
      varying float color;
      uniform sampler2D u_texture;
      void main() {
        //gl_FragColor = vec4(0.0,color/60.0,0.0,1.0);
        float calcolor = (color)/(70.0);
        gl_FragColor = texture2D(u_texture,vec2(min(max(calcolor,0.0),1.0),0.0));
        //gl_FragColor = vec4(1.0,0.0,0.0,1.0);
      }
    </script>
    <script>
      //$.getJSON('./data/radar/KAMA_sub.json', function(data) {
      //  console.log(data);
      //})
    </script>
    <script src="scripts/demo-radar-script.js"></script>
  </body>  
</html>

主要JS:

function onload() {
  var settings = {};
  settings["lat"]=35.0;
  settings["lon"]=-101.72;
  settings["mlat"]=34.95;
  settings["mlon"]=-101.75;
  settings["rlat"]=35.2333;
  settings["rlon"]=-101.709;
  settings["phi"]=0.483395;
  settings["base"] = "../data/radar/test.json";


  //set up mapbox map
  mapboxgl.accessToken=
    "pk.eyJ1IjoicXVhZHdlYXRoZXIiLCJhIjoiY2pzZTI0cXFjMDEyMTQzbnQ2MXYxMzd2YSJ9.kHgQu2YL36SZUgpXMlfaFg";

  var map=window.map=new mapboxgl.Map({
    container:'map',
    attributionControl:false,
    zoom:3,
    maxZoom:25,
    minZoom:3,
  //overlaying custom made mapboxGL map
//    style: 'mapbox://styles/quadweather/cjsgo4h6905rg1fmcimx6j9dr'
    style: 'mapbox://styles/mapbox/bright-v9',
    antialias:true,
    zoom:9,
    center:[settings.mlon, settings.mlat],
    //pitch:70.,
    //bearing:315
  });
  map.addControl(new mapboxgl.AttributionControl(),'top-right');
  map.addControl(new mapboxgl.NavigationControl(),'top-left');

  new mapboxgl.Marker()
    .setLngLat([settings.rlon, settings.rlat])
    .addTo(map)

  function createTexture(gl) {
    var colors = {"refc0":['rgba(59,59,59,1)', //0
          'rgba(59,59,59,1)', //10
          'rgba(0,151,189,1)', //20
          'rgba(21,166,2,1)',   //30
          'rgba(250,208,0,1)',  //40
          'rgba(240,124,18,1)', //50
          'rgba(214,18,0,1)', //60
          'rgba(201,92,255,1)', //70
        ]}
    var values = {"refc0":[0, 1, 2, 3, 4, 5, 6, 7]}
    var colors=colors["refc0"];
    var levs=values["refc0"];
    var colortcanvas=document.getElementById("texturecolorbar");
    colortcanvas.width=1200;
    colortcanvas.height=1;
    var ctxt = colortcanvas.getContext('2d');
    ctxt.clearRect(0,0,colortcanvas.width,colortcanvas.height); 
    var grdt=ctxt.createLinearGradient(0,0,1200,0);
    var cmax=70;
    var cmin=0;
    var clen=colors.length;

    for (var i=0;i<clen;++i) {
      grdt.addColorStop((levs[i]-cmin)/(cmax-cmin),colors[i]);
    }
    ctxt.fillStyle=grdt;
    ctxt.fillRect(0,0,1200,1);
    imagedata=ctxt.getImageData(0,0,1200,1);
    imagetexture=gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D,imagetexture);
    pageState.imagetexture = imagetexture;
    gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,imagedata)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  }

  map.on("load", function() {
    //map.addLayer(layer3d);
    myWorker.postMessage([settings["base"],settings["phi"],settings["rlat"],settings["rlon"]]);
  })

  //compile shaders
  var vertexSource = document.getElementById('vertexShader').textContent;
  var fragmentSource = document.getElementById('fragmentShader').textContent;
  var masterGl;
  var layer = {
    id:"baseReflectivity",
    type:"custom",
    minzoom:0,
    maxzoom:18,

    onAdd: function(map,gl) {
      masterGl = gl;
      createTexture(gl);

      var ext = gl.getExtension('OES_element_index_uint');
      var vertexShader=gl.createShader(gl.VERTEX_SHADER);
      gl.shaderSource(vertexShader, vertexSource);
      gl.compileShader(vertexShader);
      var compilationLog = gl.getShaderInfoLog(vertexShader);
      console.log('Shader compiler log: ' + compilationLog);
      var fragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
      gl.shaderSource(fragmentShader, fragmentSource);
      gl.compileShader(fragmentShader);
      var compilationLog = gl.getShaderInfoLog(fragmentShader);
      console.log('Shader compiler log: ' + compilationLog);
      this.program = gl.createProgram();
      gl.attachShader(this.program, vertexShader);
      gl.attachShader(this.program, fragmentShader);
      gl.linkProgram(this.program);
      this.matrixLocation = gl.getUniformLocation(this.program, "u_matrix");
      this.positionLocation = gl.getAttribLocation(this.program, "aPosition");
      this.colorLocation = gl.getAttribLocation(this.program, "aColor");
      this.textureLocation=gl.getUniformLocation(this.program,"u_texture");

      //data buffers
      this.positionBuffer = gl.createBuffer();
      this.indexBuffer = gl.createBuffer();
      this.colorBuffer = gl.createBuffer();
    },//end onAdd
    render: function(gl,matrix) {
      //console.log("render base");
      var ext = gl.getExtension('OES_element_index_uint');
      //use program
      gl.useProgram(this.program);
      //how to remove vertices from position buffer
      var size=2;
      var type=gl.FLOAT;
      var normalize=false;
      var stride=0;
      var offset=0;
      //calculate matrices
      gl.uniformMatrix4fv(this.matrixLocation,false,matrix);
      gl.uniform1i(this.textureLocation,0);
      gl.bindBuffer(gl.ARRAY_BUFFER,this.positionBuffer);
      gl.bufferData(gl.ARRAY_BUFFER,pageState.positions,gl.STATIC_DRAW);
      gl.enableVertexAttribArray(this.positionLocation);
      gl.vertexAttribPointer(this.positionLocation,size,type,normalize,stride,offset);
      
      gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer);
      gl.bufferData(gl.ARRAY_BUFFER,pageState.colors,gl.STATIC_DRAW);
      gl.enableVertexAttribArray(this.colorLocation);
      gl.vertexAttribPointer(this.colorLocation,1,type,normalize,stride,offset);

      gl.bindTexture(gl.TEXTURE_2D,pageState.imagetexture);
      gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,imagedata)
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

      var primitiveType = gl.TRIANGLES;
      var count = pageState.indices.length;
      gl.drawArrays(primitiveType, offset, pageState.positions.length/2);

    }//end render
  }

  function dataStore() {
    return {
      positions:null,
      indices:null,
      colors:null
    }
  }

  var pageState = dataStore();

  var myWorker = new Worker('scripts/generateVerticesRadarDemo.js');
  myWorker.onmessage=function(oEvent) {
    var data = new Float32Array(oEvent.data.data);
    var indices = new Int32Array(oEvent.data.indices);
    var colors = new Float32Array(oEvent.data.colors);
    pageState.positions = data;
    pageState.indices = indices;
    pageState.colors = colors;
    map.addLayer(layer);
  }
}

window.onload = onload();

JS 生成 LAT/LNG 坐標

onmessage=function(oEvent) {
  var url = oEvent.data[0];

  //250/2
  var gateRes = 1;
  if (url == "../data/radar/KTLX_sub.json") {
    gateRes = 1000/2;
  }

  function radians(deg) {
    return (3.141592654/180.)*deg;
  }

  var radarLat = radians(oEvent.data[2]);
  var radarLon = radians(oEvent.data[3]);
  var inv = 180.0/3.141592654;
  var re = 6371000.0;
  var phi = radians(oEvent.data[1]);
  var h0 = 0.0;
  
  function calculatePosition(az, range) {
        var mathaz = radians(90.0 - az);
        var h = Math.sqrt(Math.pow(range,2.0)+Math.pow(((4./3.)*re+h0),2.0)+2.*range*((4./3.)*re+h0)*Math.sin(phi))-(4./3.)*re;
        var ca = Math.acos((Math.pow(range,2.0)-Math.pow(re,2.0)-Math.pow(re+h,2.0))/(-2.0*re*(re+h)));
        var xcart = (ca*re)*Math.cos(mathaz);
        var ycart = (ca*re)*Math.sin(mathaz);
        //convert to latitude longitude
        var rho = Math.sqrt(Math.pow(xcart,2.0)+Math.pow(ycart,2.0));
        var c = rho/re;
        var lat = Math.asin(Math.cos(c)*Math.sin(radarLat)+(ycart*Math.sin(c)*Math.cos(radarLat))/(rho))*inv;
        lon = (radarLon + Math.atan((xcart*Math.sin(c))/(rho*Math.cos(radarLat)*Math.cos(c)-ycart*Math.sin(radarLat)*Math.sin(c))))*inv;

        //console.log(lat, lon)

        mx = (180.0 + lon)/360.0;
        my = (180. - (180. / 3.141592654 * Math.log(Math.tan(3.141592654 / 4. + lat * 3.141592654 / 360.)))) / 360.; 
        //console.log(mx,my);
        return {
          x:mx,
          y:my
        }

  }

  //function to process file
  function reqListener() {
    var json = JSON.parse(this.responseText);

    var azs = json.azimuths;
    var min = azs[0];
    var max = azs[azs.length-1];

    for (var key in json.radials) {
      if (key == "azimuths") continue;
      key = +key;
      var values = json.radials[key];
      var az = azs[key];
      var leftAz, rightAz, bottomR, topR;

      //case when first az
      if (key == 0) {
        //case when crossing 0
        leftAz = (min + 360 + max)/2;
        rightAz = (az+azs[key+1])/2;
      } else if (key == azs.length-1) {
        //case when crossing 0 the other way
        leftAz = (az + azs[key-1])/2;
        rightAz = (min+360+max)/2; 
      } else {
        //case when nothing to worry about
        leftAz = (az + azs[key-1])/2;
        rightAz = (az + azs[key+1])/2;
      }

      //loop through radar range gates
      for (var i=0; i<values.length; i++) {
        bottomR = values[i]-gateRes;
        topR = values[i] + gateRes;

        var bl = calculatePosition(leftAz, bottomR);
        //console.log(bl, bl.x);
        var tl = calculatePosition(leftAz, topR);
        var br = calculatePosition(rightAz, bottomR);
        var tr = calculatePosition(rightAz, topR);

        output.push(
          bl.x,//leftAz,
          bl.y,//bottomR,

          tl.x,//leftAz,
          tl.y,//topR,

          br.x,//rightAz,
          br.y,//bottomR,
          br.x,//rightAz,
          br.y,//bottomR,

          tl.x,//leftAz,
          tl.y,//topR,
          tr.x,//rightAz,
          tr.y//topR
        )
        var colorVal = json.values[key][i];
        colors.push(colorVal, colorVal, colorVal, colorVal, colorVal, colorVal);
      }
      
    }
    var typedOutput = new Float32Array(output);
    var colorOutput = new Float32Array(colors);
    var indexOutput = new Int32Array(indices);
    postMessage({"data":typedOutput.buffer,"indices":indexOutput.buffer,"colors":colorOutput.buffer},[typedOutput.buffer,indexOutput.buffer,colorOutput.buffer]);
  }

  //get file from server
  var oReq = new XMLHttpRequest();
  oReq.addEventListener("load", reqListener);
  oReq.open("GET", url);
  oReq.send();

  var output = [];
  //var maxUn = 467000;
  //var firstGate = 2125;
  //var startingAngle = 0.0;
  var indices = [];
  var colors = [];
}

我相信我已經找到了答案。 我不認為這是 WebGL 的問題,我認為這是我提供的數據的問題。 我只需將每個雷達門值乘以 100:

bottomR = values[i]*100 - gateRes;
topR = values[i]*100 + gateRes;

我必須將門分辨率設置為 WSR-88D 雷達的掃描半徑(460 公里):

var gateRes = 460;

這是非常細微的,所以如果有人遇到這個確切的問題,我希望這對你有幫助,但可能不會。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM