Algorithms
Making 3D Landscapes
Writing a program to make random 3D Landscapes based on plasma fractals is not as hard as it might seem. Below we
provide a full code for our Landscape applet. All you need to
know to write a program like this is a little trig for getting the 3D look and also know
how to make plasma fractals, which is described in previous chapter.
Of course to understand our code you need to know Java, but we didn't use any complex
technicues for it. If you need help on Java visit it's creators.
Note: Our code
is not copyrighted and in fact we encourage you to add to it, and send us any ideas or
code you think should be put in our applet.
import java.applet.*;
import java.awt.*;
public class landscape extends Applet {
Image offscr;
Graphics offscrgr;
Color cols[]={new Color(0,0,0),new Color(60,60,60),new Color(64,60,60),new
Color(72,60,60),new Color(76,56,56),new Color(84,56,56),new Color(88,52,52),new
Color(96,52,52),new Color(100,48,48),new Color(108,48,48),new Color(112,44,44),new
Color(120,44,44),new Color(128,40,40),new Color(132,40,40),new Color(140,36,36),new
Color(144,36,36),new Color(152,32,32),new Color(156,32,32),new Color(164,28,28),new
Color(168,28,28),new Color(176,24,24),new Color(180,24,24),new Color(188,20,20),new
Color(196,20,20),new Color(200,16,16),new Color(208,16,16),new Color(212,12,12),new
Color(220,12,12),new Color(224,8,8),new Color(232,8,8),new Color(236,4,4),new
Color(244,4,4),new Color(252,0,0),new Color(252,4,0),new Color(252,12,0),new
Color(252,20,0),new Color(252,28,0),new Color(252,36,0),new Color(252,44,0),new
Color(252,52,0),new Color(252,60,0),new Color(252,68,0),new Color(252,76,0),new
Color(252,84,0),new Color(252,92,0),new Color(252,100,0),new Color(252,108,0),new
Color(252,116,0),new Color(252,124,0),new Color(252,132,0),new Color(252,140,0),new
Color(252,148,0),new Color(252,156,0),new Color(252,164,0),new Color(252,172,0),new
Color(252,180,0),new Color(252,188,0),new Color(252,196,0),new Color(252,204,0),new
Color(252,212,0),new Color(252,220,0),new Color(252,228,0),new Color(252,236,0),new
Color(252,244,0),new Color(252,252,0),new Color(252,252,4),new Color(252,252,12),new
Color(252,252,20),new Color(252,252,28),new Color(252,252,36),new Color(252,252,44),new
Color(252,252,52),new Color(252,252,60),new Color(252,252,68),new Color(252,252,76),new
Color(252,252,84),new Color(252,252,92),new Color(252,252,100),new Color(252,252,108),new
Color(252,252,116),new Color(252,252,124),new Color(252,252,132),new
Color(252,252,140),new Color(252,252,148),new Color(252,252,156),new
Color(252,252,164),new Color(252,252,172),new Color(252,252,180),new
Color(252,252,188),new Color(252,252,196),new Color(252,252,204),new
Color(252,252,212),new Color(252,252,220),new Color(252,252,228),new
Color(252,252,236),new Color(252,252,244),new Color(252,252,252),new
Color(252,252,252),new Color(252,248,248),new Color(252,248,244),new
Color(252,244,240),new Color(252,244,236),new Color(252,240,232),new
Color(252,240,228),new Color(252,236,224),new Color(252,236,220),new
Color(252,232,216),new Color(252,232,212),new Color(252,228,208),new
Color(252,228,204),new Color(252,224,200),new Color(252,224,196),new
Color(252,220,192),new Color(252,220,188),new Color(252,216,184),new
Color(252,216,180),new Color(252,212,176),new Color(252,212,172),new
Color(252,208,168),new Color(252,208,164),new Color(252,204,160),new
Color(252,204,156),new Color(252,200,152),new Color(252,200,148),new
Color(252,196,144),new Color(252,196,140),new Color(252,192,136),new
Color(252,192,132),new Color(252,188,128),new Color(252,184,124),new
Color(252,184,120),new Color(252,180,116),new Color(252,180,112),new
Color(252,176,108),new Color(252,176,104),new Color(252,172,100),new Color(252,172,96),new
Color(252,168,92),new Color(252,168,88),new Color(252,164,84),new Color(252,164,80),new
Color(252,160,76),new Color(252,160,72),new Color(252,156,68),new Color(252,156,64),new
Color(252,152,60),new Color(252,152,56),new Color(252,148,52),new Color(252,148,48),new
Color(252,144,44),new Color(252,144,40),new Color(252,140,36),new Color(252,140,32),new
Color(252,136,28),new Color(252,136,24),new Color(252,132,20),new Color(252,132,16),new
Color(252,128,12),new Color(252,128,8),new Color(252,124,4),new Color(252,120,0),new
Color(252,120,0),new Color(252,116,0),new Color(252,112,0),new Color(252,108,0),new
Color(252,104,0),new Color(252,100,0),new Color(252,96,0),new Color(252,92,0),new
Color(252,88,0),new Color(252,84,0),new Color(252,80,0),new Color(252,76,0),new
Color(252,72,0),new Color(252,68,0),new Color(252,64,0),new Color(252,60,0),new
Color(252,60,0),new Color(252,56,0),new Color(252,52,0),new Color(252,48,0),new
Color(252,44,0),new Color(252,40,0),new Color(252,36,0),new Color(252,32,0),new
Color(252,28,0),new Color(252,24,0),new Color(252,20,0),new Color(252,16,0),new
Color(252,12,0),new Color(252,8,0),new Color(252,4,0),new Color(252,0,0),new
Color(252,0,0),new Color(248,0,0),new Color(244,0,0),new Color(244,0,0),new
Color(240,0,0),new Color(236,0,0),new Color(232,0,0),new Color(232,0,0),new
Color(228,0,0),new Color(224,0,0),new Color(224,0,0),new Color(220,0,0),new
Color(216,0,0),new Color(212,0,0),new Color(212,0,0),new Color(208,0,0),new
Color(204,0,0),new Color(204,0,0),new Color(200,0,0),new Color(196,0,0),new
Color(192,0,0),new Color(192,0,0),new Color(188,0,0),new Color(184,0,0),new
Color(184,0,0),new Color(180,0,0),new Color(176,0,0),new Color(172,0,0),new
Color(172,0,0),new Color(168,0,0),new Color(164,0,0),new Color(160,0,0),new
Color(160,0,0),new Color(156,4,4),new Color(152,4,4),new Color(148,8,8),new
Color(144,8,8),new Color(140,12,12),new Color(140,12,12),new Color(136,16,16),new
Color(132,16,16),new Color(128,20,20),new Color(124,20,20),new Color(120,24,24),new
Color(120,24,24),new Color(116,28,28),new Color(112,28,28),new Color(108,32,32),new
Color(104,32,32),new Color(100,36,36),new Color(100,36,36),new Color(96,40,40),new
Color(92,40,40),new Color(88,44,44),new Color(84,44,44),new Color(80,48,48),new
Color(80,48,48),new Color(76,52,52),new Color(72,52,52),new Color(68,56,56),new
Color(64,56,56),new Color(60,60,60),new Color(60,60,60)};
Color cols1[]={new Color(0,0,0),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new Color(0,0,168),new
Color(0,0,168),new Color(40,124,0),new Color(40,124,0),new Color(44,124,0),new
Color(44,124,0),new Color(44,124,4),new Color(44,124,4),new Color(44,128,4),new
Color(44,128,4),new Color(48,128,4),new Color(48,128,4),new Color(48,128,8),new
Color(48,128,8),new Color(48,132,8),new Color(48,132,8),new Color(52,132,8),new
Color(52,132,8),new Color(56,132,12),new Color(56,132,12),new Color(60,132,12),new
Color(60,132,12),new Color(60,136,12),new Color(60,136,12),new Color(60,136,16),new
Color(60,136,16),new Color(60,140,16),new Color(60,140,16),new Color(64,140,16),new
Color(64,140,16),new Color(64,140,20),new Color(64,140,20),new Color(64,144,20),new
Color(64,144,20),new Color(68,144,20),new Color(68,144,20),new Color(68,144,24),new
Color(68,144,24),new Color(68,148,24),new Color(72,148,24),new Color(72,148,28),new
Color(72,152,28),new Color(72,152,32),new Color(76,152,32),new Color(76,156,32),new
Color(80,156,32),new Color(80,156,36),new Color(80,160,36),new Color(80,160,40),new
Color(84,160,40),new Color(84,164,40),new Color(88,164,40),new Color(88,164,44),new
Color(88,168,44),new Color(88,168,48),new Color(92,168,48),new Color(92,172,48),new
Color(96,172,48),new Color(96,172,52),new Color(96,176,52),new Color(100,176,52),new
Color(100,176,56),new Color(100,180,56),new Color(100,180,56),new Color(104,180,60),new
Color(104,184,60),new Color(104,184,64),new Color(108,184,64),new Color(108,188,64),new
Color(108,188,68),new Color(112,188,68),new Color(112,188,72),new Color(112,192,72),new
Color(112,192,76),new Color(116,192,76),new Color(116,196,76),new Color(116,196,80),new
Color(120,196,80),new Color(120,200,80),new Color(120,200,84),new Color(124,200,84),new
Color(124,204,84),new Color(124,204,88),new Color(128,204,88),new Color(128,208,88),new
Color(128,208,92),new Color(132,208,92),new Color(132,212,92),new Color(136,212,92),new
Color(136,212,96),new Color(136,216,96),new Color(136,216,100),new Color(140,216,100),new
Color(140,220,100),new Color(140,220,104),new Color(144,220,104),new
Color(144,224,104),new Color(144,224,108),new Color(148,224,108),new
Color(148,228,108),new Color(152,228,108),new Color(152,228,108),new
Color(156,228,108),new Color(156,228,108),new Color(160,228,108),new
Color(164,228,108),new Color(168,228,108),new Color(168,228,108),new
Color(172,228,108),new Color(172,228,108),new Color(176,228,108),new
Color(176,228,108),new Color(180,228,108),new Color(180,228,108),new
Color(184,228,108),new Color(184,228,108),new Color(188,228,108),new
Color(188,228,108),new Color(192,228,108),new Color(196,228,108),new
Color(196,228,108),new Color(200,228,108),new Color(204,228,108),new
Color(204,228,108),new Color(208,228,108),new Color(208,228,108),new
Color(212,228,108),new Color(212,228,108),new Color(216,228,108),new
Color(220,228,108),new Color(220,228,108),new Color(224,228,108),new
Color(228,228,108),new Color(228,228,108),new Color(232,228,108),new
Color(232,228,108),new Color(232,228,104),new Color(232,228,104),new
Color(232,228,100),new Color(232,228,100),new Color(232,228,96),new Color(232,228,96),new
Color(232,228,92),new Color(232,224,92),new Color(232,224,92),new Color(232,220,88),new
Color(232,216,84),new Color(232,216,80),new Color(232,212,80),new Color(232,212,76),new
Color(232,208,76),new Color(232,204,72),new Color(232,204,68),new Color(232,200,68),new
Color(232,200,64),new Color(232,200,64),new Color(232,196,64),new Color(232,196,60),new
Color(232,192,60),new Color(232,192,56),new Color(232,188,56),new Color(232,188,52),new
Color(232,184,52),new Color(232,184,48),new Color(232,180,48),new Color(232,180,44),new
Color(232,180,44),new Color(232,176,44),new Color(232,176,44),new Color(232,176,40),new
Color(232,176,40),new Color(232,172,40),new Color(232,172,36),new Color(232,168,36),new
Color(232,168,36),new Color(228,164,32),new Color(228,164,32),new Color(228,160,32),new
Color(228,160,32),new Color(224,156,28),new Color(224,152,24),new Color(224,152,24),new
Color(224,148,20),new Color(220,148,20),new Color(220,140,16),new Color(220,140,16),new
Color(220,132,16),new Color(216,132,16),new Color(216,124,8),new Color(216,124,8),new
Color(216,116,8),new Color(128,128,128),new Color(128,128,128),new Color(252,252,252),new
Color(252,252,252),new Color(252,252,252),new Color(252,252,252),new
Color(252,252,252),new Color(252,252,252),new Color(252,252,252),new
Color(252,252,252),new Color(192,192,192),new Color(192,192,192),new
Color(252,252,252),new Color(252,252,252),new Color(252,252,252),new
Color(252,252,252),new Color(252,252,252),new Color(252,252,252),new Color(252,252,252)};
int[][] terrain;
int i, j, k, q, r, s, lod, half;
double roughness=10;
double sn=Math.sin(Math.PI / 36);
double sn1=Math.sin(5*Math.PI / 12);
double cn=Math.cos(Math.PI / 36);
double cn1=Math.cos(5*Math.PI / 12);
String terra="Wireframe";
String texture="Topo";
int divisions, avg, sum;
int px[]= new int[3];
int py[]=new int[3];
public void init() {
resize(500,300);
offscr=createImage(500,300);
offscrgr=offscr.getGraphics();
create_ground();
draw_ground();
}
public void start() {
}
public boolean mouseDown(Event e, int x, int y)
{
if(x>=50 & x<=150 & y>=282 & y<=295)
{
create_ground();
draw_ground();
repaint();
}
if(x>=405 & x<=485 & y>=277 & y<=283)
{
roughness=(int)Math.round((x-405)/4);
create_ground();
draw_ground();
repaint();
}
if(x>=530-divisions & x<=490 & y>=179 & y<=191)
{
terra="Wireframe";
draw_ground();
repaint();
}
if(x>=530-divisions & x<=490 & y>=159 & y<=171)
{
terra="Rendered";
draw_ground();
repaint();
}
if(x>=530-divisions & x<=490 & y>=239 & y<=251)
{
texture="Volcano";
draw_ground();
repaint();
}
if(x>=530-divisions & x<=490 & y>=219 & y<=231)
{
texture="Topo";
draw_ground();
repaint();
}
return true;
}
public void paint(Graphics g)
{
g.drawImage(offscr,0,0,this);
g.setColor(Color.black);
g.fillRect(1,1,490-divisions,20);
g.fillRect(1,280,490-divisions,19);
g.setColor(Color.red);
g.drawRect(0,0,499,299);
g.drawLine(1,280,499-divisions,280);
g.drawLine(499-divisions,1,499-divisions,299);
g.drawLine(499-divisions,divisions+1,499,divisions+1);
g.drawLine(1,20,499-divisions,20);
g.setColor(Color.green);
g.drawString("Create New",50,295);
g.setColor(Color.yellow);
g.drawString("Fractal Landscape
"+terra+" with roughness level "+roughness,15,15);
g.drawString("Fractals Unleashed
1999",220,295);
g.drawString("Terrain",510-divisions,150);
if(terra=="Rendered"){
g.setColor(Color.red);
}
g.drawString("Rendered",530-divisions,170);
g.setColor(Color.yellow);
if(terra=="Wireframe"){
g.setColor(Color.red);
}
g.drawString("Wireframe",530-divisions,190);
g.setColor(Color.yellow);
g.drawString("Texture",510-divisions,210);
if(texture=="Topo"){
g.setColor(Color.red);
}
g.drawString("Topo",530-divisions,230);
g.setColor(Color.yellow);
if(texture=="Volcano"){
g.setColor(Color.red);
}
g.drawString("Volcano",530-divisions,250);
g.setColor(Color.yellow);
g.drawString("Roughness",510-divisions,270);
g.setColor(Color.red);
g.drawLine(405,280,485,280);
g.drawOval(403+(int)roughness*4,278,4,4);
}
public void create_ground()
{
lod=7;
divisions = 1 << lod;
terrain = new int[(divisions + 1)*2][(divisions + 1)*2];
terrain[0][0] = (int)Math.round(Math.random()*254)+1;
terrain[0][divisions] = (int)Math.round(Math.random()*254)+1;
terrain[divisions][divisions] = (int)Math.round(Math.random()*254)+1;
terrain[divisions][0] = (int)Math.round(Math.random()*254)+1;
terrain[divisions/2][divisions/2] = (int)Math.round(Math.random()*254)+1;
terrain[0][divisions/2] = (int)Math.round(Math.random()*254)+1;
terrain[divisions/2][0] = (int)Math.round(Math.random()*254)+1;
terrain[divisions][divisions/2] = (int)Math.round(Math.random()*254)+1;
terrain[divisions/2][divisions] = (int)Math.round(Math.random()*254)+1;
for (i = 0; i < lod; ++ i) {
q = 1 << i;
r = 1 << (lod - i);
s = r >> 1;
for (j = 0; j < divisions; j += r){
for (k = 0; k < divisions; k += r){
diamond (j, k, r, roughness);
}
}
if (s > 0)
{
for (j = 0; j <= divisions; j += s){
for (k = (j + s) % r; k <= divisions; k +=
r){
square (j - s, k - s, r, roughness);
}
}
}
}
}
private void draw_ground()
{
offscrgr.setColor(Color.black);
offscrgr.fillRect(1,1,499,299);
if(terra=="Rendered"){
for (k=0; k<divisions; k++){
this.setForeground(Color.black);
this.getGraphics().fillRect(10,25,70,16);
this.setForeground(Color.red);
this.getGraphics().drawString((int)Math.round(((double)k/divisions)*100) + "%
done",20,40);
this.setForeground(Color.black);
for(i=0; i<divisions; i++){
if(texture=="Topo"){
offscrgr.setColor(cols1[256-((int)Math.round((terrain[i][k]+terrain[i+1][k]+terrain[i][k+1])/3))]);
}
else{
offscrgr.setColor(cols[256-((int)Math.round((terrain[i][k]+terrain[i+1][k]+terrain[i][k+1])/3))]);
}
px[0]=80+(int)Math.round(cn * i - cn1 * k)*2;
py[0]=70+(int)Math.round(sn * i + sn1 *
k)+(int)Math.round(terrain[i][k]/2-64-(terrain[divisions/2][divisions/2]/2-70));
px[1]=80+(int)Math.round(cn * i - cn1 * (k+1))*2;
py[1]=70+(int)Math.round(sn * i + sn1 *
(k+1))+(int)Math.round(terrain[i][k+1]/2-64-(terrain[divisions/2][divisions/2]/2-70));
px[2]=80+(int)Math.round(cn * (i+1) - cn1 * k)*2;
py[2]=70+(int)Math.round(sn * (i+1) + sn1 *
k)+(int)Math.round(terrain[i+1][k]/2-64-(terrain[divisions/2][divisions/2]/2-70));
offscrgr.fillPolygon(px,py,3);
if(texture=="Topo"){
offscrgr.setColor(cols1[256-((int)Math.round((terrain[i+1][k]+terrain[i+1][k+1]+terrain[i][k+1])/3))]);
}
else{
offscrgr.setColor(cols[256-((int)Math.round((terrain[i+1][k]+terrain[i+1][k+1]+terrain[i][k+1])/3))]);
}
px[0]=80+(int)Math.round(cn * (i+1) - cn1 * k)*2;
py[0]=70+(int)Math.round(sn * (i+1) + sn1 *
k)+(int)Math.round(terrain[i+1][k]/2-64-(terrain[divisions/2][divisions/2]/2-70));
px[1]=80+(int)Math.round(cn * i - cn1 * (k+1))*2;
py[1]=70+(int)Math.round(sn * i + sn1 *
(k+1))+(int)Math.round(terrain[i][k+1]/2-64-(terrain[divisions/2][divisions/2]/2-70));
px[2]=80+(int)Math.round(cn * (i+1) - cn1 * (k+1))*2;
py[2]=70+(int)Math.round(sn * (i+1) + sn1 *
(k+1))+(int)Math.round(terrain[i+1][k+1]/2-64-(terrain[divisions/2][divisions/2]/2-70));
offscrgr.fillPolygon(px,py,3);
offscrgr.drawLine(499-divisions+i,k+1,499-divisions+i,k+1);
}
}
}
else{
for (k=0; k<divisions; k=k+4){
for(i=0; i<divisions; i=i+4){
if(texture=="Topo"){
offscrgr.setColor(cols1[256-((int)Math.round((terrain[i][k]+terrain[i+1][k]+terrain[i][k+1])/3))]);
}
else{
offscrgr.setColor(cols[256-((int)Math.round((terrain[i][k]+terrain[i+1][k]+terrain[i][k+1])/3))]);
}
px[0]=80+(int)Math.round(cn * i - cn1 * k)*2;
py[0]=70+(int)Math.round(sn * i + sn1 *
k)+(int)Math.round(terrain[i][k]/2-64-(terrain[divisions/2][divisions/2]/2-70));
px[1]=80+(int)Math.round(cn * i - cn1 * (k+4))*2;
py[1]=70+(int)Math.round(sn * i + sn1 *
(k+4))+(int)Math.round(terrain[i][k+4]/2-64-(terrain[divisions/2][divisions/2]/2-70));
px[2]=80+(int)Math.round(cn * (i+4) - cn1 * (k))*2;
py[2]=70+(int)Math.round(sn * (i+4) + sn1 *
(k))+(int)Math.round(terrain[i+4][k]/2-64-(terrain[divisions/2][divisions/2]/2-70));
offscrgr.drawLine(px[0],py[0],px[1],py[1]);
offscrgr.drawLine(px[0],py[0],px[2],py[2]);
}
}
for (k=0; k<divisions; k++){
this.setForeground(Color.black);
this.getGraphics().fillRect(10,25,70,16);
this.setForeground(Color.red);
this.getGraphics().drawString((int)Math.round(((double)k/divisions)*100) + "%
done",20,40);
this.setForeground(Color.black);
for(i=0; i<divisions; i++){
if(texture=="Topo"){
offscrgr.setColor(cols1[256-((int)Math.round((terrain[i][k]+terrain[i+1][k]+terrain[i][k+1])/3))]);
}
else{
offscrgr.setColor(cols[256-((int)Math.round((terrain[i][k]+terrain[i+1][k]+terrain[i][k+1])/3))]);
}
offscrgr.drawLine(499-divisions+i,k+1,499-divisions+i,k+1);
}
}
}
}
private void diamond (int x, int y, int side, double scale) {
if (side > 1) {
half = side / 2;
avg = (int)Math.round((terrain[x][y] + terrain[x + side][y] +
terrain[x + side][y + side] + terrain[x][y + side]) * 0.25);
if(terrain[x + half][y + half]==0)
{
terrain[x + half][y + half] = avg + (int)Math.round(Math.random() * scale - scale / 2);
}
}
}
private void square (int x, int y, int side, double scale) {
half = side / 2;
avg = 0;
sum = 0;
if (x >= 0)
{ avg += terrain[x][y + half]; sum += 1; }
if (y >= 0)
{ avg += terrain[x + half][y]; sum += 1; }
if (x + side <= divisions)
{ avg += terrain[x + side][y + half]; sum += 1; }
if (y + side <= divisions)
{ avg += terrain[x + half][y + side]; sum += 1; }
if(terrain[x + half][y + half]==0)
{
terrain[x + half][y + half] = avg / sum +
(int)Math.round(Math.random() * scale-scale/2);
}
}
}