文章目录
前言
本文主要介绍如何在一个wayland client 里面使用 egl + opengles 实现一个最简单的纹理贴图功能,在阅读本篇文章之前,建议先读一下之前的文章 《wayland(xdg_wm_base) + egl + opengles 最简实例》
软硬件环境
硬件:PC
软件:ubuntu22.04 weston9.0 opengles2.0/3.0 egl1.4
一、纹理贴图
1. 纹理贴图介绍
纹理贴图(Texture Mapping)是计算机图形学中的一种技术,用于将图像或纹理应用到模型的表面上,以增强模型的外观和细节;纹理贴图可以使模型表面呈现出更加真实、具有细节和复杂度的外观,而不仅仅是简单的几何形状。它通过将图像或纹理映射到模型的各个顶点或多边形上来实现。
2. 使用opengles 实现纹理贴图的主要步骤
1.创建纹理对象并绑定到当前环境中
使用 glGenTextures 函数生成一个纹理对象的标识符,并绑定到当前环境中;
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
- 设置纹理参数
通过 glTexParameteri 函数设置纹理的过滤方式和纹理坐标的环绕方式,常见的过滤方式有线性过滤和最近点采样,常见的环绕方式有重复和镜像
// 设置纹理缩小时的过滤方式(缩小的情况下,将多个纹素映射到一个片元上)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// 设置纹理放大时的过滤方式(放大的情况下,将一个纹素映射到一个片元上)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 设置纹理坐标的环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- 加载纹理图像数据
使用 glTexImage2D 函数加载纹理图像数据到纹理对象中。可以从图像文件中加载纹理,也可以通过代码生成纹理数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
- 使用纹理
将纹理坐标传递给顶点着色器,并在片段着色器中进行纹理采样
opengles2.0 版本:
// 在顶点着色器中传递纹理坐标
const char* const vertexShaderSource =
"attribute vec4 vPosition; \n"
"attribute vec2 aTexCoord; \n"
"varying vec2 vTexCoord; \n"
"void main()\n"
"{\n"
" gl_Position = vPosition;\n"
"vTexCoord = aTexCoord; \n"
"}\n";
// 在片段着色器中进行纹理采样
const char* const fragmentShaderSource =
"precision mediump float;\n"
"varying vec2 vTexCoord; \n"
"uniform sampler2D uTexture; \n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(uTexture, vTexCoord);\n"
"}\n";
opengles3.0 版本:
// Vertex shader code
const char* const vertexShaderSource =
"#version 300 es \n"
"layout (location = 0) in vec4 vPosition; \n"
"layout (location = 1) in vec2 aTexCoord; \n"
"out vec2 vTexCoord; \n"
"void main()\n"
"{\n"
" gl_Position = vPosition;\n"
" vTexCoord = aTexCoord; \n"
"}\n";
// fragment shader code
const char* const fragmentShaderSource =
"#version 300 es \n"
"precision mediump float;\n"
"in vec2 vTexCoord; \n"
"layout (location = 0) out vec4 outColor;"
"uniform sampler2D uTexture; \n"
"void main()\n"
"{\n"
" outColor = texture(uTexture, vTexCoord);\n"
"}\n";
- 绑定纹理对象并传递给片段着色器
// 获取uniform变量的位置
GLint u_texture = glGetUniformLocation(program, "uTexture");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(u_texture, 0);
- 绘制结束,清除纹理
glDeleteTextures(1, &texture);
二、代码实例
1. opengles2.0 版本的egl_wayland_texture.c
代码如下(示例):
#include <wayland-client.h>
#include <wayland-server.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xdg-shell-client-protocol.h"
#define WIDTH 640
#define HEIGHT 480
struct wl_display *display = NULL;
struct wl_compositor *compositor = NULL;
struct xdg_wm_base *wm_base = NULL;
struct wl_registry *registry = NULL;
struct window {
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_egl_window *egl_window;
};
// Index to bind the attributes to vertex shaders
const unsigned int VertexArray = 0;
static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
{
xdg_wm_base_pong(shell, serial);
}
/*for xdg_wm_base listener*/
static const struct xdg_wm_base_listener wm_base_listener = {
xdg_wm_base_ping,
};
/*for registry listener*/
static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
{
if (!strcmp(interface, "wl_compositor")) {
compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) {
wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(wm_base, &wm_base_listener, NULL);
}
}
void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name)
{
}
static struct wl_registry_listener registry_listener = {
registry_add_object, registry_remove_object};
static void
handle_surface_configure(void *data, struct xdg_surface *surface,
uint32_t serial)
{
//struct window *window = data;
xdg_surface_ack_configure(surface, serial);
//window->wait_for_configure = false;
}
static const struct xdg_surface_listener xdg_surface_listener = {
handle_surface_configure
};
static void
handle_toplevel_configure(void *data, struct xdg_toplevel *toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{
}
static void
handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_toplevel_configure,
handle_toplevel_close,
};
bool initWaylandConnection()
{
if ((display = wl_display_connect(NULL)) == NULL)
{
printf("Failed to connect to Wayland display!\n");
return false;
}
if ((registry = wl_display_get_registry(display)) == NULL)
{
printf("Faield to get Wayland registry!\n");
return false;
}
wl_registry_add_listener(registry, ®istry_listener, NULL);
wl_display_dispatch(display);
if (!compositor)
{
printf("Could not bind Wayland protocols!\n");
return false;
}
return true;
}
bool initializeWindow(struct window *window)
{
initWaylandConnection();
window->surface = wl_compositor_create_surface (compositor);
window->xdg_surface = xdg_wm_base_get_xdg_surface(wm_base, window->surface);
if (window->xdg_surface == NULL)
{
printf("Failed to get Wayland xdg surface\n");
return false;
} else {
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
window->xdg_toplevel =
xdg_surface_get_toplevel(window->xdg_surface);
xdg_toplevel_add_listener(window->xdg_toplevel,
&xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "egl_wayland_texture");
}
return true;
}
void releaseWaylandConnection(struct window *window)
{
if(window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel);
if(w