Streaming data from Blender into Three.js (WebGL+Websockets)

Three.js rocks! Best WebGL library I have used so far.

That looks pretty impressive. How does it handle complex scenes?

neat :slight_smile: one step closer to have a blender webgl game engine.
three.js and mrdoob rocks indeed.

@Daccy, i haven’t tried a complex scene yet, but i expect it would perform well as long as not too many dynamic meshes are streamed. Three.js is very fast, so the bottleneck is not there.

hey this is very interesting - the ability of streaming is I think the most fascinating aspect of this!

Aermartin nice wish man - I think we are still a long way away from this but getting close :wink:

It would be a massive stress test for sure, but I wonder how this would hold up in the future for BConf presentations? Obviously not all of them, but it would certainly be interesting to see.

Anybody know how to solve this rotation bug?

Transform from Blender is streamed to a Three.js webclient, the data is in world space. Position and scale are correct. Rotation is correct if only the X axis is rotated. Rotation goes haywire when Y and Z are rotated. The video shows the affects of changing the client-side code to swap Y,Z - this gives better but still incorrect results.

Here is my javscript function that takes the message from blender and updates Three.js

function on_message(e) {
var data = ws.rQshiftStr();
var msg = JSON.parse( data );
dbugmsg = msg;

for (var name in msg['FX']) {
	var fx = FX[ name ];
	fx.enabled = msg['FX'][name][0];
	var uniforms = msg['FX'][name][1];
	if (fx.uniforms) {
		for (var n in uniforms) { fx.uniforms[ n ].value = uniforms[ n ]; }
	else {	// BloomPass
		for (var n in uniforms) { fx.screenUniforms[ n ].value = uniforms[ n ]; }

for (var name in msg['lights']) {
	var light;
	var ob = msg['lights'][ name ];
	name = name.replace('.', '_');

	if ( name in LIGHTS == false ) {	// Three.js bug, new lights are not added to old materials
		console.log('>> new light');
		LIGHTS[ name ] = light = new THREE.PointLight( 0xffffff );
		scene.add( light );
	light = LIGHTS[ name ];
	light.color.r = ob.color[0];
	light.color.g = ob.color[1];
	light.color.b = ob.color[2];
	light.distance = ob.dist;
	light.intensity =;

	light.position.x = ob.pos[0];
	light.position.y = ob.pos[2];
	light.position.z = -ob.pos[1];


for (var name in msg['meshes']) {
	var ob = msg['meshes'][ name ];
	var raw_name = name;
	name = name.replace('.', '_');

	if (name in Objects && Objects[name]) {
		m = Objects[ name ];
		if (ob.selected) { SELECTED = m; }

		var mat = new THREE.Matrix4(
		var props = mat.decompose( m.position, m.quaternion, m.scale );
		//m.position = props[ 0 ];
		//m.quaternion = props[ 1 ];
		//m.scale = props[ 2 ];

		m.position.x = ob.pos[0];
		m.position.y = ob.pos[2];
		m.position.z = -ob.pos[1];

		m.scale.x = ob.scl[0];
		m.scale.y = ob.scl[2];
		m.scale.z = ob.scl[1];

		m.rotation.x = ob.rot[0];
		m.rotation.y = ob.rot[2];
		m.rotation.z = -ob.rot[1];
		m.quaternion.w = ob.rot[0];
		m.quaternion.x = ob.rot[1];
		m.quaternion.y = ob.rot[2];
		m.quaternion.z = ob.rot[3];

		if (ob.color) {
			m._material.color.r = ob.color[0];
			m._material.color.g = ob.color[1];
			m._material.color.b = ob.color[2];
		m._material.shininess = ob.spec;

		if (ob.verts) {
			m.dirty_modifiers = true;
			m.subsurf = ob.subsurf;
			var vidx=0;
			for (var i=0; i <= ob.verts.length-3; i += 3) {
				var v = m.geometry_base.vertices[ vidx ].position;
				v.x = ob.verts[ i ];
				v.y = ob.verts[ i+2 ];
				v.z = -ob.verts[ i+1 ];
	else if (name in Objects == false) {
		console.log( '>> loading new collada' );
		Objects[ name ] = null;
		var loader = new THREE.ColladaLoader();
		loader.options.convertUpAxis = true;
		loader.load( '/objects/'+raw_name+'.dae', on_collada_ready );



Testing 2D Three.js effects overlays and random camera changes triggered by sound input.

Testing progressive image baking. Automated baking of diffuse, AO, and normal maps, with progressively higher resolution.

For rotations use Quaternions only. Because multiply of rotation matrices are not commutative. I see in your code, quaternions commented.

i think to solve this problem you need to use Quaternions

Blenders euler order is ‘XYZ’, but the equivalent euler rotation order in Three.js is ‘ZYX’ (they are just named the reverse) So try this:

m.rotation.x = ob.rot[0];
m.rotation.y = ob.rot[1];
m.rotation.z = ob.rot[2];
m.eulerOrder = ‘ZYX’;

Looks interesting. Where is the sourcecode of this?

no answer? Hm =(

Hi X3D, the source is hosted on google code.

new video by goathead