Android显示系统(04)- OpenGL ES - Shader绘制三角形

Android显示系统(02)- OpenGL ES - 概述
Android显示系统(03)- OpenGL ES - GLSurfaceView的使用
Android显示系统(04)- OpenGL ES - Shader绘制三角形
Android显示系统(05)- OpenGL ES - Shader绘制三角形(使用glsl文件)
Android显示系统(06)- OpenGL ES - VBO和EBO和VAO
Android显示系统(07)- OpenGL ES - 纹理Texture
Android显示系统(08)- OpenGL ES - 图片拉伸

一、前言:

OpenGL 1.0采用固定管线,OpenGL 2.0以上版本重要的改变就是采用了可编程管线,Shader 编程是指使用着色器(Shader)编写代码来控制图形渲染管线中特定阶段的处理过程。在图形渲染中,着色器是在 GPU 上执行的小型程序,用于定义图形渲染管线中不同阶段的处理逻辑,以实现各种视觉效果,那么渲染管线哪个阶段可编程呢?

在这里插入图片描述

就是上图的渲染管线蓝色部分。

二、Shader介绍:

1、Vertex Shader和Fragment Shader:

在现代的图形渲染中,通常会使用两种主要类型的着色器:顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)。这两种着色器分别负责处理图形的顶点数据和片元(像素)数据,通过编写这些着色器程序,开发人员可以实现各种复杂的图形效果和渲染技术。

下面是对顶点着色器和片元着色器的简要介绍:

  • 顶点着色器
    • 顶点着色器用于处理图形的顶点数据,如位置、颜色、法线等。
    • 主要作用包括对顶点位置的变换(如模型变换、视图变换、投影变换)、法线变换、顶点着色等。
    • 顶点着色器的输出通常是裁剪空间坐标或者屏幕空间坐标。
  • 片元着色器
    • 片元着色器用于处理图元的片元(像素)数据,负责计算最终的颜色输出。
    • 在片元着色器中,开发人员可以实现光照、纹理映射、阴影、透明度等效果。
    • 片元着色器的输出通常是片元的颜色、深度值、法线等。

2、图元:

在Shader编程中,“图元”(Primitive)指的是基本的几何图形单元,通常是指在3D图形渲染中的基本几何形状,如点、线、三角形、四边形等。这些基本的几何图形单元是构成复杂场景的基础,它们通过渲染管线进行处理和转换,最终呈现在屏幕上。

在Shader编程中,图元是渲染管线处理的基本单位,Shader程序会对每个图元进行相应的处理,包括顶点变换、光照计算、纹理映射等操作,最终将图元渲染到屏幕上。常见的几何图元有以下几种:

  1. 点(Point):最简单的图元,通常用于表示粒子、光源等。
  2. 线(Line):由两个点组成的图元,可用于绘制线条、边缘等。
  3. 三角形(Triangle):由三个顶点组成的图元,是最基本的多边形,是3D图形学中最重要的图元之一,因为所有复杂的表面都可以由三角形网格构成。
  4. 四边形(Quadrilateral):由四个顶点组成的图元,通常被拆分为两个三角形处理。

Shader程序通过对这些基本图元进行处理和变换,最终形成了复杂的场景和图像。在Shader编程中,开发人员可以通过编写顶点着色器和片元着色器来对这些图元进行处理,实现各种视觉效果和渲染技术。处理图元是Shader程序中的一个重要任务,它直接影响着最终的渲染效果和性能。

3、三角形:

上面的四个图元中,其实最重要的是三角形,我们把大多数复杂的图形都可以用三角形拼起来,就像我小时候(不敢说你们00后小时候)糊灯笼一样。

比如,我之前文章提到的这个复杂的图,也都是由众多小三角形构成:

在这里插入图片描述

三、重要坐标系:

在 OpenGL ES 中,“标准设备坐标系”(Normalized Device Coordinates)和“屏幕坐标系”(Screen Coordinates)是两种不同的坐标系,它们在图形渲染过程中扮演不同的角色。

  1. 标准设备坐标系(Normalized Device Coordinates)
    • 标准设备坐标系是一个抽象的坐标系,它是一个以屏幕空间的中心为原点,范围从 -1 到 1 的立方体空间。
    • 在标准设备坐标系中,坐标 (0, 0) 表示屏幕中心,(-1, -1) 表示左下角,(1, 1) 表示右上角。
    • 所有的顶点数据在通过VertexShader处理后都会被映射到标准设备坐标系,这是 OpenGL ES 中进行图形变换和裁剪的标准坐标系。
  2. 屏幕坐标系(Screen Coordinates)
    • 屏幕坐标系是实际显示设备的坐标系,它通常以左上角为原点,向右为 x 轴正方向,向下为 y 轴正方向。
    • 屏幕坐标系的坐标值通常是以像素为单位的整数值,用来确定在屏幕上绘制图像和文本等元素的位置。

