I was doing a test of new way of transforming vertex positions in compute shader for some reason and I encountered a problem. What I want is just transforming the vertex (whose id is 2) 1.0f up but after the compute shader the vertex has always been transformed 1.2f right with same height.
I checked the shaders storage buffer and uniform buffer several times by Nvidia Nsight and buffer datas looked good.
ComputeShader
#version 460 core
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(std140, binding = 0) uniform Matrix
{
float u_id;
mat4 modelM;
};
struct VertexLayout
{
vec3 positions;
float v_id;
};
layout(std430, binding = 1) buffer VertexBuffer
{
VertexLayout vertex[];
};
void main()
{
if(vertex[gl_GlobalInvocationID.x].v_id == u_id)
{
vertex[gl_GlobalInvocationID.x].positions = vec3(modelM * vec4(vertex[gl_GlobalInvocationID.x].positions, 1.0));
}
}
Main.cpp
#include "main.h"
#include "Test1.h"
Renderer* renderer;
int main()
{
if (!InitGLFW())
return -1;
renderer = new Renderer();
renderer->loadMatrix();
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
renderer->Render();
glfwSwapBuffers(window);
glfwPollEvents();
}
delete renderer;
glfwTerminate();
return 0;
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (action == GLFW_PRESS)
{
switch (key)
{
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, true);
break;
case GLFW_KEY_KP_1:
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
break;
case GLFW_KEY_KP_2:
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
break;
case GLFW_KEY_KP_4:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
case GLFW_KEY_KP_5:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
case GLFW_KEY_KP_6:
renderer->Transform();
break;
}
}
}
Test1
#pragma once
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
struct Data
{
float id;
glm::mat4 modelM;
};
class Renderer
{
public:
Renderer();
~Renderer();
void loadMatrix();
void Render();
void Transform();
Data data;
private:
unsigned int shaderID;
unsigned int programID;
unsigned int vertexBufferID;
unsigned int vertexArrayID;
unsigned int uniformBufferID;
unsigned int vertexShader;
unsigned int fragmentShader;
unsigned int prog;
};
#include "Test1.h"
#include "IO.h"
#include "glad/glad.h"
#include <iostream>
Renderer::Renderer()
{
shaderID = ShaderIO::loadShaderFromFile("resource\\shaders\\Test1\\compute.glsl", GL_COMPUTE_SHADER);
vertexShader = ShaderIO::loadShaderFromFile("resource\\shaders\\Test1\\vertex.glsl", GL_VERTEX_SHADER);
fragmentShader = ShaderIO::loadShaderFromFile("resource\\shaders\\Test1\\fragment.glsl", GL_FRAGMENT_SHADER);
prog = glCreateProgram();
glAttachShader(prog, vertexShader);
glAttachShader(prog, fragmentShader);
glLinkProgram(prog);
glValidateProgram(prog);
programID = glCreateProgram();
glAttachShader(programID, shaderID);
glLinkProgram(programID);
glValidateProgram(programID);
int isValid;
glGetProgramiv(programID, GL_VALIDATE_STATUS, &isValid);
if (!isValid)
{
std::cout << "[ERROR]: Program is not valid!" << std::endl;
glDeleteProgram(programID);
glDeleteShader(shaderID);
}
float positions[] =
{
-0.5f, -0.5f, 0.0f, 1.0f,
0.0f, 0.5f, 0.0f, 2.0f,
0.5f, -0.5f, 0.0f, 3.0f
};
glCreateVertexArrays(1, &vertexArrayID);
glEnableVertexArrayAttrib(vertexArrayID, 0);
glVertexArrayAttribBinding(vertexArrayID, 0, 0);
glVertexArrayAttribFormat(vertexArrayID, 0, 3, GL_FLOAT, GL_FALSE, 0);
glCreateBuffers(1, &vertexBufferID);
glNamedBufferData(vertexBufferID, sizeof(positions), positions, GL_DYNAMIC_DRAW);
glVertexArrayVertexBuffer(vertexArrayID, 0, vertexBufferID, 0, 4 * sizeof(float));
glBindVertexArray(vertexArrayID);
glUseProgram(prog);
glCreateBuffers(1, &uniformBufferID);
glNamedBufferData(uniformBufferID, sizeof(Data), nullptr, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniformBufferID);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vertexBufferID);
data.id = 2;
data.modelM = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
}
Renderer::~Renderer()
{
glDeleteProgram(programID);
glDeleteShader(shaderID);
glDeleteBuffers(1, &vertexBufferID);
glDeleteBuffers(1, &uniformBufferID);
glDeleteVertexArrays(1, &vertexArrayID);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteProgram(prog);
}
void Renderer::loadMatrix()
{
glNamedBufferSubData(uniformBufferID, 0, sizeof(Data), &data);
}
void Renderer::Render()
{
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void Renderer::Transform()
{
glUseProgram(programID);
glDispatchCompute(3, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glUseProgram(prog);
}
I have tried so many things and finally I found that when I exclude the u_id from uniform buffer and changed the size to just mat4's size, it worked! On the other hand, I don't know why it does not work with u_id and I have to use it. Please Help!
With the std140
standard, a member of type mat4
or vec4
is aligned to 16 bytes. This is specified in the OpenGL specification See Uniform Blocks:
- If the member is a two- or four-component vector with components consuming N basic machine units, the base alignment is 2N or 4N, respectively.
[...]- If the member is an array of scalars or vectors, the base alignment and array stride are set to match the base alignment of a single array element, according to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The array may have padding at the end; the base offset of the member following the array is rounded up to the next multiple of the base alignment.
- If the member is a column-major matrix with C columns and R rows, the matrix is stored identically to an array of C column vectors with R components each, according to rule (4).