Android OpenGL ES详解——立方体贴图

OpenGL 入门 17:立方体贴图 OpenGL 立方体贴图 阅读详情

目录

一、概念

二、如何使用

1、创建立方体贴图

2、生成纹理

3、设置纹理环绕和过滤方式

4、激活和绑定立方体贴图

三、应用举例——天空盒

1、概念

2、加载天空盒

3、显示天空盒

4、优化

四、应用举例——环境映射:反射

五、应用举例——环境映射:折射

六、应用举例——动态环境贴图

七、源码下载


一、概念

我们之前一直使用的是2D纹理,还有更多的纹理类型我们没有探索过,本教程中我们讨论的纹理类型是将多个纹理组合起来映射到一个单一纹理,它就是立方体贴图(Cube Map)。

基本上说立方体贴图它包含6个2D纹理,这每个2D纹理是一个立方体(cube)的一个面,也就是说它是一个有贴图的立方体。你可能会奇怪这样的立方体有什么用?为什么费事地把6个独立纹理结合为一个单独的纹理,只使用6个各自独立的不行吗?这是因为立方体贴图有自己特有的属性,可以使用方向向量对它们索引和采样。想象一下,我们有一个1×1×1的单位立方体,有个以原点为起点的方向向量在它的中心。

从立方体贴图上使用橘黄色向量采样一个纹理值看起来和下图有点像:

方向向量的大小无关紧要。一旦提供了方向,OpenGL就会获取方向向量触碰到立方体表面上的相应的纹理像素(texel),这样就返回了正确的纹理采样值。

方向向量触碰到立方体表面的一点也就是立方体贴图的纹理位置,这意味着只要立方体的中心位于原点上,我们就可以使用立方体的位置向量来对立方体贴图进行采样。然后我们就可以获取所有顶点的纹理坐标,就和立方体上的顶点位置一样。所获得的结果是一个纹理坐标,通过这个纹理坐标就能获取到立方体贴图上正确的纹理。

二、如何使用

1、创建立方体贴图

立方体贴图和其他纹理一样,所以要创建一个立方体贴图,在进行任何纹理操作之前,需要生成一个纹理,激活相应纹理单元然后绑定到合适的纹理目标上。这次要绑定到 GL_TEXTURE_CUBE_MAP纹理类型:

GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

由于立方体贴图包含6个纹理,立方体的每个面一个纹理,我们必须调用glTexImage2D函数6次,函数的参数和前面教程讲的相似。然而这次我们必须把纹理目标(target)参数设置为立方体贴图特定的面,这是告诉OpenGL我们创建的纹理是对应立方体哪个面的。因此我们便需要为立方体贴图的每个面调用一次 glTexImage2D(方法作用详见:)。

由于立方体贴图有6个面,OpenGL就提供了6个不同的纹理目标,来应对立方体贴图的各个面。

纹理目标(Texture target)方位
GL_TEXTURE_CUBE_MAP_POSITIVE_X右
GL_TEXTURE_CUBE_MAP_NEGATIVE_X左
GL_TEXTURE_CUBE_MAP_POSITIVE_Y上
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y下
GL_TEXTURE_CUBE_MAP_POSITIVE_Z后
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z前

2、生成纹理

和很多OpenGL其他枚举一样,对应的int值都是连续增加的,所以我们有一个纹理位置的数组或vector,就能以 GL_TEXTURE_CUBE_MAP_POSITIVE_X为起始来对它们进行遍历,每次迭代枚举值加 1,这样循环所有的纹理目标效率较高:

int width,height;
unsigned char* image;  
for(GLuint i = 0; i < textures_faces.size(); i++)
{
    image = SOIL_load_image(textures_faces[i], &width, &height, 0, SOIL_LOAD_RGB);
    glTexImage2D(
        GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
        0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image
    );
}

这儿我们有个vector叫textures_faces,它包含立方体贴图所各个纹理的文件路径,并且以上表所列的顺序排列。它将为每个当前绑定的cubemp的每个面生成一个纹理。

