openGL增强表面细节----高度贴图

2023-11-18

openGL系列文章目录

前言

现在我们扩展法线贴图的概念——从纹理图像用于扰动法向量到扰乱顶点位置本身。实
际上,以这种方式修改对象的几何体具有一定的优势,例如使表面特征沿着对象的边缘可
见,并使特征能够响应阴影贴图。我们将会看到,它还可以帮助构建地形。
一种实用的方法是使用纹理图像来存储高度值,然后使用该高度值来提升(或降低)顶
点位置。含有高度信息的图像称为高度图,使用高度图更改对象的顶点的方法称为高度贴
图①。高度图通常将高度信息编码为灰度颜色:(0,0,0)(黑色)=低高度,(1,1,1)(白色)=
高高度。这样一来通过算法或使用“画图”程序就可以轻松创建高度图。图像的对比度越
高,其表示的高度变化越大。这些概念将在图1(显示随机生成的地图)和图10.13(显
示有组织的模式的地图)中说明。
在这里插入图片描述
图1
改变顶点位置是否有用取决于改变的模型。顶点操作可以在顶点着色器中轻松完成,当模型顶点细节级别够高(例如在足够高精度的球体中)时,改变顶点高度的方法效果很好。但是,当模型的顶点数量很少(例如立方体的角)时,渲染对象的表面需要依赖于光栅器中的顶点插值来填充细节。当顶点着色器中可用于改变高度的顶点很少时,许多像素的高度将无法从高度图中检索,而需要由插值生成,从而导致表面细节较差。当然,在片段着色器中是不可能进行顶点操作的,因为这时顶点已被光栅化为像素位置。程序 展示了一个将顶点“向外”(即在表面法向量的方向上)移动的顶点着色器代
码。它通过将顶点法向量乘以从高度图检索所得的值,然后将该乘积与顶点位置相加,以
“向外”移动顶点。

一、代码

主程序c++

#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <SOIL2\soil2.h>
#include <string>
#include <iostream>
#include <fstream>
#include <glm\gtc\type_ptr.hpp> // glm::value_ptr
#include <glm\gtc\matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
#include "ImportedModel.h"
#include "Utils.h"
using namespace std;

float toRadians(float degrees) { return (degrees * 2.0f * 3.14159f) / 360.0f; }

#define numVAOs 1
#define numVBOs 3

float cameraX, cameraY, cameraZ;
float gndLocX, gndLocY, gndLocZ;
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];

// variable allocation for display
GLuint mvLoc, projLoc;
int width, height;
float aspect;
glm::mat4 pMat, vMat, mMat, mvMat;

ImportedModel ground("grid.obj");
int numGroundVertices;

GLuint heightMap;
GLuint heightTexture;

void setupVertices(void) {
	numGroundVertices = ground.getNumVertices();
	std::vector<glm::vec3> vert = ground.getVertices();
	std::vector<glm::vec2> tex = ground.getTextureCoords();
	std::vector<glm::vec3> norm = ground.getNormals();

	std::vector<float> pvalues;
	std::vector<float> tvalues;
	std::vector<float> nvalues;

	for (int i = 0; i < numGroundVertices; i++) {
		pvalues.push_back((vert[i]).x);
		pvalues.push_back((vert[i]).y);
		pvalues.push_back((vert[i]).z);
		tvalues.push_back((tex[i]).x);
		tvalues.push_back((tex[i]).y);
		nvalues.push_back((norm[i]).x);
		nvalues.push_back((norm[i]).y);
		nvalues.push_back((norm[i]).z);
	}

	glGenVertexArrays(1, vao);
	glBindVertexArray(vao[0]);
	glGenBuffers(numVBOs, vbo);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, pvalues.size() * 4, &pvalues[0], GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, tvalues.size() * 4, &tvalues[0], GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
	glBufferData(GL_ARRAY_BUFFER, nvalues.size() * 4, &nvalues[0], GL_STATIC_DRAW);
}

void init(GLFWwindow* window) {
	renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
	cameraX = 0.03f; cameraY = 0.03f; cameraZ = 0.8f;
	gndLocX = 0.0f; gndLocY = 0.0f; gndLocZ = 0.0f;

	glfwGetFramebufferSize(window, &width, &height);
	aspect = (float)width / (float)height;
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);

	setupVertices();

	heightTexture = Utils::loadTexture("heightTexture.jpg");
	heightMap = Utils::loadTexture("height.jpg");
}

void display(GLFWwindow* window, double currentTime) {
	glClear(GL_DEPTH_BUFFER_BIT);
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glUseProgram(renderingProgram);

	mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
	projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");

	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
	mMat = glm::translate(glm::mat4(1.0f), glm::vec3(gndLocX, gndLocY, gndLocZ));
	mMat = glm::rotate(mMat, toRadians(15.0f), glm::vec3(1.0f, 0.0f, 0.0f));
	mvMat = vMat * mMat;

	glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));

	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(1);

	glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(2);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, heightTexture);

	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, heightMap);

	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CCW);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	glDrawArrays(GL_TRIANGLES, 0, numGroundVertices);
}

