Wednesday, February 1, 2012

Progressive Baking


Texture maps are progressively downloaded from the Blender integrated server. Baking happens on demand and is fully automated. Client side javascript code adapts the texture request to best fit the given shader. Supported texture layers: diffuse, AO, specular intensity and displacement.

Hardware Displacement Mapping




The base mesh (without subdivision) is sent to the client. The client then applies subdivision and recalculates the tangents. The displacement map is progressively downloaded starting at 64x64 and stopping at 512x512 resolution. The displacement happens in hardware using GLSL shader model 3.0. Code recycled from the Three.js examples.

Tuesday, January 24, 2012

Pyppet - WebGL Streaming



Check out Three.js on github and get ready to be blown away, so much power in 380KB.

Websockets Streaming Mesh - WebGL Client


Websockify by Joel Martin has got everything you need to get websockets going in Python3.

Supported Streaming Modifiers



  • Cast,
  • Curve,
  • Displace,
  • Hook,
  • Lattice,
  • MeshDeform,
  • ShrinkWrap,
  • SimpleDeform,
  • Smooth,
  • Warp,
  • Wave



Streaming the default blender monkey head (500 vertices) to the web-client creates a load of about 350KB per-second. This is still using ASCII Json for transport, so hopefully in the future a binary stream or other packing method could cut this down even more.

Thursday, January 5, 2012

Pyppet2 - Audio Analysis



Prototype for real-time musical performance at live events, concerts. TODO: OSC integration to support pro music hardware, sample mixer integrated with physics system (collisions trigger sounds), particles, multiple full screen windows and camera switching driver input.

Blenderartists thread

pyppet 1.9.3b source code

Update


linux install guide
feature requests approved:


  • "assign multiple movement and rotation controls to one OSC input"

  • "adjust scale, and attack/release function" (callbacks)

Wednesday, July 6, 2011

C++ Wrapper Generator - Part1

There are several ways to wrap C++ and integrate it with Python, have a look on stackoverflow. Many wrapper generators rely on GccXML, but the project has been dead for years and has trouble parsing some newer C++. Another option is Swig, still active, but appears to require hand written wrapper code, and lacks support for things like nested classes. Clang was yet another option, it was able to output its parse tree as XML, but this feature was recently broken. So after much searching I finally found CppHeaderParser by Jashua Cloutier on SourceForge, the source code is all contained in a single file and very easy to understand. Since then (back in March), in my free time, I have been hacking away on CppHeaderParser; adding support for parsing more complex C++, resolving typedef's, nested classes, etc. For anyone else interesting in building a wrapper generator on top of it, you will be happy to hear it remains less than 2,000 lines of code, and very easy to modify to fit your particular needs. It is already being used successfully by the Emscripten project to generate a C wrapper and Javascript bindings, kripken's blog.

RPythonic-0.3.8 uses CppHeaderParser-2.0 as a backend to parse the C++ code and generate a C wrapper and Python-ctypes bindings. There is going to be a speed hit calling C++ through a C API over ctypes. Future work will solve the speed problem by generation of RPython (RFFI) bindings so that RPython can call into C++ code.

Work on both CppHeaderParser and the wrapper generator will continue, and should stablize in the next few releases. Basic features that are working now include: operators (==, +=, -=, etc.), enums, typedefs, classes and nested classes, class properties, structs, arrays, doxygen, and C compatible types. The major missing feature is wrapping of templates.

download all wrapper generator samples here


C Wrapper Sample - OgrePaged Method Call