3、设置纹理环绕和过滤方式

由于立方体贴图和其他纹理没什么不同,我们也要定义它的环绕方式和过滤方式:

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

别被 GL_TEXTURE_WRAP_R吓到,它只是简单的设置了纹理的R坐标,R坐标对应于纹理的第三个维度(就像位置的z一样)。我们把放置方式设置为 GL_CLAMP_TO_EDGE ,由于纹理坐标在两个面之间,所以可能并不能触及哪个面(由于硬件限制),因此使用 GL_CLAMP_TO_EDGE 后OpenGL会返回它们的边界的值,尽管我们可能在两个面中间进行的采样。

4、激活和绑定立方体贴图

在绘制物体之前,将使用立方体贴图,而在渲染前我们要激活相应的纹理单元并绑定到立方体贴图上,这和普通的2D纹理没什么区别。

在片段着色器中,我们也必须使用一个不同的采样器——samplerCube,用它来从texture函数中采样,但是这次使用的是一个vec3方向向量,取代vec2。下面是一个片段着色器使用了立方体贴图的例子:

in vec3 textureDir; // 用一个三维方向向量来表示立方体贴图纹理的坐标

uniform samplerCube cubemap;  // 立方体贴图纹理采样器

void main()
{
    color = texture(cubemap, textureDir);
}

看起来不错,但是何必这么做呢?因为恰巧使用立方体贴图可以简单的实现很多有意思的技术。其中之一便是著名的天空盒(Skybox)。

三、应用举例——天空盒

1、概念

天空盒(Skybox)是一个包裹整个场景的立方体,它由6个图像构成一个环绕的环境,给玩家一种他所在的场景比实际的要大得多的幻觉。比如有些在视频游戏中使用的天空盒的图像是群山、白云或者满天繁星。比如下面的夜空繁星的图像就来自《上古卷轴》:

你现在可能已经猜到立方体贴图完全满足天空盒的要求:我们有一个立方体,它有6个面,每个面需要一个贴图。上图中使用了几个夜空的图片给予玩家一种置身广袤宇宙的感觉,可实际上,他还是在一个小盒子之中。

网上有很多这样的天空盒的资源。这些天空盒图像通常有下面的样式:

如果你把这6个面折叠到一个立方体中,你机会获得模拟了一个巨大的风景的立方体。有些资源所提供的天空盒比如这个例子6个图是连在一起的,你必须手工它们切割出来,不过大多数情况它们都是6个单独的纹理图像。

2、加载天空盒

由于天空盒实际上就是一个立方体贴图,加载天空盒和之前我们加载立方体贴图的没什么大的不同。为了加载天空盒我们将使用下面的函数,它接收一个包含6个纹理文件路径的vector:

GLuint loadCubemap(vector<const GLchar*> faces)
{
    GLuint textureID;
    glGenTextures(1, &textureID);
    glActiveTexture(GL_TEXTURE0);

    int width,height;
    unsigned char* image;

    glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
    for(GLuint i = 0; i < faces.size(); i++)
    {
        image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB);
        glTexImage2D(
            GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
            GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image
        );
    }
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

    return textureID;
}

这个函数没什么特别之处。这就是我们前面已经见过的立方体贴图代码,只不过放进了一个可管理的函数中。

然后,在我们调用这个函数之前,我们将把合适的纹理路径加载到一个vector之中,顺序还是按照立方体贴图枚举的特定顺序:

vector<const GLchar*> faces;
faces.push_back("right.jpg");
faces.push_back("left.jpg");
faces.push_back("top.jpg");
faces.push_back("bottom.jpg");
faces.push_back("back.jpg");
faces.push_back("front.jpg");
GLuint cubemapTexture = loadCubemap(faces);

现在我们已经用cubemapTexture作为id把天空盒加载为立方体贴图。

3、显示天空盒

因为天空盒绘制在了一个立方体上,我们还需要另一个VAO、VBO以及一组全新的顶点,和任何其他物体一样。

