openlg 光照贴图

本文详细介绍了OpenGL中实现3D立方体的纹理映射和光照效果。通过修改顶点数据,包括纹理坐标和法线,创建了一个带有纹理的立方体,并在顶点着色器和片段着色器中处理光照计算。同时,添加了两个纹理,一个用于漫反射,另一个用于高光反射,使得模型具有金属边框的反光效果。在顶点着色器中,将纹理坐标传递给片段着色器,然后在片段着色器中应用光照模型计算出最终颜色。
摘要由CSDN通过智能技术生成
  • 包括纹理坐标和发现坐标的顶点数据
//立方体36个顶点,有纹理坐标的
float vertices[] = {
    // positions          // normals           // texture coords
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f,
     0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  0.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f,

    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f,
     0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f,

    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f,
    -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
    -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f,
    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f,

     0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,
     0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f,
     0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
     0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f,
     0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  0.0f,
     0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f,

    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,
     0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  1.0f,
     0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,
     0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f,

    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f
};
  • 对VOA修改步长以及添加新的纹理坐标信息(0,1,2)
void VAOSet()
{

	glGenVertexArrays(1,&cubeVAO);
	glGenBuffers(1,&VBO);
	//glGenBuffers(1,&EBO);

	glBindVertexArray(cubeVAO);
	glBindBuffer(GL_ARRAY_BUFFER,VBO);
	//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);

	//往显卡写值,分配显存空间GL_STATIC_DRAW表示,值不修改
	glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
	//glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
	//告诉显卡,值的结构 position
	glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)0);
	glEnableVertexAttribArray(0);
	//告诉显卡,值的结构 法线
	glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)(3*sizeof(float)));
	glEnableVertexAttribArray(1);
	//告诉显卡,值的结构 纹理坐标
	glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)(6*sizeof(float)));
	glEnableVertexAttribArray(2);
	
	glGenVertexArrays(1, &lightVAO);
    glBindVertexArray(lightVAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)0);
	glEnableVertexAttribArray(0);
	
}
  • 修改新的texture代码,添加新的图片,注意format来判断图片类型
void texture(Shader *myShader) {
    unsigned char* data;
    int width, height, nrChannels;  //长,宽,渠道数量

    //创建两个对象
    unsigned int texture[2];
    glGenTextures(2, texture);
    
    //加载第一个纹理
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//选择纹理的处理方法(纹理过滤选择线性还是就近)一般缩小的时候就近,放大线性
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    data = stbi_load("container2.png", &width, &height, &nrChannels, 0);
    GLenum format;  //判断类型
    if (nrChannels == 1)
        format = GL_RED;
    else if (nrChannels == 3)
        format = GL_RGB;
    else if (nrChannels == 4)
        format = GL_RGBA;
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);//用于输出纹理目标;参数:生成目标,级别,存储格式(RGB),宽度,高度,图源数据类型(RGB),图源在数组中每一个值的格式格式,数据
        glGenerateMipmap(GL_TEXTURE_2D);//自动生成一系列图像(根据远近)            
    }
    else
    {
        std::cout << "Failed to load texture1" << std::endl;
    }
    stbi_image_free(data);//使用之后就可以释放缓存了

    //加载第二个纹理
    glBindTexture(GL_TEXTURE_2D, texture[1]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//选择纹理的处理方法(纹理过滤选择线性还是就近)一般缩小的时候就近,放大线性
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    data = stbi_load("container2_specular.png", &width, &height, &nrChannels, 0);
    if (nrChannels == 1)
        format = GL_RED;
    else if (nrChannels == 3)
        format = GL_RGB;
    else if (nrChannels == 4)
        format = GL_RGBA;
    if (data)
    {
        //因为图片类型为png格式是有透明度的所以参数应该是GL_RGBA
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);//用于输出纹理目标;参数:生成目标,级别,存储格式(RGB),宽度,高度,图源数据类型(RGB),图源在数组中每一个值的格式格式,数据
        glGenerateMipmap(GL_TEXTURE_2D);//自动生成一系列图像(根据远近)
    }
    else
    {
        std::cout << "Failed to load texture2" << std::endl;
    }
    stbi_image_free(data);//使用之后就可以释放缓存了

    //一个纹理的位置通常被称为纹理单元
    //一个纹理单元默认位置是0
    myShader->useShader();    //要对shader进行赋值就要使用.因为要给显卡用到的glsl语言传输数据   
    glUniform1i(glGetUniformLocation(myShader->ID, "ourTexture1"), 0); //给ourTexture1赋值0,这一行可以不需要,因为默认赋值
    glUniform1i(glGetUniformLocation(myShader->ID, "ourTexture2"), 1); //给ourTexture2赋值1
    
    glActiveTexture(GL_TEXTURE0);   //先激活纹理单元0,这一行可以不需要,因为默认激活
    glBindTexture(GL_TEXTURE_2D, texture[0]);   //再绑定
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, texture[1]);
    设置边框模式不然就填充了
    //glPolygonMode(GL_FRONT_AND_BACK, /*GL_FILL*/GL_LINE);  //可以设定有没有填充背景颜色(使用纹理加载就不用这个)
}
  • 修改顶点着色器的代码(新的值layout(location=2) in vec2 aTexCoords;传输新的坐标给片段着色器out vec2 TexCoords;)
