OpenGL学习之颜色

一、颜色的表示

颜色纺锤体(颜色锥体)

颜色的视觉模型:颜色三特性的空间表示

明度(亮度):垂直轴线表示黑白亮度变化                                      

色调:水平圆周上的不同角度点,代表了不同色调的颜色

饱和度:从圆心向圆周过渡表示,同一色调下饱和度的提高。某个平面圆形上的色调饱和度不同,而明度(亮度)相同。

 CIE(Commission Internationale de L'Eclairage)色度图

CIE 1932色度图是用标称值表示的CIE色度图

其中,x表示红色分量,y表示绿色分量,E点代表白光,它的坐标是(0.33,0.33),边界上的数字表示光谱色的波长。

所欲单色光都位于舌形曲线上,这条曲线就是单色轨迹,曲线旁边标注的数字时单色(或称光谱色)光的波长值;而自然界中的各种实际颜色都位于这条闭合曲线内。

二、颜色模型

 面向设备:RGB颜色模型、CMY颜色模型

面向用户:HSV颜色模型、HSL颜色模型

RGB颜色模型:

  • 采用三维直角坐标系R-Red G-Green B-Blue
  • 构成一个RGB颜色立方体
  • 通常使用于彩色光栅图形显示设备中
  • 真实感图形学中的主要颜色模型

 

 CMY颜色模型

  • 以红、绿、蓝的补色青(Cyan)、品红(Magenta)、黄(Yellow)为原色构成的颜色模型
  • 常用于从白光中滤去某种颜色,又被成为减性原色系统,在白光中减去某种颜色来定义一种颜色
  • 用于印刷行业中

 

 HSV(HSB)颜色模型

 HSV(HSB)颜色模型:一个基于颜色六边形的六棱锥

  • H(Hue):色调,用角度度量,取值范围为0°~360° ,从红色开始按逆时针方向计算
  • S(Saturation):饱和度,表示颜色接近光谱色的程度.一种颜色,可以看成是某种光谱色不白色混合的结果.通常取值范围为0%~100%,值越大,颜色越饱和.光谱色的白光成分为0,饱和度达到最高.
  • V(Value或Brightness):明度,表示颜色明亮的程度.

 HSL(HSI)颜色模型

  • H(Hue):色调,使用不水平轴之间的角度来表示,范围从0 o到360o ,从蓝色开始
  • S(Saturation):饱和度,说明颜色的相对浓度
  • L(Lightness)或者I(Intensity):亮度,在L=0处为黑色,在L=1处为白色,灰度沿着L轴分布

采用近似的圆柱坐标系S=1,L=0.5 纯色彩S=0 仅有灰度

 三、OpenGL颜色模型

两种颜色存储方式:

颜色值:像素点附加颜色信息之后,就必须为每一个像素点额外分配一个内存空间保存该点的颜色信息,对于RGB或者RGBA颜色模式,保存的数据直接代表其颜色值。

颜色索引:对于颜色索引模式,保存的是该颜色在颜色索引表中的位置,通过查颜色索引表对应到相应的颜色。颜色索引模式的优点是占用空间小,运行速度快,缺点是显示效果稍差。

随着硬件的提速升级,目前一般采用直接存储颜色值的方式。

RGB颜色模式

RGB模式中,RGB分别表示红绿蓝三色的分量,每个分量在0.0~1.0之间,通过设置RGB不同比例,可以获得任意颜色。

 当我们想要获取一个橙色时,可以定义这样一个颜色向量

glm::vec3 coral(1.0f,0.5f,0.2f);

RGBA颜色模式:

RGB分别表示红绿蓝三色的分量,A(实际上是α系数,Alpha Coeefficient)表示颜色的透明度。

通过设置RGBA不同的值,可以获得任意的颜色。

 在县市生活中,我们看到的物体的颜色其实是它所反射的颜色(不被物体吸收的颜色)。比如:当我们用白光照在一个蓝色的玩具上,这个蓝色的玩具会吸收白光中除了蓝色以外的所有子颜色,不被吸收的蓝色光被反射到我们眼中,让这个玩具看起来是蓝色的。

当我们把白色光源颜色与珊瑚色物体颜色值相乘,所得到的就是这个物体所反射的颜色。

 LightIntensity*ObjectColor = Reflectcolor

(R,G,B)*(X,Y,Z)=(XR,YG,ZB);

glm::vec3 lightColor(1.0f,1.0f,1.0f);
glm::vec3 toyColor(1.0f,0.5f,0.31f);
glm::vec3 result = lightColor * toyColor; //=(1.0f,0.5f,0.31f);

 四、创建一个光照场景

我们使用之前创建的立方体箱子作为被投光对象,并用另一个立方体来代表光源。

顶点着色器

使用顶点着色器来绘制箱子。与之前的顶点着色器相比,容器的顶点位置是保持不变的,因此顶点着色器中没有新的代码。

#version 330 core
layout (location = 0)in vec3 apos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
gl_Position = projection * view * model *vec4(apos,1.0);
}

