Kho tháng 11/2024
Tue Nov 26 06:57:08 PM CET 2024
I almost Vulkan now
Losing steam on OpenGL so I thought I'd give Vulkan a try for fresh air. Since I should get the basics down now, it shouldn't be as nightmarish as before.
Boy. Vulkan is verbose. This is not an unpopular opinion. In fact it may be one of the most poplar description of Vulkan. But boy is it verbose. Giving up around swapchain creation and just used vk-bootstrap instead, so I would never know if GPU initialization would take 500 lines or not. Just initialization. vk-bootstrap was a good decision.
Then, even the main loop to just do the equivalent of glClear()
is
also very verbose. Although most of it seems to be connected to
swapchain, so not a very big deal. And explicit synchronization is
where Vulkan pays off, supposedly.
That's not even touching shaders. Resource management is also explicit, so it's going to be a wild ride. gl3.cc with all the fancy stuff (and a big vertices array) takes 525 lines. Draw-nothing vulkan.cc is already 497 lines. I miss OpenGL now...
Sat Nov 23 11:42:47 AM CET 2024
I OpenGL now
Technically I OpenGL'd twenty years ago. I remember sitting in the library reading about OpenGL (and probably Linux around the same time). Can't quite remember if it was long before the graphics class or not, when I made glBomb.
I wanted to get back in graphics programming for a long time, see what all this "shader" bussiness is all about, did some reading from time to time but never got to do anything for real.
glBomb source code was recovered a few years back, and I've been reviving it for fun, modernizing a bit. That code was 20 years old with OpenGL 1(?), SDL 1, C++98, no STL... It was ugly. But at least it's back somewhat working (well, it was working but harder to work with). Now is the time to look at moving away from the old OpenGL code.
So finally, modern OpenGL. Well, for a rectangle, nothing fancy yet, just to get a feeling.
#include <fstream>
#include <iostream>
#include <vector>
#include <SDL2/SDL.h>
#include <SDL2/SDL_video.h>
#define GL_GLEXT_PROTOTYPES
#include <SDL2/SDL_opengl.h>
GLuint loadShader(GLenum shaderType, const std::string& path)
{
GLuint shader = glCreateShader(shaderType);
{
std::ifstream f(path, std::ios::binary);
std::vector<char> data((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
glShaderBinary(1, &shader,
GL_SHADER_BINARY_FORMAT_SPIR_V,
reinterpret_cast<void*>(data.data()),
data.size());
}
glSpecializeShader(shader, "main", 0, nullptr, nullptr);
int success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success)
{
return shader;
}
char infoLog[512];
glGetShaderInfoLog(shader, sizeof(infoLog), nullptr, infoLog);
glDeleteShader(shader);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
return 0;
}
int main()
{
SDL_Init(SDL_INIT_VIDEO);
auto window = SDL_CreateWindow("glBomb",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600,
SDL_WINDOW_OPENGL);
SDL_GL_CreateContext(window);
// Shader
GLuint shaderProgram = glCreateProgram();
GLuint vertexShader = loadShader(GL_VERTEX_SHADER, "gl3-vert.spv");
glAttachShader(shaderProgram, vertexShader);
GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, "gl3-frag.spv");
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
int success;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
char infoLog[512];
glGetProgramInfoLog(shaderProgram, sizeof(infoLog), nullptr, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
return 1;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// VAO, VBO, EBO...
GLuint VBO;
glCreateBuffers(1, &VBO);
std::vector<float> vertices
{
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
glNamedBufferData(VBO, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);
GLuint EBO;
glCreateBuffers(1, &EBO);
std::vector<GLuint> indices
{
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
glNamedBufferData(EBO, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);
GLuint VAO;
glCreateVertexArrays(1, &VAO);
int vaoBindingPoint = 0;
glVertexArrayVertexBuffer(VAO, vaoBindingPoint, VBO, 0, 3 * sizeof(float));
int attribPos = 0;
glVertexArrayAttribFormat(VAO, attribPos, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(VAO, attribPos, vaoBindingPoint);
glEnableVertexArrayAttrib(VAO, attribPos);
glVertexArrayElementBuffer(VAO, EBO);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
while (true)
{
auto new_ticks = SDL_GetTicks64();
SDL_Event ev;
while (SDL_PollEvent(&ev))
{
if (ev.type == SDL_KEYUP && ev.key.keysym.sym == SDLK_ESCAPE)
{
return 0;
}
}
glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
SDL_GL_SwapWindow(window);
auto end_ticks = SDL_GetTicks64();
if (end_ticks - new_ticks < 100)
{
SDL_Delay(100 - (end_ticks - new_ticks));
}
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
return 0;
}
And the two dead simple shaders, vertex one
#version 460 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
and fragment one
#version 460 core
layout (location = 0) out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 1.0f, 1.0f);
}
These have to be compiled to SPIR-V first with
glslangValidator -G vert.glsl -o gl3-vert.spv
glslangValidator -G frag.glsl -o gl3-frag.spv
And that's it. Now, back to re-learning matrix calculations. Full source code following https://learnopengl.com is https://gitlab.com/pclouds/learnopengl
Cập nhật 1 lần. Lần cuối: Sun Nov 24 17:58:36+0001 2024