Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Since you've tagged this with OpenGL ES 2.0, let me suggest an alternative approach for creating smooth spheres, and that's to draw them as raytraced impostors. Rather than calculate the many vertices you'll need to replicate a smooth sphere, you can take advantage of the fact that a sphere looks pretty much the same from any angle.</p> <p>To do this, you employ a process like the following:</p> <p><img src="https://i.stack.imgur.com/wy5we.jpg" alt="Sphere impostor generation"></p> <p>You send four vertices that represent two triangles to a vertex shader, which then displaces them to create a square that always faces the user. Within that square, you use a fragment shader to raster over each pixel and provide the color that a sphere would have at that point if you were viewing it through this square window.</p> <p>The advantage of this approach is that the sphere is as smooth as the resolution of your display supports, and the sphere will easily scale from small to large without requiring any recalculation of your geometry. It does shift the burden for rendering from the vertex processor to the fragment processor, but for a single sphere that's not much of a problem on the OpenGL ES 2.0 devices I've worked with.</p> <p>I use this technique in <a href="http://www.sunsetlakesoftware.com/molecules" rel="noreferrer">this iOS application</a>, for which the source code is available on that page, and talk about it a little more <a href="http://www.sunsetlakesoftware.com/2011/05/08/enhancing-molecules-using-opengl-es-20" rel="noreferrer">here</a>. A simplified version of the vertex shader I use looks something like this:</p> <pre><code>attribute vec4 position; attribute vec4 inputImpostorSpaceCoordinate; varying mediump vec2 impostorSpaceCoordinate; varying mediump vec3 normalizedViewCoordinate; uniform mat4 modelViewProjMatrix; uniform mediump mat4 orthographicMatrix; uniform mediump float sphereRadius; void main() { vec4 transformedPosition; transformedPosition = modelViewProjMatrix * position; impostorSpaceCoordinate = inputImpostorSpaceCoordinate.xy; transformedPosition.xy = transformedPosition.xy + inputImpostorSpaceCoordinate.xy * vec2(sphereRadius); transformedPosition = transformedPosition * orthographicMatrix; normalizedViewCoordinate = (transformedPosition.xyz + 1.0) / 2.0; gl_Position = transformedPosition; } </code></pre> <p>and the simplified fragment shader is this:</p> <pre><code>precision mediump float; uniform vec3 lightPosition; uniform vec3 sphereColor; uniform mediump float sphereRadius; uniform sampler2D depthTexture; varying mediump vec2 impostorSpaceCoordinate; varying mediump vec3 normalizedViewCoordinate; const mediump vec3 oneVector = vec3(1.0, 1.0, 1.0); void main() { float distanceFromCenter = length(impostorSpaceCoordinate); // Establish the visual bounds of the sphere if (distanceFromCenter &gt; 1.0) { discard; } float normalizedDepth = sqrt(1.0 - distanceFromCenter * distanceFromCenter); // Current depth float depthOfFragment = sphereRadius * 0.5 * normalizedDepth; // float currentDepthValue = normalizedViewCoordinate.z - depthOfFragment - 0.0025; float currentDepthValue = (normalizedViewCoordinate.z - depthOfFragment - 0.0025); // Calculate the lighting normal for the sphere vec3 normal = vec3(impostorSpaceCoordinate, normalizedDepth); vec3 finalSphereColor = sphereColor; // ambient float lightingIntensity = 0.3 + 0.7 * clamp(dot(lightPosition, normal), 0.0, 1.0); finalSphereColor *= lightingIntensity; // Per fragment specular lighting lightingIntensity = clamp(dot(lightPosition, normal), 0.0, 1.0); lightingIntensity = pow(lightingIntensity, 60.0); finalSphereColor += vec3(0.4, 0.4, 0.4) * lightingIntensity; gl_FragColor = vec4(finalSphereColor, 1.0); } </code></pre> <p>The current optimized versions of these shaders are a little harder to follow, and I also use ambient occlusion lighting, which is not present with these. Also not shown is texturing of this sphere, which can be done with a proper mapping function to translate between sphere surface coordinates and a rectangular texture. This is how I provide precalculated ambient occlusion values for the surfaces of my spheres.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload