Do you want an simple noise glsl function to play with more cloud like stuff ?
So you ventured into ray-marching... then you'll soon learn about SDF (Signed Distance Field) Functions and how some people create entire worlds from them all shaded and butifull.
SDF's are also good for fonts and to interpolate between stuff in a fancy way.
I tried to use them(SDF's) to interpolate between boundingboxes of IBL(Image Based Lighting) probes. <-too many buzz words... I just wanted to say SDF's are great
lets see if we can shade your balls..i mean spheres... and maybe pass an array of positions instead of hard coding them into the shader.
[Edit]
So i made some changes and wanted to explain what i did:
The first thing i changed was the the hardcoded dot array in the glsl shader whe can do that in AppGameKit and pass the psoitions to the shader using this:
SetShaderConstantByName(1,"CloudCenter",0.0,0.0,100.0,0)
SetShaderConstantByName(1,"CloudSize",CloudSizeX#,CloudSizeY#,CloudSizeZ#,0)
For DotID=0 to 16
DotX#=random2(-CloudSizeX#/2,CloudSizeX#/2)
DotY#=random2(-CloudSizeY#/2,CloudSizeY#/2)
DotZ#=random2(-CloudSizeZ#/2,CloudSizeZ#/2)
Radius#=random2(50,200)/100.0
SetShaderConstantArrayByName(1,"sampleDots",DotID,DotX#,DotY#,DotZ#,Radius#)
next DotID
And here is the GLSL code:
uniform mediump vec3 CloudCenter;
uniform mediump vec3 CloudSize;
uniform mediump vec4 sampleDots[16];
const int dotCount = 16;
And we also dont need to write out the calculations for every dimansion:
float shape = SphereSDF(position, CloudCenter + sampleDots[ii].xyz, sampleDots[ii].w);
As you can see above instead of the distance function i created an SphereSDF function just passing all information and just using the length function instead:
float SphereSDF(vec3 position, vec3 center, float radius)
{
return length(position - center) - radius;
}
With this you should already have the dots in World space coordinates.
Now i want to have a seperate function where i can add all the different sdf functions to create different objects:
float WorldSDF(vec3 position)
{
float density = 9999.99;
for (int ii = 0; ii < dotCount; ii++)
{
float shape = SphereSDF(position, CloudCenter + sampleDots[ii].xyz, sampleDots[ii].w);
density = min(density, shape);
}
return density;
}
Here i use the min function to find the distance to the closest object.
You can add other shapes and objects in this function too just return the closest distance from of the objects
Now if you go near a sphere you'll see some artifacts sometimes it looks kinda like the moire effect sometimes like layers.
This is because till now we take static steps towards the view direction but we can do it a bit smarter and take smaller steps the closer we are to an object thus resulting in a more detailed scene.
Good thing we already get the closest distance from all objects using our WorldSDF() function and just put it instead of the STEP variable:
position += dist * direction;
Now this if you have a big scene you might have to take many steps sometimes too many steps.
So create an early exit just to be sure not to take too much time:
if (totalDist > 1000.0)
break;
totalDist += dist;
Final Result:
#version 120
varying vec3 posVarying;
varying vec2 uvVarying0;
varying mediump vec3 normalVarying;
// varying mediump vec3 lightVarying;
uniform mediump vec3 agk_CameraPos;
uniform mediump vec3 CloudCenter;
uniform mediump vec3 CloudSize;
uniform mediump vec4 sampleDots[16];
// array holding points for volumetric structures (spheres)
const int dotCount = 16;
float SphereSDF(vec3 position, vec3 center, float radius)
{
return length(position - center) - radius;
}
float FadeSDF(vec3 position)
{
return 1.0-(position.y+1.0);
}
float WorldSDF(vec3 position)
{
float density = 9999.99;
for (int ii = 0; ii < dotCount; ii++)
{
float shape = SphereSDF(position, CloudCenter + sampleDots[ii].xyz, sampleDots[ii].w);
density = min(density, shape);
}
return density;
}
vec4 RayMarching(vec3 position, vec3 direction)
{
float MAX_STEP = 50;
float totalDist = 0.0;
for(int i = 0; i < MAX_STEP; i++)
{
// check for any proximity hits by ray with dot points
float dist = WorldSDF(position);
// if it's below the threshold it hit something
if(dist < 0.001)
return vec4(1.0, 1.0, 0.0, 0.5);
if (totalDist > 1000.0)
break;
totalDist += dist;
position += dist * direction;
}
return vec4(0.0, 0.0, 0.5, 0.5); // renders the cube blue for reference
}
void main()
{
// highp vec3 viewDir = normalize(posVarying - agk_CameraPos);
highp vec3 viewDir = normalize(agk_CameraPos - posVarying); // for backface culling
vec4 color = RayMarching(posVarying, viewDir); // frag pos, viewdir, step rate
gl_FragColor = color;
}