在 OpenGL ES 渲染过程中,顶点数据首先被定义在对象坐标系中,然后通过模型变换、视图变换和投影变换将其转换到标准设备坐标系中,最终在屏幕上绘制出来。

在这里插入图片描述

总结来说,标准设备坐标系是为了方便进行图形变换和裁剪而定义的坐标系,而屏幕坐标系则是实际显示设备上的坐标系,用于确定最终图像的位置。OpenGL ES 中的渲染过程涉及将顶点数据从对象坐标系转换到标准设备坐标系,最终映射到屏幕坐标系进行显示。

四、GLSL语言:

1、概念:

着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数,在这个函数中我们处理所有的输入变量,并将结果输出到输出变量中。

一个典型的着色器有下面的结构:

#version version_number
in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

void main()
{
  // 处理输入并进行一些图形操作
  ...
  // 输出处理过的结果到输出变量
  out_variable_name = weird_stuff_we_processed;
}

当我们特别谈论到顶点着色器的时候,每个输入变量也叫顶点属性(Vertex Attribute)。我们能声明的顶点属性是有上限的,它一般由硬件来决定。OpenGL确保至少有16个包含4分量的顶点属性可用,但是有些硬件或许允许更多的顶点属性,你可以查询GL_MAX_VERTEX_ATTRIBS来获取具体的上限:

int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;

通常情况下它至少会返回16个,大部分情况下是够用了。

2、数据传递:

在这里插入图片描述

  • 可以将Prog想象成一个芯片,有很多的引脚,比如这儿的1绑定的是VertextShader,2绑定的是FragmentShader。
  • 顶点着色器Vertex负责确定3D图形的三个顶点,片元着色器Fragment负责确定每个像素的颜色;
  • 数据传给1的时候,就会自动传给vPosition;看看具体怎么传递的:
    • 通过glGetAttribLocation获取vPositon的引脚;
    • glEnableVertextAttribArray传入的参数就是上一步获取的ID,这样,就可以打开这个引脚;
    • 通过glVertexAttribPointer将准备好的顶点数据Vertex Buffer Object传递给引脚1,这样vPosition就收到了;
  • 数据传给2的时候,就会自动传给vColor
    • 通过glGetUniformLocation获取引脚;
    • 通过glUniform4fv传递给vColor即可;

3、变量:

1)vertex shader变量:

在这里插入图片描述

  • 输入变量有:Attribute类型、Uniforms类型(unform变量相当于全局变量)、Samplers类型;
  • 输出变量有:Varying类型(Vertex Shader的输出,可以作为后续的Shader的输入)
  • 内部变量有:gl_Position(这个最重要);
    • 以gl开头的变量都是内部变量;
    • vertex shader需要给gl_Position赋值来确定顶点的位置;
    • 渲染管线会根据gl_Position进行图元装配;

2)fragment shader变量:

在这里插入图片描述

  • Varying类型:作为Fragment Shader的输入,和Vertex Shader的输出一一对应;
  • gl_FragColor:内部变量,是Fragment Shader的输出,保存每个像素的颜色;
    • 确定每个像素的最终颜色;
    • 可以和纹理结合,实现纹理的映射;
    • 还可以通过它实现光照、高亮等颜色特效;

五、绘制一个三角形:

1、步骤:

  • 使用GLSurfaceView创建OpenGL ES环境;

  • 定义顶点着色器和片元着色器以及OpenGL ES程序;

  • 编译顶点着色器和片元着色器;

    • 使用GLES30.glCreateShader()创建Shader对象;
    • 使用GLES30.glShaderSource()绑定Shader和其源代码;
    • 使用GLES30.glCompileShader()编译Shader;
  • 链接OpenGL ES程序;

    • 使用GLES30.glCreateProgram()创建OpenGL ES程序;
    • 使用GLES30.glAttachShader()绑定Shader到OpenGL ES程序;
    • 使用GLES30.glLinkProgram()链接整个OpenGL ES程序;
  • 使用OpenGL ES程序;

    • 调用GLES30.glUseProgram()使用OpenGL ES程序;
    • 传递顶点数据和片元数据

