Need help with offscreen rendering

Started by Imagyx, February 10, 2021, 21:40:25

Previous topic - Next topic

Imagyx

Hello everyone.

I wanted to give it a try and switch from CPU-Raytracing with Java to using OpenGL and therefore LWJGL.
I've searched for days about one problem I cannot solve concerning the size of an image I want to save.
I setup GLFW and everything neccessary for a compute shader to render me  a simple scene on screen, which works   :)
But when I want to save into a BufferedImage bigger than my screen size, a part of the image is left black.
I read a lot about using glViewport, disabling GL_SCISSOR_TEST, using Renderbuffer and  I tried all of that with no better results.

I would appreciate it a lot if someone can help me with that, as I think that this is a simple question for any pro used to these kinds of things for a long time.
I know that I don't know much about OpenGL yet, still I want to keep going since the speedup is 1000x and more from my CPU tracer to what I have no with the GPU.
Thank you in advance for any help.


This is my setup:
createOffscreen();
		int framebuffer = initShaders();
		resetShaders();		
		glViewport(0, 0, width, height); // 3000x2040 e.g.
		glDisable(GL_SCISSOR_TEST);
		tracing();
		saveImage(framebuffer);


with methods

private void createOffscreen() {
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
		glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
		glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
		glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
		long offscreen = glfwCreateWindow(width, height, "", NULL, NULL);
		glfwMakeContextCurrent(offscreen);
		createCapabilities();
	}
	private void saveImage(int framebuffer) {
		glReadBuffer(framebuffer);
		int bpp = 4; //RGBA
		ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
		GL11.glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		BufferedImage offscreen = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		for(int x = 0; x < width; x++){
		    for(int y = 0; y < height; y++){
		        int i = (x + (width * y)) * bpp;
		        int r = buffer.get(i) & 0xFF;
		        int g = buffer.get(i + 1) & 0xFF;
		        int b = buffer.get(i + 2) & 0xFF;
		        offscreen.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b);
		    }
		}
		...ImageIO.write....
	}
	private void resetShaders() {
		glShaderSource(quadProgramVs, templating(VERTEX_SHADER ,vertexShader.getText()));
		glCompileShader(quadProgramVs);
		
		glShaderSource(quadProgramFs, templating(FRAGMENT_SHADER, fragmentShader.getText()));
		glCompileShader(quadProgramFs);
		
		glLinkProgram(quadProgram);

		glShaderSource(computeProgramShader, templating(COMPUTE_SHADER, computeShader.getText()));
		glCompileShader(computeProgramShader);
		
		glLinkProgram(computeProgram);
		
		numGroupsX = (int) Math.ceil((double) width / 8);
		numGroupsY = (int) Math.ceil((double) height / 8);
	}
	
	private int initShaders() {
		glBindVertexArray(glGenVertexArrays());

		int framebuffer = glGenTextures();
		glBindTexture(GL_TEXTURE_2D, framebuffer);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
		glBindImageTexture(0, framebuffer, 0, false, 0, GL_WRITE_ONLY, GL_RGBA8);

		// Create program to render framebuffer texture as fullscreen quad
		quadProgram = glCreateProgram();

		quadProgramVs = glCreateShader(GL_VERTEX_SHADER);
		glAttachShader(quadProgram, quadProgramVs);
		
		quadProgramFs = glCreateShader(GL_FRAGMENT_SHADER);
		glAttachShader(quadProgram, quadProgramFs);
		
		// Create ray tracing compute shader
		computeProgram = glCreateProgram();
		computeProgramShader = glCreateShader(GL_COMPUTE_SHADER);
		glAttachShader(computeProgram, computeProgramShader);
		
		return framebuffer;
	}

	private void tracing() {
		// Trace the scene
		glUseProgram(computeProgram);
		glDispatchCompute(numGroupsX, numGroupsY, 1);
		glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

		glUseProgram(quadProgram);
		glDrawArrays(GL_TRIANGLES, 0, 3);
	}