立方体贴图用于给3D立方体帖上纹理,可以用立方体的位置作为纹理坐标进行采样。当一个立方体的中心位于原点(0,0,0)的时候,它的每一个位置向量也就是以原点为起点的方向向量。这个方向向量就是我们要得到的立方体某个位置的相应纹理值。出于这个理由,我们只需要提供位置向量,而无需纹理坐标。为了渲染天空盒,我们需要一组新着色器,它们不会太复杂。因为我们只有一个顶点属性,顶点着色器非常简单:

#version 330 core
layout (location = 0) in vec3 position;
out vec3 TexCoords;

uniform mat4 projection;
uniform mat4 view;

void main()
{
    gl_Position =   projection * view * vec4(position, 1.0);  
    TexCoords = position;
}

注意,顶点着色器有意思的地方在于我们把输入的位置向量作为输出给片段着色器的纹理坐标。片段着色器就会把它们作为输入去采样samplerCube:

#version 330 core
in vec3 TexCoords;
out vec4 color;

uniform samplerCube skybox;

void main()
{
    color = texture(skybox, TexCoords);
}

片段着色器比较明了,我们把顶点属性中的位置向量作为纹理的方向向量,使用它们从立方体贴图采样纹理值。渲染天空盒现在很简单,我们有了一个立方体贴图纹理,我们简单绑定立方体贴图纹理,天空盒就自动地用天空盒的立方体贴图填充了。为了绘制天空盒,我们将把它作为场景中第一个绘制的物体并且关闭深度写入。这样天空盒才能成为所有其他物体的背景来绘制出来。