2、创建OpenGL ES环境:

定义GLSurfaceView

// 文件路径:com/example/glsurfaceviewdemo/GLSurfaceViewTest.java
public class GLSurfaceViewTest extends GLSurfaceView {
    public GLSurfaceViewTest(Context context) {
        super(context);

        // 设置OpenGL ES版本(由于3.0兼容2.0,我们使用3.0)
        setEGLContextClientVersion(3);

        // 设置渲染器Renderer,函数调用后,里面会启动一个新线程构造EGL环境
        setRenderer(new GLRenderTest());
    }
}

MainActivity使用GLSurfaceView:

// 文件路径:com/example/glsurfaceviewdemo/MainActivity.java
public class MainActivity extends AppCompatActivity {
    private GLSurfaceViewTest mGlSurfaceViewTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGlSurfaceViewTest = new GLSurfaceViewTest(this);
        setContentView(mGlSurfaceViewTest);
    }
}

3、定义顶点着色器和片元着色器:

// 文件路径:com/example/glsurfaceviewdemo/Triangle.java
// 定义的顶点着色器代码
    private final String mVertexShaderCode =
            "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "}";

    // 定义的片段着色器代码
    private final String mFragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    // 定义的三角形顶点坐标数组
    private final float[] mTriangleCoords = new float[]{
            0.0f, 0.2f, 0.0f,   // 顶部
            -0.5f, -0.5f, 0.0f, // 左下角
            0.5f, -0.5f, 0.0f   // 右下角
    };

    // 定义的fragment的颜色数组,表示每个像素的颜色
    private final float[] mColor = new float[]{0.0f, 1.0f, 0.0f, 1.0f};

4、定义OpenGL ES程序:

// 文件路径:com/example/glsurfaceviewdemo/Triangle.java
private int mProgram;
mProgram = GLES30.glCreateProgram();

5、编译着色器:

// 文件路径:com/example/glsurfaceviewdemo/Triangle.java
	public Triangle() {
        // ...

        // 2.加载并编译vertexShader和fragmentShader
        int vertexShader = Companion.compileShader(GLES30.GL_VERTEX_SHADER, mVertexShaderCode);
        int fragmentShader = Companion.compileShader(GLES30.GL_FRAGMENT_SHADER, mFragmentShaderCode);
       
       // ...
	}
    // 定义静态内部类
    public static class Companion {
        // 创建并编译着色器
        public static int compileShader(int type, String shaderCode) {
            // 创建一个着色器
            int shader = GLES30.glCreateShader(type);
            // 将着色器代码设置到着色器对象中
            GLES30.glShaderSource(shader, shaderCode);
            // 编译着色器
            GLES30.glCompileShader(shader);
            return shader;
        }
    }

6、链接OpenGL ES程序:

// 文件路径:com/example/glsurfaceviewdemo/Triangle.java
	public Triangle() {
        // ...
        // 4.attach两个编译好的着色器到program当中
        GLES30.glAttachShader(mProgram, vertexShader);
        GLES30.glAttachShader(mProgram, fragmentShader);
        // 5.链接整个program
        GLES30.glLinkProgram(mProgram);
    }

7、使用OpenGL ES程序:

// 文件路径:com/example/glsurfaceviewdemo/Triangle.java
    public void draw() {
        // 使用program
        GLES30.glUseProgram(mProgram);
        // 获取顶点着色器的位置句柄
        mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
        // 启用顶点属性数组
        GLES30.glEnableVertexAttribArray(mPositionHandle);
        // 准备三角形坐标数据
        // 重置缓冲区位置
        mVertexBuffer.position(0);
        // 指定顶点属性数据的格式和位置
        GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, mVertexBuffer);

        // 获取片元着色器的颜色句柄
        mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
        // 设置绘制三角形的颜色
        GLES30.glUniform4fv(mColorHandle, 1, mColor, 0);
        // 绘制三角形
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, mTriangleCoords.length / COORDS_PER_VERTEX);
        // 禁用顶点属性数组
        GLES30.glDisableVertexAttribArray(mPositionHandle);
    }

