QT中的OpenGL学习-----3D图形

一、3D坐标系

记住V_clip = M_projection * M_view * M_model * V_local就行,可以在顶点着色器里面添加位置信息:

#version 330 core
layout (location = 2) in vec3 aPos;//location属性位置有16个
layout (location = 3) in vec3 aColor;
layout (location = 1) in vec2 aTextureCoordinates;
out vec3 ourColor;
out vec2 TextureCoordinates;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    ourColor = aColor;
    TextureCoordinates = aTextureCoordinates;
}

片段着色器不用改变:

#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TextureCoordinates;
uniform sampler2D textureWall;
uniform sampler2D textureLe;
uniform sampler2D textureSmall;
uniform sampler2D texturePJ;
uniform float ratio;
void main()
{
    FragColor = mix(texture(textureWall, TextureCoordinates), texture(textureLe, TextureCoordinates), ratio);
}

二、透视投影

这方面可以恶补下线性代数知识。

三、代码实现

3.1 构建一个正方体的点

        在OpenGL里面,三角形是基础图形,正方体6个面,每一个面都是两个三角形拼接而成,所以点需要2×3×6=36个顶点坐标,在坐标的数组里面可以放入颜色、纹理等信息,后面调用解析的时候注意步长和位置即可。

        在编写顶点的时候,只要能连起来是个正方体即可,不同的点做原点都可以,但是一定要连起来,纹理是2个数来表示X和Y,和顶点坐标没有关系。下面是构建的一个例子:

float vertices[] =
{
    //positions //texture coordinates
    //正面
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    //背面
    -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    //左面
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    -0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    //右面
    0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    //上面
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    //下面
    -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f, 0.0f, 1.0f
};

3.2 画出正方体

注意要给M_projection * M_view * M_model这三个矩阵,写在外面也可以,但是多个3D图形的话model需要初始化,不然除了第一次的图形是单位矩阵,for循环后面的都不是。

void OpenGLWidget::paintGL()
{
    QMatrix4x4 model;
    QMatrix4x4 view;
    QMatrix4x4 projection;

    unsigned int time = QTime::currentTime().msec();
    //先旋转再位移,图片在固定位置旋转
    //先位移再旋转,图片围着一个地方转
    //具体参考线性代数矩阵知识
//    model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转
    view.translate(0.0, 0.0, -3);
    projection.perspective(45, (float)width()/height(), 0.1, 100);
    m_shaderProgram.setUniformValue("projection", projection);


    //red:0.0f无色,1.0f全红
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_DEPTH_TEST);//加了立方体可以封面
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_shaderProgram.bind();//绑定可以理解为使用它
    m_shaderProgram.setUniformValue("ratio", ratio);
    glBindVertexArray(VAO);

    switch (m_shape)
    {
    case Rect:
        //纹理绑定
        textureLe->bind(1);
        textureWall->bind(0);

        //图形绘画
        //画之前设置3D图形
        //V_clip = M_projection * M_view * M_model * V_local
        m_shaderProgram.setUniformValue("view", view);
        foreach(auto item, cubePositions)
        {
            model.setToIdentity();//初始化
            model.translate(item);//位移
            model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转
            m_shaderProgram.setUniformValue("model", model);
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }

        break;
    default:
        break;
    }
}

3.3 完整代码

#include "openglwidget.h"

unsigned int VBO, VAO, EBO;
float ratio = 0.5;
float vertices[] =
{
    //positions //texture coordinates
    //正面
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    //背面
    -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    //左面
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    -0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    //右面
    0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    //上面
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    //下面
    -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f, 0.0f, 1.0f
};

unsigned int indices[] = //note that we start from 0!
{
    0, 1, 3,//第一个三角形
    1, 2, 3 // 第二个三角形
};

//多个3D图形,建立位移数组
QVector<QVector3D> cubePositions =
{
    //X,Y,Z
    QVector3D(0.0f, 0.0f, 0.0f),
    QVector3D(2.0f, 5.0f, -15.0f),
    QVector3D(-1.5f, -2.2f, -2.5f),
    QVector3D(-3.8f, -2.0f, -12.3f),
    QVector3D(2.4f, -0.4f, -3.5f),
    QVector3D(-1.7f, 3.0f, -7.5f),
    QVector3D(1.3f, -2.0f, -2.5f),
    QVector3D(1.5f, 2.0f, -2.5f),
    QVector3D(1.5f, 0.2f, -1.5f),
    QVector3D(-1.3f, 1.0f, -1.5f)
};