#version 400 core
layout(location=0) in vec3 aPos;
layout(location=1) in vec3 aNormal;		//是法线而不是纹理
layout(location=2) in vec2 aTexCoords;	
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 FragPos;	//每一个顶点的世界坐标
void main()
{
	
	
	FragPos = vec3(model*vec4(aPos,1.0f));	//因为急需要model所以传送的时候需要传送三个矩阵而不是一个transform就够了
	Normal=mat3(transpose(inverse(model)))*aNormal;	//不等比例缩放的时候先进行逆矩阵再转置然后乘以法线
	TexCoords = aTexCoords;
	gl_Position=projection*view*vec4(FragPos,1.0f);	//减少计算量直接用世界坐标就行了

}
  • 修改片段着色器的代码,主要修改光照改为光照贴图部分:注意这里只由金属边框才发生反射是因为cube高光反射只包括了第二个图片,而第二个图片却又把中间涂黑了
#version 400 core
out vec4 FragColor;
in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoords;
uniform vec3 lightColor;
uniform vec3 objectColor;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;
//材料的结构体
struct Material{
	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
	float shininess; //影响聚光度的(发散或者聚焦)
};
Material material;
//光的结构体(属性)
struct Light{
	vec3 position;
	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
};
Light light;
void main()
{
	//材质光
	material.ambient = vec3(texture(ourTexture1,TexCoords));	
	material.diffuse =	vec3(texture(ourTexture1,TexCoords));	//这里使用材质漫反射贴图而不用向量
	material.specular = vec3(texture(ourTexture2,TexCoords));	//这里使用的是第二个金属高光
	material.shininess = 32;
	//环境光
	light.position = lightPos;
	light.ambient	=vec3(0.2);
	light.diffuse	=vec3(0.6);
	light.specular	=vec3(1.0);

	vec3 lightDirction = normalize(lightPos - FragPos);	//求出点到光源的方向向量	

	float diffuse = max(dot(Normal,lightDirction),0.0);	//漫反射计算

	vec3 viewDirction = normalize(viewPos - FragPos);
	vec3 reflectDirction = reflect(-lightDirction,Normal);
	float specular = pow(max(dot(reflectDirction,viewDirction),0.0),32);	//高光计算=反射光和实现的点乘的X次方
	
	FragColor = vec4((light.ambient*material.ambient
		+diffuse*light.diffuse*material.diffuse
		+specular*light.specular*material.specular)*lightColor, 1.0);	//因为引入了物体颜色(橙色)时候已经乘过了所以就不用乘以objectclor
}
  • 注意主函数中在生成shader变量之后紧跟着重现加上 texture(&cubeShader); //漫反射纹理
  • 结果就是只有金属边框反光了在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值