Showing posts with label camera. Show all posts
Showing posts with label camera. Show all posts

Raytracing: concepts and code, part 4, the active camera


This is an article in a multipart series on the concepts of ray tracing. I am not sure where this will lead but I am open to suggestions. We will be creating code that will run inside Blender. Blender has ray tracing renderers of course but that is not the point: by reusing Python libraries and Blender's scene building capabilities we can concentrate on true ray tracing issues like shader models, lighting, etc.
I generally present stuff in a back-to-front manner: first an article with some (well commented) code and images of the results, then one or more articles discussing the concepts. The idea is that this encourages you to experiment and have a look at the code yourself before being introduced to theory. How well this works out we will see :-)

So far the series consists of the several articles labeled ray tracing concepts

In a further bit of code cleanup we'd like to get rid of the hardcoded camera position and look at direction by using the location of the active camera in the scene together with its rotation.
Fortunately very little code has to change to make this happen in our render method:

    # the location and orientation of the active camera
    origin = scene.camera.location
    rotation = scene.camera.rotation_euler
Using the rotation we can first create the camera ray as if it originated in the default -Z direction and then simply rotate it using the camera location:
    aspectratio = height/width
    # loop over all pixels once (no multisampling)
    for y in range(height):
        yscreen = ((y-(height/2))/height) * aspectratio
        for x in range(width):
            xscreen = (x-(width/2))/width
            # align the look_at direction
            dir = Vector((xscreen, yscreen, -1))
            dir.rotate(rotation)
Later we might even adapt this code to take into account the field of vision, but for now at least we can position and aim the active camera in the scene any way we like.

Code availability

The code is available on GitHub.

Raytracing: concepts and code, part 3, a render engine


This is an article in a multipart series on the concepts of ray tracing. I am not sure where this will lead but I am open to suggestions. We will be creating code that will run inside Blender. Blender has ray tracing renderers of course but that is not the point: by reusing Python libraries and Blender's scene building capabilities we can concentrate on true ray tracing issues like shader models, lighting, etc.
I generally present stuff in a back-to-front manner: first an article with some (well commented) code and images of the results, then one or more articles discussing the concepts. The idea is that this encourages you to experiment and have a look at the code yourself before being introduced to theory. How well this works out we will see :-)

So far the series consists of the several articles labeled ray tracing concepts

The code presented in the first article of this series was a bit of a hack: running from the text editor and lots of built-in assumptions is not the way to go so lets refactor this in a proper render engine that will be available alongside Blender's built-in renderers:

A RenderEngine

All we really have to do is to derive a class from Blender's RenderEngine class and register it.The class should provide a single method render() that takes a Scene parameter and returns a buffer with RGBA pixel values.
class CustomRenderEngine(bpy.types.RenderEngine):
    bl_idname = "ray_tracer"
    bl_label = "Ray Tracing Concepts Renderer"
    bl_use_preview = True

    def render(self, scene):
        scale = scene.render.resolution_percentage / 100.0
        self.size_x = int(scene.render.resolution_x * scale)
        self.size_y = int(scene.render.resolution_y * scale)

        if self.is_preview:  # we might differentiate later
            pass             # for now ignore completely
        else:
            self.render_scene(scene)

    def render_scene(self, scene):
        buf = ray_trace(scene, self.size_x, self.size_y)
        buf.shape = -1,4

        # Here we write the pixel values to the RenderResult
        result = self.begin_result(0, 0, self.size_x, self.size_y)
        layer = result.layers[0].passes["Combined"]
        layer.rect = buf.tolist()
        self.end_result(result)

Option panels

For a custom render engine all panels in the render and material options will be hidden by default. This makes sense because not all render engines use the same options. We are interested in just the dimensions of the image we have to render and the diffuse color of any material so we explicitly add our render engine to the list of COMPAT_ENGINES in each of those panels, along with the basic render buttons and material slot list.
def register():
    bpy.utils.register_module(__name__)
    from bl_ui import (
            properties_render,
            properties_material,
            )
    properties_render.RENDER_PT_render.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
    properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
    properties_material.MATERIAL_PT_context_material.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
    properties_material.MATERIAL_PT_diffuse.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)

def unregister():
    bpy.utils.unregister_module(__name__)
    from bl_ui import (
            properties_render,
            properties_material,
            )
    properties_render.RENDER_PT_render.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
    properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
    properties_material.MATERIAL_PT_context_material.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
    properties_material.MATERIAL_PT_diffuse.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)

reusing the ray tracing code

Our previous ray tracing code is adapted to use the height and width arguments instead of arbitrary constants:
def ray_trace(scene, width, height):     

    lamps = [ob for ob in scene.objects if ob.type == 'LAMP']

    intensity = 10  # intensity for all lamps
    eps = 1e-5      # small offset to prevent self intersection for secondary rays

    # create a buffer to store the calculated intensities
    buf = np.ones(width*height*4)
    buf.shape = height,width,4

    # the location of our virtual camera (we do NOT use any camera that might be present)
    origin = (8,0,0)

    aspectratio = height/width
    # loop over all pixels once (no multisampling)
    for y in range(height):
        yscreen = ((y-(height/2))/height) * aspectratio
        for x in range(width):
            xscreen = (x-(width/2))/width
            # get the direction. camera points in -x direction, FOV = approx asin(1/8) = 7 degrees
            dir = (-1, xscreen, yscreen)
            
            # cast a ray into the scene
            
            ... indentical code omitted ...

    return buf

Code availability

The code is available on GitHub. Remember that any test scene should be visible from an virtual camera located at (8,0,0) pointing in the -x direction. The actual camera is ignored for now.

