Draw a sphere: Difference between revisions
Add Racket entry |
|||
Line 2,616: | Line 2,616: | ||
if event.type == KEYDOWN: |
if event.type == KEYDOWN: |
||
pass |
pass |
||
</lang> |
|||
=={{header|Racket}}== |
|||
[[File:Racket-sphere-plot.png|200px|thumb|right]] |
|||
Using the Typed Racket language with the plot library: |
|||
<lang racket> |
|||
#lang typed/racket |
|||
(require plot/typed) |
|||
(plot3d (polar3d (λ (θ ρ) 1)) #:altitude 25) |
|||
</lang> |
</lang> |
||
Revision as of 14:56, 5 March 2013
You are encouraged to solve this task according to the task description, using any language you may know.
The task is to draw a sphere. The sphere can be represented graphically, or in ascii art, depending on the language capabilities. Either static or rotational projection is acceptable for this task.
Ada
Translation from the C code at http://cairographics.org/samples/gradient Uses the Cairo component of GtkAda to create and save as png
<lang Ada>with Glib; use Glib; with Cairo; use Cairo; with Cairo.Png; use Cairo.Png; with Cairo.Pattern; use Cairo.Pattern; with Cairo.Image_Surface; use Cairo.Image_Surface; with Ada.Numerics;
procedure Sphere is
subtype Dub is Glib.Gdouble;
Surface : Cairo_Surface; Cr : Cairo_Context; Pat : Cairo_Pattern; Status_Out : Cairo_Status; M_Pi : constant Dub := Dub (Ada.Numerics.Pi);
begin
Surface := Create (Cairo_Format_ARGB32, 512, 512); Cr := Create (Surface); Pat := Cairo.Pattern.Create_Radial (230.4, 204.8, 51.1, 204.8, 204.8, 256.0); Cairo.Pattern.Add_Color_Stop_Rgba (Pat, 0.0, 1.0, 1.0, 1.0, 1.0); Cairo.Pattern.Add_Color_Stop_Rgba (Pat, 1.0, 0.0, 0.0, 0.0, 1.0); Cairo.Set_Source (Cr, Pat); Cairo.Arc (Cr, 256.0, 256.0, 153.6, 0.0, 2.0 * M_Pi); Cairo.Fill (Cr); Cairo.Pattern.Destroy (Pat); Status_Out := Write_To_Png (Surface, "SphereAda.png"); pragma Assert (Status_Out = Cairo_Status_Success);
end Sphere;</lang>
BASIC
QBasic
<lang QBASIC>SCREEN 13 ' enter high-color graphic mode
' sets palette colors B/N FOR i = 0 TO 255
PALETTE 255 - i, INT(i / 4) + INT(i / 4) * 256 + INT(i / 4) * 65536
NEXT i PALETTE 0, 0
' draw the sphere FOR i = 255 TO 0 STEP -1
x = 50 + i / 3 y = 99 CIRCLE (x, y), i / 3, i PAINT (x, y), i
NEXT i
' wait until keypress DO: LOOP WHILE INKEY$ = "" END</lang>
DarkBASIC
Some simple 3D objects are built into DarkBASIC. Creating a sphere only takes 1 line:
<lang darkbasic>MAKE OBJECT SPHERE 1,1</lang>
BBC BASIC
Using Direct3D. <lang bbcbasic> MODE 8
INSTALL @lib$+"D3DLIB" D3DTS_VIEW = 2 D3DTS_PROJECTION = 3 D3DRS_SPECULARENABLE = 29 SYS "LoadLibrary", @lib$+"D3DX8BBC.DLL" TO d3dx% IF d3dx%=0 ERROR 100, "Couldn't load D3DX8BBC.DLL" SYS "GetProcAddress", d3dx%, "D3DXCreateSphere" TO `D3DXCreateSphere` SYS "GetProcAddress", d3dx%, "D3DXMatrixLookAtLH" TO `D3DXMatrixLookAtLH` SYS "GetProcAddress", d3dx%, "D3DXMatrixPerspectiveFovLH" TO `D3DXMatrixPerspectiveFovLH` DIM eyepos%(2), lookat%(2), up%(2), mat%(3,3) DIM D3Dlight8{Type%, Diffuse{r%,g%,b%,a%}, Specular{r%,g%,b%,a%}, \ \ Ambient{r%,g%,b%,a%}, Position{x%,y%,z%}, Direction{x%,y%,z%}, \ \ Range%, Falloff%, Attenuation0%, Attenuation1%, Attenuation2%, \ \ Theta%, Phi%} DIM D3Dmaterial8{Diffuse{r%,g%,b%,a%}, Ambient{r%,g%,b%,a%}, \ \ Specular{r%,g%,b%,a%}, Emissive{r%,g%,b%,a%}, Power%} DIM D3Dbasemesh8{QueryInterface%, Addref%, Release%, \ \ DrawSubset%, GetNumFaces%, GetNumVertices%, GetFVF%, \ \ GetDeclaration%, GetOptions%, GetDevice%, \ \ CloneMeshFVF%, CloneMesh%, GetVertexBuffer%, GetIndexBuffer%, \ \ LockVertexBuffer%, UnlockVertexBuffer%, LockIndexBuffer%, \ \ UnlockIndexBuffer%, GetAttributeTable%} DIM D3Ddevice8{QueryInterface%, AddRef%, Release%, TestCooperativeLevel%, \ \ GetAvailableTextureMem%, ResourceManagerDiscardBytes%, GetDirect3D%, \ \ GetDeviceCaps%, GetDisplayMode%, GetCreationParameters%, SetCursorProperties%, \ \ SetCursorPosition%, ShowCursor%, CreateAdditionalSwapChain%, Reset%, \ \ Present%, GetBackBuffer%, GetRasterStatus%, SetGammaRamp%, GetGammaRamp%, \ \ CreateTexture%, CreateVolumeTexture%, CreateCubeTexture%, CreateVertexBuffer%, \ \ CreateIndexBuffer%, CreateRenderTarget%, CreateDepthStencilSurface%, \ \ CreateImageSurface%, CopyRects%, UpdateTexture%, GetFrontBuffer%, \ \ SetRenderTarget%, GetRenderTarget%, GetDepthStencilSurface%, BeginScene%, \ \ EndScene%, Clear%, SetTransform%, GetTransform%, MultiplyTransform%, \ \ SetViewport%, GetViewport%, SetMaterial%, GetMaterial%, SetLight%, GetLight%, \ \ LightEnable%, GetLightEnable%, SetClipPlane%, GetClipPlane%, SetRenderState%, \ \ GetRenderState%, BeginStateBlock%, EndStateBlock%, ApplyStateBlock%, \ \ CaptureStateBlock%, DeleteStateBlock%, CreateStateBlock%, SetClipStatus%, \ \ GetClipStatus%, GetTexture%, SetTexture%, GetTextureStageState%, \ \ SetTextureStageState%, ValidateDevice%, GetInfo%, SetPaletteEntries%, \ \ GetPaletteEntries%, SetCurrentTexturePalette%, GetCurrentTexturePalette%, \ \ DrawPrimitive%, DrawIndexedPrimitive%, DrawPrimitiveUP%, \ \ DrawIndexedPrimitiveUP%, ProcessVertices%, CreateVertexShader%, \ \ SetVertexShader%, GetVertexShader%, DeleteVertexShader%, \ \ SetVertexShaderConstant%, GetVertexShaderConstant%, GetVertexShaderDeclaration%, \ \ GetVertexShaderFunction%, SetStreamSource%, GetStreamSource%, SetIndices%, \ \ GetIndices%, CreatePixelShader%, SetPixelShader%, GetPixelShader%, \ \ DeletePixelShader%, SetPixelShaderConstant%, GetPixelShaderConstant%, \ \ GetPixelShaderFunction%, DrawRectPatch%, DrawTriPatch%, DeletePatch%} pDevice%=FN_initd3d(@hwnd%, 1, 1) IF pDevice%=0 ERROR 100, "Couldn't create Direct3D8 device" !(^D3Ddevice8{}+4) = !pDevice% SYS `D3DXCreateSphere`, pDevice%, FN_f4(1), 50, 50, ^meshSphere%, 0 IF meshSphere% = 0 ERROR 100, "D3DXCreateSphere failed" !(^D3Dbasemesh8{}+4) = !meshSphere% REM. Point-source light: D3Dlight8.Type%=1 : REM. point source D3Dlight8.Diffuse.r% = FN_f4(1) D3Dlight8.Diffuse.g% = FN_f4(1) D3Dlight8.Diffuse.b% = FN_f4(1) D3Dlight8.Specular.r% = FN_f4(1) D3Dlight8.Specular.g% = FN_f4(1) D3Dlight8.Specular.b% = FN_f4(1) D3Dlight8.Position.x% = FN_f4(2) D3Dlight8.Position.y% = FN_f4(1) D3Dlight8.Position.z% = FN_f4(4) D3Dlight8.Range% = FN_f4(10) D3Dlight8.Attenuation0% = FN_f4(1) REM. Material: D3Dmaterial8.Diffuse.r% = FN_f4(0.2) D3Dmaterial8.Diffuse.g% = FN_f4(0.6) D3Dmaterial8.Diffuse.b% = FN_f4(1.0) D3Dmaterial8.Specular.r% = FN_f4(0.4) D3Dmaterial8.Specular.g% = FN_f4(0.4) D3Dmaterial8.Specular.b% = FN_f4(0.4) D3Dmaterial8.Power% = FN_f4(100) fovy = RAD(30) aspect = 5/4 znear = 1 zfar = 1000 bkgnd% = &7F7F7F eyepos%() = 0, 0, FN_f4(6) lookat%() = 0, 0, 0 up%() = 0, FN_f4(1), 0 SYS D3Ddevice8.Clear%, pDevice%, 0, 0, 3, bkgnd%, FN_f4(1), 0 SYS D3Ddevice8.BeginScene%, pDevice% SYS D3Ddevice8.SetLight%, pDevice%, 0, D3Dlight8{} SYS D3Ddevice8.LightEnable%, pDevice%, 0, 1 SYS D3Ddevice8.SetMaterial%, pDevice%, D3Dmaterial8{} SYS D3Ddevice8.SetRenderState%, pDevice%, D3DRS_SPECULARENABLE, 1 SYS `D3DXMatrixLookAtLH`, ^mat%(0,0), ^eyepos%(0), ^lookat%(0), ^up%(0) SYS D3Ddevice8.SetTransform%, pDevice%, D3DTS_VIEW, ^mat%(0,0) SYS `D3DXMatrixPerspectiveFovLH`, ^mat%(0,0), FN_f4(fovy), \ \ FN_f4(aspect), FN_f4(znear), FN_f4(zfar) SYS D3Ddevice8.SetTransform%, pDevice%, D3DTS_PROJECTION, ^mat%(0,0) SYS D3Dbasemesh8.DrawSubset%, meshSphere%, 0 SYS D3Ddevice8.EndScene%, pDevice% SYS D3Ddevice8.Present%, pDevice%, 0, 0, 0, 0 SYS D3Ddevice8.Release%, pDevice% SYS D3Dbasemesh8.Release%, meshSphere% SYS "FreeLibrary", d3dx% END
Brlcad
<lang brlcad>opendb balls.g y # Create a database to hold our shapes units cm # Set the unit of measure in ball.s sph 0 0 0 3 # Create a sphere of radius 3 cm named ball.s with its centre at 0,0,0 </lang>
C
The lighting calculation is somewhere between crude and bogus, but hey, I'm shading it with ASCII characters, don't expect too much. <lang C>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <ctype.h>
- include <math.h>
const char *shades = ".:!*oe&#%@";
double light[3] = { 30, 30, -50 }; void normalize(double * v) {
double len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); v[0] /= len; v[1] /= len; v[2] /= len;
}
double dot(double *x, double *y) {
double d = x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; return d < 0 ? -d : 0;
}
void draw_sphere(double R, double k, double ambient) {
int i, j, intensity; double b; double vec[3], x, y; for (i = floor(-R); i <= ceil(R); i++) { x = i + .5; for (j = floor(-2 * R); j <= ceil(2 * R); j++) { y = j / 2. + .5; if (x * x + y * y <= R * R) { vec[0] = x; vec[1] = y; vec[2] = sqrt(R * R - x * x - y * y); normalize(vec); b = pow(dot(light, vec), k) + ambient; intensity = (1 - b) * (sizeof(shades) - 1); if (intensity < 0) intensity = 0; if (intensity >= sizeof(shades) - 1) intensity = sizeof(shades) - 2; putchar(shades[intensity]); } else putchar(' '); } putchar('\n'); }
}
int main()
{
normalize(light); draw_sphere(20, 4, .1); draw_sphere(10, 2, .4);
return 0;
}</lang>Output:<lang> #############%%%%
##&&eeeeeeeeee&&&&&&&####%%%%%%%% &&eeooooooooooooooeeeee&&&&######%%%%%%%% eeoo**************oooooooeeee&&&&####%%%%%%%% &&oo**!!!!!!::!!!!!!!!****oooooee&&&&######%%%%%%%%%% eeoo!!!!::::::::::::::!!!!*****ooeeee&&&&####%%%%%%%%%%%% ee**!!::::............::::!!!!***ooooeeee&&######%%%%%%%%%%%% &&oo!!::..................::!!!!*****ooeeee&&&&####%%%%%%%%%%%%%% oo!!::....................::::!!*****ooeeee&&&&####%%%%%%%%%%%%%% ee**!!::....................::::!!*****ooeeee&&&&####%%%%%%%%%%%%%%%% &&oo!!::......................::::!!*****ooeeee&&&&######%%%%%%%%%%%%%%%% ee**!!::......................::::!!*****ooeeee&&&&######%%%%%%%%%%%%%%%% ##oo**!!::......................::!!!!*****ooeeee&&&&####%%%%%%%%%%%%%%%%%%%% &&oo**::::....................::::!!!!***ooooeeee&&&&####%%%%%%%%%%%%%%%%%%%% eeoo**!!::..................::::!!!!*****ooooee&&&&######%%%%%%%%%%%%%%%%%%%% eeoo**!!::................::::!!!!****oooooeeee&&&&######%%%%%%%%%%%%%%%%%%%%
- eeoo**!!::::............::::!!!!!!****oooeeee&&&&&&######%%%%%%%%%%%%%%%%%%%%%%
- eeoo**!!!!::::::::::::::::!!!!!!****oooooeeee&&&&######%%%%%%%%%%%%%%%%%%%%%%%%
- eeoooo**!!!!!!::::::::!!!!!!******ooooeeeee&&&&&&######%%%%%%%%%%%%%%%%%%%%%%%%
- &&eeoo****!!!!!!!!!!!!!!!!******ooooeeeee&&&&&&######%%%%%%%%%%%%%%%%%%%%%%%%%%
- &&eeoooo********************ooooooeeee&&&&&&&######%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- &&&&eeoooooo************ooooooeeeeee&&&&&&&########%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%##&&eeeeeeooooooooooooooooooeeeeee&&&&&&&########%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %####&&&&eeeeeeeeeeeeeeeeeeeeee&&&&&&&&#########%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%##&&&&&&eeeeeeeeeeeeeeee&&&&&&&&&&#########%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%######&&&&&&&&&&&&&&&&&&&&&&&&###########%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%########&&&&&&&&&&&&&&############%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%##############################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%######################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%####%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% ::..:::::!!** .............::!!**oo ...................::!!**ooee .......................::!!ooeeee .......................::!!**ooee .........................::!!**ooeeee .........................::!!**ooeeee
- .........................::!!**ooeeeeee
........................::!!**ooooeeeeee
- .......................::!!**ooeeeeeeee
- .....................::!!****ooeeeeeeee
!::................:::!!****ooeeeeeeeeee
- !!::..........::::!!!****ooooeeeeeeeeee
**!!::::::::::!!!!*****ooooeeeeeeeeee oo**!!!!!!!!!!*******ooooeeeeeeeeeeee oooo********oooooooeeeeeeeeeeeeee eeeeooooooooooeeeeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeee </lang>
Fun with 3D noise texture
- include <stdlib.h>
- include <math.h>
- define MAXD 8
int g[] = { -1, 1, -1, 1 }; /* Perlin-like noise */ inline void hashed(int *data, int *out, int len) {
- define ror(a, d) ((a << (d)) | (a >> (32 - d)))
register unsigned int h = 0x12345678, tmp; unsigned int *d = (void*)data; int i = len;
while (i--) { tmp = *d++; h += ror(h, 15) ^ ror(tmp, 5); }
h ^= ror(h, 7); h += ror(h, 23); h ^= ror(h, 19); h += ror(h, 11); h ^= ror(h, 13); h += ror(h, 17);
- undef ror
for (i = len; i--; ) { out[i] = g[h & 3]; h >>= 2; } }
double scale[MAXD], scale_u[MAXD]; void noise_init() { int i; for (i = 1; i < MAXD; i++) { scale[i] = 1 / (1 + sqrt(i + 1)); scale_u[i] = scale[i] / sqrt(i + 1); } }
double noise(double *x, int d) {
- define sum(s, x) for (s = 0, j = 0; j < d; j++) s += x
register int i, j; int n[MAXD], o[MAXD], g[MAXD], tmp; double s, r, t, w, ret, u[MAXD];
sum(s, x[j]); s *= scale[d];
for (i = 0; i < d; i++) { o[i] = i; t = x[i] + s; u[i] = t - (n[i] = floor(t)); } o[d] = 0;
for (i = 0; i < d - 1; i++) for (j = i; j < d; j++) if (u[o[i]] < u[o[j]]) tmp = o[i], o[i] = o[j], o[j] = tmp;
ret = w = 0, r = 1; for (s = 0, j = 0; j < d; j++) s += n[j]; s *= scale_u[d];
for (i = 0; i <= d; i++) { for (j = 0; j < d; j++) u[j] = x[j] + s - n[j];
for (t = (d + 1.) / (2 * d), j = 0; j < d; j++) { t -= u[j] * u[j]; if (t <= 0) break; }
if (t >= 0) { r = 0; hashed(n, g, d); for (j = 0; j < d; j++) if (g[j]) r += (g[j] == 1 ? u[j] : -u[j]); t *= t; ret += r * t * t; }
if (i < d) { n[o[i]]++; s += scale_u[d]; } } return ret * (d * d); }
double get_noise2(double x, double y) { int i, ws; double r = 0, v[2];
for (i = 1, ws = 0; i <= 128; i <<= 1) { v[0] = x * i, v[1] = y * i; r += noise(v, 2); ws ++; } r /= ws; return r; }
double get_noise3(double x, double y, double z) { int i, ws; double r = 0, v[3], w;
for (i = 1, ws = 0; i <= 32; i <<= 1) { v[0] = x * i, v[1] = y * i, v[2] = z * i; w = 1./sqrt(i); r += noise(v, 3) * w; ws += w; } return r / ws; }
int main(int c, char** v)
{
unsigned char pix[256 * 256], *p;
int i, j;
double x, y, z, w;
FILE *fp;
noise_init();
for (p = pix, i = 0; i < 256 * 256; i++) *p++ = 0;
for (p = pix, i = 0; i < 256; i++) { y = (i - 128) / 125.; for (j = 0; j < 256; j++, p++) { x = (j - 128) / 125.; *p = (get_noise2(i/256., j/256.) + 1) / 6 * i;
z = 1- x*x - y*y; if (z < 0) continue;
z = sqrt(z);
w = get_noise3(x, y, z);
w = (w + 1) / 2; w *= (1 + x - y + z) / 3.5; if (w < 0) w = 0;
*p = w * 255; } }
fp = fopen("out.pgm", "w+"); fprintf(fp, "P5\n256 256\n255\n"); fwrite(pix, 1, 256 * 256, fp); fclose(fp);
return 0; }</lang>
C#
<lang java>using System;
namespace Sphere {
internal class Program { private const string Shades = ".:!*oe%&#@"; private static readonly double[] Light = {30, 30, -50};
private static void Normalize(double[] v) { double len = Math.Sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); v[0] /= len; v[1] /= len; v[2] /= len; }
private static double Dot(double[] x, double[] y) { double d = x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; return d < 0 ? -d : 0; }
public static void DrawSphere(double r, double k, double ambient) { var vec = new double[3]; for(var i = (int)Math.Floor(-r); i <= (int)Math.Ceiling(r); i++) { double x = i + .5; for(var j = (int)Math.Floor(-2*r); j <= (int)Math.Ceiling(2*r); j++) { double y = j/2.0 + .5; if(x*x + y*y <= r*r) { vec[0] = x; vec[1] = y; vec[2] = Math.Sqrt(r*r - x*x - y*y); Normalize(vec); double b = Math.Pow(Dot(Light, vec), k) + ambient; int intensity = (b <= 0) ? Shades.Length - 2 : (int)Math.Max((1 - b)*(Shades.Length - 1), 0); Console.Write(Shades[intensity]); } else Console.Write(' '); } Console.WriteLine(); } }
private static void Main() { Normalize(Light); DrawSphere(6, 4, .1); DrawSphere(10, 2, .4); Console.ReadKey(); } }
}</lang>
D
<lang d>import std.stdio, std.math, std.algorithm, std.numeric;
alias double[3] V3; V3 light = [30, 30, -50];
void normalize(ref V3 v) pure {
v[] /= dotProduct(v, v) ^^ 0.5;
}
double dot(in ref V3 x, in ref V3 y) pure nothrow {
immutable double d = dotProduct(x, y); return d < 0 ? -d : 0;
}
void drawSphere(in double R, in double k, in double ambient) {
enum shades = ".:!*oe&#%@"; foreach (int i; cast(int)floor(-R) .. cast(int)ceil(R) + 1) { immutable double x = i + 0.5; foreach (int j; cast(int)floor(-2*R)..cast(int)ceil(2*R)+1){ immutable double y = j / 2. + 0.5; if (x ^^ 2 + y ^^ 2 <= R ^^ 2) { V3 vec = [x, y, (R^^2 - x^^2 - y^^2) ^^ 0.5]; vec.normalize(); immutable double b = dot(light, vec) ^^ k + ambient; int intensity = cast(int)((1-b) * (shades.length-1)); intensity = min(shades.length-1, max(intensity, 0)); putchar(shades[intensity]); } else putchar(' '); } putchar('\n'); }
}
void main() {
light.normalize(); drawSphere(20, 4, 0.1); drawSphere(10, 2, 0.4);
}</lang>
Delphi
Under Microsoft Windows: If you notice the big sphere loses its roundness, then try increasing the width of the Windows console. By default it’s 80; so put it to something bigger, let’s say 90.
Steps: Run the CMD Windows shell. Then follow this path to setup the new width: Main Menu-> Properties -> Layout -> Window Size -> Width.
<lang Delphi> program DrawASphere;
{$APPTYPE CONSOLE}
uses
SysUtils, Math;
type
TDouble3 = array[0..2] of Double; TChar10 = array[0..9] of Char;
var
shades: TChar10 = ('.', ':', '!', '*', 'o', 'e', '&', '#', '%', '@'); light: TDouble3 = (30, 30, -50 );
procedure normalize(var v: TDouble3); var len: Double; begin len:= sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); v[0] := v[0] / len; v[1] := v[1] / len; v[2] := v[2] / len; end;
function dot(x, y: TDouble3): Double; begin Result:= x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; Result:= IfThen(Result < 0, -Result, 0 ); end;
procedure drawSphere(R, k, ambient: Double); var vec: TDouble3; x, y, b: Double; i, j, intensity: Integer; begin for i:= Floor(-R) to Ceil(R) do begin x := i + 0.5; for j:= Floor(-2*R) to Ceil(2 * R) do begin y:= j / 2 + 0.5; if(x * x + y * y <= R * R) then begin vec[0]:= x; vec[1]:= y; vec[2]:= sqrt(R * R - x * x - y * y); normalize(vec); b:= Power(dot(light, vec), k) + ambient; intensity:= IfThen(b <= 0, Length(shades) - 2, Trunc(max( (1 - b) * (Length(shades) - 1), 0 ))); Write(shades[intensity]); end else Write(' '); end; Writeln; end; end;
begin
normalize(light); drawSphere(19, 4, 0.1); drawSphere(10, 2, 0.4); Readln;
end. </lang>
Output:
&&&&&&&&&&####### &eeeeeooeeeeeeee&&&&&&####### eeooo*********oooooeeeee&&&&&#######% eo***!!!!!!!!!!!*****ooooeeee&&&&&#######%% eo**!!!::::::::::!!!!!****ooooeeee&&&&########%%% eo*!!::::........:::::!!!!****oooeeee&&&&########%%%% eo*!!::..............:::::!!!***ooooeeee&&&&#########%%%% eo*!!::..................:::!!!!***oooeeee&&&&&########%%%%%% eo*!::....................::::!!!***ooooeeee&&&&#########%%%%%% o**!::.....................::::!!!***ooooeeee&&&&#########%%%%%%% eo*!::......................::::!!!***ooooeeee&&&&##########%%%%%%% eo*!!::......................:::!!!!***ooooeee&&&&&##########%%%%%%%% eo**!!::.....................:::!!!!***ooooeeee&&&&&##########%%%%%%%%% &eo**!!::...................::::!!!!****oooeeeee&&&&&##########%%%%%%%%%% eeo**!!:::................:::::!!!!****ooooeeee&&&&&##########%%%%%%%%%%% &eoo**!!!::::............:::::!!!!****oooooeeee&&&&&###########%%%%%%%%%%%% &eeo***!!!::::::::::::::::::!!!!!****ooooeeeee&&&&&&##########%%%%%%%%%%%%% &eeoo***!!!!::::::::::::!!!!!!*****oooooeeeee&&&&&&###########%%%%%%%%%%%%% &&eeoo****!!!!!!!!!!!!!!!!!!*****oooooeeeee&&&&&&############%%%%%%%%%%%%%% &&eeeooo*****!!!!!!!!!!*******ooooooeeeeee&&&&&&############%%%%%%%%%%%%%%% #&&eeeoooo*****************oooooooeeeeee&&&&&&&############%%%%%%%%%%%%%%%% #&&&eeeeoooooooooooooooooooooooeeeeeee&&&&&&&#############%%%%%%%%%%%%%%%%% ##&&&&eeeeeoooooooooooooooeeeeeeeee&&&&&&&&##############%%%%%%%%%%%%%%%%%% ###&&&&eeeeeeeeeeeeeeeeeeeeeee&&&&&&&&&&##############%%%%%%%%%%%%%%%%%%% ####&&&&&&&eeeeeeeeeeeeeee&&&&&&&&&&&################%%%%%%%%%%%%%%%%%%%% #####&&&&&&&&&&&&&&&&&&&&&&&&&&&&#################%%%%%%%%%%%%%%%%%%%%% ########&&&&&&&&&&&&&&&&&&&####################%%%%%%%%%%%%%%%%%%%%%% ############################################%%%%%%%%%%%%%%%%%%%%%%% %#######################################%%%%%%%%%%%%%%%%%%%%%%%%% %%##################################%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%###########################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%#################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% ::...:::!!!*o ..............::!!*oo ..................::!!**ooe .....................::!!**ooee .......................::!!**ooee ........................::!!**oooee .........................::!!**oooeee :........................::!!!**oooeeee ........................::!!!**ooooeeee :......................::!!!***oooeeeee :....................:::!!!***oooeeeeee !:.................:::!!!****oooeeeeeee *!:::...........::::!!!!***ooooeeeeeeee *!!!:::::::::::!!!!!****oooooeeeeeeee o**!!!!!!!!!!!!!*****oooooeeeeeeeee oo**************ooooooeeeeeeeeeee eoooooooooooooooooeeeeeeeeeeeee eeeooooooooeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeee
DWScript
but adapted to spit out a PGM image
<lang delphi> type
TFloat3 = array[0..2] of Float;
var
light : TFloat3 = [ 30, 30, -50 ];
procedure normalize(var v : TFloat3); var
len: Float;
begin
len := sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); v[0] /= len; v[1] /= len; v[2] /= len;
end;
function dot(x, y : TFloat3) : Float; begin
Result := x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; if Result<0 then Result:=-Result else Result:=0;
end;
procedure drawSphere(R, k, ambient : Float); var
vec : TFloat3; x, y, b : Float; i, j, size, intensity : Integer;
begin
size:=Trunc(Ceil(R)-Floor(-R)+1); PrintLn('P2'); PrintLn(IntToStr(size)+' '+IntToStr(size)); PrintLn('255'); for i := Floor(-R) to Ceil(R) do begin x := i + 0.5; for j := Floor(-R) to Ceil(R) do begin y := j + 0.5; if (x * x + y * y <= R * R) then begin vec[0] := x; vec[1] := y; vec[2] := sqrt(R * R - x * x - y * y); normalize(vec); b := Power(dot(light, vec), k) + ambient; intensity := ClampInt( Round(b*255), 0, 255); Print(intensity); Print(' ') end else Print('0 '); end; PrintLn(); end;
end;
normalize(light); drawSphere(19, 4, 0.1); </lang>
Go
Using image library rather than ASCII art. <lang go>package main
import (
"fmt" "image" "image/color" "image/png" "math" "os"
)
type vector [3]float64
func normalize(v *vector) {
invLen := 1 / math.Sqrt(dot(v, v)) v[0] *= invLen v[1] *= invLen v[2] *= invLen
}
func dot(x, y *vector) float64 {
return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]
}
func drawSphere(r int, k, amb float64, dir *vector) *image.Gray {
w, h := r*4, r*3 img := image.NewGray(image.Rect(-w/2, -h/2, w/2, h/2)) vec := new(vector) for x := -r; x < r; x++ { for y := -r; y < r; y++ { if z := r*r - x*x - y*y; z >= 0 { vec[0] = float64(x) vec[1] = float64(y) vec[2] = math.Sqrt(float64(z)) normalize(vec) s := dot(dir, vec) if s < 0 { s = 0 } lum := 255 * (math.Pow(s, k) + amb) / (1 + amb) if lum < 0 { lum = 0 } else if lum > 255 { lum = 255 } img.SetGray(x, y, color.Gray{uint8(lum)}) } } } return img
}
func main() {
dir := &vector{-30, -30, 50} normalize(dir) img := drawSphere(200, 1.5, .2, dir) f, err := os.Create("sphere.png") if err != nil { fmt.Println(err) return } if err = png.Encode(f, img); err != nil { fmt.Println(err) } if err = f.Close(); err != nil { fmt.Println(err) }
}</lang>
Haskell
<lang haskell>import Graphics.Rendering.OpenGL.GL import Graphics.UI.GLUT.Objects import Graphics.UI.GLUT
setProjection :: IO () setProjection = do
matrixMode $= Projection ortho (-1) 1 (-1) 1 0 (-1)
grey1,grey9,red,white :: Color4 GLfloat grey1 = Color4 0.1 0.1 0.1 1 grey9 = Color4 0.9 0.9 0.9 1 red = Color4 1 0 0 1 white = Color4 1 1 1 1
setLights :: IO () setLights = do
let l = Light 0 ambient l $= grey1 diffuse l $= white specular l $= white position l $= Vertex4 (-4) 4 3 (0 :: GLfloat) light l $= Enabled lighting $= Enabled
setMaterial :: IO () setMaterial = do
materialAmbient Front $= grey1 materialDiffuse Front $= red materialSpecular Front $= grey9 materialShininess Front $= (32 :: GLfloat)
display :: IO() display = do
clear [ColorBuffer] renderObject Solid $ Sphere' 0.8 64 64 swapBuffers
main :: IO() main = do
_ <- getArgsAndInitialize _ <- createWindow "Sphere" clearColor $= Color4 0.0 0.0 0.0 0.0 setProjection setLights setMaterial displayCallback $= display mainLoop</lang>
Icon and Unicon
Unicon provides a built-in interface to openGL including some higher level abstractions (for more information see Unicon Technical References, 3D Graphics). The example below draws a blue sphere on a black background and waits for input to quit.
<lang Unicon>procedure main() W := open("Demo", "gl", "size=400,400", "bg=black") | stop("can't open window!") WAttrib(W, "slices=40", "rings=40", "light0=on, ambient white; diffuse gold; specular gold; position 5, 0, 0" ) Fg(W, "emission blue") DrawSphere(W, 0, 0, -5, 1) Event(W) end</lang>
J
The simplest way to draw a sphere is to run the sphere demo code from J's simple demos. (This assumes J version 6.)
Normally you would bring up this demo by using the menu system:
Studio > Demos... > opengl simple... [ok] > sphere [Run]
<lang j>load 'system/examples/graphics/opengl/simple/sphere.ijs'</lang>
Raytracing Solution
Here's a version using raytracing computed in J. luminosity is an array of luminosity values with theoretical maximum 1 and minimum 0, and viewmat is used to display this.
<lang j>'R k ambient' =. 10 2 0.4 light =. (% +/&.:*:) 30 30 _50 pts =. (0&*^:(0={:))@:(,,(0>.(*:R)-+)&.*:)"0/~ i:15j200 luminosity =. (>:ambient) %~ (ambient * * +/&.:*:"1 pts) + k^~ 0>. R%~ pts +/@:*"1 -light
load 'viewmat' togreyscale =. 256 #. [: <. 255 255 255 *"1 0 ] 'rgb' viewmat togreyscale luminosity</lang>
Java
<lang java>public class Sphere{
static char[] shades = {'.', ':', '!', '*', 'o', 'e', '&', '#', '%', '@'};
static double[] light = { 30, 30, -50 }; private static void normalize(double[] v){ double len = Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); v[0] /= len; v[1] /= len; v[2] /= len; }
private static double dot(double[] x, double[] y){ double d = x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; return d < 0 ? -d : 0; }
public static void drawSphere(double R, double k, double ambient){ double[] vec = new double[3]; for(int i = (int)Math.floor(-R); i <= (int)Math.ceil(R); i++){ double x = i + .5; for(int j = (int)Math.floor(-2 * R); j <= (int)Math.ceil(2 * R); j++){ double y = j / 2. + .5; if(x * x + y * y <= R * R) { vec[0] = x; vec[1] = y; vec[2] = Math.sqrt(R * R - x * x - y * y); normalize(vec); double b = Math.pow(dot(light, vec), k) + ambient; int intensity = (b <= 0) ? shades.length - 2 : (int)Math.max((1 - b) * (shades.length - 1), 0); System.out.print(shades[intensity]); } else System.out.print(' '); } System.out.println(); } }
public static void main(String[] args){ normalize(light); drawSphere(20, 4, .1); drawSphere(10, 2, .4); }
}</lang> Output:
&&&&&&&&&&####### &eeeeeeeeeeeeeeee&&&&&&#######% &eoooo*******oooooooeeeee&&&&&########% eoo****!!!!!!!!******oooooeeee&&&&&########%% eoo**!!!!::::::::!!!!!*****ooooeeee&&&&&########%%% eo**!!::::::...:::::::!!!!!***ooooeeee&&&&&########%%%% eo*!!:::.............:::::!!!!***ooooeeee&&&&&########%%%%% eo*!!:::.................::::!!!!***ooooeeee&&&&#########%%%%%% eo*!!::....................::::!!!****oooeeee&&&&&#########%%%%%% &o**!::......................::::!!!****oooeeee&&&&&##########%%%%%%% &o**!::.......................::::!!!****oooeeee&&&&&##########%%%%%%%% &oo*!!::.......................:::!!!!***ooooeeee&&&&&##########%%%%%%%%% &eo*!!::.......................::::!!!****ooooeeee&&&&&##########%%%%%%%%%% eo**!!::......................::::!!!!***ooooeeeee&&&&&##########%%%%%%%%%% &eo**!!:::...................:::::!!!!****ooooeeee&&&&&###########%%%%%%%%%%% eeo**!!::::................:::::!!!!!****ooooeeee&&&&&&###########%%%%%%%%%%% &eeo***!!:::::...........::::::!!!!!****oooooeeee&&&&&&###########%%%%%%%%%%%%% &eeoo**!!!!::::::::::::::::::!!!!!*****ooooeeeee&&&&&&############%%%%%%%%%%%%% &eeooo***!!!!::::::::::::!!!!!!!*****oooooeeeee&&&&&&############%%%%%%%%%%%%%% &&eeooo***!!!!!!!!!!!!!!!!!!!******oooooeeeeee&&&&&&############%%%%%%%%%%%%%%% &&eeeooo******!!!!!!!!!!********ooooooeeeeee&&&&&&&############%%%%%%%%%%%%%%%% #&&eeeooooo******************oooooooeeeeee&&&&&&&#############%%%%%%%%%%%%%%%%% #&&&eeeeoooooooo******oooooooooooeeeeeee&&&&&&&&#############%%%%%%%%%%%%%%%%%% ##&&&&eeeeeooooooooooooooooooeeeeeeee&&&&&&&&&##############%%%%%%%%%%%%%%%%%%% ##&&&&&eeeeeeeeeeeeeeeeeeeeeeeeee&&&&&&&&&################%%%%%%%%%%%%%%%%%%% ####&&&&&&eeeeeeeeeeeeeeeeeee&&&&&&&&&&&################%%%%%%%%%%%%%%%%%%%%% #####&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#################%%%%%%%%%%%%%%%%%%%%%% %#######&&&&&&&&&&&&&&&&&&&&&&&&###################%%%%%%%%%%%%%%%%%%%%%%%% %###########&&&&&&&&&&&&&#######################%%%%%%%%%%%%%%%%%%%%%%%%% %############################################%%%%%%%%%%%%%%%%%%%%%%%%%% %%#######################################%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%#################################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%#########################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%#############%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% ::...:::!!!*o ..............::!!*oo ..................::!!**ooe .....................::!!**ooee .......................::!!**ooee ........................::!!**oooee .........................::!!**oooeee :........................::!!!**oooeeee ........................::!!!**ooooeeee :......................::!!!***oooeeeee :....................:::!!!***oooeeeeee !:.................:::!!!****oooeeeeeee *!:::...........::::!!!!***ooooeeeeeeee *!!!:::::::::::!!!!!****oooooeeeeeeee o**!!!!!!!!!!!!!*****oooooeeeeeeeee oo**************ooooooeeeeeeeeeee eoooooooooooooooooeeeeeeeeeeeee eeeooooooooeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeee
Logo
Drawing a sphere is actually very simple in logo, using the perspective function to make life easier.
<lang logo>to sphere :r cs perspective ht ;making the room ready to use repeat 180 [polystart circle :r polyend down 1] polyview end</lang>
Liberty BASIC
<lang lb> WindowWidth =420 WindowHeight =460
nomainwin
open "Sphere" for graphics_nsb_nf as #w
- w "down ; fill lightgray"
xS =200 yS =200 for radius =150 to 0 step -1
level$ =str$( int( 256 -256 *radius /150)) c$ =level$ +" " +level$ +" " +level$ #w "color "; c$ #w "backcolor "; c$ #w "place "; xS; " "; yS xS =xS -0.5 yS =yS -0.2 #w "circlefilled "; radius
next radius
- w "flush"
wait close #w end </lang>
Lua
<lang Lua>require ("math")
shades = {'.', ':', '!', '*', 'o', 'e', '&', '#', '%', '@'}
function normalize (vec)
len = math.sqrt(vec[1]^2 + vec[2]^2 + vec[3]^2) return {vec[1]/len, vec[2]/len, vec[3]/len}
end
light = normalize{30, 30, -50}
function dot (vec1, vec2)
d = vec1[1]*vec2[1] + vec1[2]*vec2[2] + vec1[3]*vec2[3] return d < 0 and -d or 0
end
function draw_sphere (radius, k, ambient)
for i = math.floor(-radius),-math.floor(-radius) do x = i + .5 local line = for j = math.floor(-2*radius),-math.floor(-2*radius) do y = j / 2 + .5 if x^2 + y^2 <= radius^2 then vec = normalize{x, y, math.sqrt(radius^2 - x^2 - y^2)} b = dot(light,vec) ^ k + ambient intensity = math.floor ((1 - b) * #shades) line = line .. (shades[intensity] or shades[1]) else line = line .. ' ' end end print (line) end
end
draw_sphere (20, 4, 0.1) draw_sphere (10, 2, 0.4)</lang> Output:
&&&&&&&&&&&&##### &eeeoooooooooeeeeee&&&&&####### eooo*************oooooeeee&&&&&######## eo**!!!!!!!!!!!!!!!*****ooooeeee&&&&######### eo*!!!:::::...:::::::!!!!****oooeeee&&&&&########## o**!:::..............::::!!!!***ooooeee&&&&&########### o*!!::...................::::!!!***ooooeee&&&&&############ eo*!::......................::::!!!***oooeeee&&&&&############# o*!::.........................:::!!!***ooooeee&&&&&############## &o*!::..........................:::!!!***ooooeeee&&&&###############% eo*!::...........................:::!!!***ooooeeee&&&&&###############% eo*!::............................:::!!!***ooooeeee&&&&&###############%% &o*!!::...........................:::!!!!***oooeeee&&&&&#################%% eo*!!:...........................::::!!!***ooooeeee&&&&&#################%% eo**!!::.........................::::!!!****oooeeee&&&&&&#################%%% eo**!!::.......................::::!!!!****oooeeeee&&&&&##################%%% &eo**!!:::....................:::::!!!!***ooooeeeee&&&&&&##################%%%% &eoo**!!::::................:::::!!!!****ooooeeeee&&&&&&###################%%%% &eoo***!!!:::::........:::::::!!!!!****oooooeeeee&&&&&&###################%%%%% &eeoo***!!!!:::::::::::::::!!!!!!*****ooooeeeee&&&&&&&####################%%%%% &&eeoo****!!!!!!!!!!!!!!!!!!!!*****oooooeeeeee&&&&&&######################%%%%% &&eeeooo******!!!!!!!!!!!*******ooooooeeeeee&&&&&&&######################%%%%%% #&&eeeooooo******************oooooooeeeeee&&&&&&&#######################%%%%%%% ##&&&eeeeoooooooooo*ooooooooooooeeeeeeee&&&&&&&&#######################%%%%%%%% ##&&&eeeeeeooooooooooooooooeeeeeeeee&&&&&&&&&########################%%%%%%%% ###&&&&&eeeeeeeeeeeeeeeeeeeeeeee&&&&&&&&&&##########################%%%%%%%%% ####&&&&&&&eeeeeeeeeeeeeee&&&&&&&&&&&&############################%%%%%%%%% ######&&&&&&&&&&&&&&&&&&&&&&&&&&&&&##############################%%%%%%%%%% ########&&&&&&&&&&&&&&&&&&&&&&################################%%%%%%%%%%% ###############&&&&&#######################################%%%%%%%%%%%% #########################################################%%%%%%%%%%%% #####################################################%%%%%%%%%%%% #################################################%%%%%%%%%%%%%% #############################################%%%%%%%%%%%%%% ########################################%%%%%%%%%%%%%%% ##################################%%%%%%%%%%%%%%%%% %##########################%%%%%%%%%%%%%%%%%% %%%%############%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% ........::!!* ...............::!!*o ....................::!**oo .......................::!**ooo ........................::!!**ooo .........................::!!**oooo ..........................::!!**ooooe ...........................::!!**ooooee ..........................::!!***ooooee .........................::!!!**oooooee .......................:::!!!**oooooeee :.....................::!!!***ooooooeee !::................:::!!!!***ooooooeeee !!::..........:::::!!!****ooooooeeeee *!!!::::::::::!!!!!****oooooooeeeee o***!!!!!!!!!******ooooooooeeeeee ooo***********ooooooooooeeeeeee oooooooooooooooooooeeeeeeee eooooooooooeeeeeeeeee eeeeeeeeeeeee
Mathematica
Mathematica has many 3D drawing capabilities. To create a sphere with radius one centered at (0,0,0): <lang Mathematica>Graphics3D[Sphere[{0,0,0},1]]</lang>
Maxima
<lang maxima>/* Two solutions */ plot3d(1, [theta, 0, %pi], [phi, 0, 2 * %pi], [transform_xy, spherical_to_xyz], [grid, 30, 60], [box, false], [legend, false])$
load(draw)$ draw3d(xu_grid=30, yv_grid=60, surface_hide=true,
parametric_surface(cos(phi)*sin(theta), sin(phi)*sin(theta), cos(theta), theta, 0, %pi, phi, 0, 2 * %pi))$</lang>
Openscad
Drawing a sphere is easy in openscad:
<lang openscad>// This will produce a sphere of radius 5 sphere(5);</lang>
Pascal
After changing "{$APPTYPE CONSOLE}" to "{$mode delphi}" or "{$mode objfpc}" the Delphi example works with FreePascal.
Perl 6
Translation of C. Modified to output .pgm file.
<lang perl6>my $x = my $y = 255; $x +|= 1; # must be odd
my @light = normalize([ 3, 2, -5 ]);
my $depth = 255;
sub MAIN ($outfile = 'sphere-perl6.pgm') {
my $out = open( $outfile, :w, :bin ) or die "$!\n"; $out.say("P5\n$x $y\n$depth"); # .pgm header $out.print( draw_sphere( ($x-1)/2, .9, .2)».chrs ); $out.close;
}
sub normalize (@vec) { return @vec »/» ([+] @vec Z* @vec).sqrt }
sub dot (@x, @y) { return -([+] @x Z* @y) max 0 }
sub draw_sphere ( $rad, $k, $ambient ) {
my @pixels; my $r2 = $rad * $rad; my @range = -$rad .. $rad; for @range X @range -> $x, $y { if (my $x2 = $x * $x) + (my $y2 = $y * $y) < $r2 { my @vector = normalize([$x, $y, ($r2 - $x2 - $y2).sqrt]); my $intensity = dot(@light, @vector) ** $k + $ambient; my $pixel = (0 max ($intensity * $depth).Int) min $depth; @pixels.push($pixel); } else { @pixels.push(0); } } return @pixels;
}</lang>
PicoLisp
This is for the 64-bit version. <lang PicoLisp>(load "@lib/openGl.l")
(glutInit) (glutInitDisplayMode (| GLUT_RGBA GLUT_DOUBLE GLUT_ALPHA GLUT_DEPTH)) (glutInitWindowSize 400 400) (glutCreateWindow "Sphere")
(glEnable GL_LIGHTING) (glEnable GL_LIGHT0) (glLightiv GL_LIGHT0 GL_POSITION (10 10 -10 0))
(glEnable GL_COLOR_MATERIAL) (glColorMaterial GL_FRONT_AND_BACK GL_AMBIENT_AND_DIFFUSE)
(glClearColor 0.3 0.3 0.5 0) (glColor4f 0.0 0.8 0.0 1.0)
(displayPrg
(glClear (| GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT)) (glutSolidSphere 0.9 40 32) (glFlush) (glutSwapBuffers) )
- Exit upon mouse click
(mouseFunc '((Btn State X Y) (bye))) (glutMainLoop)</lang>
<lang PicoLisp>(scl 24)
(setq *Shades
(list "." ":" "!" "*" "o" "e" "&" "#" "%" "@"))
(setq *Light
(list 30.0 30.0 -50.0))
(de normalize (V)
(let Len (sqrt (sum (quote (X) (** X 2)) V)) (mapcar (quote (X) (*/ X 1.0 Len)) V)))
(de dot (X Y)
(let D (sum (quote (A B) (*/ A B 1.0)) X Y) (if (< D 0) (- D) 0)))
(de floor (N)
(* 1.0 (*/ (- N 0.5) 1.0)))
(de ceil (N)
(* 1.0 (*/ (+ N 0.5) 1.0)))
(de drawSphere (R K Ambient)
(let Vec NIL (for (I (floor (- R)) (<= I (ceil R)) (+ I 1.0)) (let X (+ I 0.5) (for (J (floor (* -2 R)) (<= J (ceil (* 2 R))) (+ J 1.0)) (let Y (+ (/ J 2) 0.5) (if (<= (+ (*/ X X 1.0) (*/ Y Y 1.0)) (*/ R R 1.0)) (prog (setq Vec (list X Y (sqrt (* 1.0 (- (*/ R R 1.0) (*/ X X 1.0) (*/ Y Y 1.0)))))) (setq Vec (normalize Vec)) (let (B NIL Intensity NIL) (setq B (+ (/ (** (dot *Light Vec) K) (** 1.0 (- K 1))) Ambient)) (setq Intensity (if (<= B 0) (- (length *Shades) 2) (max (format (round (*/ (- 1.0 B) (* (- (length *Shades) 1) 1.0) 1.0) 0)) 0))) (prin (nth *Shades (+ Intensity 1) 1)))) (prin " ")))) (prinl)))))
(setq *Light (normalize *Light)) (drawSphere 20.0 4 0.1) (drawSphere 10.0 2 0.4)</lang> Output:
##############%%% #&&eeeeeeeeeee&&&&&&######%%%%% &eeeoooooooooooooeeeee&&&&&######%%%%%% &eooo**************oooooeeee&&&&&#####%%%%%%% &eoo**!!!!!!!!!!!!!!*****ooooeeee&&&&######%%%%%%%% eoo**!!!::::::::::::!!!!****ooooeeee&&&&######%%%%%%%%% eoo*!!!::::.......::::::!!!!****oooeeee&&&&######%%%%%%%%%% &eo*!!:::..............::::!!!!***ooooeeee&&&&######%%%%%%%%%%% eo**!!::.................::::!!!****oooeeee&&&&######%%%%%%%%%%%% &eo*!!:::..................::::!!!!***oooeeee&&&&&######%%%%%%%%%%%%% &eo*!!:::...................::::!!!!***oooeeee&&&&&######%%%%%%%%%%%%%% &eo**!!::....................::::!!!****oooeeee&&&&&######%%%%%%%%%%%%%%% #eoo*!!:::...................::::!!!!***ooooeeee&&&&#######%%%%%%%%%%%%%%%% &eo**!!:::.................:::::!!!!****oooeeee&&&&&#######%%%%%%%%%%%%%%%% &eoo**!!::::...............:::::!!!!****ooooeeee&&&&#######%%%%%%%%%%%%%%%%%% &eoo**!!!::::...........::::::!!!!*****ooooeeee&&&&&#######%%%%%%%%%%%%%%%%%% #&eoo***!!!::::::::::::::::::!!!!!****ooooeeeee&&&&&#######%%%%%%%%%%%%%%%%%%%% #&eeoo***!!!!::::::::::::!!!!!!!*****ooooeeeee&&&&&#######%%%%%%%%%%%%%%%%%%%%% #&eeooo****!!!!!!!!!!!!!!!!!!******ooooeeeee&&&&&&#######%%%%%%%%%%%%%%%%%%%%%% #&&eeooo******!!!!!!!!!!!*******ooooooeeeee&&&&&&#######%%%%%%%%%%%%%%%%%%%%%%% #&&&eeooooo******************ooooooeeeeee&&&&&&########%%%%%%%%%%%%%%%%%%%%%%%% ##&&&eeeooooooo********oooooooooeeeeeee&&&&&&#########%%%%%%%%%%%%%%%%%%%%%%%%% ###&&&eeeeeooooooooooooooooooeeeeeee&&&&&&&&#########%%%%%%%%%%%%%%%%%%%%%%%%%% %###&&&&eeeeeeeeeeeoeeeeeeeeeeeee&&&&&&&&##########%%%%%%%%%%%%%%%%%%%%%%%%%%%% %####&&&&&eeeeeeeeeeeeeeeeee&&&&&&&&&&##########%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%#####&&&&&&&&&&&&&&&&&&&&&&&&&&&############%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%#######&&&&&&&&&&&&&&&&&&&&##############%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%############&&&&&###################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%##############################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%#######################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%#########%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%% !::::::!!!**o ............:::!!**oe :................::!!**ooee :...................::!!**ooeee ......................::!!**ooeee .......................::!!**ooeeee .......................:::!!**ooeeeee :.......................::!!***ooeeeeee :......................::!!!**oooeeeeee :....................:::!!!**oooeeeeeee !:..................:::!!***oooeeeeeeee !!:..............::::!!!***oooeeeeeeeee *!!::::.....::::::!!!!***ooooeeeeeeeeee o*!!!!::::::!!!!!!****ooooeeeeeeeeeee o****!!!!!!!******oooooeeeeeeeeeeee eooo********oooooooeeeeeeeeeeeeee eeeoooooooooooeeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeee
PostScript
Gradient filled circle: <lang PostScript>%!PS-Adobe-3.0 %%BoundingBox 0 0 300 300
150 150 translate 0 0 130 0 360 arc
/Pattern setcolorspace << /PatternType 2
/Shading << /ShadingType 3 /ColorSpace /DeviceRGB /Coords [-60 60 0 0 0 100] /Function << /FunctionType 2 /Domain [0 1] /C0 [1 1 1] /C1 [0 0 0] /N 2 >> >>
>> matrix makepattern setcolor fill
showpage %%EOF </lang>
POV-Ray
This is what POVray was made for. An example with a sky, surface and transparency:
<lang POVray> camera { location <0.0 , .8 ,-3.0> look_at 0}
light_source{< 3,3,-3> color rgb 1}
sky_sphere { pigment{ gradient <0,1,0> color_map {[0 color rgb <.2,.1,0>][.5 color rgb 1]} scale 2}}
plane {y,-2 pigment { hexagon color rgb .7 color rgb .5 color rgb .6 }}
sphere { 0,1
texture { pigment{ color rgbft <.8,1,1,.4,.4> } finish { phong 1 reflection {0.40 metallic 0.5} } } interior { ior 1.5}
} </lang>
Yields this:
PureBasic
3D Sphere animation. <lang PureBasic>; Original by Comtois @ 28/03/06
- Updated/Formated by Fluid Byte @ March.24,2009
- http://www.purebasic.fr/english/viewtopic.php?p=281258#p281258
Declare CreateSphere(M,P) Declare UpdateMesh()
- _SIZEVERT = 36
- _SIZETRIS = 6
- FULLSCREEN = 0
Structure VECTOR
X.f Y.f Z.f
EndStructure
Structure VERTEX
X.f Y.f Z.f NX.f NY.f NZ.f Color.l U.f V.f
EndStructure
Structure TRIANGLE
V1.w V2.w V3.w
EndStructure
Macro CALC_NORMALS
*PtrV\NX = *PtrV\X *PtrV\NY = *PtrV\Y *PtrV\NZ = *PtrV\Z
EndMacro
Global *VBuffer, *IBuffer Global Meridian = 50, Parallele = 50, PasLength = 4, Length
Define EventID, i, NbSommet, CameraMode, Angle.f, Pas.f = 0.5
InitEngine3D() : InitSprite() : InitKeyboard()
Add3DArchive(GetTemporaryDirectory(),#PB_3DArchive_FileSystem) Add3DArchive(#PB_Compiler_Home + "Examples\Sources\Data\",#PB_3DArchive_FileSystem)
If #FULLSCREEN
OpenScreen(800,600,32,"Sphere 3D")
Else
OpenWindow(0,0,0,800,600,"Sphere 3D",#PB_Window_SystemMenu | 1) OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0)
EndIf
- -Texture
CreateImage(0,128,128) StartDrawing(ImageOutput(0)) For i = 0 To 127 Step 4
Box(0,i,ImageWidth(0),2,RGB(255,255,255)) Box(0,i + 2,ImageWidth(0),2,RGB(0,0,155))
Next i StopDrawing() SaveImage(0,GetTemporaryDirectory() + "temp.bmp") : FreeImage(0)
- -Material
CreateMaterial(0,LoadTexture(0,"temp.bmp")) RotateMaterial(0,0.1,#PB_Material_Animated)
- -Mesh
CreateSphere(Meridian,Parallele)
- -Entity
CreateEntity(0,MeshID(0),MaterialID(0)) ScaleEntity(0,60,60,60)
- -Camera
CreateCamera(0,0,0,100,100) MoveCamera(0,0,0,-200) CameraLookAt(0,EntityX(0),EntityY(0),EntityZ(0))
- -Light
AmbientColor(RGB(105, 105, 105)) CreateLight(0, RGB(255, 255, 55), EntityX(0) + 150, EntityY(0) , EntityZ(0)) CreateLight(1, RGB( 55, 255, 255), EntityX(0) - 150, EntityY(0) , EntityZ(0)) CreateLight(2, RGB( 55, 55, 255), EntityX(0) , EntityY(0) + 150, EntityZ(0)) CreateLight(3, RGB(255, 55, 255), EntityX(0) , EntityY(0) - 150, EntityZ(0))
- ----------------------------------------------------------------------------------------------------
- MAINLOOP
- ----------------------------------------------------------------------------------------------------
Repeat
If #FULLSCREEN = 0 Repeat EventID = WindowEvent() Select EventID Case #PB_Event_CloseWindow : End EndSelect Until EventID = 0 EndIf Angle + Pas RotateEntity(0, Angle, Angle,Angle) If PasLength > 0 : UpdateMesh() : EndIf If ExamineKeyboard() If KeyboardReleased(#PB_Key_F1) CameraMode = 1 - CameraMode CameraRenderMode(0, CameraMode) EndIf EndIf RenderWorld() FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
- ----------------------------------------------------------------------------------------------------
- FUNCTIONS
- ----------------------------------------------------------------------------------------------------
Procedure CreateSphere(M,P)
; M = Meridian ; P = Parallele ; The radius is 1. Front to remove it later, it's just for the demo. If M < 3 Or P < 2 : ProcedureReturn 0 : EndIf Protected Normale.VECTOR, NbSommet, i, j, Theta.f, cTheta.f, sTheta.f Protected Alpha.f, cAlpha.f, sAlpha.f, *PtrV.VERTEX, *PtrF.TRIANGLE, NbTriangle NbSommet = 2 + ((M + 1) * P) *VBuffer = AllocateMemory(#_SIZEVERT * Nbsommet) For i = 0 To M Theta = i * #PI * 2.0 / M cTheta = Cos(theta) sTheta = Sin(theta) For j = 1 To P Alpha = j * #PI / (P + 1) cAlpha = Cos(Alpha) sAlpha = Sin(Alpha) *PtrV = *VBuffer + #_SIZEVERT * ((i * P) + (j - 1)) *PtrV\X = sAlpha * cTheta *PtrV\Y = sAlpha * sTheta *PtrV\Z = cAlpha *PtrV\U = Theta / (2.0 * #PI) *PtrV\V = Alpha / #PI CALC_NORMALS Next j Next i ; Southpole *PtrV = *VBuffer + #_SIZEVERT * ((M + 1) * P) *PtrV\X = 0 *PtrV\Y = 0 *PtrV\Z = -1 *PtrV\U = 0 *PtrV\V = 0 CALC_NORMALS ; Northpole *PtrV + #_SIZEVERT *PtrV\X = 0 *PtrV\Y = 0 *PtrV\Z = 1 *PtrV\U = 0 *PtrV\V = 0 CALC_NORMALS ; Les facettes NbTriangle = 4 * M * P *IBuffer = AllocateMemory(#_SIZETRIS * NbTriangle) *PtrF = *IBuffer For i = 0 To M - 1 For j = 1 To P - 1 *PtrF\V1 = ((i + 1) * P) + j *PtrF\V2 = ((i + 1) * P) + (j - 1) *PtrF\V3 = (i * P) + (j - 1) *PtrF + #_SIZETRIS *PtrF\V3 = ((i + 1) * P) + j ;Recto *PtrF\V2 = ((i + 1) * P) + (j - 1) ;Recto *PtrF\V1 = (i * P) + (j - 1) ;Recto *PtrF + #_SIZETRIS *PtrF\V1 = i * P + j *PtrF\V2 = ((i + 1) * P) + j *PtrF\V3 = (i * P) + (j - 1) *PtrF + #_SIZETRIS *PtrF\V3 = i * P + j ;Recto *PtrF\V2 = ((i + 1) * P) + j ;Recto *PtrF\V1 = (i * P) + (j - 1) ;Recto *PtrF + #_SIZETRIS Next j Next i ; The Poles For i = 0 To M - 1 *PtrF\V3 = (M + 1) * P + 1 *PtrF\V2 = (i + 1) * P *PtrF\V1 = i * P *PtrF + #_SIZETRIS *PtrF\V1 = (M + 1) * P + 1 ;Recto *PtrF\V2 = (i + 1) * P ;Recto *PtrF\V3 = i * P ;Recto *PtrF + #_SIZETRIS Next i For i = 0 To M - 1 *PtrF\V3 = (M + 1) * P *PtrF\V2 = i * P + (P - 1) *PtrF\V1 = (i + 1) * P + (P - 1) *PtrF + #_SIZETRIS *PtrF\V1 = (M + 1) * P ;Recto *PtrF\V2 = i * P + (P - 1) ;Recto *PtrF\V3 = (i + 1) * P + (P - 1) ;Recto *PtrF + #_SIZETRIS Next i If CreateMesh(0,100) Protected Flag = #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_UVCoordinate | #PB_Mesh_Color SetMeshData(0,Flag,*VBuffer,NbSommet) SetMeshData(0,#PB_Mesh_Face,*IBuffer,NbTriangle) ProcedureReturn 1 EndIf ProcedureReturn 0
EndProcedure
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure UpdateMesh()
Protected NbTriangle = 4 * Meridian * Parallele Length + PasLength If Length >= NbTriangle PasLength = 0 Length = Nbtriangle EndIf SetMeshData(0,#PB_Mesh_Face,*IBuffer,Length)
Python
<lang python>import math
shades = ('.',':','!','*','o','e','&','#','%','@')
def normalize(v): len = math.sqrt(v[0]**2 + v[1]**2 + v[2]**2) return (v[0]/len, v[1]/len, v[2]/len)
def dot(x,y): d = x[0]*y[0] + x[1]*y[1] + x[2]*y[2] return -d if d < 0 else 0
def draw_sphere(r, k, ambient, light): for i in range(int(math.floor(-r)),int(math.ceil(r)+1)): x = i + 0.5 line =
for j in range(int(math.floor(-2*r)),int(math.ceil(2*r)+1)): y = j/2 + 0.5 if x*x + y*y <= r*r: vec = normalize((x,y,math.sqrt(r*r - x*x - y*y))) b = dot(light,vec)**k + ambient intensity = int((1-b)*(len(shades)-1)) line += shades[intensity] if 0 <= intensity < len(shades) else shades[0] else: line += ' '
print(line)
light = normalize((30,30,-50)) draw_sphere(20,4,0.1, light) draw_sphere(10,2,0.4, light)</lang> Output:
&&&&&&&&&&###### &&eeeeeeeeeeeeeeee&&&&&&######%% &&oooo********ooooooeeeeee&&&&########%% oo****!!!!!!!!******ooooooeeee&&&&########%% eeoo**!!!!::::::::!!!!******ooooeeee&&&&########%%%% ee**!!::::::....::::::!!!!!!**ooooeeee&&&&&&########%%%% ee**!!::..............::::!!!!****ooooeeee&&&&########%%%%%% ee**!!::..................::::!!!!**ooooeeee&&&&##########%%%%%% oo!!::....................::::!!!!****ooeeee&&&&&&########%%%%%% oo**::......................::::!!!!****ooeeee&&&&&&##########%%%%%% &&**!!::......................::::!!!!****ooeeee&&&&&&##########%%%%%%%% oo**!!::......................::::!!!!**ooooeeee&&&&&&##########%%%%%%%% &&oo!!::........................::::!!****ooooeeee&&&&&&##########%%%%%%%%%% ee**!!::......................::::!!!!****ooooeeee&&&&&&##########%%%%%%%%%% ee**!!::::..................::::::!!!!****ooooeeee&&&&############%%%%%%%%%% ee**!!::::................::::::!!!!****ooooeeee&&&&&&############%%%%%%%%%% &&ee****!!::::............::::::!!!!****ooooooeeee&&&&&&##########%%%%%%%%%%%%%% &&eeoo**!!!!::::::::::::::::::!!!!******ooooeeee&&&&&&############%%%%%%%%%%%%%% &&eeoo****!!!!::::::::::::!!!!!!******ooooeeeeee&&&&&&############%%%%%%%%%%%%%% &&eeoooo**!!!!!!!!!!!!!!!!!!!!******ooooeeeeee&&&&&&############%%%%%%%%%%%%%%%% &&eeeeoo******!!!!!!!!!!********ooooooeeeeee&&&&&&&&############%%%%%%%%%%%%%%%% ##&&eeoooooo******************ooooooeeeeee&&&&&&&&############%%%%%%%%%%%%%%%%%% ##&&eeeeoooooooo******ooooooooooooeeeeee&&&&&&&&##############%%%%%%%%%%%%%%%%%% ##&&&&eeeeeeooooooooooooooooooeeeeeeee&&&&&&&&##############%%%%%%%%%%%%%%%%%%%% ##&&&&eeeeeeeeeeeeeeeeeeeeeeeeee&&&&&&&&&&################%%%%%%%%%%%%%%%%%% ####&&&&&&eeeeeeeeeeeeeeeeee&&&&&&&&&&&&################%%%%%%%%%%%%%%%%%%%% ######&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&##################%%%%%%%%%%%%%%%%%%%%%% %%######&&&&&&&&&&&&&&&&&&&&&&&&####################%%%%%%%%%%%%%%%%%%%%%%%% ############&&&&&&&&&&&&########################%%%%%%%%%%%%%%%%%%%%%%%% %%############################################%%%%%%%%%%%%%%%%%%%%%%%%%% %%######################################%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%################################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%########################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%##############%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%% ::..::::!!** ..............::!!oo ..................::!!**ooee ......................::!!**ooee ......................::!!**ooee ........................::!!**ooooee ........................::!!**ooooee ::........................::!!**ooooeeee ........................::!!!!**ooooeeee ::......................::!!****ooeeeeee ::....................::!!!!**ooooeeeeee !!..................::!!!!****ooeeeeeeee **::::..........::::!!!!****ooooeeeeeeee !!!!::::::::::!!!!!!****ooooeeeeeeee oo**!!!!!!!!!!!!******ooooeeeeeeeeee oo**************ooooooeeeeeeeeee eeooooooooooooooooeeeeeeeeeeeeee eeeeooooooooeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeee eeeeeeeeeeee
Python: Using Pygame
Renders a sphere with random Perlin noise. This code contains unnecessary functions which are part of a 3D graphics library I wrote. Uses Pygame and Python 3.2.2 <lang python> import pygame from pygame.locals import * import time import sys import random import math class Tricubic:
def __init__(self,pts): self.coefficients = [] for plane in pts: planecoeffs = [] for line in plane: p = (line[3]-line[2])-(line[0]-line[1]) q = (line[0]-line[1])-p r = line[2]-line[0] s = line[1] planecoeffs.append([p,q,r,s]) self.coefficients.append(planecoeff) def Eval(at): return Misc.Cubic([CoeffBicubic(coeffs[0],d),CoeffBicubic(coeffs[1],d),CoeffBicubic(coeffs[2],d),CoeffBicubic(coeffs[3],d)],d.z) def CoeffCubic(coeffs,d): return (coeffs[0]*(d.x**3))+(coeffs[1]*(d.x**2))+(coeffs[2]*d.x)+coeffs[3] def CoeffBicubic(coeffs,d): return Misc.Cubic([CoeffCubic(coeffs[0],d),CoeffCubic(coeffs[1],d),CoeffCubic(coeffs[2],d),CoeffCubic(coeffs[3],d)],d.y)
class Misc:
def LinePara(line,t): return Vector3.Add(line[0],Vector3.Scale(Vector3.Subtract(line[1],line[0]),t)) def LUR(at,above): look = at.Unit() right = Vector3.Cross(look,above).Unit() up = Vector3.Scale(Vector3.Cross(look,right),-1) return [look,up,right] def LinePlane(line,triangle,cp=True): try: u = Vector3.Subtract(triangle.points[1].point,triangle.points[0]) v = Vector3.Subtract(triangle.points[2],triangle.points[0]) n = Vector3.Cross(u,v) r = (Vector3.Dot(n,Vector3.Subtract(triangle.points[0],line.start))/Vector3.Dot(n,line.direction)) if stp: point = Vector3.Add(Vector3.Scale(line.direction,r),line.start) w = Vector3.Subtract(point,triangle.points[0]) udv = Vector3.Dot(u,v) wdv = Vector3.Dot(w,v) vdv = Vector3.Dot(v,v) wdu = Vector3.Dot(w,u) udu = Vector3.Dot(u,u) denominator = (udv**2)-(udu*vdv) s = ((udv*wdv)-(vdv*wdu))/denominator t = ((udv*wdu)-(udu*wdv))/denominator return [r,Vector2(s,t),point] print('hooray') else: return [r] except: return None def Cubic(pts,d): p = (pts[3]-pts[2])-(pts[0]-pts[1]) q = (pts[0]-pts[1])-p r = pts[2]-pts[0] s = pts[1] return (p*(d**3))+(q*(d**2))+(r*d)+s def Bicubic(pts,d): return Misc.Cubic([Misc.Cubic(pts[0],d.x),Misc.Cubic(pts[1],d.x),Misc.Cubic(pts[2],d.x),Misc.Cubic(pts[3],d.x)],d.y) def Tricubic(pts,d): return Misc.Cubic([Misc.Bicubic(pts[0],d),Misc.Bicubic(pts[1],d),Misc.Bicubic(pts[2],d),Misc.Bicubic(pts[3],d)],d.z) def Quadcubic(pts,d): return Misc.Cubic([Misc.Tricubic(pts[0],d),Misc.Tricubic(pts[1],d),Misc.Tricubic(pts[2],d),Misc.Tricubic(pts[3],d)],d.w) def Linear(pts,d): return (pts[2]*d)+(pts[1]*(1-d)) def Bilinear(pts,d): return Misc.Linear([0,Misc.Linear(pts[1],d.x),Misc.Linear(pts[2],d.x)],d.y) def Trilinear(pts,d): return Misc.Linear([0,Misc.Bilinear(pts[1],d),Misc.Bilinear(pts[2],d)],d.z) def LP2(line,triangle,cp=True): try: bla = triangle.points[1] bla = triangle.points[0] u = Vector3.Subtract(triangle.points[1].point,triangle.points[0].point) v = Vector3.Subtract(triangle.points[2].point,triangle.points[0].point) n = Vector3.Cross(u,v) d = Vector3.Subtract(line[1],line[0]) r = (Vector3.Dot(n,Vector3.Subtract(triangle.points[0].point,line[0]))/Vector3.Dot(n,d)) if cp: point = Vector3.Add(Vector3.Scale(d,r),line[0]) w = Vector3.Subtract(point,triangle.points[0].point) udv = Vector3.Dot(u,v) wdv = Vector3.Dot(w,v) vdv = Vector3.Dot(v,v) wdu = Vector3.Dot(w,u) udu = Vector3.Dot(u,u) denominator = (udv**2)-(udu*vdv) s = ((udv*wdv)-(vdv*wdu))/denominator t = ((udv*wdu)-(udu*wdv))/denominator return (r,Vector2(s,t),point) else: return (r) except: return None def Phong(normal,viewer,light,material,term): # light (vector_to,diffuse,specular) # material (ambient,diffuse,specular,shininess) n = normal.Unit() v = viewer.Unit() l = light[0].Unit() ldn = Vector3.Dot(l,n) #print(ldn) val = 0 if ldn > 0: val += material[1][term]*ldn*light[1][term] rdv = Vector3.Dot(Vector3.Subtract(Vector3.Scale(n,2*ldn),l),v) if rdv > 0: val += (material[2][term]*(rdv**material[3])*light[2][term]) #print(val) return val def Lighting(ambient,normal,viewer,lights,material,term): # lights [(vector_to,diffuse,specular)] # material (ambient,diffuse,specular,shininess) val = material[0][term]*ambient[term] for light in lights: val += Misc.Phong(normal,viewer,light,material,term) return val def Lighting2(start,direction,ambient,intersect,triangle,lights): coord = intersect[1] val = Color.Add(Color.Multiply(ambient,Color.Multiply(triangle.material.color['ambient'],triangle.Map('ambient',coord))), Color.Multiply(triangle.material.color['glow'],triangle.Map('glow',coord))) for light in lights: for n in range(3): val[n] += Misc.Phong(triangle.InterpolatedNormal(coord), Vector3.Scale(direction,-1), (light.To(intersect[2]),light.Diffuse(intersect[2]),light.Specular(intersect[2])), (Color(), Color.Multiply(triangle.material.color['diffuse'],triangle.Map('diffuse',coord)), Color.Multiply(triangle.material.color['specular'],triangle.Map('specular',coord)), triangle.material.shiny),n) return val def Ray(start,direction,scene,color=True,sector=None): intersect = None intersected = None col = None for triangle in scene.triangles: possible = True if sector != None: possible = False for point in triangle.points: if not(point.sector.x < sector.x): possible = True if possible: possible = False for point in triangle.points: if not(point.sector.x > sector.x): possible = True if possible: possible = False for point in triangle.points: if not(point.sector.y < sector.y): possible = True if possible: possible = False for point in triangle.points: if not(point.sector.y > sector.y): possible = True possible = True if possible: tmp = Misc.LP2([start,Vector3.Add(start,direction)],triangle,color) write = False if type(tmp) == type(5.1): tmp = None if (tmp != None): if (intersect == None): if (tmp[0] > 0) and (tmp[1].x >= 0) and (tmp[1].y >= 0) and (tmp[1].x+tmp[1].y <= 1): write = True elif (tmp[0] > 0) and (tmp[0] < intersect[0]) and (tmp[1].x >= 0) and (tmp[1].y >= 0) and (tmp[1].x+tmp[1].y <= 1): write = True if write: intersect = tmp intersected = triangle if color and (intersect != None): applicable = [] for light in scene.lights: block = Misc.Ray(intersect[2],light.To(intersect[2]),scene,False) if block == None: applicable.append(light) elif light.location != None: if Vector3.Subtract(light.location,intersect[2]).Magnitude() < block[0]: applicable.append(light) col = Misc.Lighting2(start,direction,scene.ambient,intersect,intersected,applicable) return (intersect,col) else: return intersect
class DirLight:
def __init__(self,direction,diffuse,specular): self.location = None self.direction = direction.Unit() self.diffuse = diffuse self.specular = specular def To(self,frm): return Vector3.Scale(self.direction,-1) def Diffuse(self,to): return self.diffuse def Specular(self,to): return self.specular
class Material:
def __init__(self): self.color = {'ambient':Color(1,1,1), 'diffuse':Color(1,1,1), 'specular':Color(1,1,1), 'glow':Color(1,1,1)} self.maps = {'ambient':Map(), 'diffuse':Map(), 'specular':Map(), 'glow':Map(), 'bump':Map()} self.shiny = 10
class Map:
def __init__(self,surface=None): self.surface = surface if self.surface != None: self.width = self.surface.get_width() self.height = self.surface.get_height() def __getitem__(self,index): if self.surface == None: return Color(1,1,1) else: try: return Color.From255(self.surface.get_at((int(index.x*(self.width-1)),int(index.y*(self.height-1))))) except: return Color(0,0,1)
class Color:
def __init__(self,r=0,g=0,b=0): self.r = r self.g = g self.b = b def __getitem__(self,index): if index == 0: return self.r elif index == 1: return self.g elif index == 2: return self.b def __setitem__(self,index,value): if index == 0: self.r = value elif index == 1: self.g = value elif index == 2: self.b = value def Multiply(A,B): return Color(A.r*B.r,A.g*B.g,A.b*B.b) def Add(A,B): return Color(A.r+B.r,A.g+B.g,A.b+B.b) def From255(A): return Color(A.r/255,A.g/255,A.b/255)
class Vertex:
def __init__(self,point,normal,maps): self.bpoint = point self.bnormal = normal self.maps = maps for name in ['ambient','diffuse','specular','glow','bump']: try: bla = self.maps[name] except: self.maps[name] = Vector2() self.sector = None def Transform(self,points,norms): self.point = Matrix2.Multiply(self.bpoint.Horizontal(),points).Vectorize() self.normal = Matrix2.Multiply(self.bnormal.Horizontal(),norms).Vectorize()
class Triangle:
def __init__(self,vertices,material=Material()): self.points = vertices self.material = material def Map(self,name,coord): pts = [] for n in range(3): pts.append(self.points[n].maps[name]) loc = Vector2.Add(pts[0], Vector2.Add(Vector2.Scale(Vector2.Subtract(pts[1],pts[0]),coord.x), Vector2.Scale(Vector2.Subtract(pts[2],pts[0]),coord.y))) #print(loc.x,loc.y) return self.material.maps[name][loc] def InterpolatedNormal(self,coord): return Vector3.Add(Vector3.Scale(self.points[0].normal,1-coord.x-coord.y), Vector3.Add(Vector3.Scale(self.points[1].normal,coord.x),Vector3.Scale(self.points[2].normal,coord.y))).Unit()
class Line:
def __init__(self,A,B=None,direction=None): self.start = A if B != None: self.direction = Vector3.Subtract(B,A).Unit() elif direction != None: self.direction = direction else: raise RuntimeError('Neither B nor direction are specified')
class Scene:
def __init__(self): self.triangles = [] self.vertices = [] self.lights = [] self.exterior = [] self.ambient = 0
class Matrix2:
def __init__(self,data=[[]]): self.FromData(data) def __getitem__(self,index): return self.data[index[1]][index[0]] def __setitem__(self,index,value): self.data[index[1]][index[0]]=value def Dimension(self): self.rows = len(self.data) self.cols = len(self.data[0]) def FromData(self,data): self.data = data length=len(data[0]) for row in data: if len(row)!=length: self.data=None raise RuntimeError('Data rows are not of uniform length.') self.Dimension() def Multiply(A,B): if A.cols!=B.rows: raise RuntimeError('Column count of Matrix2 \"A\" does not match row count of Matrix2 \"B\".') matrix = Matrix2.Empty(B.cols,A.rows) x=0 while x<matrix.cols: y=0 while y<matrix.rows: val=0 n=0 while n<A.cols: val+=A[(n,y)]*B[(x,n)] n+=1 matrix[(x,y)]=val y+=1 x+=1 return matrix def Scalar(A,n): pass def Empty(rows,cols): data = [] row = [0]*rows n = 0 while n < cols: data.append(row[:]) n+=1 matrix=Matrix2(data) matrix.Dimension() return matrix def Identity(cols): matrix = Matrix2.Empty(cols,cols) n = 0 while n < cols: matrix[(n,n)]=1 n += 1 return matrix def Vectorize(self): if self.cols==1: if self.rows!=4: raise RuntimeError('Only 1 by 4 or 4 by 1 Matrix2s can be cast to Vector3s.') vertical=True elif self.rows==1: if self.cols!=4: raise RuntimeError('Only 1 by 4 or 4 by 1 Matrix2s can be cast to Vector3s.') vertical = False else: raise RuntimeError('Only 1 by 4 or 4 by 1 Matrix2s can be cast to Vector3s.') vector=[0]*4 n=0 while n<4: if vertical: vector[n]=self[(0,n)] else: vector[n]=self[(n,0)] n+=1 return Vector3(vector[0],vector[1],vector[2],vector[3]) def Print(self,decimals,spaces): length=0 for row in self.data: for val in row: string=str(round(val,decimals)) if length<len(string): length=len(string) text= for row in self.data: temp= for value in row: val=str(round(float(value),decimals)) pads=length-len(val) pad=int(pads/2) temp+=(' '*pad)+val+(' '*(pads-pad))+(' '*spaces) text+=(' '*spaces)+temp[0:len(temp)-1]+(' '*spaces)+'\n' return(text[0:len(text)-1]) def RotX(angle): return Matrix2([ [1,0,0,0], [0,math.cos(angle),0-math.sin(angle),0], [0,math.sin(angle),math.cos(angle),0], [0,0,0,1]]) def RotY(angle): return Matrix2([ [math.cos(angle),0,0-math.sin(angle),0], [0,1,0,0], [math.sin(angle),0,math.cos(angle),0], [0,0,0,1]]) def RotZ(angle): return Matrix2([ [math.cos(angle),0-math.sin(angle),0,0], [math.sin(angle),math.cos(angle),0,0], [0,0,1,0], [0,0,0,1]]) def Translate(vector): return Matrix2([ [1,0,0,0], [0,1,0,0], [0,0,1,0], [vector.x,vector.y,vector.z,1]]) def Scale(vector): return Matrix2([ [vector.x,0,0,0], [0,vector.y,0,0], [0,0,vector.z,0], [0,0,0,1]]) def Clone(self): data = [] for row in self.data: data.append(row[:]) return Matrix2(data) def Inverse(self): adjoint = self.Adjoint() det = self.Determinant() if det == 0: raise RuntimeError('Cannot find the inverse of a matrix with a determinant of 0') inverse = Matrix2.Empty(self.rows,self.cols) x = 0 while x < self.cols: y = 0 while y < self.rows: inverse[(x,y)] = adjoint[(x,y)]/det y += 1 x += 1 return inverse def Transpose(self): transpose = Matrix2.Empty(self.cols,self.rows) x = 0 while x < self.cols: y = 0 while y < self.rows: transpose[(y,x)] = self[(x,y)] y += 1 x += 1 return transpose def Adjoint(self): return self.Cofactors().Transpose() def Determinant(self): if self.rows != self.cols: raise RuntimeError('Cannot find the determinant of a non-square matrix') if self.rows == 1: return self[(0,0)] cofactors = self.Cofactors() determinant = 0 n = 0 while n < self.cols: determinant += self[(n,0)]*cofactors[(n,0)] n += 1 return determinant def Minors(self): if self.rows != self.cols: raise RuntimeError('Cannot find the minors of a non-square matrix') if self.rows == 1: raise RuntimeError('Cannot find the minors of a 1 by 1 matrix') minors = Matrix2.Empty(self.rows,self.cols) lines = range(self.rows) x = 0 while x < self.cols: y = 0 while y < self.cols: tiny = Matrix2.Empty(self.rows-1,self.cols-1) ox = 0 nx = 0 while ox < self.cols: oy = 0 ny = 0 while oy < self.cols: if not((ox == x) or (oy == y)): tiny[(nx,ny)] = self[(ox,oy)] if oy != y: ny += 1 oy += 1 if ox != x: nx += 1 ox += 1 minors[(x,y)] = tiny.Determinant() y += 1 x += 1 return minors def Cofactors(self): minors = self.Minors() cofactors = Matrix2.Empty(self.rows,self.cols) x = 0 while x < self.cols: y = 0 while y < self.rows: if int((x+y)/2) == ((x+y)/2): cofactors[(x,y)] = minors[(x,y)] else: cofactors[(x,y)] = -1*minors[(x,y)] y += 1 x += 1 return cofactors def Perspective(e): return Matrix2([ [1,0,0,0], [0,1,0,0], [0,0,1,1/e[2]], [-e[0],-e[1],0,0]]) def Add(A,B): if A.rows != B.rows: RuntimeError('The row counts of Matrix \"A\" and Matrix \"B\" are not identical.') if A.cols != B.cols: RuntimeError('The column counts of Matrix \"A\" and Matrix \"B\" are not identical.') matrix = Matrix.Empty(A.rows,A.cols) for x in range(A.cols): for y in range(A.rows): matrix[(x,y)] = A[(x,y)]+B[(x,y)] return matrix def Subtract(A,B): if A.rows != B.rows: RuntimeError('The row counts of Matrix \"A\" and Matrix \"B\" are not identical.') if A.cols != B.cols: RuntimeError('The column counts of Matrix \"A\" and Matrix \"B\" are not identical.') matrix = Matrix.Empty(A.rows,A.cols) for x in range(A.cols): for y in range(A.rows): matrix[(x,y)] = A[(x,y)]+B[(x,y)] return matrix def DivHomogeneous(self): if (self.cols,self.rows) == (1,4): for y in range(3): self[(0,y)] = self[(0,y)]/self[(0,3)] self[(0,3)] = 1 if (self.cols,self.rows) == (4,1): for x in range(3): self[(x,0)] = self[(x,0)]/self[(3,0)] self[(3,0)] = 1 else: raise RuntimeError('1 by 4 or 4 by 1 Matrix2 expected') def Object(pos,look,up,right): return Matrix2([ [right.x,right.y,right.z,0], [up.x,up.y,up.z,0], [look.x,look.y,look.z,0], [pos.x,pos.y,pos.z,1]]) def Camera(eye,look,up,right): return Matrix2([ [right.x,up.x,look.x,0], [right.y,up.y,look.y,0], [right.z,up.z,look.z,0], [-Vector3.Dot(eye,right), -Vector3.Dot(eye,up), -Vector3.Dot(eye,look),1]]) def YPR(rot): return Matrix2.Multiply( Matrix2.Multiply(Matrix2.RotZ(rot.z), Matrix2.RotX(rot.x)), Matrix2.RotY(rot.y))
class Vector2:
def __init__(self,data=0,y=0): if (type(data) == type(5)) or (type(data) == type(5.1)): self.x = data self.y = y else: self.x = data[0] self.y = data[1] def __getitem__(self,index): if index == 0: return self.x elif index == 1: return self.y def __setitem__(self,index,value): if index == 0: self.x = value elif index == 1: self.y = 1 def Add(A,B): return Vector2(A.x+B.x,A.y+B.y) def Subtract(A,B): return Vector2(A.x-B.x,A.y-B.y) def Scale(A,n): return Vector2(A.x*n,A.y*n) def Magnitude(self): return ((self.x**2)+(self.y**2))**.5 def Unit(self): return Vector2.Scale(self,1/self.Magnitude()) def Clone(self): return Vector2(self.x,self.y)
class Vector3:
def __init__(self,data=0,y=0,z=0,w=1): if (type(data) == type(5)) or (type(data) == type(5.1)): self.x = data/w self.y = y/w self.z = z/w else: try: temp = data[3] except: temp = 1 self.x = data[0]/temp self.y = data[1]/temp self.z = data[2]/temp def __getitem__(self,index): if index == 0: return self.x elif index == 1: return self.y elif index == 2: return self.z def __setitem__(self,index,value): if index == 0: self.x = value elif index == 1: self.y = value elif index == 2: self.z = value def Vertical(self): return Matrix2([[self.x],[self.y],[self.z],[1]]) def Horizontal(self): return Matrix2(self.x,self.y,self.z,1) def Dot(A,B): return (A.x*B.x)+(A.y*B.y)+(A.z*B.z) def Cross(A,B): return Vector3([ (A.y*B.z)-(A.z*B.y), (A.z*B.x)-(A.x*B.z), (A.x*B.y)-(A.y*B.x)]) def Add(A,B): return Vector3(A.x+B.x,A.y+B.y,A.z+B.z) def Subtract(A,B): return Vector3(A.x-B.x,A.y-B.y,A.z-B.z) def Scale(A,n): return Vector3(A.x*n,A.y*n,A.z*n) def Magnitude(self): return ((self.x**2)+(self.y**2)+(self.z**2))**.5 def Print(self,decimals,spaces): return self.Horizontal().Print(decimals,spaces) def Same(A,B): same = False if A.x == B.x: if A.y == B.y: if A.z == B.z: same = True return same def Unit(self): return Vector3.Scale(self,1/self.Magnitude()) def Clone(self): return Vector3(self.x,self.y,self.z)
class Vector4:
def __init__(self,data=0,y=0,z=0,w=0): if (type(data) == type(5)) or (type(data) == type(5.1)): self.x = data self.y = y self.z = z self.w = w else: self.x = data[0] self.y = data[0] self.z = data[0] self.w = data[0]
points = [Vector3([-1,-1,0]),Vector3([1,-1,0]),Vector3([0,1,0])] width = 255 height = width screen = pygame.display.set_mode((width,height),0,32) scl = 2 pos = Vector3([0,0,5]) view = Vector3([0,0,1]) frames = 0
def Transform(point,mat):
return Matrix2.Multiply(point.Horizontal(),mat).Vectorize()
def RV():
return Vector3([random.random(),random.random(),random.random()])
green = pygame.Color(0,255,0) def XY(bla):
return (((width*bla[0])+width)/2,((height*bla[1])+width)/2)
screen.fill(pygame.Color(0,0,0)) size = 255
world = Matrix2.Identity(4) inv = world.Inverse() invt = world.Inverse().Transpose() center = Vector3(0,0,2)
def Texture(size):
texture = [] for pa in range(size): plane = [] for pb in range(size): line = [] for pc in range(size): line.append(random.random()) plane.append(line) texture.append(plane) return texture
lights = [(Vector3(-10,6,-9),[.7,.7*.9,.7*.8],[.7,.7*.9,.9*.8])] lights = [(Vector3(-10,6,-9),[.8,.8,.8],[.7,.7,.7])]
depth = 3 groups = [] for n in range(1):
textures = [] for n in range(depth): textures.append(Texture(4**(n+1))) groups.append(textures)
def Select(texture,at):
sel = [] for pa in range(4): aplane = texture[pa+math.floor(at.z)] bplane = [] for pb in range(4): aline = aplane[pb+math.floor(at.y)] bline = [] for pc in range(4): bline.append(aline[pc+math.floor(at.x)]) bplane.append(bline) sel.append(bplane) return (sel,Vector3(at.x%1,at.y%1,at.z%1))
def Round(val):
return val-(val-math.floor(val))
theta = math.tan(70*math.pi/360) for x in range(width):
for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() if event.type == KEYDOWN: pass for y in range(height): l = Vector3(theta*2*((x/width)-.5),theta*2*((y/width)-.5),1).Unit() ldc = Vector3.Dot(l,center) d = ldc-(((ldc**2)-Vector3.Dot(center,center)+1)**.5) if type(d) != type((-1)**.5): intersection = Vector3.Scale(l,d) normal = Vector3.Subtract(intersection,center).Unit() point = Transform(normal,world)
s = Vector3.Scale(Vector3.Add(point,Vector3(1,1,1)),.5) val = 0 for i in range(depth): sel = Select(groups[0][i],Vector3.Scale(s,4**i)) val += Misc.Tricubic(sel[0],sel[1])*((1/2)**i)/4 val = (25*val)%1 vals = [0,Misc.Linear([0,.3,1],val),1]
coloring = [] for i in range(3): #light = Misc.Lighting([1,1,1],normal,Vector3.Scale(intersection,-1),lights,([0,.03*val,.03],[0,.7*val,.7],[.3,.3,.3],7),i) light = Misc.Lighting([.1,.1,.1],normal,Vector3.Scale(intersection,-1),lights,(vals,vals,[1,1,1],10),i) if light > 1: light = 1 elif light < 0: light = 0 coloring.append(round(255*light)) screen.set_at((x,height-y),pygame.Color(coloring[0],coloring[1],coloring[2])) pygame.display.update()
pygame.image.save(screen,"PythonSphere.png") while True:
for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() if event.type == KEYDOWN: pass
</lang>
Racket
Using the Typed Racket language with the plot library:
<lang racket>
- lang typed/racket
(require plot/typed) (plot3d (polar3d (λ (θ ρ) 1)) #:altitude 25) </lang>
REXX
This program is modeled after the "C" version.
The REXX language doesn't have a SQRT function, so a version is included here.
Same with CEILing and FLOOR.
<lang rexx>/*REXX program to express a lighted sphere with simple chars for shading*/
call drawSphere 19, 4, 2/10
call drawSphere 10, 2, 4/10
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────drawSphere subroutine───────────────*/
drawSphere: procedure; parse arg r, k, ambient
if 1=='f1'x then shading='.:!*oe&#%@' /*for EBCDIC machs.*/
else shading='·:!ºoe@░▒▓' /*for ASCI machines*/ lightSource = '30 30 -50' /*the light source.*/
parse value norm(lightSource) with s1 s2 s3 /*normalize light S*/ sLen=length(shading); sLen1=sLen-1; rr=r*r
do i=floor(-r) to ceil(r) ; x= i+.5; xx=x**2; aLine= do j=floor(-2*r) to ceil(2*r); y=j/2+.5; yy=y**2 if xx+yy<=rr then do parse value norm(x y sqrt(rr-xx-yy)) with v1 v2 v3 dot=s1*v1 + s2*v2 + s3*v3 if dot>0 then dot=0 b=abs(dot)**k + ambient if b<=0 then brite=sLenm1 else brite=trunc( max( (1-b) * sLen1, 0) ) aLine=aLine || substr(shading,brite+1,1) end else aLine=aLine' ' end /*j*/ say strip(aLine,'trailing') end /*i*/
return /*─────────────────────────────────────"1-liner" subroutines────────────*/ ceil: procedure; parse arg x; _=trunc(x); return _ + (x>0) * (x\=_) floor: procedure; parse arg x; _=trunc(x); return _ - (x<0) * (x\=_) norm: parse arg _1 _2 _3; _=sqrt(_1*_1+_2*_2+_3*_3); return _1/_ _2/_ _3/_ sqrt: procedure; parse arg x; if x=0 then return 0; return .sqrt(x)/1 .sqrt: d=digits(); numeric digits 11; g=.sqrtGuess()
do j=0 while p>9; m.j=p; p=p%2+1; end do k=j+5 by -1 to 0; if m.k>11 then numeric digits m.k; g=.5*(g+x/g);end return g
.sqrtGuess: numeric form; m.=11; p=d+d%4+2; v=format(x,2,1,,0) 'E0'
parse var v g 'E' _ .; return g*.5'E'_%2</lang>
output
eeeeeeeeee@@@@@@@ eoooooooooooooooeeeee@@@@@@@░ ooººº!!!!!!!!ººººººooooeeeee@@@@@@@░░ oºº!!!:::::::::!!!!!ºººººooooeeee@@@@@@@░░░ oº!!::::·········:::::!!!!ºººooooeeeee@@@@@@@░░░░ oº!:::················::::!!!ººººoooeeeee@@@@@@@░░░░░ oº!::····················::::!!!ººººoooeeeee@@@@@@@░░░░░░ oº!::·······················:::!!!!ºººooooeeee@@@@@@@@░░░░░░░ oº!::·························:::!!!ºººooooeeeee@@@@@@@░░░░░░░░ oº!:···························:::!!!ººººoooeeeee@@@@@@@@░░░░░░░░ oº!::··························::::!!!ºººooooeeeee@@@@@@@@░░░░░░░░░ oº!::···························:::!!!!ºººooooeeeee@@@@@@@@░░░░░░░░░░ oº!!::··························::::!!!ººººooooeeeee@@@@@@@@░░░░░░░░░░░ eoº!!::·························::::!!!ººººooooeeeee@@@@@@@@@░░░░░░░░░░░░ ooº!!::························::::!!!ººººooooeeeeee@@@@@@@@░░░░░░░░░░░░░ eooº!!:::·····················::::!!!!ººººoooooeeeee@@@@@@@@@░░░░░░░░░░░░░░ eooºº!!:::·················:::::!!!!!ººººooooeeeeee@@@@@@@@@░░░░░░░░░░░░░░░ eooºº!!!:::::··········:::::::!!!!!ººººoooooeeeeee@@@@@@@@@@░░░░░░░░░░░░░░░ eeooººº!!!:::::::::::::::::!!!!!!ºººººoooooeeeeee@@@@@@@@@@░░░░░░░░░░░░░░░░ eeoooººº!!!!!!!:::::::!!!!!!!!ººººººoooooeeeeee@@@@@@@@@@@░░░░░░░░░░░░░░░░░ @eeoooººººº!!!!!!!!!!!!!!!ºººººººooooooeeeeeee@@@@@@@@@@@░░░░░░░░░░░░░░░░░░ @@eeeooooºººººººººººººººººººººoooooooeeeeeee@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░ @@@eeeooooooºººººººººººººoooooooooeeeeeeee@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░ @@@eeeeeooooooooooooooooooooooeeeeeeeee@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░ @@@@@eeeeeeeooooooooooooeeeeeeeeeeee@@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░░░ @@@@@@eeeeeeeeeeeeeeeeeeeeeeeee@@@@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░░░░ @@@@@@@@@eeeeeeeeeeeeeeeee@@@@@@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░░░░░ ░@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░@@@@@@@@@@@@@@@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░@@@@@@@@@@@@@@@@@@░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░ ::···:::!!!ºo ··············::!!ºoo ··················::!!ººooe ·····················::!!ººooee ·······················::!!ººooee ························::!!ººoooee ·························::!!ººoooeee :························::!!!ººoooeeee ························::!!!ººooooeeee :······················::!!!ºººoooeeeee :····················:::!!!ºººoooeeeeee !:·················:::!!!ººººoooeeeeeee º!:::···········::::!!!!ºººooooeeeeeeee º!!!:::::::::::!!!!!ººººoooooeeeeeeee oºº!!!!!!!!!!!!!ºººººoooooeeeeeeeee ooººººººººººººººooooooeeeeeeeeeee eoooooooooooooooooeeeeeeeeeeeee eeeooooooooeeeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeeee eeeeeeeeeeeee
Ruby
Shoes comes with this sample program.
<lang ruby>Shoes.app :width => 500, :height => 500, :resizable => false do
image 400, 470, :top => 30, :left => 50 do nostroke fill "#127" image :top => 230, :left => 0 do oval 70, 130, 260, 40 blur 30 end oval 10, 10, 380, 380 image :top => 0, :left => 0 do fill "#46D" oval 30, 30, 338, 338 blur 10 end fill gradient(rgb(1.0, 1.0, 1.0, 0.7), rgb(1.0, 1.0, 1.0, 0.0)) oval 80, 14, 240, 176 image :top => 0, :left => 0 do fill "#79F" oval 134, 134, 130, 130 blur 40 end image :top => 150, :left => 40, :width => 320, :height => 260 do fill gradient(rgb(0.7, 0.9, 1.0, 0.0), rgb(0.7, 0.9, 1.0, 0.6)) oval 60, 60, 200, 136 blur 20 end end
end</lang>
Run BASIC
<lang runbasic>graphic #g, 300, 300 'create a graphic object
- g place(100,100) 'place the drawing pen at 100,100
- g circle(75) 'make a circle with radius 75
render #g 'show it</lang>
Smalltalk
there are various OpenGL bindings available; here is a translation of the bare-bones code from C/Go:
although there is a Point3 class in some loadable library, here is some self contained code, defining a local anon Point3D class. <lang Smalltalk> Point3D :=
Point subclass:#Point3D instanceVariableNames:'z' classVariableNames: poolDictionaries: category: inEnvironment:nil.
Point3D compile:'z ^ z'. Point3D compile:'z:v z := v'.
normalize := [:v | |invLen|
invLen := 1 / (dot value:v value:v) sqrt. v x: v x * invLen. v y: v y * invLen. v z: v z * invLen.
].
dot := [:a :b |
(a x * b x) + (a y * b y) + (a z * b z)
].
drawSphere := [:r :k :amb :dir |
|w h imh vec img|
w := r*4. h := r*3. img := Image width:w height:h depth:8. img photometric:#blackIs0; createPixelStore. vec := Point3D new. 0-r to:r do:[:x | 0-r to:r do:[:y | |z s lum| (z := (r*r) - (x*x) - (y*y)) >= 0 ifTrue:[ vec x: x. vec y: y. vec z: z sqrt. normalize value:vec. s := dot value:dir value:vec. s < 0 ifTrue:[ s := 0 ]. lum := 255 * ((s raisedTo: k) + amb) / (1 + amb). lum < 0 ifTrue:[ lum := 0 ] ifFalse:[ lum > 255 ifTrue:[ lum := 255 ]]. img atX:(x+(w//2)) y:(y+(h//2)) put:(Color greyByte:lum). ] ] ]. img
].
main := [
|dir img|
dir := Point3D new x:-30; y:-30; z:50; yourself. normalize value:dir. img := drawSphere value: 100 value: 1.5 value: 0.2 value: dir. img displayOn:(View new extent:400@400; openAndWait). img saveOn:'sphere.png'.
].
SVG
Tcl
Assuming the task is to draw a likeness of a sphere, this would usually do:
<lang Tcl>proc grey {n} {format "#%2.2x%2.2x%2.2x" $n $n $n}
pack [canvas .c -height 400 -width 640 -background white]
for {set i 0} {$i < 255} {incr i} {
set h [grey $i] .c create arc [expr {100+$i/5}] [expr {50+$i/5}] [expr {400-$i/1.5}] [expr {350-$i/1.5}] \ -start 0 -extent 359 -fill $h -outline $h}
}</lang> Results in this image:
XPL0
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations def R=100, R2=R*R; \radius, in pixels; radius squared def X0=640/2, Y0=480/2; \coordinates of center of screen int X, Y, Z, C, D2; \coords, color, distance from center squared [SetVid($112); \set 640x480x24 graphics mode for Y:= -R to +R do \for all the coordinates near the circle
for X:= -R to +R do \ which is under the sphere [D2:= X*X + Y*Y; C:= 0; \default color is black if D2 <= R2 then \coordinate is inside circle under sphere [Z:= sqrt(R2-D2); \height of point on surface of sphere above X,Y C:= Z-(X+Y)/2+130; \color is proportional; offset X and Y, and ]; \ shift color to upper limit of its range Point(X+X0, Y+Y0, C<<8+C); \green + blue = cyan ];
repeat until KeyHit; \wait for keystroke SetVid($03); \restore normal text mode ]</lang>