openGL增强表面细节----法线贴图

2023-11-05

openGL系列文章目录

前言

凹凸贴图的一种替代方法是使用查找表来替换法向量。这样我们就可以在不依赖数学函
数的情况下,对凸起进行构造,例如月球上的陨石坑所对应的凸起。一种使用查找表的常
见方法叫作法线贴图。
为了理解法线贴图的工作原理,我们首先注意,向量通过3 字节存储,X、Y 和Z 分量
各占1 字节,就可以达到合理的精度。这样,我们就可以将法向量存储在彩色图像文件中,
其中R、G 和B 分量分别对应于X、Y 和Z。图像中的RGB 值以字节存储,通常被解释为[0…1]
范围内的值,但是向量可以有正负值分量。如果我们将法向量分量限制在[−1…+1]范围内,
那么在图像文件中将法向量N 存储为像素的简单转换是:
在这里插入图片描述

法线贴图使用一个图像文件(称为法线贴图),该图像文件包含在光照下所期望表面外
观的法向量。在法线贴图中,向量相对于任意平面XY 表示,其X 和Y 分量表示与“垂直”
的偏差,其Z 分量设置为1,严格垂直于XY 平面的向量(即没有偏差)将表示为(0, 0, 1),
而不垂直的向量将具有非零的X 和/或Y 分量。我们需要使用上面的公式将值转换至RGB 空
间;例如,(0, 0, 1)将存储为(0.5, 0.5, 1),因为实际偏移的范围为[−1…+1],而RGB 值的
范围为[0…1]。
我们可以通过纹理单元的另一种妙用来生成这样一幅法线贴图:我们在纹理单元中存储所需的法向量而非颜色。然后,在给定片段中,我们就可以使用采样器从法线贴图中查找值,接下来,我们将所得的值作为法向量,而非输出像素颜色(在纹理贴图中我们是这么做的)。图10.3 展示了一个法线贴图图像文件的例子,通过将GIMP 法线贴图插件[GI16]应用于Luna [LU16]纹理而生成。法线贴图图像文件并不
适合作为图像查看,我们展示这幅图就是为了指明这一点,法线贴图最终看起来基本都是蓝色的。这是因为图像文件中每个像素的B 值(蓝色值)都是1(最大蓝色值),这会让它在作
为图像时看起来是“蓝色的”。
图1 展示了两个不同的法线贴图图像文件(它们都由Luna [LU16]的纹理构建)以及在
Blinn-Phong 光照模型下将它们应用于球体的结果。从法线贴图查找到的法向量不能直接使用,因为它们是相对于上述的任意XY 平面定义
的,并没有考虑它们在物体上的位置以及在相机空间中的方向。这个问题的解决策略是建
立一个转换矩阵,用于将法向量转换为相机空间,如下所示。
在对象的每个顶点处,我们考虑与对象相切的平面。顶点处的物体的法向量垂直于该切
面。我们在该切面中定义两个相互垂直的向量,同时也垂直于法向量,称为切向量和副切
向量(有时称为副法向量)。构造我们期望的变换矩阵要求我们的模型包括每个顶点的切向
量(可以通过计算切向量和法向量的叉积来构建副切向量)。如果模型中没有定义切向量,
则需要通过计算得到它们。在球体的情况下,可以通过计算得到精确的切向量。以下是对
程序的修改:
在这里插入图片描述
图1
在这里插入图片描述
图2

一、具体实现思路