OpenGLWidget::OpenGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
    m_timer = new QTimer;
    m_timer->start(100);
    connect(m_timer, &QTimer::timeout, this, [=](){
        update();
    });
}

OpenGLWidget::~OpenGLWidget()
{
    makeCurrent();
    glDeleteBuffers(1,&VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteVertexArrays(1,&VAO);
    doneCurrent();
}

void OpenGLWidget::drawShape(Shape shape)
{
    m_shape = shape;
    update();
}

void OpenGLWidget::setWireframe(bool wireframe)
{
    makeCurrent();
    if (wireframe)
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    else
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }
    update();
    doneCurrent();
}

void OpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    //使用QT封装的着色器
    bool success;
    m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/shapes.vert");//顶点着色器
    m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/shapes.frag");//片段着色器
    success = m_shaderProgram.link();//连接到着色器
    if(!success)
        qDebug() << "ERR:" << m_shaderProgram.log();

    //创建VBO和VAO对象,并赋予ID
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    //绑定VBO和VAO对象
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    //为当前绑定到target的缓冲区对象创建一个新的数据存储
    //如果data不是NULL,则使用来自此指针的数据初始化数据存储
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //访问着色器里面属性的位置
    m_shaderProgram.bind();
    GLint posLocation = m_shaderProgram.attributeLocation("aPos");//询问着色器里面变量aPos顶点信息的属性位置
    GLint textureLocation = m_shaderProgram.attributeLocation("aTextureCoordinates");

    //告知显卡如何解析缓冲里的顶点属性值
    glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);

    //告知显卡如何解析缓冲里的纹理属性值
    glVertexAttribPointer(textureLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));

    //开启VAO管理的顶点属性值
    glEnableVertexAttribArray(posLocation);

    //开启VAO管理的纹理属性值
    glEnableVertexAttribArray(textureLocation);

    //EBO创建与绑定
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //纹理
    textureWall = new QOpenGLTexture(QImage(":/imags/imag/1.jpg").mirrored());
    textureLe = new QOpenGLTexture(QImage(":/imags/imag/2.jpg").mirrored());
    textureSmall = new QOpenGLTexture(QImage(":/imags/imag/3.jpg").mirrored());
    texturePJ = new QOpenGLTexture(QImage(":/imags/imag/4.jpg").mirrored());
    //设置纹理单元,纹理单元有16个
    m_shaderProgram.bind();
    m_shaderProgram.setUniformValue("textureWall", 0);
    m_shaderProgram.setUniformValue("textureLe", 1);
    m_shaderProgram.setUniformValue("textureSmall", 2);
    m_shaderProgram.setUniformValue("texturePJ", 3);

    //设置渐远纹理
    texturePJ->generateMipMaps();

    //纹理绑定
    textureLe->bind(1);
    textureWall->bind(0);

    //VAO和VBO绑定为0,相当于释放休息
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    QMatrix4x4 projection;
    projection.perspective(45, (float)width()/height(), 0.1, 100);
    m_shaderProgram.setUniformValue("projection", projection);
}

void OpenGLWidget::resizeGL(int w, int h)
{
    Q_UNUSED(h)
    Q_UNUSED(w)
}

void OpenGLWidget::paintGL()
{
    QMatrix4x4 model;
    QMatrix4x4 view;

    unsigned int time = QTime::currentTime().msec();
    //先旋转再位移,图片在固定位置旋转
    //先位移再旋转,图片围着一个地方转
    //具体参考线性代数矩阵知识
//    model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转
    view.translate(0.0, 0.0, -3);


    //red:0.0f无色,1.0f全红
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_DEPTH_TEST);//加了立方体可以封面
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_shaderProgram.bind();//绑定可以理解为使用它
    m_shaderProgram.setUniformValue("ratio", ratio);
    glBindVertexArray(VAO);

    switch (m_shape)
    {
    case Rect:
        //纹理绑定
        textureLe->bind(1);
        textureWall->bind(0);

        //图形绘画
        //画之前设置3D图形
        //V_clip = M_projection * M_view * M_model * V_local
        m_shaderProgram.setUniformValue("view", view);
        foreach(auto item, cubePositions)
        {
            model.setToIdentity();//初始化
            model.translate(item);//位移
            model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转
            m_shaderProgram.setUniformValue("model", model);
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }

        break;
    default:
        break;
    }
}

void OpenGLWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_Up:
        ratio += 0.1;
        break;
    case Qt::Key_Down:
        ratio -= 0.1;
        break;
    default:
        break;
    }
    if(ratio>1) ratio = 1;
    if(ratio<0) ratio = 0;

    m_shaderProgram.bind();
    m_shaderProgram.setUniformValue("ratio", ratio);
    update();
}



详细代码看压缩文件。

3.4 学习地址

5-3代码实现3D效果_哔哩哔哩_bilibili

四、效果展示

3D旋转跳跃画圈圈

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

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

相关文章

基础算法前缀和与差分

前言 本次博客会介绍一维和二维的前缀和&#xff0c;以及一维二维差分的基本使用&#xff0c;尽量画图&#xff0c;多使用配合文字 使大家理解&#xff0c;希望有所帮助吧 一维前缀和 问题描述 这里有一个长度为n的数组&#xff0c;我们要算出【2,5】区间的元素和 暴力思…

linux定时备份数据库sql文件(表格、视图、存储过程,已保存的查询语句不会被备份)

创建一个脚本文件xxx.sh 为其设置全部权限chmod 777 xxx.sh #!/bin/bash # 设置备份目录和文件名 current_time$(date "%Y%m%d_%H%M%S") backup_dir"/root/db_back/db" backup_file"$backup_dir/db_ship_backup_$current_time.sql" log_file&…

【JavaEE初阶】网络原理|认识协议|协议分层|TCP/IP模型|封装和分用

一、认识协议 1.概念 简单来说&#xff1a;就是一种通信双方&#xff0c;对于通信规则的约定&#xff08;标准&#xff09;&#xff0c;一定是通信双方都认可的 但是这个协议不一定是认可面非常广的&#xff0c;即使是两个人之间的也可叫做协议 就好⽐⻅⽹友&#xff0c;彼此…

Docker搭建项目管理软件禅道

文章目录 一、简介二、部署三、使用 一、简介 禅道是以项目管理为核心的协作平台&#xff0c;旨在帮助团队高效地进行项目管理和协作。 禅道提供了项目管理、任务管理、团队协作、文档管理、报告统计等功能。 禅道官网 二、部署 操作系统&#xff1a;22.04.4 创建文件夹 …

Linux驱动开发——(三)并发与竞争

目录 一、并发与竞争简介 二、原子操作 2.1 原子操作简介 2.2 原子整形操作API 2.3 原子位操作API 2.4 原子操作驱动代码 三、自旋锁 3.1 自旋锁简介 3.2 自旋锁API 3.3 自旋锁驱动代码 四、信号量 4.1 信号量简介 4.2 信号量API 4.3 信号量驱动代码 一、并发与…

Redis-cluster集群架构

一、集群架构 上述集群架构师一个由多个主从节点群组成的分布式服务器&#xff0c;具有复制、高可用和分片的特性。Redis集群不需要sentine哨兵也能完成节点移除和故障转移。官方文档称可以扩展上万个节点。推荐不超过1000个&#xff1b;从节点只担任备份的角色&#xff0c;不承…

JavaWeb过滤器

Javaweb过滤器是一种用于在Servlet处理请求之前或之后对请求进行预处理或后处理的组件。过滤器可以用于拦截请求、修改请求参数、过滤响应内容等操作。其主要作用包括&#xff1a; 拦截请求&#xff1a;过滤器可以拦截客户端请求&#xff0c;对请求进行验证、过滤或修改&#x…

STL-list的使用及其模拟实现

在C标准库中&#xff0c;list 是一个双向链表容器&#xff0c;用于存储一系列元素。与 vector 和 deque 等容器不同&#xff0c;list 使用带头双向循环链表的数据结构来组织元素&#xff0c;因此list插入删除的效率非常高。 list的使用 list的构造函数 list迭代器 list的成员函…

【Interconnection Networks 互连网络】Dragonfly Topology 蜻蜓网络拓扑

