OpenGL进阶03.绘制地面

Posted stq_wyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL进阶03.绘制地面相关的知识,希望对你有一定的参考价值。

这篇文章来讲一下如何绘制一个黑白相间的地面。添加了vertexbuffer和ground以及shader类,Uitls.h里添加了一个创建BufferObject的接口。

Utils.h

#pragma once
#include "ggl.h"
unsigned char* LoadFileContent(const char* path, int& filesize);

GLuint CompileShader(GLenum shaderType, const char* shaderCode);

GLuint CreateProgram(GLuint vsShader, GLuint fsShader);

float GetFrameTime();

unsigned char* DecodeBMP(unsigned char* bmpFileData, int& width, int& height);

GLuint CreateTexture2D(unsigned char* pixelData, int width, int height, GLenum type);

GLuint CreateTexture2DFromBMP(const char* bmpPath);

GLuint CreateBufferObject(GLenum bufferType, GLsizeiptr size, GLenum usage, void* data = nullptr);

看下新加接口的实现Utils.cpp:

GLuint CreateBufferObject(GLenum bufferType, GLsizeiptr size, GLenum usage, void* data/* = nullptr*/)
{
	GLuint object;
	glGenBuffers(1, &object);
	glBindBuffer(bufferType, object);
	glBufferData(bufferType, size, data, usage);
	glBindBuffer(bufferType, 0);
	return object;
}

vertexbuffer.h:包含Vertex的结构体和一些方法的定义。

#pragma once
#include "ggl.h"
struct Vertex
{
	float Position[4];
	float Color[4];
	float Texcoord[4];
	float Normal[4];
};

class VertexBuffer {
public:
	Vertex* mVertexes;
	int mVertexCount;
	void SetSize(int vertexCount);
	void SetPosition(int index, float x, float y, float z, float w = 1.0f);
	void SetColor(int index, float r, float g, float b, float a = 1.0f);
	void SetTexcoord(int index, float x, float y);
	void SetNormal(int index, float x, float y, float z);
};

vertexbuffer.cpp:

#include "vertexbuffer.h"
#include "Utils.h"

void VertexBuffer::SetSize(int vertexCount)
{
	mVertexCount = vertexCount;
	mVertexes = new Vertex[mVertexCount];
	memset(mVertexes, 0, sizeof(Vertex) * mVertexCount);
}

void VertexBuffer::SetPosition(int index, float x, float y, float z, float w /* = 1.0f */)
{
	mVertexes[index].Position[0] = x;
	mVertexes[index].Position[1] = y;
	mVertexes[index].Position[2] = z;
	mVertexes[index].Position[3] = w;
}

void VertexBuffer::SetColor(int index, float r, float g, float b, float a /* = 1.0f */)
{
	mVertexes[index].Color[0] = r;
	mVertexes[index].Color[1] = g; 
	mVertexes[index].Color[2] = b;
	mVertexes[index].Color[3] = a;
}

void VertexBuffer::SetTexcoord(int index, float x, float y)
{
	mVertexes[index].Texcoord[0] = x;
	mVertexes[index].Texcoord[1] = y;
}

void VertexBuffer::SetNormal(int index, float x, float y, float z)
{
	mVertexes[index].Normal[0] = x;
	mVertexes[index].Normal[1] = y;
	mVertexes[index].Normal[2] = z;
	mVertexes[index].Normal[3] = 1.0;
}

Shader类是对shader代码读取和编译以及赋值的一个封装,使我们代码看起来更简洁:

shader.h:

#pragma once
#include "ggl.h"
class Shader
{
public:
	GLuint mProgram;
	GLint mModelMatrixLocation, mViewMatrixLocation, mProjectionMatrixLocation;
	GLint mPositionLocation, mColorLocation, mTexcoordLocation, mNormalLocation;
	void Init(const char* vs, const char* fs);
	void Bind(float* M, float* V, float* P);
};

shader.cpp:

#include "shader.h"
#include "Utils.h"
#include "vertexbuffer.h"
void Shader::Init(const char* vs, const char* fs)
{
	int nFileSize = 0;
	const char* vsCode = (char*)LoadFileContent(vs, nFileSize);
	const char* fsCode = (char*)LoadFileContent(fs, nFileSize);

	GLuint vsShader = CompileShader(GL_VERTEX_SHADER, vsCode);

	if (vsShader == 0)
	{
		return;
	}
	GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, fsCode);
	if (fsShader == 0)
	{
		return;
	}
	mProgram = CreateProgram(vsShader, fsShader);
	glDeleteShader(vsShader);
	glDeleteShader(fsShader);

	if (mProgram != 0)
	{
		mModelMatrixLocation = glGetUniformLocation(mProgram, "ModelMatrix");
		mViewMatrixLocation = glGetUniformLocation(mProgram, "ViewMatrix");
		mProjectionMatrixLocation = glGetUniformLocation(mProgram, "ProjectionMatrix");

		mPositionLocation = glGetAttribLocation(mProgram, "position");
		mColorLocation = glGetAttribLocation(mProgram, "color");
		mTexcoordLocation = glGetAttribLocation(mProgram, "texcoord");
		mNormalLocation = glGetAttribLocation(mProgram, "normal");
	}
}

void Shader::Bind(float* M, float* V, float* P)
{
	glUseProgram(mProgram);
	glUniformMatrix4fv(mModelMatrixLocation, 1, GL_FALSE, M);
	glUniformMatrix4fv(mViewMatrixLocation, 1, GL_FALSE, V);
	glUniformMatrix4fv(mProjectionMatrixLocation, 1, GL_FALSE, P);
	glEnableVertexAttribArray(mPositionLocation);
	glVertexAttribPointer(mPositionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
	glEnableVertexAttribArray(mColorLocation);
	glVertexAttribPointer(mColorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 4));
	glEnableVertexAttribArray(mTexcoordLocation);
	glVertexAttribPointer(mTexcoordLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 8));
	glEnableVertexAttribArray(mNormalLocation);
	glVertexAttribPointer(mNormalLocation, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 12));
}

ground是设置地面数据:

ground.h:

#pragma once
#include "utils.h"
#include "vertexbuffer.h"
#include "shader.h"
class Ground {
	VertexBuffer* mVertexBuffer;
	GLuint mVBO;
	Shader* mShader;
	glm::mat4 mModelMatrix;
public:
	void Init();
	void Draw(glm::mat4& viewMatrix, glm::mat4& projectionMatrix);
};

ground.cpp:

#include "ground.h"
void Ground::Init() {
	mVertexBuffer = new VertexBuffer;
	mVertexBuffer->SetSize(1600);
	for (int z = 0; z < 20; ++z) 
	{
		float zStart = 100.0f - z * 10.0f;
		for (int x = 0; x < 20; ++x) 
		{
			int offset = (x + z * 20) * 4;
			float xStart = x * 10.0f - 100.0f;
			mVertexBuffer->SetPosition(offset, xStart, -1.0f, zStart);
			mVertexBuffer->SetPosition(offset + 1, xStart + 10.0f, -1.0f, zStart);
			mVertexBuffer->SetPosition(offset + 2, xStart, -1.0f, zStart - 10.0f);
			mVertexBuffer->SetPosition(offset + 3, xStart + 10.0f, -1.0f, zStart - 10.0f);
			mVertexBuffer->SetNormal(offset, 0.0f, 1.0f, 0.0f);
			mVertexBuffer->SetNormal(offset + 1, 0.0f, 1.0f, 0.0f);
			mVertexBuffer->SetNormal(offset + 2, 0.0f, 1.0f, 0.0f);
			mVertexBuffer->SetNormal(offset + 3, 0.0f, 1.0f, 0.0f);
			if ((z % 2) ^ (x % 2)) 
			{
				mVertexBuffer->SetColor(offset, 0.1f, 0.1f, 0.1f);
				mVertexBuffer->SetColor(offset + 1, 0.1f, 0.1f, 0.1f);
				mVertexBuffer->SetColor(offset + 2, 0.1f, 0.1f, 0.1f);
				mVertexBuffer->SetColor(offset + 3, 0.1f, 0.1f, 0.1f);
			}
			else 
			{
				mVertexBuffer->SetColor(offset, 0.8f, 0.8f, 0.8f);
				mVertexBuffer->SetColor(offset + 1, 0.8f, 0.8f, 0.8f);
				mVertexBuffer->SetColor(offset + 2, 0.8f, 0.8f, 0.8f);
				mVertexBuffer->SetColor(offset + 3, 0.8f, 0.8f, 0.8f);
			}
		}
	}
	mVBO = CreateBufferObject(GL_ARRAY_BUFFER, sizeof(Vertex) * mVertexBuffer->mVertexCount, GL_STATIC_DRAW, mVertexBuffer->mVertexes);
	mShader = new Shader;
	mShader->Init("Res/ground.vs", "Res/ground.fs");
}
void Ground::Draw(glm::mat4& viewMatrix, glm::mat4& projectionMatrix) {
	glEnable(GL_DEPTH_TEST);
	glBindBuffer(GL_ARRAY_BUFFER, mVBO);
	mShader->Bind(glm::value_ptr(mModelMatrix), glm::value_ptr(viewMatrix), glm::value_ptr(projectionMatrix));
	for (int i = 0; i < 400; i++) 
	{
		glDrawArrays(GL_TRIANGLE_STRIP, i * 4, 4);
	}
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

shader代码新增了ground.vs和ground.fs,

ground.vs:

attribute vec4 position;
attribute vec4 color;
attribute vec4 normal;

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
varying vec4 V_Color;

void main()
{
    V_Color = color;
    gl_Position = ProjectionMatrix*ViewMatrix*ModelMatrix*position;
}

ground.fs:

#ifdef GL_ES
precision mediump float;
#endif
varying vec4 V_Color;

void main()
{
    gl_FragColor = V_Color;
}

最后在scene.cpp里调用ground的初始化以及绘制函数就可以了:

scene.cpp:

#include "scene.h"
#include "ggl.h"
#include "Utils.h"
#include "ground.h"

GLuint vbo,ebo;
GLuint program;
GLint positionLocation, modelMatrixLocation, viewMatrixLocation, projectionMatrixLocation,colorLocation;
GLuint texcoordLocation, textureLocation;
GLuint texture;
glm::mat4 modelMatrix, viewMatrix, projectionMatrix;
Ground ground;

void Init()
{
	float data[] = {
		-0.2f,-0.2f,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,0.0f,
		0.2f,-0.2f,0.0f,1.0f,0.0f,1.0f,0.0f,1.0f,1.0f,0.0f,
		0.0f,0.2f,0.0f,1.0f,1.0f,0.0f,0.0f,1.0f,0.5f,1.0f
	};
	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 30, data, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	unsigned short indexes[] = { 0,1,2 };
	glGenBuffers(1, &ebo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * 3, indexes, GL_STATIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	int fileSize = 0;
	//读取shader代码
	unsigned char* shaderCode = LoadFileContent("Res/test.vs", fileSize);
	GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char*)shaderCode);
	delete shaderCode;

	shaderCode = LoadFileContent("Res/test.fs", fileSize);
	GLuint fsShader = CompileShader(GL_FRAGMENT_SHADER, (char*)shaderCode);
	delete shaderCode;
	
	program = CreateProgram(vsShader, fsShader);
	glDeleteShader(vsShader);
	glDeleteShader(fsShader);
	//获取shader中的变量
	positionLocation = glGetAttribLocation(program, "position");
	colorLocation = glGetAttribLocation(program, "color");
	texcoordLocation = glGetAttribLocation(program, "texcoord");
	modelMatrixLocation = glGetUniformLocation(program, "ModelMatrix");
	viewMatrixLocation = glGetUniformLocation(program, "ViewMatrix");
	projectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix");
	textureLocation = glGetUniformLocation(program, "U_Texture");
	modelMatrix = glm::translate(0.0f, 0.0f, -0.6f);
	//texture = CreateTexture2DFromBMP("Res/test.bmp");
	ground.Init();
}