glDepthMask(GL_FALSE);
skyboxShader.Use();
// ... Set view and projection matrix
glBindVertexArray(skyboxVAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthMask(GL_TRUE);
// ... Draw rest of the scene

如果你运行程序就会陷入困境,我们希望天空盒以玩家为中心,这样无论玩家移动了多远,天空盒都不会变近,这样就产生一种四周的环境真的非常大的印象。当前的视图矩阵对所有天空盒的位置进行了转转缩放和平移变换,所以玩家移动,立方体贴图也会跟着移动!我们打算移除视图矩阵的平移部分,这样移动就影响不到天空盒的位置向量了。在基础光照教程里我们提到过我们可以只用4X4矩阵的3×3部分去除平移。我们可以简单地将矩阵转为33矩阵再转回来,就能达到目标

glm::mat4 view = glm::mat4(glm::mat3(camera.GetViewMatrix()));

这会移除所有平移,但保留所有旋转,因此用户仍然能够向四面八方看。由于有了天空盒,场景即可变得巨大了。如果你添加些物体然后自由在其中游荡一会儿你会发现场景的真实度有了极大提升。最后的效果看起来像这样:

尝试用不同的天空盒实验,看看它们对场景有多大影响。

4、优化

现在我们在渲染场景中的其他物体之前渲染了天空盒。这么做没错,但是不怎么高效。如果我们先渲染了天空盒,那么我们就是在为每一个屏幕上的像素运行片段着色器,即使天空盒只有部分在显示着;fragment可以使用前置深度测试(early depth testing)简单地被丢弃,这样就节省了我们宝贵的带宽。

所以最后渲染天空盒就能够给我们带来轻微的性能提升。采用这种方式,深度缓冲被全部物体的深度值完全填充,所以我们只需要渲染通过前置深度测试的那部分天空的片段就行了,而且能显著减少片段着色器的调用。问题是天空盒是个1×1×1的立方体,极有可能会渲染失败,因为极有可能通不过深度测试。简单地不用深度测试渲染它也不是解决方案,这是因为天空盒会在之后覆盖所有的场景中其他物体。我们需要耍个花招让深度缓冲相信天空盒的深度缓冲有着最大深度值1.0,如此只要有个物体存在深度测试就会失败,看似物体就在它前面了。

在坐标系教程中我们说过,透视除法(perspective division)是在顶点着色器运行之后执行的,把gl_Position的xyz坐标除以w元素。我们从深度测试教程了解到除法结果的z元素等于顶点的深度值。利用这个信息,我们可以把输出位置的z元素设置为它的w元素,这样就会导致z元素等于1.0了,因为,当透视除法应用后,它的z元素转换为w/w = 1.0:

void main()
{
    vec4 pos = projection * view * vec4(position, 1.0);
    gl_Position = pos.xyww;
    TexCoords = position;
}

最终,标准化设备坐标就总会有个与1.0相等的z值了,1.0就是深度值的最大值。只有在没有任何物体可见的情况下天空盒才会被渲染(只有通过深度测试才渲染,否则假如有任何物体存在,就不会被渲染,只去渲染物体)。

我们必须改变一下深度方程,把它设置为GL_LEQUAL,原来默认的是GL_LESS。深度缓冲会为天空盒用1.0这个值填充深度缓冲,所以我们需要保证天空盒是使用小于等于深度缓冲来通过深度测试的,而不是小于。

四、应用举例——环境映射:反射

我们现在有了一个把整个环境映射到为一个单独纹理的对象,我们利用这个信息能做的不仅是天空盒。使用带有场景环境的立方体贴图,我们还可以让物体有一个反射或折射属性。像这样使用了环境立方体贴图的技术叫做环境贴图技术,其中最重要的两个是反射(reflection)和折射(refraction)。

反射

凡是是一个物体(或物体的某部分)反射(Reflect)他周围的环境的属性,比如物体的颜色多少有些等于它周围的环境,这要基于观察者的角度。例如一个镜子是一个反射物体:它会基于观察者的角度泛着它周围的环境。

反射的基本思路不难。下图展示了我们如何计算反射向量,然后使用这个向量去从一个立方体贴图中采样:

我们基于观察方向向量I和物体的法线向量N计算出反射向量R。我们可以使用GLSL的内建函数reflect来计算这个反射向量。最后向量R作为一个方向向量对立方体贴图进行索引/采样,返回一个环境的颜色值。最后的效果看起来就像物体反射了天空盒。

因为我们在场景中已经设置了一个天空盒,创建反射就不难了。我们改变一下箱子使用的那个片段着色器,给箱子一个反射属性:

#version 330 core
in vec3 Normal;
in vec3 Position;
out vec4 color;

uniform vec3 cameraPos;
uniform samplerCube skybox;

void main()
{
    vec3 I = normalize(Position - cameraPos);
    vec3 R = reflect(I, normalize(Normal));
    color = texture(skybox, R);
}

我们先来计算观察/摄像机方向向量I,然后使用它来计算反射向量R,接着我们用R从天空盒立方体贴图采样。要注意的是,我们有了片段的插值Normal和Position变量,所以我们需要修正顶点着色器适应它。

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;

out vec3 Normal;
out vec3 Position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
    Normal = mat3(transpose(inverse(model))) * normal;
    Position = vec3(model * vec4(position, 1.0f));
}

我们用了法线向量,所以我们打算使用一个法线矩阵(normal matrix)变换它们。Position输出的向量是一个世界空间位置向量。顶点着色器输出的Position用来在片段着色器计算观察方向向量。

因为我们使用法线,你还得更新顶点数据,更新属性指针。还要确保设置cameraPos的uniform。

然后在渲染箱子前我们还得绑定立方体贴图纹理:

