Actual size image script.

Hi all,

First, here’s what I’m trying to do. I’m writing a script that takes an image file and at the 3d cursor, creates a plane oriented square to the camera that will be rendered the actual pixel size of the image.

Okay, so I know the distance from the camera to the cursor (even my poor math skills can get me that far). I know how to load, create, and texture my mesh. Even orienting it towards the camera is no prob.

The main thing I’m lacking is how to know how big a given plane at a known distance must be to appear the actual size. (1 image pixel = 1 rendered pixel)

I know it probably involves frustums and matrix transforms and other such 3d wizardry. Beyond that, my Jedi skills still have a long way to go.

Any help?

Thanks in advance!

FWIW, here’s the code.

Notice right now I’m doing
return (px*d)/1000

This is pretty much plucked from the air.

#!BPY

""" Registration info for Blender menus:
Name: 'k+) Cel Plane'
Blender: 242
Group: 'AddMesh'
Tip: ''
"""

__author__ = "Kurt"
__url__ = ""
__version__ = "1.0"

__bpydoc__ = """\This creates a planar mesh sized to the current camera and mapped to an image.
"""

# $Id: k_celPlane.py,v 1.0 2007/12/25 23:14:48 kurt Exp $

import Blender 
from Blender import *
from math import *

def pixels2BlenderUnits(px,d):
        """
        calculates how many blender units equals (px) rendered pixels at a distance from the camera (d)
        """
        return (px*d)/1000


def celPlaneGui(filename=None):
        """
        returns the new object or None
        """
        if filename==None:
                Window.FileSelector(celPlaneGui,"Cel Plane Image")
                return
        #streachX=Draw.Create(0.0)
        #streachY=Draw.Create(0.0)
        #controls=[\
        #    ('Streach X:',streachX,0.01,9999.0,'X scale of result'),\
        #    ('Streach Y:',streachY,0.01,9999.0,'Y scale of result')\
        #]
        #if Draw.PupBlock("Cel Plane",controls):
        mesh=celPlane(filename)
        Window.RedrawAll()
        return mesh
    
def dist3d(a,b):
        """
        the distance between two 3d points
        """
        return sqrt(pow(a[0]-b[0],2)+pow(a[1]-b[1],2)+pow(a[2]-b[2],2))

def celPlane(imageFile,streachX=0.0,streachY=0.0,celPlaneName=None):
        """
        creates an image plane at the 3D cursor, alligned to the camera
        and optionally scaled (TODO)
        """
        # load the image
        img=Image.Load(imageFile)
        imgSize=img.getSize()
        if(celPlaneName==None):
                celPlaneName="cp_"+img.getName()
        # initial setup
        print "---- Creating "+celPlaneName
        Window.DrawProgressBar(1.0,"Creating cel plane '%s' ..." % celPlaneName)
        cursorPos=Blender.Window.GetCursorPos()
        scn=Scene.GetCurrent()
        camObj=scn.getCurrentCamera()
        cam=Camera.Get(camObj.name)
        d=dist3d(camObj.getLocation(),cursorPos)
        # generate mesh data
        verts=[]
        faces=[]
        w=pixels2BlenderUnits(imgSize[0],d)/2
        h=pixels2BlenderUnits(imgSize[1],d)/2
        verts.append([-w,-h,0])
        verts.append([w,-h,0])
        verts.append([w,h,0])
        verts.append([-w,h,0])
        faces.append([0,1,2,3])
        # create the mesh
        me=Blender.Mesh.New(celPlaneName)
        me.verts.extend(verts)
        me.faces.extend(faces)
        # make that an object, correctly placed at cursor
        ob=Object.New("Mesh",celPlaneName)
        ob.link(me)
        scn.objects.link(ob)
        ob.setLocation(cursorPos[0],cursorPos[1],cursorPos[2])
        ob.setEuler(camObj.rot)
        # apply the initial image as a texture
        tex=Texture.New(celPlaneName)
        tex.type=Texture.Types.IMAGE
        tex.setImage(img)
        tex.extend=Texture.ExtendModes.EXTEND
        tex.imageFlags=Texture.ImageFlags.INTERPOL|Texture.ImageFlags.USEALPHA|Texture.ImageFlags.MIPMAP
        mat=Material.New(celPlaneName)
        mat.setAlpha(0.0)
        mat.emit = 1.0
        mat.mode |= Material.Modes.ZTRANSP
        mat.setTexture(0,tex,Texture.TexCo.ORCO,Texture.MapTo.COL|Texture.MapTo.ALPHA)
        mats=ob.getMaterials()
        mats.append(mat)
        ob.setMaterials(mats)
        # cleanup
        Window.DrawProgressBar(1.0,"Done cel plane")
        return ob

if __name__ == '__main__':
    celPlaneGui()

I was just trying to see how do something similar.

I think what you’re after here is a good old Perspective Projection, followed by some kind of mysterious Blender Units-to-pixels scaling factor.

Beyond that, I can’t say much as I haven’t fully solved the problem, myself. :stuck_out_tongue:

Doesn’t Alt V do this already?

This script will be great for a mockup I’m planning to do that is similar to this one.

Some feedback after testing the script:
It imports the image, creates the rectangle and adds the new material with the flat mapping, although I had to assign the material manually.

It would be great if instead of Orco-Flat mapping it had a UV map, this would make it possible to see it on the 3D view.

Also if it was possible to import more than one image at a time it would make the workflow extremelly fast.

Thanks for this script!