I tried to render a triangle with a tessellation shader. Now, without the tessellation shaders, the triangle renders fine. As soon as I add the tessellation shaders, I get a blank screen. I have also written glPatchParameteri(GL_PATCH_VERTICES,3) before glDrawArrays(GL_PATCHES,0,3).
Here are the shaders:
VERTEX SHADER:
#version 440 core
layout (location = 0) in vec2 apos;
out vec2 pos;
void main()
{
//gl_Position = vec4(apos,1.0f,1.0f); without tessellation shaders
pos = apos;
}
TESSELLATION CONTROL SHADER
#version 440 core
layout (vertices = 3) out;
in vec2 pos[];
out vec2 EsPos[];
void main()
{
EsPos[gl_InvocationID] = pos[gl_InvocationID];
gl_TessLevelOuter[0] = 3.0f;
gl_TessLevelOuter[1] = 3.0f;
gl_TessLevelOuter[2] = 3.0f;
gl_TessLevelInner[0] = 3.0f;
}
TESSELLATION EVALUATE SHADER
#version 440 core
layout (triangles, equal_spacing, ccw) in;
in vec2 EsPos[];
vec2 finalpos;
vec2 interpolate2D(vec2 v0, vec2 v1);
void main()
{
finalpos = interpolate2D(EsPos[0],EsPos[1]);
gl_Position = vec4(finalpos,0.0f,1.0f);
}
vec2 interpolate2D(vec2 v0, vec2 v1)
{
return (vec2(gl_TessCoord.x)*v0 + vec2(gl_TessCoord.y)*v1);
}
FRAGMENT SHADER
#version 440 core
out vec4 Fragment;
void main()
{
Fragment = vec4(0.0f,1.0f,1.0f,1.0f);
}
EDIT:
I made changes in the interpolate2D function, but still I am getting a blank screen.
The output patch size of the Tessellation Evaluation shader is 3:
layout (vertices = 3) out;
Thus the length of the input array to the Tessellation Control Shader is 3, too. Furthermore, the abstract patch type is triangles,
layout (triangles, equal_spacing, ccw) in;
thus the tessellation coordinate (gl_TessCoord) is a Barycentric coordinate. Change the interpolation:
vec2 interpolate2D(vec2 v0, vec2 v1, vec2 v2)
{
return v0*gl_TessCoord.x + v1*gl_TessCoord.y + v2*gl_TessCoord.z;
}
void main()
{
finalpos = interpolate2D(EsPos[0], EsPos[1], EsPos[2]);
// [...]
}
Related
I'm new to OpenGL, and I'm trying to move an object using the mouse. I'm using OpenGL 4.4 Core Profile, MinGW32, freeGLUT, GLU, and GLEW, programming in C.
The program draw an hexagon with GL_LINE_LOOP and the color (0.5, 0.5, 0.5, 1.0).
The problem is when I move it using the mouse, the object is softly blinking, the color changes to a darker grey. The blinking also occurs when drawing with the color (1.0, 1.0, 1.0, 1.0), but it is less visible.
I tried to change the swap interval using wglSwapIntervalEXT(), but it accepts only values 0 and 1. I also tried to enable Triple Buffering and "wait for Vsync" parameter of my graphic card. Changing these three parameters doesn't solve the problem.
The code is very simple, the vertex shader takes an Uniform vector t that corresponds to the translation to apply to the object.
Vertex shader program:
#version 440 core
in vec3 vertex_position;
uniform vec3 vertex_color;
uniform vec4 t;
uniform mat4 matrix;
out vec4 color;
vec4 vp;
void main() {
color = vec4(vertex_color,1.0);
vp = matrix * vec4(vertex_position,1.0);
gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);
}
Fragment shader program:
#version 440 core
in vec4 color;
void main()
{
gl_FragColor = color;
}
The draw function is very simple, and I have a timer function that call glutPostRedisplay() every 16 ms, in order to have arround 60 FPS. I tried without the timer function, it increases the FPS, but the blinking even occurs.
The draw function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
The complete source code that shows the problem is here:
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
// coordinates of the hexagon:
GLfloat hexagon[18];
GLuint vao;
GLuint vbo;
// translations:
GLfloat tx = 0.0;
GLfloat ty = 0.0;
GLfloat tz = 0.0;
GLfloat tw = 0.0;
// window dimensions:
GLint width;
GLint height;
int window;
// coordinates of clicked point
int clicked_x;
int clicked_y;
// set to 1 if clicked down:
int clicked_down = 0;
/////////////////////////////////////////////////////////
//
// Shader programs for core profile:
//
const char * vsprog_core =
"#version 440 core\n"
"in vec3 vertex_position;\n"
"uniform vec3 vertex_color;\n"
"uniform vec4 t;\n"
"uniform mat4 matrix;\n"
" \n"
"out vec4 color;\n"
" \n"
"vec4 vp;\n"
" \n"
"void main() {\n"
" color = vec4(vertex_color,1.0);\n"
" vp = matrix * vec4(vertex_position,1.0);\n"
" gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);\n"
"}\n";
const char * fsprog_core =
"#version 440 core\n"
"in vec4 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = color;\n"
"}\n";
// uniforms locations:
GLint tloc;
GLint colorloc;
GLint matrixloc;
GLuint shader_program_core;
GLfloat PMVmatrix[16] = {
0.500000, 0.000000, 0.000000, 0.000000,
0.000000, 0.500000, 0.000000, 0.000000,
0.000000, 0.000000, 0.500000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000
};
void Draw()
{
int i,j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
//glutPostRedisplay();
}
void onMouseClick(int button, int state, int x, int y) {
if(state == GLUT_UP && button == GLUT_LEFT_BUTTON) clicked_down = 0;
if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) {
clicked_down = 1;
clicked_x = x;
clicked_y = y;
}
}
void onMouseMove(int x, int y) {
int i,j;
if(clicked_down == 1) {
// compute x coordinate of the clicked point from the clicked x pixel:
GLfloat x1 = (clicked_x)*2.0/width - 1.0;
// compute x coordinate of the actual point from the actual x pixel:
GLfloat x2 = (x)*2.0/width - 1.0;
// compute y coordinate of the clicked point from the clicked y pixel:
GLfloat y1 = (clicked_y)*2.0/height - 1.0;
// compute y coordinate of the actual point from the actual y pixel:
GLfloat y2 = (y)*2.0/height - 1.0;
tx += x2 - x1;
ty += y1 - y2;
// save actual coordinates as previous ones, for the next move:
clicked_x = x;
clicked_y = y;
}
}
void timer( int value )
{
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
int main( int argc, char *argv[ ], char *envp[ ] )
{
int i,j;
glutInitContextVersion(4, 4);
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE/* | GLUT_DEBUG*/);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640,480);
window = glutCreateWindow("Program");
//glutFullScreen();
width = glutGet(GLUT_WINDOW_WIDTH);
height = glutGet(GLUT_WINDOW_HEIGHT);
// get version info
const GLubyte* renderer;
const GLubyte* version;
///////////////////////////////////////////////////////////////////////
//
// start GLEW extension handler
//
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return(-1);
}
fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
// get version info
renderer = glGetString(GL_RENDERER); // get renderer string
version = glGetString(GL_VERSION); // version as a string
printf("\nRenderer: %s", renderer);
printf("\nOpenGL version supported %s", version);
fflush(stdout);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
//////////////////////////////////////////////////////////
//
// Shaders:
//
GLint params;
GLint len;
GLuint vscore = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vscore, 1, &vsprog_core, NULL);
glCompileShader(vscore);
glGetShaderiv(vscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(vscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
GLuint fscore = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fscore, 1, &fsprog_core, NULL);
glCompileShader(fscore);
glGetShaderiv(fscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(fscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
shader_program_core = glCreateProgram();
glAttachShader(shader_program_core, fscore);
glAttachShader(shader_program_core, vscore);
glLinkProgram(shader_program_core);
glGetProgramiv(shader_program_core,GL_LINK_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetProgramInfoLog(shader_program_core,100000,&len,log);
printf("\n\n%s\n\n",log);
fflush(stdout);
return(-1);
}
//
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
//
// Compute coordinates of the hexagon:
//
hexagon[0] = cos(0.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[1] = sin(0.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[2] = 0.0;
hexagon[3] = cos(1.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[4] = sin(1.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[5] = 0.0;
hexagon[6] = cos(2.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[7] = sin(2.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[8] = 0.0;
hexagon[9] = cos(3.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[10] = sin(3.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[11] = 0.0;
hexagon[12] = cos(4.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[13] = sin(4.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[14] = 0.0;
hexagon[15] = cos(5.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[16] = sin(5.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[17] = 0.0;
// VAO:
glGenVertexArrays(1, &(vao));
glBindVertexArray(vao);
// VBO:
glGenBuffers(1,&(vbo));
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), hexagon, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0*sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
// End VAO:
glBindVertexArray(0);
glutMouseFunc(onMouseClick);
glutMotionFunc(onMouseMove);
glutDisplayFunc(Draw);
glutTimerFunc(0,timer,0);
glutMainLoop();
return 0;
}
The shaders are defined in two char* constants. Left-clicking and moving the mouse allow to move the object.
From your description, my (wild) guess is you have texturing enabled but you're not providing any texture information.
So, just call glDisable(GL_TEXTURE_2D); before drawing your cube.
I am trying to adapt the code from a couple of the HLSL shaders in the WPF Pixel Shader Effects Library on Codeplex to create a pixel shader which creates a diagonal transition from Texture1 to Texture2 by sliding Texture2 across Texture1 as if it were overlaying (i.e. Texture1 remain "stationary" while Texture2 gradually replaces Texture1) from the upper left-hand corner.
I am struggling to properly understand the "uv" notation and how to manipulate it to achieve my goal.
So far I have tried
float Progress : register(C0);
sampler2D Texture1 : register(s0);
sampler2D Texture2 : register(s1);
struct VS_OUTPUT
{
float4 Position : POSITION;
float4 Color : COlOR;
float2 UV : TEXCOORD;
};
float4 SampleWithBorder(float4 border, sampler2D tex, float2 uv)
{
if (any(saturate(uv) - uv))
{
return border;
}
else
{
return tex2D(tex, uv);
}
}
float4 SlideDiagonal(float2 uv,float progress)
{
uv += progress;
float4 c1 = SampleWithBorder(float4(0,0,0,0), Texture2, uv);
if(c1.a <=0)
{
return tex2D(Texture1, uv);
}
return c1;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 main(VS_OUTPUT input) : COlOR
{
return SlideDiagonal(input.UV, Progress/100);
}
and also
float Progress : register(C0);
sampler2D Texture1 : register(s1);
sampler2D Texture2 : register(s0);
float4 SampleWithBorder(float4 border, sampler2D tex, float2 uv)
{
if (any(saturate(uv) - uv))
{
return border;
}
else
{
return tex2D(tex, uv);
}
}
float4 Shrink(float2 uv,float progress)
{
float speed = 200;
float2 center = float2(0.001, 0.001);
float2 toUV = uv - center;
float distanceFromCenter = length(toUV);
float2 normToUV = toUV / distanceFromCenter;
float2 newUV = center + normToUV * (distanceFromCenter *(progress*speed+1));
float4 c1 = SampleWithBorder(float4(0,0,0,0), Texture2, newUV);
if(c1.a <= 0)
{
return tex2D(Texture1, uv);
}
return c1;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 main(float2 uv : TEXCOORD) : COlOR
{
return Shrink(uv, Progress/100);
}
but in both cases the "slide" operates in reverse, reducing the amount of visible Texture2 as progress increases to 1 and, in the case of the former, Texture1 is not displayed at all.
I have come back to the problem a couple of times over Christmas to no avail and now I think I am suffering a "wood for the trees" problem.
If anyone knows the solution to this particular problem it would be greatly appreciated.
And in the spirit of "teaching a man to fish" if there was any information out there to help me understand how to manipulate "uv" that would also be great.
Many thanks in advance for your help
regards
Ian Carson
The texture coordinates (uv) specify where to look into the texture. With the line
uv += progress;
you shift the texture coordinate depending on the progress. If it is zero, the original coordinates are used (and the entire Texture2 is shown). By increasing progress, you go more and more to the bottom right corner of Texture2 and draw it at the original position. This lets the texture slide towards the top left corner. So if you want it the other way around, try:
uv += 1 - progress;
A big thank you to Nico for creating a clearing in the trees! His answer gave me the change of perspective I need to solve this problem. #Nico - Upvote for you, thanks mate.
For completeness I have included the final result from my Shazzam tinkerings which allows for a diagonal slide from any of the 4 corners using a float input called (imaginatively) "Corner". In production the float would be replaced by an int driven from an enumeration of possible corners - TopLeft, TopRight, BottomRight, BottomLeft. The order in the code is as shown represented by 1, 2, 3 & 4.
Here's the shader:
/// <summary>Modifies the Progress value.</summary>
/// <minValue>0</minValue>
/// <maxValue>100</maxValue>
/// <defaultValue>0</defaultValue>
float Progress : register(C0);
/// <summary>Modifies the Corner value.</summary>
/// <minValue>1</minValue>
/// <maxValue>1</maxValue>
/// <defaultValue>1</defaultValue>
float Corner : register(C1);
sampler2D Texture1 : register(s0);
sampler2D Texture2 : register(s1);
float4 SampleWithBorder(float4 border, sampler2D tex, float2 uv, float corner)
{
if (any(saturate(uv) - uv))
{
return border;
}
else
{
float2 rev = uv;
//Swap y position again to counteract the inversion caused by
//needing to get to get to corners BottomLeft and TopRight
if(corner >=2 && corner < 3 || corner>=4
{
rev.y = 1 - rev.y;
}
return tex2D(tex, rev);
}
}
float4 SlideDiagonal(float2 uv, float progress, float corner)
{
float2 rev = uv;
//Swap y position to get to corners BottomLeft and TopRight
if(corner >=2 && corner < 3 || corner>=4)
{
rev.y = 1 - rev.y;
}
float2 newUV;
//TopLeft
if(corner >= 1 && corner < 2)
{
newUV = rev + (1- progress);
}
//TopRight
if(corner >= 2 && corner < 3)
{
newUV = rev - (1- progress);
}
//BottomRight
if(corner >= 3 && corner < 4)
{
newUV = rev - (1- progress);
}
//BottomLeft
if(corner >= 4)
{
newUV = rev + (1- progress);
}
float4 c1 = SampleWithBorder(float4(0,0,0,0), Texture2, newUV, corner);
if(c1.a <=0)
{
return tex2D(Texture1, uv);
}
return c1;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 main(float2 input : TEXCOORD) : COlOR
{
return SlideDiagonal(input, Progress/100, Corner);
}
I am attempting to tessellate a a sphere, but when I apply the tessellation shaders nothing shows up on screen. After reading quite a bit of literature on this and going through some questions here, I am still unable to figure out what is wrong. There are no errors when linking or loading the shaders either so I am somewhat at a loss.
The shader and drawing code is below.
Thanks.
Vertex
#version 410
in vec4 vPosition;
out vec3 Position;
void main()
{
Position = vPosition.xyz;
}
Control
#version 410
layout(vertices = 3) out;
in vec3 Position[];
out vec3 tcPosition[];
#define ID gl_InvocationID
void main()
{
tcPosition[ID] = Position[ID];
if(ID == 0) {
gl_TessLevelInner[0] = 3.0;
gl_TessLevelOuter[0] = 2.0;
gl_TessLevelOuter[1] = 2.0;
gl_TessLevelOuter[2] = 2.0;
}
}
Evaluation
#version 410
layout(triangles, equal_spacing, ccw) in;
in vec3 tcPosition[];
out vec3 tePosition;
uniform mat4 projection;
uniform mat4 Modelview;
void main()
{
vec3 p0 = gl_TessCoord.x * tcPosition[0];
vec3 p1 = gl_TessCoord.y * tcPosition[1];
vec3 p2 = gl_TessCoord.z * tcPosition[2];
vec3 tePosition = p0 + p1 + p2;
gl_Position = vec4(tePosition, 1.0);
}
Fragment
#version 410
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
Draw Code
glPatchParameteri(GL_PATCH_VERTICES, 3);
glDrawArrays( GL_PATCHES, 0, sphere.vertexNumber );
I am trying to pass a large amount of information to my fragment shader but I always reach a limit (too many textures binded, texture too large, etc., array too large, etc.). I use a ThreeJS custom shader.
I have a 256*256*256 rgba volume that I want to pass to my shader.
In my shader, I want to map the fragments's world position to a voxel in this 256*256*256 volume.
Is there a good strategy to deal with this amount of information? Which would be the best pratice? Is there any good workaround?
My current approach is to generate 4 different 2048x2048 rgba texture containing all the data I need.
To create each 2048x2048 texture, I just push every row of every slice sequencially to a big array and split this array in 2048x2048x4 chuncks, which are my textures:
var _imageRGBA = new Uint8Array(_dims[2] *_dims[1] * _dims[0] * 4);
for (_k = 0; _k < _dims[2]; _k++) {
for (_j = 0; _j < _dims[1]; _j++) {
for (_i = 0; _i < _dims[0]; _i++) {
_imageRGBA[4*_i + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = _imageRGBA[4*_i + 1 + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = _imageRGBA[4*_i + 2 + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = _imageN[_k][_j][_i];//255 * i / (_dims[2] *_dims[1] * _dims[0]);
_imageRGBA[4*_i + 3 + 4*_dims[0]*_j + 4*_dims[1]*_dims[0]*_k] = 255;
}
}
}
Each texture looks something like that:
On the shader side, I try to map a fragment's worldposition to an actual color from the texture:
Vertex shader:
uniform mat4 rastoijk;
varying vec4 vPos;
varying vec2 vUv;
void main() {
vPos = modelMatrix * vec4(position, 1.0 );
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
}
</script>
Fragment shader:
<script id="fragShader" type="shader">
vec4 getIJKValue( sampler2D tex0, sampler2D tex1, sampler2D tex2, sampler2D tex3, vec3 ijkCoordinates, vec3 ijkDimensions) {
// IJK coord to texture
float textureSize = 2048.0;
float index = ijkCoordinates[0] + ijkCoordinates[1]*ijkDimensions[0] + ijkCoordinates[2]*ijkDimensions[0]*ijkDimensions[1];
// map index to right 2048 x 2048 slice
float sliceIndex = floor(index / (textureSize*textureSize));
float inTextureIndex = mod(index, textureSize*textureSize);
// get row in the texture
float rowIndex = floor(inTextureIndex/textureSize);
float colIndex = mod(inTextureIndex, textureSize);
// map indices to u/v
float u = colIndex/textureSize;
float v =1.0 - rowIndex/textureSize;
vec2 uv = vec2(u,v);
vec4 ijkValue = vec4(0, 0, 0, 0);
if(sliceIndex == float(0)){
ijkValue = texture2D(tex0, uv);
}
else if(sliceIndex == float(1)){
ijkValue = texture2D(tex1, uv);
}
else if(sliceIndex == float(2)){
ijkValue = texture2D(tex2, uv);
}
else if(sliceIndex == float(3)){
ijkValue = texture2D(tex3, uv);
}
return ijkValue;
}
uniform mat4 rastoijk;
uniform sampler2D ijk00;
uniform sampler2D ijk01;
uniform sampler2D ijk02;
uniform sampler2D ijk03;
uniform vec3 ijkDimensions;
varying vec4 vPos;
varying vec2 vUv;
void main(void) {
// get IJK coordinates of current element
vec4 ijkPos = rastoijk * vPos;
// show whole texture in the back...
vec3 color = texture2D(ijk00, vUv).rgb;
//convert IJK coordinates to texture coordinates
if(int(floor(ijkPos[0])) > 0
&& int(floor(ijkPos[1])) > 0
&& int(floor(ijkPos[2])) > 0
&& int(floor(ijkPos[0])) < int(ijkDimensions[0])
&& int(floor(ijkPos[1])) < int(ijkDimensions[1])
&& int(floor(ijkPos[2])) < int(ijkDimensions[2])){
// try to map IJK to value...
vec3 ijkCoordinates = vec3(floor(ijkPos[0]), floor(ijkPos[1]), floor(ijkPos[2]));
vec4 ijkValue = getIJKValue(ijk00, ijk01, ijk02, ijk03, ijkCoordinates, ijkDimensions);
color = ijkValue.rgb;
}
gl_FragColor = vec4(color, 1.0);
// or discard if not in IJK bounding box...
}
</script>
That doesn't work well. I now get an image with weird artifacts (nyquist shannon effect?). As I zoom in, the image appears. (even though not perfect, some black dots)
Any help advices would be greatly appreciated. I also plan to do some raycasting for volume rendering using this approach (very needed in the medical field)
Best,
The approach to handle large arrays using multiple textures was fine.
The issue was how I was generating the texture with THREE.js.
The texture was generated using the default linear interpolation: http://threejs.org/docs/#Reference/Textures/DataTexture
What I needed was nearest neighboor interpolation. This was, the texture is still pixelated and we can access the real IJK value (not an interpolated value)
Found it there: http://www.html5gamedevs.com/topic/8109-threejs-custom-shader-creates-weird-artifacts-space-between-faces/
texture = new THREE.DataTexture( textureData, tSize, tSize, THREE.RGBAFormat, THREE.UnsignedByteType, THREE.UVMapping,
THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.NearestFilter );
Thanks
I have some code that draws squares by passing points through a geometry shader. I construct an array which is sequences of 3 floats, bind that to the in vec3 vert attribute of my vertex shader, and everything is fine.
However, I want to add another float which the fragment shader will use to calculate color. This is in the vertex shader (to pass through) as in float val. Despite being able to find vert, glGetAttribLocation can't find val (get_program_attrib(): Atrrib val not found (-1)).
Code:
void load_model(GLuint* vao, GLuint* vbo) {
glGenVertexArrays(1, vao);
glBindVertexArray(*vao);
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
float data[SQUARES_PER_AXIS_SQ * 4] = {0};
squares_count = 0;
for (int i = 0; i < SQUARES_PER_AXIS_SQ; i++) {
int x_pos = i % SQUARES_PER_AXIS;
int y_pos = i / SQUARES_PER_AXIS;
if (fabs(squares[i]) > 0.0) {
data[squares_count * 4 + 0] = x_pos / ((float)SQUARES_PER_AXIS) * 2 - 1;
data[squares_count * 4 + 1] = (SQUARES_PER_AXIS - y_pos) / ((float)SQUARES_PER_AXIS) * 2 - 1;
data[squares_count * 4 + 2] = 0.5f;
data[squares_count * 4 + 3] = (float)squares[i];
squares_count++;
}
}
DPRINT("Loaded %d squares\n", squares_count);
glBufferData(GL_ARRAY_BUFFER, squares_count * 4 * sizeof(float), data, GL_STATIC_DRAW);
glEnableVertexAttribArray(get_program_attrib(main_shader, "vert"));
glEnableVertexAttribArray(get_program_attrib(main_shader, "val"));
glVertexAttribPointer(get_program_attrib(main_shader, "vert"), 3, GL_FLOAT, GL_FALSE, 4, NULL);
glVertexAttribPointer(get_program_attrib(main_shader, "val"), 1, GL_FLOAT, GL_FALSE, 4, (float*)(3 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
GLuint get_program_attrib(program_t* prog, GLchar* name) {
if (!name) {
DPRINT("ERROR: name == NULL\n");
return -1;
}
GLint attrib = glGetAttribLocation(prog->id, name);
if (attrib < 0)
DPRINT("Atrrib %s not found (%d)\n", name, attrib);
return attrib;
}
Vertex shader:
#version 150
in vec3 vert;
in float val;
out float value;
void main() {
gl_Position = vec4(vert, 1);
value = val;
}
Fragment shader:
#version 150
in float value;
out vec4 color;
void main() {
color = vec4(value, 0, 0, 1);
}
Geometry shader:
#version 150
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
uniform float square_size;
void main() {
vec4 position = gl_in[0].gl_Position;
gl_Position = vec4(position.x, position.y, position.zw);
EmitVertex();
gl_Position = vec4(position.x, position.y + square_size, position.zw);
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y, position.zw);
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y + square_size, position.zw);
EmitVertex();
EndPrimitive();
}
Vertex shader outputs are not passed directly to the fragment shader when you have a geometry shader.
It is this that is causing all of your problems. For a vertex attribute to be active, it has to contribute to the final output of your program. Basically that means something calculated in the fragment shader has to be based off of it.
Unfortunately, that is not happening right now. You have a variable called value that is output from your vertex shader and a variable called value that is input by your fragment shader. Because the geometry shader sits inbetween the two of them, the fragment shader only looks for an output named value in the geometry shader -- no such output exists.
Naturally you might think that the solution would be to create a variable called value in the geometry shader that serves as the input and the output. However, that will not work, you would have to declare it inout value and that is invalid.
Here are the necessary corrections:
Vertex shader:
#version 150
in vec3 vert;
in float val;
out float value_vtx; // Output is fed to the Geometry Shader
void main() {
gl_Position = vec4(vert, 1);
value_vtx = val;
}
Fragment shader:
#version 150
in float value_geo; // Takes its input from the Geometry Shader
out vec4 color;
void main() {
color = vec4(value_geo, 0, 0, 1);
}
Geometry shader:
#version 150
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
uniform float square_size;
in float value_vtx []; // This was output by the vertex shader
out float value_geo; // This will be the input to the fragment shader
void main() {
vec4 position = gl_in[0].gl_Position;
gl_Position = vec4(position.x, position.y, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x, position.y + square_size, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y + square_size, position.zw);
value_geo = value_vtx[0];
EmitVertex();
EndPrimitive();
}
You may be asking why I assigned value_geo 4 times when it is constant. That is because EmitVertex (...) causes all output variables to become undefined when it returns, so you have to set it every time.