这就是一个绘制三角形的函数;

8、渲染器调用:

在渲染器中周期性地调用上面的绘制函数。

// 文件路径:com/example/glsurfaceviewdemo/GLRenderTest.java
public class GLRenderTest implements GLSurfaceView.Renderer {
    private Triangle mTriangle;
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        mTriangle = new Triangle();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0, 0,  width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl){
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
        mTriangle.draw();
    }
}

9、运行结果:

在这里插入图片描述

10、附:全部代码:

文件路径:com/example/glsurfaceviewdemo/MainActivity.java

package com.example.glsurfaceviewdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    private GLSurfaceViewTest mGlSurfaceViewTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGlSurfaceViewTest = new GLSurfaceViewTest(this);
        setContentView(mGlSurfaceViewTest);
    }
}

文件路径:com/example/glsurfaceviewdemo/GLSurfaceViewTest.java

package com.example.glsurfaceviewdemo;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;

public class GLSurfaceViewTest extends GLSurfaceView {
    public GLSurfaceViewTest(Context context) {
        super(context);

        // 设置OpenGL ES版本(由于3.0兼容2.0,我们使用3.0)
        setEGLContextClientVersion(3);

        // 设置渲染器Renderer,函数调用后,里面会启动一个新线程构造EGL环境
        setRenderer(new GLRenderTest());
    }
}

文件路径:com/example/glsurfaceviewdemo/GLRenderTest.java

package com.example.glsurfaceviewdemo;

import android.opengl.GLES30;
import android.opengl.GLSurfaceView;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class GLRenderTest implements GLSurfaceView.Renderer {
    private Triangle mTriangle;
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        mTriangle = new Triangle();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0, 0,  width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl){
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
        mTriangle.draw();
    }
}

文件路径:com/example/glsurfaceviewdemo/Triangle.java

package com.example.glsurfaceviewdemo;

import android.opengl.GLES30;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL;

public class Triangle {
    public Triangle() {
        // 1.初始化顶点缓冲区,存储三角形坐标
        // 为顶点坐标分配DMA内存空间
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(mTriangleCoords.length * 4);
        // 设置字节顺序为本地字节顺序(会根据硬件架构自适应大小端)
        byteBuffer.order(ByteOrder.nativeOrder());
        // 将字节缓冲区转换为浮点缓冲区
        mVertexBuffer = byteBuffer.asFloatBuffer();
        // 将顶点三角形坐标放入缓冲区
        mVertexBuffer.put(mTriangleCoords);
        // 设置缓冲区的位置指针到起始位置
        mVertexBuffer.position(0);

        // 2.加载并编译vertexShader和fragmentShader
        int vertexShader = Companion.compileShader(GLES30.GL_VERTEX_SHADER, mVertexShaderCode);
        int fragmentShader = Companion.compileShader(GLES30.GL_FRAGMENT_SHADER, mFragmentShaderCode);
        // 3.创建一个OpenGL程序
        mProgram = GLES30.glCreateProgram();
        // 4.attach两个编译好的着色器到program当中
        GLES30.glAttachShader(mProgram, vertexShader);
        GLES30.glAttachShader(mProgram, fragmentShader);
        // 5.链接整个program
        GLES30.glLinkProgram(mProgram);
    }

    // 顶点数据是float类型,因此,使用这个存储
    private FloatBuffer mVertexBuffer;
    private int mProgram;
    // 定义的顶点着色器代码
    private final String mVertexShaderCode =
            "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "}";

    // 定义的片段着色器代码
    private final String mFragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    // 定义的三角形顶点坐标数组
    private final float[] mTriangleCoords = new float[]{
            0.0f, 0.2f, 0.0f,   // 顶部
            -0.5f, -0.5f, 0.0f, // 左下角
            0.5f, -0.5f, 0.0f   // 右下角
    };

    // 定义的fragment的颜色数组,表示每个像素的颜色
    private final float[] mColor = new float[]{0.0f, 1.0f, 0.0f, 1.0f};
    // 顶点着色器的位置句柄
    private int mPositionHandle = 0;
    // 片元着色器的位置句柄
    private int mColorHandle = 0;
    private final int COORDS_PER_VERTEX = 3;

    // 定义静态内部类
    public static class Companion {
        // 创建并编译着色器
        public static int compileShader(int type, String shaderCode) {
            // 创建一个着色器
            int shader = GLES30.glCreateShader(type);
            // 将着色器代码设置到着色器对象中
            GLES30.glShaderSource(shader, shaderCode);
            // 编译着色器
            GLES30.glCompileShader(shader);
            return shader;
        }
    }

    public void draw() {
        // 使用program
        GLES30.glUseProgram(mProgram);
        // 获取顶点着色器的位置句柄
        mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
        // 启用顶点属性数组
        GLES30.glEnableVertexAttribArray(mPositionHandle);
        // 准备三角形坐标数据
        // 重置缓冲区位置
        mVertexBuffer.position(0);
        // 指定顶点属性数据的格式和位置
        GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, mVertexBuffer);

        // 获取片元着色器的颜色句柄
        mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
        // 设置绘制三角形的颜色
        GLES30.glUniform4fv(mColorHandle, 1, mColor, 0);
        // 绘制三角形
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, mTriangleCoords.length / COORDS_PER_VERTEX);
        // 禁用顶点属性数组
        GLES30.glDisableVertexAttribArray(mPositionHandle);
    }
}

六、总结:

本文主要介绍了Shader以及GLSL语言,同时画出了一个三角形,但是一般工程中GLSL语言会用单独的文件写,后续我们改进下!

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

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

相关文章

Ubuntu 22.04安装Nessus(离线激活模式)

Ubuntu 22.04安装Nessus 一、 Nessus 简介二、Nessus下载安装三、激活Nessus四、创建一个基础扫描五、 破解Nessus只能扫描16个地址的限制六、更新插件 一、 Nessus 简介 Nessus 官网&#xff1a; https://www.tenable.com/ Nessus号称世界上最流行的扫描程序&#xff0c;Nessu…

OpenAI 发布 o1 LLM,推出 ChatGPT Pro

OpenAI正式发布了专为复杂推理而构建的 OpenAI o1大型语言模型(LLM)。 该公司还推出了 ChatGPT Pro&#xff0c;这是一项每月 200 美元的套餐&#xff0c;包括无限制访问 OpenAI o1、o1-mini、GPT-4o 和高级语音对话。 OpenAI o1 从 9 月 12 日起在 ChatGPT 中推出预览版&…

上海理工大学《2024年867自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《上海理工大学867自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2024年真题 Part1&#xff1a;2024年完整版真题 2024年真题

汽配行业数字化解决方案(一)

汽配行业数字化解决方案&#xff0c;是通过整合云计算、大数据、人工智能、物联网等先进技术&#xff0c;构建一个全面、高效、智能的数字化生态系统&#xff0c;以实现汽配供应链的全程可视化与智能化管理。该解决方案涵盖了从供应商管理、库存优化、订单处理、物流跟踪到客户…

华为开源自研AI框架昇思MindSpore应用案例:基于MindSpore框架的SGD优化器案例实现

SGD优化器基本原理讲解 随机梯度下降&#xff08;SGD&#xff09;是一种迭代方法&#xff0c;其背后基本思想最早可以追溯到1950年代的Robbins-Monro算法&#xff0c;用于优化可微分目标函数。 它可以被视为梯度下降优化的随机近似&#xff0c;因为它用实际梯度&#xff08;从…

集成学习综合教程

一、前置知识 一个分类器的分类准确率在60%-80%&#xff0c;即&#xff1a;比随机预测略好&#xff0c;但准确率却不太高&#xff0c;我们可以称之为 “弱分类器”&#xff0c;比如CART&#xff08;classification and regression tree 分类与回归树&#xff09;。 反之&#x…

大语言模型技术相关知识-笔记整理

系列文章目录 这个系列攒了很久。主要是前段之间面试大语言模型方面的实习&#xff08;被拷打太多次了&#xff09;&#xff0c;然后每天根据面试官的问题进行扩展和补充的这个笔记。内容来源主要来自视频、个人理解以及官方文档中的记录。方便后面的回顾。 2024-12-7: 对公式…

