1、使用用户FBO通过一系列操作从相对于镜面的反向照相机开始渲染场景地形和旋转中的甜甜圈以及代表反向照相机的蓝色圆筒,将其渲染结果存储到mirrorTexture(FBO映射目标就是GL_COLOR_ATTACHMENT0 这个纹理捆绑点)

2、重置FBO后,再次从真正的照相机视角来绘制场景地形和旋转的甜甜圈以及绘制镜面,并镜面会判断照相机是否能看到镜面来决定是否渲染出镜面画面(即mirrorTexture),若无法看到则渲染黑色镜面。

需要注意的是,虽然在第一步也渲染了场景,但此时的场景是输出到FBO上的,这个结果会缓存到mirrorTexture 它是由glDrawBuffers(1, fboBuffs)来指定给哪个捆绑点对应的纹理的,而第二步才真正渲染到屏幕上。

#pragma comment(lib, "gltools.lib")
#include <stdio.h>
#include <iostream>#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>//#include <GL/glu.h>#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endifstatic GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
static GLfloat vGrey[] = { 0.5f, 0.5f, 0.5f, 1.0f };
static GLfloat vLightPos[] = { -2.0f, 3.0f, -2.0f, 1.0f };
static const GLenum windowBuff[] = { GL_BACK_LEFT };
static const GLenum fboBuffs[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
static GLint mirrorTexWidth = 800;
static GLint mirrorTexHeight = 800;GLsizei  screenWidth;           // Desired window or desktop width
GLsizei  screenHeight;          // Desired window or desktop heightGLboolean bFullScreen;           // Request to run full screen
GLboolean bAnimated;            // Request for continual updatesGLShaderManager     shaderManager;          // Shader Manager
GLMatrixStack       modelViewMatrix;        // Modelview Matrix
GLMatrixStack       projectionMatrix;       // Projection Matrix
GLFrustum           viewFrustum;            // View Frustum
GLGeometryTransform transformPipeline;      // Geometry Transform Pipeline
GLFrame             cameraFrame;            // Camera frame
GLFrame             mirrorFrame;            // Mirror frameGLTriangleBatch      torusBatch;
GLTriangleBatch     sphereBatch;
GLTriangleBatch     cylinderBatch;
GLBatch             floorBatch;
GLBatch             mirrorBatch;
GLBatch             mirrorBorderBatch;GLuint              fboName;
GLuint              textures[1];
GLuint              mirrorTexture;
GLuint              depthBufferName;void DrawWorld(GLfloat yRot);
bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode);///
// Load in a BMP file as a texture. Allows specification of the filters and the wrap mode
bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{GLbyte *pBits;GLint iWidth, iHeight;pBits = gltReadBMPBits(szFileName, &iWidth, &iHeight);if (pBits == NULL)return false;// Set Wrap modesglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, iWidth, iHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, pBits);// Do I need to generate mipmaps?if (minFilter == GL_LINEAR_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_NEAREST_MIPMAP_NEAREST)glGenerateMipmap(GL_TEXTURE_2D);return true;
}///
// OpenGL related startup code is safe to put here. Load textures, etc.
void SetupRC()
{GLenum err = glewInit();if (GLEW_OK != err){/* Problem: glewInit failed, something is seriously wrong. */fprintf(stderr, "Error: %s\n", glewGetErrorString(err));}// Initialze Shader ManagershaderManager.InitializeStockShaders();glEnable(GL_DEPTH_TEST);// BlackglClearColor(0.0f, 0.0f, 0.0f, 1.0f);gltMakeTorus(torusBatch, 0.4f, 0.15f, 35, 35);gltMakeSphere(sphereBatch, 0.1f, 26, 13);gltMakeCylinder(cylinderBatch, 0.3f, 0.2f, 1.0, 10, 10);GLfloat alpha = 0.25f;floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);floorBatch.Normal3f(0.0, 1.0f, 0.0f);floorBatch.Vertex3f(-20.0f, -0.41f, 20.0f);floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);floorBatch.MultiTexCoord2f(0, 10.0f, 0.0f);floorBatch.Normal3f(0.0, 1.0f, 0.0f);floorBatch.Vertex3f(20.0f, -0.41f, 20.0f);floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);floorBatch.MultiTexCoord2f(0, 10.0f, 10.0f);floorBatch.Normal3f(0.0, 1.0f, 0.0f);floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);floorBatch.MultiTexCoord2f(0, 0.0f, 10.0f);floorBatch.Normal3f(0.0, 1.0f, 0.0f);floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);floorBatch.End();mirrorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);mirrorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);mirrorBatch.Normal3f(0.0f, 1.0f, 0.0f);mirrorBatch.Vertex3f(-1.0f, 0.0f, 0.0f);mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);mirrorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);mirrorBatch.Normal3f(0.0f, 1.0f, 0.0f);mirrorBatch.Vertex3f(1.0f, 0.0f, 0.0f);mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);mirrorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);mirrorBatch.Normal3f(0.0f, 1.0f, 0.0f);mirrorBatch.Vertex3f(1.0f, 2.0f, 0.0f);mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);mirrorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);mirrorBatch.Normal3f(0.0f, 1.0f, 0.0f);mirrorBatch.Vertex3f(-1.0f, 2.0f, 0.0f);mirrorBatch.End();mirrorBorderBatch.Begin(GL_TRIANGLE_STRIP, 13);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(-1.0f, 0.1f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(-1.0f, 0.0f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(1.0f, 0.1f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(1.0f, 0.0f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(0.9f, 0.0f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(1.0f, 2.0f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(0.9f, 2.0f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(1.0f, 1.9f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(-1.0f, 2.f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(-1.0f, 1.9f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(-0.9f, 2.f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(-1.0f, 0.0f, 0.01f);mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);mirrorBorderBatch.Vertex3f(-0.9f, 0.0f, 0.01f);mirrorBorderBatch.End();glGenTextures(1, textures);glBindTexture(GL_TEXTURE_2D, textures[0]);LoadBMPTexture("marble.bmp", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);// Create and bind an FBOglGenFramebuffers(1, &fboName);glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName);// Create depth renderbufferglGenRenderbuffers(1, &depthBufferName);glBindRenderbuffer(GL_RENDERBUFFER, depthBufferName);glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, mirrorTexWidth, mirrorTexHeight);// Create the reflection textureglGenTextures(1, &mirrorTexture);glBindTexture(GL_TEXTURE_2D, mirrorTexture);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mirrorTexWidth, mirrorTexHeight, 0, GL_RGBA, GL_FLOAT, NULL);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// Attach texture to first color attachment and the depth RBOglFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTexture, 0);glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferName);// Make sure all went wellgltCheckErrors();// Reset framebuffer bindingglBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}///
// Do your cleanup here. Free textures, display lists, buffer objects, etc.
void ShutdownRC(void)
{// Make sure default FBO is boundglBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);// Cleanup texturesglActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, 0);glDeleteTextures(1, &mirrorTexture);glDeleteTextures(1, textures);// Cleanup RBOsglDeleteRenderbuffers(1, &depthBufferName);// Cleanup FBOsglDeleteFramebuffers(1, &fboName);}///
// This is called at least once and before any rendering occurs. If the screen
// is a resizeable window, then this will also get called whenever the window
// is resized.
void ChangeSize(int nWidth, int nHeight)
{glViewport(0, 0, nWidth, nHeight);transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());modelViewMatrix.LoadIdentity();// update screen sizesscreenWidth = nWidth;screenHeight = nHeight;
}///
// Update the camera based on user input, toggle display modes
//
void SpecialKeys(int key, int x, int y)
{float linear = 0.40f;float angular = float(m3dDegToRad(2.5f));if (key == GLUT_KEY_UP)cameraFrame.MoveForward(linear);if (key == GLUT_KEY_DOWN)cameraFrame.MoveForward(-linear);if (key == GLUT_KEY_LEFT)cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);if (key == GLUT_KEY_RIGHT)cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}///
// Draw the scene
//
void DrawWorld(GLfloat yRot)
{M3DMatrix44f mCamera;modelViewMatrix.GetMatrix(mCamera);// Need light position relative to the CameraM3DVector4f vLightTransformed;m3dTransformVector4(vLightTransformed, vLightPos, mCamera);// Draw the light source as a small white unshaded spheremodelViewMatrix.PushMatrix();modelViewMatrix.Translatev(vLightPos);shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vWhite);sphereBatch.Draw();modelViewMatrix.PopMatrix();// Draw stuff relative to the cameramodelViewMatrix.PushMatrix();modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),transformPipeline.GetProjectionMatrix(),vLightTransformed, vGreen, 0);torusBatch.Draw();modelViewMatrix.PopMatrix();
}///
// Render a frame. The owning framework is responsible for buffer swaps,
// flushes, etc.
void RenderScene(void)
{static CStopWatch animationTimer;float yRot = animationTimer.GetElapsedSeconds() * 60.0f;M3DVector3f vCameraPos;M3DVector3f vCameraForward;M3DVector3f vMirrorPos;M3DVector3f vMirrorForward;cameraFrame.GetOrigin(vCameraPos);cameraFrame.GetForwardVector(vCameraForward);// Set position of mirror frame (camera)vMirrorPos[0] = 0.0;vMirrorPos[1] = 0.1f;vMirrorPos[2] = -6.0f; // view pos is actually behind mirrormirrorFrame.SetOrigin(vMirrorPos);// Calculate direction of mirror frame (camera)// Because the position of the mirror is known relative to the origin// find the direction vector by adding the mirror offset to the vector// of the viewer-originvMirrorForward[0] = vCameraPos[0];vMirrorForward[1] = vCameraPos[1];vMirrorForward[2] = (vCameraPos[2] + 5);m3dNormalizeVector3(vMirrorForward);mirrorFrame.SetForwardVector(vMirrorForward);// first render from the mirrors perspectiveglBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName);glDrawBuffers(1, fboBuffs);glViewport(0, 0, mirrorTexWidth, mirrorTexHeight);// Draw scene from the perspective of the mirror cameramodelViewMatrix.PushMatrix();M3DMatrix44f mMirrorView;mirrorFrame.GetCameraMatrix(mMirrorView);modelViewMatrix.MultMatrix(mMirrorView);// Flip the mirror camera horizontally for the reflectionmodelViewMatrix.Scale(-1.0f, 1.0f, 1.0f);glBindTexture(GL_TEXTURE_2D, textures[0]); // MarbleglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite, 0);floorBatch.Draw();DrawWorld(yRot);// Now draw a cylinder representing the viewerM3DVector4f vLightTransformed;modelViewMatrix.GetMatrix(mMirrorView);m3dTransformVector4(vLightTransformed, vLightPos, mMirrorView);modelViewMatrix.Translate(vCameraPos[0], vCameraPos[1] - 0.8f, vCameraPos[2] - 1.0f);modelViewMatrix.Rotate(-90.0f, 1.0f, 0.0f, 0.0f);shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),transformPipeline.GetProjectionMatrix(),vLightTransformed, vBlue, 0);cylinderBatch.Draw();modelViewMatrix.PopMatrix();// Reset FBO. Draw world again from the real cameras perspectiveglBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);glDrawBuffers(1, windowBuff);glViewport(0, 0, screenWidth, screenHeight);modelViewMatrix.PushMatrix();M3DMatrix44f mCamera;cameraFrame.GetCameraMatrix(mCamera);modelViewMatrix.MultMatrix(mCamera);glBindTexture(GL_TEXTURE_2D, textures[0]); // MarbleglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite, 0);floorBatch.Draw();DrawWorld(yRot);// Now draw the mirror surfacesmodelViewMatrix.PushMatrix();modelViewMatrix.Translate(0.0f, -0.4f, -5.0f);if (vCameraPos[2] > -5.0){glBindTexture(GL_TEXTURE_2D, mirrorTexture); // ReflectionshaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);}else{// If the camera is behind the mirror, just draw blackshaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);}mirrorBatch.Draw();shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGrey);mirrorBorderBatch.Draw();modelViewMatrix.PopMatrix();modelViewMatrix.PopMatrix();// Do the buffer SwapglutSwapBuffers();// Do it againglutPostRedisplay();
}int main(int argc, char* argv[])
{screenWidth = 800;screenHeight = 600;bFullScreen = false;bAnimated = true;fboName = 0;depthBufferName = 0;gltSetWorkingDirectory(argv[0]);glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);glutInitWindowSize(screenWidth, screenHeight);glutCreateWindow("FBO Textures");glutReshapeFunc(ChangeSize);glutDisplayFunc(RenderScene);glutSpecialFunc(SpecialKeys);SetupRC();glutMainLoop();ShutdownRC();return 0;
}

