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

(goathead) #1

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

(Daccy) #2

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

(aermartin) #3

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

(goathead) #4

@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.

(cekuhnen) #5

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:

(BenDansie) #6

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.

(goathead) #7

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 );



(goathead) #8

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

(goathead) #9

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

(gonchar) #10

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

(Hyzhak) #11

i think to solve this problem you need to use Quaternions

(rectalogic) #12

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’;

(X3DModels) #13

Looks interesting. Where is the sourcecode of this?

(X3DModels) #14

no answer? Hm =(

(goathead) #15

Hi X3D, the source is hosted on google code.

(Meta-Androcto) #16

new video by goathead