Blender add-on: create a camera view filling backdrop

whether for product presentations or outdoor scenes, often you need a backdrop that nicely fills the camera view, preferably with a nice curve upwards to hide the horizon and also not larger than necessary to reduce the number of vertices and particles.

Creating this by hand is not massively time consuming but tedious enough to benefit from a small add-on: BackDrop.

Features

By default it creates a flat horizontal mesh at z=0 that fills the camera view exactly. By working with the margin option you can create a backdrop that is slightly bigger than the exact view and unchecking the Zero level option will allow you to position the backdrop on another z-coordinate.

The Lift option will elevate the far end of the backdrop resulting in a curved mesh. The curvature can be adjusted but that doesn't work well yet.

The backdrop mesh is parented to the camera so it will move with it if you rotate or translate the camera.

Availability

The plugin is available on my blenderaddons project on GitHub. Just download backdrop.py and install it from File -> user preferences -> Add-ons -> install from file

Bugs and limitations

The plugin cannot in all circumstances create a suitable backdrop, for example if the camera is pointing upward. If this is the case, a suitable error is displayed in the properties in the toolbar.

Also, the curvature control sucks, and in fact create a curves surface using bezier interpolation is not optiomal since the points are not evenly spaced. For this we need to convert it to an arc length parameterization but I don't have time to do that now.

Blender addon: visible vertices part III: bug fixes

A couple of weeks ago I presented a small addon that created a vertex group with weights that depend on the visibility of the vertex from the camera. This can be quite useful if you want to restrict particles to areas where they are actually visible, which will reduce render time and memory consumption and in a folow-up article I showed some new features. The addon was wel received but did contain a annoying bug which is fixed in this new version: vertices that were far enough behind the camera received weight as well; this is now fixed. I also disabled numerous print statements accidentally left in for debugging purposes.

Availability and usage

All functionality of this add-on plus a lot more is now available as a convenient all-in-one add-on on BlenderMarket. It comes with an extensive PDF manual and your purchase will encourage me to develop new Blender add-ons.

Version 0.0.3 of the simple add-on shown in this article is available from GitHub (right click the link to download the script somewhere then install it from Blender with File -> User Preferences -> Addons -> Install from file. Don't forget to enable the check box and don;t forget to remove any previous version from you addon directory).

Once installed it's available in weight paint mode from the Weights menu.

The addon might also be discussed in this BlenderArtists thread.

Blender Addon: Weight paint vertices visible from the active camera, part II: distance weights and more

A couple of weeks ago I presented a small addon that created a vertex group with weights that depend on the visibility of the vertex from the camera. This can be quite useful if you want to restrict particles to areas where they are actually visible, which will reduce render time and memory consumption.

The addon did take into other objects in the scene that could block the view but there was room for improvement. The first new feature in this version is that the weight of the visible vertices diminishes with the distance from the camera. For a field of grass particles you often can do with less particles at a greater distance without destroying the apparent density so this helps in cutting down the number of particles even further.

The second addition is the option to add a margin around the camera frame. Some extra particles just outside the camera view might be needed to prevent a sparse edge and to allow shadows from outside the view.

The final extra is the addition of a vertex weight edit modifier. Probably one of the lesser known modifiers, this nifty tool allows us to tweak vertex weights after the are calculated. The addon itself for example decreases the weight linearly with distance but if you want it to fall off in a different way this can be done quite easily by tweaking the curve in the modifier.

All these new options are on by default and the addon even makes sure the vertex weight modifier is visible in the properties panel just to draw some attention to it.

Example

The image below shows the generated weights falling of with the distance to the camera and with some extra margin selected:

Availability and usage

All functionality of this add-on plus a lot more is now available as a convenient all-in-one add-on on BlenderMarket. It comes with an extensive PDF manual and your purchase will encourage me to develop new Blender add-ons.

Version 0.0.2 of the simple add-on shown in this article is available from GitHub (right click the link to download the script somewhere then install it from Blender with File -> User Preferences -> Addons -> Install from file. Don't forget to enable the check box).

Once installed it's available in weight paint mode from the Weights menu.

The addon might also be discussed in this BlenderArtists thread.

Blender Addon: Weight paint vertices visible from the active camera

When working with particles it is often a waste of resources to distribute the particles outside the area visible from the camera. Fortunately the particle distribution can be controlled by a vertex group but weight painting the visible area by hand is a bit cumbersome. I therefore created a simple script that offers the option to paint the vertices of a mesh in the active vertex group with a weight of one if they are visible from the camera and zero otherwise. With a toggle switch you can select whether objects in the scene should be taken into account as well.

Availability and usage

All functionality of this add-on plus a lot more is now available as a convenient all-in-one add-on on BlenderMarket. It comes with an extensive PDF manual and your purchase will encourage me to develop new Blender add-ons.

The simple add-on presented in this article is available from GitHub (right click the link to download the script somewhere then install it from Blender with File -> User Preferences -> Addons -> Install from file. Don't forget to enable the check box).

Once installed it's available in weight paint mode from the Weights menu as shown below:

Simply select the mesh you want to paint, switch to weight paint mode and click Weights -> Visible Vertices. It will adjust the weights of the active vertex group and if the mesh hasn't got one, a new vertex group will be added. If you toggle the Full Scene option (in the VisibleVertices tab of the toolbar, you might need to press control-T to show it) objects in the scene might block the view as well as shown in the image below, where a cube and a sphere are shown in wireframe mode to reveal that blocked portions of the plane have been assigned a weight of zero.



The add-on was presented in this BlenderArtists thread.