创建灯立方体

由于后期的学习中会对顶点数据和属性指针频繁修改,所以我们为灯创建一个新的VAO。

unsigned int lightVAO;
glGenVertexArray(1,&lightVAO);
glBindVertexArray(lightVAO);
//只需要绑定VBO不用再次设置VBO的数据,因为箱子的VBO数据中已经包含了正确的立方体顶点数据
glBindBuffer(GL_ARRAY_BUFFER,VBO);
//设置灯立方体的顶点属性(对我们来说仅仅只有位置数据)
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);
glEnableVertexAttribArray(0);

片段着色器

这个片段着色器从uniform变量中接受物体的颜色和光源的颜色。

#version 330 core
out vec4 FragColor;

uniform vec3 objectColor;
uniform vec3 lightColor;

void main()
{
FragColor = vec4(lightColor * objectColor,1.0);
}
lightingShader.use();
lightingShader.setVec3("objectColor",1.0f,0.5f,0.31f);
lightingShader.setVec3("lightColor",1.0f,1.0f,1.0f);

当修改顶点或者片段着色器后,灯的位置和颜色也会随之改变,我们并不希望这样。所以我们要为灯的绘制创建另外一套着色器,从而能够保证它能在其它光照着色器发生改变的时候不受影响。

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0);//将向量的四个分量全部设置为1.0
}

当我们想要绘制我们的物体时,我们需要使用刚刚定义的着色器来绘制箱子。当我们想要绘制灯的时候,我们会使用灯的着色器。

为了显示真正的灯,我们将表示光源的立方体与光源绘制在相同的位置。

声明一个全局vec3变量来表示光源在场景的世界空间坐标中的位置。

glm::vec3 lightPos(1.2f,1.0f,2.0f);

把灯移动到这个位置,并将其缩小。

