当前位置: 首页 > news >正文

(十三)MipMap

MipMap概念

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

滤波

在这里插入图片描述

采样

在这里插入图片描述
在这里插入图片描述

mipmap级别判定

问题:opengl如何判定应该使用下一级的mipmap呢?
通过glsl中的求偏导函数计算变化量决定
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

手动实现mipmap原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1、生成mipmap的各个级别
2、修改vertexShader使得三角形随着时间变小
**** 需要更改Filter才能够在变小的时候使用mipmap *****

#include <glad/glad.h>//glad必须在glfw头文件之前包含
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
void frameBufferSizeCallbakc(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}GLuint program = 0;
GLuint vao = 0;
void prepareVAO()
{//positionsfloat positions[] = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f,  0.5f, 0.0f,};//颜色float colors[] = {1.0f, 0.0f,0.0f,0.0f, 1.0f,0.0f,0.0f, 0.0f,1.0f,};//索引unsigned int indices[] = {0, 1, 2,};//uv坐标float uvs[] = {0.0f, 0.0f,1.0f, 0.0f,0.5f, 1.0f,};//2 VBO创建GLuint posVbo = 0;GLuint colorVbo = 0;GLuint uvVbo = 0;glGenBuffers(1, &posVbo);glBindBuffer(GL_ARRAY_BUFFER, posVbo);glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);glGenBuffers(1, &colorVbo);glBindBuffer(GL_ARRAY_BUFFER, colorVbo);glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);glGenBuffers(1, &uvVbo);glBindBuffer(GL_ARRAY_BUFFER, uvVbo);glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);//3 EBO创建GLuint ebo = 0;glGenBuffers(1, &ebo);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//4 VAO创建vao = 0;glGenVertexArrays(1, &vao);glBindVertexArray(vao);//5 绑定vbo ebo 加入属性描述信息//5.1 加入位置属性描述信息glBindBuffer(GL_ARRAY_BUFFER, posVbo);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//5.2 加入颜色属性描述信息glBindBuffer(GL_ARRAY_BUFFER, colorVbo);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//5.3 加入uv属性描述数据glBindBuffer(GL_ARRAY_BUFFER, uvVbo);glEnableVertexAttribArray(2);glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);//5.2 加入ebo到当前的vaoglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);glBindVertexArray(0);
}
void prepareShader() {//1 完成vs与fs的源代码,并且装入字符串const char* vertexShaderSource ="#version 330 core\n""layout (location = 0) in vec3 aPos;\n""layout (location = 1) in vec3 aColor;\n""layout (location = 2) in vec2 aUV;\n""out vec3 color;\n""out vec2 uv;\n""uniform float time;\n""void main()\n""{\n""   float scale = 1.0/time;\n""   vec3 sPos = aPos * scale;\n""   gl_Position = vec4(sPos, 1.0);\n""   color = aColor;\n""   uv = aUV;\n""}\0";const char* fragmentShaderSource ="#version 330 core\n""out vec4 FragColor;\n""in vec3 color;\n""in vec2 uv;\n""uniform sampler2D sampler;\n""void main()\n""{\n""  FragColor = texture(sampler, uv);\n""}\n\0";//2 创建Shader程序(vs、fs)GLuint vertex, fragment;vertex = glCreateShader(GL_VERTEX_SHADER);fragment = glCreateShader(GL_FRAGMENT_SHADER);//3 为shader程序输入shader代码glShaderSource(vertex, 1, &vertexShaderSource, NULL);glShaderSource(fragment, 1, &fragmentShaderSource, NULL);int success = 0;char infoLog[1024];//4 执行shader代码编译 glCompileShader(vertex);//检查vertex编译结果glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(vertex, 1024, NULL, infoLog);std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;}glCompileShader(fragment);//检查fragment编译结果glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(fragment, 1024, NULL, infoLog);std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;}//5 创建一个Program壳子program = glCreateProgram();//6 将vs与fs编译好的结果放到program这个壳子里glAttachShader(program, vertex);glAttachShader(program, fragment);//7 执行program的链接操作,形成最终可执行shader程序glLinkProgram(program);//检查链接错误glGetProgramiv(program, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(program, 1024, NULL, infoLog);std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;}//清理glDeleteShader(vertex);glDeleteShader(fragment);
}
GLuint genTexture(const char* picPath, int unitTexturt)
{//1 stbImage 读取图片int width, height, channels;//--反转y轴stbi_set_flip_vertically_on_load(true);unsigned char* data = stbi_load(picPath, &width, &height, &channels, STBI_rgb_alpha);//2 生成纹理并且激活单元绑定GLuint texture = 0;glGenTextures(1, &texture);//--激活纹理单元--glActiveTexture(GL_TEXTURE0 + unitTexturt);//--绑定纹理对象--glBindTexture(GL_TEXTURE_2D, texture);int tmepWidth = width, tempHeight = height;//3 传输纹理数据,开辟显存//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//遍历每个mipmap的层级,为每个级别的mipmap填充图片数据for (int level = 0; true; ++level){//1 将当前级别的mipmap对应的数据发往gpu端glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, tmepWidth, tempHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//2 判断是否退出循环if (tmepWidth == 1 && tempHeight == 1)break;//3 计算下一次循环的宽度/高度,除以2tmepWidth = tmepWidth > 1 ? tmepWidth / 2 : 1;tempHeight = tempHeight > 1 ? tempHeight / 2 : 1;}//***释放数据stbi_image_free(data);//4 设置纹理的过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//*****重要*****////GL_NEAREST:在单个mipmap上采用最邻近采样//GL_LINEAR   //MIPMAP_LINEAR:在两层mipmap之间采用线性插值//MIPMAP_NEARESTglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);//5 设置纹理的包裹方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//uglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//vreturn texture;
}
void prepareTextrue()
{//GLuint grassTexture = genTexture("grass.jpg", 0);//GLuint landTexture = genTexture("land.jpg", 1);//GLuint noiseTexture = genTexture("noise.jpg", 2);GLuint wallTexture = genTexture("goku.jpg", 0);
}void render()
{//执行opengl画布清理操作glClear(GL_COLOR_BUFFER_BIT);//1.绑定当前的programglUseProgram(program);//2 更新Uniform的时候,一定要先UserProgram//2.1 通过名称拿到Uniform变量的位置Location//2.2 通过Location更新Uniform变量的值GLint time = glGetUniformLocation(program, "time");int i = glfwGetTime();glUniform1f(time, glfwGetTime());GLint sampler = glGetUniformLocation(program, "sampler");glUniform1i(sampler, 0);//3 绑定当前的vaoglBindVertexArray(vao);//4 发出绘制指令//glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
}int main()
{//初始化glfw环境glfwInit();//设置opengl主版本号glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//设置opengl次版本号glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//设置opengl启用核心模式glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//创建窗体对象GLFWwindow* window = glfwCreateWindow(800, 600, "lenarnOpenGL", nullptr, nullptr);//设置当前窗体对象为opengl的绘制舞台glfwMakeContextCurrent(window);//窗体大小回调glfwSetFramebufferSizeCallback(window, frameBufferSizeCallbakc);//键盘相应回调glfwSetKeyCallback(window, glfwKeyCallback);//使用glad加载所有当前版本opengl的函数if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "初始化glad失败" << std::endl;return -1;};//设置opengl视口大小和清理颜色glViewport(0, 0, 800, 600);glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//shaderprepareShader();//vaoprepareVAO();//textureprepareTextrue();//执行窗体循环while (!glfwWindowShouldClose(window)){//接受并分发窗体消息//检查消息队列是否有需要处理的鼠标、键盘等消息//如果有的话就将消息批量处理,清空队列glfwPollEvents();//渲染操作render();//切换双缓存glfwSwapBuffers(window);}//推出程序前做相关清理glfwTerminate();return 0;
}

