赞
踩
arcgis js api的externalRenderers可以直接使用webgl的shader,这样就使得你可以按照自己想法做各种效果。但前提是:熟悉webgl。
先看一下externalRenderers的介绍:
externalRenderers | API Reference | ArcGIS API for JavaScript 4.24 | ArcGIS DevelopersDocumentation site for ArcGIS API for JavaScript on ArcGIS Developers.https://developers.arcgis.com/javascript/latest/api-reference/esri-views-3d-externalRenderers.html这里的例子不是很清晰,以下是个简单的例子(在arcgis三维场景上画一个三角形):
- <template>
- <div id="main-view"></div>
- </template>
-
- <script>
- import SceneView from '@arcgis/core/views/SceneView'
- import Map from '@arcgis/core/Map'
- import esriConfig from "@arcgis/core/config";
- import * as externalRenderers from "@arcgis/core/views/3d/externalRenderers";
- import {initWebgl2Shaders} from '../utils/initWebgl2Shaders'
- import Matrix4 from '@math.gl/core/dist/es5/classes/matrix4'
- let viewer = null
- let map = null
- export default {
- mounted() {
- this.initConfig()
- this.init()
- this.initRender()
- },
- methods:{
- // 初始设置
- initConfig(){
- esriConfig.assetsPath = "./assets";
- },
- init(){
- map = new Map({
- basemap: 'hybrid',
- ground: "world-elevation"
- })
- viewer = new SceneView({
- map,
- container: 'main-view'
- })
- viewer.ui.empty('bottom-trailing')
- viewer.ui.empty('manual')
- },
- initRender(){
- let myExternalRenderer = {
- vbo: null,
- shaderProgram: null,
- a_Position: null,
- setup: function(context) {
- let gl = context.gl;
-
- // 初始化shader
- var VSHADER=`#version 300 es
- layout (location=0) in vec4 a_Position;
- void main(){
- gl_Position=a_Position;
- }
- `;
- var FSHADER=`#version 300 es
- precision mediump float;
- out vec4 fragColor;
- void main(){
- fragColor=vec4(1.0,0.0,0.0,1.0);
- }
- `;
- this.shaderProgram=initWebgl2Shaders(gl, VSHADER, FSHADER)
- if(!this.shaderProgram){
- console.assert("初始化shader错误")
- }
- this.a_Position= gl.getAttribLocation(this.shaderProgram, 'a_Position')
- gl.enableVertexAttribArray(this.a_Position) //连接变量a_Position和缓冲区对象
-
-
- // 初始化bufferdata
- this.vbo = context.gl.createBuffer();
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- let positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
- context.gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
- },
- render: function(context) {
- let gl = context.gl
-
- gl.enable(gl.DEPTH_TEST); // 开启深度检测
- // gl.disable(gl.CULL_FACE);
- // gl.disable(gl.BLEND);
-
- gl.useProgram(this.shaderProgram);
-
- // 创建数据
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- gl.vertexAttribPointer(this.a_Position,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_Posiotion
-
- context.gl.drawArrays(gl.TRIANGLES, 0, 3);
-
- console.log(1) // 每帧检测
- }
- }
- externalRenderers.add(viewer, myExternalRenderer);
- },
- }
- }
- </script>
-
- <style>
- #main-view{
- width: 1000px;
- height: 800px;
- }
- </style>
其中initWebgl2Shaders的方法
- function checkShaderCompilation(gl, shader) {
- var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
- // console.log("Shader compiled successfully: " + compiled);
- var compilationLog = gl.getShaderInfoLog(shader);
- // console.log("Shader compiler log: " + compilationLog);
- }
-
- export function initWebgl2Shaders(gl, vertCode, fragCode) {
- // Create a vertex shader object
- var vertShader = gl.createShader(gl.VERTEX_SHADER);
-
- // Attach vertex shader source code
- gl.shaderSource(vertShader, vertCode);
-
- // Compile the vertex shader
- gl.compileShader(vertShader);
-
- checkShaderCompilation(gl, vertShader);
-
- // Create fragment shader object
- var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
-
- // Attach fragment shader source code
- gl.shaderSource(fragShader, fragCode);
-
- // Compile the fragment shader
- gl.compileShader(fragShader);
-
- checkShaderCompilation(gl, fragShader);
-
- // Create a shader program object to store
- // the combined shader program
- var shaderProgram = gl.createProgram();
-
- // Attach a vertex shader
- gl.attachShader(shaderProgram, vertShader);
-
- // Attach a fragment shader
- gl.attachShader(shaderProgram, fragShader);
-
- // Link both the programs
- gl.linkProgram(shaderProgram);
-
- // Use the combined shader program object
- gl.useProgram(shaderProgram);
-
- return shaderProgram;
- }
最终效果:
两步:
1、在shader里添加矩阵
2、引用@math.gl/core,api见下面的链接
例子(将上面的initshader改为initshader2):
- initRender2() {
- let myExternalRenderer = {
- vbo: null,
- shaderProgram: null,
- a_Position: null,
- setup: function(context) {
- let gl = context.gl;
-
- // 初始化shader
- var VSHADER=`#version 300 es
- layout (location=0) in vec4 a_Position;
- uniform mat4 u_formMatrix;
- void main(){
- gl_Position= u_formMatrix*a_Position;
- }
- `;
- var FSHADER=`#version 300 es
- precision mediump float;
- out vec4 fragColor;
- void main(){
- fragColor=vec4(1.0,0.0,0.0,1.0);
- }
- `;
- this.shaderProgram=initWebgl2Shaders(gl, VSHADER, FSHADER)
- if(!this.shaderProgram){
- console.assert("初始化shader错误")
- }
- this.a_Position= gl.getAttribLocation(this.shaderProgram, 'a_Position')
- gl.enableVertexAttribArray(this.a_Position) //连接变量a_Position和缓冲区对象
-
-
- // 初始化bufferdata
- this.vbo = context.gl.createBuffer();
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- let positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
- context.gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
- },
- render: function(context) {
- let gl = context.gl
-
- gl.enable(gl.DEPTH_TEST); // 开启深度检测
- // gl.disable(gl.CULL_FACE);
- // gl.disable(gl.BLEND);
-
- gl.useProgram(this.shaderProgram);
-
- // 创建数据
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- gl.vertexAttribPointer(this.a_Position,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_Posiotion
-
- //旋转矩阵
- let u_formMatrix=gl.getUniformLocation(this.shaderProgram, 'u_formMatrix')
- let formMatrix=new Matrix4().translate([-1.0, -1.0, 0])
- gl.uniformMatrix4fv(u_formMatrix, false, formMatrix.elements)
-
- context.gl.drawArrays(gl.TRIANGLES, 0, 3);
-
- console.log(1) // 每帧检测
- }
- }
- externalRenderers.add(viewer, myExternalRenderer);
- },
最终效果:
提取出颜色的步骤:
1、在shader中提取出颜色
2、给颜色赋值
例子3(将例1的initshader改为initshader3):
- initRender3() {
- let myExternalRenderer = {
- vbo: null,
- shaderProgram: null,
- a_Position: null,
- a_color: null,
- colorBuffer: null,
- setup: function(context) {
- let gl = context.gl;
-
- // 初始化shader
- var VSHADER=`#version 300 es
- layout (location=0) in vec4 a_Position;
- layout (location=1) in vec4 a_color;
- out vec4 v_color;
- uniform mat4 u_formMatrix;
- void main(){
- gl_Position= u_formMatrix*a_Position;
- v_color=a_color;
- }
- `;
- var FSHADER=`#version 300 es
- precision mediump float;
- in vec4 v_color;
- out vec4 fragColor;
- void main(){
- fragColor=v_color;
- }
- `;
- this.shaderProgram=initWebgl2Shaders(gl, VSHADER, FSHADER)
- if(!this.shaderProgram){
- console.assert("初始化shader错误")
- }
- this.a_Position= gl.getAttribLocation(this.shaderProgram, 'a_Position')
- gl.enableVertexAttribArray(this.a_Position) //连接变量a_Position和缓冲区对象
- this.a_color= gl.getAttribLocation(this.shaderProgram, 'a_color')
- gl.enableVertexAttribArray(this.a_color) //连接变量a_color和缓冲区对象
-
- // 初始化顶点的bufferdata
- this.vbo = context.gl.createBuffer();
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- let positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
- context.gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
-
- // 给顶点的各个点赋予颜色
- this.colorBuffer=gl.createBuffer() //创建缓冲区对象
- gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer) //将缓冲区对象绑定到目标
- let colors=new Float32Array([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])
- gl.bufferData(gl.ARRAY_BUFFER,colors,gl.STATIC_DRAW) //向缓冲区对象写入数据
- },
- render: function(context) {
- let gl = context.gl
-
- gl.enable(gl.DEPTH_TEST); // 开启深度检测
- // gl.disable(gl.CULL_FACE);
- // gl.disable(gl.BLEND);
-
- gl.useProgram(this.shaderProgram);
-
- // 创建数据
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- gl.vertexAttribPointer(this.a_Position,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_Posiotion
- gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer) //将缓冲区对象绑定到目标
- gl.vertexAttribPointer(this.a_color,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_color
-
- //旋转矩阵
- let u_formMatrix=gl.getUniformLocation(this.shaderProgram, 'u_formMatrix')
- let formMatrix=new Matrix4().translate([-1.0, -1.0, 0])
- gl.uniformMatrix4fv(u_formMatrix, false, formMatrix.elements)
-
- context.gl.drawArrays(gl.TRIANGLES, 0, 3);
-
- console.log(1) // 每帧检测
- }
- }
- externalRenderers.add(viewer, myExternalRenderer);
- },
最终效果:
添加动态效果,通常最好的办法就是修改矩阵。
在例3的基础上,修改一下矩阵,注意动态效果需要在render里添加externalRenderers.requestRender(viewer);用来场景变化时,仍然调用该render。
例子4((将例1的initshader改为initshader4)
- initRender4() {
- let myExternalRenderer = {
- vbo: null,
- shaderProgram: null,
- a_Position: null,
- a_color: null,
- colorBuffer: null,
- i: 0,
- setup: function(context) {
- let gl = context.gl;
-
- // 初始化shader
- var VSHADER=`#version 300 es
- layout (location=0) in vec4 a_Position;
- layout (location=1) in vec4 a_color;
- out vec4 v_color;
- uniform mat4 u_formMatrix;
- void main(){
- gl_Position= u_formMatrix*a_Position;
- v_color=a_color;
- }
- `;
- var FSHADER=`#version 300 es
- precision mediump float;
- in vec4 v_color;
- out vec4 fragColor;
- void main(){
- fragColor=v_color;
- }
- `;
- this.shaderProgram=initWebgl2Shaders(gl, VSHADER, FSHADER)
- if(!this.shaderProgram){
- console.assert("初始化shader错误")
- }
- this.a_Position= gl.getAttribLocation(this.shaderProgram, 'a_Position')
- gl.enableVertexAttribArray(this.a_Position) //连接变量a_Position和缓冲区对象
- this.a_color= gl.getAttribLocation(this.shaderProgram, 'a_color')
- gl.enableVertexAttribArray(this.a_color) //连接变量a_color和缓冲区对象
-
- // 初始化顶点的bufferdata
- this.vbo = context.gl.createBuffer();
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- let positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
- context.gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
-
- // 给顶点的各个点赋予颜色
- this.colorBuffer=gl.createBuffer() //创建缓冲区对象
- gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer) //将缓冲区对象绑定到目标
- let colors=new Float32Array([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])
- gl.bufferData(gl.ARRAY_BUFFER,colors,gl.STATIC_DRAW) //向缓冲区对象写入数据
- },
- render: function(context) {
- let gl = context.gl
- this.i += 1
- gl.enable(gl.DEPTH_TEST); // 开启深度检测
- // gl.disable(gl.CULL_FACE);
- // gl.disable(gl.BLEND);
- gl.useProgram(this.shaderProgram);
-
- // 创建数据
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- gl.vertexAttribPointer(this.a_Position,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_Posiotion
- gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer) //将缓冲区对象绑定到目标
- gl.vertexAttribPointer(this.a_color,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_color
-
- //旋转矩阵
- let u_formMatrix=gl.getUniformLocation(this.shaderProgram, 'u_formMatrix')
- let formMatrix=new Matrix4()
- formMatrix.rotateY(Math.PI/180 * this.i)
- gl.uniformMatrix4fv(u_formMatrix, false, formMatrix.elements)
-
- context.gl.drawArrays(gl.TRIANGLES, 0, 3);
-
- console.log(1) // 每帧检测
- externalRenderers.requestRender(viewer);
- }
- }
- externalRenderers.add(viewer, myExternalRenderer);
- },
最终效果:
5、关联相机
根据webgl的三维矩阵方程:
gl_position=ProjectionMatrix*ViewMatrix*ModelMatrix*position
可以在render里使用相机的ProjectionMatrix和ViewMatrix。(根据地球的大小,可以将三角形长宽设置在10000000m)
- initRender5() {
- let myExternalRenderer = {
- vbo: null,
- shaderProgram: null,
- a_Position: null,
- a_color: null,
- colorBuffer: null,
- i: 0,
- setup: function(context) {
- let gl = context.gl;
-
- // 初始化shader
- var VSHADER=`#version 300 es
- layout (location=0) in vec3 a_Position;
- layout (location=1) in vec4 a_color;
- out vec4 v_color;
- uniform mat4 u_projectionMatrix;
- uniform mat4 u_viewMatrix;
- uniform mat4 u_formMatrix;
- void main(){
- gl_Position= u_projectionMatrix*u_viewMatrix*u_formMatrix*vec4(a_Position,1.0);
- v_color=a_color;
- }
- `;
- var FSHADER=`#version 300 es
- precision mediump float;
- in vec4 v_color;
- out vec4 fragColor;
- void main(){
- fragColor=v_color;
- }
- `;
- this.shaderProgram=initWebgl2Shaders(gl, VSHADER, FSHADER)
- if(!this.shaderProgram){
- console.assert("初始化shader错误")
- }
- this.a_Position= gl.getAttribLocation(this.shaderProgram, 'a_Position')
- gl.enableVertexAttribArray(this.a_Position) //连接变量a_Position和缓冲区对象
- this.a_color= gl.getAttribLocation(this.shaderProgram, 'a_color')
- gl.enableVertexAttribArray(this.a_color) //连接变量a_color和缓冲区对象
-
- // 初始化顶点的bufferdata
- this.vbo = context.gl.createBuffer();
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- let positions = new Float32Array([0, 0, 0, 10000000, 0, 0, 0, 10000000, 0]);
- context.gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
-
- // 给顶点的各个点赋予颜色
- this.colorBuffer=gl.createBuffer() //创建缓冲区对象
- gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer) //将缓冲区对象绑定到目标
- let colors=new Float32Array([1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0])
- gl.bufferData(gl.ARRAY_BUFFER,colors,gl.STATIC_DRAW) //向缓冲区对象写入数据
- },
- render: function(context) {
- let gl = context.gl
- this.i += 1
- gl.enable(gl.DEPTH_TEST); // 开启深度检测
- // gl.disable(gl.CULL_FACE);
- // gl.disable(gl.BLEND);
- gl.useProgram(this.shaderProgram);
-
- // 创建数据
- context.gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
- gl.vertexAttribPointer(this.a_Position,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_Posiotion
- gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer) //将缓冲区对象绑定到目标
- gl.vertexAttribPointer(this.a_color,3,gl.FLOAT,false,0,0) //将缓冲区对象分配给a_color
-
- // project 矩阵
- let programUniformProjectionMatrix = gl.getUniformLocation(
- this.shaderProgram,
- "u_projectionMatrix"
- );
-
- console.log(context.camera)
- gl.uniformMatrix4fv(
- programUniformProjectionMatrix,
- false,
- context.camera.projectionMatrix
- );
- // view 矩阵
- let programUniformViewMatrix = gl.getUniformLocation(
- this.shaderProgram,
- "u_viewMatrix"
- );
- gl.uniformMatrix4fv(
- programUniformViewMatrix,
- false,
- context.camera.viewMatrix
- );
- //旋转矩阵
- let u_formMatrix=gl.getUniformLocation(this.shaderProgram, 'u_formMatrix')
- let formMatrix=new Matrix4()
- formMatrix.rotateY(Math.PI/180*this.i)
- gl.uniformMatrix4fv(u_formMatrix, false, formMatrix.elements)
-
- context.gl.drawArrays(gl.TRIANGLES, 0, 3);
-
- console.log(this.i) // 每帧检测
- externalRenderers.requestRender(viewer);
- }
- }
- externalRenderers.add(viewer, myExternalRenderer);
- },
最终效果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。