WebGL异步绘制多点

异步绘制线段

1.先画一个点
在这里插入图片描述
2.一秒钟后,在左下角画一个点
在这里插入图片描述
3.两秒钟后,我再画一条线段
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas id="webgl" width="200" height="200"></canvas>
    <script>
        const webgl = document.getElementById('webgl')
        const gl = webgl.getContext('webgl')

        // 创建着色器
        const vertexShader = gl.createShader(gl.VERTEX_SHADER)
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
        // 绑定数据源
        // 声明顶点着色器 attribute 变量
        gl.shaderSource(vertexShader, `
            attribute vec4 a_Position;
            void main(){
               gl_Position = a_Position;
               gl_PointSize = 20.0;
            }
        `)
        gl.shaderSource(fragmentShader, `
            void main(){
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        `)

        // 编译着色器
        gl.compileShader(vertexShader)
        gl.compileShader(fragmentShader)
        // 创建着色器程序
        const program = gl.createProgram()
        // 绑定着色器
        gl.attachShader(program, vertexShader)
        gl.attachShader(program, fragmentShader)
        // 连接着色器
        gl.linkProgram(program)
        // 使用着色器
        gl.useProgram(program)

        // 顶点数据
        let points = [0, 0.2]
        // 创建缓冲区
        const vertexBuffer = gl.createBuffer()
        // 绑定缓冲区 
        // target 要把缓冲区放在webgl系统中的什么位置, buffer 缓冲区
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
        // 写入数据
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW)
        // 获取到顶点着色器中变量
        const a_Position = gl.getAttribLocation(program, 'a_Position')
        // 从当前绑定的缓冲区中读取顶点数据(index, size, type, normalized是否顶点数据归一, stride相邻两个顶点间的字节数, offset从缓冲区的什么位置开始存储变量)
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)
        // 开启顶点数据的批处理功能
        gl.enableVertexAttribArray(a_Position)

        gl.drawArrays(gl.POINTS, 0, 1);

        // 一秒钟后,向顶点数据中再添加的一个顶点,修改缓冲区数据,然后清理画布,绘制顶点
        setTimeout(() => {
            points.push(-0.2, -0.1)
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW)
            gl.drawArrays(gl.POINTS, 0, 2);
        }, 1000)

        // 两秒钟后,清理画布,绘制顶点,绘制线条
        setTimeout(() => {
            gl.drawArrays(gl.POINTS, 0, 2);
            gl.drawArrays(gl.LINE_STRIP, 0, 2);
        }, 2000)
    </script>
</body>

</html>

封装

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas id="webgl" width="200" height="200"></canvas>
    <script>
        const webgl = document.getElementById('webgl')
        const gl = webgl.getContext('webgl')

        // 创建着色器
        const vertexShader = gl.createShader(gl.VERTEX_SHADER)
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
        // 绑定数据源
        // 声明顶点着色器 attribute 变量
        gl.shaderSource(vertexShader, `
            attribute vec4 a_Position;
            void main(){
               gl_Position = a_Position;
               gl_PointSize = 20.0;
            }
        `)
        gl.shaderSource(fragmentShader, `
            void main(){
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        `)

        // 编译着色器
        gl.compileShader(vertexShader)
        gl.compileShader(fragmentShader)
        // 创建着色器程序
        const program = gl.createProgram()
        // 绑定着色器
        gl.attachShader(program, vertexShader)
        gl.attachShader(program, fragmentShader)
        // 连接着色器
        gl.linkProgram(program)
        // 使用着色器
        gl.useProgram(program)


        const defAttr = () => ({
            gl: null,
            vertices: [],
            geoData: [],
            size: 2,
            attrName: 'a_Position',
            count: 0,
            types: ['POINTS'],
        })
        class Poly {
            constructor(attr) {
                Object.assign(this, defAttr(), attr)
                this.init()
            }
            init() {
                const { attrName, size, gl } = this
                if (!gl) { return }
                const vertexBuffer = gl.createBuffer()
                gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
                this.updateBuffer()
                const a_Position = gl.getAttribLocation(program, attrName)
                gl.vertexAttribPointer(a_Position, size, gl.FLOAT, false, 0, 0)
                gl.enableVertexAttribArray(a_Position)
            }
            addVertice(...params) {
                this.vertices.push(...params)
                this.updateBuffer()
            }
            popVertice() {
                const { vertices, size } = this
                const len = vertices.length
                vertices.splice(len - size, len)
                this.updateCount()
            }
            setVertice(ind, ...params) {
                const { vertices, size } = this
                const i = ind * size
                params.forEach((param, paramInd) => {
                    vertices[i + paramInd] = param
                })
            }
            updateBuffer() {
                const { gl, vertices } = this
                this.updateCount()
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)
            }
            updateCount() {
                this.count = this.vertices.length / this.size
            }
            updateVertices(params) {
                const { geoData } = this
                const vertices = []
                geoData.forEach(data => {
                    params.forEach(key => {
                        vertices.push(data[key])
                    })
                })
                this.vertices = vertices
            }
            draw(types = this.types) {
                const { gl, count } = this
                for (let type of types) {
                    gl.drawArrays(gl[type], 0, count);
                }
            }
        }

        const poly = new Poly({
            gl,
            vertices: [0, 0.2]
        })
        poly.draw(['POINTS'])

        setTimeout(() => {
            poly.addVertice(-0.2, -0.1)
            poly.draw(['POINTS'])
        }, 1000)

        setTimeout(() => {
            poly.draw(['POINTS', 'LINE_STRIP'])
        }, 2000)
    </script>
