写在开头:文章是基于纹理 - LearnOpenGL CN 教程的学习记录,强烈建议在网站上先弄清楚原理再看此文章。以Qt-GL窗口代替GLFW的写法,Qt库中一些类代替教程中的类,一起入坑。

效果图:

上图使用了两纹理混合。接下来是一些比较重要的,使用glUniform1i,可以给纹理采样器分配一个位置值,这样的话我们能够在一个片段着色器中设置多个纹理。一个纹理的位置值通常称为一个纹理单元(Texture Unit)。一个纹理的默认纹理单元是0,它是默认的激活纹理单元,所以教程前面部分我们没有分配一个位置值。

纹理单元的主要目的是让我们在着色器中可以使用多于一个的纹理。通过把纹理单元赋值给采样器,我们可以一次绑定多个纹理,只要我们首先激活对应的纹理单元。就像glBindTexture一样,我们可以使用glActiveTexture激活纹理单元,传入我们需要使用的纹理单元:

如果有需要更多的纹理应当这样:

 //激活纹理单元0glActiveTexture(GL_TEXTURE0);m_combine_texture1->bind();//激活纹理单元1glActiveTexture(GL_TEXTURE1);m_combine_texture2->bind();

OpenGL至少保证有16个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0到GL_TEXTRUE15。它们都是按顺序定义的,所以我们也可以通过GL_TEXTURE0 + 8的方式获得GL_TEXTURE8,这在当我们需要循环一些纹理单元的时候会很有用.

不同于教程的地方:

用QOpenGLTexture代替stb_image.h

stb_image.h的写法:

glGenTextures(1, &texture2);glBindTexture(GL_TEXTURE_2D, texture2);// set the texture wrapping parametersglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);   // set texture wrapping to GL_REPEAT (default wrapping method)glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);// set texture filtering parametersglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// load image, create texture and generate mipmapsdata = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrChannels, 0);if (data){// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBAglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}

QOpenGLTexture的写法:

m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());if(!m_combine_texture2->isCreated()){qDebug() << "Failed to load texture";}//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);

主要代码:

#ifndef TEXTUREWIDGET_H
#define TEXTUREWIDGET_H#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QDebug>
#include <QOpenGLTexture>
#include "Shader.h"class HelloTexture;
namespace Ui {
class TextureWidget;
class QOpenGLTexture;
}class TextureWidget : public QWidget
{Q_OBJECTpublic:explicit TextureWidget(QWidget *parent = nullptr);~TextureWidget();private:Ui::TextureWidget *ui;HelloTexture *m_contentWidget;
};class HelloTexture : public QOpenGLWidget,protected QOpenGLExtraFunctions
{enum TARGET_STATUS{Original,Combine,Exercise2,Exercise3,Exercise4};public:HelloTexture();~HelloTexture();private:void InitOriginal();void InitCombine();void InitExercise2();void InitExercise3();void InitExercise4();protected:virtual void initializeGL();virtual void resizeGL(int w, int h);virtual void paintGL();
private:TARGET_STATUS m_status;Shader *m_shader;QOpenGLTexture *m_texture;QOpenGLTexture *m_combine_texture1;QOpenGLTexture *m_combine_texture2;
};#endif // TEXTUREWIDGET_H

cpp

