How to draw smooth lines in 2D scene with OpenGL without using GL_LINE_SMOOTH? - c++

Since GL_LINE_SMOOTH is not hardware accelerated, nor supported on all GFX cards, how do you draw smooth lines in 2D mode, which would look as good as with GL_LINE_SMOOTH ?
Edit2: My current solution is to draw a line from 2 quads, which fade to zero transparency from edges and the colors in between those 2 quads would be the line color. it works good enough for basic smooth lines rendering and doesnt use texturing and thus is very fast to render.

So, you want smooth lines without:
line smoothing.
full-screen antialiasing.
shaders.
Alright.
Your best bet is to use Valve's Alpha-Tested Magnification technique. The basic idea, for your needs, is to create a texture that represents the distance from the line, with the center of the texture being a distance of 1.0. This could probably be a 1D texture.
Then using the techniques described in the paper (many of which work with fixed-function, including the antialiased version), draw a quad that represents your lines. Obviously you'll need alpha blending (and thus it isn't order-independent). You use your line width to control the distance at which it becomes the appropriate color, thus allowing you to make narrow or wide lines.
Doing this with shaders is virtually identical to the above, except without the texture. Instead of accessing a distance texture, the distance is passed and interpolated from the vertex shader. For the left-edge of the quad, the vertex shader passes 0. For the right edge, it passes 1. You multiply this by 2, subtract 1, and take the absolute value.
That's your distance from the line (the line being the center of the quad). Then just use that distance exactly as Valve's algorithm does.

Turning on full-screen anti-aliasing and using a quad would be my first choice.

Currently I am using 2 or 3 quads to do this, it is the simpliest way to do it.
If line thickness <= 1px, then you need only 2 quads.
If line thickness > 1px, then you need to add third quad in the middle.
The fading edge quads thickness must not change if the line thickness >= 1px.
In the image below you can see the quads with blue borders. White color means full opacity and black color means zero opacity (=fully transparent).

Related

How to colour vertices as a grid (like wireframe mode) using shaders?

I've created a plane with six vertices per square that form a terrain.
I colour each vertex using the terrain height value in the pixel shader.
I'm looking for a way to colour pixels between vertexes black, while keeping everything else the same to create a grid effect. The same effect you get from wireframe mode, except for the diagonal line, and the transparent part should be the normal colour.
My terrain, and how it looks in wireframe mode:
How would one go about doing this in pixel shader, or otherwise?
See "Solid Wireframe" - NVIDIA paper from a few years ago.
The idea is basically this: include a geometry shader that generates barycentric coordinates as a varying for each vertex. In your fragment / pixel shader, check the value of the bary components. If they are below a certain threshold, you color the pixel however you'd like your wireframe to be colored. Otherwise, light it as you normally would.
Given a face with vertices A,B,C, you'd generate barycentric values of:
A: 1,0,0
B: 0,1,0
C: 0,0,1
In your fragment shader, see if any component of the bary for that fragment is less than, say, 0.1. If so, it means that it's close to one of the edges of the face. (Which component is below the threshold will also tell you which edge, if you want to get fancy.)
I'll see if I can find a link and update here in a few.
Note that the paper is also ~10 years old. There are ways to get bary coordinates without the geometry shader these days in some situations, and I'm sure there are other workarounds. (Geometry shaders have their place, but are not the greatest friend of performance.)
Also, while geom shaders come with a perf hit, they're significantly faster than a second pass to draw a wireframe. Drawing in wireframe mode in GL (or DX) carries a significant performance penalty because you're asking the rasterizer to simulate Bresenham's line algorithm. That's not how rasterizers work, and it is freaking slow.
This approach also solves any z-fighting issues that you may encounter with two passes.
If your mesh were a single triangle, you could skip the geometry shader and just pack the needed values into a vertex buffer. But, since vertices are shared between faces in any model other than a single triangle, things get a little complicated.
Or, for fun: do this as a post processing step. Look for high ddx()/ddy() (or dFdx()/dFdy(), depending on your API) values in your fragment shader. That also lets you make some interesting effects.
Given that you have a vertex buffer containing all the vertices of your grid, make an index buffer that utilizes the vertex buffer but instead of making groups of 3 for triangles, use pairs of 2 for line segments. This will be a Line List and should contain all the pairs that make up the squares of the grid. You could generate this list automatically in your program.
Rough algorithm for rendering:
Render your terrain as normal
Switch your primitive topology to Line List
Assign the new index buffer
Disable Depth Culling (or add a small height value to each point in the vertex shader so the grid appears above the terrain)
Render the Line List
This should produce the effect you are looking for of the terrain drawn and shaded with a square grid on top of it. You will need to put a switch (via a constant buffer) in your pixel shader that tells it when it is rendering the grid so it can draw the grid black instead of using the height values.

Method to fix the video-projector deformation with GLSL/HLSL full-screen shader