上述代码即可实现随着时间的变化,不同层级的图片贴到三角形中的效果。
还可以不在代码中设置层级间的采样方式 即注释掉

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

在fs中,实现根据像素对应图素的数量多少,决定采样哪个层级的mipmap

#version 330 core
out vec4 FragColor;
in vec3 color;
in vec2 uv;
uniform sampler2D sampler;
uniform float width;
uniform float height;
void main()
{//FragColor = texture(sampler, uv);//1 获取当前像素对应的纹理上的纹素具体位置vec2 location = uv * vec2(width, height);//2 计算当前像素对应纹素具体位置在xy方向上的变化量vec2 dx = dFdx(location);vec2 dy = dFdy(location);//3 选择最大的delta,求log2(delta)float maxDelta = sqrt(max(dot(dx, dx), dot(dy,dy)));float L = log2(maxDelta);//4 计算出mipmap的采样级别int level = max(int(L + 0.5), 0);FragColor = textureLod(sampler, uv, level);
}

fs的glsl设置以上字符串,渲染时设置图片的宽度和高度即可达到同样的效果。

opengl自动生成mipmap

在这里插入图片描述

#include <glad/glad.h>//glad必须在glfw头文件之前包含
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
void frameBufferSizeCallbakc(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}GLuint program = 0;
GLuint vao = 0;
void prepareVAO()
{//positionsfloat positions[] = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f,  0.5f, 0.0f,};//颜色float colors[] = {1.0f, 0.0f,0.0f,0.0f, 1.0f,0.0f,0.0f, 0.0f,1.0f,};//索引unsigned int indices[] = {0, 1, 2,};//uv坐标float uvs[] = {0.0f, 0.0f,1.0f, 0.0f,0.5f, 1.0f,};//2 VBO创建GLuint posVbo = 0;GLuint colorVbo = 0;GLuint uvVbo = 0;glGenBuffers(1, &posVbo);glBindBuffer(GL_ARRAY_BUFFER, posVbo);glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);glGenBuffers(1, &colorVbo);glBindBuffer(GL_ARRAY_BUFFER, colorVbo);glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);glGenBuffers(1, &uvVbo);glBindBuffer(GL_ARRAY_BUFFER, uvVbo);glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);//3 EBO创建GLuint ebo = 0;glGenBuffers(1, &ebo);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//4 VAO创建vao = 0;glGenVertexArrays(1, &vao);glBindVertexArray(vao);//5 绑定vbo ebo 加入属性描述信息//5.1 加入位置属性描述信息glBindBuffer(GL_ARRAY_BUFFER, posVbo);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//5.2 加入颜色属性描述信息glBindBuffer(GL_ARRAY_BUFFER, colorVbo);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//5.3 加入uv属性描述数据glBindBuffer(GL_ARRAY_BUFFER, uvVbo);glEnableVertexAttribArray(2);glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);//5.2 加入ebo到当前的vaoglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);glBindVertexArray(0);
}
void prepareShader() {//1 完成vs与fs的源代码,并且装入字符串const char* vertexShaderSource ="#version 330 core\n""layout (location = 0) in vec3 aPos;\n""layout (location = 1) in vec3 aColor;\n""layout (location = 2) in vec2 aUV;\n""out vec3 color;\n""out vec2 uv;\n""uniform float time;\n""void main()\n""{\n""   float scale = 1.0/time;\n""   vec3 sPos = aPos * scale;\n""   gl_Position = vec4(sPos, 1.0);\n""   color = aColor;\n""   uv = aUV;\n""}\0";const char* fragmentShaderSource ="#version 330 core\n""out vec4 FragColor;\n""in vec3 color;\n""in vec2 uv;\n""uniform sampler2D sampler;\n""void main()\n""{\n""  FragColor = texture(sampler, uv);\n""}\n\0";//2 创建Shader程序(vs、fs)GLuint vertex, fragment;vertex = glCreateShader(GL_VERTEX_SHADER);fragment = glCreateShader(GL_FRAGMENT_SHADER);//3 为shader程序输入shader代码glShaderSource(vertex, 1, &vertexShaderSource, NULL);glShaderSource(fragment, 1, &fragmentShaderSource, NULL);int success = 0;char infoLog[1024];//4 执行shader代码编译 glCompileShader(vertex);//检查vertex编译结果glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(vertex, 1024, NULL, infoLog);std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;}glCompileShader(fragment);//检查fragment编译结果glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(fragment, 1024, NULL, infoLog);std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;}//5 创建一个Program壳子program = glCreateProgram();//6 将vs与fs编译好的结果放到program这个壳子里glAttachShader(program, vertex);glAttachShader(program, fragment);//7 执行program的链接操作,形成最终可执行shader程序glLinkProgram(program);//检查链接错误glGetProgramiv(program, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(program, 1024, NULL, infoLog);std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;}//清理glDeleteShader(vertex);glDeleteShader(fragment);
}
GLuint genTexture(const char* picPath, int unitTexturt)
{//1 stbImage 读取图片int width, height, channels;//--反转y轴stbi_set_flip_vertically_on_load(true);unsigned char* data = stbi_load(picPath, &width, &height, &channels, STBI_rgb_alpha);//2 生成纹理并且激活单元绑定GLuint texture = 0;glGenTextures(1, &texture);//--激活纹理单元--glActiveTexture(GL_TEXTURE0 + unitTexturt);//--绑定纹理对象--glBindTexture(GL_TEXTURE_2D, texture);//3 传输纹理数据,开辟显存glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//为当前纹理对象生成mipmapglGenerateMipmap(GL_TEXTURE_2D);//***释放数据stbi_image_free(data);//4 设置纹理的过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//*****重要*****////GL_NEAREST:在单个mipmap上采用最邻近采样//GL_LINEAR   //MIPMAP_LINEAR:在两层mipmap之间采用线性插值//MIPMAP_NEARESTglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);//5 设置纹理的包裹方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//uglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//vreturn texture;
}
void prepareTextrue()
{//GLuint grassTexture = genTexture("grass.jpg", 0);//GLuint landTexture = genTexture("land.jpg", 1);//GLuint noiseTexture = genTexture("noise.jpg", 2);GLuint wallTexture = genTexture("goku.jpg", 0);
}void render()
{//执行opengl画布清理操作glClear(GL_COLOR_BUFFER_BIT);//1.绑定当前的programglUseProgram(program);//2 更新Uniform的时候,一定要先UserProgram//2.1 通过名称拿到Uniform变量的位置Location//2.2 通过Location更新Uniform变量的值GLint time = glGetUniformLocation(program, "time");int i = glfwGetTime();glUniform1f(time, glfwGetTime());GLint sampler = glGetUniformLocation(program, "sampler");glUniform1i(sampler, 0);//3 绑定当前的vaoglBindVertexArray(vao);//4 发出绘制指令//glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
}int main()
{//初始化glfw环境glfwInit();//设置opengl主版本号glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//设置opengl次版本号glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//设置opengl启用核心模式glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//创建窗体对象GLFWwindow* window = glfwCreateWindow(800, 600, "lenarnOpenGL", nullptr, nullptr);//设置当前窗体对象为opengl的绘制舞台glfwMakeContextCurrent(window);//窗体大小回调glfwSetFramebufferSizeCallback(window, frameBufferSizeCallbakc);//键盘相应回调glfwSetKeyCallback(window, glfwKeyCallback);//使用glad加载所有当前版本opengl的函数if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "初始化glad失败" << std::endl;return -1;};//设置opengl视口大小和清理颜色glViewport(0, 0, 800, 600);glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//shaderprepareShader();//vaoprepareVAO();//textureprepareTextrue();//执行窗体循环while (!glfwWindowShouldClose(window)){//接受并分发窗体消息//检查消息队列是否有需要处理的鼠标、键盘等消息//如果有的话就将消息批量处理,清空队列glfwPollEvents();//渲染操作render();//切换双缓存glfwSwapBuffers(window);}//推出程序前做相关清理glfwTerminate();return 0;
}

