--- title: "Random Dot Stereograms" type: "article" slug: "random-dot-stereograms-2" url: "http://localhost/article/random-dot-stereograms-2/" markdown_url: "http://localhost/article/random-dot-stereograms-2.md" published_at: "2025-11-27T02:01:14+00:00" modified_at: "2026-06-21T23:20:59+00:00" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "Random Dot Stereograms (RDS) can give the illusion of depth if you have binocular vision. Instead of the usual pair of stereoscopic pictures, a single 'picture' is made with several swaths side by side, interleaved so as to provide the brain with depth clues when you gaze at the dots in a certain way. It…" category: - name: "QL Hacker's Journal" slug: "ql-hackers-journal" taxonomy: "category" url: "http://localhost/category/periodicals/ql-hackers-journal/" post_tag: - name: "Full Text" slug: "fulltext" taxonomy: "post_tag" url: "http://localhost/tag/fulltext/" - name: "QL" slug: "ql" taxonomy: "post_tag" url: "http://localhost/tag/ql/" - name: "Superbasic (programming language)" slug: "superbasic-programming-language" taxonomy: "post_tag" url: "http://localhost/tag/superbasic-programming-language/" - name: "Type-in program" slug: "type-in-program" taxonomy: "post_tag" url: "http://localhost/tag/type-in-program/" model: - name: "Sinclair QL" slug: "sinclair-ql" taxonomy: "model" url: "http://localhost/model/sinclair-ql/" indiv: - name: "Herb Schaaf" slug: "herb-schaaf" taxonomy: "indiv" url: "http://localhost/indiv/herb-schaaf/" publication_r: id: 33686 title: "QL Hacker’s Journal" type: "periodical" url: "http://localhost/periodical/ql-hackers-journal/" authors_r: - name: "Herb Schaaf" slug: "herb-schaaf" taxonomy: "indiv" url: "http://localhost/indiv/herb-schaaf/" issue: "9" issues_articles: - id: 61545 title: "QL Hacker’s Journal 9" type: "issue" url: "http://localhost/issue/ql-hackers-journal-9/" pubdate: "June 1992" archive_link: true --- # Random Dot Stereograms Random Dot Stereograms (RDS) can give the illusion of depth if you have binocular vision. Instead of the usual pair of stereoscopic pictures, a single ‘picture’ is made with several swaths side by side, interleaved so as to provide the brain with depth clues when you gaze at the dots in a certain way. It takes a little blinking and practice, but when it ‘snaps-in’ to view the effect is marvelous. Once seen, it is fairly easy to find again. The best width for a swath is about half the distance between your eyes, say an inch or so. I have been using seven swaths, so that a RDS can be made on the screen that is about 7 inches wide and 6 inches high, and the effect is pleasing. I’ve done two so far, one a ‘splash’ like ripples in a pond and another of a pretzel. I’ve enjoyed working out the procedures and functions in SuperBasic, and a RDS only takes a minute or so to develop. Maybe I’ll get (or take) the time to try it in C to speed things up, or even do animation in 3D! I’ve tried other swath widths, dot sizes, dot densities, and dot quantities, so you can too! A dot size of 1 pixel used to now and then ‘hang’ the QL into limbo, but since I added a missing END IF it has been OK. Pixels of size 4 are pretty good, and faster. A density of 1% or even less will work! The minimum number of dots per swath seems to be around 42 or so. There is a short program “eyefuse3” to calibrate your setup for the range of separation that you can accomodate. See how close and how far you can still fuse two images into three, and then pick a middle value for your swath width. Simple objects like a sphere are probably easier to find for the beginner, but splashes, pretzles, and saddles, etc. are fun. Some simpler DEFine FuNctions are included. Enjoy! ### eyefuse3 ``` 100 REMark eyefuse3 125 WTV 126 PAPER 4 :INK 0 127 CLS 135 xo = 50: yo = 50 137 sep = 100 145 n = 8 155 bk = 1 165 explain 175 PAPER 0 : INK 6 180 CLS 200 FOR ac = 1 TO n 210 FOR dn = 1 TO n 220 BLOCK bk*1.5,bk,xo+ac*bk*1.5,yo+dn*bk, ((ac MOD 2 + dn MOD 2) MOD 2)*4 222 BLOCK bk*1.5,bk,100+xo+ac*bk*1.5,yo+dn*bk, ((((ac MOD 2 + dn MOD 2) MOD 2)-1)*-1)*2 230 END FOR dn 240 END FOR ac 247 CURSOR xo+n*1.5,yo :PRINT;"o" 248 CURSOR sep+xo+n*1.5,yo :PRINT;"O" 249 AT 16,2:PRINT;"use <--ク and ケ--> keys" 250 AT 17,2:PRINT;" to change separation" 251 AT 19,2:PRINT " hold ESC key to exit" 255 REPeat moves 257 AT 10,15: PRINT;sep;" " 258 CURSOR xo+sep , yo 260 IF INKEY$(-1) = CHR$(192) : PAN -1,4 :sep=sep-1 270 IF INKEY$(-1) = CHR$(200) : PAN 1,4 :sep=sep+1 280 IF INKEY$(-1) == CHR$(27) : EXIT moves 290 END REPeat moves 300 DEFine PROCedure explain 310 PRINT " If you have binocular vision and can see fairly well"¥ 320 PRINT "with either eye, it is possible that you may be able"¥ 330 PRINT "to 'see' objects in depth on your QL monitor screen"¥¥ 340 PRINT "This exercise will 'calibrate' your eyes and your VDU"¥ 350 PRINT¥"Make a note of the separation distance in pixels when"¥ 360 PRINT "you find it easiest to fuse the two little checker boards" 365 PRINT "into THREE little checkerboards." 370 PRINT "If you see 3 that's great; If you see two or four, change"¥ 380 PRINT "something: tilt your head, blink, move away from or closer"¥ 390 PRINT "to the screen, change eye-glasses, etc. while trying the"¥ 400 PRINT "various pixel separations"¥ 410 PRINT "The big 'O' will dominate the little 'o' when you have"¥ 420 PRINT "good super-imposition and the center checkerboard will"¥ 425 PRINT "be olive-drab"¥¥"Touch [SPACE BAR] to continue" 435 PAUSE 445 END DEFine explain 455 REMark end of eyefuse3 ``` RDSphere_QLHJ_bas ``` 100 REMark RDSphere_QLHJ_bas 110 REMark H.L Schaaf May 9,1992 120 REMark ref. Mathematica Journal Winter 1991 V.1,N.3, p.69-75 130 REMark 'Random Dot Stereograms' by Dror Bar-Natan @ Princeton 140 REMark dror@math.princeton.edu 150 ipl_dis = -20 :REMark image plane displacement, + is closer 160 obj_dis = 10 :REMark object displacement, - is more distant 170 iwide =360 : ihigh =240 : REMark image width and height 180 ytox = 4/3 : REMark y to x aspect ratio of QL blocks 190 swide = 60 : REMark swath width 200 zscale = 8 : REMark adjust for depth of Z axis 210 MODE 4 : CSIZE#2,1,0:CSIZE#0,0,0 220 WINDOW#1, iwide+8,256,0,0 :PAPER 0 : INK 7 230 WINDOW#2,144,190,368,0 : BORDER#2,2,2 240 PAPER#2,4 : INK #2,0 250 WINDOW#0 ,144,64,368,192 :BORDER #0,2,4 260 nk = 7 : REMark ink color 7 = white 270 CLS#0 : CLS#2 : CLS#1 280 REMark fill in with blocks 290 : 300 REMark ask for density and block size 310 INPUT#2; " % density ? ";dens : density = dens/100 320 INPUT #2;"Block size ? ";bk 330 hb = bk/2 : REMark half block 340 : 350 d_begin = DATE : REMark start timer 360 : 370 ac = swide DIV bk : REMark blocks across (columns) 380 ns = 2*ac : REMark allow for left shifts 390 dn = ihigh DIV bk : REMark blocks down (rows) 395 : 400 REMark create random pattern for first swath 404 RANDOMISE(32000) 410 DIM rdot%(density*ac*dn) 415 cnt = DIMN(rdot%) 417 FOR i = 0 TO cnt 418 rdot%(i) = RND (0 TO ac*dn) 419 END FOR i 420 : 580 REMark recap 590 PRINT#2¥¥" "; :UNDER#2, 1 600 PRINT#2;"Swath Data:" : UNDER#2, 0 610 PRINT#2;" ";ac;" across" 620 PRINT#2;" ";dn;" down" 630 PRINT#2;" ";ac*dn;" total" 640 PRINT #2;" ";cnt;" dots/swath" 650 PRINT #2;" ";(INT(10000*cnt/(ac*dn)))/100;" % density" 660 : 670 REMark create swaths 680 DIM swaths%(cnt,ns) 690 : 700 REMark put random pattern into first swath 710 REMark y values go into zeroth elements 720 FOR count = 0 TO cnt 730 i = rdot%(count) DIV (ac) 740 j = rdot%(count) - i*(ac) 750 swaths%(count,0)=i*bk 760 swaths%(count,1)=j*bk 765 BLOCK bk,bk,swaths%(count,1),swaths%(count ,0),nk 770 END FOR count 780 : 790 REMark create guides to help get proper 'focus' 800 gdlx=(iwide-swide)/2 : gdly=ihigh+6 810 gdrx=(iwide+swide)/2 : gdry=gdly 820 BLOCK 8,8,gdlx,gdly,nk 830 BLOCK 4,4,gdlx+2,gdly+2,0 840 BLOCK 8,8,gdrx,gdry,nk 850 BLOCK 4,4,gdrx+2,gdry+2,0 860 : 870 REMark geometric reference coordinates 880 xcntr=(iwide-swide)/2 : ycntr = ihigh/2 890 : 900 REMark a function to return the 3D value 910 DEFine FuNction sphere(x,y) 920 LOCal xs,ys,xx,yy 930 radius = 8*8 940 diam = 2*radius 950 diamsq = diam*diam 960 xs=ABS(xcntr-(x+hb)) 970 ys=ABS(ycntr-(y+hb))*ytox 980 xy = (xs*xs+ys*ys) 990 IF xy > diamsq 1000 offset = ipl_dis 1010 ELSE 1020 zz = diamsq-xy 1030 z=SQRT(zz) 1040 offset = z + obj_dis 1050 END IF 1060 RETurn offset DIV zscale 1070 END DEFine 1080 : 1090 REMark build remaining swaths 1100 OVER 1 1110 FOR i = 0 TO cnt 1120 FOR j = 2 TO ns 1130 ZD = sphere(swaths%(i,j-1),swaths%(i,0)) 1140 swaths%(i,j)=swide+(swaths%(i,j-1)) - ZD 1150 IF ((swaths%(i,j)+bk)>iwide) : EXIT j 1160 BLOCK bk,bk,swaths%(i,j),swaths%(i,0),nk 1170 END FOR j 1180 END FOR i 1190 : 1200 d_end = DATE :REMark stop timer 1210 d_lap = d_end - d_begin 1220 PRINT #2¥¥" Elapsed time:"¥" ";d_lap;" seconds" 1230 : 1240 REMark save screen 1250 SBYTES_O ram2_rds_scr,2^17,2^15 1260 PRINT #2¥¥" sbytes saved to"¥" ram2_rds_scr" 1270 : 1280 STOP ``` Following are some other DEFine Functions: (Change line 1130 to suit) ### A Pyramid of sorts ``` 900 REMark a function to return the 3D value 910 DEFine FuNction pyr(x,y) 920 LOCal xs,ys,xx,yy 930 baseline = 150 960 xs=ABS(xcntr-(x+hb)) 970 ys=ABS(ycntr-(y+hb))*ytox 980 xy = (xs+ys) 990 IF xy > baseline 1000 offset = ipl_dis 1010 ELSE 1020 zz = baseline-xy 1040 offset = zz + obj_dis 1050 END IF 1060 RETurn offset DIV zscale 1070 END DEFine ``` ### Imagine a Phillips head cavity ? ``` 900 REMark a function to return the 3D value 910 DEFine FuNction phlhd(x,y) 920 LOCal xs,ys,xx,yy 930 baseline = 80 960 xs=ABS(xcntr-(x+hb)) 970 ys=ABS(ycntr-(y+hb))*ytox 980 xy = SQRT(xs*ys) 990 IF xy > baseline 1000 offset = ipl_dis 1010 ELSE 1020 zz = xy - baseline 1040 offset = zz + obj_dis 1050 END IF 1060 RETurn offset DIV zscale 1070 END DEFine ``` ### Fan-blades making an X? ``` 900 REMark a function to return the 3D value 910 DEFine FuNction xvane(x,y) 920 LOCal xs,ys,xx,yy 930 baseline = 50 960 xs=ABS(xcntr-(x+hb)) 970 ys=ABS(ycntr-(y+hb))*ytox 980 xy = (xs-ys) 990 IF ABS(xy) > baseline 1000 offset = ipl_dis 1010 ELSE 1020 zz = baseline - xy 1040 offset = zz + obj_dis 1050 END IF 1060 RETurn offset DIV zscale 1070 END DEFine ``` ### Diamond shape (similar to pyramid) ``` 900 REMark a function to return the 3D value 910 DEFine FuNction diamond(x,y) 920 LOCal xs,ys,xx,yy 930 baseline = 100 960 xs=ABS(xcntr-(x+hb)) 970 ys=ABS(ycntr-(y+hb))*ytox 980 xy = (2*xs+3*ys)/5 990 IF xy > baseline 1000 offset = ipl_dis 1010 ELSE 1020 zz = baseline - xy 1040 offset = zz + obj_dis 1050 END IF 1060 RETurn offset DIV zscale 1070 END DEFine ``` ### Sinc – the classic splash, change scales for sombrero ``` 900 REMark a function to return the 3D value 910 DEFine FuNction sinc(x,y) 920 LOCal xs,ys,xx,yy 960 xs=ABS(xcntr-(x+hb))/swide 970 ys=ABS(ycntr-(y+hb))*ytox/swide 980 xy = SQRT(xs*xs+ys*ys)/2 1020 z = 2*PI*xy 1040 offset = 2*swide*(SIN(z)/z) 1050 END IF 1060 RETurn offset DIV zscale 1070 END DEFine ``` P.S. I’m especially proud of my ‘pretzle’ sometimes known as the Escher knot. If there is interest let the Editor know, and we will show you the complicated way I did it. Even better, show us your interesting RDS FuNctions etc.!