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

网站建设优化去哪学成都学网站建设费用

网站建设优化去哪学,成都学网站建设费用,企石镇网站建设公司,手机网站微信咨询说明#xff1a;跟着learnopengl的内容学习#xff0c;不是纯翻译#xff0c;只是自己整理记录。 强烈推荐原文#xff0c;无论是内容还是排版。 原文链接 本文地址#xff1a; http://blog.csdn.net/aganlengzi/article/details/50421006 纹理 Textures 为了使我们创建的… 说明跟着learnopengl的内容学习不是纯翻译只是自己整理记录。 强烈推荐原文无论是内容还是排版。 原文链接 本文地址 http://blog.csdn.net/aganlengzi/article/details/50421006 纹理 Textures 为了使我们创建的对象比如说三角形更加生动我们已经学习了为对象的每个像素点设置不同的颜色来使它变得更加有趣。但是在实际应用中这种方式需要我们为模型创建太多的颜色还要完成颜色与点的映射工作量巨大这不现实。 一种普遍为人们所接受的方式是使用纹理。纹理是二维图像虽然也有一维或者三维纹理的存在用于描述对象的细节。比如用一张印有砖头的图像贴到一个三维的房子对象的表面上这个三维的房子变得逼真。因为图像上能够呈现的细节是非常多的所以我们可以让我们的创建的对象呈现出非常逼真的细节而无需为它添加更多的点或者颜色比如门、窗等等。 除了图像纹理也可以用于存储要发送给shader的大量数据我们将会在一次单独的教程给予讲解。 本教程中你将学会怎样将一张砖头的图像映射到之前我们已经创建的三角形上。如下图所示 为了将一个纹理映射到三角形上我们需要为三角形的每个顶点绑定相关纹理的哪个位置。每个顶点都应该关联一个纹理坐标这个坐标指定了这个点要绑定的纹理部分。片段一个要显示在屏幕上的像素点的所有信息插值完成其他片段的绑定。 纹理坐标在x和y坐标我们使用的是二维图像上的取值范围都是[0,1]。利用纹理坐标来获得纹理颜色的过程叫做采样。纹理坐标中的原点(00)在一个纹理的左下角(11)在其右上角。下图展示了我们怎样将纹理坐标映射到三角形 我们为三角形指定了三个坐标点。我们想要将这个矩形二维图像的左下角映射到我们创建三角形的左下角将这个矩形图形的右下角映射到三角形的右下角将这个矩形图片的上边缘中点映射到三角形的上顶点这正好是矩形图片中三角形砖墙的范围。在图中显示的结果就是图片的(0,0)坐标点映射到左下角(1,0)坐标点映射到右下角(0.5,1)坐标点映射到上顶点。我们只需给顶点处理器发送三个纹理坐标而顶点处理器将它们传递给片段处理器片段处理器利用插值的方法完成所有点的映射。 所以上述我们需要指定的纹理坐标如下所示 GLfloat texCoords[] {0.0f, 0.0f, // Lower-left corner 1.0f, 0.0f, // Lower-right corner0.5f, 1.0f // Top-center corner }; 纹理采样是比较笼统的说法它可以通过多种方式完成完成的效果当然各有不同。所以我们的一项重要工作就是告诉OpenGL如何进行纹理采样。 纹理包裹 Texture Wrapping 纹理坐标的范围通常是从(0,0)到(1,1)但是当我们指定的坐标值超出这个范围怎么办呢OpenGL默认的处理方式是一值重复这张图片但是实际上我们有多种方式可供选择。 GL_REPEAT: 默认的方式重复纹理GL_MIRRORED_REPEAT: 和重复纹理相似但是重复的是镜像处理过的纹理GL_CLAMP_TO_EDGE: 在纹理和边缘之间拉伸纹理GL_CLAMP_TO_BORDER: 坐标之外显示为用户定义的边缘颜色 当我们以以上三种不同方式制定坐标值在规定的(01)之外时每一种方式都会产生不同的效果。如下图所示 前面提到的不同的方式都可以通过glTexParameter*函数设置没个坐标轴s,t或者r(仅在使用三维纹理时)和x,y,z是相同的 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); 函数的第一个参数指定了纹理目标我们使用的是二维图像所以纹理目标是GL_TEXTURE_2D。 第二个参数指定了我们想要设置的坐标轴。最后一个参数指定了我们想要设置的包裹模式以方便OpenGL在设置当前激活的纹理的包裹方式时选择我们指定的方式。 需要注意的是如果我们指定的是GL_CLAMP_TO_BORDER方式我们还应该指定一种边缘颜色。这通过glTexParameter加后缀fv函数并通过GL_TEXTURE_BORDER_COLOR和一个颜色向量参数来指定即如下所示的方式 float borderColor[] { 1.0f, 1.0f, 0.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 纹理过滤 Texture Filtering 纹理坐标不依赖分辨率可以使任何的浮点值因此OpenGL必须要解析哪一个纹理坐标应该映射到哪一个纹理像素texture pixel简写texel。如果你想要将一个低分辨率的纹理映射到一个很大的对象上的时候这就显得尤为重要。你可能会猜想OpenGL肯定提供了纹理像素向屏幕像素之间的映射选项。确实有很多可选的方式但是目前我们讨论最重要的两个选项GL_NEAREST和GL_LINEAR。 GL_NEAREST也叫作最邻近过滤是OpenGL采取的默认纹理过滤方式。当过滤方式设置成GL_NEARESTOpenGL选择最靠近纹理坐标的像素点。在下图中你可以看到4个像素点中间那个十字号表示纹理坐标的精确位置。左上角的纹理像素的中心是和精确的纹理坐标值最接近的所以被选为采样的颜色如下图所示 GL_LINEAR也叫作双线性过滤它选择纹理坐标临近纹理像素的颜色值的插值作为采样的颜色。离纹理坐标越近的点的颜色值就越多地被采样。下图可见返回的是临近像素的混合颜色值 但是这两种过滤方式下的真实视觉效果是怎么样的呢让我们试着将一个低分辨率的纹理绑定到一个比这个纹理尺寸要大的对象上的效果这种情况下纹理会被拉伸我们应该能够看到独立的像素点。 使用GL_NEAREST方式的结果是我们能够清楚地看到一个个的像素点但是使用GL_LINEAR方式产生的效果完全不同它产生了一种更为平滑的效果单独的像素点在这种方式下不容易被看到。GL_LINEAR方式产生了更实际的效果但是一些开发者更喜欢那种像素点的效果所以选择GL_NEAREST方式。 纹理过滤可以用于设置放大U或者缩小操作所以你可以在缩小的时候使用最邻近方式但是在放大的时候使用线性过滤方式。因此我们需要通过glTexParameter*函数指定这两种选项。代码如下所示 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 变频译码 Mipmaps 假设我们有一个分厂大的空间里面有成千上万的对象每一个对象都要贴图。在人眼看到的场景中必然有很多对象在很远处但是它们有着和近处对象一样高分辨率的贴图。因为这些对象对于观察者来说在很远处那么它们可能只会产生很少的片段。OpenGL很难在高分辨率的纹理中采样正确的颜色值因为它不得不从一大块纹理中为一个片段取出一个颜色值这是不值得的。这将会在小的对象上面产生视觉上的错误更不用提在小对象上使用高分辨率纹理的内存浪费。 OpenGL使用一种叫做变频译码的方式来解决这个问题简单来说就是一组纹理图像它们中每一个后来的纹理都是原来的1/2*1/2大小如下图所示。其中的原理是显而易见的在举例观察者一定距离的时候OpenGL将会使用一个与这个距离最佳匹配的不同的变频译码纹理。因为这个对象在很远处较小的分辨率观察者也不会觉察出来。并且mipmaps对性能也有好处。 手工创建一系列类似于上面的变频映射图像是繁杂的但是幸运的是OpenGL为我们提供了这项功能。只需要在我们创建一个纹理之后调用glGenerateMipmaps后面你将会看到使用的实例。 在不同的变频映射纹理之间选择的时候OpenGL可能会造成一些显而易见的瑕疵比如说两种规格的纹理之间边缘错位无法对接。像正常的纹理过滤在mipmap的不同等级之间进行过滤也是可以的实际上和正常的纹理过滤的原理是类似的。在mipmap等级改变的时候我们也可以使用NEAREST或者LINEAR过滤的方式来消除上面所述的问题。一下是可以用来原始过滤方式的四种选项 GL_NEAREST_MIPMAP_NEAREST: 使用最邻近的mipmap来匹配像素尺寸并且使用最邻近值方式进行纹理采样GL_LINEAR_MIPMAP_NEAREST: 使用最邻近的mipmap级别并且使用线性插值方式GL_NEAREST_MIPMAP_LINEAR: 在最靠近纹理坐标值的不同mipmap间使用线性插值方式并且使用最邻近插值方式GL_LINEAR_MIPMAP_LINEAR: 在最靠近的mipmap间使用线性插值方式并且使用线性插值方式进行采样 正如纹理过滤设置方法一样我们需要使用glTexParameteri函数来设置选择以上的四种方式之一如下所示 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 一个常见的错误是设置这四种方式中的一种为放大映射这种方式不会产生任何效果因为mipmap最主要的应用是在缩小的时候使用对象在远处观察者看到的对象是变小的。所以纹理放大的时候是不用mipmap的如果为GL_TEXTURE_MAG_FILTER设置了上述mipmap选项中的一种那么OpenGL就会报GL_INVALID_ENUM错误。 加载和创建纹理 在使用纹理之前我们首先要做的是将它们加载到我们的应用中。纹理图像可以通过多种格式存储每一中都有不同的数据结构和组织方式那么我们应该怎样在应用中得到这些纹理的数据呢一种解决方法是我们选定一种喜欢的图像格式例如.PNG并且自己写一个图像加载和转换模块将这种格式的纹理转换成二维数组格式的数据进行存储。虽然写这个模块并不是太繁琐但是如果你想要使用更多的图像格式应该怎么办再写一个最终是不是将要为你使用的每一种纹理格式都写一个对应的纹理图像加载模块 另一种可能更好的解决方法是使用一个支持多种常用图像个数的图像加载函数库由它来帮助我们完成纹理的加载即由不同格式的图像加载到我们的程序中变成一个存储着纹理数据的二维数组。就像我们使用的SOIL一样。 SOIL SOILSimple OpenGL Image Library支持最常用的多种图像格式并且非常易用你可以从这儿下载到。像其它你已经使用的函数库GLFW,GLEW一样,你可能需要自己生成.lib文件。 下面就是在讲怎么配置和使用SOIL了。 我配置的方法是 1下载得到压缩包soil.zip 2解压后用Visual Studio 2012打开soil.zip\Simple OpenGL Image Library\projects\VC9的工程并同意做单向版本提升 3编译得到Debug/SOIL.lib 4将yourpathto\soil.zip\Simple OpenGL Image Library\src添加到工程的包含路径下 5将your\path\to\SOIL.lib添加到工程的库目录下 6在编写的工程源文件中添加头文件#include int width, height; unsigned char* image SOIL_load_image(container.jpg, width, height, 0, SOIL_LOAD_RGB); 这个函数的第一个参数是图像文件container.jpg的位置第二个和第三个参数是图像的宽度和高度。我们需要在后面生成纹理的时候使用到这两个参数。第四个参数指定了这个图像含有的通道数但是目前我们将这个值设置成0.最后一个参数指定了SOIL应该以何种方式加载这个图像我们只对图像的RGB分量感兴趣加载的结果是将图像存储成一个大的字符/字节数组。 生成一个纹理 就像之前生成OpenGL中的对象一样每个纹理生成的时候也绑定一个唯一的ID如下所示 GLuint texture; glGenTextures(1, texture); glGenTextures函数的第一个参数指定我们要生成纹理个数它们的ID将会保存到第二参数中第二个参数是一个地址可以使一个变量在第一个参数为1的情况下或者是数组的起始地址。我们的例子中因为只生成一个纹理所以我们给的参数是1和变量texture的地址。像之前的VBO,VAO 和EBO等对象我们将纹理绑定到其目标上以方便我们对当前绑定的纹理进行操作 glBindTexture(GL_TEXTURE_2D, texture); 现在这个纹理对象已经绑定到了二维纹理目标上实际是将其ID进行了绑定接下来我们就可以利用之前加载的图像数据来生成纹理了。纹理的生成需要使用glTexImage2D函数完成 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); 这个函数是一个有很多参数的“大”函数以下对每个参数进行逐一讲解: 第一个参数指定纹理的目标我们将GL_TEXTURE_2D作为实参传进去表示接下来的操作将对绑定到GL_TEXTURE_2D的纹理对象进行操作而不会操作绑定到GL_TEXTURE_1D或者绑定到G_TEXTURE_3D目标的纹理对象。 第二个参数指定了mipmap的级别实际上我们可以手工设置每一个创建的mipmap的级别但是我们目前只是将这个值设置为基础级别也就是0. 第三个参数指定了OpenGL应该以什么样的数据类型来存储创建的纹理。我们的图像应为只加载了RGB信息所以这里设置的是GL_RGB。 第四个和第五个参数指定了生成纹理的宽度和高度。我们之前已经保存了我们设置的值这里传进去的就是这两个变量。 下一个参数总是0先不用管。 第七个和第八个参数指定了源图像的格式和数据类型。我们在加载的时候因为加载的是RGB信息所以这里指定的是GL_RGB同时我们之前说过加载的图像会被保存成字符或者字节类型所以这里传进去的实参是GL_UNSIGNED_BYTE。 最后一个参数是实际的图像数据地址也就是我们之前利用那个库加载和转换的数据。 在调用glTexImage2D之后当前绑定的纹理对象就已经附加上了纹理图像。但是当前它只有基础级别的mipmap因为我们目前指定的就只是基础级别的如果我们想要使用其它级别的mipmap一种方法是我们需要手工改变第二个参数来生成不同级别的纹理另一种方法是在生成纹理之后调用glGenerateMipmap函数它将会自动为我们生成当前绑定纹理对象所有级别的mipmap。 在我们生成了纹理和对应的mipmap之后释放图像内存和为特定目标解绑纹理对象是一种好的习惯。 SOIL_free_image_data(image); glBindTexture(GL_TEXTURE_2D, 0); 以上纹理生成的整个过程大致是下面代码描述的样子 GLuint texture; glGenTextures(1, texture); glBindTexture(GL_TEXTURE_2D, texture); // Set the texture wrapping/filtering options (on the currently bound texture object) ... // Load and generate the texture int width, height; unsigned char* image SOIL_load_image(container.jpg, width, height, 0, SOIL_LOAD_RGB); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); SOIL_free_image_data(image); glBindTexture(GL_TEXTURE_2D, 0); 使用纹理 下面我们将会使用在前面的几个教程中创建的由两个三角形拼成的矩形来演示怎样使用纹理。我们首先要设置OpenGL采样纹理的方式所以我们先来修改之前的顶点数据向其中添加纹理坐标 GLfloat 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 }; 因为设置了纹理坐标那么之前的关于数据放入内存的方式和VBO的设置以及OpenGL解释数据的方式都要进行更新。目前在内存中数据的组织方式如下图所示 所以要首先修改vertex shader让OpenGL能够正确读入数据并且将纹理坐标信息输出到片段处理程序 #version 330 core layout (location 0) in vec3 position; layout (location 1) in vec3 color; layout (location 2) in vec2 texCoord;out vec3 ourColor; out vec2 TexCoord;void main() {gl_Position vec4(position, 1.0f);ourColor color;TexCoord texCoord; } 然后指定VBO的设置和OpenGL解释数据的方式 glVertexAttribPointer(2, 2, GL_FLOAT,GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); glEnableVertexAttribArray(2); 需要注意的是我们在设置location2即刚加载的纹理数据的时候的步长指定为8 * sizeof(GLfloat)在设置position和color的步长的时候也需要设置这个值。 片段处理程序中我们首先设置其接收顶点处理程序中传递进来的纹理坐标其次只知道坐标是不能完成颜色值的采样的还必须能够访问到纹理数据。但是怎样才能够让片段处理程序访问到纹理对象的数据呢GLSL中专为纹理对象内嵌了一个数据类型sampler*后缀是我们要访问的纹理类型比如说sampler1D,sampler2D等。所以我们可以通过uniform类型的变量很方便地为片段处理程序添加一个纹理如下所示的sampler2D类型的变量ourTexture注意这个ourTexture是在OpenGL程序中当前绑定的纹理对象这也正是使用uniform的原因。 #version 330 core in vec3 ourColor; in vec2 TexCoord;out vec4 color;uniform sampler2D ourTexture;void main() {color texture(ourTexture, TexCoord); } 我们利用GLSL内嵌的纹理颜色采样函数texture来完成采样这个函数的第一个参数是一个sampler数据类型的变量第二个参数是相应的纹理坐标。这个texture函数对ourTexture指定的纹理数据通过texCoord指定的纹理坐标进行采样采样的方式是我们之前已经讲过的默认或者已经设置过的方式最邻近或者插值。 目前整个纹理对象的使用剩下的就是在调用渲染函数glDrawElements之前对将这个纹理对象进行绑定了。没错利用我们之前讲过的能够存储状态设置信息的VAO来实现 glBindTexture(GL_TEXTURE_2D, texture); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); 如果一切都正确的话我们将会得到如下所示的运行结果 如果你得到的结果与我得到的结果不同那么可能你的程序中的某个地方存在错误完成的代码在这儿。 后文是为了得到更为酷炫一点的效果将纹理和通过指定顶点颜色的方式相结合。得到不同的效果也就是在片段处理程序中进行如下修改 color texture(ourTexture, TexCoord) * vec4(ourColor, 1.0f); 得到的效果应该是纹理颜色值和指定的顶点颜色值插值结果的混合颜色; 还不错~ 纹理单位 Texture Units 前面说过我们在fragment shader中设置的uniform sampler2D类型的变量并没有像之前我们使用uniform类型的变量一样需要在OpenGL函数中对其值进行设定。其值默认已经设置成了我们之前绑定的纹理对象。实际上我们也可以在代码中指定我们要操作的纹理对象的位置。 纹理单位的主要目的是让我们在shader中使用超过一个纹理对象。通过为sampler指定纹理单位我们可以一次绑定多个纹理只要我们能够在此之前激活相关的纹理单位。就像调用glBindTexture函数一样我们可以通过glActiveTexture函数激活我们想要使用的纹理如下所示 glActiveTexture(GL_TEXTURE0); // Activate the texture unit first before binding texture glBindTexture(GL_TEXTURE_2D, texture); 激活了纹理单位之后随后的glBindTexture调用就会绑定纹理到当前激活的纹理单位上。上面代码中指定的纹理单位GL_TEXTURE0实际上是一致默认激活的所以在之前的代码中我们调用glBindTexture中不需要对纹理单位进行任何的激活操作。 以下的讲解就是如何使用多个纹理。 OpenGL中至少应该有16个纹理单位供我们使用使用上面的函数可以激活GL_TEXTURE0到GL_TEXTURE15的纹理单位。它们是线性组织的所以我们也可以通过GL_TEXTURE0 8的方式指定GL_TEXTURE8这在我们使用循环对多个纹理单位进行操作的时候就会显得十分好用。但是我们还应该通过编辑fragment shader的方式来接受另一个sampler对象这个是相对简单的 #version 330 core ...uniform sampler2D ourTexture1; uniform sampler2D ourTexture2;void main() {color mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2); } 现在通过这个片段处理器产生的最终颜色就是两个纹理颜色的混合值了。GLSL的内置mix函数要求两个参数值需要对这两个颜色值进行线性插值上述的texture函数产生颜色值而mix函数产生这两个颜色值的混合值混合的方式是由第三个参数指定的如果第三个参数是0.0那么整个mix函数返回的就是第一个参数值如果第三个参数值是1.0那么返回的就是第二个参数值。所以0.2代表值返回的颜色值是第一个参数的80%和第二个参数的20%的颜色混合值。 我们现在加载和创建另一个纹理。我们应该已经对这个过程比较熟悉了。首先确保创建另一个纹理对象加载一个图像利用上面讲到的SOIL并且通过glTexImage2D函数生成纹理第二个纹理图像我们将使用你学习OpenGL时候的表情来生成就是这个。 为了使用两个纹理对象我们需要对绘制过程进行一点修改为的是像上面所说的将两个纹理都绑定到激活的不同纹理单位上并且需要指定哪一个纹理对象对应着哪一个纹理单位 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); glUniform1i(glGetUniformLocation(ourShader.Program, ourTexture1), 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2); glUniform1i(glGetUniformLocation(ourShader.Program, ourTexture2), 1);glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); 需要注意的是我们通过glUniform1i函数来为我们设置的sampler对象设置我们的纹理单位的位置。这样我们将对应的uniform变量也就是sampler变量设置成正确的纹理单位GL_TEXTURE0和GL_TEXTURE1我们应该得到的效果是这样的 我们注意到我们的笑脸图案是倒置的产生这种现象的原因是OpenGL默认原点坐标在图像的左下角但是图像通常认为原点坐标在左上角所以就会造成了倒置的现象。有一些类似于SOIL的加载图像的库是提供加载的时候对y轴进行设置的选项的但是SOIL没有。 目前我们解决这个问题的方法有两个 第一种方法是在指定纹理坐标的时候将y坐标轴的坐标值反向原来的坐标应该绑定在下面的设置成绑定到上面倒个。 我们可以通过设置vertex shader来帮助我们完成上述y轴坐标的交换实际上很简单只需要将原来的坐标值做如下的操作TexCoord vec2(texCoord.x, 1.0f - texCoord.y)。 上述的两种方法实际上只是针对我们这个例子的具体方法在真正的实现的时候两种方式只能算是奇技淫巧。。。。。。可能在大工程中使用会出乱子的。最好的方式还是在图像数据加载的时候进行或者是将图像本身进行反转操作。这样的话得到的数据是适合于OpenGL使用的。 不管使用了哪种方法我们做过处理之后得到最终的显示效果应该是如下图所示的这样的我使用的方法是将原图像进行倒置 最终的源码在这儿包括vertex shader和fragment shader。
http://www.yutouwan.com/news/233176/

