![]() |
|
Shader Problems - GLSL sampler3d() - 5.1.9 |
thebignic
Member #14,419
July 2012
|
Before I spend any more time bashing my head against a wall... I'm trying to bind a texture to a sampler3D object and I'm assuming that I can't use al_set_shader_sampler() because that would bind a 2D sampler. (Or am I missing something?) So I'm trying to bind it manually but having trouble sorting out how to get the program ID out of the ALLEGRO_SHADER so I can glGetUniformLocation() and manually bind. Other than setting up the shader manually myself (which I can do, just wanted to try using allegros built-in stuff as much as possible this time around) Whats the most graceful way to get the program ID of a shader? (I know this will be openGL specific, and I'll have to write a separate routine for DX but I'll get to that later.) ALLEGRO_SHADER_GLSL_S does not appear to be exposed, so I can't really cast to that and get the program id out there. (Trying to define ALLEGRO_SHADER_GLSL_S and all its nested internal types seems really messy...) Recommendations? Only reason I'm able to use 5.1.9 is because of Reynoldo sharing the binaries - I have only successfully built Allegro ONCE, adn it was on OSX and ... frankly... I don't have it in me to build Allegro from scratch just to add an al_set_shader_sampler3d() for myself... if thats whats necessary, then fine. But yeah... I'm lazy. I've got so much past trauma trying to build Allegro (and other libraries) that I'm paralyzed there
|
RPG Hacker
Member #12,492
January 2011
![]() |
No simple way, as far as I can tell. You could try the following, though: 1. Include the header "allegro5\internal\aintern_shader.h" so that you get the definition of ALLEGRO_SHADER. 2. Get your shader pointer and cast it to an unsigned char pointer, so that you can do simple byte-length pointer arithmetic. 3. Add sizeof(ALLEGRO_SHADER) to this pointer. 4. Add ((sizeof(GLuint) * 2) to this pointer 5. Cast this pointer to a GLuint pointer If everything worked as expected, this GLuint pointer should now point to the memory holding the program ID. Note that this might not work at all. Like, if ALLEGRO_SHADER_GLSL_S happens not to be a tightly packed struct, this method will fail. Even if it doesn't fail, note that this is a highly platform-specific solution, becaues different compilers might pack structs differently (even the same compiler could pack structs differently depending on whether you're doing a 32- or a 64-bit build). If you go with this method, make sure to thoroughly test the outcome on all platforms you're interested in. The foolproof version would be to either build a GL shader yourself or build the Allegro library, though.
|
thebignic
Member #14,419
July 2012
|
This seems relevant: GLuint al_get_opengl_program_object(ALLEGRO_SHADER *shader) I dont see any documentation, but it seems straight forward. It would be nice if the documentation mentioned it - it would have saved me a full day of head banging. Also, the documentation isnt clear to me that when using al_use_shader(NULL), how that might affect subsequent calls. It seems that as soon as I al_use_shader(NULL), no subsequent calls to al_use_shader() seem to work? The program continues to use the default shader from that point on, despite being toggled between the shader I created and the default? EDIT: aactually when I used al_use_shader() on any two shaders (even if I manually load a default shader) it doesn't work after the second call. Wtf am I doing wrong? I can see the screen blink with the correct shader for one draw call, but after I toggle to another shader it stops working (and seems to be using default only.)>:(>:( EDIT #2: does al_set_target_bitmap() change the shader being used?!?!?!?!?!?
|
Mark Oates
Member #1,146
March 2001
![]() |
Hey thebicnic, Good news is you can do it, I've used essentially the exact same process you describe to add a GL_TEXTURE_CUBE_MAP / sampler_cube and extending it to sampler3d should be very similar. There are a few critical things: 1) You should upgrade to the latest version of Allegro 5.1.13. It has al_get_opengl_program_object() which was literally just added in this version. Here's the change log. Building and/or getting Allegro since 5.1.9 has been made quite a bit easier than Previous versions, across all platforms. Shader API has also improved. 2) Always reference the latest documentation from the official Allegro 5 repo. It's the most up to date. The manuals on allegro.cc are out of date - don't use them. 3) To add anything OpenGL specific to Allegro 5 you just need to #include <allegro5/allegro_opengl.h> (and link the opengl libraries to build). 4) Here is how I implemented adding GL_TEXTURE_CUBE_MAP and sampler_cube: thebignic said: Also, the documentation isnt clear to me that when using al_use_shader(NULL), how that might affect subsequent calls.
Quote: EDIT #2: does al_set_target_bitmap() change the shader being used?!?!?!?!?!? Shaders are relatively-ish new. Their behavior is a little undocumented and you will find some peculiarities, for example with al_set_target_bitmap() which stores/flushes/resets some state, including projection. That is, for example, each bitmap has its own projection transform. Also, when using al_draw_bitmap(), al_draw_prim(), and friends, Allegro binds the first texture TEXTURE0 to the ALLEGRO_BITMAP that you pass into those functions (or does nothing if you pass NULL). Allegro could really benefit from a great shader tutorial since the exact bounds of these behaviors is still yet to be outlined in the docs. They're completely usable, however. -- |
RPG Hacker
Member #12,492
January 2011
![]() |
Mark Oates said: which was literally just added in this version Welp, no wonder I didn't find it while scanning the headers of Allegro on my PC. That was actually my first idea, I thought "maybe the allegro_opengl.h header already has a getter for the program index", but I think I have version 5.1.10 on my system, so naturally, I didn't find anything like that. Feel stupid for my last, rather hacky, post now.
|
thebignic
Member #14,419
July 2012
|
Ok, so I'm on 5.1.13 and I can get the program ID now. Running into issues with texture3d() / glTexImage3D() now. Does anyone have a working code snippet of generating/binding a 3D texture buffer? I can't imagine its all that different from 2D and the (very few) examples I've seen of glTexImage3D() appear to be very similar (to each other, and to what I have.) Marks cube map is interesting and I don't see anything that is being done there that I'm not doing (albeit for texture3d) in my own code. It seems like no matter what my data is (all bytes = 0 or all bytes = 255) I cant read anything sensible in the shader using texture3d() (ie: from vec(1,1,1) or vec(0,0,0) or vec (0.5,0.5,0.5) texture3d() is still returning color values like (0.1,0.9,0.1) when I've uploaded a buffer full of zeros? I'm still grabbing glGetError after every single GL call and nothing is throwing an error with the shader compile/link or attaching the texture to a uniform at draw time. I'm totally stumped. Day #2 .... EDIT: Well.. moments after I posted this, of course, I discovered that I was passing a reference of a pointer to glTexImage3D() so.. yeah... don't do that. ... I still blame OpenGL for my basic C++ snafu
|
Mark Oates
Member #1,146
March 2001
![]() |
What is a texture3d? Like, what would you use it for? Serious question. Another thing to keep in mind that could be a bit strange is that Allegro texture coordinates are [0-bitmap_width], [0-bitmap_height]. This is different from the usual [0-1], [0-1] texture coordinates that you get with UV textures. Because of that, in the shader you might use al_use_tex_matrix and multiply the incoming texture coordinates by al_tex_matrix. That may have an affect on the appearance of your texture3d. You could be getting textures that are only drawing in the top left pixel (0,0) You can also create a custom vertex which may make more sense for 3D and textures. My vertex definition uses [0-1],[0-1] for texture coordinates and also includes a vertex normal. Here's what it looks like. But that may or may not be related to your actual problem. -- |
thebignic
Member #14,419
July 2012
|
Mark said: What is a texture3d? Like, what would you use it for? Serious question. Color correction look-up table (LUT) Other than that, it appears to be used for volumetric rendering (clouds, water?) and maybe voxel rendering but thats all way above my head!
|
Mark Oates
Member #1,146
March 2001
![]() |
thebignic said: Color correction look-up table (LUT) I have no idea how that works. It sounds cool, though. I'd be totally into hearing about your implementation. -- |
thebignic
Member #14,419
July 2012
|
Here's a brief overview of my current color correction lookup table solution. I just learned about the possibility of doing this last week, so I am by no means an expert. I just thought I'd share cause there doesn't seem to be any reasonably complete examples anywhere, let alone any that use Allegro. While this may have a few pieces missing, I think all of the heavy lifting is documented... If I left something important out, let me know. I'm no artist, but see attachments for examples of what a LUT can do to transform an image in real time, with no other processing. ("lut-natural" is the way the game draws without any color correction) Also see attachments for a neutral LUT (RGBTable16x1.png) that you can use to build your own. How it works...
To make a LUT, just draw your game as you normally would, screenshot, take it into Photoshop and paste a neutral LUT into a corner somewhere. Then modify the colours, saturation, hue, contrast, etc until the image looks how you want. This "look up table" basically contains every colour that you can draw, in a 3D cube, and corrected using the rules we used to modify the colours in Photoshop. When you draw a pixel with a shader, all the colour correction shader will do is use the source colour as a position in the LUT cube and see what the new colour should be based on the LUT image we loaded up. 16x16x16 colours is enough to do a decent linear interpolation for my needs but you may want to go to 32x32x32 if you're into that sort of thing. The Code... buildLut() will take an image (ie: the PNG we created above) and then load it into a GL_TEXTURE_3D array so that we can use Sampler3D in our shader. We can use Allegro to build the shaders as long as we can get the OpenGL ID later with al_get_opengl_program_object() so it'll require the latest version of Allegro to do it that way. We can't use Allegro to bind the 3D texture to the shader though, so EnableLUTDrawing() To draw using a lookup table, just enable the LUT shader with a specified table ID 1
2al_set_target_bitmap(tempBitmap);
3
4[... draw your game using default shader ... ]
5
6al_set_target_bitmap(al_get_backbuffer(displayManager.display));
7
8shaderManager.EnableLUTDrawing( LUT_ARENA01_DUSK );
9
10al_draw_bitmap(tempBitmap, 0,0,0);
11
12al_flip_display();
PIXEL SHADER (Colour Correction)
1#ifdef GL_ES
2precision mediump float;
3#endif
4uniform sampler2D al_tex;
5uniform sampler3D ColorGradingLUT;
6
7uniform bool al_use_tex;
8varying vec4 varying_color;
9varying vec2 varying_texcoord;
10
11
12const float lutSize = 16.0;
13const vec3 scale = vec3((lutSize - 1.0) / lutSize);
14const vec3 offset = vec3(1.0 / (2.0 * lutSize));
15
16void main()
17{
18 if (al_use_tex) {
19
20 vec4 rawColor = varying_color * texture2D(al_tex, varying_texcoord);
21 vec4 lutSample = texture3D(ColorGradingLUT, scale * texture2D(al_tex, varying_texcoord).rgb + offset);
22
23 gl_FragColor.a = texture2D(al_tex, varying_texcoord).a;
24 if (gl_FragColor.a < 0.001) {
25 gl_FragColor.g=0;
26 gl_FragColor.r=0;
27 gl_FragColor.b=0;
28 gl_FragColor.a=0;
29 }
30
31 } else {
32 gl_FragColor = varying_color;
33 }
34}
VERTEX SHADER (DEFAULT)
1attribute vec4 al_pos;
2attribute vec4 al_color;
3attribute vec2 al_texcoord;
4uniform mat4 al_projview_matrix;
5uniform bool al_use_tex_matrix;
6uniform mat4 al_tex_matrix;
7varying vec4 varying_color;
8varying vec2 varying_texcoord;
9void main()
10{
11 varying_color = al_color;
12 if (al_use_tex_matrix) {
13 vec4 uv = al_tex_matrix * vec4(al_texcoord, 0, 1);
14 varying_texcoord = vec2(uv.x, uv.y);
15 }
16 else
17 varying_texcoord = al_texcoord;
18 gl_Position = al_projview_matrix * al_pos;
19}
Shader Manager (partial)
1
2static const int MAX_LUTS = 3;
3enum LUTList {
4 LUT_01_DAY
5 ,LUT_01_DUSK
6 ,LUT_01_NIGHT
7};
8
9///point to a single LUT image
10static const std::string LUTStrings[] = {
11 "LUT_01_day.png"
12 ,"LUT_01_dusk.png"
13 ,"LUT_01_evening.png"
14};
1
2
3 ALLEGRO_BITMAP *bmpLUT[MAX_LUTS];
4 GLuint bmpLUT_GL[MAX_LUTS];
5
6 ALLEGRO_SHADER *default_shader;
7 ALLEGRO_SHADER *LUT_shader;
8 GLuint LUT_shader_GL;
9 GLuint default_shader_GL;
10
11
12void ShaderManager::EnableLUTDrawing(int LUTID) {
13
14 al_use_shader(LUT_shader);
15
16 GLenum err;
17
18 glActiveTexture(GL_TEXTURE1);
19 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glActiveTexture(); ERROR: " << err << "\n";
20
21 GLint handle = glGetUniformLocation(LUT_shader_GL, "ColorGradingLUT");
22 if (handle < 0) std::cout << " No uniform variable found -- handle: " << handle << "\n";
23 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glGetUniformLocation(); ERROR: " << err << "\n";
24
25 GLuint texture = bmpLUT_GL[LUTID];
26
27 glBindTexture(GL_TEXTURE_3D, texture);
28 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glBindTexture(); ERROR: " << err << "\n";
29
30 glUniform1i(handle, 1);
31 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glUniform1i(); ERROR: " << err << "\n";
32
33}
34
35///given a bitmap, build a GL_TEXTURE_3D object and bind it
36GLuint ShaderManager::buildLut(ALLEGRO_BITMAP * lutBMP) {
37
38 if (!lutBMP) return -1;
39
40 std::cout << " generating 3d lut image from bitmap...\n";
41
42 ALLEGRO_LOCKED_REGION *bmpLock= al_lock_bitmap(lutBMP, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY );
43
44 GLuint glID;
45
46 GLenum err;
47
48 GLubyte * pixels;
49 pixels = new GLubyte [ 16 * 16 * 16 * 3 ]; ///LUT size is 16x16x16 and only contains RGB elements (no alpha)
50 long i=0;
51 for (int z = 0; z <16; z++) {
52 for (int y = 0; y < 16; y++) {
53 for (int x = 0; x < 16; x++) {
54 ///neutral
55 //pixels[i + 0] = util.unlerp(0,15,z) * 255; // blue
56 //pixels[i + 1] = util.unlerp(0,15,y) * 255; // green
57 //pixels[i + 2] = util.unlerp(0,15,x) * 255; // red
58
59 ///sample bitmap
60 int x2d = x + (z * 16);
61 int y2d = y;
62 ALLEGRO_COLOR c = al_get_pixel(lutBMP, x2d, y2d);
63 pixels[i + 2] = c.b * 255; // blue
64 pixels[i + 1] = c.g * 255; // green
65 pixels[i + 0] = c.r * 255; // red
66
67 i=i+3;
68 }
69 }
70 }
71 al_unlock_bitmap(lutBMP);
72
73 glEnable(GL_TEXTURE_3D);
74 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glEnable(); ERROR: " << err<< "\n";
75
76 glActiveTexture(GL_TEXTURE1);
77 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glActiveTexture(); ERROR: " << err << "\n";
78
79 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
80 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glPixelStorei(); ERROR: " << err << "\n";
81
82 glGenTextures(1, &glID);
83 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glGenTextures(); ERROR: " << err << "\n";
84
85 glBindTexture(GL_TEXTURE_3D, glID);
86 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glBindTexture(); ERROR: " << err << "\n";
87
88 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ///required for trilinear filtering which we NEED
89 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
90 //glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
91 //glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
92 //glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
93
94 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glTexParameteri(); ERROR: " << err << "\n";
95
96 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB8, 16, 16, 16, 0, GL_RGB,GL_UNSIGNED_BYTE, pixels);
97 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glTexImage3D(); ERROR: " << err << "\n";
98
99 glDisable(GL_TEXTURE_3D);
100 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glDisable(); ERROR: " << err << "\n";
101
102 glActiveTexture(GL_TEXTURE0);
103 err=glGetError(); if ( err != GL_NO_ERROR) std::cout << " glActiveTexture(); ERROR: " << err << "\n";
104
105
106
107 delete [] pixels;
108 pixels = NULL;
109
110 std::cout << "glID=" << glID << "\n";
111
112 return glID;
113
114}
115
116void ShaderManager::loadShaders()
117{
118
119 std::cout << "\n\n\nloadShaders()\n";
120
121 default_shader = al_loadShaderFromFile("PIXEL.txt", "VERTEX.txt");
122 default_shader_GL = al_get_opengl_program_object(default_shader);
123
124 LUT_shader = al_loadShaderFromFile("PIXEL_COLOUR_CORRECT.txt", "VERTEX.txt");
125 LUT_shader_GL = al_get_opengl_program_object(LUT_shader);
126
127
128 std::cout << " loading / building LUTS...\n";
129
130 for (int i=0; i<MAX_LUTS; i++) {
131 bmpLUT[i] = al_load_bitmap( LUTStrings[i].c_str() );
132 if(!bmpLUT[i])
133 {
134 std::cout << "image file open error: " << LUTStrings[i] << "\n";
135 return;
136 }
137
138 bmpLUT_GL[i] = buildLut( bmpLUT[i]);
139 if (bmpLUT_GL[i] <1) std::cout << "ERROR: " << bmpLUT[i] << " handle returned=" << bmpLUT_GL[i] << "\n";
140
141 }
142
143
144
145
146
147}
148
149
150
151ALLEGRO_SHADER * ShaderManager::al_loadShaderFromFile(std::string fragment, std::string vertex){
152
153 ALLEGRO_SHADER * shadey;
154
155 shadey = al_create_shader(ALLEGRO_SHADER_GLSL);
156 if (!shadey) {
157 std::cout << "Could not create shader.\n";
158 }
159
160 if (!al_attach_shader_source_file(shadey, ALLEGRO_VERTEX_SHADER, vertex.c_str())) {
161 std::cout << "al_attach_shader_source_file failed:" << al_get_shader_log(shadey) << "\n";
162 }
163 if (!al_attach_shader_source_file(shadey, ALLEGRO_PIXEL_SHADER, fragment.c_str())) {
164 std::cout << "al_attach_shader_source_file failed: " << al_get_shader_log(shadey) << "\n";
165 }
166
167 if (!al_build_shader(shadey)) {
168 std::cout << "al_build_shader failed:" << al_get_shader_log(shadey) << "\n";
169 } else {
170 std::cout << "shader build succeeded: " << al_get_shader_log(shadey) << "\n";
171 }
172
173 std::cout << "gl program: " << al_get_opengl_program_object(shadey) << "\n";
174
175 return shadey;
176
177}
|
Mark Oates
Member #1,146
March 2001
![]() |
That's cool. So it's like a giant lookup table that's values are interpolated, similar to how 2D texture's pixel values are interpolated. The only thing I can relate "3D texture" to is like, procedurally generated textures like wood that have different values based on XYZ. {"name":"610198","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/7\/27ba756e6a1e7670b4a70ceab8b87fcd.jpg","w":1100,"h":499,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/7\/27ba756e6a1e7670b4a70ceab8b87fcd"} -- |
|