</body>

</html>

根据鼠标点击绘制点和线

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas id="webgl"></canvas>
    <script>
        const webgl = document.getElementById('webgl')
        webgl.width = window.innerWidth
        webgl.height = window.innerHeight
        const gl = webgl.getContext('webgl')

        // 创建着色器
        const vertexShader = gl.createShader(gl.VERTEX_SHADER)
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
        // 绑定数据源
        // 声明顶点着色器 attribute 变量
        gl.shaderSource(vertexShader, `
            attribute vec4 a_Position;
            void main(){
               gl_Position = a_Position;
               gl_PointSize = 20.0;
            }
        `)
        gl.shaderSource(fragmentShader, `
            void main(){
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        `)

        // 编译着色器
        gl.compileShader(vertexShader)
        gl.compileShader(fragmentShader)
        // 创建着色器程序
        const program = gl.createProgram()
        // 绑定着色器
        gl.attachShader(program, vertexShader)
        gl.attachShader(program, fragmentShader)
        // 连接着色器
        gl.linkProgram(program)
        // 使用着色器
        gl.useProgram(program)


        const defAttr = () => ({
            gl: null,
            vertices: [],
            geoData: [],
            size: 2,
            attrName: 'a_Position',
            count: 0,
            types: ['POINTS'],
        })
        class Poly {
            constructor(attr) {
                Object.assign(this, defAttr(), attr)
                this.init()
            }
            init() {
                const { attrName, size, gl } = this
                if (!gl) { return }
                const vertexBuffer = gl.createBuffer()
                gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
                this.updateBuffer()
                const a_Position = gl.getAttribLocation(program, attrName)
                gl.vertexAttribPointer(a_Position, size, gl.FLOAT, false, 0, 0)
                gl.enableVertexAttribArray(a_Position)
            }
            addVertice(...params) {
                this.vertices.push(...params)
                this.updateBuffer()
            }
            popVertice() {
                const { vertices, size } = this
                const len = vertices.length
                vertices.splice(len - size, len)
                this.updateCount()
            }
            setVertice(ind, ...params) {
                const { vertices, size } = this
                const i = ind * size
                params.forEach((param, paramInd) => {
                    vertices[i + paramInd] = param
                })
            }
            updateBuffer() {
                const { gl, vertices } = this
                this.updateCount()
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)
            }
            updateCount() {
                this.count = this.vertices.length / this.size
            }
            updateVertices(params) {
                const { geoData } = this
                const vertices = []
                geoData.forEach(data => {
                    params.forEach(key => {
                        vertices.push(data[key])
                    })
                })
                this.vertices = vertices
            }
            draw(types = this.types) {
                const { gl, count } = this
                for (let type of types) {
                    gl.drawArrays(gl[type], 0, count);
                }
            }
        }

        const poly = new Poly({
            gl,
            types: ['POINTS', 'LINE_STRIP']
        })

        webgl.addEventListener('click', (e) => {
            // 获取鼠标距离视口尺寸的距离
            const { clientX, clientY } = e
            // 获取cavans坐标宽高,距离视口尺寸的距离
            const { left, top, width, height } = webgl.getBoundingClientRect()
            // 鼠标在canvas中的位置
            const [cssX, cssY] = [clientX - left, clientY - top]

            // canvas坐标转webgl坐标
            // canvas画布的中心位置
            const [halfWidth, halfHeight] = [width / 2, height / 2]
            // 鼠标基于webgl坐标的中心位置
            const [xBaseCenter, yBaseCenter] = [cssX - halfWidth, cssY - halfHeight]
            // 解决y方向的差异
            const yBaseCenterTop = -yBaseCenter
            // 解决坐标基底的差异
            const [x, y] = [xBaseCenter / halfWidth, yBaseCenterTop / halfHeight]
            
            poly.addVertice(x, y)
            poly.draw()
        })

    </script>