glBindVertexArray(cubeVAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

编译运行你的代码,你等得到一个镜子一样的箱子。箱子完美地反射了周围的天空盒:

看起来挺惊艳,但是现实中大多数模型都不是完全反射的。我们可以引进反射贴图(reflection map)来使模型有另一层细节。和diffuse漫反射、specular镜面反射贴图一样,我们可以从反射贴图上采样来决定fragment的反射率。使用反射贴图我们还可以决定模型的哪个部分有反射能力,以及强度是多少。

五、应用举例——环境映射:折射

环境映射的另一个形式叫做折射(Refraction),它和反射差不多。折射是光线通过特定材质对光线方向的改变。我们通常看到像水一样的表面,光线并不是直接通过的,而是让光线弯曲了一点。它看起来像你把半只手伸进水里的效果。

折射遵守斯涅尔定律,使用环境贴图看起来就像这样:

我们有个观察向量I,一个法线向量N,这次折射向量是R。就像你所看到的那样,观察向量的方向有轻微弯曲。弯曲的向量R随后用来从立方体贴图上采样。

折射可以通过GLSL的内建函数refract来实现,除此之外还需要一个法线向量,一个观察方向和一个两种材质之间的折射指数。

折射指数决定了一个材质上光线扭曲的数量,每个材质都有自己的折射指数。下表是常见的折射指数:

材质折射指数
空气1.00
水1.33
冰1.309
玻璃1.52
宝石2.42

我们使用这些折射指数来计算光线通过两个材质的比率。在我们的例子中,光线/视线从空气进入玻璃(如果我们假设箱子是玻璃做的)所以比率是1.00/1.52 = 0.658。

我们已经绑定了立方体贴图,提供了定点数据,设置了摄像机位置的uniform。现在只需要改变片段着色器:

void main()
{
    float ratio = 1.00 / 1.52;
    vec3 I = normalize(Position - cameraPos);
    vec3 R = refract(I, normalize(Normal), ratio);
    color = texture(skybox, R);
}

通过改变折射指数你可以创建出完全不同的视觉效果。编译运行应用,结果也不是太有趣,因为我们只是用了一个普通箱子,这不能显示出折射的效果,看起来像个放大镜。使用同一个着色器,纳米服模型却可以展示出我们期待的效果:玻璃制物体。

你可以向想象一下,如果将光线、反射、折射和顶点的移动合理的结合起来就能创造出漂亮的水的图像。一定要注意,出于物理精确的考虑当光线离开物体的时候还要再次进行折射;现在我们简单的使用了单边(一次)折射,大多数目的都可以得到满足。

六、应用举例——动态环境贴图

现在,我们已经使用了静态图像组合的天空盒,看起来不错,但是没有考虑到物体可能移动的实际场景。我们到现在还没注意到这点,是因为我们目前还只使用了一个物体。如果我们有个镜子一样的物体,它周围有多个物体,只有天空盒在镜子中可见,和场景中只有这一个物体一样。

使用帧缓冲可以为提到的物体的所有6个不同角度创建一个场景的纹理,把它们每次渲染迭代储存为一个立方体贴图。之后我们可以使用这个(动态生成的)立方体贴图来创建真实的反射和折射表面,这样就能包含所有其他物体了。这种方法叫做动态环境映射(Dynamic Environment Mapping),因为我们动态地创建了一个物体的以其四周为参考的立方体贴图,并把它用作环境贴图。

它看起效果很好,但是有一个劣势:使用环境贴图我们必须为每个物体渲染场景6次,这需要非常大的开销。现代应用尝试尽量使用天空盒子,凡可能预编译立方体贴图就创建少量动态环境贴图。动态环境映射是个非常棒的技术,要想在不降低执行效率的情况下实现它就需要很多巧妙的技巧。

七、源码下载

Android OpenGL 立方体贴图应用举例-天空盒演示demo源码下载:

https://download.youkuaiyun.com/download/github_27263697/89991149

推荐文章

https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/06%20Cubemaps/#_4

OpenGL ES for Android (立方体贴图) 简介 我们前面学过纹理贴图,我们可以用6个2D纹理的纹理构建成立方体,而立方体贴图本身就是包含6个2D纹理的纹理,它优势在于可以通过一个方向向量来进行索引/采样。只要在立方体贴图的中心点,就能使用立方体的实际位置向量来对立方体贴图进行采样。 创建立方体贴图 与2D纹理区别不大,创建立方体贴图同样是创建纹理,只是我们的glBindTexture的方法的参数要变为GLES20.GL_TEXTURE_CUBE_MAP,然后同样要处理环绕和过滤方式。与2D纹理不同的是,它需要用6张图片来分别设置立方体的六个面 阅读详情

相关推荐

Android OpenGL ES 3D立方体多纹理贴图实现教程

在计算机图形学中,三维模型的创建和渲染都需要严谨的数学支持,尤其是线性代数中的向量和矩阵运算,它们在定义三维空间中的对象以及在处理坐标变换时都发挥着关键作用。GLSL与C语言有很强的相似性,但它专为图形编程进行了优化和扩展。GLSL基本单位是着色器,包含一系列的输入、输出变量,以及处理这些变量的程序代码。以下是GLSL的一些基础语法要点:变量类型:如floatintboolvec2vec3vec4(向量)、mat2mat3mat4(矩阵)等。数组与结构体。

weixin_29050829的博客 1224

OpenGL高级-立方体贴图

 渲染物体的顶点着色器:  渲染物体的片段着色器:  渲染天空盒的顶点着色器:  渲染天空盒的片段着色器: 主程序 优化  如果先渲染天空盒再渲染物体,由于场景中天空盒很多的片段可能被物体遮挡,但先渲染天空盒会对天空盒的所有片段执行片段着色器,这样会造成性能的浪费。如果我们先渲染物体,然后只渲染天空盒没有被遮挡的部分,那么会得到优化,如何渲染天空盒没有被遮挡的部分呢?  透视除法在顶点着色器之后执行,即把gl_Position的xyz除以w元素。我们需要使得天空盒在执行透视除法后z元素为1,因此我们在天空

少年的博客 1086

Android OpenGL 立方体贴图应用举例-天空盒演示demo源码

Android OpenGL 立方体贴图应用举例——天空盒演示demo源码 立方体贴图详解见:https://blog.youkuaiyun.com/github_27263697/article/details/143738612 一、概念 二、如何使用 1、创建立方体贴图 2、生成纹理 3、设置纹理环绕和过滤方式 4、激活和绑定立方体贴图 三、应用举例——天空盒 1、概念 2、加载天空盒 3、显示天空盒 4、优化 四、应用举例——环境映射:反射 五、应用举例——环境映射:折射 六、应用举例——动态环境贴图

【Android OpenGL ES 开发 (四)】纹理相关(一)

纹理贴图的原理 1.作用:可以用来渲染视频。 生成OpenGL中的纹理对象 1.像素数据想要绘制出来需要先变成纹理 2.创建纹理放在GPU上 GLuint CreateTexture2D(unsigned char *pixelData,int width,int height,GLenum type) { GLuint texture; glGenTextures(1,&texture);//创建一个纹理对象 glBindTexture(GL_TEXTURE_2

用可见的方式来记录和分享每一次收获 743

基于yolov5的鸟类图像准确识别

本项目主要基于yolov5进行鸟类准确识别,主要识别白鹭家族,红脚鹬,反嘴鹬,环颈珩,小白鹭以及夜鹭六类鸟

weixin_46064184的博客 3822

[Dify] 如何在Dify中解析上传的TXT文件内容

在Dify平台上构建智能应用时,解析用户上传的.txt文件是关键步骤。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 2636

在Android中使用OpenGL ES开发第(六)节:纹理贴图实现

一、前期出知识储备 在前面的文章里,我们已经对点、线和三角形进行了渲染,并用这些简单的图形和颜色完成了一些常规的工作。但是还缺点什么,如果我们想在这些图形上绘画并加入精致的细节呢?像艺术家一样,我们可以从基本的图形和颜色开始,再使用纹理(texture)在其表面上加入额外的细节。简单来说,纹理就是一个图像或照片,它们可以被加载进OpenGL中。 自然界中的纹理是二维的,但是OpenGL也支...

Chin_Style的博客 5147

【异常】OpenClaw 项目 `fetch failed` 报错问题排查与解决方案Response interrupted: TypeError: fetch failed

针对无超时控制、异常兜底缺失导致的请求中断,封装标准化的安全请求工具,一次性解决超时控制、异常捕获、日志埋点三大问题,全项目替换原生。:将项目运行的 Node.js 版本升级至 18.x 及以上 LTS 版本,使用 Node.js 内置的稳定版。实现的网络请求环节,包括但不限于:第三方开放接口调用、内部服务接口通信、跨域资源请求、外部配置拉取等场景。:针对无法升级 Node.js 版本的存量环境,通过社区稳定兼容包替换原生。类型异常,直接造成业务请求响应中断。第二步:业务代码改造,替换原生。

奶爸的编程之路,也就一周冷个三天 366

第十九章 opengl之高级OpenGL(立方体贴图)

第十九章 opengl之高级OpenGL(立方体贴图)

Re_view的博客 1028

爆肝整理:微信公众号文章HTML编写完整规范,运营必备手册

微信公众号文章排版总是出错?📱 这份完整的HTML编写规范文档帮你彻底解决!文档包含所有支持的标签、CSS属性、实用代码模板和注意事项 📋,让你快速掌握微信文章的HTML编写技巧,告别第三方编辑器依赖 ✅

XiaoqiangClub的博客 2301

《派出你的AI同事:WorkBuddy案例实战》055:客服工单自动分类与话术生成

客服工单自动分类与话术生成 —— 《派出你的AI同事:WorkBuddy案例实战》系列文章,配图已统一为规范示意图。

LuckyHanMo的博客 281

学习OpenGL ES for Android(二十三)— 立方体贴图

我们前面学过纹理贴图,我们可以用6个2D纹理的纹理构建成立方体,而立方体贴图本身就是包含6个2D纹理的纹理,它优势在于可以通过一个方向向量来进行索引/采样。只要在立方体贴图的中心点,就能使用立方体的实际位置向量来对立方体贴图进行采样。 创建立方体贴图 与2D纹理区别不大,创建立方体贴图同样是创建纹理,只是我们的glBindTexture的方法的参数要变为GLES20.GL_TEXTURE_CU...

chends 1689

YOLO11有效改进专栏目录

YOLO11改进专栏导航

A1983Z的博客 3674

OpenGL ES 3.0立方体贴图编程教程:创建沉浸式环境反射效果

OpenGL ES 3.0立方体贴图是实现环境反射、天空盒等高级视觉效果的核心技术,能让3D场景呈现出逼真的环境交互效果。本教程将通过**Simple_TextureCubemap**示例项目,带你快速掌握立方体贴图的创建与应用方法,从零开始构建令人惊艳的沉浸式图形应用。 ## 📌 什么是立方体贴图? 立方体贴图(Cube Map)是一种特殊的纹理映射技术,由6个2D纹理组成,分别对应立方体

gitblog_00156的博客 425

05 - GRACE数据处理-球谐展开与球谐综合

GRACE数据处理-球谐展开和综合前面在介绍GRACE相关理论的时候提到过下面的公式,从公式形式上可以看出,面密度变化和球谐系数(CS)之间是能够相互转换的,那这个转化的过程可以称为球谐展开,简单理解就是将全球网格数据转化为球谐系数的过程。而球谐综合可以看作是球谐展开的逆过程,利用球谐系数计算到全球格网分布。

weixin_43339605的博客 1050

Linux LT8912b调试记录(MIPI转LVDS/HDMI)

本文记录了在RK3588平台上使用LT8912B芯片实现MIPI转LVDS/HDMI的调试过程。主要包含设备树配置、驱动代码实现及常见问题解决。调试重点包括:1)正确配置1280x800分辨率的LVDS屏幕参数;2)确保I2C总线正常通信;3)解决花屏、图像抖动、黑屏等问题,涉及lane-rate计算、同步信号极性调整及MIPI模式选择。文中提供了详细的寄存器配置代码和故障排查方法,特别强调了I2C通信验证和电压匹配的重要性。通过参数优化和多种模式测试,最终实现了稳定的视频输出转换。

