Meshcripter: a first taste

Posted: January 19, 2011 in Meshcripter
Tags: , , , ,

In this post, I’m going to show you some examples of Meshcripter using.

If you’re trembling, watch this (I suggest you to watch it on Youtube for a better quality):

Meshcripter provides a handful of global objects that manage the interaction with the main components (the mesh, the renderer, the console, and a special algebraic object). These are specialized as soon as the user needs finer grain objects (e.g. a face). We have four global objects:

mesh manages mesh interaction/access;

viewer allows customizations of the renderer;

algebra endows the console with vector and matrices;

console provides access to the console itself;

Mesh Access

Mesh access operations are, for example, mesh traversal and interaction (performed through mesh global object). These operations allow us to obtain references to finer grain scripters:

# vertex = mesh.vertex(0)
vertex [0] (0.00,0.00,0.00)
# vertex.coords()
0.00,0.00,0.00

vertex is a “console-reference” to vertex 0 (each element has a unique integer index – like in Topology). Suppose we want to change the coordinates of vertex:

# vertex.changeCoords([0.1,0.1,0.1])

This function modifies the coordinates of the caller vertex, receiving an array as a parameter. Now, we generate a 20×20 quads grid and we map it to a disk (circle):

Grid Generation panel

Remember the parametric form of the circle:

x = radius u cos(v)
y = radius u sin(v)
z = 0
u ∈ [0,1]
v ∈ [0,2π]
radius is a real number

We use it to map the grid to a disk:

for(i=0; i<mesh.verts_num(); i++) {
          x = mesh.vertex(i).coords()[0];
          y = mesh.vertex(i).coords()[1];
          mesh.vertex(i).changeCoords([
                   y*Math.cos(x*Math.PI*2),
                   y*Math.sin(x*Math.PI*2),
                   0
         ]);
}

Grid mapped to a unit-disk

One can perform as many mappings as one wants to, knowing the function to use. The result can be exported in a new mesh.

Now, we obtain a reference to the face 0 and we show some basic information about that:

# face = mesh.face(0)
face [0] {vertices->(0, 11, 12, 1) edges->(3, 0, 1, 2)}

It means the face 0 is bounded by vertices 0, 11, 12, 1 and by edges 3, 0, 1, 2. Obviously, it is possible to grasp a reference to one of these:

# vertex_of_face = face.vertex(0)
vertex [0] (0.00,0.00,0.00)

These initial functions suffice to deal with several issues (e.g. Topology, Geometry).

Mesh Refinement

# mesh.split_face(54)
# mesh.split_face(53)
# mesh.split_face(44)
# mesh.split_face(43)

QuadTree splits performed on some faces of the grid

The effect of some quadtree splits is shown above. Below, barycentric splits are figured:

A couple of barycentric splits performed on the grid

Observe a progressive split on a torus (the doughnut), starting from a 3×3 quads grid:

Progressive splits on a torus (3x3 to 96x96).

The latter rendering is performed by a couple of shaders, implementing the Phong lighting model.

Renderer Customization

The object viewer provides several functions able to customize the renderer. For example, materials/lights setting, shaders, faces/edges selection/highlighting, mesh subsets rendering.

We select some faces through the picking function and return them stopping it:

Faces picking of a torus

# faces=viewer.stopPicking()
7,17,27,37,47,57,67,77,87,97

faces is an array containing the indices of the selected faces . Let’s draw only these:

# viewer.faces(faces)

Drawing of the selected faces

Similarly with some edges:

# edges = [3,6,9,12,15,18,21,24,27,30]
# viewer.edges(edges)

Drawing of some edges

viewer allows us to employ custom materials. Let’s create an emerald (searching the Web for the values) and use it together with a Blinn-Phong light per-pixel shader:

# emerald = viewer.newMaterial()
# emerald.setAmbient([0.0215, 0.1745, 0.0215, 1])
# emerald.setDiffuse([0.07568, 0.61424, 0.07568, 1])
# emerald.setSpecular([0.633, 0.727811, 0.633, 1])
# emerald.setShininess(0.6*128)
# viewer.setMaterial(emerald)

Elephant mesh rendered with an emerald material

We can manage lights properties (a single source, for now):

# viewer.lightPos([1,1,1,0])
# viewer.lightAmb([1,0,0,0])

These commands, for example, sets the position and the ambient component of the light.

Some built-in shaders are shown above (the user can also write his own shaders):

Different shaders applied on the elephant (Toon, Brick, Bumpy, Normals as RGB color)

Computational Functionalities

Meshcripter provides both sparse matrices and vectors (supplied by boost library). The reason arises from its original purpose: supporting the Metrized Chains Method (plm.dia.uniroma3.it/milicchio/2009/10/discrete-physics-using-metrized-chains). Specifically, one can associate a value for each vertices (faces) and color the mesh according to these values (using a color map – e.g. a heat field). These data could be imported or computed by Meshcripter, thanks to its “algebraic support”. For example, we can render two Dirac impulses on a toroidal grid (opposite bounded vertices and edges are “topologically equivalent”):

Two Dirac impulses on a quads grid

Impulses on the refined grid


Distorted Grid (in according to the impulses impact)

It’s not important how to obtain those values, but the support to matrices calculation is significant:

# matrix = algebra.getMatrix(1,1)
matrix { _->0}
# matrix_2 = algebra.newMatrix([[1,1],[2,2]])
matrix {(0,0)->1, (0,1)->1, (1,0)->2, (1,1)->2}
# vector = algebra.newVector([1,2,3,4])
vector {0->1, 1->2, 2->3, 3->4}

Mehscripter supplies all the functions for accessing/setting values on matrices and vectors, in addition to sum, inversion, product, transposition, SOE solving, etc.
It’s interesting to observe the full integration with Javascript arrays (in both “directions”):

# vector = algebra.getVector(16)
vector { _->0}
# vector.set(0,10)
# vector.set(10,-1.05)
# vector
{0->10, 10->-1.05, _->0}
# js_array = vector.toArray()
10,0,0,0,0,0,0,0,0,0,-1.05,0,0,0,0,0
# js_array[0]
10
# js_array[1]
0
# js_array[3]=4
4
# js_array
10,0,0,4,0,0,0,0,0,0,-1.05,0,0,0,0,0
# vector.replace(js_array)
# vector
{0->10, 3->4, 10->-1.05, _->0}

Scripts loaded from a file

Sometimes writing programs by hand is inconvenient, it could be better to load them from a file, also for reusing purposes. For example, suppose you know a lot of materials and you want to store their values in a file, thus you’ll be able to employ them when you need to. Then you can just write a simple txt file (or any format you like) and load it when you want to, invoking the load function (or using the console menu):

# load("materials.txt")

Through the scripts, writing own functions is as easy as loading them. This capability makes the tool highly customizable. As a final example, we write a script to map a grid to a sinusoidal surface:

for(i=0;i<mesh.verts_num();i++) {
	x = mesh.vertex(i).coords()[0];
	y = mesh.vertex(i).coords()[1];
	mesh.vertex(i).changeCoords([
		x, y,
		0.3*Math.sin(x*2*Math.PI)*Math.sin(y*2*Math.PI)]);
}

The sinusoidal surface obtained by the script listed above

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s