是否可以从openlayers访问低级WebGL,就像访问简单的canvas html5元素一样?
var context = event.glContext;
var gl = context.getGL();
我已经尝试调整low-level clipping example in openlayers来绘制一个简单的三角形,例如WebGL Fundamentals tutorial中的一个三角形连接到precompose
事件,但没有任何运气。
这是挂钩的正确事件吗?
以下代码将openstreetmap切片图层作为基础和静态图像,并在this example后面重新投影。
这个想法是将顶级静态图像作为画布操作来测试低级WebGL。但唯一发生的事情是,无论我传递给缓冲区的哪一点,顶层都会剪切底层OSM层。
我对WebGL的理解非常有限,有人能指出我正确的方向吗?
proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' +
'+x_0=400000 +y_0=-100000 +ellps=airy ' +
'+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' +
'+units=m +no_defs');
var imageExtent = [0, 0, 700000, 1300000];
var img = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/' +
'British_National_Grid.svg/2000px-British_National_Grid.svg.png',
crossOrigin: '',
projection: 'EPSG:27700',
imageExtent: imageExtent
})
});
var myosm = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
//layers: [myosm, img],
layers: [myosm, img],
target: 'map',
renderer: /** @type {Array<ol.renderer.Type>} */ (['webgl', 'canvas']),
view: new ol.View({
center: ol.proj.transform(
ol.extent.getCenter(imageExtent), 'EPSG:27700', 'EPSG:3857'),
zoom: 4
})
});
var vertexShaderSource = document.getElementById("2d-vertex-shader").text;
var fragmentShaderSource = document.getElementById("2d-fragment-shader").text;
img.on('precompose', function(e) {
var context = e.glContext;
var gl = context.getGL();
var program = gl.createProgram();
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
gl.attachShader(program, vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
var positionLocation = gl.getAttribLocation(program, 'a_position');
var positions = [
0, 0,
0, 0.5,
0.7, 0,
];
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
context.useProgram(program);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 24);
});
&#13;
<link href="https://openlayers.org/en/v4.6.4/css/ol.css" rel="stylesheet"/>
<script src="https://openlayers.org/en/v4.6.4/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.4.4/proj4.js"></script>
<div id="map" class="map"></div>
<div id="no-webgl" class="alert alert-danger" style="display: none">
This example requires a browser that supports <a href="http://get.webgl.org/">WebGL</a>.
</div>
<script id="2d-vertex-shader" type="notjs">
// an attribute will receive data from a buffer
attribute vec4 a_position;
// all shaders have a main function
void main() {
// gl_Position is a special variable a vertex shader
// is responsible for setting
gl_Position = a_position;
}
</script>
<script id="2d-fragment-shader" type="notjs">
// fragment shaders don't have a default precision so we need
// to pick one. mediump is a good default
precision mediump float;
void main() {
// gl_FragColor is a special variable a fragment shader
// is responsible for setting
gl_FragColor = vec4(1, 0, 0.5, 1); // return redish-purple
}
</script>
&#13;
答案 0 :(得分:1)
我找到了一种通过使用ImageCanvas作为源的图像层来操作openlayers上的低级WebGL的方法:
var canvasLayer = new ol.layer.Image({
source: new ol.source.ImageCanvas({
canvasFunction: canvasFunction,
projection: 'EPSG:3857'
})
});
canvasFunction将是WebGL例程的结果(准备并调用mainWebGL():
var canvasFunction = function(extent, resolution, pixelRatio, size, projection) {
var canvas = document.createElement('canvas');
canvas.setAttribute('width', size[0]);
canvas.setAttribute('height', size[1]);
var gl = canvas.getContext("webgl");
var glOut = mainWebGL(canvas, gl);
gl.drawArrays(glOut[1], glOut[2], glOut[3]);
return canvas;
};
在附带的工作示例中,我举例说明了如何将WebGL图层限制在地理范围内。
当然,在[-1,1] WebGL坐标中完成WebGL绘图并获得合理的地理配准,应该实现一个带有转换矩阵的额外函数(不包括在内但应该是什么的可以找到谷歌地图的here。
// WebGL - Fundamentals
//from https://webglfundamentals.org/webgl/webgl-fundamentals.html
function main() {
webglLayer = mainOL();
}
function mainOL() {
proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' +
'+x_0=400000 +y_0=-100000 +ellps=airy ' +
'+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' +
'+units=m +no_defs');
function transform(extent) {
return ol.proj.transformExtent(extent, 'EPSG:4326', 'EPSG:3857');
}
var extents = {
India: transform([68.17665, 7.96553, 97.40256, 35.49401]),
Argentina: transform([-73.41544, -55.25, -53.62835, -21.83231]),
Nigeria: transform([2.6917, 4.24059, 14.57718, 13.86592]),
Sweden: transform([11.02737, 55.36174, 23.90338, 69.10625])
};
var canvasFunction = function(extent, resolution, pixelRatio, size, projection) {
var canvas = document.createElement('canvas');
var canvasWidth = size[0],
canvasHeight = size[1];
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', canvasHeight);
var gl = canvas.getContext("webgl");
var glOut = mainWebGL(canvas, gl);
gl.drawArrays(glOut[1], glOut[2], glOut[3]);
return canvas;
};
var imageExtent = [0, 0, 700000, 1300000];
var overlay = new ol.layer.Tile({
extent: extents.India,
source: new ol.source.TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.world-black.json?secure',
crossOrigin: 'anonymous'
})
});
var canvasLayer = new ol.layer.Image({
source: new ol.source.ImageCanvas({
canvasFunction: canvasFunction,
projection: 'EPSG:3857'
})
});
var myosm = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
//layers: [myosm
layers: [myosm],
target: 'map',
view: new ol.View({
center: ol.proj.transform(
ol.extent.getCenter(imageExtent), 'EPSG:27700', 'EPSG:3857'),
zoom: 4
})
});
map.addLayer(overlay);
map.addLayer(canvasLayer);
canvasLayer.setExtent(extents["India"]);
overlay.setExtent(extents["India"]);
return canvasLayer;
}
function createShader(gl, type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
gl.deleteShader(shader);
}
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
gl.deleteProgram(program);
}
function mainWebGL(canvas, gl) {
// Get the strings for our GLSL shaders
var vertexShaderSource = document.getElementById("2d-vertex-shader").text;
var fragmentShaderSource = document.getElementById("2d-fragment-shader").text;
// create GLSL shaders, upload the GLSL source, compile the shaders
var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
// Link the two shaders into a program
var program = createProgram(gl, vertexShader, fragmentShader);
// look up where the vertex data needs to go.
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
// Create a buffer and put three 2d clip space points in it
var positionBuffer = gl.createBuffer();
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var positions = [
0, 0,
0, -0.5,
0.2, 0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// code above this line is initialization code.
// code below this line is rendering code.
// Tell WebGL how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// Turn on the attribute
gl.enableVertexAttribArray(positionAttributeLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset)
// draw
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 3;
//gl.drawArrays(primitiveType, offset, count);
return [gl, primitiveType, offset, count];
//return canvas;
}
main();
<link href="https://openlayers.org/en/v4.6.4/css/ol.css" rel="stylesheet">
<script src="https://openlayers.org/en/v4.6.4/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.4.4/proj4.js"></script>
<div id="map" class="map"></div>
<script id="2d-vertex-shader" type="notjs">
// an attribute will receive data from a buffer
attribute vec4 a_position;
// all shaders have a main function
void main() {
// gl_Position is a special variable a vertex shader
// is responsible for setting
gl_Position = a_position;
}
</script>
<script id="2d-fragment-shader" type="notjs">
// fragment shaders don't have a default precision so we need
// to pick one. mediump is a good default
precision mediump float;
void main() {
// gl_FragColor is a special variable a fragment shader
// is responsible for setting
gl_FragColor = vec4(1, 0, 0.5, 1); // return redish-purple
}
</script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-lessons-helper.js"></script>