Qt-OpenGL-03 纹理Texture
写在开头:文章是基于纹理 - 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相关推荐
- OpenGL(十九)——Qt OpenGL波动纹理(旗子的飘动效果)
OpenGL(十九)--Qt OpenGL波动纹理(旗子的飘动效果) 一.场景 在日常的项目中,我们经常会实现波动的一些纹理效果,比如飘动的旗子,水的波纹,地图上某一点的波浪圈圈等...,本篇介绍波动 ...
- 纹理窗口Qt+OpenGL之纹理贴图
上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助.今天在这里和大家一起学习一下纹理窗口 NeNe的代码中是加载到了一个正方体当中,代码很长.其实单纯的想要纹理贴图是很便利的.具体的纹理贴图技巧在 ...
- OpenGL(十八)——Qt OpenGL绘制一个3D世界
OpenGL(十八)--Qt OpenGL绘制一个3D世界 一.说明 本篇介绍构建一个3D的世界. 二.简介 加载3D世界,并在其中漫游: 在这一课中,你将学会如何加载3D世界,并在3D世界中漫游. ...
- Qt OpenGL(二十)——Qt OpenGL 核心模式版本
Qt OpenGL(二十)--Qt OpenGL 核心模式版本 一.写在前面 在之前的OpenGL教程(1~19)中,采用的方式都是固定渲染管线,也就是OpenGL3.2版本之前的写法,但是OpenG ...
- OpenGL(十四)——Qt OpenGL纹理
OpenGL(十四)--Qt OpenGL纹理 一.纹理 终于写到纹理的部分了: 纹理(Texture)的本质是一个2D图片(1D和3D),或者叫图形数据.只是在OpenGL中专业术语中称其为纹理. ...
- OpenGL入门(四)之纹理Texture
本系列文章为Learn OpenGL个人学习总结! OpenGL入门(一)之认识OpenGL和创建Window OpenGL入门(二)之渲染管线pipeline,VAO.VBO和EBO OpenGL入 ...
- Qt实现3D纹理渲染自由旋转空间立方体
昨天七夕,关于七夕美好的爱情传说源自于浩瀚银河星空,又碰巧最近在学习QtOpenGL实现三维纹理防体重建,突发奇想用Qt实现一个立方体星空模型,并且能随着鼠标操作实现空间自由旋转 核心思想是用到Qt ...
- OpenGL(十六)——Qt OpenGL融合(将两张图片叠合成一张图片)
OpenGL(十六)--Qt OpenGL融合(将两张图片叠合成一张图片) 一.场景 在常用的项目场景中,我们经常会遇到将两个图片合在一起变成一张图片,这时候就会有前后之分,特别是两个物体合在一起的时 ...
- openCV读入图片,openGL实现纹理贴图
本文结合结合openCV,openGL的优点,实现混合编程. (1)OpenCV提供图形处理和计算机视觉方面的通用算法,读入二维图片很方便: (2)OpenGL是跨平台的图形程序接口,它用于二维,三维 ...
- 【QT项目:视频播放器——Qt opengl编程】通过shader完成显示yuv
通过Qt opengl不是为了3D绘制,而是为了将视频绘制起来 使用opengl 可以极大降低yuv转rgb的转换开销 使用Opengl需要考虑三大问题: 1.QOpenGLWidget(与界面如何交 ...
最新文章
- Ubuntu下编译并运行C++代码
- OpenGL材质和光照(转)part1
- 计算机考试金麦圈编号教程,计算机二级:数据处理.doc
- 图解用工具对PE文件格式做初步研究
- springmvc静态资源拦截与访问
- 多CPU,多核,多进程,多线程以及进程和线程的简单理解以及区别
- 转仁兄:Binary search and its variation
- 【POJ - 2373】Dividing the Path(单调队列优化dp)
- shell脚本检查进程脚本
- 用winformz时间格式不正确_煮八爪鱼,有人用冷水,有人用开水,大厨:都不对,教你正确做法...
- XXX required a bean of type ‘XXXXXXXX‘ that could not be found ,博客可帮忙找错
- bin 转hex方法
- endnote x9破解版怎么导入word 2019使用呢?
- Rockchip平台cpu散热风扇随温度自动调速的配置方法
- MATLAB对数坐标图和统计图(semilogy/loglog)
- 知识追踪常见建模方法之IRT项目反应理论
- 超链接打开qq对话框
- 【软件测试】以闭环思维解决BUG复现率高问题
- android 5.1 壁纸路径,Android5.1 壁纸来源选项中有两个“壁纸”选项
- php memcached 性能测试,多种方法实时监测 Memcached 命中率