Draw a sphere: Difference between revisions
added autohotkey |
Perl entry |
||
Line 1,379: | Line 1,379: | ||
{{works with|Free_Pascal}} |
{{works with|Free_Pascal}} |
||
After changing "{$APPTYPE CONSOLE}" to "{$mode delphi}" or "{$mode objfpc}" the Delphi example works with FreePascal. |
After changing "{$APPTYPE CONSOLE}" to "{$mode delphi}" or "{$mode objfpc}" the Delphi example works with FreePascal. |
||
=={{header|Perl}}== |
|||
{{trans|Perl 6}} |
|||
This produces a PGM image which can't be uploaded on rosettacode at the moment. It looks similar as the Perl 6 solution, though. |
|||
<lang perl>use strict; |
|||
use warnings; |
|||
my $x = my $y = 255; |
|||
$x |= 1; # must be odd |
|||
my $depth = 255; |
|||
my $light = Vector->new(rand, rand, rand)->normalized; |
|||
print "P2\n$x $y\n$depth\n"; |
|||
my ($rad, $ambient) = (($x - 1)/2, .2); |
|||
my ($r2) = $rad ** 2; |
|||
{ |
|||
for my $x (-$rad .. $rad) { |
|||
my $x2 = $x**2; |
|||
for my $y (-$rad .. $rad) { |
|||
my $y2 = $y**2; |
|||
my $pixel = 127; |
|||
if ($x2 + $y2 < $r2) { |
|||
my $v = Vector->new($x, $y, sqrt($r2 - $x2 - $y2))->normalized; |
|||
my $I = ($light . $v) + $ambient; |
|||
$I = $I < 0 ? 0 : $I > 1 ? 1 : $I; |
|||
$pixel = int($I * $depth); |
|||
} |
|||
print $pixel; |
|||
print $y == $rad ? "\n" : " "; |
|||
} |
|||
} |
|||
} |
|||
package Vector { |
|||
sub new { |
|||
my $class = shift; |
|||
bless ref($_[0]) eq 'Array' ? $_[0] : [ @_ ], $class; |
|||
} |
|||
use overload q{.} => sub { |
|||
my ($a, $b) = @_; |
|||
my $sum = 0; |
|||
for (0 .. @$a - 1) { |
|||
$sum += $a->[$_] * $b->[$_] |
|||
} |
|||
return $sum; |
|||
}, |
|||
q{""} => sub { sprintf "Vector:[%s]", join ' ', @{shift()} }; |
|||
sub normalized { |
|||
my $this = shift; |
|||
my $norm = sqrt($this . $this); |
|||
bless [ map $_/$norm, @$this ], ref $this; |
|||
} |
|||
}</lang> |
|||
=={{header|Perl 6}}== |
=={{header|Perl 6}}== |
Revision as of 22:11, 16 March 2014
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>
This uses a very loose binding to SDL as found in any GPS installation. For it to work, you must choose New Project From Templte|Empty Game
<lang Ada> with Display; use Display; with Display.Basic; use Display.Basic;
procedure Main is
Ball : Shape_Id := New_Circle (X => 0.0, Y => 0.0, Radius => 20.0, Color => Blue);
begin
null;
end Main; </lang>
AutoHotkey
<lang ahk>#NoEnv SetBatchLines, -1
- SingleInstance, Force
- Uncomment if Gdip.ahk is not in your standard library
- Include, Gdip.ahk
- Settings
X := 200, Y := 200, Width := 200, Height := 200 ; Location and size of sphere rotation := -30 ; degrees ARGB := 0xFFFF0000 ; Color=Solid Red
If !pToken := Gdip_Startup() ; Start gdi+ { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } OnExit, Exit
Gui, -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs ; Create GUI Gui, Show, NA ; Show GUI hwnd1 := WinExist() ; Get a handle to this window we have created in order to update it later hbm := CreateDIBSection(A_ScreenWidth, A_ScreenHeight) ; Create a gdi bitmap drawing area hdc := CreateCompatibleDC() ; Get a device context compatible with the screen obm := SelectObject(hdc, hbm) ; Select the bitmap into the device context pGraphics := Gdip_GraphicsFromHDC(hdc) ; Get a pointer to the graphics of the bitmap, for use with drawing functions Gdip_SetSmoothingMode(pGraphics, 4) ; Set the smoothing mode to antialias = 4 to make shapes appear smother
Gdip_TranslateWorldTransform(pGraphics, X, Y) Gdip_RotateWorldTransform(pGraphics, rotation)
- Base ellipse
pBrush := Gdip_CreateLineBrushFromRect(0, 0, Width, Height, ARGB, 0xFF000000) Gdip_FillEllipse(pGraphics, pBrush, 0, 0, Width, Height)
- First highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.1, Height*0.01, Width*0.8, Height*0.6, 0x33FFFFFF, 0x00FFFFFF) Gdip_FillEllipse(pGraphics, pBrush, Width*0.1, Height*0.01, Width*0.8, Height*0.6)
- Second highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.3, Height*0.02, Width*0.3, Height*0.2, 0xBBFFFFFF, 0x00FFFFFF) Gdip_FillEllipse(pGraphics, pBrush, Width*0.3, Height*0.02, Width*0.3, Height*0.2)
UpdateLayeredWindow(hwnd1, hdc, 0, 0, A_ScreenWidth, A_ScreenHeight)
SelectObject(hdc, obm) ; Select the object back into the hdc
Gdip_DeletePath(Path)
Gdip_DeleteBrush(pBrush)
DeleteObject(hbm) ; Now the bitmap may be deleted
DeleteDC(hdc) ; Also the device context related to the bitmap may be deleted
Gdip_DeleteGraphics(G) ; The graphics may now be deleted
Return
Exit:
- gdi+ may now be shutdown on exiting the program
Gdip_Shutdown(pToken) ExitApp</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>
HTML
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
JavaScript
This Javascript entry uses an HTML wrapper to offer easy running and some interactivity. It is made as such, though, that the entire HTML wrapper can be removed (except for a canvas with id c
) and still work. If you remove the HTML, call the draw_sphere
function to draw the thing.
<lang javascript><!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Draw a sphere</title> <script> var light=[30,30,-50],gR,gk,gambient;
function normalize(v){ var len=Math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); v[0]/=len; v[1]/=len; v[2]/=len; return v; }
function dot(x,y){ var d=x[0]*y[0]+x[1]*y[1]+x[2]*y[2]; return d<0?-d:0; }
function draw_sphere(R,k,ambient){ var i,j,intensity,b,vec,x,y,cvs,ctx,imgdata,idx; cvs=document.getElementById("c"); ctx=cvs.getContext("2d"); cvs.width=cvs.height=2*Math.ceil(R)+1; imgdata=ctx.createImageData(2*Math.ceil(R)+1,2*Math.ceil(R)+1); idx=0; for(i=Math.floor(-R);i<=Math.ceil(R);i++){ x=i+.5; for(j=Math.floor(-R);j<=Math.ceil(R);j++){ y=j+.5; if(x*x+y*y<=R*R){ vec=[x,y,Math.sqrt(R*R-x*x-y*y)]; vec=normalize(vec); b=Math.pow(dot(light,vec),k)+ambient; intensity=(1-b)*256; if(intensity<0)intensity=0; if(intensity>=256)intensity=255; imgdata.data[idx++]=imgdata.data[idx++]=255-~~(intensity); //RG imgdata.data[idx++]=imgdata.data[idx++]=255; //BA } else { imgdata.data[idx++]=imgdata.data[idx++]=imgdata.data[idx++]=imgdata.data[idx++]=255; //RGBA } } } ctx.putImageData(imgdata,0,0); }
light=normalize(light);
</script>
</head>
<body onload="gR=200;gk=4;gambient=.2;draw_sphere(gR,gk,gambient)">
R=<input type="range" id="R" name="R" min="5" max="500" value="200" step="5" onchange="document.getElementById('lR').innerHTML=gR=parseFloat(this.value);draw_sphere(gR,gk,gambient)">
<label for="R" id="lR">200</label>
k=<input type="range" id="k" name="k" min="0" max="10" value="4" step=".25" onchange="document.getElementById('lk').innerHTML=gk=parseFloat(this.value);draw_sphere(gR,gk,gambient)">
<label for="k" id="lk">4</label>
ambient=<input type="range" id="ambient" name="ambient" min="0" max="1" value=".2" step=".05" onchange="document.getElementById('lambient').innerHTML=gambient=parseFloat(this.value);draw_sphere(gR,gk,gambient)">
<label for="ambient" id="lambient">0.2</label>
<canvas id="c">Unsupportive browser...</canvas>
</body>
</html></lang>
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
This produces a PGM image which can't be uploaded on rosettacode at the moment. It looks similar as the Perl 6 solution, though.
<lang perl>use strict; use warnings;
my $x = my $y = 255; $x |= 1; # must be odd my $depth = 255;
my $light = Vector->new(rand, rand, rand)->normalized;
print "P2\n$x $y\n$depth\n";
my ($rad, $ambient) = (($x - 1)/2, .2); my ($r2) = $rad ** 2; {
for my $x (-$rad .. $rad) {
my $x2 = $x**2; for my $y (-$rad .. $rad) { my $y2 = $y**2; my $pixel = 127; if ($x2 + $y2 < $r2) { my $v = Vector->new($x, $y, sqrt($r2 - $x2 - $y2))->normalized; my $I = ($light . $v) + $ambient; $I = $I < 0 ? 0 : $I > 1 ? 1 : $I; $pixel = int($I * $depth); } print $pixel; print $y == $rad ? "\n" : " "; }
}
}
package Vector {
sub new {
my $class = shift; bless ref($_[0]) eq 'Array' ? $_[0] : [ @_ ], $class;
} use overload q{.} => sub {
my ($a, $b) = @_; my $sum = 0; for (0 .. @$a - 1) { $sum += $a->[$_] * $b->[$_] } return $sum;
}, q{""} => sub { sprintf "Vector:[%s]", join ' ', @{shift()} }; sub normalized {
my $this = shift; my $norm = sqrt($this . $this); bless [ map $_/$norm, @$this ], ref $this;
}
}</lang>
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:
Processing
3D rendering is built into Processing.
<lang Processing>void setup() {
size(500,500,P3D); background(200);
}
void draw() {
stroke(200); translate(250,250); lights(); sphere(100);
}</lang>
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 the CEILing and FLOOR functions.
<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>
- Programming Tasks
- Solutions by Programming Task
- Ada
- GtkAda
- Display
- AutoHotkey
- GDIP
- BASIC
- BBC BASIC
- Brlcad
- C
- C sharp
- D
- Delphi
- DWScript
- Go
- HTML
- Haskell
- Unicon
- J
- Java
- JavaScript
- Logo
- Liberty BASIC
- Lua
- Mathematica
- Maxima
- Openscad
- Geometric Primitives
- Pascal
- Perl
- Perl 6
- PicoLisp
- GLUT
- PostScript
- POV-Ray
- Processing
- PureBasic
- Python
- Racket
- REXX
- Ruby
- Shoes
- Run BASIC
- Smalltalk
- SVG
- Tcl
- Tk
- XPL0