对于那些表面不可导以至于无法精确求解切向量的模型,其切向量可以通过近似得到,
例如在构造(或加载)模型时,将每个顶点指向下一个顶点的向量作为切向量。请注意,
这种近似可能会导致切向量与顶点法向量不严格垂直。因此,如果要实现适用于各种模型
的法线贴图,需要考虑这种可能性(我们的解决方案中对此进行了处理)。
切向量与顶点、纹理坐标以及法向量一样,是从缓冲区(VBO)传递到顶点着色器中的
顶点属性。然后,顶点着色器通过应用MV 矩阵的逆转置并将结果沿着流水线转发以由光
栅器进行插值并最终进入片段着色器,从而对正常向量进行处理。逆转置的应用将法向量
和切向量转换为相机空间,之后我们使用叉积构造副切向量。
一旦我们在相机空间中得到法向量、切向量和副切向量,就可以使用它们来构造矩阵(依
其分量命名为“TBN”矩阵),该矩阵用于将从法线贴图中检索到的法向量转换为在相机空
间中相对于物体表面的法向量。
在片段着色器中,新法向量的计算在calcNewNormal()函数中完成。函数的第三行[包
含dot(tangent,normal)]的计算确保切向量垂直于法向量。新的切向量和法向量的叉积就
是副切向量。
然后,我们创建一个类型为mat3 的3×3 矩阵,作为TBN。mat3 构造函数接收3 个向量
作为参数,生成一个矩阵,其中顶行是第一个向量,中间行是第二个向量,底行是第三个
向量(类似于从摄像机位置构建视图矩阵,见图3.13)。
着色器使用片段的纹理坐标来提取与当前片段对应的法线贴图单元。着色器在提取时使
用采样器变量“normMap”,并被绑定到纹理单元0(注意:因此在C++ / OpenGL 应用程序
中必须将法线贴图图像附加到纹理单元0)。因为需要将颜色分量从纹理中存储范围[0…1]
转换为其原始范围[−1 … + 1],我们将其乘以2.0 再减去1.0。然后将TBN 矩阵应用于所得法向量以产
生当前像素的最终法向量。着色器的其余部分与用于Phong 光照的片段着色器相同。片段着色器代码基于Etay Meiri [ME11]的版本,如程序10.2 所示。制作法线贴图图像可以使用各种各样的工具。有的图像编辑工具就有制作法线贴图的功能,例如GIMP [GI16]和Photoshop [PH16]。它们通过分析图像中的边缘,推断凸起和凹陷,并产生相应的法线贴图。图3 显示了由Hastings-Trew [HT16]基于
NASA 卫星数据创建的月面纹理图。其相应的法线贴图由GIMP 法线贴图插件[GP16],通过处理由Hastings-Trew 创建的黑白版本月面纹理图生成。
在这里插入图片描述
图3

二、代码

主程序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 "Sphere.h"
#include "Utils.h"
using namespace std;

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

#define numVAOs 1
#define numVBOs 4

float cameraX, cameraY, cameraZ;
float sphLocX, sphLocY, sphLocZ;
float lightLocX, lightLocY, lightLocZ;
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];

// variable allocation for display
GLuint mvLoc, projLoc, nLoc;
int width, height;
float aspect;
glm::mat4 pMat, vMat, mMat, mvMat, invTrMat;
GLuint globalAmbLoc, ambLoc, diffLoc, specLoc, posLoc, mambLoc, mdiffLoc, mspecLoc, mshiLoc;
glm::vec3 currentLightPos;
float lightPos[3];
float rotAmt = 0.0f;

Sphere mySphere(48);
int numSphereVertices;

GLuint roofTexture;

// white light
float globalAmbient[4] = { 0.7f, 0.7f, 0.7f, 1.0f };
float lightAmbient[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
float lightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
float lightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };

// silver material
float* matAmb = Utils::silverAmbient();
float* matDif = Utils::silverDiffuse();
float* matSpe = Utils::silverSpecular();
float matShi = Utils::silverShininess();

void setupVertices(void) {
	numSphereVertices = mySphere.getNumIndices();

	std::vector<int> ind = mySphere.getIndices();
	std::vector<glm::vec3> vert = mySphere.getVertices();
	std::vector<glm::vec2> tex = mySphere.getTexCoords();
	std::vector<glm::vec3> norm = mySphere.getNormals();
	std::vector<glm::vec3> tang = mySphere.getTangents();

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

	for (int i = 0; i < mySphere.getNumIndices(); i++) {
		pvalues.push_back((vert[ind[i]]).x);
		pvalues.push_back((vert[ind[i]]).y);
		pvalues.push_back((vert[ind[i]]).z);
		tvalues.push_back((tex[ind[i]]).s);
		tvalues.push_back((tex[ind[i]]).t);
		nvalues.push_back((norm[ind[i]]).x);
		nvalues.push_back((norm[ind[i]]).y);
		nvalues.push_back((norm[ind[i]]).z);
		tanvalues.push_back((tang[ind[i]]).x);
		tanvalues.push_back((tang[ind[i]]).y);
		tanvalues.push_back((tang[ind[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);

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

void installLights(glm::mat4 vMatrix) {
	glm::vec3 transformed = glm::vec3(vMatrix * glm::vec4(currentLightPos, 1.0));
	lightPos[0] = transformed.x;
	lightPos[1] = transformed.y;
	lightPos[2] = transformed.z;

	// get the locations of the light and material fields in the shader
	globalAmbLoc = glGetUniformLocation(renderingProgram, "globalAmbient");
	ambLoc = glGetUniformLocation(renderingProgram, "light.ambient");
	diffLoc = glGetUniformLocation(renderingProgram, "light.diffuse");
	specLoc = glGetUniformLocation(renderingProgram, "light.specular");
	posLoc = glGetUniformLocation(renderingProgram, "light.position");
	mambLoc = glGetUniformLocation(renderingProgram, "material.ambient");
	mdiffLoc = glGetUniformLocation(renderingProgram, "material.diffuse");
	mspecLoc = glGetUniformLocation(renderingProgram, "material.specular");
	mshiLoc = glGetUniformLocation(renderingProgram, "material.shininess");

	//  set the uniform light and material values in the shader
	glProgramUniform4fv(renderingProgram, globalAmbLoc, 1, globalAmbient);
	glProgramUniform4fv(renderingProgram, ambLoc, 1, lightAmbient);
	glProgramUniform4fv(renderingProgram, diffLoc, 1, lightDiffuse);
	glProgramUniform4fv(renderingProgram, specLoc, 1, lightSpecular);
	glProgramUniform3fv(renderingProgram, posLoc, 1, lightPos);
	glProgramUniform4fv(renderingProgram, mambLoc, 1, matAmb);
	glProgramUniform4fv(renderingProgram, mdiffLoc, 1, matDif);
	glProgramUniform4fv(renderingProgram, mspecLoc, 1, matSpe);
	glProgramUniform1f(renderingProgram, mshiLoc, matShi);
}

void init(GLFWwindow* window) {
	renderingProgram = Utils::createShaderProgram("vertShader.glsl", "fragShader.glsl");
	cameraX = 0.0f; cameraY = 0.0f; cameraZ = 2.0f;
	sphLocX = 0.0f; sphLocY = 0.0f; sphLocZ = -1.0f;
	lightLocX = -5.0f; lightLocY = 2.0f; lightLocZ = 5.0f;

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

	setupVertices();

	roofTexture = Utils::loadTexture("castleroofNORMAL.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");
	nLoc = glGetUniformLocation(renderingProgram, "norm_matrix");

	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
	mMat = glm::translate(glm::mat4(1.0f), glm::vec3(sphLocX, sphLocY, sphLocZ));
	mMat = glm::rotate(mMat, toRadians(20.0f), glm::vec3(1.0f, 0.0f, 0.0f));
	mMat = glm::rotate(mMat, rotAmt, glm::vec3(0.0f, 1.0f, 0.0f));
	rotAmt += 0.002f;
	mvMat = vMat * mMat;
	invTrMat = glm::transpose(glm::inverse(mvMat));

	currentLightPos = glm::vec3(lightLocX, lightLocY, lightLocZ);
	installLights(vMat);

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

	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);

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

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

	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CCW);

	glDrawArrays(GL_TRIANGLES, 0, numSphereVertices);
}

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 - program2", 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);
}

着色器程序

1.顶点着色器

#version 430

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

out vec3 varyingLightDir;
out vec3 varyingVertPos;
out vec3 varyingNormal;
out vec3 varyingTangent;
out vec3 originalVertex;
out vec2 tc;
out vec3 varyingHalfVector;

layout (binding=0) uniform sampler2D s;

struct PositionalLight
{	vec4 ambient;
	vec4 diffuse;
	vec4 specular;
	vec3 position;
};
struct Material
{	vec4 ambient;
	vec4 diffuse;
	vec4 specular;
	float shininess;
};

uniform vec4 globalAmbient;
uniform PositionalLight light;
uniform Material material;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 norm_matrix;

void main(void)
{	varyingVertPos = (mv_matrix * vec4(vertPos,1.0)).xyz;
	varyingLightDir = light.position - varyingVertPos;
	tc = texCoord;
	
	originalVertex = vertPos;

	varyingNormal = (norm_matrix * vec4(vertNormal,1.0)).xyz;
	varyingTangent = (norm_matrix * vec4(vertTangent,1.0)).xyz;
	
	varyingHalfVector =
		normalize(normalize(varyingLightDir)
		+ normalize(-varyingVertPos)).xyz;

	gl_Position = proj_matrix * mv_matrix * vec4(vertPos,1.0);
}

2.片元着色器

#version 430

in vec3 varyingLightDir;
in vec3 varyingVertPos;
in vec3 varyingNormal;
in vec3 varyingTangent;
in vec3 originalVertex;
in vec2 tc;
in vec3 varyingHalfVector;

out vec4 fragColor;

layout (binding=0) uniform sampler2D normMap;

struct PositionalLight
{	vec4 ambient;  
	vec4 diffuse;  
	vec4 specular;  
	vec3 position;
};

struct Material
{	vec4 ambient;  
	vec4 diffuse;  
	vec4 specular;  
	float shininess;
};

uniform vec4 globalAmbient;
uniform PositionalLight light;
uniform Material material;
uniform mat4 mv_matrix;	 
uniform mat4 proj_matrix;
uniform mat4 norm_matrix;

vec3 calcNewNormal()
{
	vec3 normal = normalize(varyingNormal);
	vec3 tangent = normalize(varyingTangent);
	tangent = normalize(tangent - dot(tangent, normal) * normal);
	vec3 bitangent = cross(tangent, normal);
	mat3 tbn = mat3(tangent, bitangent, normal);
	vec3 retrievedNormal = texture(normMap,tc).xyz;
	retrievedNormal = retrievedNormal * 2.0 - 1.0;
	vec3 newNormal = tbn * retrievedNormal;
	newNormal = normalize(newNormal);
	return newNormal;
}

void main(void)
{	// normalize the light, normal, and view vectors:
	vec3 L = normalize(varyingLightDir);
	vec3 V = normalize(-varyingVertPos);

	vec3 N = calcNewNormal();

	// get the angle between the light and surface normal:
	float cosTheta = dot(L,N);
	
	// compute light reflection vector, with respect N:
	//vec3 R = normalize(reflect(-L, N));
	
	vec3 H = normalize(varyingHalfVector);
	
	// angle between the view vector and reflected light:
	float cosPhi = dot(H,N);

	// compute ADS contributions (per pixel):
	fragColor = globalAmbient * material.ambient
	+ light.ambient * material.ambient
	+ light.diffuse * material.diffuse * max(cosTheta,0.0)
	+ light.specular  * material.specular
		* pow(max(cosPhi,0.0), material.shininess*3.0);
}

效果

在这里插入图片描述

源码下载

源码下载地址

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

openGL增强表面细节----法线贴图 的相关文章

  • 为什么拥有单独的投影矩阵但结合模型和视图矩阵会有好处?

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

    我无法得到SOIL http www lonesock net soil html正确使用 Visual Studio 2010 我远非 VS 专家 但据我所知 只需执行以下步骤即可使环境正常运行 属性 gt gt C C gt 常规 gt
  • gldrawarrays 不绘制任何东西

    我正在尝试用 VBO 绘制一个三角形 我在窗口上没有看到任何像素 我也没有看到任何 GL ERROR 这是我尝试运行的代码 include
  • OpenGL:如何检查用户是否支持glGenBuffers()?

    我检查了文档 它说 OpenGL 版本必须至少为 1 5 才能制作glGenBuffers 工作 用户使用的是1 5版本但是函数调用会导致崩溃 这是文档中的错误 还是用户的驱动程序问题 我正在用这个glGenBuffers 对于VBO 我如
  • 编译 GLUI 库,VS2010 给我一个奇怪的命名空间错误

    我有一个针对我所在班级的 OpenGL 项目 它基于 GLUI 提供的 GLUI 库无法工作 这就是我尝试自己编译它的原因 因此 我从 SourceForge 下载了源代码并尝试编译 glui 库 它给了我这个 但我找不到任何相关信息 1
  • wglCreateContextAttribsARB 函数崩溃

    我尝试写下代码 我有InitializeOGL 的代码 bool Ogl InitializeOGL bool vSync cout lt lt Init OpenGL lt
  • 纹理映射 C++ OpenGL

    我已经阅读了相关内容 包括 Nehe 和此处的解决方案 但我找不到具体的答案 我正在尝试加载一张名为stars jpg 的照片 我想通过使用 uv 坐标映射它来使其成为场景的背景 方法是 glBegin GL QUADS glTexCoor
  • 如何使用现代 OpenGL 在透视投影中绘制对象的正交轴? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有带有透视投影的 3D 场景 我还可以选择场景中的一个对象 我需要为选定的对象绘制轴 问题是轴不会在透视投影中保存其大小 如果物体远离眼睛
  • 云或烟雾的粒子系统

    我正在尝试使用 OpenGL 和 CUDA 制作一个简单的用于云和烟雾模拟的粒子系统 如何使粒子系统中的粒子表现得像真正的云或烟雾在低湍流风中的表现 我现在遇到的一些问题是 颗粒聚集成一个大球 粒子扩散到无限远 粒子突然弹射离开 我已经完成
  • 在 QML 中控制纹理 3D 对象的不透明度

    我对 QML 中的 Qt 3D 有点陌生 我正在尝试控制 Qt 3D 的不透明度textured3D 对象 我正在使用简单qml3d https github com tripolskypetr simpleqml3d测试项目来做到这一点
  • glColor4f() - alpha 值的效果

    我正在使用 glColor4f 令人惊讶的是 更改 alpha 即第四个参数 不会导致透明度发生任何变化 代码段是 const GLfloat squareVertices 0 5 0 5 0 0 0 5 0 5 0 0 0 5 0 5 0
  • MATLAB 图形渲染:OpenGL 与 Painters?

    当谈到使用哪个渲染器来处理 MATLAB 图形或何时它很重要时 我一无所知 但我遇到过某些示例 其中does matter plot 0 0 ko markersize 50 linewidth 8 set gcf renderer ope
  • GLSL 中统一浮点行为和常量浮点行为的不同

    我正在尝试在 GLSL 中实现模拟双精度 并且观察到一种奇怪的行为差异 导致 GLSL 中出现细微的浮点错误 考虑以下片段着色器 写入 4 浮点纹理以打印输出 layout location 0 out vec4 Output unifor
  • Windows下使用GLEW使用OpenGL扩展

    我一直在 Windows 上使用 OpenGL 扩展痛苦的方式 https stackoverflow com questions 14413 using opengl extensions on windows GLEW 是更简单的方法吗
  • Opengl 视频纹理

    我正在使用 Visual Studio 10 在 Windows 上用 C 开发 opengl 应用程序 目前我在立方体上使用静态纹理 但我想集成视频纹理 你知道我可以使用哪个库来打开和解密视频吗 查看 ffmpeg libavformat
  • OpenGL:始终相同的颜色

    我正在 Windows 上编写一个程序 使用c opengl 2 1 and SDL我在顶点颜色方面遇到了一些问题 我在用着glColor3f设置每个顶点集的颜色 但它似乎不起作用 无论我选择什么颜色 我都会将每个顶点绘制为红色 我检查了传
  • 为什么我的 CAOpenGLLayer 更新速度比之前的 NSOpenGLView 慢?

    我有一个在 Mac OS X 上渲染 OpenGL 内容的应用程序 最初它渲染到 NSOpenGLView 然后我将其更改为渲染到 CAOpenGLLayer 子类 当我这样做时 我看到了巨大的性能损失 帧速率减半 鼠标响应能力降低 卡顿
  • 渲染缓冲区大于窗口大小 - OpenGL

    我正在尝试绘制大于屏幕尺寸 即 320x480 的渲染缓冲区 512x512 执行 glReadPixels 后 图像看起来是正确的 除非图像的尺寸超过了屏幕尺寸 在本例中 超过了水平 320 和垂直 480 是什么原因导致这种异常现象呢
  • 实例着色器矩阵的设置

    我想绘制实例立方体 我可以打电话GL DrawArraysInstanced PrimitiveType Triangles 0 36 2 成功地 我的问题是所有立方体都绘制在相同的位置和相同的旋转 我如何为每个立方体单独更改它 要创建不同
  • 渲染到一个颜色通道而不影响其他通道

    使用 OpenGL 任何版本 如何通过一次仅影响一个颜色通道来渲染到帧缓冲区对象 例如 我的帧缓冲区对象具有 GL BGRA 布局 现在我想执行一些渲染命令 这些命令应该只改变红色通道 因此 如果片段用颜色 204 0 0 0 渲染并且像素

随机推荐

  • Vim的NerdTree插件

    在vundle插件管理的方式 直接在 vimrc中的Plugin段落中加入 Plugin scrooloose nerdtree 然后重启Vim并输入PluginInstall 即可完成安装 然后输入 NERDTreeToggle即可打开文
  • vue-property-decorator的简单介绍,一看就会

    参考 https github com kaorun343 vue property decorator 怎么使vue支持ts写法呢 我们需要用到vue property decorator 这个组件完全依赖于vue class compo
  • Layui学习笔记,隔壁都馋哭了

    添加一个Tab 切换用户管理 删除商品管理 删除所有tab 简单风格的Tab 网站设置 用户管理 权限分配 商品管理 订单管理 高度默认自适应 也可以随意固宽 2 Tab进行了响应式处理 所以无需担心数量多少 内容2 内容3 内容4 内容5
  • 【Unity Shader】unity海边波浪效果的实现

    效果图如下 GIF因为为了把图压小所以删掉了一些帧导致后面速度突然很快 实际效果并不是这样 PS 对于移动端 参考该文章 http www lsngo net 2018 03 22 unity seawave vertexcolor 之前在
  • react(56)——在项目中使用开发者工具redux-devtools-extension

    1 谷歌安装插件 需要访问外网 在谷歌商店中下载 也可以自己格外找资源 2 项目中添加redux devtools extension库 在终端运行cnpm add redux devtools extension即可 3 在store j
  • 使用cookie和session实现登录(简单原理解析)

    cookie 浏览器在客户端电脑硬盘中开辟的一块空间 主要用来存储服务端数据 比如sessionId cookie中的数据是以域名的形式进行区分的 cookie中的数据是有过期时间的超过时间会被浏览器自动删除 cookie中的数据可以随着请
  • 2023网络安全面试题(附答案)+面经

    前言 随着国家政策的扶持 网络安全行业也越来越为大众所熟知 相应的想要进入到网络安全行业的人也越来越多 为了拿到心仪的Offer之外 除了学好网络安全知识以外 还要应对好企业的面试 所以在这里我归纳总结了一些网络安全方面的常见面试题 希望能
  • 读磁盘概述

    磁盘结构 磁道C 磁头H 扇区S 一个磁盘有很多个盘面 上面是其中一个盘面 每个盘面对应一个磁头 磁盘的最小单元是扇区 通过CHS可以定位到一个确定的扇区 每个扇区一般是512个字节 CHS寻道方式 设置好寄存器的值 然后一个int 13就
  • [笔记]MySQL 删除重复数据

    通过内连接 INNER JOIN 方式删除重复数据 场景复现 CREATE TABLE user id bigint 11 AUTO INCREMENT name varchar 64 PRIMARY KEY id engine InnoD
  • Google guava之SortedMultiset简介说明

    转自 Google guava之SortedMultiset简介说明 下文笔者讲述guava中SortedMultiset集合的简介说明 如下所示 guava之SortedMultiset集合简介 SortedMultiset集合 可用于按
  • Android Context完全解析与各种获取Context方法

    Context类型 我们知道 Android应用都是使用Java语言来编写的 那么大家可以思考一下 一个Android程序和一个Java程序 他们最大的区别在哪里 划分界限又是什么呢 其实简单点分析 Android程序不像Java程序一样
  • Gnuradio+uhd驱动软件安装流程

    工作时一部分内容 需要用到gnuradio软件配置 属于软件无线电USRP的内容 不属于计算机视觉 只作为记录 一样的花费了较长时间 大概两周 终于安装成功 虽然有点脱离了自己的兴趣爱好 但也算近期的一个成果 将它分享出来 网上资料很杂乱
  • 二十四.刷题.14

    一个数如果恰好等于它的因子之和 这个数就称为 完数 例如6 1 2 3 编程找出1000以内的所有完数 include
  • 解决报错: PostCSS received undefined instead of CSS string

    解决方案1 可能本地有多个nodeJS版本 本地使用了nvm 之前切到另一个版本编译node sass后 再切换到另外一个nodeJS版本 导致的问题 注意 node sass是一个绑定libsass sass的一种版本 的nodeJS库
  • golang 协程的实现原理

    核心概念 要理解协程的实现 首先需要了解go中的三个非常重要的概念 它们分别是G M和P 没有看过golang源代码的可能会对它们感到陌生 这三项是协程最主要的组成部分 它们在golang的源代码中无处不在 G goroutine G是go
  • 一文概括常用图像处理算法

    本文总结了11种常用的图像处理算法 包含了预处理算法以及检测算法 并介绍了一些常用的开发库 一 算法 预处理算法 检测算法 在采集完图像后 首先会对图像进行预处理操作 保证图像的对比度清晰 水平 方便后续图像处理 常用的图像处理算法 1 图
  • 数学建模专栏 - 聚类分析入门:基本概念和MATLAB实现

    摘要 本文将介绍聚类分析的基本概念和MATLAB的实现方法 我们将先介绍聚类分析的概念和应用场景 然后介绍聚类算法的基本原理 最后用一个实际案例来演示如何使用MATLAB进行聚类分析 1 简介 聚类分析是一种无监督学习方法 用于将数据集分成
  • 关于servlet上传图片,显示不出来报 Get http://localhost:9095/assets/img/head/1656901332651.jpg 404错误

    目录 第一种解决方法 第二种解决方法 第三种方法 配置虚拟路径 不建议尝试 上传图片的工具类 我的tomcat是放在E liulanqi apache tomcat 9 0 62 webapps 第一种解决方法 将上传的图片路径改为上到到t
  • Java知识点汇总--多态

    Java多态 1 多态 1 1 多态的概述 1 2 多态中的成员访问特点 1 3 多态的好处和弊端 1 4 多态中的转型 1 5 多态的案例 1 多态 1 1 多态的概述 什么是多态 同一个对象 在不同时刻表现出来的不同形态 多态的前提 要
  • openGL增强表面细节----法线贴图

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一 具体实现思路 二 代码 主程序c 着色器程序 效果 源码下载 前言 凹凸贴图的一种替代方法是使用查找表来替换法向量 这样我们就可以在不依赖数学函 数的情况下 对凸起进行