qq_45147279的博客 1086

android opengl es 3d 贴图 旋转立方体demo

效果展示源码和apk的下载资源下载核心代码package com.rex;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLSurfaceView; import android.opengl.GLU; import android.opengl.GLUtils

qq_28844947的博客 1724

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

OpenGL ES -> SurfaceView + EGL实现立方体纹理贴图+透视效果

OpenGL ES -> SurfaceView + EGL实现立方体纹理贴图+透视效果的Kotlin代码

sunshine_guo的博客 513

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

opengl es3.0学习篇八:纹理

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33701564的博客 376

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【Android】OpenGL ES---绘制3D图形、应用纹理贴图

绘制3D图形 glDrawElements(int mode,int count,int type Buffer indices): 根据indices指定的索引点来绘制三角形 第一个参数mode指定绘制的图形类型,可设置为GL10.GL_TRIANGLES或GL10.GL_TRIANGLE_STRIPE; 第二个参数指定一共包含多少个顶点。 indices参数最重要,它包装了一个长度为3N的数组,比如让该参数包装(0,2,3, 1, 4,5 )数组,这意味着告诉OpenGL ES 要绘制两个三角形,第一

qq_42179419的博客 1099

初学Android,OpenGL ES之使用纹理(八十三)

在网上发现这些讲纹理的文章,非常不错android 游戏导引(4. 简单纹理贴图)http://www.cnblogs.com/shengdoushi/archive/2011/01/13/1934181.htmlAndroid OpenGL es 纹理坐标设定与贴图规则http://blog.youkuaiyun.com/cjkwin/article/details/6016224Android OpenG

