
early grass experiments - using compute shaders and indirect draw
some more early experiments with grass, trying a GPU based approach in order to improve grass rendering performance in order to be able to cover bigger areas with grass.

some more early experiments with grass, trying a GPU based approach in order to improve grass rendering performance in order to be able to cover bigger areas with grass.
I’m looking for someone who:
enjoys low-level graphics/game engine programming
has experience with OpenGL, C, or Rust
wants to work on a serious long-term project
is interested in learning and experimenting together
This is mainly a passion project for learning and building something impressive. If you’re interested, DM me.
Hi, I am jejoxdev, a solo indie game developer.
This is a battle demonstration for my ongoing work on HARD VOID Early Access on Steam.
HARD VOID is a 4X game with lovecraftian thematic, and heavy use of procedural algorithms:
procedural multiple-universes (multiverse), procedural spaceship hulls, and now procedural oceans on the planets.
It's fully developed on Linux, with OpenGL and C language (C99). It's also available on Windows.
If interested:
https://store.steampowered.com/app/2978460/HARD_VOID/
Updated grass system to use instanced glb file with billboard grass clumps instead of procedurally generated grass blades(couldnt get this to look right)
Hello, World!
I have started learning graphics programming for a few days with the help of learnopengl.com and I feel like I learned quite a lot in these few days. Setting up an OpenGL 3.3 project with C++ in Visual Studio, Drawing a blank window with GLFW and then drawing an RGB triangle in it with OpenGL and GLSL. Learned about shaders, buffers and different OpenGL objects and their use.
I am really getting a lot interested in this field of computer science. but, I am also a bit nervous about it. As there is a lot mathematics involved in this which is my biggest weakpoint.
I would like to hear about how y'all got into graphics programming and what challenges did y'all face while learning it.
I have the following vertex shader to draw things in window coordinates:
#version 330 core
layout(location = 0) in vec2 pos;
uniform ivec2 window_size;
void main() {
float x = float(pos.x) / window_size.x * 2.0 - 1.0;
float y = float(pos.y) / window_size.y * -2.0 + 1.0;
gl_Position = vec4(x, y, 0.0, 1.0);
}
It works fine. However, when I change the type of pos from vec2 to ivec2, it misbehaves. The vertex coordinates are defined as GLint anyway, so I'm a bit confused that I need to use them as floating point in the shader. It isn't a problem (the shader needs to convert them to float anyway), but I would still like an explanation why it doesn't work. It seems like I've misunderstood something.
Do people write functions to convert models they made in blender (or other 3d modeling programs) into vertices that can be rendered by OpenGL or do they handwrite all of the vertices?
just wanted to say some words about this subreddit: thank you for looking at my stuff!
i managed to reach the person that inspired me the most, and on top of that, ive been getting a lot of support and views. thank you so much. i hope one day this procedural generation engine will be good enough for people to use. it will be open source and free for everybody. im really pouring my soul into this project and thank you for being here for me.
Edit: It just started working and I have ABSOLUTELY NO IDEA why.
I'm following the tutorial at learnopengl.com and I'm trying to get texture coordinates working, but for some reason the texture coordinates are all zero in the fragment shader and I can't figure out why. Everything else works, it's just the UVs.
Vertex array:
float vertices[] = {
// positions // colors // UVs
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
Attribute pointer setup:
// position attribute
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 coordinate attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
Vertex shader:
#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;
void main()
{
gl_Position = vec4(aPos, 1.0f);
ourColor = aColor;
TexCoord = aTexCoord;
}
Fragment shader:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D texture0;
void main()
{
FragColor = vec4(TexCoord, 0.0f, 1.0f);
}
main.cpp:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <cmath>
#include "shader.hpp"
#include "stb_image.h"
float vertices[] = {
// positions // colors // UVs
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3,
1, 2, 3
};
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(800, 600, "GLTest", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position attribute
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 coordinate attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
Shader shader("./shader.vs", "./shader.fs"); // Shader type defined in shader.hpp
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height, nrChannels;
unsigned char *data = stbi_load("./texture.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
stbi_image_free(data);
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
shader.hpp:
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
Shader(const char *vertexPath, const char *fragmentPath)
{
// 1. Read shader source from filepaths
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ifstream exception flags
vShaderFile.exceptions(std::iostream::failbit | std::iostream::badbit);
fShaderFile.exceptions(std::iostream::failbit | std::iostream::badbit);
try
{
// Open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
// Read files
std::stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// Close files
vShaderFile.close();
fShaderFile.close();
// Convert stringstream to string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure e)
{
std::cout << "Failed to read shader files:\n\t" << e.what() << std::endl;
}
// 2. Compile shaders
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
unsigned int vertex, fragment;
int success;
char infoLog[512];
// Vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, sizeof(infoLog), NULL, infoLog);
std::cout << "Failed to compile vertex shader:\n\t" << infoLog << std::endl;
}
// Fragment shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, sizeof(infoLog), NULL, infoLog);
std::cout << "Failed to compile fragment shader:\n\t" << infoLog << std::endl;
}
// Shader program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, sizeof(infoLog), NULL, infoLog);
std::cout << "Failed to link shader program:\n\t" << infoLog << std::endl;
}
// Delete unlinked shaders
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void use()
{
glUseProgram(ID);
}
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
};
#endif
Hi guys, I'm putting on the final touches for the release of Leadwerks 5.1. Here's the recording for this week's live developer chat.
This Week's Progress
I integrated tessellation back into our new virtual texturing terrain system. Our stochastic vegetation system has been updated to work with the 5.1 renderer, with support for the new terrain-mesh blending feature. This blends objects into the ground but can also act as a color-grading tool that lets you easily create outdoor scenes with a professional cohesive look. The use of alpha-to-coverage with our multisample antialiasing (MSAA) makes grass and trees look clean and sharp.
Links
Alright so this sounds like something I would google, but I couldn't find much for my specific conundrum. I want to draw a cone that starts from a point, and the faces of the cone are drawn based on an angle from 0 to 360 degrees which defines it's spread, and the direction of the spotlight. I specifically need this to draw the way spotlights will light up an area based on the spotlight entity's settings. Does anyone know of any examples I could look at to help me out with the math? Thank you.
Hi, I recently got interested in learning graphics programming with OpenGL and I've heard a lot about learnopengl.com. So, I gave it a try.
I just completed the "Hello Triangle" section of the page and honestly I learned quite well about vertex buffer objects, vertex shaders and vertex attribute objects. Though, honestly I had to ask ChatGPT about some concepts that didn't "click" to me immediately like the use of glVertexAttribPointer and why VAO is important. but, I finally got it.
The thing that I observed and which bothers me a bit is that the author explains a concept and drops the code snippets that correspond to that concept but, They don't tell you where the code should go in your existing codebase. In one moment it goes on to explain the use of VBO then drop some code snippets then in another moment how the vertex attribute pointers work then drop some other snippets and then finally explain the use of VAO for storing all those configurations and which buffer data it use and drop some snippets thereafter. but, It doesn't seem to explain how it all should be laid out in order. I had a hard time understanding it.
Okay, It could be just me. but, Anyways it's really a helpful resource. I might get used to it after a while.
I am just here to say Hi to the community. I hope I do well in my journey to learn graphics programming. Let me know what you think about this.
I've looked around and it seems that resources for 4.6 are fewer and far between especially compared to something like 3.3, and it looks like basically no major games really used 4.6 either.
I'm curious on how viable it actually is for like games, engines, etc. or if there's some astute reason as to why no one seems to use this version, because supposedly it's better optimized for modern hardware (albeit not on the same level as something like Vulkan)
I wanted to add simple physics interactions to my project, but I cannot, for the life of me, figure out how to properly link any of the popular physics libraries to my Visual Studio/OpenGL project. I have been trying for a few hours now to get something/anything to work, and I am about to give up.
I don't need it to do much. Just basic collisions and simple shapes along a 3D plane.
With GLEW and SDL, I can just download the binaries, add the include folder, and reference the lib files. With every physics engine I have found (PhysX, Bullet, Jolt, ReactPhysics3D, Chrono), it seems as though I have to build it myself, scour the directories for the lib file I should be referencing, and then try to figure out what Visual Studio is looking for to resolve the LINK errors. I got close to getting Bullet to work, but I was runtime errors when following the example code that is provided on Github.
So I am asking: what is the simplest 3D physics library that I can plug into my project? Or there a more verbose guide for I can follow for adding physics to an OpenGL visual studio project?