OpenGL教程之 纹理练习

news2024/12/24 0:23:38

网址

LearnOpenGL
在这里插入图片描述

练习一

 修改片段着色器,仅让笑脸图案朝另一个方向看。
 解析:朝向另一个方向很简单,即让上文中的图片进行左右对称变换即可,即将片段着色器中笑脸的纹理坐标从textCord转换为vec2( 1 - textCord.x, text.y )。这里用到了GLSL向量的重组技巧。
 代码:

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;

void main()
{
    FragColor = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, vec2(1.0 - TexCoord.x, TexCoord.y)), 0.2);
}

练习二

 尝试用不同的纹理环绕方式,设定一个从0.0f到2.0f范围内的(而不是原来的0.0f到1.0f)纹理坐标。试试看能不能在箱子的角落放置4个笑脸。

GL_REPEAT 环绕

 更改顶点数据中的纹理坐标即可:

GLfloat 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 Right
         0.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 
    };

 运行结果为:
在这里插入图片描述

GL_MIRRORED_REPEAT 环绕

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);

 修改纹理二S轴的环绕方式为GL_MIRRORED_REPEAT,结果为:
在这里插入图片描述

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

 修改纹理二S轴和T轴的环绕方式为GL_MIRRORED_REPEAT,结果为:
在这里插入图片描述

GL_CLAMP_TO_EDGE 环绕

 对两个纹理都采用 GL_CLAMP_TO_EDGE 环绕方式,代码如下:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

 结果如下:
在这里插入图片描述

GL_CLAMP_TO_BORDER 环绕

 对笑脸纹理采用 GL_CLAMP_TO_BORDER 环绕方式,代码如下:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    float borderColor[] = { 1.0f, 1.0f , 0.0f, 1.0f };
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

 结果展示:
在这里插入图片描述

练习三

 尝试在矩形上只显示纹理图像的中间一部分,修改纹理坐标,达到能看见单个的像素的效果。尝试使用GL_NEAREST的纹理过滤方式让像素显示得更清晰。
 只显示纹理图形的中间一部分,只用将顶点的纹理坐标都修改到中间即可,具体的顶点数据为:

GLfloat vertices[] = {
        // Positions          // Colors           // Texture Coords  (Note that we changed them to 'zoom in' on our texture image)
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   0.55f, 0.55f,  // Top Right
         0.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 
    };

 纹理过滤方式的设置:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

 具体效果:
在这里插入图片描述

练习四

 使用一个uniform变量作为mix函数的第三个参数来改变两个纹理可见度,使用上和下键来改变箱子或笑脸的可见度。
 在片段着色器中定义一个uniform的变量:

#version 330 core
in vec3 ourColor;
in vec2 TexCoord;

out vec4 color;

uniform float mixValue;

// Texture samplers
uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;

void main()
{
	// Linearly interpolate between both textures (second texture is only slightly combined)
	color = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), mixValue);
}

 游戏循环中的赋值:

glUniform1f(glGetUniformLocation(ourShader.Program, "mixValue"), mixValue);

 按键事件处理代码:

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
    // Change value of uniform with arrow keys (sets amount of textre mix)
    if (key == GLFW_KEY_UP && action == GLFW_PRESS)
    {
        mixValue += 0.1f;
        if (mixValue >= 1.0f)
            mixValue = 1.0f;
    }
    if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
    {
        mixValue -= 0.1f;
        if (mixValue <= 0.0f)
            mixValue = 0.0f;
    }
}

 结果:
在这里插入图片描述
 完整代码:

#include <iostream>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>

// Other Libs
#include <SOIL.h>

// Other includes
#include "Shader.h"


// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

// Holds uniform value of texture mix
GLfloat mixValue = 0.2f;

// The MAIN function, from here we start the application and run the game loop
int main()
{
    // Init GLFW
    glfwInit();
    // Set all the required options for GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);

    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);

    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    glewInit();

    // Define the viewport dimensions
    glViewport(0, 0, WIDTH, HEIGHT);


    // Build and compile our shader program
    Shader ourShader("path/to/shaders/textures.vs", "path/to/shaders/textures.frag");


    // Set up vertex data (and buffer(s)) and attribute pointers
    GLfloat vertices[] = {
        // Positions          // Colors           // Texture Coords
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // Top Right
         0.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 
    };
    GLuint indices[] = {  // Note that we start from 0!
        0, 1, 3, // First Triangle
        1, 2, 3  // Second Triangle
    };
    GLuint VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // Color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // TexCoord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(0); // Unbind VAO


    // Load and create a texture 
    GLuint texture1;
    GLuint texture2;
    // ====================
    // Texture 1
    // ====================
    glGenTextures(1, &texture1);
    glBindTexture(GL_TEXTURE_2D, texture1); // All upcoming GL_TEXTURE_2D operations now have effect on our texture object
    // Set our texture parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// Set texture wrapping to GL_REPEAT
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // Set texture filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // Load, create texture and generate mipmaps
    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); // Unbind texture when done, so we won't accidentily mess up our texture.
    // ===================
    // Texture 2
    // ===================
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);
    // Set our texture parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // Set texture filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // Load, create texture and generate mipmaps
    image = SOIL_load_image("awesomeface.png", &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);
   

    // Game loop
    while (!glfwWindowShouldClose(window))
    {
        // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
        glfwPollEvents();

        // Render
        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
	
        // Activate shader
        ourShader.Use();     

        // Bind Textures using texture units
        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);  

        // Set current value of uniform mix
        glUniform1f(glGetUniformLocation(ourShader.Program, "mixValue"), mixValue);
        
        // Draw container
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        // Swap the screen buffers
        glfwSwapBuffers(window);
    }
    // Properly de-allocate all resources once they've outlived their purpose
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    // Terminate GLFW, clearing any resources allocated by GLFW.
    glfwTerminate();
    return 0;
}

// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
    // Change value of uniform with arrow keys (sets amount of textre mix)
    if (key == GLFW_KEY_UP && action == GLFW_PRESS)
    {
        mixValue += 0.1f;
        if (mixValue >= 1.0f)
            mixValue = 1.0f;
    }
    if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
    {
        mixValue -= 0.1f;
        if (mixValue <= 0.0f)
            mixValue = 0.0f;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【淘宝】商品列表页数据采集+商品销量数据采集代码

采集场景 在淘宝首页&#xff08;https://s.taobao.com/&#xff09;输入关键词搜索&#xff0c;采集搜索后得到的商品列表页数据。示例中关键词为【耐克】&#xff0c;可根据需求进行更换&#xff0c;同时支持自动批量输入多个关键词。 采集字段 采集字段包括关键字文本值…

Nginx和tomcat反向代理(动静分离)

正向代理&#xff1a; 当用户想访问某一网址时&#xff0c;用户先访问代理服务器&#xff0c;然后由代理服务器向目标网址发送请求最终将数据返回代理服务器&#xff0c;最后代理服务器将数据返回给用户这一过程我们称之为正向代理。 反向代理&#xff1a;基本流程是与正向代理…

【react全家桶学习】如何创建一个react组件(超详)

前提是你安装了react脚手架&#xff0c;不会的看这里&#xff0c;然后再进行创建哦~ 【react全家桶学习】初始化react脚手架及项目结构讲解_suohs Blog的博客-CSDN博客 目录 问题1&#xff1a;如何创建一个简单的hello组件&#xff1f; 问题2&#xff0c;如果组件特别多怎么…

庚顿数据正式发布军工版实时数据库庚金3.0,鼎力支撑中国国防数字化

庚金实时数据库管理系统是北京庚顿数据科技有限公司旗下自主知识产权的军工级产品&#xff0c;可有效满足特种行业自主产权、高性能、高安全、高稳定等高端需求&#xff0c;轻松实现海量实时数据高频采集、海量存储等应用场景&#xff0c;切实保障了客户生产活动的稳定运行。庚…

c/c++:数组做函数参数,传入函数的首地址,相当于传址,指针做函数返回值,数组止做c语言中函数的返回值

c/c:数组做函数参数&#xff0c;传入函数的首地址&#xff0c;相当于传址&#xff0c;指针做函数返回值&#xff0c;数组禁止做c语言中函数的返回值 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0…

Python小姿势 - Python基础知识

Python基础知识 Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。 Python的创始人为吉多范罗苏姆&#xff08;Guido van Rossum&#xff09;&#xff0c;于1989年底发布第一个公开发行版本——0.9.0。 自2004年以来&#xff0c;Python已经成为顶级开源项目&…

从浏览器地址栏输入 url 到显示主页的过程?

当在浏览器地址栏输入一个URL并按下回车键后&#xff0c;发生了一系列复杂的过程&#xff1a; DNS解析&#xff1a;浏览器会对输入的URL进行DNS解析&#xff0c;将域名转换为服务器的IP地址。这一过程包括浏览器缓存、操作系统缓存、本地HOST文件配置、本地DNS服务器以及远程DN…

多通道振弦传感器无线采集仪 数据发送详解

多通道振弦传感器无线采集仪 数据发送过程 每次采集仪启动后会将采集到的传感器数据进行内部存储&#xff0c;并在设置好的时间间隔将数据发送出去&#xff0c;通过修改“数据发送方式”参数&#xff0c;监测数据可由数据接口输出也可经由无线网络发送。 在发送监测数据时&…

SpringCloud --- Nacos注册中心、配置管理

一、Nacos注册中心 1.1、认识和安装Nacos Nacos是阿里巴巴的产品&#xff0c;现在是SpringCloud中的一个组件。相比Eureka功能更加丰富&#xff0c;在国内受欢迎程度较高。 1.2、服务注册到nacos Nacos是SpringCloudAlibaba的组件&#xff0c;而SpringCloudAlibaba也遵循Spr…

3dtiles之点云pnts文件详解

3DTiles是一种用于在WebGL环境中渲染大规模三维地理数据的规范&#xff0c;它允许开发者将复杂的三维数据以高效的方式传输、存储和呈现。而PNTS格式则是3DTiles规范中用于存储点云数据的格式之一。在本文中&#xff0c;我们将探讨3DTiles和PNTS的基本原理以及它们如何用于处理…

集成学习(Ensembles)

Ensembles 前言EnsemblesAveraging,StackingWhy does averaging work?如何理解&#xff1a;In practice errors won’t be completely independent due to noise in the labels Random ForestsDoes averaging work if you use trees with the same parameters?Bootstrap Samp…

【AgentGPT】网页版的 Auto-GPT,让 AI 成为我们的生产力工具

在上一篇文章笔者分享了 Auto-GPT 的安装&使用,不过因为操作相对繁琐,可能会导致许多想使用工具的人卡在环境的设定上。 所以这边再介绍另一款无需安装,可直接使用的工具“AgentGPT”;他的操作超级简单,只要设定好目标(Goal),一键发送即可! 大纲 ▋ 如何免费使用 A…

【C++】计算类的大小

目录 简介计算类的大小场景1&#xff1a;空类场景2场景3&#xff1a;含有虚函数场景4&#xff1a;继承场景5&#xff1a;存在字节对齐的情况 总结结语 简介 Hello&#xff01; 非常感谢您阅读海轰的文章&#xff0c;倘若文中有错误的地方&#xff0c;欢迎您指出&#xff5e; …

Linux多媒体子系统02:V4L2核心框架分析(部分)

目录 1 V4L2框架结构概述 1.1 imx8视频输入通路硬件结构 1.2 V4L2设备节点观察 1.3 dts配置观察 1.4 probe函数观察 1.4.1 函数功能简介 1.4.2 各模块probe函数分析 1.5 V4L2框架结构图示 2 设备管理机制 2.1 v4l2_device结构体相关 2.1.1 v4l2_device结构体 2.1.2…

15.Java多线程

目录 1. Java基本介绍 2. JDK下载安装及其环境配置 3. 一个简单的java程序 4. Eclipse基本使用、数据类型、运算符 5. 控制语句&#xff08;if、switch、for、while、foreach&#xff09; 6. Java数组 7. Java字符串对象(String|StringBuffer|StringBuilder|StringJoiner…

教你如何免费使用ChatGPT 4?(国内可以直接访问,不用魔法)

目录 一. 内容介绍 二. 功能介绍 三. 优势 四. 版本比较 五. 国内试用方法 内容介绍&#xff1a; ChatGPT 4是由OpenAI开发的最新一代大型语言模型&#xff0c;其采用了GPT-3.5的技术架构&#xff0c;是目前全球最强大的通用AI模型之一。ChatGPT 4拥有极高的语言处理能力和…

SD卡恢复怎么做?内存卡数据恢复,3个方法!

案例&#xff1a;sd卡怎么恢复&#xff1f; 【我的sd卡用了快一年了&#xff0c;里面存储了很多非常重要的文件&#xff0c;但不知道为什么我今天将它插入电脑后&#xff0c;很多文件都无法显示了&#xff0c;大家有什么好的方法可以恢复sd卡吗&#xff1f;感谢回答&#xff0…

【翻译一下官方文档】之uniapp的导航条设置

目录 uni.setNavigationBarTitle(OBJECT) uni.setNavigationBarColor(OBJECT) uni.hideHomeButton(OBJECT) uni.setNavigationBarTitle(OBJECT) 动态设置当前页面的标题。 OBJECT参数说明 参数类型必填说明titleString是页面标题successFunction否接口调用成功的回调函数fai…

安虚拟机详细教程 VMware虚拟机与主机之间不能复制粘贴及拖拽问题

VMware虚拟机中安装Ubuntu18.04&#xff08;linux发行版&#xff09;【超详细图文教程】_vmware安装ubuntu18.04__7270的博客-CSDN博客 1. 查看vmware Tools是否安装 打开虚拟机 &#xff0c;点击上方导航栏 ‘虚拟机’ 查看VMware Tools是否安装&#xff0c;如果未安装&#…

Linux和shell命令第一节课

windows开发 linux服务 区块链&#xff0c; 稳定&#xff0c;安全&#xff0c;可移植性&#xff0c;低资源消耗&#xff0c;开源软件---windows付费 linux就是操作系统&#xff0c;网络服务&#xff0c;移动设备&#xff0c;嵌入式系统&#xff0c;计算器服务器 除个人桌面…