model = glm::mat4();
model = glm::translate(model,lightPos);
model = glm::scale(model,glm::vec3(0.2f);

绘制灯立方体

lamShader.use();
//设置模型、视图、和投影矩阵uniform


//绘制灯立方体对象
glBindVertexArrar(lightVAO);
glDrawArrays(GL_TRIANGLES,0,36);

在这里分享一个我新学到的技巧:

在一大段代码的开头加#pragma region *** ,结尾加#pragma endregion,然后在开头的#pragma region ***前面按一下tab,就可以把它们都收起来。

 这里有对之前的代码进行整理

fragmentSource.txt

#version 330 core

in vec2 TexCoord;
in vec4 vertexColor;

// texture samplers
uniform sampler2D ourTexture;
uniform sampler2D ourFace;
uniform vec3 objColor;
uniform vec3 ambientColor;

out vec4 FragColor;

void main()
{
	// linearly interpolate between both textures (80% container, 20% awesomeface)
	//FragColor = mix(texture(ourTexture, TexCoord), texture(ourFace, TexCoord), 0.2);
	FragColor = vec4(objColor * ambientColor,1.0)*texture(ourTexture, TexCoord)* texture(ourFace, TexCoord);
}

vertexSource.txt

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;

uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;

out vec2 TexCoord;
out vec4 vertexColor;
void main()
{
	gl_Position = projMat *  viewMat * modelMat * vec4(aPos, 1.0);
	vertexColor = vec4(aColor.x,aColor.y,aColor.z,1);
	TexCoord = aTexCoord;
}

 main.cpp

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

#include <iostream>
#include"Shader.h"
#include"Camera.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT =600;

	#pragma region Camera Declare
Camera camera(glm::vec3(0, 0, 3.0f), glm::radians(-15.0f), glm::radians(180.0f), glm::vec3(0, 1.0f, 0));
#pragma endregion

	#pragma region Input Declare
float lastX;
float lastY;
bool firstMouse = true;

void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
	{
		glfwSetWindowShouldClose(window, true);
	}
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
	{
		camera.speedZ = 1.0f;
	}
	else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
	{
		camera.speedZ = -1.0f;
	}
	else
	{
		camera.speedZ = 0;
	}
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	// make sure the viewport matches the new window dimensions; note that width and 
	// height will be significantly larger than specified on retina displays.
	glViewport(0, 0, width, height);
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
	if (firstMouse == true)
	{
		lastX = xpos;
		lastY = ypos;
		firstMouse = false;

	}
	float deltaX, deltaY;
	deltaX = xpos - lastX;
	deltaY = ypos - lastY;

	lastX = xpos;
	lastY = ypos;
	camera.ProcessMouseMovement(deltaX, deltaY);

}

#pragma endregion