/* Forests::TreeLoader3D.addTree */
/** \brief Adds an entity to the scene with the specified location, rotation, and scale.
\param entity The entity to be added to the scene.
\param position The desired position of the tree
\param yaw The desired rotation around the vertical axis in degrees
\param scale The desired scale of the entity

While TreeLoader3D allows you to provide full 3-dimensional x/y/z coordinates,
you are restricted to only yaw rotation, and only uniform scale.

\warning By default, scale values may not exceed 2.0. If you need to use higher scale
values than 2.0, use setMaximumScale() to reconfigure the maximum. */
/*void addTree ( Ogre : : Entity * entity , __const__ Ogre : : Vector3 & position , Ogre : : Degree yaw = Ogre : : Degree ( 0 ) , Ogre : : Real scale = 1 0f , void * userData = __null ) ;
returns_fundamental: True
returns_pointer: 0
returns_reference: False
returns: void
returns_class: False
*/
void TreeLoader3D_addTree( void* object, void* arg0, void* arg1, void* arg2 ) {
((Forests::TreeLoader3D*)object)->addTree(
//type: Ogre::Entity *, raw_type: Ogre::Entity, pointer: 1, ,
(Ogre::Entity*)arg0,
//type: const Ogre::Vector3 &, raw_type: Ogre::Vector3, constant: 1, reference: 1, ,
(Ogre::Vector3&)arg1,
//type: Ogre::Degree, raw_type: Ogre::Degree, default: Ogre : : Degree ( 0, ,
(Ogre::Degree&)arg2 );
}



C Wrapper Sample - BulletPhysics - Set Property



/* --------------- class btVector3 --------------- */
/* */
/**@brief btVector3 can be used to represent 3D points and vectors.
* It has an un-used w component to suit 16-byte alignment when btVector3 is stored in containers. This extra component can be used by derived classes (Quaternion?) or by user
* Ideally, this class should be replaced by a platform optimized SIMD version that keeps the data in registers
*/
/* ---------properties--------- */
//type: btScalar, raw_type: btScalar, typedefs: 1, fundamental: True, array: 4, ctypes_type: ctypes.c_float,
void btVector3_m_floats__property_set__( void* object,btScalar arg[4] ) {
((btVector3*)object)->m_floats[ 0 ] = arg[ 0 ];
((btVector3*)object)->m_floats[ 1 ] = arg[ 1 ];
((btVector3*)object)->m_floats[ 2 ] = arg[ 2 ];
((btVector3*)object)->m_floats[ 3 ] = arg[ 3 ]; }



C Wrapper Sample - BulletPhysics - Operator Overloading



/**@brief Scale the vector
* @param s Scale factor */
/*} inline btVector3 & operator * = ( __const__ btScalar & s ) {
returns_fundamental: False
returns_pointer: 0
returns_reference: True
returns: btVector3
returns_class: True
*/
void* btVector3___operator____imult__( void* object, const btScalar & arg0 ) {
return (void*)(& (((btVector3&)object)*=(arg0)) );
}


Pass1: Generate C Wrapper



  • flatten all method calls to functions

  • the instance is passed as the first argument

  • all instances are passed as void pointers

  • C compatible types are passed directly

  • objects returned are cast to void pointers

  • create wrapper functions for operators

  • create wrapper functions for get/set properties



Pass2: Generate Python-ctypes Wrapper



  • create a Python class for each C++ class

  • __init__ calls the constructor C wrapper

  • each method calls the C wrapper function

  • methods that return instances are passed to the matching python class

  • __del__ calls the destructor

  • operators overload: __mult__, __add__, etc..

  • __getattr__, __setattr__ call the get/set wrapper functions

Thursday, May 19, 2011

ODE-ctypes in Blender



http://rpythonic.googlecode.com/files/Active-Physics-Blender-release1.zip


ODE-ctypes addon for blender is deprecated, code moved into Pyppet2 core engine.

Tuesday, May 10, 2011

Kinect Hand Tracking



Ctypes and Threads


Check out this ctypes technique to escape the GIL.



Fast Hand Detection





HAAR wavelets are by far the most popular way of detecting hands or other features, the problem is speed, the Haar cascade can easily take a single core to 100% usage, and this is not suitable if we plan to run this hand detector within another program like Blender or RealXtend and maintain good performance.

