If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

Main content

Generating 3D shapes

So we have a cube now, but what if we want to change its position or size? Or what if we want a rectangular cuboid or many cuboids? With our current code, we would have to change the nodes one-by-one, which would be nuisance. What we would like is a simple method to create a cuboid with a certain position and dimensions. In other words, we want a function that maps a position and dimensions into an array of nodes and an array of edges.

Defining a cuboid

A cuboid has three dimensions: width, height and depth:
It also has a position in 3D space, giving us six parameters. There are a couple of ways we could define the position of the cuboid: we could define its center or we could define one corner. The former is probably more common, but I think the latter is easier to use.
Our function needs to return both the nodes and edges array. One way to return two variables is to package the variables into an object, with a key for nodes and a key for edges. Note, you can use any string to refer to the variable, I just find it easier to use the same word.
// Create a cuboid with a vertex at (x, y, z)
// with width, w, height, h, and depth, d.
var createCuboid = function(x, y, z, w, h, d) {
   var nodes = [];
   var edges = [];
   var shape = { 'nodes': nodes, 'edges': edges };
   return shape;
};
If we used that function to create a cuboid, we'd access the first node like this:
var shape = createCuboid(0, 0, 0, 100, 160, 50);
var node0 = shape.nodes[0];
This will set node0 to the first value in the nodes array. At the moment, however, there are no values in the nodes or edges arrays.
We define the nodes as being every combination of position with or without the corresponding dimension. Edges are defined the same way as before (except rather than define each of the edges individually first, I define them all at once). Note that this function allows you to specify negative dimensions for the cuboid.
var createCuboid = function(x, y, z, w, h, d) {
   var nodes = [[x, y, z ], [x, y, z+d], [x, y+h, z ], [x, y+h, z+d], [x+w, y, z ], [x+w, y, z+d], [x+w, y+h, z ], [x+w, y+h, z+d]];

   var edges = [[0, 1], [1, 3], [3, 2], [2, 0], [4, 5], [5, 7], [7, 6], [6, 4], [0, 4], [1, 5], [2, 6], [3, 7]];

   return { 'nodes': nodes, 'edges': edges};
};
We can then create a cuboid with width 100, height 160, depth 50 and one node on the origin like this:
var shape = createCuboid(0, 0, 0, 100, 160, 50);
Since our previous code just references global nodes and edges variables, we need to store our object's properties into those globals:
var nodes = shape.nodes; var edges = shape.edges;
You can see the complete code below.

Working with multiple shapes

We can create shapes with different dimensions, what if we want more than one? Whenever we want a variable number of things, an array is useful, so lets create an array of shapes.
var shape1 = createCuboid(-120, -20, -20, 240, 40, 40);
var shape2 = createCuboid(-120, -50, -30, -20, 100, 60);
var shape3 = createCuboid( 120, -50, -30, 20, 100, 60);
var shapes = [shape1, shape2, shape3];
Now we need to change the display and rotate functions to work with an array of objects. Start by wrapping the code to display edges in a for loop that loops through all the shapes:
// Draw edges
stroke(edgeColor);
for (var shapeNum = 0; shapeNum < shapes.length; shapeNum++) {
   var nodes = shapes[shapeNum].nodes;
   var edges = shapes[shapeNum].edges;
   for (var e = 0; e < edges.length; e++) {
      var n0 = edges[e][0];
      var n1 = edges[e][1];
      var node0 = nodes[n0];
      var node1 = nodes[n1];
      line(node0[0], node0[1], node1[0], node1[1]);
   }
}
And a similar for loop for displaying nodes:
// Draw nodes
fill(nodeColor);
noStroke();
for (var shapeNum = 0; shapeNum < shapes.length; shapeNum++) {
   var nodes = shapes[shapeNum].nodes;
   for (var n = 0; n < nodes.length; n++) {
      var node = nodes[n]; ellipse(node[0], node[1], nodeSize, nodeSize);
   }
}
We could add a similar for loop to each of the rotate functions, but I think it's more flexible to pass the array of nodes to each function - that way we can rotate shapes independently of one another. For example, the rotateZ3D() function would look like this:
var rotateZ3D = function(theta, nodes) { ... };
Now when we use the mouse to rotate, we have to loop through the shapes and call the function for each one:
mouseDragged = function() {
   var dx = mouseX - pmouseX;
   var dy = mouseY - pmouseY;
   for (var shapeNum = 0; shapeNum < shapes.length; shapeNum++) {
      var nodes = shapes[shapeNum].nodes;
      rotateY3D(dx, nodes);
      rotateX3D(dy, nodes);
   }
};
Make sure you remove any other calls to the rotate functions that do not pass in any nodes. You can see the complete code below.