相关文章:

  • 广州平台网站搭建网站栏目划分怎么做
  • 个人做网站怎么备案丹阳建设局官方网站
  • 网站建设与管理 情况总结企业管理咨询服务合同模板
  • 网络营销的主要形式有建设网站网页设计与制作教程第五版课后答案
  • 网站后台使用说明公司网站建设素材
  • 在线做ppt的网站有哪些网站建设中主机放在哪里
  • 网站建设虚线的代码代做百度首页排名
  • 深圳建网站的公司张家港高端网站建设公司
  • 辽宁响应式网站费用安卓手机app下载
  • 卖水果做哪个网站好乱起封神是那个网站开发的?
  • 义乌有什么企业网站吗网络建设标准
  • 自适应网站制作教程旅游村庄网站建设方案
  • 如何入侵网站服务器嵊州建设局网站
  • 关于学校的网站模板免费下载网站分为哪几类
  • 人才网站运营建设 材料php网站建设 关键技术
  • 嘉兴网站建设技术托管青岛网站建设在线
  • 西安专业做网站的公司哪家好网上书城网站建设总结
  • 门户网站改造方案霸州做网站shijuewang
  • 网站代备案便宜团购网站平台建设
  • 网站建设个体营业执照门店做网站有没有必要
  • 找工程项目信息网站dedecms是什么意思
  • 汶上哪个广告公司做网站国内新闻最新消息2021
  • win7搭建网站服务器大型网站建设历史
  • 婺源网站建设wyjcwlwordpress ftp存储
  • 做旅游网站公司wordpress标签id在哪里
  • 高米店网站建设wordpress给分类添加自定义栏目
  • 临西网站建设嘉祥网站建设多少钱
  • 手机网站的优势报告老师怪怪怪怪物
  • 电商网站前台功能模块各学院二级网站建设通报
  • 个人网站有哪些天元建设集团有限公司李华