nicklockwood / ShapeScript

The ShapeScript 3D modeling app for macOS and iOS
https://shapescript.info
MIT License
395 stars 18 forks source link

Questions about 2D drawing #15

Closed mgrider closed 8 months ago

mgrider commented 10 months ago

As a follow-up to a thread on Mastodon, I'm posting an example script I've been using to test using ShapeScript for 2D drawing.

Here's the script I've been using:

// ShapeScript document

detail 300

define setupCameraFor2D {
    option unitWidth 8.5
    option unitHeight 11
    option pixelsPerUnit 72
    camera {
        fov 0
        width unitWidth * pixelsPerUnit
        height unitHeight * pixelsPerUnit
        if unitWidth > unitHeight {
            size unitHeight / 2
            position 0 0 unitWidth
        } else {
            size unitHeight / 2
            position 0 0 unitHeight
        }
    }
}

define docWidth 8.5
define docHeight 11

setupCameraFor2D {
    unitWidth docWidth
    unitHeight docHeight
//    pixelsPerUnit 300
}

cube {
    position -1.5
    color 1 0 0
}

sphere {
    color 0 1 0
}

cone {
    position 1.5
    color 0 0 1
}

define drawGrid {
    define gridWidth 24
    define gridHeight 24
    group {
        position (-gridWidth/2)+0.5 (-gridHeight/2)+0.5 0
        for x in 0 to gridWidth-1 step 2 {
            for y in 0 to gridHeight-1 step 2 {
                cube {
                    size 1 1 0.01
                    color 1 1 1
                    position x y 0
                }
                cube {
                    size 1 1 0.01
                    color 0.5 0.5 0.5
                    position x y+1 0
                }
                cube {
                    size 1 1 0.01
                    color 0.5 0.5 0.5
                    position x+1 y 0
                }
                cube {
                    size 1 1 0.01
                    color 1 1 1
                    position x+1 y+1 0
                }
            }
        }
    }
}
drawGrid

This results in the following image:

export2D_vertical

If I swap the docWidth/docHeight, it results in this:

export2D_horizontal

You can see this is pretty much just the default ShapeScript scene, but I've added a gray grid to show that the unit size is correct relative to the size of my exported image.

This is all working for me, and it seems like I'll be able to take this and run with it, but it took a while for me to get here, and I have a few questions:

  1. As I pointed out on mastodon, I don't really know why the camera size should always be unitHeight/2 (and not unitWidth/2..?). I guess I don't really need to know this.
  2. This seems like maybe it's a bug, but if I change the group position line in drawGrid to remove the extra .5 units on the x and y axis, then the entire scene is actually no longer drawn in the center of my exported image. I'm not exactly sure why this should be, and it makes me wonder if I should be I positioning the camera at unitWidth/2 unitHeight/2 and everything else offset from 0,0, instead of trying to leave 0,0 in the center of my image?
  3. I've verified that uncommenting my pixelsPerUnit 300 line does result in the same image of the right dimensions, but when I open the image in Pixelmator, it still says it's 72 DPI. I can then change the image size (without resampling) to 300 dpi and the dimensions are correct. Is this something I have control over? (Or, perhaps more accurately, that you have control over?)
nicklockwood commented 10 months ago
  1. As I pointed out on mastodon, I don't really know why the camera size should always be unitHeight/2 (and not unitWidth/2..?). I guess I don't really need to know this.

This is to do with how 3D viewports are specified, but I think it's probably easiest to just accept that this will always be the case, regardless of size or aspect ratio.

  1. This seems like maybe it's a bug, but if I change the group position line in drawGrid to remove the extra .5 units on the x and y axis, then the entire scene is actually no longer drawn in the center of my exported image. I'm not exactly sure why this should be

By default ShapeScript tries to center the scene in view. Setting the camera position partly overrides that, but since you aren't also overriding the camera orientation it will still try to point at the center, which can lead to weird angles.

Enabling "Show axes" in the view menu may help to clarify what's going on a bit, since when axes are enabled the view is always centered on the origin instead of the scene.

I think the following settings should do what you want:

define setupCameraFor2D {
    option unitWidth 8.5
    option unitHeight 11
    option pixelsPerUnit 72
    camera {
        fov 0
        width unitWidth * pixelsPerUnit
        height unitHeight * pixelsPerUnit
        size unitHeight / 2
        position 0 0 1000
        orientation 0
    }
}

it makes me wonder if I should be I positioning the camera at unitWidth/2 unitHeight/2 and everything else offset from 0,0, instead of trying to leave 0,0 in the center of my image?

Either way should work, but traditionally 0,0 is the center of the camera in 3D so it may be easier to stick with that.

  1. I've verified that uncommenting my pixelsPerUnit 300 line does result in the same image of the right dimensions, but when I open the image in Pixelmator, it still says it's 72 DPI. I can then change the image size (without resampling) to 300 dpi and the dimensions are correct. Is this something I have control over? (Or, perhaps more accurately, that you have control over?)

ShapeScript has no concept of DPI, and images exported by ShapeScript do not include any DPI metadata so they will always be exported at 72DPI (or whatever default is assumed by the software that imports them). You can sometimes override this by naming the image with an @2x suffix (e.g. MyImage@2x.png) to indicate that you want Retina display resolution.

mgrider commented 8 months ago

Thank you!!! Appreciate you closing this loop.

And the code snippet. Setting orientation was definitely the missing piece for me.