本科毕业了,比较顺利地找到了IT行业的工作,作为一个机械专业的本科生实属不易啊!回想各种面试,还是觉得技术很重要,毕竟IT行业是一个日新月异的行业,需要你持续学习。应届生应该是进入BAT等大公司的最容易的时候了,毕竟才毕业,没有什么工作经验,对你的要求也相应的低得多。通过与公司的交流,因为是一家手机游戏公司,所以需要懂OpenGL(其实我觉得没必要深入学习,毕竟可以再cocos2d基础上进行再封装的嘛!这不是重复造轮子么?),所以就学习了一下。
当然,首先必须要看的就是“红皮书”和“蓝宝书”了,但是我们学校图书馆的蓝宝书只有第五版,不过貌似现在中文的版本也就只有第五版的吧,不过觉得还是听老的了,用的是glut框架,我用的Mac,从OS X 10.9之后glut就被加入到过时行列了,所以网上查了下,现在都用的glfw代替之,不过就目前来说,感觉这两个之间没什么差别,而且我觉得glut通过函数指针调用自定义渲染函数等的方式比glfw还更好一点,其他的不知。可能是某些技术过于落后了吧。在Mac平台,当然首选的开发工具就是Xcode了,在一番环境配置之后,终于搞定了环境的配置,这里顺便提一下,超级宝典提供的那个GLTools工具库确实方便了很多初学者,可以快速看到实际效果,大大增强信心,相反,红宝书更加注重理论,一开始就开始讲理论,什么缓存之类的,让初学者云里雾里。不过GLTool在mac平台需要自己编译成库,我是编译成的静态库,在terminal用g++编译的。
超级宝典快速浏览了一下,刚看完着色器,感觉是时候终结一下了,基本上的opengl基础知识都看完了,该上手编写代码了,但是强迫症,不想用超级宝典提供的库,想完全用glfw和opengl来实现,自己编写简单的着色器程序。所以首要的任务当然就是学习glfw,在官网看了glfw的入门教程,大概知道了glfw的使用,就那么几个函数。然后当然就是着色器编写了,我发现直接将超级宝典的着色器来用回编译不过,可能是opengl版本什么的吧,也可能是因为在mac平台,具体位置,貌似超级宝典中的in/out变量限制符不能用。希望知道的人求教一下。所以就用了glfw示例程序的着色器编写形式,然后自己简化了一下。目标就是画一个静态的三角形就好啦,屏蔽掉所有复杂的部分。直接上源码,里面注释也有几个我的疑问,希望大神解答!
#include <iostream>
#include <glfw3.h>
using namespace std;
static const char* vertex_shader_text =
"uniform vec4 vCol;\n"
"attribute vec4 vPos;\n"
"varying vec4 color;\n"
"void main()\n"
"{\n"
" gl_Position = vPos;\n"
" color = vCol;\n"
"}\n";
static const char* fragment_shader_text =
"varying vec4 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0,0,0,1.0);\n"
"}\n";
void errorCallBack(int error,const char* description)
{
cout<<"Error:"<<error<<" " <<description<<endl;
}
void windowShouldClosedCallBack(GLFWwindow * window)
{
cout<<"window is going to be closed;\n";
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
void glfwMain()
{
if (!glfwInit()) {
cout<<"glfwInit failed!\n";
}
glfwSetErrorCallback(errorCallBack);
//创建窗口
GLFWwindow * window = glfwCreateWindow(640,480, "First GLFW", nullptr, nullptr);
if (!window) {
cout<<"Create Window Failed \ n";
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glfwSetWindowCloseCallback(window, windowShouldClosedCallBack);
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glfwSwapInterval(1000/60.0);
GLfloat vects[] ={-0.5f,0.5f,0.f,1.0f,
0.5f,0.5f,0.f,1.0f,
0.f,-0.5f,0.f,1.0f};
GLuint bufferId = 0;
//分配bufferID
glGenBuffers(1, &bufferId);
//我的理解就是制定这个已经分配的ID是什么类型的buffer,然后就是分配内存
glBindBuffer(GL_ARRAY_BUFFER, bufferId);
//将数据传递到这个buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(vects), vects, GL_STATIC_DRAW);
//下面的都是着色器的编译和链接
GLuint vShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vShaderID, 1, &vertex_shader_text, NULL);
glCompileShader(vShaderID);
GLint r = 1;
glGetShaderiv(vShaderID, GL_COMPILE_STATUS, &r);
if (r==GL_FALSE) {
cout<<"Fail to compile vertex shader\n";
}
GLuint fShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fShaderID, 1, &fragment_shader_text, NULL);
glCompileShader(fShaderID);
glGetShaderiv(fShaderID, GL_COMPILE_STATUS, &r);
if (r==GL_FALSE) {
cout<<"Fail to compile fragment shader\n";
}
GLuint program = glCreateProgram();
glAttachShader(program, vShaderID);
glAttachShader(program, fShaderID);
glLinkProgram(program);
//glValidateProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &r);
if (r==GL_FALSE) {
cout<<"Fail to link program\n";
}
//因为vPos是一个attribute,所以获取attribute的index,传递数据给着色器
GLuint vPosLoc = glGetAttribLocation(program, "vPos");
//将着色器变量Index与缓存中的,其实我觉得很奇怪,他怎么知道是哪个buffer,也没有bufferID相关的参数
glVertexAttribPointer(vPosLoc, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(vPosLoc);
glClearColor(0.0, 1.0f, 1.0f, 1.0f);
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
}