OPENGL 3D图形开发小记,地形,光照,阴影等

缘起,遥想11年之时DX9之时初学3D图形开发时只是入了个门,最终不了了之,遂有了这次重新拾起准备深究一下。

初学之时,当时也仅是依葫芦画瓢式的开发,仅做到了:相机在场景中的漫游,而且遇到某些复杂问题自己也还没能力解决,当时选择DX也是因为DX开发入门相对简单。

如今回头一看,opengl 都已经4.7版本了,而且网上资料也不少。做出来的效果不比DX差,所以就有了这次近一个星期的重新回炉。

基本结构记录

点,线,三角形,构成模型的最小图元,顶点颜色,纹理坐标等..

模型坐标,世界坐标,观测者视口,透视投影,这些涉及到矩阵运算需要一些数学知识

纹理,着色器(顶点,片段)等...

因为有过相关DX9 的接触,所以直接跳过了。

实际上了解上面相关的基础概念之后,相关基础开发就并不难了,因为3D基础开发就基于以上的概念,网上也有很多相关资料。

初级应用开发已经足够了,

当然高级一点的应用材质、光照、后期特效之类的其实都是需要靠帧缓冲及着色器来完成。

开发工具 vs2015,opengl glew glfw。

一、地形:

在有了基本概念之后,笔者直接以尝试通过高度图来绘制地形模型作为动手实践的第一步,

以上图片来源于网络,过程中看到了网上他人的实现方法,对方采用的是混合纹理贴图,通过顶点和片段着色器,实现逼真的效果,不过对方的实现方式地形高度是通过最终到着色器之后进行的,所以需要在顶点着色器中做一些运算。

所以和笔者只是入门型尝试开发有点不一样,毕竟是想通过高度图中的灰度像素值来实现自动建模,所以笔者采用了生成网格模型+2D贴图的方式最终效果如下:

初步完成之后虽然不是很逼真,但剩下的就是混合纹理和着色器的事情了。

核心代码如下,主要对坐标进行了一定比列的缩放:

	int imgW, imgH, imgChannel;

	if (hmFname == nullptr) {
		return -1;
	}

	unsigned char* data = loadImg(hmFname, &imgW, &imgH, &imgChannel, 1, true);//1灰度图	

	int index1 = 0, index = 0;
	float xrate = imgW / 2.0f;
	float rrate = imgH / 2.0f;
	if (data) {
		for (int r = 0; r < imgH; r++)
		{
			for (int c = 0; c < imgW; c++)
			{
				//生成顶点数组, 坐标按照三角网格处理 GL_TRIGANLES
				index1 = r*imgW + c;
				vertexs.push_back((c - xrate) / xrate);
				vertexs.push_back(data[index1] / 255.0f);
				vertexs.push_back((r - rrate) / rrate);
				//顶点颜色
				vertexs.push_back(1.0f);
				vertexs.push_back(0.0f);
				vertexs.push_back(0.0f);
				//纹理坐标
				vertexs.push_back((c - xrate) / imgW);
				vertexs.push_back((r - rrate) / imgH);
			}
		}
		imgH -= 1;
		int iW = imgW - 1;
		for (int r = 0; r < imgH; r++)
		{
			for (int c = 0; c < iW; c++)
			{

				index1 = r*imgW + c;
				index = (r + 1)*imgW + c;
				indicess.push_back(index1);
				indicess.push_back(index1 + 1);
				indicess.push_back(index + 1);

				indicess.push_back(index1);
				indicess.push_back(index);
				indicess.push_back(index + 1);

			}
		}
	}
	loadImgFree(data);

	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);

	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, vertexs.size() * sizeof(float), &vertexs[0], GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicess.size() * sizeof(unsigned int), &indicess[0], GL_STATIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	// color attribute
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	// texture coord attribute
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);

	//textureID = loadTexture2(texName, GL_REPEAT, GL_REPEAT, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
	textureID = loadTexture(texName);

	return 0;

 顶点着色器如下:

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

out vec3 ourColor;
out vec2 TexCoord;

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

void main()
{
	gl_Position = projection * view * model * vec4(aPos, 1.0);
	ourColor = aColor;
	TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

片段着色器:

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

// texture sampler
uniform sampler2D texture1;

void main()
{
	FragColor = texture(texture1, TexCoord);
}

 

二、3D模型加载:

犹记得当初DX9加载的模型好像是.x文件格式,但是现在市面各种3D软件各种格式,所以准备直接读取obj文件,不过,obj 只是网格文件,需要额外的mtl纹理材质文件等,所以直接选择了.fbx文件的模型,然后从openmesh换到了现在amssip,主要还是为了加载炫酷的3D模型格式,这个网上资料也很多,参考网络资源。

这个涉及纹理网格的贴图等,实际上有了上面的自己完成的地势图开发之后,对这些的理解也就不难了。

当然更主要的模型的纹理,材质,反射折射效果等也需要通过着色器来完成。

同时天空盒等需要一些特殊处理才能实现,主要是需要移除观察者视口,防止天空盒随着一起移动。

三、后期特效:

阴影、后期特效等都需要缓冲帧来完成,来一张反色的阴间特效,当然还可以通过卷积核来实现一些其他的特效,比如边缘,轮廓,或者高斯模糊等一些图片处理的效果

阴影实现原理:实际上就是将光源代替成观察者视口,这样观察者视口所见的内容就是光源光照的内容,而看不到的部分则是阴影部分,然后通过着色器来完成处理即可。

阴影只是测试通过,暂时还没集成到自己的场景中。

 

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值