蜻蜓拓扑 Dragonfly Topology 1. 拓扑参数2. Topology Description 拓扑描述3. Topology Variations 拓扑变体 蜻蜓拓扑 Dragonfly Topology 1. 拓扑参数 Dragonfly拓扑参数&#xff1a; N N N: 网络中终端(terminal)的总数量 p p p: 连接到每个路由器的终端数量 a a a: 每…

Go语言并发控制

channel // cancelFn 数据通道关闭通知退出 func cancelFn(dataChan chan int) {for {select {case val, ok : <-dataChan:// 关闭data通道时&#xff0c;通知退出// 一个可选是判断data指定值时退出if !ok {fmt.Printf("Channel closed &#xff01;&#xff01;&…

Rest接口/Nginx日志记录和采集

文章目录 一、Rest接口日志二、Nginx日志三、采集日志四、夜莺查看Nginx日志五、夜莺查看Rest接口日志 一、Rest接口日志 记录日志字典定义 接口URL接口名称,类别,入参全记录,出参全记录,入参字段1:中文名1/入参字段2:中文名2,出参字段1:中文名1/test/api/login账户登录,登录…

java-单列集合List详解

一、List概述 ​​​​​​​List 接口继承自 Collection 接口。这意味着所有 List 类型的对象都是 Collection 类型的对象&#xff0c;它们共享 Collection 接口中定义的所有方法。 List集合的特点&#xff1a; 1、有序&#xff1a;存和取得元素顺序一致 2、有索引&#xf…

Java- Object根父类

在java中&#xff0c;所有的类都有一个公共的父类&#xff0c;这个java.lang.Object类 * * * Object所有类的根&#xff0c;成为超类。 1.证明Object是根 public class A_Object01 {public static void main(String[] args) {//证明Object是根//基本数据类型int a 0;Object…

【硬十宝典】——1.4【基础知识】电源完整性——理解与设计

定义&#xff1a; 电源完整性&#xff08;Power integrity&#xff09;简称PI&#xff0c;是确认电源来源及目的端的电压及电流是否符合需求。 电源完整性在现今的电子产品中相当重要。有几个有关电源完整性的层面&#xff1a;芯片层面、芯片封装层面、电路板层面及系统层面。…

18-Echarts 配置系列之:数据集 dataset

简介&#xff1a; 数据集&#xff08;dataset&#xff09;是专门用来管理数据的组件。简化在每一个系列中设置数据&#xff0c;这一个配置是在Echarts4 中开始支持。 通过数据集配置&#xff0c;避免为每一个系列创建一个数据&#xff0c;避免格式转化的痛苦。 简单举例&…

开启智慧之旅,AI与机器学习驱动的微服务设计模式探索

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自热榜文章&#x1f525;&#xff1a;探索设计模式的魅力&#xff1a;开启智慧…

2024年腾讯云免费服务器最新申请入口链接

腾讯云免费服务器申请入口 txybk.com/go/free 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云百科txybk.com分享2024年最新腾讯云免费服务器申请入口、限制…

YOLOv8操作指南-下载+配置环境

下载&#xff1a;github&#xff0c;进入搜索YOLOv8 就这个&#xff0c;点开 下载就可以了&#xff0c;然后解压一下 配置环境&#xff1a; 安装Pytorch 先看一下这个&#xff1a; 如果电脑有GPU的话&#xff1a; 判断自己电脑GPU&#xff1a;打开任务管理器 我的是英伟达3…

sherpa + ncnn 离线语音识别

目录结构 前言音视频格式转为wavsherpa-ncnn编译LinuxWindowswindows编译中遇到的问题问题“nmake -? failed with: no such file or directory”编译失败原因 成功编译截图 可执行程序说明模型下载语言识别测试LinuxWindows 参考文献 前言 小编需要实现离线音视频语言部分识…

vulfocus靶场couchdb 权限绕过 (CVE-2017-12635)

Apache CouchDB是一个开源数据库&#xff0c;专注于易用性和成为"完全拥抱web的数据库"。它是一个使用JSON作为存储格式&#xff0c;JavaScript作为查询语言&#xff0c;MapReduce和HTTP作为API的NoSQL数据库。应用广泛&#xff0c;如BBC用在其动态内容展示平台&…