unsigned int LoadImageToGPU(const char*filename, GLint internalformat, GLenum format, int textureSlot)
{
	unsigned int texBuffer;
	glGenTextures(1, &texBuffer);
	glActiveTexture(GL_TEXTURE0 + textureSlot);
	glBindTexture(GL_TEXTURE_2D, texBuffer);

	int width, height, nrChannels;
	stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
	unsigned char *data = stbi_load(filename, &width, &height, &nrChannels, 0);
	if (data)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, GL_UNSIGNED_BYTE, data);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load texture" << std::endl;
	}
	stbi_image_free(data);
	return texBuffer;
}
int main()
{
	#pragma region Open a window
	// glfw: initialize and configure
	// ------------------------------
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

														
	GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	// glad: load all OpenGL function pointers
	// ---------------------------------------
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	// configure global opengl state
	// -----------------------------
	glEnable(GL_DEPTH_TEST);
#pragma endregion
	
	
	#pragma region Model Data
		float vertices[] = {
		-0.5f, -0.5f, -0.5f, 
		0.5f, -0.5f, -0.5f,  
		0.5f,  0.5f, -0.5f,  
		0.5f,  0.5f, -0.5f,  
		-0.5f,  0.5f, -0.5f, 
		-0.5f, -0.5f, -0.5f, 

		-0.5f, -0.5f,  0.5f, 
		0.5f, -0.5f,  0.5f,  
		0.5f,  0.5f,  0.5f,  
		0.5f,  0.5f,  0.5f,  
		-0.5f,  0.5f,  0.5f, 
		-0.5f, -0.5f,  0.5f, 

		-0.5f,  0.5f,  0.5f, 
		-0.5f,  0.5f, -0.5f, 
		-0.5f, -0.5f, -0.5f, 
		-0.5f, -0.5f, -0.5f, 
		-0.5f, -0.5f,  0.5f, 
		-0.5f,  0.5f,  0.5f, 

		0.5f,  0.5f,  0.5f,  
		0.5f,  0.5f, -0.5f,  
		0.5f, -0.5f, -0.5f,  
		0.5f, -0.5f, -0.5f,  
		0.5f, -0.5f,  0.5f,  
		0.5f,  0.5f,  0.5f,  

		-0.5f, -0.5f, -0.5f,
		0.5f, -0.5f, -0.5f, 
		0.5f, -0.5f,  0.5f, 
		0.5f, -0.5f,  0.5f, 
		-0.5f, -0.5f,  0.5f,
		-0.5f, -0.5f, -0.5f,

		-0.5f,  0.5f, -0.5f,
		0.5f,  0.5f, -0.5f, 
		0.5f,  0.5f,  0.5f, 
		0.5f,  0.5f,  0.5f, 
		-0.5f,  0.5f,  0.5f,
		-0.5f,  0.5f, -0.5f,
	};

	glm::vec3 cubePositions[] = {
		glm::vec3(0.0f,  0.0f,  0.0f),
		glm::vec3(2.0f,  5.0f, -15.0f),
		glm::vec3(-1.5f, -2.2f, -2.5f),
		glm::vec3(-3.8f, -2.0f, -12.3f),
		glm::vec3(2.4f, -0.4f, -3.5f),
		glm::vec3(-1.7f,  3.0f, -7.5f),
		glm::vec3(1.3f, -2.0f, -2.5f),
		glm::vec3(1.5f,  2.0f, -2.5f),
		glm::vec3(1.5f,  0.2f, -1.5f),
		glm::vec3(-1.3f,  1.0f, -1.5f)
	};
#pragma endregion
	
	#pragma region Init Shader Pragram
	Shader ourShader("VertexSource.txt", "fragmentSource.txt");
#pragma endregion

	#pragma region Init and Load Models to VAO,VBO 
	unsigned int  VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	unsigned int VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


	// position attribute
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	// texture coord attribute
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
#pragma endregion

	#pragma region Init and Load Texture
	unsigned int texBufferA;
	texBufferA = LoadImageToGPU("container.jpg",GL_RGB,GL_RGB,0);
	unsigned int texBufferB;
	texBufferB = LoadImageToGPU("awesomeface.png",GL_RGBA, GL_RGBA, 1);
#pragma endregion
	// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)
	// -------------------------------------------------------------------------------------------
	#pragma region Prepare MVP matrices
	glm::mat4 modelMat;
	glm::mat4 viewMat;
	glm::mat4 projMat;
	projMat = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
#pragma endregion
	// render loop
	// -----------
	while (!glfwWindowShouldClose(window))
	{
		// input
		processInput(window);

		// clear srceen 
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the depth buffer now!


		viewMat = camera.GetViewMatrix();
		
		for (unsigned int i = 0; i < 10; i++)
		{
			//set Model Matrix
			modelMat = glm::translate(glm::mat4(1.0f), cubePositions[i]);
			//set View and Project Matrices here

			//set Material->shader program
			ourShader.use();
			//set Material->textures																								
			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, texBufferA);
			glActiveTexture(GL_TEXTURE1);
			glBindTexture(GL_TEXTURE_2D, texBufferB);
			//set material->uniforms
			glUniform1i(glGetUniformLocation(ourShader.ID, "ourTexture"), 0);
			glUniform1i(glGetUniformLocation(ourShader.ID, "ourFace"), 1);
			unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "modelMat");
			unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "viewMat");
			unsigned int projectLoc = glGetUniformLocation(ourShader.ID, "projMat");
			glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMat));
			glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMat));
			glUniformMatrix4fv(projectLoc, 1, GL_FALSE, glm::value_ptr(projMat));
			glUniform3f(glGetUniformLocation(ourShader.ID, "objColor"), 1.0f, 0.5f, 0.31f);
			glUniform3f(glGetUniformLocation(ourShader.ID, "ambientColor"), 1.0f, 1.0f, 1.0f);

			// set Model
			glBindVertexArray(VAO);

			//Drawcall
			glDrawArrays(GL_TRIANGLES, 0, 36);
		}

		//Clean up,prepare for next render loop
		glfwSwapBuffers(window);
		glfwPollEvents();
		camera.UpdataCameraPos();
	}

	// optional: de-allocate all resources once they've outlived their purpose:
	// ------------------------------------------------------------------------
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	// glfw: terminate, clearing all previously allocated GLFW resources.
	// ------------------------------------------------------------------
	glfwTerminate();
	return 0;
}

 其他的camera类和Shader没有发生改变。

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Estelle_Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值