0

I am attempting to create a voxel style game, and I want to use GL_POINTS to simulate spherical voxels.

I am aiming to have them look like 3d spheres without having to render an actual sphere with many vertices.

However, when I created a mass of GL_POINTS, they overlap in a way that makes it obvious that they are flat circle sprites.

Here is an example: my image example of gl_points overlapping showing circular sprite:

img

I would like to have the circular GL_POINTS overlap in a way that makes them look like spheres being squished together and hiding parts of each other.

For an example of what I would like to achieve, here is an image showing Star Defenders 3D by Eric Gurt, in which he used spherical points as voxels in Javascript for his levels:

Example image showing points that look like spheres:

img

As you can see, where the points overlap, they hide parts of each other creating the illusion that they are 3d spheres instead of circular sprites.

Is there a way to replicate this in openGL? I am using OpenGL 3.3.0.

Spektre
  • 49,595
  • 11
  • 110
  • 380
rabbet
  • 1
  • 1
  • 2
    An option is to set the depth ([`gl_FragDepth`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_FragDepth.xhtml)) dependent on the distance to the center of the sphere in the [Fragment Shader](https://www.khronos.org/opengl/wiki/Fragment_Shader) – Rabbid76 Apr 26 '20 at 09:30
  • @Rabbid76 Thank you for your comment! I didnt even know what gl_fragdepth was. I did some research on it, still trying to figure out how i would get that to work... – rabbet Apr 26 '20 at 10:27
  • see [How can i make gradient sphere on glsl?](https://stackoverflow.com/a/41442375/2521214) simply set `glPointSize()` to cover your sphere with actual view zoom/FOV and in shader compute the sphere surface fragments ... Another alternative to `glPointSize` is geometry shader emiting triangles from points ... do not forget to update fragment depth as Rabbid76 suggested – Spektre Apr 27 '20 at 08:41
  • @Spektre thank you for your reply aswel, im still studying and trying my best to get it working – rabbet Apr 28 '20 at 00:58
  • a similar question as asked here: https://stackoverflow.com/questions/53650693/opengl-impostor-sphere-problem-when-calculating-the-depth-value . He figured it out at the bottom, however, all this was done without using GL_POINTS, and used a quad with two triangles instead. Im having difficulty getting this to work with GL_POINTS :( – rabbet Apr 28 '20 at 03:05
  • @rabbet IIRC glPointSize is not unlimited so if your spheres are too big they will not be fully covered by point rectangle that is why I suggested geometry shader to emit triangles if glPointSize is not enough. However new GLSL does not recognize QUAD primitive in geometry shader so it needs to be triangles (either 1 or 2) – Spektre Apr 28 '20 at 06:14
  • @Spektre this is my code for calculating glpointsize, its in my shader `gl_PointSize = viewPortSize.y * projectionMatrix[1][1] * pointRadius / gl_Position.w;` – rabbet Apr 28 '20 at 07:16
  • @rabbet I am ignoring the size computation for now and use hardcoded size ... as I am fighting worse problem as the tranfromed coordinates are fishy for GL_POINT primitive need to think about converting from screen space to world coordinates ... probably raycasting reverse projection. So it seems that geometry shadr would be simpler approach – Spektre Apr 28 '20 at 07:24
  • 1
    @Spektre this allows you to control gl_PointSize in a shader program : `glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);` Also doesnt gl point size just controll the width of the 2d sprite in pixels? I dont think it has anything to do with depth.. – rabbet Apr 28 '20 at 07:49
  • didn't know that... I am hitting a wall ... the `gl_FragCoord` inside Fragment shader is not correct for the bigger Points ... so I can not recompute the surface position. Either I am doing something stupid but more likely its a driver bug :( – Spektre Apr 28 '20 at 08:03
  • @rabbet my bet is that the Point is just copied instead of reinterpolated . However Fragment shader is called multiple times there is some degree of change but its thousands times smaller then it should be :( so raw GL_POINTS is a no go. The only thing left is emitting outscribed primitives in geometry ... or use something like this: [GLSL voxel raytracer](https://stackoverflow.com/a/48092685/2521214) – Spektre Apr 28 '20 at 08:14

1 Answers1

0

I have finally implemented a way to make points look like spheres by changing gl_FragDepth.

This is the code from my fragment shader to make a square gl_point into a sphere. (no lighting)

void makeSphere()
{
    //clamps fragments to circle shape. 
    vec2 mapping = gl_PointCoord * 2.0F - 1.0F;
    float d = dot(mapping, mapping);

    if (d >= 1.0F)
    {//discard if the vectors length is more than 0.5
        discard;
    }
    float z = sqrt(1.0F - d);
    vec3 normal = vec3(mapping, z);
    normal = mat3(transpose(viewMatrix)) * normal;
    vec3 cameraPos = vec3(worldPos) + rad * normal;


    ////Set the depth based on the new cameraPos.
    vec4 clipPos = projectionMatrix * viewMatrix * vec4(cameraPos, 1.0);
    float ndcDepth = clipPos.z / clipPos.w;
    gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;

    //calc ambient occlusion for circle
    if (bool(fAoc))
        ambientOcclusion = sqrt(1.0F - d * 0.5F);
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
rabbet
  • 1
  • 1