lee576的专栏 8951

初学Android OpenGL ES之使用纹理 八十三

初学Android OpenGL ES之使用纹理 八十三

hffyyff的博客 206

Android OpenGL天空盒

Android OpenGL天空盒 天空盒是表达三维全景的一个方法,不管你的头转向哪边,这个全景图在任何方向上都能被看见。 1、立方体贴图 立方体一共有6个面,需要6个图片资源,按照左、右、下、上、前和后的顺序传递立方体的面。 立方体贴图的惯例是:在立方体内部使用左手坐标系统,而在立方体外部使用右手坐标系统。所以前面的纹理贴到z轴的负面,后面的纹理贴到z轴的正面。 2、加载图片 (

假装你是大灰狼的专栏 1319

OpenGL ES for Android(光照贴图)

简介 在之前文章中,我们模拟了物体的独特的光照特效,但是在一个面上所有点的效果都是一样的,显然和现实情况还有差距。在现实世界中,大部分物体的表面都是有不同材质的,对光的反应也不相同。在光照场景中,通常有漫反射和镜面光贴图(Map)两种方式,来精确控制物体的漫反射分量和镜面光分量以模拟现实世界的物体。 漫反射贴图 现在我们使用纹理来代替前面的纯色实现立方体的面,然后显示光照的效果。我们使用下面这样一幅图片来作为立方体的面: struct Material { sampler2D

1 373

Android OpenGL ES 2.0 完整开发指南:从零到三维旋转立方体

这是一个完整的 Android OpenGL ES 2.0 示例项目,展示如何在 Android 平台上使用 Kotlin 和 OpenGL ES 2.0 渲染一个带有纹理贴图的 3D 旋转立方体。· 索引缓冲区(EBO): 存储绘制顺序,减少重复顶点。· 检查图片尺寸是否为2的幂次方(非必须,但推荐)· 顶点缓冲区(VBO): 存储顶点坐标数据。· 顶点坐标是否在 -1 到 1 范围内。· 纹理坐标缓冲区: 存储UV坐标。· MVP矩阵计算是否正确。· 添加备用纹理生成机制。· 索引顺序是否正确。

tangweiguo03051987的博客 512

Android学习之-------OpenGLES详解

Android OpenGLES2.0(一)——了解OpenGLES2.0 https://blog.youkuaiyun.com/junzia/article/details/52793354 Android OpenGLES2.0(二)——绘制一个三角形 https://blog.youkuaiyun.com/junzia/article/details/52801772 Android OpenGLES2.0(三)...

菠萝菠萝蜜的博客 434
上一篇: Android OpenGL ES详解——纹理
下一篇: Android OpenGL ES详解——glTexImage2D方法
闲暇部落
博客等级 码龄12年 2775粉丝 215原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲暇部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值