Another method that is faster is to check for convexity defects of contours, this blog by Andol has a good overview of the techniques. Using the heuristic 4 or more defects is hand, and simply checking for defects among the many contour passes will yield false-positives from noise. The first trick is to filter out this noise on the contour with extreme polygon reduction, using the function cv.ApproxPoly with a factor of 20-30.0 or more. This reduces the head to a few triangles, while keeping the star-shape of the hand.

Monday, April 18, 2011

RPython modules for CPython




It is now possible to use RPythonic to write CPython extension modules in RPython, RPythonic will work as the front-end that uses the PyPy translation toolchain to generate C code, compile it with GCC, package it in a cache directory with generated ctypes wrappers, and finally replace the decorated functions in-place in CPython.

RPythonic 0.2.8



RPython CPython Module API



import os, sys
sys.path.append('..')
import rpythonic
rpythonic.set_cache( '../cache' )
rpythonic.set_pypy_root( '../../pypy' )
################################
rpy = rpythonic.RPython()
@rpy.bind() # declare arg types is optional if,
def add( a=1, b=1000 ): # keyword defaults are given
return a+b
@rpy.bind(a=float, b=float)
def sub( a, b ):
return a-b
rpy.cache('test1') # only compiles if cache is dirty
########### now functions are using compiled version ###########
print add( 99, 88 )

Module Compiling and Caching


Sunday, November 14, 2010

Blender Python Operator API

The classic __init__ method is not used when defining a custom bpy operator. Instead you will define class-level attributes using the types in bpy.props: BoolProperty, StringProperty, FloatProperty, IntProperty, etc. Ignore that the values returned by bpy.props types are always a tuple with the first item a pointer to the property function just-called, and the second item a dictionary that contains the arguments you passed to the property function.

bpy.types




All widgets and operators dynamically appear in the bpy.types listing object. Care must be taken to give your operator a unique class name, and a unique 'bl_idname'. By not giving a unique name you can override blender's default behavior or interface. For example lets override the INFO menu with extra buttons.



class INFO_HT_header(bpy.types.Header):
bl_space_type = 'INFO'
def draw(self, context):
layout = self.layout
wm = context.window_manager
window = context.window
scene = context.scene
rd = scene.render
layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER', text="")
#layout.operator("ogre_export", text="Ogre")
row = layout.row(align=True)
sub = row.row(align=True)
sub.menu("INFO_MT_instances")
sub.menu("INFO_MT_groups")
sub.menu("INFO_MT_actors")
sub.menu("INFO_MT_dynamics")

if True: #context.area.show_menus:
sub.menu("INFO_MT_file")
sub.menu("INFO_MT_add")
if rd.use_game_engine: sub.menu("INFO_MT_game")
else: sub.menu("INFO_MT_render")
layout.separator()
if window.screen.show_fullscreen:
layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous")
layout.separator()
else:
layout.template_ID(context.window, "screen", new="screen.new", unlink="screen.delete")

layout.separator()
layout.template_running_jobs()
layout.template_reports_banner()

layout.separator()
if rd.has_multiple_engines:
layout.prop(rd, "engine", text="")
layout.template_header()
if context.area.show_menus:
layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete")
layout.label(text=scene.statistics())
layout.menu( "INFO_MT_help" )
else:
screen = context.screen
row = layout.row(align=True)
row.operator("screen.frame_jump", text="", icon='REW').end = False
row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False
if not screen.is_animation_playing:
row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True
row.operator("screen.animation_play", text="", icon='PLAY')
else:
sub = row.row()
sub.scale_x = 2.0
sub.operator("screen.animation_play", text="", icon='PAUSE')
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True
row.operator("screen.frame_jump", text="", icon='FF').end = True

row = layout.row(align=True)
if not scene.use_preview_range:
row.prop(scene, "frame_start", text="Start")
row.prop(scene, "frame_end", text="End")
else:
row.prop(scene, "frame_preview_start", text="Start")
row.prop(scene, "frame_preview_end", text="End")

layout.prop(scene, "frame_current", text="")


