First, we draw three orthogonal golden rectangles centered on the origin. A golden rectangle has the ratio of its edge lengths equal to the golden ratio.
Then connect the corners of the golden rectangles to their 5 neighbors. Each triplet of adjacent points can form a triangle.
Then add a triangle face to each adjacent triplet of corners. Now we have a 20 face icosahedron.
Then split each triangle into 4, and normalize all the corners to be the same distance away. Since each face is now 4 faces, there are now 80 faces.
Do it again to get 320 faces.
Then again to get 1280 faces. Now it looks like a sphere.
Then we can remove the rectangles and fill in the faces of thetriangles.
To light and modify the shader we can diffusive the light linearly on the cosine of the angle between the light and the normal vector for the surface.
For any point on the sphere with normal vector , and any point light source at position the new color can be calculated from the base color by:
Where is the ambient brightness, and is the brightness of the light. just means linear interpolation, and will just keep the value of the cosine from going negative.
Then also add a spectral effect, based on the angle between the reflected light and the camera position.
Given the point , the light source position , the camera position , and the normal vector the intensity of a spectral effect can be calculated:
First reflect the incoming light vector across the normal vector:
Then find the cosine between the incoming light and the camera direction
Then the spectral factor can be calculated by exponentiating the cosine
Then the final color can be calculated by interpolating between the balls diffuse color and the lights color
Now we turn off the wireframe.
Then we can add a beach ball as the base color.
The fragment shader can be found here:
#version 300 es
precision highp float;
uniform uint fragEnum;
uint ENUM_RED = 0u;
uint ENUM_GREEN = 1u;
uint ENUM_BLUE = 2u;
uint ENUM_BLACK = 3u;
uint ENUM_WHITE = 4u;
uint ENUM_CLEAR_RED = 5u;
uint ENUM_CLEAR_GREEN = 6u;
uint ENUM_CLEAR_BLUE = 7u;
uint ENUM_REFLECTIVE_RED = 8u;
uint ENUM_SPECTRAL_RED = 9u;
uint ENUM_BEACHBALL = 10u;
uniform vec3 lightPos;
uniform mat4 cameraMatrix;
in vec3 model_pos;
in vec3 world_pos;
out vec4 outColor;
float AMBIENT_BRIGHTNESS = 0.4;
float DIFFUSE_BRIGHTNESS = 0.6;
vec3 getBeachBallColor(){
float x = model_pos.x;
float y = model_pos.y;
float r = x*x + y*y;
if (r < 0.03) {
return vec3(1, 1, 0);
}
float c2 = x*x/r;
if (c2 < 0.75) {
if (x > 0.0) {
if (y > 0.0) {
return vec3(0, 1, 0);
} else {
return vec3(0, 0, 1);
}
} else {
return vec3(1, 1, 1);
}
} else {
if (x > 0.0) {
return vec3(1, 1, 1);
} else {
return vec3(1, 0, 0);
}
}
return vec3(1.0, 0.0, 0.0);
}
float diffuse_reflect_factor(){
vec3 dir = vec3(lightPos) - vec3(world_pos);
float cosine = dot(normalize(dir), normalize(vec3(model_pos)));
float cf = clamp((AMBIENT_BRIGHTNESS * cosine) + DIFFUSE_BRIGHTNESS, 0.0, 1.0);
return cf;
}
float specular_reflect_factor(){
vec3 camera_pos = vec3(inverse(cameraMatrix) * vec4(0.0, 0.0, 0.0, 1.0));
vec3 incident = -(camera_pos - vec3(world_pos));
vec3 optimal_dir = normalize(reflect(incident, normalize(vec3(model_pos))));
vec3 light_dir = normalize(lightPos - vec3(world_pos));
float cos = dot(optimal_dir, light_dir);
float shinyness = 5.0;
float factor = pow(clamp(cos, 0.0, 1.0), shinyness);
return factor;
}
void main() {
if(fragEnum == ENUM_RED){
outColor = vec4(1.0, 0.0, 0.0, 1.0);
}else if(fragEnum == ENUM_GREEN){
outColor = vec4(0.0, 1.0, 0.0, 1.0);
}else if(fragEnum == ENUM_BLUE){
outColor = vec4(0.0, 0.0, 1.0, 1.0);
}else if(fragEnum == ENUM_BLACK){
outColor = vec4(0.0, 0.0, 0.0, 1.0);
}else if(fragEnum == ENUM_WHITE){
outColor = vec4(1.0, 1.0, 1.0, 1.0);
}else if(fragEnum == ENUM_CLEAR_RED){
outColor = vec4(0.5, 0.0, 0.0, 0.5);
}else if(fragEnum == ENUM_CLEAR_GREEN){
outColor = vec4(0.0, 0.5, 0.0, 0.5);
}else if(fragEnum == ENUM_CLEAR_BLUE){
outColor = vec4(0.0, 0.0, 0.5, 0.5);
}else if(fragEnum == ENUM_REFLECTIVE_RED){
outColor = vec4(diffuse_reflect_factor() * vec3(1.0, 0.0, 0.0), 1.0);
}else if(fragEnum == ENUM_SPECTRAL_RED){
vec4 regular_color = vec4(diffuse_reflect_factor() * vec3(1.0, 0.0, 0.0), 1.0);
vec4 light_color = vec4(1.0, 1.0, 1.0, 1.0);
float specular_factor = specular_reflect_factor();
outColor = (specular_factor * light_color) + ((1.0-specular_factor) * regular_color);
}else if(fragEnum == ENUM_BEACHBALL){
vec4 regular_color = vec4(diffuse_reflect_factor() * getBeachBallColor(), 1.0);
vec4 light_color = vec4(1.0, 1.0, 1.0, 1.0);
float specular_factor = specular_reflect_factor();
outColor = (specular_factor * light_color) + ((1.0-specular_factor) * regular_color);
}else{
outColor = vec4(model_pos, 1.0);
}
}