[英]Changing buffers of different shapes with same shader fails at rendering - 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.