当前位置: 首页 > news >正文

05-ArcGIS For JavaScript-RenderNode后处理效果

05-ArcGIS For JavaScript-RenderNode后处理效果

  • 综述
  • 代码解析
  • 代码实现
    • 颜色混合
      • 完整代码
      • 结果
      • 高亮处理
      • 完整代码
      • 结果
  • 结语

综述

ArcGIS For JavaScript 4.9版本提供了很多优秀的功能,其中提供了RenderNode类,既可以支持第三方渲染引擎的植入,例如webgl、threejs等三维引擎,同时也支持对当前场景中的渲染进行后处理操作。

ArcGIS官网中描述支持可实现的几种后处理操作:混合颜色、深度渲染、高亮及法线操作等后处理。

在这里插入图片描述
今天这里会简单描述下混合颜色和高亮的处理。

代码解析

const LuminanceRenderNode = RenderNode.createSubclass({consumes: { required: ["composite-color"] }produces: ["composite-color"]render(inputs) {// custom render code}
});

要实现后处理功能,需要通过RenderNode.createSubclass去创建渲染对象。其中主要包括了:

  • consumes: 声明渲染需要引擎的哪些输入。
  • produces: 定义呈现函数产生的输出。

例如,要请求composite-color和法线,函数consume()被指定如下:consume: {required: [“composite-color”, “normals”], optional: [“highlights”]}。

输出总是作为渲染函数的输入之一给出。例如,后处理渲染函数可以声明生成复合色输出: produces: “composite-color”。

代码实现

颜色混合

颜色混合需要做两点改动:

  • 初始化参数设置
	  this.consumes = { required: ["composite-color"] };this.produces = "composite-color";
  • shader代码修改,主要是对fragColor颜色值的修改。
            const vshader = `#version 300 esin vec2 position;out vec2 uv;void main() {gl_Position = vec4(position, 0.0, 1.0);uv = position * 0.5 + vec2(0.5);}`;// The fragment shader program applying a greyscsale conversionconst fshader = `#version 300 esprecision highp float;out lowp vec4 fragColor;in vec2 uv;uniform sampler2D colorTex;void main() {vec4 color = texture(colorTex, uv);fragColor = vec4(vec3(dot(color.rgb, vec3(0.2126, 0.7152, 0.0722))), color.a);}`;

完整代码

<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" /><title>Custom RenderNode - Color modification | Sample | ArcGIS Maps SDK for JavaScript 4.30</title><link rel="stylesheet" href="https://js.arcgis.com/4.30/esri/themes/light/main.css" /><script src="https://js.arcgis.com/4.30/"></script><script type="module" src="https://js.arcgis.com/calcite-components/2.8.5/calcite.esm.js"></script><link rel="stylesheet" type="text/css" href="https://js.arcgis.com/calcite-components/2.8.5/calcite.css" /><style>html,body,#viewDiv {padding: 0;margin: 0;height: 100%;width: 100%;}</style><script>require(["esri/Map", "esri/views/SceneView", "esri/views/3d/webgl/RenderNode"], function (Map,SceneView,RenderNode) {const view = new SceneView({container: "viewDiv",map: new Map({ basemap: "satellite" })});// Create and compile WebGL shader objectsfunction createShader(gl, src, type) {const shader = gl.createShader(type);gl.shaderSource(shader, src);gl.compileShader(shader);return shader;}// Create and link WebGL program objectfunction createProgram(gl, vsSource, fsSource) {const program = gl.createProgram();if (!program) {console.error("Failed to create program");}const vertexShader = createShader(gl, vsSource, gl.VERTEX_SHADER);const fragmentShader = createShader(gl, fsSource, gl.FRAGMENT_SHADER);gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);const success = gl.getProgramParameter(program, gl.LINK_STATUS);if (!success) {// covenience console output to help debugging shader codeconsole.error(`Failed to link program:error ${gl.getError()},info log: ${gl.getProgramInfoLog(program)},vertex: ${gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)},fragment: ${gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)}vertex info log: ${gl.getShaderInfoLog(vertexShader)},fragment info log: ${gl.getShaderInfoLog(fragmentShader)}`);}return program;}// Derive a new subclass from RenderNode called LuminanceRenderNodeconst LuminanceRenderNode = RenderNode.createSubclass({constructor: function () {// consumes and produces define the location of the the render node in the render pipelinethis.consumes = { required: ["composite-color"] };this.produces = "composite-color";},// Ensure resources are cleaned up when render node is removeddestroy() {if (this.program) {this.gl?.deleteProgram(this.program);}if (this.positionBuffer) {this.gl?.deleteBuffer(this.positionBuffer);}if (this.vao) {this.gl?.deleteVertexArray(this.vao);}},properties: {// Define getter and setter for class member enabledenabled: {get: function () {return this.produces != null;},set: function (value) {// Setting produces to null disables the render nodethis.produces = value ? "composite-color" : null;this.requestRender();}}},render(inputs) {// The field input contains all available framebuffer objects// We need color texture from the composite render targetconst input = inputs.find(({ name }) => name === "composite-color");const color = input.getTexture();// Acquire the composite framebuffer object, and bind framebuffer as current targetconst output = this.acquireOutputFramebuffer();const gl = this.gl;// Clear newly acquired framebuffergl.clearColor(0, 0, 0, 1);gl.colorMask(true, true, true, true);gl.clear(gl.COLOR_BUFFER_BIT);// Prepare custom shaders and geometry for screenspace renderingthis.ensureShader(this.gl);this.ensureScreenSpacePass(gl);// Bind custom programgl.useProgram(this.program);// Use composite-color render target to be modified in the shadergl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D, color.glName);gl.uniform1i(this.textureUniformLocation, 0);// Issue the render call for a screen space render passgl.bindVertexArray(this.vao);gl.drawArrays(gl.TRIANGLES, 0, 3);// use depth from input on output framebufferoutput.attachDepth(input.getAttachment(gl.DEPTH_STENCIL_ATTACHMENT));return output;},program: null,textureUniformLocation: null,positionLocation: null,vao: null,positionBuffer: null,// Setup screen space filling triangleensureScreenSpacePass(gl) {if (this.vao) {return;}this.vao = gl.createVertexArray();gl.bindVertexArray(this.vao);this.positionBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);const vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);gl.vertexAttribPointer(this.positionLocation, 2, gl.FLOAT, false, 0, 0);gl.enableVertexAttribArray(this.positionLocation);gl.bindVertexArray(null);},// Setup custom shader programsensureShader(gl) {if (this.program != null) {return;}// The vertex shader program// Sets position from 0..1 for fragment shader// Forwards texture coordinates to fragment shaderconst vshader = `#version 300 esin vec2 position;out vec2 uv;void main() {gl_Position = vec4(position, 0.0, 1.0);uv = position * 0.5 + vec2(0.5);}`;// The fragment shader program applying a greyscsale conversionconst fshader = `#version 300 esprecision highp float;out lowp vec4 fragColor;in vec2 uv;uniform sampler2D colorTex;void main() {vec4 color = texture(colorTex, uv);fragColor = vec4(vec3(dot(color.rgb, vec3(0.2126, 0.7152, 0.0722))), color.a);}`;this.program = createProgram(gl, vshader, fshader);this.textureUniformLocation = gl.getUniformLocation(this.program, "colorTex");this.positionLocation = gl.getAttribLocation(this.program, "position");}});// Initializes the new custom render node and connects to SceneViewconst luminanceRenderNode = new LuminanceRenderNode({ view });// Toggle button to enable/disable the custom render nodeconst renderNodeToggle = document.getElementById("renderNodeToggle");renderNodeToggle.addEventListener("calciteSwitchChange", () => {luminanceRenderNode.enabled = !luminanceRenderNode.enabled;});view.ui.add("renderNodeUI", "top-right");});</script></head><body><calcite-block open heading="Toggle Render Node" id="renderNodeUI"><calcite-label layout="inline">Color<calcite-switch id="renderNodeToggle" checked> </calcite-switch>Grayscale</calcite-label></calcite-block><div id="viewDiv"></div></body>
</html>

结果

在这里插入图片描述

高亮处理

高亮是设置其实和颜色混合差不多,只是需要在声明consumes的时候,设置optional: [“highlights”] 。

this.consumes = { required: ["composite-color"], optional: ["highlights"] };

完整代码

<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" /><title>Custom RenderNode - Color modification | Sample | ArcGIS Maps SDK for JavaScript 4.30</title><link rel="stylesheet" href="https://js.arcgis.com/4.30/esri/themes/light/main.css" /><script src="https://js.arcgis.com/4.30/"></script><script type="module" src="https://js.arcgis.com/calcite-components/2.8.5/calcite.esm.js"></script><link rel="stylesheet" type="text/css" href="https://js.arcgis.com/calcite-components/2.8.5/calcite.css" /><style>html,body,#viewDiv {padding: 0;margin: 0;height: 100%;width: 100%;}</style><script>require(["esri/Map","esri/views/SceneView","esri/views/3d/webgl/RenderNode","esri/layers/SceneLayer"], function (Map,SceneView,RenderNode,SceneLayer) {const layer = new SceneLayer({url:'https://tiles.arcgis.com/tiles/V6ZHFr6zdgNZuVG0/arcgis/rest/services/campus_buildings/SceneServer'// url: "https://tiles.arcgis.com/tiles/z2tnIkrLQ2BRzr6P/arcgis/rest/services/SanFrancisco_Bldgs/SceneServer",// outFields:["NAME",""]});const view = new SceneView({container: "viewDiv",map: new Map({ basemap: "satellite", // ground: "world-elevation" }),highlightOptions: {haloColor: [255, 38, 150],color: [255, 255, 255],fillOpacity: 0.3}});view.map.add(layer);view.popupEnabled = false;let layerView = null;let highlight = null;view.when(function () {view.extent = layer.fullExtent;view.whenLayerView(layer).then((_layerView) => {layerView = _layerView;})})view.on('click', function (event) {view.hitTest(event).then(function (response) {let result = response.results[0];if(result == undefined){if(highlight){highlight.remove();highlight = null;}return;}// let objectId = result.graphic.attributes.OBJECTID;let objectId = result.graphic.attributes.OID;if (highlight) {highlight.remove();highlight = null;}// highlight the feature with the returned objectIdhighlight = layerView.highlight([objectId]);})})// Create and compile WebGL shader objectsfunction createShader(gl, src, type) {const shader = gl.createShader(type);gl.shaderSource(shader, src);gl.compileShader(shader);return shader;}// Create and link WebGL program objectfunction createProgram(gl, vsSource, fsSource) {const program = gl.createProgram();if (!program) {console.error("Failed to create program");}const vertexShader = createShader(gl, vsSource, gl.VERTEX_SHADER);const fragmentShader = createShader(gl, fsSource, gl.FRAGMENT_SHADER);gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);const success = gl.getProgramParameter(program, gl.LINK_STATUS);if (!success) {// covenience console output to help debugging shader codeconsole.error(`Failed to link program:error ${gl.getError()},info log: ${gl.getProgramInfoLog(program)},vertex: ${gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)},fragment: ${gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)}vertex info log: ${gl.getShaderInfoLog(vertexShader)},fragment info log: ${gl.getShaderInfoLog(fragmentShader)}`);}return program;}// Derive a new subclass from RenderNode called LuminanceRenderNodeconst LuminanceRenderNode = RenderNode.createSubclass({constructor: function () {// consumes and produces define the location of the the render node in the render pipelinethis.consumes = { required: ["composite-color"], optional: ["highlights"] };this.produces = "composite-color";},// Ensure resources are cleaned up when render node is removeddestroy() {if (this.program) {this.gl?.deleteProgram(this.program);}if (this.positionBuffer) {this.gl?.deleteBuffer(this.positionBuffer);}if (this.vao) {this.gl?.deleteVertexArray(this.vao);}},properties: {// Define getter and setter for class member enabledenabled: {get: function () {return this.produces != null;},set: function (value) {// Setting produces to null disables the render nodethis.produces = value ? "composite-color" : null;this.requestRender();}}},render(inputs) {// The field input contains all available framebuffer objects// We need color texture from the composite render targetconst input = inputs.find(({ name }) =>name === "composite-color");const input1 = inputs.find(({ name }) =>name === "highlights");if (input1 == undefined) {return;}// const color = input1.getTexture();// Acquire the composite framebuffer object, and bind framebuffer as current targetconst output = this.acquireOutputFramebuffer();const gl = this.gl;// Clear newly acquired framebuffergl.clearColor(0, 0, 0, 1);gl.colorMask(true, true, true, true);gl.clear(gl.COLOR_BUFFER_BIT);// Prepare custom shaders and geometry for screenspace renderingthis.ensureShader(this.gl);this.ensureScreenSpacePass(gl);// Bind custom programgl.useProgram(this.program);gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D, input?.getTexture().glName);gl.uniform1i(this.textureUniformLocation, 0);// Use composite-color render target to be modified in the shadergl.activeTexture(gl.TEXTURE1);gl.bindTexture(gl.TEXTURE_2D, input1?.getTexture().glName);gl.uniform1i(this.textureUniformLocation, 1);// Issue the render call for a screen space render passgl.bindVertexArray(this.vao);gl.drawArrays(gl.TRIANGLES, 0, 3);// use depth from input on output framebufferoutput.attachDepth(input.getAttachment(gl.DEPTH_STENCIL_ATTACHMENT));return output;},program: null,textureUniformLocation: null,positionLocation: null,vao: null,positionBuffer: null,// Setup screen space filling triangleensureScreenSpacePass(gl) {if (this.vao) {return;}this.vao = gl.createVertexArray();gl.bindVertexArray(this.vao);this.positionBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);const vertices = new Float32Array([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]);gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);gl.vertexAttribPointer(this.positionLocation, 2, gl.FLOAT, false, 0, 0);gl.enableVertexAttribArray(this.positionLocation);gl.bindVertexArray(null);},// Setup custom shader programsensureShader(gl) {if (this.program != null) {return;}// The vertex shader program// Sets position from 0..1 for fragment shader// Forwards texture coordinates to fragment shaderconst vshader = `#version 300 esin vec2 position;out vec2 uv;void main() {gl_Position = vec4(position, 0.0, 1.0);uv = position * 0.5 + vec2(0.5);}`;// The fragment shader program applying a greyscsale conversionconst fshader = `#version 300 esprecision highp float;out lowp vec4 fragColor;in vec2 uv;uniform sampler2D colorTex;void main() {vec4 color = texture(colorTex, uv);fragColor = vec4(color);// fragColor = vec4(vec3(dot(color.rgb, vec3(0.2126, 0.7152, 0.0722))), color.a);}`;this.program = createProgram(gl, vshader, fshader);this.textureUniformLocation = gl.getUniformLocation(this.program, "colorTex");this.positionLocation = gl.getAttribLocation(this.program, "position");}});// Initializes the new custom render node and connects to SceneViewconst luminanceRenderNode = new LuminanceRenderNode({ view });// Toggle button to enable/disable the custom render nodeconst renderNodeToggle = document.getElementById("renderNodeToggle");renderNodeToggle.addEventListener("calciteSwitchChange", () => {luminanceRenderNode.enabled = !luminanceRenderNode.enabled;});view.ui.add("renderNodeUI", "top-right");});</script>
</head><body><calcite-block open heading="Toggle Render Node" id="renderNodeUI"><calcite-label layout="inline">Color<calcite-switch id="renderNodeToggle" checked> </calcite-switch>Grayscale</calcite-label></calcite-block><div id="viewDiv"></div>
</body></html>

结果

在这里插入图片描述

结语

对于ArcGIS来说,后处理为Web开发提供了更多的可能性。但是这里对于opengl和shader的要求会比较高,所以需要更多的技术储备,才能更好的去实现后处理的开发。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • [012-1].第12节:Mysql的配置文件的使用
  • ubuntu安装workon
  • MyBatis缓存
  • DataKit之OpenGauss数据迁移工具
  • 大数据技术基础编程、实验和案例----大数据课程综合实验案例
  • SpringBoot如何实现简单的跨域配置
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • 程序员修炼之路
  • vue3 动态加载组件
  • web文件上传与下载
  • 【附安装包】CentOS7(Linux)详细安装教程(手把手图文详解版)
  • Selenium 无法定位元素的几种解决方案
  • masscan 端口扫描——(Golang 简单使用总结)
  • playbooks 分布式部署 LNMP
  • 创新食堂管理:采购系统源码与供应链APP开发详解
  • ES6--对象的扩展
  • Mocha测试初探
  • Python进阶细节
  • QQ浏览器x5内核的兼容性问题
  • React as a UI Runtime(五、列表)
  • React16时代,该用什么姿势写 React ?
  • Yeoman_Bower_Grunt
  • yii2权限控制rbac之rule详细讲解
  • 第十八天-企业应用架构模式-基本模式
  • 聊聊sentinel的DegradeSlot
  • 我是如何设计 Upload 上传组件的
  • 自动记录MySQL慢查询快照脚本
  • 2017年360最后一道编程题
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​第20课 在Android Native开发中加入新的C++类
  • # Redis 入门到精通(八)-- 服务器配置-redis.conf配置与高级数据类型
  • #FPGA(基础知识)
  • #HarmonyOS:基础语法
  • $nextTick的使用场景介绍
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (145)光线追踪距离场柔和阴影
  • (70min)字节暑假实习二面(已挂)
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (轉貼) 2008 Altera 亞洲創新大賽 台灣學生成果傲視全球 [照片花絮] (SOC) (News)
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET Core中Emit的使用
  • .NET MVC之AOP
  • .NET Standard 的管理策略
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [.net]官方水晶报表的使用以演示下载
  • []使用 Tortoise SVN 创建 Externals 外部引用目录
  • [acwing周赛复盘] 第 69 场周赛20220917
  • [Angular] 笔记 7:模块
  • [Django 0-1] Core.Checks 模块
  • [ffmpeg] 定制滤波器
  • [Java算法分析与设计]--线性结构与顺序表(List)的实现应用
  • [LeetCode] Verify Preorder Sequence in Binary Search Tree 验证二叉搜索树的先序序列