</body>

</html>

根据鼠标绘制多条点和线

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas id="webgl"></canvas>
    <script>
        const webgl = document.getElementById('webgl')
        webgl.width = window.innerWidth
        webgl.height = window.innerHeight
        const gl = webgl.getContext('webgl')

        // 创建着色器
        const vertexShader = gl.createShader(gl.VERTEX_SHADER)
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
        // 绑定数据源
        // 声明顶点着色器 attribute 变量
        gl.shaderSource(vertexShader, `
            attribute vec4 a_Position;
            void main(){
               gl_Position = a_Position;
               gl_PointSize = 20.0;
            }
        `)
        gl.shaderSource(fragmentShader, `
            void main(){
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        `)

        // 编译着色器
        gl.compileShader(vertexShader)
        gl.compileShader(fragmentShader)
        // 创建着色器程序
        const program = gl.createProgram()
        // 绑定着色器
        gl.attachShader(program, vertexShader)
        gl.attachShader(program, fragmentShader)
        // 连接着色器
        gl.linkProgram(program)
        // 使用着色器
        gl.useProgram(program)


        const defAttr = () => ({
            gl: null,
            vertices: [],
            geoData: [],
            size: 2,
            attrName: 'a_Position',
            count: 0,
            types: ['POINTS'],
        })
        class Poly {
            constructor(attr) {
                Object.assign(this, defAttr(), attr)
                this.init()
            }
            init() {
                const { attrName, size, gl } = this
                if (!gl) { return }
                const vertexBuffer = gl.createBuffer()
                gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
                this.updateBuffer()
                const a_Position = gl.getAttribLocation(program, attrName)
                gl.vertexAttribPointer(a_Position, size, gl.FLOAT, false, 0, 0)
                gl.enableVertexAttribArray(a_Position)
            }
            addVertice(...params) {
                this.vertices.push(...params)
                this.updateBuffer()
            }
            popVertice() {
                const { vertices, size } = this
                const len = vertices.length
                vertices.splice(len - size, len)
                this.updateCount()
            }
            setVertice(ind, ...params) {
                const { vertices, size } = this
                const i = ind * size
                params.forEach((param, paramInd) => {
                    vertices[i + paramInd] = param
                })
            }
            updateBuffer() {
                const { gl, vertices } = this
                this.updateCount()
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)
            }
            updateCount() {
                this.count = this.vertices.length / this.size
            }
            updateVertices(params) {
                const { geoData } = this
                const vertices = []
                geoData.forEach(data => {
                    params.forEach(key => {
                        vertices.push(data[key])
                    })
                })
                this.vertices = vertices
            }
            draw(types = this.types) {
                const { gl, count } = this
                for (let type of types) {
                    gl.drawArrays(gl[type], 0, count);
                }
            }
        }

        // 容器来承载(多线)绘制
        class Sky {
            constructor(gl) {
                this.gl = gl
                this.children = []
            }
            add(obj) {
                obj.gl = this.gl
                this.children.push(obj)
            }
            updateVertices(params) {
                this.children.forEach(ele => {
                    ele.updateVertices(params)
                })
            }
            draw() {
                this.children.forEach(ele => {
                    ele.init()
                    ele.draw()
                })
            }
        }

        const sky = new Sky(gl)
        // 当前正在绘制的多边形
        let poly = null

        //删除最后一个顶点
        function popVertice() {
            poly.popVertice()
            poly = null
        }

        // 取消右击提示
        webgl.oncontextmenu = function () {
            return false
        }

        // 鼠标点击事件
        webgl.addEventListener("mousedown", (event) => {
            if (event.button === 2) {
                // 右击删除正在绘制的点
                popVertice()
            } else {
                // 获取鼠标距离视口尺寸的距离
                const { clientX, clientY } = event
                // 获取cavans坐标宽高,距离视口尺寸的距离
                const { left, top, width, height } = webgl.getBoundingClientRect()
                // 鼠标在canvas中的位置
                const [cssX, cssY] = [clientX - left, clientY - top]
   
                // canvas坐标转webgl坐标
                // canvas画布的中心位置
                const [halfWidth, halfHeight] = [width / 2, height / 2]
                // 鼠标基于webgl坐标的中心位置
                const [xBaseCenter, yBaseCenter] = [cssX - halfWidth, cssY - halfHeight]
                // 解决y方向的差异
                const yBaseCenterTop = -yBaseCenter
                // 解决坐标基底的差异
                const [x, y] = [xBaseCenter / halfWidth, yBaseCenterTop / halfHeight]
                if (poly) {
                    poly.addVertice(x, y)
                } else {
                    crtPoly(x, y)
                }
            }
            render()
        });
        //鼠标移动
        webgl.addEventListener("mousemove", (event) => {
            if (poly) {
                // 获取鼠标距离视口尺寸的距离
                const { clientX, clientY } = event
                // 获取cavans坐标宽高,距离视口尺寸的距离
                const { left, top, width, height } = webgl.getBoundingClientRect()
                // 鼠标在canvas中的位置
                const [cssX, cssY] = [clientX - left, clientY - top]

                // canvas坐标转webgl坐标
                // canvas画布的中心位置
                const [halfWidth, halfHeight] = [width / 2, height / 2]
                // 鼠标基于webgl坐标的中心位置
                const [xBaseCenter, yBaseCenter] = [cssX - halfWidth, cssY - halfHeight]
                // 解决y方向的差异
                const yBaseCenterTop = -yBaseCenter
                // 解决坐标基底的差异
                const [x, y] = [xBaseCenter / halfWidth, yBaseCenterTop / halfHeight]
                poly.setVertice(poly.count - 1, x, y)
                render()
            }
        });

        //创建多边形
        function crtPoly(x, y) {
            poly = new Poly({
                vertices: [x, y, x, y],
                types: ['POINTS', 'LINE_STRIP']
            })
            sky.add(poly)
        }
        // 渲染方法
        function render() {
            sky.draw()
        }

    </script>
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/535670.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[2024年4月最新]Python安装教程