I am working in VR field where good calibration of a projected screen is very important, and because of difficult-to-adjust ceiling mounts and other hardware specificities, I am looking for a fullscreen shader method to “correct” the shape of the screen.
Most of 2D or 3D engines allows to apply a full-screen effect or deformation by redrawing the rendering result on a quad that you can deform or render in a custom way.
The first idea was to use a vertex shader to offset the corners of this screen quad, so the image is deformed as a quadrilateral (like the hardware keystone on a projector), but it won’t be enough for the requirements
(this approach is described on math.stackexchange with a live fiddle demo).
In my target case:
The image deformation must be non-linear most of the time, so 9 or 16 control points are needed to get a finer adjust.
The borders of the image are not straight (barrel or pillow effect), so even with few control points, the image must be distorted in a curved way in between. Otherwise the deformation would make visible linear seams between at each control points’ limits.
Ideally, knowing the corrected position of each control points of 3x3 or 4x4 grid, the way would be to define a continuous transform for the texture coordinates of the image being drawn on the full screen
quad:
u,v => corrected_u, corrected_v
You can find an illustration here.
I’ve saw some FFD algorithm that works in 2D or 3D that would allow to deform “softly” an image or mesh as if it was made of rubber, but the implementation seems heavy for a real-time shader.
I thought also of a weight-based deformation as we have in squeletal/soft-bodies animation, but seems uncertain to weight properly the control points.
Do you know a method, algorithm or general approach that could help me solve the problem ?
I saw some mesh-based deformation like the new Oculus Rift DK2 requires for its own deformations, but most of the 2D/3D engine use a single quad made of 4 vertices only in standard.
If you need non linear deformation Bezier Surfaces are pretty handy and easy to implement.
You can either pre build them in CPU, or use hardware tessellation (example provided here)
Continuing my research, I found a way.
I created a 1D RGB texture corresponding to a "ramp" or cosine values. This will be the 3 influence coefficients of offset parameters on a 0..1 axis, with 3 coefficients at 0, 0.5 and 1 :
Red starts at 1 at x=0 and goes down to 0 at x=.5
Green start at 0 at x=0, goes to 1 at x=0.5 and goes back to 0 at x=1
Blue starts at 0 at x=0.1 and goes up to 1 at x=1
With these, from 9 float2 uniforms I can interpolate very softly my parameters over the image (with 3 lookups on horizontal, and a final one for vertical).
Then, one interpolated, I offsets the texture coord with these and it works :-D
This is more or less a weighted interpolation of the coordinates using texture lookups for speedup.

Antialiased GLSL impostors

If you draw a sphere using an impostor based ray-tracing approach as described for example here
http://www.arcsynthesis.org/gltut/Illumination/Tutorial%2013.html
you typically draw a quad and then use 'discard' to skip pixels that have a distance from the quad center larger than the sphere radius.
When you turn on anti-aliasing, GLSL will anti-alias the border of the primitive you draw - in this case the quad - but not the border between the drawn and discarded pixels.
I have attached two screen shots displaying the sphere and a blow-up of its border. Except for the top-most pixels, that lie on the quad border, clearly the sphere border has not been anti-aliased.
Is there any trick I can use to make the impostor spheres have a nice anti-aliased border?
Best regard,
Mads
Instead of just discarding the pixel, set your sphere to have inner and outer radius.
Everything inside the inner radius is fully opaque, everything outside the outer radius is discarded, and anything in between is linearly interpolated between 0 and 1 alpha values.
float alpha = (position - inner) / (outer - inner);
Kneejerk reaction would be to multisample for yourself: render to a texture that is e.g. four times as large as your actual output, then ensure you generate mip maps and render from that texture back onto your screen.
Alternatively do that directly in your shader and let OpenGL continue worrying about geometry edges: sample four rays per pixel and average them.

C++ OpenGL Creating Glowing Lines

I have researched and the methods used to make a blooming effects are usually based on having a sharp and blurred image conjoined to give the glow effect. But I want to know how I can make gl_lines(or any line) have brightness. Since in my game I am randomly generating a simple 2D terrain, I wish to make the terrain line segments glow.
Use a fragment shader to calculate the distance from a fragment to the edge and color the fragment with the appropriate color value. You can use a simple control curve to control the radius and intensity anlong of the glow(like in photoshop). It can also be tuned to act like wireframe visualization. The idea is you don't really rasterize points to lines using a draw call, just shade each pixel based on its distance from the corresponding edge.
The difference from using a blur pass is that you will first get better performance, and second - per-pixel control over the glow, you can have non-uniform glow which you cannot get by using blur because it is not really aware of the actual line geometry, it just blindly works on pixels, whereas with edge distance detection you do use the actual geometry data as input without flatting it down to pixels. You can also have stuff like gradient glows, e.g. the glow color is different and changes with the radius.

Drawing procedural lines on top of a texture avoiding aliasing in glsl

My goal is to draw white lines over an asphalt road. Since the properties of the road change, there cannot be just a texture representing both asphalt and white lines.
The current approach is to apply the asphalt texture and code some information in the other two texture coordinates. In a pixel shader, reading those coordinates, I decide whether that fragment should be white or not.
This results in high levels of aliasing. And that’s the problem I want to try to solve.
I have been changing the “whiteness” of the line applying smoothstep or linear interpolation. I have also changed the width and color according to distance from camera. This helps a little bit, but at far away distances, there are still ugly aliased lines.
How would you go on doing this? Would it be better to have a texture representing a smoothed white line and accessing the texels? Should I implement a bilinear filter accessing neighboring texels?
You should simply use 2 textures with 2 coordinates.
Small seamless asphalt texture tiled on the road polygon.
Mark texture with alpha that you will place on the middle of this polygon (with texture coordinate offset)
Or you can create extra polygons in the middle of the road for marks to avoid any aliasing.
To make it all looks real you can apply Texture Bombing with dirt and cracks.