iron_render
这里就是放任何跟渲染相关功能的地方。2D渲染器,刚开始相对简单(我想像中了啦)。
我的设计会是,在初始化(CreateRenderer
)之後,接下来只要在Game Loop里面呼叫DrawXXXX
就可以画出相对应的想要的图案画贴图,之後会像视窗功能那样在Game Loop中有StartDraw
跟EndDraw
之类的记录这一Frame的状态,DrawXXXX
会在StartDraw
跟EndDraw
之间呼叫。
// This is a example
while(1) {
StartDraw();
DrawRectangle();
DrawTexture();
EndDraw();
}
会说简单只要还有一点,主要是大部分得图形,甚至是全部,都可以视为是矩形。最多就4个顶点与,然後会有使用贴图与颜色的不同,所以我会把预设的Shader直接写在iron_render.c
文件里面,基本的一些绘制就可以应付了,除非之後有甚麽特殊效果,需要用不同的Shader来制作,就再说吧~;)
预设的shader没甚麽变,还是长这样(如果不知道甚麽是shader的话,可以参考这篇)
// vertex
static const char* DEFAULT_2D_VERTEX_SHADER_CODE = "#version 330 core\n"
"in vec2 _Pos;\n"
"in vec2 _Texcoords;\n"
"out vec2 Texcoords;\n"
"void main() {\n"
" gl_Position = vec4(_Pos, 0.0, 1.0);\n"
" Texcoords = _Texcoords;\n"
"}\n\0";
// fragment
static const char* DEFAULT_2D_FRAGMENT_SHADER_CODE = "#version 330 core\n"
"in vec2 Texcoords;\n"
"uniform vec4 _Color;\n"
"uniform sampler2D _Texture2D;"
"out vec4 _FragColor;\n"
"void main() {\n"
" _FragColor = _Color * texture(_Texture2D, Texcoords);\n"
"}\n\0";
之前没有说,shader当中设置的变数,前面的in
、out
、uniform
是甚麽意思?
首先来讲uniform
,可以看到在Shader中标示uniform
的变数,在DrawXXXX
中用glUniform4f
设定了变数,uniform
其实就是Shader里的常数,透过外部去设置这个变数,如同之前所写的,就是把颜色设定到shader里。
in
跟out
两个关键字比较新,之前OpenGL2.0时的GLSL是用varying
,这是用在shader管线之间传递参数用的,不会提供给外部,in
跟out
是视作一对的,例如: 传递_Pos
// In vertex shader
out vec2 _Pos;
然後经过管线传到fragment shader,那就要是:
// In fragment shader
in vec2 _Pos
如上,连参数名称也要一样。
但看看vertex shader的_Pos
跟_Texcoords
,开头就是in
那这是哪来的呢?这些在vertex shader的就是attribute了,在OpenGL2.0的GLSL也是用这个关键字,这个要搭配
glGetAttribLocation(...)
glVertexAttribPointer(...)
glEnableVertexAttribArray(...)
一起使用,还有如果有点进上面参考资料的,里面的shader在attribute前面有加上layout(location = 0)
其实就是直接标示了attrubute的位置,不用使用glGetAttribLocation
注: 这边也证实我之前说错了,可编程管线,也就是Shader,其语言不是3.0才有的,2.0就有了
在CreateRenderer
的地方,加写这一段,等於是把之前设置顶点数据的地方,换句话说,创建VertexBufferObject
、VertexArrayObject
、IndexBufferObject
的地方((如果不知道这些是甚麽的话,也请参考这篇),初始化一份存起来即可
...
glGenVertexArrays(1, &RENDER_2D_CONTEXT.vao);
glBindVertexArray(RENDER_2D_CONTEXT.vao);
glGenBuffers(1, &RENDER_2D_CONTEXT.vbo);
glBindBuffer(GL_ARRAY_BUFFER, RENDER_2D_CONTEXT.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES), VERTICES, GL_STATIC_DRAW);
glGenBuffers(1, &RENDER_2D_CONTEXT.ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RENDER_2D_CONTEXT.ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(INDICES), INDICES, GL_STATIC_DRAW);
// set position attribute
glVertexAttribPointer(RENDER_2D_CONTEXT.default_shader.attribs_locations[SHADER_ATTRIB_VEC2_POS], 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(RENDER_2D_CONTEXT.default_shader.attribs_locations[SHADER_ATTRIB_VEC2_POS]);
// set texture coordinate attribute
glVertexAttribPointer(RENDER_2D_CONTEXT.default_shader.attribs_locations[SHADER_ATTRIB_VEC2_TEXCOORD], 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(RENDER_2D_CONTEXT.default_shader.attribs_locations[SHADER_ATTRIB_VEC2_TEXCOORD]);
glBindVertexArray(0);
...
然後DrawFirstTriangle
与DrawFirstTexture
的地方只要留下呼叫要使用的shader与VAO、绑上要的属性、绘制图形这三个功能就好了。
// Draw Rect
glBindVertexArray(RENDER_2D_CONTEXT.vao);
glUseProgram(RENDER_2D_CONTEXT.default_shader.id);
V4f v = ColorToVec4f(c);
glUniform4f(RENDER_2D_CONTEXT.default_shader.attribs_locations[SHADER_ATTRIB_VEC4_COLOR], v.r, v.g, v.b, v.a);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, RENDER_2D_CONTEXT.default_texture.id);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
// DrawTexture
glBindVertexArray(RENDER_2D_CONTEXT.vao);
glUseProgram(RENDER_2D_CONTEXT.default_shader.id);
// set shader color
V4f v = ColorToVec4f(c);
glUniform4f(RENDER_2D_CONTEXT.default_shader.attribs_locations[SHADER_ATTRIB_VEC4_COLOR], v.r, v.g, v.b, v.a);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.id);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
完成後,如果呼叫DrawFirstRectangle
的话会看到乌漆麻黑一片,这是因为预设的shader有这段:
_FragColor = _Color * texture(_Texture2D, Texcoords);
这表示强制需要使用一张贴图。
那就在CreateRenderer
的地方,产生一张***1x1的白色像素***当作预设的贴图,方便在之後如果Shader或贴图载入错误了,就会直接使用预设的资源...
// create default texture, a pixel 1x1 white squad
unsigned char white_pixel[4] = { 255, 255, 255, 255 };
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &RENDER_2D_CONTEXT.default_texture.id);
glBindTexture(GL_TEXTURE_2D, RENDER_2D_CONTEXT.default_texture.id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, white_pixel);
glBindTexture(GL_TEXTURE_2D, 0);
这样就完成了!
<<: [Day 05] 产出回应内文&初探AES CBC加密 - [C#]丰收款API必备前置作业(四)
>>: 【Day 4】物理时间、happens-before 关系、causality
5.亮度 常见使用夜间模式的一个原因,也不是因为健康与否,只是因为觉得白底有点太亮了 确实亮度也一直...
#328 - Odd Even Linked List 连结: https://leetcode....
DBABootcamp 资料库管理师(Database Administrator, 简称 DBA)...
基本物件设计: ...
物件导向程序设计是程序设计中极为重要的一环,其基本概念为物件及类别。 类别定义事物的特点,物件为事件...