def gather_instances():
instances = {}
for ob in bpy.data.objects:
if ob.data and ob.data.users > 1:
if ob.data not in instances: instances[ ob.data ] = []
instances[ ob.data ].append( ob )
return instances

def select_instances( context, name ):
for ob in bpy.data.objects: ob.select = False
ob = bpy.data.objects[ name ]
if ob.data:
inst = gather_instances()
for ob in inst[ ob.data ]: ob.select = True
bpy.context.scene.objects.active = ob

def select_group( context, name, options={} ):
for ob in bpy.data.objects: ob.select = False
for grp in bpy.data.groups:
if grp.name == name:
bpy.context.scene.objects.active = grp.objects[0]
for ob in grp.objects: ob.select = True

class INFO_MT_instances(bpy.types.Menu):
bl_label = "Instances"
def draw(self, context):
layout = self.layout
inst = gather_instances()
for data in inst:
ob = inst[data][0]
op = layout.operator("select_instances", text=ob.name) # operator has no variable for button name?
op.mystring = ob.name
layout.separator()

class INFO_MT_instance(bpy.types.Operator):
'''select instance group'''
bl_idname = "select_instances"
bl_label = "Select Instance Group"
bl_options = {'REGISTER', 'UNDO'}
mystring= StringProperty(name="MyString", description="...", maxlen=1024, default="my string")
@classmethod
def poll(cls, context): return True
def invoke(self, context, event):
print( 'invoke select_instances op', event )
select_instances( context, self.mystring )
return {'FINISHED'}

class INFO_MT_groups(bpy.types.Menu):
bl_label = "Groups"
def draw(self, context):
layout = self.layout
for group in bpy.data.groups:
op = layout.operator("select_group", text=group.name) # operator no variable for button name?
op.mystring = group.name
layout.separator()

class INFO_MT_group(bpy.types.Operator):
'''select group'''
bl_idname = "select_group"
bl_label = "Select Group"
bl_options = {'REGISTER', 'UNDO'}
mystring= StringProperty(name="MyString", description="...", maxlen=1024, default="my string")
@classmethod
def poll(cls, context): return True
def invoke(self, context, event):
select_group( context, self.mystring )
return {'FINISHED'}

class INFO_MT_actors(bpy.types.Menu):
bl_label = "Actors"
def draw(self, context):
layout = self.layout
for ob in bpy.data.objects:
if ob.game.use_actor:
op = layout.operator("select_actor", text=ob.name)
op.mystring = ob.name
layout.separator()

class INFO_MT_actor(bpy.types.Operator):
'''select actor'''
bl_idname = "select_actor"
bl_label = "Select Actor"
bl_options = {'REGISTER', 'UNDO'} # Options for this panel type
mystring= StringProperty(name="MyString", description="...", maxlen=1024, default="my string")
@classmethod
def poll(cls, context): return True
def invoke(self, context, event):
bpy.data.objects[self.mystring].select = True
return {'FINISHED'}

class INFO_MT_dynamics(bpy.types.Menu):
bl_label = "Dynamics"
def draw(self, context):
layout = self.layout
for ob in bpy.data.objects:
if ob.game.physics_type in 'DYNAMIC SOFT_BODY RIGID_BODY'.split():
op = layout.operator("select_dynamic", text=ob.name)
op.mystring = ob.name
layout.separator()

class INFO_MT_dynamic(bpy.types.Operator):
'''select dynamic'''
bl_idname = "select_dynamic"
bl_label = "Select Dynamic"
bl_options = {'REGISTER', 'UNDO'} # Options for this panel type
mystring= StringProperty(name="MyString", description="...", maxlen=1024, default="my string")
@classmethod
def poll(cls, context): return True
def invoke(self, context, event):
bpy.data.objects[self.mystring].select = True
return {'FINISHED'}

Monday, October 4, 2010

Inside The Blender C API - Part2