void SetViewPortSize(float width, float height)
{
	projectionMatrix = glm::perspective(60.0f, width / height, 0.1f, 1000.0f);
}

void Draw()
{
	float frameTime = GetFrameTime();
	glClearColor(0.1f, 0.4f, 0.6f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	ground.Draw(viewMatrix, projectionMatrix);

    //为了方便展示效果,三角形绘制部分注释了
	/*glUseProgram(program);
	glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));
	glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
	glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
	
	glBindTexture(GL_TEXTURE_2D, texture);
	glUniform1i(textureLocation, 0);

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glEnableVertexAttribArray(positionLocation);
	glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 10, 0);

	glEnableVertexAttribArray(colorLocation);
	glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 10, (void*)(sizeof(float)*4));

	glEnableVertexAttribArray(texcoordLocation);

	glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 10, (void*)(sizeof(float) * 8));
	
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glUseProgram(0);*/


}

三角形绘制部分代码我先注释了,来看下地面长什么样吧:

以上是关于OpenGL进阶03.绘制地面的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL进阶03.绘制地面

OpenGL进阶01.使用Shader绘制三角形

我的OpenGL学习进阶之旅关于OpenGL ES 绘制纹理,因为加载纹理坐标设置错误,导致纹理无法渲染的问题

我的OpenGL学习进阶之旅关于OpenGL ES 绘制纹理,因为加载纹理坐标设置错误,导致纹理无法渲染的问题

我的OpenGL学习进阶之旅使用glDrawElements绘制的时候,不绘制任何图元,报错 1282 即 GL_INVALID_OPERATION

我的OpenGL学习进阶之旅使用glDrawElements绘制的时候,不绘制任何图元,报错 1282 即 GL_INVALID_OPERATION