【OpenGL】FBO渲染到纹理案例相关推荐

  1. 音视频开发之旅(38) -使用FBO实现渲染到纹理(Render to texture)

    目录 FBO基本知识 FBO实现渲染到纹理的流程 实践 遇到的问题 资料 收获 在之前的学习实践中我们把图片.视频.图形等渲染到屏幕时,采用的是直接屏幕上即默认的帧缓冲区,如果我们在渲染时不想直接渲染 ...

  2. NeHe OpenGL教程 第三十六课:从渲染到纹理

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  3. qt android opengl,案例:实现Qt和OpenGL混合渲染 | 求索阁

    Qt自有一个绘图的引擎,这个引擎的核心就是QPainter,我们知道QPainter在渲染二维图形和文字有很大的优势,而OpenGL是当前流行的三维渲染器,怎样才能将两者结合起来,制作更为丰富的应用程 ...

  4. osg渲染到纹理技术(一)

    render-to-textures(RTT)允许 开发者根据场景的一部分图像创建成一张纹理图,烘焙到场景中的某一物体上,这种技术用于创建更好看的特殊的表现形式,或者被保存用于以后的延迟着色,和多通道 ...

  5. OpenGL FBO

    FBO一个最常见的应用就是:渲染到纹理(render to texture),通过这项技术可以实现发光效果,环境映射,阴影映射等很炫的效果. OpenGL中的Frame Buffer Object(F ...

  6. Android OpenGL+Camera2渲染(3) —— 大眼,贴纸功能实现

    Android OpenGL+Camera2渲染(1) -- OpenGL简单介绍 Android OpenGL+Camera2渲染(2) -- OpenGL实现Camera2图像预览 Android ...

  7. Android Camera OpenGL FBO的理解

    背景概念: 首先,Android显示系统中,系统默认的渲染器是OpenGL,混合使用skia,各个厂商可能有不同的实现,大部分都是OpenGL. Android在系统启动时,经过BootLoader启 ...

  8. Android OpenGL+Camera2渲染(2) —— OpenGL实现Camera2图像预览

    Android OpenGL+Camera2渲染(1) -- OpenGL简单介绍 Android OpenGL+Camera2渲染(2) -- OpenGL实现Camera2图像预览 Android ...

  9. CSharpGL(42)借助帧缓存实现渲染到纹理(RenderToTexture)

    CSharpGL(42)借助帧缓存实现渲染到纹理(RenderToTexture) 渲染到纹理(Render To Texture)是实现很多OpenGL高级效果的一个基础.本文记录了如何用CShar ...

  10. OpenGL 文本渲染Text Rendering

    OpenGL文本渲染Text Rendering 文本渲染Text Rendering简介 经典文本渲染:位图字体 现代文本渲染:FreeType 着色器 渲染一行文本 更进一步 文本渲染Text R ...

最新文章

  1. CompletableFuture:让你的代码免受阻塞之苦
  2. OC中的自动引用计数
  3. 华夫饼为什么不松软_掌握这2个关键点,5个小细节,3个小技巧,保证烙饼松软又好吃...
  4. 经验 | 计算机视觉顶会上的灌水文都有哪些特征?
  5. 漫画丨让你专心干技术,没让你干到35岁啊…
  6. SpringBoot文件上传异常之提示The temporary upload location xxx is not valid
  7. 复旦大学《高等代数学(第三版)》教材习题答案
  8. Excel自定义下拉框
  9. 异步赠书:10月Python畅销书升级
  10. Ubuntu 16 永久修改ulimit中的max file open限制
  11. 如何选择和设置SEO关键词
  12. python网络数据采集 第二版_Python网络数据采集 (影印版)第2版
  13. 基于OBD系统的量产车评估测试(PVE)
  14. ImportError:cannot import name ‘namedtuple‘from ‘collections‘(C:\Python\Pyth...
  15. 星环科技的“星图解密”:只有偏执狂,才能让中国基础软件打破对国外进口的依赖...
  16. 网页css样式滚动字幕
  17. c语言题查询答案,C语言习题级答案.docx
  18. 干货 | SSMS客户端连接京东云RDS SQL Server配置方法
  19. 刷题总结——regular words(hdu1502 dp+高精度加法+压位)
  20. 一个轻巧高效的多线程c++stream风格异步日志(二)

热门文章

  1. ES6(ES2015)
  2. Python相关文章索引(13)
  3. 驰为vi10 java_驰为Win10 Remix双系统 for Vi10,独一无二
  4. 二、JavaScript 基础(上) - 章节课后练习题及答案
  5. 软件开发之大忌:想当然
  6. 知识付费的内容变现有哪些方式?
  7. 如何卸载手机系统自带应用(无需root)?【亲测有用】
  8. 倪文迪陪你学蓝桥杯2021寒假每日一题:1.29日(2019省赛A组第7题)
  9. 如何获取excel 中的 某几个列的值
  10. NLP 语义匹配:经典前沿方案整理