一、Python下载 1、进入Python官网 官网地址&#xff1a;https://www.python.org 2、点击【Downloads】展开后点击【Windows】跳转到下载python版本页面&#xff0c;选择"Stable Releases"稳定版本&#xff0c;我下载的是Python 3.10.10版本&#xff0c;所以找到【…

IDEA中无法保存设置 Cannot Save Settings

确定原因: 在IDEA中父工程不应该存在有子工程的相关东西 首先,这是我的DCYJ项目(观察右侧的Content Root) 其次,这是我的EAPOFode项目(观察右侧的Content Root爆红处) 最后我将DCYJ项目右侧的Content Root全部删掉

共享单车到底是什么通信原理

我们经常骑的共享单车到底是什么通信原理&#xff0c;有人了解过吗&#xff1f; 一、智能车锁 共享单车最核心的硬件是智能车锁&#xff0c;主要用于实现控制和定位功能。 车锁内集成了嵌入式芯片&#xff08;通信模块&#xff09;&#xff0c;GPS模块和物联网SIM卡。 智能锁制…

DP例题详解(二)最短编辑距离和编辑距离

902. 最短编辑距离 - AcWing题库 #include<bits/stdc.h>using namespace std;const int N1010;int n,m; char a[N],b[N]; int f[N][N];int main() {cin>>n>>a1;cin>>m>>b1;for(int i0;i<m;i)f[0][i]i;for(int i0;i<n;i)f[i][0]i;//先初始化…

用户状态保持机制-Session

0、业务需求 会话&#xff1a;web应用中的会话是指一个客户端浏览器和服务器之间连续发生的一系列请求和响应的过程。 会话状态&#xff1a;web应用中的会话状态是指web服务器与浏览器在会话过程中产生的状态信息&#xff0c;借助会话状态&#xff0c;服务器能够把属于同一会话…

线性表概念及实现1

文章目录 前言一、线性表1.定义2.特点3.一般线性表的抽象数据类型定义 二、线性表的顺序存储&#xff08;顺序表&#xff09;1.基本概念2.数组实现顺序表3.顺序表中基本操作的具体实现 总结 前言 T_T此专栏用于记录数据结构及算法的&#xff08;痛苦&#xff09;学习历程&#…

纯小白蓝桥杯备赛笔记--DAY14(计算几何)

文章目录 计算几何基础平面几何距离圆的周长和面积圆与圆之间的关系&#xff1a;海伦公式计算三角形面积点到直线的距离 点积和叉积例题&#xff1a; 点和线的关系点的表示形式和代码判断点在直线的那边点到线的垂足点到线的距离例题-1242例题-1240升级--点到线段的距离--1285 …

指定世界TOP名校|医学研究学者公派美国麻省理工学院做博士后

W医生公派博士后条件为&#xff1a;世界TOP100的知名高校&#xff0c;研究方向相符且前沿。最终我们用世界顶级高校-美国麻省理工学院&#xff08;MIT&#xff09;的博士后邀请函助其获得单位资助&#xff0c;顺利通过签证并出国。 W医生背景&#xff1a; 申请类型&#xff1a…