#include "texturewidget.h"
#include "ui_texturewidget.h"#include <QImage>TextureWidget::TextureWidget(QWidget *parent) :QWidget(parent),ui(new Ui::TextureWidget)
{ui->setupUi(this);m_contentWidget = new HelloTexture();ui->verticalLayout->addWidget(m_contentWidget);
}TextureWidget::~TextureWidget()
{delete ui;
}static GLuint VBO, VAO, EBO = 0;
HelloTexture::HelloTexture()
{}HelloTexture::~HelloTexture()
{}void HelloTexture::InitOriginal()
{m_status = TARGET_STATUS::Original;m_shader = new Shader(":/shader/res/shaders/getting_started/4.1.texture.vs",":/shader/res/shaders/getting_started/4.1.texture.fs");//垂直镜像mirroredm_texture = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());if(!m_texture->isCreated()){qDebug() << "Failed to load texture";}//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);m_texture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);m_texture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);m_texture->setMinificationFilter(QOpenGLTexture::Linear);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);m_texture->setMagnificationFilter(QOpenGLTexture::Linear);//m_texture->setFormat(QOpenGLTexture::RGBFormat); //将纹理储存为rgb值
}void HelloTexture::InitCombine()
{m_status = TARGET_STATUS::Combine;m_shader = new Shader(":/shader/res/shaders/getting_started/4.2.texture.vs",":/shader/res/shaders/getting_started/4.2.texture.fs");//垂直镜像mirroredm_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());if(!m_combine_texture1->isCreated()){qDebug() << "Failed to load texture";}//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);m_combine_texture1->setMinificationFilter(QOpenGLTexture::Linear);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Linear);m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());if(!m_combine_texture2->isCreated()){qDebug() << "Failed to load texture";}//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);//设置纹理单元编号m_shader->use();m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);}void HelloTexture::InitExercise2()
{m_status = TARGET_STATUS::Exercise2;m_shader = new Shader(":/shader/res/shaders/getting_started/4.3.texture.vs",":/shader/res/shaders/getting_started/4.3.texture.fs");//垂直镜像mirroredm_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());if(!m_combine_texture1->isCreated()){qDebug() << "Failed to load texture";}//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);m_combine_texture1->setMinificationFilter(QOpenGLTexture::Linear);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Linear);m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());if(!m_combine_texture2->isCreated()){qDebug() << "Failed to load texture";}//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);//设置纹理单元编号m_shader->use();m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);}void HelloTexture::InitExercise3()
{m_status = TARGET_STATUS::Exercise3;m_shader = new Shader(":/shader/res/shaders/getting_started/4.4.texture.vs",":/shader/res/shaders/getting_started/4.4.texture.fs");//垂直镜像mirroredm_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());if(!m_combine_texture1->isCreated()){qDebug() << "Failed to load texture";}m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);m_combine_texture1->setMinificationFilter(QOpenGLTexture::Nearest);m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Nearest);m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());if(!m_combine_texture2->isCreated()){qDebug() << "Failed to load texture";}m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);m_combine_texture2->setMinificationFilter(QOpenGLTexture::Nearest);m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Nearest);//设置纹理单元编号m_shader->use();m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);
}void HelloTexture::InitExercise4()
{m_status = TARGET_STATUS::Exercise4;m_shader = new Shader(":/shader/res/shaders/getting_started/4.5.texture.vs",":/shader/res/shaders/getting_started/4.5.texture.fs");//垂直镜像mirroredm_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());if(!m_combine_texture1->isCreated()){qDebug() << "Failed to load texture";}m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);m_combine_texture1->setMinificationFilter(QOpenGLTexture::Linear);m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Linear);m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());if(!m_combine_texture2->isCreated()){qDebug() << "Failed to load texture";}//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);//设置纹理单元编号m_shader->use();m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);//设置混合值m_shader->m_shaderProgram.setUniformValue("mixValue", 0.5f);
}void HelloTexture::initializeGL()
{//初始化functionsthis->initializeOpenGLFunctions();//运行选项//InitOriginal();//InitCombine();//InitExercise2();//InitExercise3();InitExercise4();float ver[32];if(m_status == Exercise2){float vertices[] = {// positions          // colors           // texture coords (note that we changed them to 2.0f!)0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   2.0f, 2.0f, // top right0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   2.0f, 0.0f, // bottom right-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 2.0f  // top left};for(int i = 0 ; i < 32; i++){ver[i] = vertices[i];}}else if(m_status == Exercise3){float vertices[] = {// positions          // colors           // texture coords0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   0.55f, 0.55f, // top right0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   0.55f, 0.45f, // bottom right-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.45f, 0.45f, // bottom left-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.45f, 0.55f  // top left};for(int i = 0 ; i < 32; i++){ver[i] = vertices[i];}}else{float vertices[] = {// positions          // colors           // texture coords0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left};for(int i = 0 ; i < 32; i++){ver[i] = vertices[i];}}unsigned int indices[] = {0, 1, 3, // first triangle1, 2, 3  // second triangle};glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(ver), ver, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// position attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);// texture coord attributeglVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));glEnableVertexAttribArray(2);}void HelloTexture::resizeGL(int w, int h)
{glViewport(0,0,w,h);
}void HelloTexture::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);if(m_status == Original){m_texture->bind();}else{//激活纹理单元0glActiveTexture(GL_TEXTURE0);m_combine_texture1->bind();//激活纹理单元1glActiveTexture(GL_TEXTURE1);m_combine_texture2->bind();}// render containerm_shader->use();glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

下一篇:Qt-OpenGL-04 变换Transformations

Qt-OpenGL-03 纹理Texture相关推荐

  1. OpenGL(十九)——Qt OpenGL波动纹理(旗子的飘动效果)

    OpenGL(十九)--Qt OpenGL波动纹理(旗子的飘动效果) 一.场景 在日常的项目中,我们经常会实现波动的一些纹理效果,比如飘动的旗子,水的波纹,地图上某一点的波浪圈圈等...,本篇介绍波动 ...

  2. 纹理窗口Qt+OpenGL之纹理贴图

    上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助.今天在这里和大家一起学习一下纹理窗口 NeNe的代码中是加载到了一个正方体当中,代码很长.其实单纯的想要纹理贴图是很便利的.具体的纹理贴图技巧在 ...

  3. OpenGL(十八)——Qt OpenGL绘制一个3D世界

    OpenGL(十八)--Qt OpenGL绘制一个3D世界 一.说明 本篇介绍构建一个3D的世界. 二.简介 加载3D世界,并在其中漫游: 在这一课中,你将学会如何加载3D世界,并在3D世界中漫游. ...

  4. Qt OpenGL(二十)——Qt OpenGL 核心模式版本

    Qt OpenGL(二十)--Qt OpenGL 核心模式版本 一.写在前面 在之前的OpenGL教程(1~19)中,采用的方式都是固定渲染管线,也就是OpenGL3.2版本之前的写法,但是OpenG ...

  5. OpenGL(十四)——Qt OpenGL纹理

    OpenGL(十四)--Qt OpenGL纹理 一.纹理 终于写到纹理的部分了: 纹理(Texture)的本质是一个2D图片(1D和3D),或者叫图形数据.只是在OpenGL中专业术语中称其为纹理. ...

  6. OpenGL入门(四)之纹理Texture

    本系列文章为Learn OpenGL个人学习总结! OpenGL入门(一)之认识OpenGL和创建Window OpenGL入门(二)之渲染管线pipeline,VAO.VBO和EBO OpenGL入 ...

  7. Qt实现3D纹理渲染自由旋转空间立方体

    昨天七夕,关于七夕美好的爱情传说源自于浩瀚银河星空,又碰巧最近在学习QtOpenGL实现三维纹理防体重建,突发奇想用Qt实现一个立方体星空模型,并且能随着鼠标操作实现空间自由旋转 核心思想是用到Qt ...

  8. OpenGL(十六)——Qt OpenGL融合(将两张图片叠合成一张图片)

    OpenGL(十六)--Qt OpenGL融合(将两张图片叠合成一张图片) 一.场景 在常用的项目场景中,我们经常会遇到将两个图片合在一起变成一张图片,这时候就会有前后之分,特别是两个物体合在一起的时 ...

  9. openCV读入图片,openGL实现纹理贴图

    本文结合结合openCV,openGL的优点,实现混合编程. (1)OpenCV提供图形处理和计算机视觉方面的通用算法,读入二维图片很方便: (2)OpenGL是跨平台的图形程序接口,它用于二维,三维 ...

  10. 【QT项目:视频播放器——Qt opengl编程】通过shader完成显示yuv

    通过Qt opengl不是为了3D绘制,而是为了将视频绘制起来 使用opengl 可以极大降低yuv转rgb的转换开销 使用Opengl需要考虑三大问题: 1.QOpenGLWidget(与界面如何交 ...

最新文章

  1. Ubuntu下编译并运行C++代码
  2. OpenGL材质和光照(转)part1
  3. 计算机考试金麦圈编号教程,计算机二级:数据处理.doc
  4. 图解用工具对PE文件格式做初步研究
  5. springmvc静态资源拦截与访问
  6. 多CPU,多核,多进程,多线程以及进程和线程的简单理解以及区别
  7. 转仁兄:Binary search and its variation
  8. 【POJ - 2373】Dividing the Path(单调队列优化dp)
  9. shell脚本检查进程脚本
  10. 用winformz时间格式不正确_煮八爪鱼,有人用冷水,有人用开水,大厨:都不对,教你正确做法...
  11. XXX required a bean of type ‘XXXXXXXX‘ that could not be found ,博客可帮忙找错
  12. bin 转hex方法
  13. endnote x9破解版怎么导入word 2019使用呢?
  14. Rockchip平台cpu散热风扇随温度自动调速的配置方法
  15. MATLAB对数坐标图和统计图(semilogy/loglog)
  16. 知识追踪常见建模方法之IRT项目反应理论
  17. 超链接打开qq对话框
  18. 【软件测试】以闭环思维解决BUG复现率高问题
  19. android 5.1 壁纸路径,Android5.1 壁纸来源选项中有两个“壁纸”选项
  20. php memcached 性能测试,多种方法实时监测 Memcached 命中率

热门文章

  1. 5大IT行业热门岗,总有一个适合你!
  2. 抖音配音用什么软件制作片头?有免费的吗?
  3. SPRO节点的事务代码(转载)
  4. Linux mmap内存映射
  5. 系统架构设计笔记(73)—— 政府信息化与电子政务
  6. java毕业设计宠物爱心驿站Mybatis+系统+数据库+调试部署
  7. 如何成为一名Chrome应用开发者
  8. HBase 2.0 MOB 保存图片小视频利器
  9. 世上最健康的作息时间表 11点半睡觉7点半起床
  10. 从NSM到Parquet:存储结构的衍化