Want to join the conversation?

  • old spice man green style avatar for user Bye :)
    How would you create a three-dimensional shape with faces?
    (57 votes)
    Default Khan Academy avatar avatar for user
  • male robot donald style avatar for user eamccarter
    In the future will Khan Academy have a 3D canvas?
    (24 votes)
    Default Khan Academy avatar avatar for user
  • piceratops ultimate style avatar for user SuperHeroMe
    Is there a way to make 3D shapes without using trigonometry? I am only nine years old, but I love doing coding. But of course I don't know trigonometry.
    (25 votes)
    Default Khan Academy avatar avatar for user
    • old spice man green style avatar for user Bob Lyon
      I don't think that you need to know Trig to use these functions anymore than you needed it to invoke rotate in 2D land. Similarly you don't need to know Linear Algebra to use translate, scale or rotate. Knowing the higher maths may help some appreciate what is going on (or send them running for the exits).
      (20 votes)
  • purple pi teal style avatar for user Sploderfan
    Is it possible to generate a 3D object isometrically? If so, what are the mathematics used in creating one?
    (8 votes)
    Default Khan Academy avatar avatar for user
  • aqualine ultimate style avatar for user Nathan Moran
    Is it possible to use anything other than points and lines in the construction of 3D shapes? For example, if I wanted to create a 3D cylinder, could I somehow use ellipses for the 2 faces, or would I have to substitute a tediously crafted regular polygon that has sufficient sides to bear at least a resemblance to a real circle?
    (5 votes)
    Default Khan Academy avatar avatar for user
  • primosaur ultimate style avatar for user TurtleKing66
    How would you make a 3D shape smaller as it gets further away from the "camera" (I know that there isn't exactly a camera, but how would you make things smaller as their Z value decreases?)
    (5 votes)
    Default Khan Academy avatar avatar for user
    • old spice man green style avatar for user Bob Lyon
      First assume the camera is fixed and located at a fairly far away positive Z location, most likely centered on the canvas, e.g.
          camera = (0, 0, 1000)
      Then the perspective point, pp of point p is computed with
          d = distanceBetween(camera, p)
      scaleFactor = camera.z / d
      pp = (scaleFactor*p.x, scaleFactor*p.y, p.z)
      Working backwards, note that (1) the value of pp.z should not matter since perspective is only used for rendering onto the 2D canvas, (2) the scaleFactor is one (a noop) at the 3D universe's origin, and less than (or greater than) one for points farther (or nearer), and (3) distanceBetween simply uses the Pythagorean theorem for computing the distance between two 3D points.

      See line 305 at https://www.khanacademy.org/computer-programming/3d-perspective-shading/4521460558135296
      (2 votes)
  • leafers ultimate style avatar for user NathanFischer
    What does the keyword map do in javascript, and if possible could you also write a simple code to demonstrate how it can be used. Thanks in advanced! :)
    (3 votes)
    Default Khan Academy avatar avatar for user
    • old spice man green style avatar for user Bob Lyon
      The function allegedly maps a value in one range to its corresponding value in another range. In fact, the value and its mapping can be "out of range".

      Given any number x, the map function returns y where
          y = mx + b
      where x is the first argument to the function and m and b are determined by last four arguments to the function. Specifically m and b are determined by the Algebraic line passing through the two points (low1, low2) and (high1, high2).

      For example, we (should) know that water freezes at 0° Celsius or 32° Fahrenheit and boils at 100° Celsius or 212° Fahrenheit. What is the Celsius equivalent of 86°F?
          answer = map(86, 32, 212, 0, 100);
      What is the Fahrenheit equivalent of -40°C?
          answer = map(-40, 0, 100, 32, 212);

      So the map function lets us use linear equations without knowing Algebra.
      (5 votes)
  • duskpin tree style avatar for user suhada.sahan.n
    What does a circle look like in 3D?
    (2 votes)
    Default Khan Academy avatar avatar for user
  • blobby green style avatar for user Zander
    Does anyone know how to upload textures onto cubes in P3D?
    (2 votes)
    Default Khan Academy avatar avatar for user
    • leaf blue style avatar for user Hunter R. Shaw
      The Processing documentation site has this example of P3D texturing:
      size(400, 400, P3D);
      noStroke();
      PImage img = loadImage("shells.jpg");
      textureMode(NORMAL);
      beginShape();
      texture(img);
      vertex(40, 80, 0, 0);
      vertex(320, 20, 1, 0);
      vertex(380, 360, 1, 1);
      vertex(160, 380, 0, 1);
      endShape();

      I frankly haven't the slightest clue whether you are able to do such a thing within the bounds of KA, and I'm struggling to find it in me to make that discovery.

      We are here to help you out, but one of the biggest things you have to learn is to a) use the right tool for the right job; you're not going to successfully build Superliminal on KA (even if you had the know-how), b) take things at a slower pace, and don't get into a project that's so out of your depth that you must ask questions at every turn, and c) USE GOOGLE. It's your best friend. Near-unlimited knowledge at your fingertips. If I lacked a functioning search engine, it's likely that a third of my answers would not be present.
      (6 votes)
  • mr pants green style avatar for user lanitoman
    if I completed every course in khan academy is it possible to make a complicated game like Minecraft using only javascript (no other language)
    (2 votes)
    Default Khan Academy avatar avatar for user
    • spunky sam blue style avatar for user Dalendrion
      Khan Academy's lessons cover some of the basics. You can use that knowledge to create basic games. And they can be fun.
      I highly recommend the Computer Science section at https://www.khanacademy.org/computing/.
      Those courses will teach you more fundamentals that will be extremely helpful.

      But for games like Minecraft, there's more to learn.
      How do you create 3D environments (that doesn't lag)?
      How do you let players play together?
      How do you save games?
      How do you create physics?
      How do you generate a whole world?
      And so on.

      But the good news is, once you've finished Khan Academy's courses, you have the basic knowledge required to explore all of these questions.
      So in that sense, yes, with enough research, it will be possible.
      (4 votes)