In the "main" function of "creator.c" the function call "WM_keymap_init(C)" ('C' blender-context) setups basic mouse and keyboard handling. Calls to CTX_wm_manager(C) which returns a pointer to the wmWindowManager struct contained by C. WM_keymap_init, a new wmKeyConfig struct is created by WM_keyconfig_new, passed to: wm_window_keymap, ED_spacetypes_keymap, and WM_keyconfig_userdef. Finally the wmKeyConfig is assigned to the wmWindowManager struct as `defaultconf`.

Blender Context.

bContext

:
blender/source/blender/blenkernel/BKE_context.h

C contains: thread index, window manager struct, data-context-struct, and eval struct. The window manager struct contains: a manager, window, screen, area, region, menu, and store. The data-context-struct contains the scene and python context.

blenkernel note:


Many functions defined in blender/source/blender/blendkernel are prefixed with BKE, but not all. CTX_create and CTX_wm_manager are two examples of blendkernel functions that do not start with BKE.

DNA_windowmanager_types.h


The wmWindowManager struct and wmKeyConfig are defined in blender/source/blender/makesdna/DNA_windowmanager_types.h. Other important window manager related structs also define here are: wmWindow and wmOperator. The wmWindow struct contains a pointer to a wmEvent struct named `eventstate`, and a list named `queue` that contains all events. Two other event lists inside wmWindow are: `handlers` and `modalhandlers`.

WM_types.h and wm_event_types.h


Both of these headers are in: blender/source/blender/windowmanager/. wmEvent and other window event related things are defined here, the structs are in WM_types.h and the enums are in wm_event_types.h. Below is the definition of wmEvent:

/* each event should have full modifier state */
/* event comes from eventmanager and from keymap */
typedef struct wmEvent {
struct wmEvent *next, *prev;
short type; /* event code itself (short, is also in keymap) */
short val; /* press, release, scrollvalue */
short x, y; /* mouse pointer position, screen coord */
short mval[2]; /* region mouse position, name convention pre 2.5 :) */
short unicode; /* future, ghost? */
char ascii; /* from ghost */
char pad;
/* previous state */
short prevtype;
short prevval;
short prevx, prevy;
double prevclicktime;
short prevclickx, prevclicky;
/* modifier states */
short shift, ctrl, alt, oskey; /* oskey is apple or windowskey, value denotes order of pressed */
short keymodifier; /* rawkey modifier */
short pad1;
/* keymap item, set by handler (weak?) */
const char *keymap_idname;
/* custom data */
short custom; /* custom data type, stylus, 6dof, see wm_event_types.h */
short customdatafree;
int pad2;
void *customdata; /* ascii, unicode, mouse coords, angles, vectors, dragdrop info */
} wmEvent;

Tuesday, September 28, 2010

RPythonic

RPythonic takes in C code and outputs three different formats: 1. pure RPython code, 2. ctypes wrappers, and 3. rffi wrappers. Using the PyPy translation toolchain the pure RPython code can be translated back to C, or C# and Java (allowing your C code to be executed by .Net or Java runtimes). The generated ctypes wrapper can be used from CPython. The rffi wrappers allow you to use C code from RPython. RPythonic is built using PycParser, a powerful C parser written by Eli Bendersky written in Python.

Why not Pygccxml?
Pygccxml is made up of about 50 files and several thousands of lines of code, totalling about 1MB of code; and relies on the external program Gccxml. Gccxml is old and development has stalled. Another automatic binding generator Pybindgen uses Pygccxml, and the interface between Pybindgen and Pygccxml alone is over two thousands lines of code, not pretty!

PycParser is super clean, 10 files, less than 150KB of code; is pure Python and relies on no external programs. While Pygccxml can parse C/C++ code, it can not parse the function bodies. On the other hand, PycParser can fully parse C and function bodies, but not C++. For RPython and ctypes wrappers we are only interested in C; and because PycParser can fully parse C, translation of C to RPython is also possible at the same time the bindings are generated.

RPythonic on google code

Thursday, April 9, 2009