Hi there!
For some reason the scene that should display data from SSBO looks really strange: random colors flickering and I don’t understand why.
I’ve recorded the screen to demonstrate the process (https://drive.google.com/file/d/18b0yG1Jhv1DchH0J5-XjkYFM399acn6e/view?usp=sharing) - the initial scene is on the left, the puzzled scene is on the right. Any help is appreciated!
Code:
#define PRINT_VAR(x) std::cout<<#x<<" == "<<x<<std::endl;
void checkGLError(std::string op);
// camera
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
int main( void )
{
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
int width = SCR_WIDTH;
int height = SCR_HEIGHT;
window = glfwCreateWindow( width, height, "Tutorial 08 - Basic Shading", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set the mouse at the center of the screen
glfwPollEvents();
glfwSetCursorPos(window, 1024/2, 768/2);
// Dark blue background
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders( "StandardShading.vertexshader", "StandardShading.fragmentshader" );
// add shaders for stencil
Shader shader("2.stencil_testing.vs", "2.stencil_testing.fs");
Shader shaderSingleColor("2.stencil_testing.vs", "2.stencil_single_color.fs");
// Get a handle for our "MVP" uniform
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint ViewMatrixID = glGetUniformLocation(programID, "V");
GLuint ModelMatrixID = glGetUniformLocation(programID, "M");
// Load the texture
GLuint Texture = loadDDS("uvmap.DDS");
// Get a handle for our "myTextureSampler" uniform
GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler");
// Read our .obj file
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
std::vector<glm::vec3> colors;
bool res = loadOBJ("suzanne.obj", vertices, uvs, normals);
// compute gradient
for (size_t i=0; i<normals.size() - 1; i+=2){
float A = compute_gradient(normals[i], normals[i+1]);
}
colors.resize(normals.size());
std::ofstream MyVerticesFile("vertices_data.txt");
std::ofstream MyUVSFile("uvs_data.txt");
std::ofstream MynNormalsFile("normals_data.txt");
for (size_t i=0; i<vertices.size(); ++i){
MyVerticesFile << glm::to_string(vertices[i]) << std::endl;
if(!((i+1)%3))MyVerticesFile << std::endl;
}
for (size_t i=0; i<uvs.size(); ++i){
MyUVSFile << glm::to_string(uvs[i]) << std::endl;
if(!((i+1)%3))MyUVSFile << std::endl;
}
for (size_t i=0; i<normals.size(); ++i){
MynNormalsFile << glm::to_string(normals[i]) << std::endl;
if(!((i+1)%3))MynNormalsFile << std::endl;
}
std::vector<glm::vec3> standardColors(6);
standardColors[0]=glm::vec3(1.0,0,0);
standardColors[1]=glm::vec3(0,1.0,0);
standardColors[2]=glm::vec3(0,0,1.0);
standardColors[3]=glm::vec3(1.0,0,1.0);
standardColors[4]=glm::vec3(1.0,1.0,0);
standardColors[5]=glm::vec3(1.0,1.0,1.0);
for (size_t i=0; i<vertices.size(); i+=3){
glm::vec3 clr = standardColors[rand()%6];
colors[i] = clr;
colors[i+1] = clr;
colors[i+2] = clr;
}
MyVerticesFile.close();
MyUVSFile.close();
MynNormalsFile.close();
// Load it into a VBO
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(glm::vec2), &uvs[0], GL_STATIC_DRAW);
GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW);
GLuint colorbuffer;
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &colors[0], GL_STATIC_DRAW);
GLuint imageBuffer;
std::vector<float> image;
image.resize(width*height*3);
cv::Mat img = cv::Mat(height, width, CV_32FC3);
std::cout<<"Creating image buffer"<<std::endl;
glCreateBuffers(1, &imageBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, imageBuffer);
glNamedBufferStorage(imageBuffer, // Name of the buffer
//width*height*sizeof(glm::vec3), // Storage size in bytes
width*height*sizeof(float)*3, // Storage size in bytes
img.data,//&image[0], // initial data
GL_MAP_WRITE_BIT | GL_MAP_READ_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_PERSISTENT_BIT ); // Allow map for writing
glBufferData(GL_SHADER_STORAGE_BUFFER, /*width*height*sizeof(glm::vec3)*/width*height*sizeof(float)*3, /*&image[0]*/img.data, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2/*see fragment shader binding*/, imageBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLuint depthBuffer;
cv::Mat depth = cv::Mat(height, width, CV_32FC1);
std::cout<<"Creating depthBuffer buffer"<<std::endl;
glCreateBuffers(1, &depthBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, imageBuffer);
glNamedBufferStorage(depthBuffer, // Name of the buffer
//width*height*sizeof(glm::vec3), // Storage size in bytes
width*height*sizeof(float), // Storage size in bytes
depth.data,//&image[0], // initial data
GL_MAP_WRITE_BIT | GL_MAP_READ_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_PERSISTENT_BIT ); // Allow map for writing
glBufferData(GL_SHADER_STORAGE_BUFFER, /*width*height*sizeof(glm::vec3)*/width*height*sizeof(float), /*&image[0]*/depth.data, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1/*see fragment shader binding*/, depthBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
glUseProgram(programID)
std::cout<<"Initiating width/height uniform"<<std::endl;
GLuint imageHeightID = glGetUniformLocation(programID, "imageHeight");
GLuint imageWidthID = glGetUniformLocation(programID, "imageWidth");
glUniform1i(imageHeightID, height);
glUniform1i(imageWidthID, width);
int h,w;
glGetUniformiv( programID, imageHeightID,&h);
glGetUniformiv( programID, imageWidthID,&w);
PRINT_VAR(h);
PRINT_VAR(w);
// Get a handle for our "LightPosition" uniform
glUseProgram(programID);
GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");
//glEnable(GL_FRAMEBUFFER_SRGB);
std::cout<<"Creating buffers finished"<<std::endl;
glMemoryBarrier( GL_SHADER_STORAGE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT);
glEnable(GL_DEPTH_TEST);
int iImg = 0;
do{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, imageBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2/*see fragment shader binding*/, imageBuffer);
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Compute the MVP matrix from keyboard and mouse input
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glm::vec3 lightPos = glm::vec3(4,4,4);
glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// Set our "myTextureSampler" sampler to use Texture Unit 0
glUniform1i(TextureID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// color attribute buffer : normals
GLuint colorAttribLocation = glGetAttribLocation(programID,"reqColor");
glEnableVertexAttribArray(colorAttribLocation);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
colorAttribLocation, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, vertices.size() );
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glFinish();
// Get a pointer to the buffer's data store
std::cout<<"Grabbing imageBuffer"<<std::endl;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, imageBuffer);
void * ptr = glMapNamedBuffer(imageBuffer,GL_READ_ONLY);// GL_READ_WRITE);//
if(ptr != NULL)
{
// Copy our data into it...
memcpy(img.data, ptr, width*height*sizeof(float)*3);
// Tell OpenGL that we're done with the pointer
glUnmapNamedBuffer(imageBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
cv::imshow("Suzane",img);
std::stringstream ss;
std::cout<<"Image read"<<std::endl;
cv::waitKey(100);
float zero = 0.0f;
GLubyte val = 0;
glClearNamedBufferData(imageBuffer, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, &val);
checkGLError("Clear");
}
else
{
checkGLError("Map returned NULL");
glUnmapNamedBuffer(imageBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}
glBindBuffer(GL_SHADER_STORAGE_BUFFER, depthBuffer);
ptr = glMapNamedBuffer(depthBuffer,GL_READ_ONLY);
if(ptr != NULL)
{
// Copy our data into it...
memcpy(depth.data, ptr, width*height*sizeof(float));
// Tell OpenGL that we're done with the pointer
cv::imshow("Suzane deep",depth);
checkGLError("Depth");
}
else
checkGLError("Depth NULL");
glUnmapNamedBuffer(depthBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLubyte val = 0;
glClearNamedBufferData(depthBuffer, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE,&val);
glFlush();
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
// Cleanup VBO and shader
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &uvbuffer);
glDeleteBuffers(1, &normalbuffer);
glDeleteProgram(programID);
glDeleteTextures(1, &Texture);
glDeleteVertexArrays(1, &VertexArrayID);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
void checkGLError(std::string op) {
int error;
while ((error = glGetError()) != GL_NO_ERROR) {
std::cout<<"MyApp"<< op << ": glError " << error<<std::endl;
}
}
Vertex Shader
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;
layout(location = 2) in vec3 vertexNormal_modelspace;
layout(location = 3) in vec3 reqColor;
// Output data ; will be interpolated for each fragment.
out vec2 UV;
out vec3 Position_worldspace;
out vec3 Normal_cameraspace;
out vec3 EyeDirection_cameraspace;
out vec3 LightDirection_cameraspace;
out vec3 colorIn;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
uniform vec3 LightPosition_worldspace;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
// Position of the vertex, in worldspace : M * position
Position_worldspace = (M * vec4(vertexPosition_modelspace,1)).xyz;
// Vector that goes from the vertex to the camera, in camera space.
// In camera space, the camera is at the origin (0,0,0).
vec3 vertexPosition_cameraspace = ( V * M * vec4(vertexPosition_modelspace,1)).xyz;
EyeDirection_cameraspace = vec3(0,0,0) - vertexPosition_cameraspace;
// Vector that goes from the vertex to the light, in camera space. M is ommited because it's identity.
vec3 LightPosition_cameraspace = ( V * vec4(LightPosition_worldspace,1)).xyz;
LightDirection_cameraspace = LightPosition_cameraspace + EyeDirection_cameraspace;
// Normal of the the vertex, in camera space
Normal_cameraspace = ( V * M * vec4(vertexNormal_modelspace,0)).xyz; // Only correct if ModelMatrix does not scale the model ! Use its inverse transpose if not.
// UV of the vertex. No special space for this one.
UV = vertexUV;
// coloring
colorIn = reqColor;
}
Fragment Shader:
layout(early_fragment_tests) in;
// Interpolated values from the vertex shaders
in vec2 UV;
in vec3 Position_worldspace;
in vec3 Normal_cameraspace;
in vec3 EyeDirection_cameraspace;
in vec3 LightDirection_cameraspace;
in vec3 colorIn;
layout(origin_upper_left) in vec4 gl_FragCoord ;
// Ouput data
out vec3 color;
// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;
uniform mat4 MVP;
uniform vec3 LightPosition_worldspace;
uniform int imageBufferID;
uniform int imageWidth;
uniform int imageHeight;
layout(std430, binding = 2) buffer imageLayout
{
float image[];
} SharedBuffer;
layout(std430, binding = 1) buffer ImageDepthLayout
{
float depth[];
} SharedDepthBuffer;
#define SIZE_OF_VEC3 12
void main(){
vec3 LightColor = vec3(1,1,1);
float LightPower = 50.0f;
// Material properties
vec3 MaterialDiffuseColor = texture( myTextureSampler, UV ).rgb;
vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * MaterialDiffuseColor;
vec3 MaterialSpecularColor = vec3(0.3,0.3,0.3);
// Distance to the light
float distance = length( LightPosition_worldspace - Position_worldspace );
// Normal of the computed fragment, in camera space
vec3 n = normalize( Normal_cameraspace );
// Direction of the light (from the fragment to the light)
vec3 l = normalize( LightDirection_cameraspace );
float cosTheta = clamp( dot( n,l ), 0,1 );
// Eye vector (towards the camera)
vec3 E = normalize(EyeDirection_cameraspace);
// Direction in which the triangle reflects the light
vec3 R = reflect(-l,n);
// Cosine of the angle between the Eye vector and the Reflect vector,
// clamped to 0
// - Looking into the reflection -> 1
// - Looking elsewhere -> < 1
float cosAlpha = clamp( dot( E,R ), 0,1 );
memoryBarrierBuffer();
vec4 xy = gl_FragCoord;
highp int x = int(xy.x);
highp int y = int(xy.y);
int stride = imageWidth*3;//SIZE_OF_VEC3*imageWidth;
int maxOffset = imageWidth*imageHeight*3;//*SIZE_OF_VEC3;
int offset = int(3*x + y*stride);
if(offset>=maxOffset) offset= maxOffset-1;
int ind = offset;
int strideDepth = imageWidth;
int offsetDepth = int(x + y*strideDepth);
if( (xy.z<SharedDepthBuffer.depth[offsetDepth]) || (SharedDepthBuffer.depth[offsetDepth] == 0))
{
SharedDepthBuffer.depth[offsetDepth] = xy.z;
SharedBuffer.image[offset] = colorIn.x;
SharedBuffer.image[offset+1] = colorIn.y;
SharedBuffer.image[offset+2] = colorIn.z;
}
color = colorIn;
}