Compute shader not working - trying to just make it work at all

HI :slight_smile:
So, I want to try the compute shader to calculate transfer functions on my 3D texture, and output a new 3D texture, but I cant get it to work at all… Nothing happens. Right now I am just trying to fill the whole new 3D texture (outVolumeTexture) with values of 100.0. If I try to put in a nullptr as data for outVolumeTexture, the result is still empty. If I put in pData, the resulting 3d texture is just pData (it doesnt get changed).
Here is my volume renderer. I am calling the compute shader in my constructor. Is this a problem? Or is it something with the formats of my 3D textures? Or am I forgetting something?

GLSL SHADER:

#version 450
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;

layout(r32f, binding = 0) uniform image3D inputVolumeImage;
layout(r32f, binding = 1) uniform image3D outputVolumeImage;
//layout(r32ui, binding = 2) uniform uimage2D outputHistogramImage;

void main(void)
{
    ivec3 coord = ivec3(gl_GlobalInvocationID);
    imageStore(outputVolumeImage, coord, vec4(100.0, 100.0, 100.0, 100.0));

RENDERING FILE (.cpp):

#include "VolumeRenderer.h"
#include <globjects/base/File.h>
#include <iostream>
#include "Viewer.h"

using namespace dynamol;
using namespace gl;
using namespace glm;
using namespace globjects;

VolumeRenderer::VolumeRenderer(Viewer* viewer, bool isVR) : Renderer(viewer, isVR)
{
	if (isVR) {
		viewportSize = (ivec2)viewer->renderTargetSize();
	} 
	else {
		viewportSize = viewer->viewportSize();
	}

	//  Load shaders and attach to program

	// MAIN RENDER SHADER
	m_program = globjects::Program::create();
	m_vertexShaderSource = Shader::sourceFromFile("./../res/volume/volume-vs.glsl");
	m_fragmentShaderSource = Shader::sourceFromFile("./../res/volume/volume-fs.glsl");
	m_vertexShader = Shader::create(GL_VERTEX_SHADER, m_vertexShaderSource.get());
	m_fragmentShader = Shader::create(GL_FRAGMENT_SHADER, m_fragmentShaderSource.get());
	m_program->attach(m_vertexShader.get(), m_fragmentShader.get());

	// Build quad to fill screen
	m_quadVertices->setStorage(std::array<vec2, 4>({ vec2(-1.0f, 1.0f), vec2(-1.0f, -1.0f), vec2(1.0f, 1.0f), vec2(1.0f, -1.0f) }), gl::GL_NONE_BIT);
	auto vertexBindingQuad = m_quadArray->binding(0);						//bind buffer 0
	vertexBindingQuad->setBuffer(m_quadVertices.get(), 0, sizeof(vec2));	//point at the array above, start at 0, stride of vec2
	vertexBindingQuad->setFormat(2, GL_FLOAT);
	m_quadArray->enable(0);
	m_quadArray->unbind();

	// Load data, create and bind source 3D texture
	unsigned short uWidth = viewer->scene()->volume()->uWidth;
	unsigned short uHeight = viewer->scene()->volume()->uHeight;
	unsigned short uDepth = viewer->scene()->volume()->uDepth;
	unsigned short* pData = viewer->scene()->volume()->pData;

	volumeTexture = Texture::create(GL_TEXTURE_3D);
	volumeTexture->setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	volumeTexture->setParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	volumeTexture->setParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	volumeTexture->setParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	volumeTexture->setParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
	volumeTexture->image3D(0, GL_R32F, ivec3(uWidth, uHeight, uDepth), 0, GL_RED, GL_UNSIGNED_SHORT, pData);
	

	// COMPUTE SHADER
	m_computeProgram = globjects::Program::create();
	m_computeShaderSource = Shader::sourceFromFile("./../res/volume/volume-cs.glsl");
	m_computeShader = Shader::create(GL_COMPUTE_SHADER, m_computeShaderSource.get());
	m_computeProgram->attach(m_computeShader.get());

	// Create and bind output 3D texture
	outVolumeTexture = Texture::create(GL_TEXTURE_3D);
	outVolumeTexture->setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	outVolumeTexture->setParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	outVolumeTexture->setParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	outVolumeTexture->setParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	outVolumeTexture->setParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
	outVolumeTexture->image3D(0, GL_R32F, ivec3(uWidth, uHeight, uDepth), 0, GL_RED, GL_UNSIGNED_SHORT, pData);

	// Create and bind output histogram texture
	outHistogramTexture = Texture::create(GL_TEXTURE_2D);
	outHistogramTexture->setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	outHistogramTexture->setParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	outHistogramTexture->setParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	outHistogramTexture->setParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	outHistogramTexture->image2D(0, GL_R32F, ivec2(512, 512), 0, GL_RED, GL_UNSIGNED_SHORT , nullptr);

	int groupSizeX = 1, groupSizeY = 1, groupSizeZ = 1;
	int numGroupsX = ceilf(float(uWidth) / float(groupSizeX));
	int numGroupsY = ceilf(float(uHeight) / float(groupSizeY));
	int numGroupsZ = ceilf(float(uDepth) / float(groupSizeZ));

	m_computeProgram->use();

	m_computeProgram->setUniform("inputVolumeImage", 0);
	volumeTexture->bindActive(0);
	m_computeProgram->setUniform("outputVolumeImage", 1);
	outVolumeTexture->bindActive(1);
	//m_computeProgram->setUniform("outputHistogramImage", 2);
	//outHistogramTexture->bindActive(2);
	
	m_computeProgram->dispatchCompute(uWidth, uHeight, uDepth);
	glMemoryBarrier(GL_ALL_BARRIER_BITS);
	m_computeProgram->release();

	volumeTexture->unbind();
	outVolumeTexture->unbind();
	outHistogramTexture->unbind();
	
}

std::list<globjects::File*> VolumeRenderer::shaderFiles() const
{
	return std::list<globjects::File*>({
		m_vertexShaderSource.get(),
		m_fragmentShaderSource.get()
	});
}

void VolumeRenderer::display()
{
	// SaveOpenGL state
	auto currentState = State::currentState();

	// Set background color
	glm::vec3 m_backgroundColor = viewer()->backgroundColor();

	// Update matrices
	const mat4 projectionMatrix = viewer()->projectionTransform();
	const mat4 viewMatrix = viewer()->viewTransform();
	const mat4 modelMatrix = viewer()->modelTransform(); 
	const mat4 modelViewMatrix = viewMatrix * modelMatrix;
	const mat4 modelViewProjectionMatrix = projectionMatrix * modelViewMatrix;
	const mat4 inverseModelViewProjectionMatrix = inverse(modelViewProjectionMatrix);

	// BIND FRAMEBUFFER
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	
	// Set OpenGL parameters
	glViewport(0, 0, viewportSize.x, viewportSize.y);
	glClearDepth(1.0f);
	glClearColor(0.0, 0.0, 0.0, 65535.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);

	// set shader parameters
	m_program->setUniform("modelViewProjectionMatrix", modelViewProjectionMatrix);
	m_program->setUniform("inverseModelViewProjectionMatrix", inverseModelViewProjectionMatrix);
	m_program->setUniform("maxNumberOfSteps", maxNumberOfSteps);
	m_program->setUniform("minimumHitDistance", minimumHitDistance);
	m_program->setUniform("maximumTraceDistance", maximumTraceDistance);
	m_program->setUniform("lightPosition", lightPosition);
	m_program->setUniform("lightColor", lightColor);
	m_program->setUniform("volumeTexture", 1);
	outVolumeTexture->bindActive(1);

	m_quadArray->bind();
	m_program->use();
	// Render a screen filling quad (as a triangle strip), so we can cast rays for every pixel
	m_quadArray->drawArrays(gl::GL_TRIANGLE_STRIP, 0, 4);
	m_program->release();
	m_quadArray->unbind();
	outVolumeTexture->unbind();

	glDisable(GL_BLEND);
	glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
	currentState->apply();
}

void VolumeRenderer::displayVR()
{
	viewportSize = ivec2(vec2(viewer()->renderTargetSize()));

	display();

	
}

OK so my professor answered it for me!

the problem is here:

m_computeProgram->setUniform("inputVolumeImage", 0);
volumeTexture->bindActive(0);
m_computeProgram->setUniform("outputVolumeImage", 1);
outVolumeTexture->bindActive(1);

You are not using textures in your shader, but you are using image units. The bind/bindActive functions bind the corresponding textures to texture units which would be accessible via samplers in glsl. For image units, there is a separate command (glBindImageTexture), see the VolumeApp-v4 example on Mitt, renderwidget.cpp, lines 125 to 127.

Note that globject’s texture class has an abstraction over this (the bindImageTexture method) that you can/should use. Hence, in your example code, the above lines should be replaced by

volumeTexture->bindImageTexture(0, 0, true, 0, GL_READ_ONLY, GL_R32F);
outVolumeTexture->bindImageTexture(1, 0, true, 0, GL_WRITE_ONLY, GL_R32F);

(the setUniforms are not necessary since the id of image unit is already specified in the shader code using binding = 0 / binding = 1 – this corresponds to the first parameter of bindImageTexture)

1 Like