LC 501.二叉搜索树中的众数

501.二叉搜索树中的众数 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 …

全国贫困县DID数据(2008-2022年)

数据来源&#xff1a;国W院扶贫开发领导小组办公室 时间跨度&#xff1a;2008-2022年 数据范围&#xff1a;各县域 数据指标 年份 县域名称 所属地市 所属省份 县域代码 是否贫困县(是为1&#xff0c;否为0) 参考文献&#xff1a; [1]马雯嘉,吴茂祯.从全面脱贫到乡村振兴…

VQ-BeT: Behavior Generation with Latent Actions 代码复现(Mujoco 安装)

代码地址&#xff1a;https://github.com/jayLEE0301/vq_bet_official.git 创建环境 conda create -n vq-bet python3.9 conda activate vq-bet拉取库 git clone https://github.com/jayLEE0301/vq_bet_official.git export PROJ_ROOT$(pwd)安装pytorch conda install pyto…

AI论文速读 | 线性时间序列预测模型分析

论文标题&#xff1a;An Analysis of Linear Time Series Forecasting Models 作者&#xff1a; William Toner&#xff0c; Luke Darlow 机构&#xff1a;爱丁堡大学&#xff08;Edinburgh&#xff09;&#xff0c;华为研究中心&#xff08;爱丁堡&#xff09; 论文链接&am…

开源项目若依放大招了?

前言 鉴于之前写了篇插件式相关的文章&#xff0c;阅读量比起其它文章可不要好太多&#xff0c;所以我决定继续这个主题&#xff01; 以前我们公司用的就是Ruoyi&#xff0c;代码比较简单易懂。但是有些功能确实用不上&#xff0c;比如部门和岗位&#xff0c;每次新项目我拉了…

Docker安装及开启远程访问

这几天有人问我docker是怎么开启远程服务的&#xff1f; 正好之前我做过这件事情&#xff0c;并且写了相关的笔记&#xff0c;现在整理为一篇博客发出来。 安装Docker 首先更新一下自己的yum版本 yum update安装一下所需要的软件包 yum-config-manager --add-repo http://…

Java复习第十七天学习笔记(转发、重定向,GET,POST),附有道云笔记链接

【有道云笔记】十七 4.3 转发、重定向、Get、POST、乱码 https://note.youdao.com/s/GD5TRksQ 一、转发 转发&#xff1a;一般查询了数据之后&#xff0c;转发到一个jsp页面进行展示 req.setAttribute("list", list); req.getRequestDispatcher("student_lis…

套接字通信模型

本文内容主要参考《Android图形显示系统》 套接字也就是socket&#xff0c;一般用于网络中两个主机之间应用进程进行通信&#xff0c;在同一个主机也可以使用套接字完成进程之间的通信。 在图形显示系统中&#xff0c;用到套接字进行通信的地方主要有VSync信号的分发以及输入事…

Linux:动态库加载、编址

目录 一、库的概念 二、动静态库的加载 2.1绝对编址与相对编址 2.1一般程序的加载 三、动态库的加载 一、库的概念 库默认就是一个磁盘级文件&#xff0c;所以在执行代码时&#xff0c;库和可执行程序都会被加载到内存中&#xff0c;从原理上&#xff0c;库函数的调用依旧…

软件测试:遇到bug怎么分析,这篇文章值得一看

为什么定位问题如此重要&#xff1f; 可以明确一个问题是不是真的“bug” 很多时候&#xff0c;我们找到了问题的原因&#xff0c;结果发现这根本不是bug。原因明确&#xff0c;误报就会降低多个系统交互&#xff0c;可以明确指出是哪个系统的缺陷&#xff0c;防止“踢皮球”&…

C--函数指针与回调函数

文章目录 定义函数指针qsort中的回调函数自实现排序的回调函数 定义 回调函数&#xff0c;当一个函数执行时&#xff0c;中途调用其他定义好的函数来帮助实现功能&#xff0c;再继续执行这个函数 函数指针 类型为函数的指针&#xff0c;如下 void func() { } int main() {…

如何让视频流媒体平台免受网络攻击

在各国&#xff0c;流媒体服务已越来越受到大众的欢迎。有统计表明&#xff0c;目前视频流已占网络整体流量的80%以上。不过如您所见&#xff0c;近年来&#xff0c;数字威胁的不断增加&#xff0c;也让网络攻击逐年递增。单个视频用户受到的危险&#xff0c;往往会危及到整个服…