void window_size_callback(GLFWwindow* win, int newWidth, int newHeight) {
	aspect = (float)newWidth / (float)newHeight;
	glViewport(0, 0, newWidth, newHeight);
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);
}

int main(void) {
	if (!glfwInit()) { exit(EXIT_FAILURE); }
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	GLFWwindow* window = glfwCreateWindow(800, 800, "Chapter10 - program4a", NULL, NULL);
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);

	glfwSetWindowSizeCallback(window, window_size_callback);

	init(window);

	while (!glfwWindowShouldClose(window)) {
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

## 2.着色器程序
顶点着色器

```cpp
#version 430

layout (location=0) in vec3 vertPos;
layout (location=1) in vec2 texCoord;
layout (location=2) in vec3 vertNormal;

out vec2 tc;

uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D t;	// for texture
layout (binding=1) uniform sampler2D h;	// for height map

void main(void)
{	vec4 p = vec4(vertPos,1.0) + vec4((vertNormal*((texture(h, texCoord).r)/5.0f)),1.0f);
	tc = texCoord;
	gl_Position = proj_matrix * mv_matrix * p;
}

2.片元着色器

#version 430

in vec2 tc;
out vec4 fragColor;

uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D t;	// for texture
layout (binding=1) uniform sampler2D h;	// for height map

void main(void)
{	fragColor = texture(t, tc);
}

效果

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

openGL增强表面细节----高度贴图 的相关文章

  • OpenGL NURBS 曲面

    我正在学习 OpenGL 我想要一个中间有轻微驼峰的表面 我目前正在使用这段代码 但我不确定如何调整 ctrl 点以使其达到我想要的方式 它目前就像 我想要这样的 我不完全确定我应该使用哪些控制点 并且我对其工作原理感到困惑 include
  • Opengl 非同步/非阻塞地图

    我刚刚找到以下内容OpenGL 规范ARB map buffer range http www opengl org registry specs ARB map buffer range txt 我想知道是否可以使用此扩展进行非阻塞地图调
  • 交错顶点提交如何提高性能?

    我已经阅读并看到了其他问题 这些问题通常都指向将顶点位置和颜色等交错到一个数组中的建议 因为这可以最大限度地减少从 cpu 发送到 gpu 的数据 我不清楚的是 即使使用交错数组 您仍然必须对位置和颜色指针进行单独的 GL 调用 OpenG
  • 使用 openGL、SOIL 加载图像

    我尝试了很多使用 SOIL 在 openGL 中加载和显示图像的示例 运行下面的源代码时 它仅显示一个没有图像的白色四边形 我尝试打开一个名为 foto 的图像 我将图像文件放在程序的文件夹中 bool keyStates new bool
  • (定义一个宏)方便OpenGL命令调试?

    有时插入条件打印和检查需要很长时间glGetError 使用二分搜索的形式来缩小范围 其中第一个函数调用是 OpenGL 首先报告错误 我认为如果有一种方法可以构建一个宏 我可以包装所有可能失败的 GL 调用 并有条件地调用 那就太酷了gl
  • OpenGL 的每个组件 alpha 通道?

    是否可以使用 OpenGL 对每个组件使用一个 alpha 通道 一个用于红色 一个用于绿色 一个用于蓝色 进行混合 如果没有 有哪些可能的解决方法 这不是直接支持的东西 不过 您自己实现起来相当容易 使用 3 通道 alpha 纹理渲染三
  • CPU 到 GPU 法线映射

    我正在创建一个地形网格 然后这个答案 https stackoverflow com a 5284527 1356106我正在尝试将 CPU 计算法线迁移到基于着色器的版本 以便通过降低网格分辨率并使用在片段着色器中计算的法线贴图来提高性能
  • gluPerspective 与 gluOrtho2D

    我查看了 MSDN 上关于这两个函数的文档 但是 我不太明白这两个功能之间的区别 一个是用于设置 3D 相机视图 另一个是用于设置 2D 相机视图 如果能得到解答就太好了 预先感谢您的评论 正交投影基本上是没有透视的 3D 投影 本质上 这
  • 为什么我的 FPS 相机一劳永逸地滚动?

    如果我忽略四元数代数的肮脏细节 我想我理解了旋转和平移变换背后的数学 但仍然不明白我做错了什么 为什么我的相机一劳永逸地滚动 更具体地说 我应该如何从相机的方向 旋转矩阵 计算相机视图矩阵 我正在用 Python 编写一个简约的 3d 引擎
  • glEnableVertexAttribArray 中“index”参数的含义以及(可能)OS X OpenGL 实现中的错误

    1 我是否正确理解 要使用顶点数组或VBO进行绘制 我需要所有属性在着色器程序链接之前调用glBindAttribLocation 或者在着色器程序成功链接后调用glGetAttribLocation 然后使用glVertexAttribP
  • lwjgl 3 , glUniformMatrix4 导致 jre 崩溃

    我正在使用 lwjgl 3 并学习现代 opengl 3 我想将统一矩阵发送到顶点着色器 以便我可以应用转换 我尝试过 但程序因此错误而崩溃 A fatal error has been detected by the Java Runti
  • lnk1104:无法打开“LIBC.lib”链接

    使用 GLee 将着色器写入我的 OpenGL 项目并编译后 我收到了错误LNK1104 cannot open file LIBC lib 我尝试按照其他人的建议添加它并忽略它 但没有解决问题 有没有其他方法可以解决我错过的这个问题 以下
  • 使用 GLSL 着色器在同一片段着色器中定义的多个子例程类型无法正常工作

    我正在开发一个使用 GLSL 着色器的程序 我编写了 2 种不同的方法来用 2 种不同的方法计算 ADS 环境光 漫反射 镜面反射 着色 为了正确完成这项工作 我使用子例程来使用一种或另一种方法来计算 ADS 着色 这是片段着色器代码的一部
  • 对齐坐标系

    Let s say I have 2 coordinate systems as it is shown in image attached 如何对齐这个坐标系 我知道我需要将第二个坐标系围绕 X 平移 180 度 然后将其平移到第一个坐标
  • 使用draw()而不是eventloop时的pyglet

    我正在尝试用 pyglet 画一个圆 但当我使用 draw 函数而不是 app run 循环时 它是不可见的 有什么建议我可以做什么吗 谢谢 from math import from pyglet gl import window pyg
  • 为什么拥有单独的投影矩阵但结合模型和视图矩阵会有好处?

    当您学习 3D 编程时 您会被告知用 3 个变换矩阵来思考是最简单的 模型矩阵 该矩阵对于每个模型都是独立的 它根据需要旋转和缩放对象 最后将其移动到 3D 世界中的最终位置 模型矩阵将模型坐标转换为世界坐标 视图矩阵 对于大量对象 如果不
  • 使用 JOGL 和 Android OpenGL 编写可移植 Java 应用程序

    我计划编写一款可以在 PC 和 Android 上运行的 Java 3D 游戏 不幸的是 这两个平台似乎没有通用的 OpenGL API API 是否有显着差异 有没有办法在两个版本中使用相同的 3D 代码 这是不是一个好主意 Androi
  • gldrawarrays 不绘制任何东西

    我正在尝试用 VBO 绘制一个三角形 我在窗口上没有看到任何像素 我也没有看到任何 GL ERROR 这是我尝试运行的代码 include
  • 更改 GLUT 调用以与 MFC/C++ 一起使用

    我有一个使用 GLUT 进行 OpenGL 渲染的程序 现在我需要它位于 MFC 项目内部 以便它可以与另一个程序组件一起使用 我已经按照这个教程进行操作 http www codeguru com cpp g m opengl openf
  • 致命错误 gl.h 包含在 glew.h 之前

    include

随机推荐

  • WSL 使用的文件没有权限无法删除

    转载于 https www cnblogs com jffun blog p 11255096 html
  • Vite 和 Webpack 的区别

    Vite 和 Webpack 都是前端打包工具 它们的作用类似 但实现方式和使用方法有所不同 以下是它们之间的一些区别 构建速度 Vite 的构建速度比 Webpack 更快 因为 Vite 在开发环境下使用了浏览器原生的 ES 模块加载
  • 浏览器油猴插件Tampermonkey下载安装

    没有插件的浏览器 不是真正的浏览器 当我们的浏览器装上插件之后 瞬间强大了许多 下面给大家介绍一下浏览器插件神器油猴插件Tampermonkey的下载安装 油猴Tampermonkey插件下载安装方法一 直接打开油猴Tampermonkey
  • 为什么要用box-sizing: border-box?一般什么时候用?

    1 新建一个HTML文档 并定义一个块元素 CSS示例 normal width 100px height 100px background blue 步骤阅读 2 保存文件 预览效果 步骤阅读 3 再次加入一个DIV并在原有的CSS上复制
  • 二十三、SQL 数据分析实战(10个简单的SQL题目)

    文章目录 题目1 比赛名单整理 题目2 热门游戏排行 题目3 社区生鲜App覆盖分析 题目4 社区团购行为分析 题目5 统计字符出现次数 题目6 找出各类别商品销量最高的商品 题目7 找出每个部门薪资第二高的员工 题目8 游戏玩家登录情况分
  • Java面向对象编程

    在单处理器系统中 如果同时存在有12个进程 则处于就绪队列中的进程数量最多为 A 1 B 9 C 10 D 11 答案 D 以下关于多线程的叙述中错误的是 A 线程同步的方法包括使用临界区 互斥量 信号量等 B 两个线程同时对简单类型全局变
  • 约瑟夫环问题(报数问题)

    先说一下什么是约瑟夫环问题 这是百科的解释 约瑟夫环 约瑟夫问题 是一个数学的应用问题 已知n个人 以编号1 2 3 n分别表示 围坐在一张圆桌周围 从编号为k的人开始报数 数到m的那个人出列 他的下一个人又从1开始报数 数到m的那个人又出
  • 如何在csdn免费下载资料?

    1 可以在个人设置里 绑定手机账号奖励整整50分 点下头像一个人中心一账号设置一手机绑定 2 完成任务 任务要在http task csdn net 里才能看到 3 上传有效 有效啊 别上个广告啊 非法啥的 反而还扣了 资源 4 评论资源
  • QT 5.8

    QT与Qt Creator 前者是框架 类似与MFC 而后者是QT的编译器 也可以使用Visual studio编辑 编译需要其他的 Index of new archive qt 5 8 5 8 0
  • MySQL的体系架构

    文章目录 前言 MySQL的Server层 MySQL的存储引擎 1 InnoDB 存储引擎 2 MyISAM 存储引擎 3 Memory 存储引擎 前言 在学习一种事务之前 我们需要先了解事物的基本组成结构 清楚了事物的基本组成结构之后
  • Linux或者ubuntu子系统中OpenMPI的安装

    在Linux中安装MPI Message Passing Interface 需要以下步骤 检查依赖项 首先 确保系统已经安装了必要的编译工具和库文件 运行以下命令更新软件包并安装所需依赖项 sudo apt update sudo apt
  • 【C语言】实现字符串逆序输出(包含空格的字符串)

    1 目的 实现字符串的逆序输出 比如I believe you 变为you believe I的形式 2 基本思路 这里我们先创建一个可以实现逆序打印的函数 将字符串逆序变为 uoy eveileb I 然后再将每个字符串逆序 从而变为yo
  • java 基础重学(一)-面向对象

    一 什么是面向过程 面向过程 是一种以事件为中心的编程思想 编程的时候把解决问题的步骤分析出来 然后用函数把这些步骤实现 在一步一步的具体步骤中再按顺序调用函数 自顶向下 逐步求精 模块化封装函数主张按功能把软件系统逐步细分 对每个涉及到的
  • 华为OD机试真题 Java 实现【整数对最小和】【2022Q4 100分】,附详细解题思路

    一 题目描述 给定两个整数数组array1 array2 数组元素按升序排列 假设从array1 array2中分别取出一个元素可构成一对元素 现在需要取出k对元素 并对取出的所有元素求和 计算和的最小值 注意 两对元素如果对应于array
  • 在win10, win11 家庭版中安装远程桌面服务

    win10 win11 家庭版中提供远程桌面服务 简介 在windows家庭版中 是不提供远程桌面服务的 你没有办法使用远程桌面连接到windows家庭版中 当然 你可用升级windows 版本到专业版 这样就可用享受到windows自带的
  • MySQL从5.6版本到5.7版本的升级过程

    MySQL从5 6版本到5 7版本的升级过程 二进制升级过程 1 介绍 此处因原有的版本就是5 6的 就不再赘述5 6的安装过程了 原有数据库5 6的目录情况 basedir usr local mysql base目录是做的软链 指向my
  • Matplotlib输出中文显示问题

    Matplotlib输出中文显示问题 试过觉得有用的办法 http www 360doc com content 14 0713 12 16740871 394080556 shtml
  • ggplot2读书笔记6:第四章 语法 基础理论

    碎碎念ing 终于结束了 ggplot2 的第一部分 Getting Started 今天开始看第二部分 语法 第四章 Mastering the Grammar 介绍了ggplot2的一些基础语法知识 大概是对前期内容在理论上做一个总结
  • x390拆机 升级内存和硬盘_战66拆机加内存折腾手记

    前言 今年6 18时入HP 战66二代AMD版时就在计划双十一时升级内存到16G 并顺带加个机械硬盘 结果用了4个多月后感觉目前硬盘空间尚无压力 所以只计划加内存 晒单 之前有朋友用过芝奇 说还不错 既有逼格也有保障 没有等到11 11当天
  • openGL增强表面细节----高度贴图

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一 代码 主程序c 效果 前言 现在我们扩展法线贴图的概念 从纹理图像用于扰动法向量到扰乱顶点位置本身 实 际上 以这种方式修改对象的几何体具有一定的优势 例如使表面特征沿