diff --git a/shaders/exitpoints.frag b/shaders/exitpoints.frag new file mode 100644 index 0000000000..5ddaaa0ad3 --- /dev/null +++ b/shaders/exitpoints.frag @@ -0,0 +1,19 @@ +#version 400 core + +// uniform sampler2D texUnit; + +in vec3 vPosition; +in vec2 texCoords; +out vec4 fragColor; + +void main() { + fragColor = vec4(vPosition+0.5, 1.0); + // if (fragColor.x <= 0.55 && fragColor.x >= 0.45) + // fragColor = vec4(1.0); + // else if (fragColor.y <= 0.55 && fragColor.y >= 0.45) + // fragColor = vec4(1.0); + + // fragColor = vec4(texCoords.x, texCoords.y, 0.0, 1.0); + + // fragColor = texture(texUnit, -texCoords+1); +} \ No newline at end of file diff --git a/shaders/passthrough.vert b/shaders/exitpoints.vert similarity index 90% rename from shaders/passthrough.vert rename to shaders/exitpoints.vert index 17f7c98511..d5afded9d6 100644 --- a/shaders/passthrough.vert +++ b/shaders/exitpoints.vert @@ -9,7 +9,6 @@ out vec2 texCoords; void main() { gl_Position = modelViewProjection * vec4(vertPosition, 1.0); - // vPosition = gl_Position.xyz; vPosition = vertPosition; texCoords = texCoordinate; } \ No newline at end of file diff --git a/shaders/passthrough.frag b/shaders/passthrough.frag deleted file mode 100644 index 97198b736c..0000000000 --- a/shaders/passthrough.frag +++ /dev/null @@ -1,19 +0,0 @@ -#version 400 core - -uniform sampler2D texJonas; - -in vec3 vPosition; -in vec2 texCoords; -out vec4 fragColor; - -void main() { - fragColor = vec4(vPosition+0.5, 1.0); - if (fragColor.x <= 0.55 && fragColor.x >= 0.45) - fragColor = vec4(1.0); - else if (fragColor.y <= 0.55 && fragColor.y >= 0.45) - fragColor = vec4(1.0); - - fragColor = vec4(texCoords.x, texCoords.y, 0.0, 1.0); - - fragColor = texture(texJonas, -texCoords+1); -} \ No newline at end of file diff --git a/shaders/rendertoscreen.frag b/shaders/rendertoscreen.frag new file mode 100644 index 0000000000..b16026dc4c --- /dev/null +++ b/shaders/rendertoscreen.frag @@ -0,0 +1,33 @@ +#version 400 core + +uniform sampler2D texBack, texFront; +uniform sampler3D texVolume; +uniform int screenWidth, screenHeight; + +in vec3 vPosition; +in vec2 texCoords; +out vec4 fragColor; + +void main() {; + fragColor = vec4(texCoords, 1.0, 1.0); + + vec3 front = texture(texFront, texCoords).xyz; + vec3 back = texture(texBack, texCoords).xyz; + vec3 direction = back-front; + direction = normalize(direction); + vec3 position = front; + float stepSize = 0.05; + vec4 color = vec4(0); + vec4 tmp; + + + for (int i = 0; i < 100; ++i) { + tmp = texture(texVolume, position); + if (tmp.r > color.r) + color = tmp; + + position = position + direction * stepSize; + } + + fragColor = vec4(color.rrr,1.0); +} \ No newline at end of file diff --git a/shaders/rendertoscreen.vert b/shaders/rendertoscreen.vert new file mode 100644 index 0000000000..164a5e8643 --- /dev/null +++ b/shaders/rendertoscreen.vert @@ -0,0 +1,15 @@ +#version 400 core + +layout(location = 0) in vec2 texCoordinate; +layout(location = 2) in vec3 vertPosition; + +out vec3 vPosition; +out vec2 texCoords; + +// Source: http://stackoverflow.com/questions/2588875/whats-the-best-way-to-draw-a-fullscreen-quad-in-opengl-3-2 +const vec2 screenScale = vec2(0.5, 0.5); + +void main() { + texCoords = vertPosition.xy*screenScale+screenScale; // scale vertex attribute to [0-1] range + gl_Position = vec4(vertPosition.xy, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/rendering/volumeraycaster.cpp b/src/rendering/volumeraycaster.cpp index 8586a6f4b6..1c942c990e 100644 --- a/src/rendering/volumeraycaster.cpp +++ b/src/rendering/volumeraycaster.cpp @@ -2,29 +2,21 @@ #include #include -#include #include namespace openspace { GLuint vertexArray = GL_FALSE; GLuint vertexPositionBuffer = GL_FALSE; -GLint matrix_loc = -1; -GLuint sgctFBO; VolumeRaycaster::VolumeRaycaster() { initialize(); } -VolumeRaycaster::VolumeRaycaster(Camera* camera) { - _camera = camera; - initialize(); -} - VolumeRaycaster::~VolumeRaycaster() {} void VolumeRaycaster::initialize() { - const GLfloat size = 0.5f; + const GLfloat size = 1.0f; const GLfloat vertex_texcoord_data[] = { // square of two triangles (sigh) -size, -size, 0.0f, 0.0f, 0.0f, size, size, 0.0f, 1.0f, 1.0f, @@ -54,23 +46,35 @@ void VolumeRaycaster::initialize() { glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer glBindVertexArray(0); //unbind array - _test = loadTexture(absPath("${BASE_PATH}/openspace-data/jonas.jpg")); + myBox = new sgct_utils::SGCTBox(1.0f, sgct_utils::SGCTBox::Regular); - if (_test == nullptr) - std::cout << "Image failed to load" << std::endl; - - _test->uploadTexture(); - - myBox = new sgct_utils::SGCTBox(1.5f, sgct_utils::SGCTBox::Regular); +// ------ VOLUME READING ---------------- + const char* filename = "../openspace-data/skull_256x256x256_8.raw"; + int dimensions[3]; + dimensions[0] = 256;dimensions[1] = 256;dimensions[2] = 256; + createVolumetexture(filename, dimensions); // ------ SETUP SHADERS ----------------- - _program = new ProgramObject("RaycastProgram"); + _FBOProgram = new ProgramObject("RaycastProgram"); + ShaderObject* vertexShader = new ShaderObject(ShaderObject::ShaderTypeVertex, absPath("${BASE_PATH}/shaders/exitpoints.vert")); + ShaderObject* fragmentShader = new ShaderObject(ShaderObject::ShaderTypeFragment, absPath("${BASE_PATH}/shaders/exitpoints.frag")); + _FBOProgram->attachObject(vertexShader); + _FBOProgram->attachObject(fragmentShader); + _FBOProgram->compileShaderObjects(); + _FBOProgram->linkProgramObject(); - ShaderObject* vertexShader = new ShaderObject(ShaderObject::ShaderTypeVertex, absPath("${BASE_PATH}/shaders/passthrough.vert")); - ShaderObject* fragmentShader = new ShaderObject(ShaderObject::ShaderTypeFragment, absPath("${BASE_PATH}/shaders/passthrough.frag")); - - _program->attachObject(vertexShader); - _program->attachObject(fragmentShader); + _screenProgram = new ProgramObject("RaycastProgram"); + vertexShader = new ShaderObject(ShaderObject::ShaderTypeVertex, absPath("${BASE_PATH}/shaders/rendertoscreen.vert")); + fragmentShader = new ShaderObject(ShaderObject::ShaderTypeFragment, absPath("${BASE_PATH}/shaders/rendertoscreen.frag")); + _screenProgram->attachObject(vertexShader); + _screenProgram->attachObject(fragmentShader); + _screenProgram->compileShaderObjects(); + _screenProgram->linkProgramObject(); + _screenProgram->setUniform("texBack", 0); + _screenProgram->setUniform("texFront", 1); + _screenProgram->setUniform("texVolume", 2); + _screenProgram->setUniform("screenWidth", sgct::Engine::instance()->getActiveXResolution()); + _screenProgram->setUniform("screenHeight", sgct::Engine::instance()->getActiveYResolution()); // ------ SETUP FBO --------------------- _fbo = new FramebufferObject(); @@ -78,61 +82,95 @@ void VolumeRaycaster::initialize() { int x = sgct::Engine::instance()->getActiveXResolution(); int y = sgct::Engine::instance()->getActiveYResolution(); - _texture = new Texture(glm::size3_t(x,y,1)); - _texture->uploadTexture(); - - _fbo->attachTexture(_texture); - if (_fbo->isComplete()) - std::cout << "All is well" << std::endl; - else - std::cout << "Uh oh" << std::endl; + _backTexture = new Texture(glm::size3_t(x,y,1)); + _frontTexture = new Texture(glm::size3_t(x,y,1)); + _backTexture->uploadTexture(); + _frontTexture->uploadTexture(); + _fbo->attachTexture(_backTexture, GL_COLOR_ATTACHMENT0); + _fbo->attachTexture(_frontTexture, GL_COLOR_ATTACHMENT1); _fbo->deactivate(); } -void VolumeRaycaster::loadUniforms() { - glm::mat4 modelViewProjectionMatrix = sgct::Engine::instance()->getActiveModelViewProjectionMatrix(); - _program->setUniform("modelViewProjection", modelViewProjectionMatrix); - - glActiveTexture(GL_TEXTURE0); - _test->bind(); - _program->setUniform("texJonas", 0); -} - void VolumeRaycaster::render() { -// ------ DRAW TO FBO ------------------- - sgctFBO = FramebufferObject::getActiveObject(); // Save SGCTs main FBO + glm::mat4 modelViewProjectionMatrix = sgct::Engine::instance()->getActiveModelViewProjectionMatrix(); + _FBOProgram->setUniform("modelViewProjection", modelViewProjectionMatrix); +// ------ DRAW TO FBO ------------------- + _sgctFBO = FramebufferObject::getActiveObject(); // Save SGCTs main FBO _fbo->activate(); + _FBOProgram->activate(); + +// Draw backface + glDrawBuffer(GL_COLOR_ATTACHMENT0); glClearColor(0.2f, 0.2f, 0.2f, 0); glClear(GL_COLOR_BUFFER_BIT); - _program->compileShaderObjects(); - _program->linkProgramObject(); - _program->activate(); - loadUniforms(); - glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); myBox->draw(); glDisable(GL_CULL_FACE); - _program->deactivate(); +// Draw frontface + glDrawBuffer(GL_COLOR_ATTACHMENT1); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0.2f, 0.2f, 0.2f, 0); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + myBox->draw(); + glDisable(GL_CULL_FACE); + + _FBOProgram->deactivate(); _fbo->deactivate(); // ------ DRAW TO SCREEN ---------------- - glBindFramebuffer(GL_FRAMEBUFFER, sgctFBO); // Re-bind SGCTs main FBO + glBindFramebuffer(GL_FRAMEBUFFER, _sgctFBO); // Re-bind SGCTs main FBO + _screenProgram->activate(); + +// Set textures + glActiveTexture(GL_TEXTURE0); + _backTexture->bind(); + glActiveTexture(GL_TEXTURE1); + _frontTexture->bind(); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_3D, _volumeTexture); + +// Draw screenquad glClearColor(0.2f, 0.2f, 0.2f, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - _program->compileShaderObjects(); - _program->linkProgramObject(); - _program->activate(); - loadUniforms(); - glBindVertexArray(vertexArray); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); - _program->deactivate(); + _screenProgram->deactivate(); +} + +void VolumeRaycaster::createVolumetexture(const char *filename, int dimensions[3]) { + // Make sure that the texture is not used + if(glIsTexture(_volumeTexture)) + glDeleteTextures(1, &_volumeTexture); + + int size = dimensions[0]*dimensions[1]*dimensions[2]; + GLubyte *data = new GLubyte[size]; + + if( FILE *fin = fopen(filename, "rb") ){ + fread(data, sizeof(unsigned char), size, fin); + fclose(fin); + } + else + fprintf( stderr, "Could not open file '%s'\n", filename ); + + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + glGenTextures(1, &_volumeTexture); + glBindTexture(GL_TEXTURE_3D, _volumeTexture); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + glTexImage3D(GL_TEXTURE_3D, 0, GL_R8, dimensions[0], dimensions[1],dimensions[2],0, GL_RED, GL_UNSIGNED_BYTE,data); + glBindTexture(GL_TEXTURE_3D, 0); + delete []data; + std::cout << "Volume texture created" << std::endl; } }// namespace openspace diff --git a/src/rendering/volumeraycaster.h b/src/rendering/volumeraycaster.h index 7e4d83db0c..f9c760bde9 100644 --- a/src/rendering/volumeraycaster.h +++ b/src/rendering/volumeraycaster.h @@ -5,8 +5,8 @@ #include #include -#include #include +#include namespace openspace { using namespace ghoul::opengl; @@ -14,20 +14,23 @@ using namespace ghoul::opengl; class VolumeRaycaster { public: VolumeRaycaster(); - VolumeRaycaster(Camera* camera); ~VolumeRaycaster(); void initialize(); void render(); private: - void loadUniforms(); + void createVolumetexture(const char *filename, int dimensions[3]); FramebufferObject* _fbo; - Texture* _texture; - Texture* _test; + Texture* _backTexture; + Texture* _frontTexture; + Texture* _volume; - Camera* _camera; - ProgramObject* _program; + GLuint _volumeTexture; + GLuint _sgctFBO; + + ProgramObject* _FBOProgram; + ProgramObject* _screenProgram; sgct_utils::SGCTBox* myBox; };