卖产品的网站怎么做,提供网站建设的功能,微平台是什么,如何查看网站是否被kArcGIS JSAPI 高级教程 - ArcGIS Maps SDK for JavaScript - 原生代码实现动态扩散效果 核心代码完整代码#xff1a;在线示例 ArcGIS Maps SDK for JavaScript 从 4.29 开始增加 RenderNode 类#xff0c;可以添加数据以及操作 FBO#xff08;ManagedFBO#xff09;#… ArcGIS JSAPI 高级教程 - ArcGIS Maps SDK for JavaScript - 原生代码实现动态扩散效果 核心代码完整代码在线示例 ArcGIS Maps SDK for JavaScript 从 4.29 开始增加 RenderNode 类可以添加数据以及操作 FBOManagedFBO
通过操作 FBO可以通过后处理实现很多效果官方提供了几个示例感兴趣可以看看。
本文介绍一下通过 FBO实现动态扩散效果效果。
本文包括核心代码、完整代码以及在线示例。 核心代码
介绍一下原理首先通过深度值和 uv获取世界坐标定义中心点
将世界坐标投影到中心点的平面上并根据点到平面的距离与指定半径的关系决定是否应用混合效果
混合因子依据距离与半径的差值计算实现平滑过渡实现扩散效果。
并且控制混合效果的半径由 u_radius 变量决定混合颜色由 test_color 变量定义。
#version 300 esprecision mediump float;
out mediump vec4 fragColor;in vec2 uv;// 页面颜色纹理
uniform sampler2D colorTex;
// 深度纹理
uniform sampler2D depthTex;// 相机视图矩阵
uniform mat4 u_viewMatrix;
// 相机投影矩阵
uniform mat4 u_projectionMatrix;
// 相机逆投影矩阵
uniform mat4 u_inverseProjectionMatrix;// 相机远近截面
uniform vec2 nearFar;// 动态颜色
uniform vec4 test_color;
// 扫描半径
uniform float u_radius;// 定义光线和观察者的世界位置
uniform vec3[2] u_lightWorldPosition;// 线性化深度
float linearizeDepth(float depth) {float depthNdc depth * 2.0 - 1.0;return (2.0 * nearFar[0] * nearFar[1]) / (depthNdc * (nearFar[1] - nearFar[0]) - (nearFar[1] nearFar[0]));
}// 获取深度值
float linearDepth(vec2 uv) {ivec2 iuv ivec2(uv * vec2(textureSize(depthTex, 0)));return texelFetch(depthTex, iuv, 0).r;
}// 深度值获取坐标
vec4 getPositionByDepth(vec2 uv) {// 获取深度值float depth linearDepth(uv);// 将深度值转换为视图空间中的Z值float viewZ linearizeDepth(depth);// 计算裁剪空间中的W值float clipW u_projectionMatrix[2][3] * viewZ u_projectionMatrix[3][3];// 将纹理坐标和深度值转换为NDC坐标vec3 ndcPosition vec3(uv, depth) * 2.0 - 1.0;// 将NDC坐标转换为裁剪坐标vec4 clipPosition vec4(ndcPosition, 1.0) * clipW;// 将裁剪坐标变换回视图坐标vec4 viewPos u_inverseProjectionMatrix * clipPosition;// 进行透视除法将视图坐标转换为齐次坐标viewPos / viewPos.w;// 返回视图空间中的位置return viewPos;
}// 将一个点投影到一个平面上。
vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point) {// 计算从平面原点到点的向量vec3 v01 point - planeOrigin;// 计算该向量与平面法线的点积float d dot(planeNormal, v01);// 将点投影到平面上return (point - planeNormal * d);
}void main() {// 从颜色纹理中获取当前像素的颜色vec4 color texture(colorTex, uv);// 将获取的颜色设置为片段颜色fragColor color;// 转换坐标 start // 计算第一个光源位置在视图空间中的位置vec4 center0 u_viewMatrix * vec4(u_lightWorldPosition[0], 1.0);center0 / center0.w;// 计算第二个光源位置在视图空间中的位置vec4 center500 u_viewMatrix * vec4(u_lightWorldPosition[1], 1.0);center500 / center500.w;// 计算两个光源之间的法线用于后续的投影计算vec3 circleNormal normalize(center500.xyz - center0.xyz);// 转换坐标 end // 获取当前像素在视图空间中的位置vec4 viewPos getPositionByDepth(uv);// 将视图空间中的点投影到一个平面上// 这个平面由扫描平面法线和扫描中心定义vec3 prjOnPlane pointProjectOnPlane(circleNormal,center0.xyz,viewPos.xyz);// 计算投影点到扫描中心的距离float dis length(prjOnPlane.xyz - center0.xyz);// 如果距离小于指定的半径应用混合效果if (dis u_radius) {// 计算混合因子float f 1.0 - abs(u_radius - dis) / u_radius;f pow(f, 4.0);// 根据混合因子混合当前颜色和测试颜色fragColor.rgb mix(color.rgb, test_color.rgb/255.0, f);}
} 完整代码
!DOCTYPE html
html langen
headmeta charsetutf-8/meta nameviewport contentinitial-scale1, maximum-scale1,user-scalableno/titleCustom RenderNode - 扩散扫描效果 | Sample | ArcGIS Maps SDK for JavaScript 4.29/titlescript typetext/javascript srchttps://openlayers.vip/examples/resources/dat_gui/dat.gui.js/scriptlink relstylesheet typetext/css hrefhttps://openlayers.vip/examples/resources/dat_gui/dat.gui.css/link relstylesheet hrefhttps://openlayers.vip/arcgis_api/4.30/esri/themes/light/main.css/script srchttps://openlayers.vip/arcgis_api/4.30/init.js/scriptscript srchttps://openlayers.vip/examples/resources/renderCommon.js/scriptscript typemodule srchttps://openlayers.vip/arcgis_api/calcite-components/2.8.1/calcite.esm.js/scriptlink relstylesheet typetext/css hrefhttps://openlayers.vip/arcgis_api/calcite-components/2.8.1/calcite.css /stylehtml,body,#viewDiv {padding: 0;margin: 0;height: 100%;width: 100%;}/style
/head
body
scriptrequire([esri/Map, esri/views/SceneView, esri/views/3d/webgl/RenderNode,esri/Graphic, esri/views/3d/webgl,esri/geometry/SpatialReference,esri/widgets/Home,esri/layers/IntegratedMesh3DTilesLayer,], function (Map,SceneView,RenderNode,Graphic,webgl,SpatialReference,Home,IntegratedMesh3DTilesLayer,) {// 地面点const point {type: point, // autocasts as new Point()x: 114.17494271319552,y: 22.29474643685136,z: 1,viewH: 3000,};// 空中点const pointSky {type: point, // autocasts as new Point()x: 114.17494271319552,y: 22.29474643685136,z: 500};const {map, view} initMap({Map, SceneView, Home},undefined,point);const layer new IntegratedMesh3DTilesLayer({url: http://openlayers.vip/cesium/3dtile/xianggang_1.1/tileset.json,title: Utrecht Integrated Mesh 3D Tiles});view.map.add(layer);const markerSymbol {type: simple-marker, // autocasts as new SimpleMarkerSymbol()color: [226, 119, 40],outline: {// autocasts as new SimpleLineSymbol()color: [255, 255, 255],width: 2}};// 创建点对象const pointGraphic new Graphic({geometry: point,symbol: markerSymbol});view.graphics.add(pointGraphic);// 平铺点数据const points [point.x, point.y, point.z,pointSky.x, pointSky.y, pointSky.z,];view.when(() {// 世界坐标const localOriginRender webgl.toRenderCoordinates(view,points,0,SpatialReference.WGS84,new Float32Array(points.length),0,(points.length) / 3,);// Derive a new subclass from RenderNode called LuminanceRenderNodeconst LuminanceRenderNode RenderNode.createSubclass({constructor: function (param) {param {...param}// consumes and produces define the location of the the render node in the render pipelinethis.consumes {required: [composite-color]};this.produces composite-color;// 半径this.test_float 500;// 持续时间this.test_brightness 2000;// 颜色this.test_color [0, 255, 255, 0.1];// 记录时间this._time (new Date()).getTime();this.point param.point;},// Ensure resources are cleaned up when render node is removeddestroy() {this.shaderProgram this.gl?.deleteProgram(this.shaderProgram);this.positionBuffer this.gl?.deleteBuffer(this.positionBuffer);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) {// 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;const depth input.getTexture(gl.DEPTH_STENCIL_ATTACHMENT);// Clear newly acquired framebuffergl.clearColor(0, 0, 0, 0);gl.colorMask(true, true, true, true);gl.clear(gl.COLOR_BUFFER_BIT);// 激活透明activeOpacity(gl);// Prepare custom shaders and geometry for screenspace renderingthis.ensureShader(gl);this.ensureScreenSpacePass(gl);// Bind custom programgl.useProgram(this.shaderProgram);// Use composite-color render target to be modified in the shader// 绑定颜色纹理gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D, color.glName);gl.uniform1i(this.textureUniformLocation, 0);// 绑定深度纹理gl.activeTexture(gl.TEXTURE2);gl.bindTexture(gl.TEXTURE_2D, depth.glName);gl.uniform1i(this.depthTextureUniformLocation, 2);gl.uniform2fv(this.nearFarUniformLocation, [this.camera.near, this.camera.far]);gl.uniform1f(this.scanRadiusUniformLocation,this.test_float * (((new Date()).getTime() - this._time) % this.test_brightness) / this.test_brightness);gl.uniform4fv(this.textureUniformTestColor, this.test_color);gl.uniform3fv(this.textureUniformLightWorldPosition, this.point);// 激活相机矩阵activeMatrix(this);// 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));this.requestRender();return output;},shaderProgram: null,textureUniformLocation: null,depthTextureUniformLocation: 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.shaderProgram ! null) {return;}// The vertex shader programconst vshader #version 300 esin vec2 position;out vec2 uv;void main() {uv position * 0.5 vec2(0.5);gl_Position vec4(position, 0.0, 1.0);};// The fragment shader program applying a greyscsale conversionconst fshader #version 300 esprecision mediump float;out mediump vec4 fragColor;in vec2 uv;// 页面颜色纹理uniform sampler2D colorTex;// 深度纹理uniform sampler2D depthTex;// 相机视图矩阵uniform mat4 u_viewMatrix;// 相机投影矩阵uniform mat4 u_projectionMatrix;// 相机逆投影矩阵uniform mat4 u_inverseProjectionMatrix;// 相机远近截面uniform vec2 nearFar;// 动态颜色uniform vec4 test_color;// 扫描半径uniform float u_radius;// 定义光线和观察者的世界位置uniform vec3[2] u_lightWorldPosition;// 线性化深度float linearizeDepth(float depth) {float depthNdc depth * 2.0 - 1.0;return (2.0 * nearFar[0] * nearFar[1]) / (depthNdc * (nearFar[1] - nearFar[0]) - (nearFar[1] nearFar[0]));}// 获取深度值float linearDepth(vec2 uv) {ivec2 iuv ivec2(uv * vec2(textureSize(depthTex, 0)));return texelFetch(depthTex, iuv, 0).r;}// 深度值获取坐标vec4 getPositionByDepth(vec2 uv) {// 获取深度值float depth linearDepth(uv);// 将深度值转换为视图空间中的Z值float viewZ linearizeDepth(depth);// 计算裁剪空间中的W值float clipW u_projectionMatrix[2][3] * viewZ u_projectionMatrix[3][3];// 将纹理坐标和深度值转换为NDC坐标vec3 ndcPosition vec3(uv, depth) * 2.0 - 1.0;// 将NDC坐标转换为裁剪坐标vec4 clipPosition vec4(ndcPosition, 1.0) * clipW;// 将裁剪坐标变换回视图坐标vec4 viewPos u_inverseProjectionMatrix * clipPosition;// 进行透视除法将视图坐标转换为齐次坐标viewPos / viewPos.w;// 返回视图空间中的位置return viewPos;}// 将一个点投影到一个平面上。vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point) {// 计算从平面原点到点的向量vec3 v01 point - planeOrigin;// 计算该向量与平面法线的点积float d dot(planeNormal, v01);// 将点投影到平面上return (point - planeNormal * d);}void main() {// 从颜色纹理中获取当前像素的颜色vec4 color texture(colorTex, uv);// 将获取的颜色设置为片段颜色fragColor color;// 转换坐标 start // 计算第一个光源位置在视图空间中的位置vec4 center0 u_viewMatrix * vec4(u_lightWorldPosition[0], 1.0);center0 / center0.w;// 计算第二个光源位置在视图空间中的位置vec4 center500 u_viewMatrix * vec4(u_lightWorldPosition[1], 1.0);center500 / center500.w;// 计算两个光源之间的法线用于后续的投影计算vec3 circleNormal normalize(center500.xyz - center0.xyz);// 转换坐标 end // 获取当前像素在视图空间中的位置vec4 viewPos getPositionByDepth(uv);// 将视图空间中的点投影到一个平面上// 这个平面由扫描平面法线和扫描中心定义vec3 prjOnPlane pointProjectOnPlane(circleNormal,center0.xyz,viewPos.xyz);// 计算投影点到扫描中心的距离float dis length(prjOnPlane.xyz - center0.xyz);// 如果距离小于指定的半径应用混合效果if (dis u_radius) {// 计算混合因子float f 1.0 - abs(u_radius - dis) / u_radius;f pow(f, 4.0);// 根据混合因子混合当前颜色和测试颜色fragColor.rgb mix(color.rgb, test_color.rgb/255.0, f);}};this.shaderProgram initWebgl2Shaders(gl, vshader, fshader);this.nearFarUniformLocation gl.getUniformLocation(this.shaderProgram, nearFar);this.textureUniformLocation gl.getUniformLocation(this.shaderProgram, colorTex);this.depthTextureUniformLocation gl.getUniformLocation(this.shaderProgram, depthTex);this.textureUniformTestColor gl.getUniformLocation(this.shaderProgram, test_color);this.textureUniformLightWorldPosition gl.getUniformLocation(this.shaderProgram, u_lightWorldPosition);this.scanRadiusUniformLocation gl.getUniformLocation(this.shaderProgram, u_radius);this.positionLocation gl.getAttribLocation(this.shaderProgram, position);}});// Initializes the new custom render node and connects to SceneViewconst luminanceRenderNode new LuminanceRenderNode({view, point:localOriginRender});var gui new dat.GUI();gui.add(luminanceRenderNode, test_float, 0, 1000).name(扫描半径);gui.add(luminanceRenderNode, test_brightness, 0, 4000).name(持续时间);var colorController gui.addColor(luminanceRenderNode, test_color).name(颜色);// Toggle button to enable/disable the custom render nodeconst renderNodeToggle document.getElementById(renderNodeToggle);renderNodeToggle.addEventListener(calciteSwitchChange, () {luminanceRenderNode.enabled !luminanceRenderNode.enabled;});});});
/script
calcite-block open headingToggle Render Node idrenderNodeUIcalcite-label layoutinlineColorcalcite-switch idrenderNodeToggle checked/calcite-switchGrayscale/calcite-label
/calcite-block
div idviewDiv/div
/body
/html 在线示例
ArcGIS Maps SDK for JavaScript 在线示例原生代码实现动态扩散效果