starfield shader - ported, would like feedback

Hi

Ported a shader from http://glslsandbox.com/e#32816.0

I put it up on code exchange: https://code.coronalabs.com/code/starfield

here it is running in playground: https://goo.gl/imfoYr

Would be interested in feedback on any errors, or better ways to optimize it for corona

thanks!

Nicely done!

Looks nice.  :slight_smile:

Some feedback:

You can replace

 vec2 resolution = vec2(CoronaVertexUserData.x,CoronaVertexUserData.y);

with

 vec2 resolution = CoronaVertexUserData.xy;

or simply use the right-hand side directly in later steps.

This

 vec2 position = gl\_FragCoord.xy / resolution.xy; position.y \*= resolution.y/resolution.x;

seems a little odd, unless it’s actually exploiting the subtle numerical precision difference between floating point numbers and mathematical ones. If not, the division and multiplication by the y-component cancel, so you could just write

 vec2 position = gl\_FragCoord.xy / resolution.xx;

or

 vec2 position = gl\_FragCoord.xy / resolution.x;

instead.

Lastly, if you’ll need to support older devices, the line

 return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) \* 43758.5453);

might be better served with something like

#if GL\_FRAGMENT\_PRECISION\_HIGH == 1 return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) \* 43758.5453); #else return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) \* 437.585453); #endif

though you’d have to experiment to be sure. (For the constant and the details I’m about to mention, see page 3 of the reference card.) Basically, any floating-point number is interpolated between adjacent powers of 2. If you have 1 / 65536 precision, you can get pretty close to that number (between 32768 and 65536, you can land on multiples of 0.5), but if your device can only muster 1024ths, you won’t (in that same range, you’d snap to multiples of 32!), which will probably be too choppy for small objects like your stars. 

StarCrunch - thanks for the feedback. 

a lot of this is still black box to me - afaik - still not entirely clear on use of resolution, and gl_FragCoord - maybe that i need to use the texCoord? Any advice on how to actually examine these values? - eg -i’ve figured out texCoord is a vec2 with range between 0 - 1.0, so from what i understand ,maybe this whole section is redundant - positions is the texCoord I think

#if GL_FRAGMENT_PRECISION_HIGH == 1

return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
#else
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 437.585453);

#endif

I can probably get away with the low precision version - from what i see its giving comparable results

My next goal is to make it so I can use as a scrolling space BG as my character moves

updated the gist - removed more unnecessary bits.

If the starfield will be a full-screen background, then yes, I think  position and texCoord should be the same. A lot of these online shader editors basically assume full-screen, free-standing effects, thus the built-in resolution parameter, whereas that will only occasionally apply in practice.

As far as figuring out values goes, if you know something is between 0 and 1, one way is to return it through a color from the fragment kernel, say as

if (true) return vec4(value, 0., 0., 1.); // the "if (true)" is to make the compiler happy, // so it doesn't complain about the rest of your // now-unreachable fragment kernel code

(Vertex kernels can likewise pass values to the fragment kernel through a varying, then do this same thing there.)

The (per-pixel) result will be black for a value of 0, bright red for a value of 1, otherwise in-between. You can use more color channels for more values, but it obviously takes a little more mental effort to figure out the components.

For values that can go higher than 1, you’ll want to figure out the maximum value and divide by that. (I’m not sure that returning colors outside [0, 1] has well-defined behavior. I think it clamps on some platforms, but also seem to recall less predictable results elsewhere. In any case, you’ll be getting false positives and / or negatives.) For values with a minimum other than 0, use the more general (x - min) / (max - min) to put x in the [0, 1] range.

so, hit a little snag. for some reason, shader works fine in simulator, but not on real device. started a new thread for that, will update here once figureout the problem

https://forums.coronalabs.com/topic/63270-works-in-simulator-not-on-device-iosipad-air/

Nicely done!

Looks nice.  :slight_smile:

Some feedback:

You can replace

 vec2 resolution = vec2(CoronaVertexUserData.x,CoronaVertexUserData.y);

with

 vec2 resolution = CoronaVertexUserData.xy;

or simply use the right-hand side directly in later steps.

This

 vec2 position = gl\_FragCoord.xy / resolution.xy; position.y \*= resolution.y/resolution.x;

seems a little odd, unless it’s actually exploiting the subtle numerical precision difference between floating point numbers and mathematical ones. If not, the division and multiplication by the y-component cancel, so you could just write

 vec2 position = gl\_FragCoord.xy / resolution.xx;

or

 vec2 position = gl\_FragCoord.xy / resolution.x;

instead.

Lastly, if you’ll need to support older devices, the line

 return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) \* 43758.5453);

might be better served with something like

#if GL\_FRAGMENT\_PRECISION\_HIGH == 1 return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) \* 43758.5453); #else return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) \* 437.585453); #endif

though you’d have to experiment to be sure. (For the constant and the details I’m about to mention, see page 3 of the reference card.) Basically, any floating-point number is interpolated between adjacent powers of 2. If you have 1 / 65536 precision, you can get pretty close to that number (between 32768 and 65536, you can land on multiples of 0.5), but if your device can only muster 1024ths, you won’t (in that same range, you’d snap to multiples of 32!), which will probably be too choppy for small objects like your stars. 

StarCrunch - thanks for the feedback. 

a lot of this is still black box to me - afaik - still not entirely clear on use of resolution, and gl_FragCoord - maybe that i need to use the texCoord? Any advice on how to actually examine these values? - eg -i’ve figured out texCoord is a vec2 with range between 0 - 1.0, so from what i understand ,maybe this whole section is redundant - positions is the texCoord I think

#if GL_FRAGMENT_PRECISION_HIGH == 1

return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
#else
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 437.585453);

#endif

I can probably get away with the low precision version - from what i see its giving comparable results

My next goal is to make it so I can use as a scrolling space BG as my character moves

updated the gist - removed more unnecessary bits.

If the starfield will be a full-screen background, then yes, I think  position and texCoord should be the same. A lot of these online shader editors basically assume full-screen, free-standing effects, thus the built-in resolution parameter, whereas that will only occasionally apply in practice.

As far as figuring out values goes, if you know something is between 0 and 1, one way is to return it through a color from the fragment kernel, say as

if (true) return vec4(value, 0., 0., 1.); // the "if (true)" is to make the compiler happy, // so it doesn't complain about the rest of your // now-unreachable fragment kernel code

(Vertex kernels can likewise pass values to the fragment kernel through a varying, then do this same thing there.)

The (per-pixel) result will be black for a value of 0, bright red for a value of 1, otherwise in-between. You can use more color channels for more values, but it obviously takes a little more mental effort to figure out the components.

For values that can go higher than 1, you’ll want to figure out the maximum value and divide by that. (I’m not sure that returning colors outside [0, 1] has well-defined behavior. I think it clamps on some platforms, but also seem to recall less predictable results elsewhere. In any case, you’ll be getting false positives and / or negatives.) For values with a minimum other than 0, use the more general (x - min) / (max - min) to put x in the [0, 1] range.

so, hit a little snag. for some reason, shader works fine in simulator, but not on real device. started a new thread for that, will update here once figureout the problem

https://forums.coronalabs.com/topic/63270-works-in-simulator-not-on-device-iosipad-air/