相关文章:

  • 谷歌正在试行人脸识别办公室安全系统
  • mmaction2版本适配(Linux)
  • 比赛获奖的武林秘籍:01 如何看待当代大学生竞赛中“卷”“祖传老项目”“找关系”的现象?
  • 龙芯杯个人赛记录
  • Django 对模型创建的两表插入数据
  • 11.SQL注入-盲注基于(base on boolian)
  • sharepoint api 没有这个文件所属site的权限的情况下访问指定文件
  • 脑启发设计:人工智能的进化之路
  • 深入理解计算机系统 CSAPP 家庭作业8.26
  • RPM方式安装mysql
  • 无法解析的外部符号 _imp_XXX
  • 基于Hadoop平台的电信客服数据的处理与分析④项目实现:任务15:数据生产
  • 【unity实战】使用Unity实现动作游戏的攻击 连击 轻重攻击和打击感
  • 航空数据管控系统-①项目准备阶段:任务2:项目技术预研(技术架构)
  • 对标 GPT-4o 的开源实时语音多模态模型:Moshi
  • @jsonView过滤属性
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • CentOS7简单部署NFS
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • MySQL几个简单SQL的优化
  • node 版本过低
  • Rancher-k8s加速安装文档
  • react-native 安卓真机环境搭建
  • 大数据与云计算学习:数据分析(二)
  • 分类模型——Logistics Regression
  • 猴子数据域名防封接口降低小说被封的风险
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 学习HTTP相关知识笔记
  • 在Docker Swarm上部署Apache Storm:第1部分
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • ​MySQL主从复制一致性检测
  • #etcd#安装时出错
  • #pragma 指令
  • #微信小程序:微信小程序常见的配置传值
  • (02)Hive SQL编译成MapReduce任务的过程
  • (16)Reactor的测试——响应式Spring的道法术器
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (四)Android布局类型(线性布局LinearLayout)
  • (转)Linq学习笔记
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .NET Core引入性能分析引导优化
  • .Net MVC + EF搭建学生管理系统
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .net Signalr 使用笔记
  • .NET 中的轻量级线程安全
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .Net的DataSet直接与SQL2005交互
  • .NET值类型变量“活”在哪?
  • @Conditional注解详解
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • @ModelAttribute使用详解
  • @Transactional注解下,循环取序列的值,但得到的值都相同的问题