【开源免费】基于SpringBoot+Vue.JS中小型医院网站(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 078 &#xff0c;文末自助获取源码 \color{red}{T078&#xff0c;文末自助获取源码} T078&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

哈希知识详解

一、哈希 以前&#xff0c;在面对海量数据的查找时&#xff0c;最快就是红黑树 logN&#xff0c;无法满足需求。 于是探索出了另一种用关键字 key 值与其存储位置建立映射的思想&#xff0c;让查找效率提升到 O(1) &#xff0c;这个就是哈希。 二、哈希函数 1、直接定值法 ①…

红日靶场vulnstark 4靶机的测试报告[细节](一)

目录 一、测试环境 1、系统环境 2、注意事项 3、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、漏洞利用Getshell ①Struts 2 s2-045漏洞 手工利用s2-45漏洞 Msf综合利用 ②Tomcat框架(CVE-2017-12615) ③phpMyAdmin(CVE-2018-12613) 构造语句写入冰蝎木…

D92【python 接口自动化学习】- pytest基础用法

day92 pytest的skip和skipif用法 学习日期&#xff1a;20241208 学习目标&#xff1a;pytest基础用法 -- pytest的skip和skipif用法 学习笔记&#xff1a; 测试用例跳过 skip和skipif用法&#xff0c;测试用例跳过 pytest.mark.skip 跳过标记的用例 pytest.mark.skipif(1 …

【Java】类似王者荣耀游戏

r77683962/WangZheYouDianRongYao 运行效果图&#xff1a; 类似王者荣耀游戏运行效果图_哔哩哔哩_bilibili

【数字电路与逻辑设计】实验二 数值比较器

文章总览&#xff1a;YuanDaiMa2048博客文章总览 【数字电路与逻辑设计】实验二 数值比较器 一、实验内容二、设计过程&#xff08;一&#xff09;真值表&#xff08;二&#xff09;设计思路 三、源代码&#xff08;一&#xff09;代码说明&#xff1a;&#xff08;二&#xff…

探索十个 AI 对话提示词网站,提升交互体验

learning prompt 网址&#xff1a;Hello from Learning Prompt | Learning Prompt 简介&#xff1a;这是一个学习 提示词 的网站&#xff0c;有 ChatGPT&#xff0c;Midjourney 的提示词教程、技巧等&#xff0c;他在右上角有中文语言的选择&#xff0c;教程非常详尽 LangCha…

C# Decimal

文章目录 前言1. Decimal 的基本特性2. 基本用法示例3. 特殊值与转换4. 数学运算示例5. 精度处理示例6. 比较操作示例7. 货币计算示例8. Decimal 的保留小数位数9. 处理 Decimal 的溢出和下溢10. 避免浮点数计算误差总结 前言 decimal 是 C# 中一种用于表示高精度十进制数的关键…

数据库-mysql(基本语句)

演示工具&#xff1a;navicat 连接&#xff1a;mydb 一.操作数据库 1.创建数据库 ①create database 数据库名称 //普通创建 ②create database if not exists 数据库名称 //创建数据库&#xff0c;判断不存在&#xff0c;再创建&#xff1a; 使用指定数据库 use 数据库…

使用Tesseract进行图片文字识别

Tesseract介绍 Tesseract 是一个开源的光学字符识别&#xff08;OCR&#xff09;引擎&#xff0c;最初由 HP 在 1985 年至 1995 年间开发&#xff0c;后来被 Google 收购并开源。Tesseract 支持多种语言的文本识别&#xff0c;能够识别图片中的文字&#xff0c;并将其转换为可…

智慧营区解决方案

1. 数据处理与服务封装 该智慧化解决方案注重数据的全面采集与处理&#xff0c;包括网页数据、图片、视频等非结构化数据&#xff0c;以及系统数据、文本、关系型数据库等结构化数据。通过数据抽取、稽核、规整、解析、清洗等流程&#xff0c;实现数据的入库与存储&#xff0c…

信号level 1:信号的产生

目录 引言 基础知识&#xff08;背景&#xff09; 信号的产生 方法一&#xff1a;通过终端按键产生信号&#xff08;键盘按键输入&#xff09; 方式二&#xff1a;通过kill指令 方法3&#xff1a;系统调用 方法四&#xff1a;硬件异常 方法五&#xff1a;软件产生异常 进…

国城杯-misc-Tr4ffIc_w1th_Ste90 [WP]

打开流量包&#xff0c;发现主要是UDP流量&#xff0c;然后还有H264的视频数据 右击&#xff0c;UDP追踪流 然后更换为原始数据 另存为.ts的文件&#xff0c;打开就看到密码 !t15tH3^pAs5W#RD*f0RFL9 打开压缩包是一个文件和一个图片 import numpy as np import cv2 import …