简体   繁体   English

带有自定义渲染器、vertexShader 和 fragmentShader 的 Openlayers

[英]Openlayers with custom Renderer, vertexShader & fragmentShader

I am looking to render some output to an openlayers map using the vertexShader & fragmentShader from the WebGL options.我希望使用 WebGL 选项中的 vertexShader 和 fragmentShader 将一些 output 渲染到 openlayers map。 The long term goal is something like the effect at windy.com .长期目标类似于windy.com的效果。

I have created a CustomWebGLPointsLayer (extending ol/layer/WebGLPoints) & specified some simple shaders to control for position & color.我创建了一个 CustomWebGLPointsLayer(扩展 ol/layer/WebGLPoints)并指定了一些简单的着色器来控制 position 和颜色。 With my CustomWebGLPointsLayer, data points are being placed in the center of the map resulting in a triangle (top left, top right, center) on the map. This triangle also ignores the color(s) I am attempting to set.使用我的 CustomWebGLPointsLayer,数据点被放置在 map 的中心,从而在 map 上形成一个三角形(左上角、右上角、中心)。这个三角形也忽略了我试图设置的颜色。

Questions are:问题是:

  • How can I get these points rendered appropriately?我怎样才能适当地呈现这些点?
  • How can I get the dynamic color to work correctly?如何让动态颜色正常工作?

Repo is here if you want to play with the code.如果你想玩代码,回购就在这里

CustomWebGLPointsLayer instantiation: CustomWebGLPointsLayer 实例化:

class CustomWebGLPointsLayer extends WebGLPointsLayer {
  createRenderer() {
    return new WebGLPointsLayerRenderer(this, { 
      // "attributes" are passed into the shaders
      attributes: [
        {
          name: 'a_coords',
          callback: function(feature) {
            // Array of XY positions per feature to pass to the vertexShader.
            const coordinatesArr = [ 
              feature.values_[0],
              feature.values_[1],
            ];
            return coordinatesArr;
          }
        },
        {
          name: 'a_color',
          callback: function(feature) {
            // Create an array of some colors & select one at random
            const colorsArr = {
              "red":   `[1.0, 0.0, 0.0]`,
              "green": `[0.0, 1.0, 0.0]`,
              "blue":  `[0.0, 0.0, 1.0]`,
            };

            const obj = Object.keys(colorsArr);
            const randomColor = obj[Math.floor(Math.random() * obj.length)];
            const vec3_color = colorsArr[randomColor];

            return vec3_color;
          }
        }
      ],
      vertexShader: 
      `
      // Specify the precision level to use with floats in this shader.
      precision mediump float;

      // Declare attributes; these values are passed into GLSL from JavaScript
      attribute vec2 a_coords;
      attribute vec3 a_color;

      // Declare varyings; these values will be passed along to the fragmentShader
      varying vec3 v_color;

      void main() {
        gl_Position = vec4(a_coords, 0.0, 0.0); // Set the position
        v_color = vec3(a_color); // set the value of v_color <-- This doesn't work?
      }
      `,
      // This should paint all fragments the value of v_color
      fragmentShader: `
      precision mediump float;

      // Declare varyings; these values have been passed along from the vertexShader
      varying vec3 v_color;

      void main() {
        gl_FragColor = vec4(v_color, 0.5); // Set the color dynamically - DOESN'T WORK
        // gl_FragColor = vec4(1.0, 0.0, 1.0, 0.5); // pink; WORKS!
        // gl_FragColor = vec4(1, 0, 0, 0.5); // red; WORKS! (testing ints, not floats)
      }
      `
    })
  }
};

And the map和 map

const map = new Map({
      layers: [
        new Tile({ source: new OSM() }),
        // new WebGLPointsLayer({ // Use this if you want to see the points rendered statically
        new CustomWebGLPointsLayer({
          source: new VectorSource({ features: featuresArr }),
          style: {
            symbol: {
              symbolType: "triangle",
              size: 16,
              color: "red",
              rotation: ["*", ["get", "deg"], Math.PI / 180],
              rotateWithView: true,
            },
          },
        }),
      ],
      target: "map",
      view: new View({center: [0, 0],zoom: 0,}),
    });

Thanks!谢谢!

I have the color passing into the shaders now, which effectively answers this question (which, if phrased better, was "How can I pass unique values per feature to the shaders?). Repo is updated if you want to play with it.我现在将颜色传递到着色器中,这有效地回答了这个问题(如果措辞更好的话,是“我如何将每个特征的唯一值传递给着色器?”)。如果您想使用它,请更新 Repo。

Here is my custom layer.这是我的自定义图层。 You can see that I separated the RGB values into distinct attributes.您可以看到我将 RGB 值分成不同的属性。 featureColorRed, featureColorBlue & featureColorGreen are all set as features during data processing. featureColorRed, featureColorBlue & featureColorGreen 都是在数据处理时设置为特征。 Each is a FLOAT which appears to be a requirement of passing data into the shaders(?).每个都是一个 FLOAT,这似乎是将数据传递到着色器(?)的要求。

// A custom renderer intended to draw GLSL output to a layer
class CustomWebGLPointsLayer extends WebGLPointsLayer {
  createRenderer() {
    return new WebGLPointsLayerRenderer(this, { 
      attributes: [
        {
          name: 'featureColorRed',
          callback: function(feature) {
            const color = feature.values_.featureColorRed;
            return color;
          }
        },
        {
          name: 'featureColorGreen',
          callback: function(feature) {
            const color = feature.values_.featureColorGreen;
            return color;
          }
        },
        {
          name: 'featureColorBlue',
          callback: function(feature) {
            const color = feature.values_.featureColorBlue;
            return color;
          }
        },
      ],

      vertexShader: 
      `
      attribute vec2 a_coordinates;
      attribute float a_featureColorRed;
      varying vec4 v_featureColor;

      attribute float a_featureColorGreen;
      varying vec4 v_featureColorGreen;

      attribute float a_featureColorBlue;
      varying vec4 v_featureColorBlue;

      void main() {
        v_featureColor = vec4(a_featureColorRed, a_featureColorGreen, a_featureColorBlue, 1.0);
        gl_Position = vec4(a_coordinates, 0.0, 1.0);
      }`,

      fragmentShader: `
      precision mediump float;

      varying vec4 v_featureColor;

      void main() {
        gl_FragColor = v_featureColor;
      }
      `
    })
  }
};

Then creating my custom layer.然后创建我的自定义层。 featuresArr is the data that has been processed. featuresArr 是已经处理过的数据。 IDK why I need to include "symbolType" here but without this style object OL fails to load. IDK 为什么我需要在此处包含“symbolType”但没有此样式 object OL 无法加载。

const customGLSLLayer = new CustomWebGLPointsLayer({
  source: new VectorSource({ features: featuresArr }),
  style: {
    symbol: {
      symbolType: "square",
    },
  },
  zIndex: 10,
});

And finally, the map (which is pretty standard).最后是 map(非常标准)。


const map = new Map({
  layers: [
    new Tile({ 
      source: new OSM(), 
      zIndex: 1, 
    }),
    customGLSLLayer
  ],
  target: "map",
  view: new View({center: [0, 0],zoom: 0,}),
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM