PDA

View Full Version : Text in WebGL



Phinehas
09-19-2010, 09:08 PM
Hi.

I'm trying to model a simple cube and want to add some information (such as the x,y coordinates) into the cube. Is there any methods to do it?

SteveBaker
10-13-2010, 08:18 PM
See my reply to this thread:

viewtopic.php?f=9&t=3185 (http://www.khronos.org/message_boards/viewtopic.php?f=9&t=3185)

huttarl
10-22-2010, 02:20 PM
See my reply to this thread:
viewtopic.php?f=9&t=3185 (http://www.khronos.org/message_boards/viewtopic.php?f=9&t=3185)
Steve, in that thread, you write:


There is no API in OpenGL (or OpenGLES) for drawing text. You either do that outside of the API (maybe using some other operating-system commands) - or you write your own font rendering stuff.For what I'm after, and it sounds like what Phinehas is after, the goal is being able to debug/trace what your shader code is doing. So you have to either get information back out of the GPU to the controlling program (is that possible?), or else do font rendering within the GPU.

So regarding font rendering, you write

On systems with decent shader support, I've been experimenting with a technique where I send the strings I need down to the GPU as a texture map with one texel per character (containing the ASCII code) and use fragment shader code to convert use that value as the coordinate for looking up the font texture - amazingly, it actually works pretty well. For text that only changes slowly (so you aren't continually reloading the texture) that can be blindingly efficient. However, the shader to do that is a pain to get right!That sounds like it would be very very useful for people like us who are trying to "see" what's happening to the values of variables in our shader code. Or can these techniques not be driven from within a shader? Are you willing to post an example of how you've done this?

That would be great...

Thanks,
Lars

huttarl
10-22-2010, 02:44 PM
P.S. I just saw that you have a house in Cedar Hill. Howdy neighbor! from Duncanville.

Phinehas
01-04-2011, 08:32 PM
See my reply to this thread:

viewtopic.php?f=9&t=3185 (http://www.khronos.org/message_boards/viewtopic.php?f=9&t=3185)

Hi SteveBaker,

I'm doing a project (Web Application) drawing some mathematical diagrams using WebGL. I want to draw the length of the line next to the line and the angle between two lines/planes in WebGL. Is there any efficient method to draw it? :(

wglb
01-05-2011, 07:17 AM
You could use another canvas for creating dynamic texture with text (displaying lines length) and then display f.e. textured (there is ability to use canvas as a texture source) rectangles next to the lines

SteveBaker
01-05-2011, 08:03 AM
Sorry, I can't share any actual shader code with you - but here is the general approach:

1) You need two texture maps - let's call them "FONT" and "STRING".
2) The "FONT" texture is a long, thin map (in my case, it was a 2048 x 32 monochrome map) which has all of the characters you want to draw in it. In my case, I wanted the 94 ASCII characters from space to '~'. Hence each character occupies a little patch of texture that's 21 pixels wide by 32 high...and there is a little wasted space at the end of the texture. I used MIPmapping and clamp-to-edge modes for this map.
3) The "STRING" texture is another 8 bit monochrome map that has one ASCII character in each "pixel". If you only have 4 bit textures - you'll need a color map so you can pack the low order 4 bits of the ASCII code into (say) Red and the high order 4 bits into Green. This map must be set to point-sampling and clamp-to-edge. Your application fills up this map with the ASCII codes of the strings it wants to render and uses the texture rectangle load command to write any parts that changed once per frame.
4) The vertex shader just transforms the polygon however you want to get it to the right place on the screen.
5) The fragment shader takes a "uniform vec2 Start" which is the start of the ASCII string of your message in the STRING texture and a "uniform vec4 Background" and "uniform vec4 Foreground" which are the RGBA colors of the text and its background.
6) When you want to render a string, you set up the appropriate shader uniforms for whichever message you want to display and draw a polygon whose texture coordinates run from zero to one vertically - and from zero to the number of characters you need to draw horizontally.
7) The shader adds the 'floor' of the texture 'x' coordinate to 'Start.x' and then divides 'Start.xy' by the vec2(width,height) of the STRING texture in pixels. That gives you the coordinate to look up the STRING texture in order to extract the ASCII code of the character you're going to render.
8) Now, you subtract 32 from that ASCII code and multiply it by 21/2048 (ie the width of one character in your FONT map) and add on the fractional part of the texture 'x' coordinate. That, along with the texture 'y' coordinate can now be used to look up the texel in the FONT map.
9) You can use the value you read from the font map to mix the Foreground and Background colors/alpha's - but there is a "gotcha". When you go from one letter in the string to the next, the final texture coordinates used to index into the FONT map jump suddenly from one part of the map to another - which really confuses the MIPmapper. If you do nothing, you'll get thin sparkly lines between the characters in your final output. The pragmatic way to "fix" that is to note that for most fonts, there is more background color than foreground - so the average grey shade is less than 50% and you can just say "treat any font brightness value that's less than 50% as background" - but that makes antialiassing of the font look pretty terrible. If you don't need really tiny point sizes, you can fix the problem by simply turning off MIPmapping on the FONT map. If your shader-foo is strong, you can use 'ddx/ddy' to solve it - but those aren't available in WebGL/OpenGL-ES - so that won't work here.

Anyway - this sounds really complicated - but it's not too terrible in practice. The result is pretty cool - you can render any ASCII string of any length by drawing a single rectangle!

If your strings are all pre-defined - then you can make the STRINGS texture one-time and load it just like any other texture - but if they are dynamic, then you have to update it whenever a string that you're displaying changes.

-- Steve.

Phinehas
01-09-2011, 11:54 PM
You could use another canvas for creating dynamic texture with text (displaying lines length) and then display f.e. textured (there is ability to use canvas as a texture source) rectangles next to the lines


Now, I'm using this method to show the text. However, I encounter the difficulties on mapping the texture and drawing line in color in the same scene. I don't know how to set "gl_FragColor" to perform these two drawing function.

Is there any method to perform it?

SteveBaker
01-10-2011, 12:53 PM
You need a different shader for your lines and for your text.

SteveBaker
01-10-2011, 01:00 PM
Outputting text from a shader to help you debug it is a non-starter. That's flat out not gonna work.

Debugging shaders is a pain - but fortunately they are really short programs. If I'm forced to debug one, I'll set the output color equal to the value of some variable that I'm testing. I also do shader debugging in a regular C++/OpenGL test harness that I wrote which lets you do full-up debugging using a variety of nVidia tools and also Microsoft's "PIX" tool.

For really complex shaders, I don't write GLSL code at all - but instead use a graphical editor that I wrote that lets you generate shaders by connecting up boxes representing various low-level operations with lines representing control flow. That tool generates the shader in software so I don't have to even look at the source code. The way it renders the diagram for editing, you see the output of each operator - so it's very easy to visually debug your shaders. That tool took me 3 months to write!

Sadly, that tool isn't for public consumption - but there are other shader editors out there that work in kinda the same way. Check out AMD's "RenderMonkey" for example.