فهرست منبع

Instancing is working! (hooray)

Juan Linietsky 8 سال پیش
والد
کامیت
943d27f46d

+ 1 - 0
drivers/gles3/rasterizer_gles3.cpp

@@ -124,6 +124,7 @@ void RasterizerGLES3::begin_frame(){
 	storage->frame.time[3]=Math::fmod(time_total,60);
 	storage->frame.count++;
 
+	storage->update_dirty_multimeshes();
 	storage->update_dirty_skeletons();
 	storage->update_dirty_shaders();
 	storage->update_dirty_materials();

+ 92 - 0
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -1098,6 +1098,55 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) {
 			glBindVertexArray(s->array_id); // everything is so easy nowadays
 
 		} break;
+
+		case VS::INSTANCE_MULTIMESH: {
+
+			RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh*>(e->owner);
+			RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+			glBindVertexArray(s->instancing_array_id); // use the instancing array ID
+			glBindBuffer(GL_ARRAY_BUFFER,multi_mesh->buffer); //modify the buffer
+
+			int stride = (multi_mesh->xform_floats+multi_mesh->color_floats)*4;
+			glEnableVertexAttribArray(8);
+			glVertexAttribPointer(8,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+0);
+			glVertexAttribDivisorARB(8,1);
+			glEnableVertexAttribArray(9);
+			glVertexAttribPointer(9,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+4*4);
+			glVertexAttribDivisorARB(9,1);
+
+			int color_ofs;
+
+			if (multi_mesh->transform_format==VS::MULTIMESH_TRANSFORM_3D) {
+				glEnableVertexAttribArray(10);
+				glVertexAttribPointer(10,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+8*4);
+				glVertexAttribDivisorARB(10,1);
+				color_ofs=12*4;
+			} else {
+				glDisableVertexAttribArray(10);
+				glVertexAttrib4f(10,0,0,1,0);
+				color_ofs=8*4;
+			}
+
+			switch(multi_mesh->color_format) {
+
+				case VS::MULTIMESH_COLOR_NONE: {
+					glDisableVertexAttribArray(11);
+					glVertexAttrib4f(11,1,1,1,1);
+				} break;
+				case VS::MULTIMESH_COLOR_8BIT: {
+					glEnableVertexAttribArray(11);
+					glVertexAttribPointer(11,4,GL_UNSIGNED_BYTE,GL_TRUE,stride,((uint8_t*)NULL)+color_ofs);
+					glVertexAttribDivisorARB(11,1);
+
+				} break;
+				case VS::MULTIMESH_COLOR_FLOAT: {
+					glEnableVertexAttribArray(11);
+					glVertexAttribPointer(11,4,GL_FLOAT,GL_FALSE,stride,((uint8_t*)NULL)+color_ofs);
+					glVertexAttribDivisorARB(11,1);
+				} break;
+			}
+
+		} break;
 	}
 
 }
@@ -1133,6 +1182,25 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
 			}
 
 		} break;
+		case VS::INSTANCE_MULTIMESH: {
+
+			RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh*>(e->owner);
+			RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry);
+
+			int amount = MAX(multi_mesh->size,multi_mesh->visible_instances);
+
+			if (s->index_array_len>0) {
+
+				glDrawElementsInstancedARB(gl_primitive[s->primitive],s->index_array_len, (s->array_len>=(1<<16))?GL_UNSIGNED_INT:GL_UNSIGNED_SHORT,0,amount);
+
+			} else {
+
+				glDrawArraysInstancedARB(gl_primitive[s->primitive],0,s->array_len,amount);
+
+			}
+
+		} break;
+
 	}
 
 }
@@ -1481,6 +1549,11 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
 			}
 		}
 
+		if ((prev_base_type==VS::INSTANCE_MULTIMESH) != (e->instance->base_type==VS::INSTANCE_MULTIMESH)) {
+			state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING,e->instance->base_type==VS::INSTANCE_MULTIMESH);
+			rebind=true;
+		}
+
 		if (material!=prev_material || rebind) {
 
 			rebind = _setup_material(material,p_alpha_pass);
@@ -1519,6 +1592,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
 	glFrontFace(GL_CW);
 	glBindVertexArray(0);
 
+	state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING,false);
 	state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false);
 	state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false);
 	state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false);
@@ -2414,6 +2488,24 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_
 			} break;
 			case VS::INSTANCE_MULTIMESH: {
 
+				RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getptr(inst->base);
+				ERR_CONTINUE(!multi_mesh);
+
+				if (multi_mesh->size==0 || multi_mesh->visible_instances==0)
+					continue;
+
+				RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getptr(multi_mesh->mesh);
+				if (!mesh)
+					continue; //mesh not assigned
+
+				int ssize = mesh->surfaces.size();
+
+				for (int i=0;i<ssize;i++) {
+
+					RasterizerStorageGLES3::Surface *s = mesh->surfaces[i];
+					_add_geometry(s,inst,multi_mesh,-1,p_shadow);
+				}
+
 			} break;
 			case VS::INSTANCE_IMMEDIATE: {
 

+ 489 - 51
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -2716,31 +2716,45 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P
 
 		//generate arrays for faster state switching
 
-		glGenVertexArrays(1,&surface->array_id);
-		glBindVertexArray(surface->array_id);
-		glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+		for(int i=0;i<2;i++) {
 
-		for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+			if (i==0) {
+				//for normal draw
+				glGenVertexArrays(1,&surface->array_id);
+				glBindVertexArray(surface->array_id);
+				glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
+			} else {
+				//for instancing draw (can be changed and no one cares)
+				glGenVertexArrays(1,&surface->instancing_array_id);
+				glBindVertexArray(surface->instancing_array_id);
+				glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id);
 
-			if (!attribs[i].enabled)
-				continue;
+			}
+
+
+			for(int i=0;i<VS::ARRAY_MAX-1;i++) {
+
+				if (!attribs[i].enabled)
+					continue;
+
+				if (attribs[i].integer) {
+					glVertexAttribIPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+				} else {
+					glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
+				}
+				glEnableVertexAttribArray(attribs[i].index);
 
-			if (attribs[i].integer) {
-				glVertexAttribIPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
-			} else {
-				glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset);
 			}
-			glEnableVertexAttribArray(attribs[i].index);
 
-		}
+			if (surface->index_id) {
+				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+			}
 
-		if (surface->index_id) {
-			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id);
+			glBindVertexArray(0);
+			glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
 		}
 
-		glBindVertexArray(0);
-		glBindBuffer(GL_ARRAY_BUFFER,0); //unbind
-
 	}
 
 	{
@@ -3068,14 +3082,14 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
 
 	if (mesh->custom_aabb!=AABB())
 		return mesh->custom_aabb;
-/*
+
 	Skeleton *sk=NULL;
 	if (p_skeleton.is_valid())
 		sk=skeleton_owner.get(p_skeleton);
-*/
+
 	AABB aabb;
-	/*
-	if (sk && sk->bones.size()!=0) {
+
+	if (sk && sk->size!=0) {
 
 
 		for (int i=0;i<mesh->surfaces.size();i++) {
@@ -3088,21 +3102,67 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
 				const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr();
 				const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr();
 
-				int sbs = sk->bones.size();
+				int sbs = sk->size;
 				ERR_CONTINUE(bs>sbs);
-				Skeleton::Bone *skb = sk->bones.ptr();
+				float *skb = sk->bones.ptr();
+
+
 
 				bool first=true;
-				for(int j=0;j<bs;j++) {
-
-					if (!skused[j])
-						continue;
-					AABB baabb = skb[ j ].transform_aabb ( skbones[j] );
-					if (first) {
-						laabb=baabb;
-						first=false;
-					} else {
-						laabb.merge_with(baabb);
+				if (sk->use_2d) {
+					for(int j=0;j<bs;j++) {
+
+						if (!skused[j])
+							continue;
+
+						float *dataptr = &skb[8*j];
+
+						Transform mtx;
+
+						mtx.basis.elements[0][0]=dataptr[ 0];
+						mtx.basis.elements[0][1]=dataptr[ 1];
+						mtx.origin[0]=dataptr[ 3];
+						mtx.basis.elements[1][0]=dataptr[ 4];
+						mtx.basis.elements[1][1]=dataptr[ 5];
+						mtx.origin[1]=dataptr[ 7];
+
+						AABB baabb = mtx.xform( skbones[j] );
+						if (first) {
+							laabb=baabb;
+							first=false;
+						} else {
+							laabb.merge_with(baabb);
+						}
+					}
+				} else {
+					for(int j=0;j<bs;j++) {
+
+						if (!skused[j])
+							continue;
+
+						float *dataptr = &skb[12*j];
+
+						Transform mtx;
+						mtx.basis.elements[0][0]=dataptr[ 0];
+						mtx.basis.elements[0][1]=dataptr[ 1];
+						mtx.basis.elements[0][2]=dataptr[ 2];
+						mtx.origin.x=dataptr[ 3];
+						mtx.basis.elements[1][0]=dataptr[ 4];
+						mtx.basis.elements[1][1]=dataptr[ 5];
+						mtx.basis.elements[1][2]=dataptr[ 6];
+						mtx.origin.y=dataptr[ 7];
+						mtx.basis.elements[2][0]=dataptr[ 8];
+						mtx.basis.elements[2][1]=dataptr[ 9];
+						mtx.basis.elements[2][2]=dataptr[10];
+						mtx.origin.z=dataptr[11];
+
+						AABB baabb = mtx.xform ( skbones[j] );
+						if (first) {
+							laabb=baabb;
+							first=false;
+						} else {
+							laabb.merge_with(baabb);
+						}
 					}
 				}
 
@@ -3117,7 +3177,7 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
 				aabb.merge_with(laabb);
 		}
 	} else {
-*/
+
 		for (int i=0;i<mesh->surfaces.size();i++) {
 
 			if (i==0)
@@ -3125,9 +3185,9 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh,RID p_skeleton) const{
 			else
 				aabb.merge_with(mesh->surfaces[i]->aabb);
 		}
-/*
+
 	}
-*/
+
 	return aabb;
 
 }
@@ -3146,75 +3206,431 @@ void RasterizerStorageGLES3::mesh_clear(RID p_mesh){
 
 RID RasterizerStorageGLES3::multimesh_create(){
 
-	return RID();
+	MultiMesh *multimesh = memnew( MultiMesh );
+	return multimesh_owner.make_rid(multimesh);
 }
 
-void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb){
+void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format){
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+
+	if (multimesh->size==p_instances && multimesh->transform_format==p_transform_format && multimesh->color_format==p_color_format)
+		return;
+
+	if (multimesh->buffer) {
+		glDeleteBuffers(1,&multimesh->buffer);
+		multimesh->data.resize(0);
+	}
+
+	multimesh->size=p_instances;
+	multimesh->transform_format=p_transform_format;
+	multimesh->color_format=p_color_format;
+
+	if (multimesh->size) {
+
+		if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) {
+			multimesh->xform_floats=8;
+		} else {
+			multimesh->xform_floats=12;
+
+		}
+
+		if (multimesh->color_format==VS::MULTIMESH_COLOR_NONE) {
+			multimesh->color_floats=0;
+		} else if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+			multimesh->color_floats=1;
+		} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+			multimesh->color_floats=4;
+		}
+
+		int format_floats = multimesh->color_floats+multimesh->xform_floats;
+		multimesh->data.resize(format_floats*p_instances);
+		for(int i=0;i<p_instances;i+=format_floats) {
+
+			int color_from=0;
+
+			if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) {
+				multimesh->data[i+0]=1.0;
+				multimesh->data[i+1]=0.0;
+				multimesh->data[i+2]=0.0;
+				multimesh->data[i+3]=0.0;
+				multimesh->data[i+4]=0.0;
+				multimesh->data[i+5]=1.0;
+				multimesh->data[i+6]=0.0;
+				multimesh->data[i+7]=0.0;
+				color_from=8;
+			} else {
+				multimesh->data[i+0]=1.0;
+				multimesh->data[i+1]=0.0;
+				multimesh->data[i+2]=0.0;
+				multimesh->data[i+3]=0.0;
+				multimesh->data[i+4]=0.0;
+				multimesh->data[i+5]=1.0;
+				multimesh->data[i+6]=0.0;
+				multimesh->data[i+7]=0.0;
+				multimesh->data[i+8]=0.0;
+				multimesh->data[i+9]=0.0;
+				multimesh->data[i+10]=1.0;
+				multimesh->data[i+11]=0.0;
+				color_from=12;
+			}
+
+			if (multimesh->color_format==VS::MULTIMESH_COLOR_NONE) {
+				//none
+			} else if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+
+				union {
+					uint32_t colu;
+					float colf;
+				} cu;
+
+				cu.colu=0xFFFFFFFF;
+				multimesh->data[i+color_from+0]=cu.colf;
+
+			} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+				multimesh->data[i+color_from+0]=1.0;
+				multimesh->data[i+color_from+1]=1.0;
+				multimesh->data[i+color_from+2]=1.0;
+				multimesh->data[i+color_from+3]=1.0;
+			}
+		}
+
+		glGenBuffers(1,&multimesh->buffer);
+		glBindBuffer(GL_ARRAY_BUFFER,multimesh->buffer);
+		glBufferData(GL_ARRAY_BUFFER,multimesh->data.size()*sizeof(float),NULL,GL_DYNAMIC_DRAW);
+		glBindBuffer(GL_ARRAY_BUFFER,0);
+
+	}
+
+	multimesh->dirty_data=true;
+	multimesh->dirty_aabb=true;
+
+	if (!multimesh->update_list.in_list()) {
+		multimesh_update_list.add(&multimesh->update_list);
+	}
 
 }
+
 int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const{
 
-	return 0;
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh,0);
+
+	return multimesh->size;
 }
 
 void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh,RID p_mesh){
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
 
-}
-void RasterizerStorageGLES3::multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb){
+	multimesh->mesh=p_mesh;
 
+	multimesh->dirty_aabb=true;
 
+	if (!multimesh->update_list.in_list()) {
+		multimesh_update_list.add(&multimesh->update_list);
+	}
 }
-void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform){
 
+void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform){
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_INDEX(p_index,multimesh->size);
+	ERR_FAIL_COND(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D);
+
+	int stride = multimesh->color_floats+multimesh->xform_floats;
+	float *dataptr=&multimesh->data[stride*p_index];
+
+	dataptr[ 0]=p_transform.basis.elements[0][0];
+	dataptr[ 1]=p_transform.basis.elements[0][1];
+	dataptr[ 2]=p_transform.basis.elements[0][2];
+	dataptr[ 3]=p_transform.origin.x;
+	dataptr[ 4]=p_transform.basis.elements[1][0];
+	dataptr[ 5]=p_transform.basis.elements[1][1];
+	dataptr[ 6]=p_transform.basis.elements[1][2];
+	dataptr[ 7]=p_transform.origin.y;
+	dataptr[ 8]=p_transform.basis.elements[2][0];
+	dataptr[ 9]=p_transform.basis.elements[2][1];
+	dataptr[10]=p_transform.basis.elements[2][2];
+	dataptr[11]=p_transform.origin.z;
+
+	multimesh->dirty_data=true;
+	multimesh->dirty_aabb=true;
+
+	if (!multimesh->update_list.in_list()) {
+		multimesh_update_list.add(&multimesh->update_list);
+	}
 }
+
 void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform){
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_INDEX(p_index,multimesh->size);
+	ERR_FAIL_COND(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_3D);
+
+	int stride = multimesh->color_floats+multimesh->xform_floats;
+	float *dataptr=&multimesh->data[stride*p_index];
+
+	dataptr[ 0]=p_transform.elements[0][0];
+	dataptr[ 1]=p_transform.elements[1][0];
+	dataptr[ 2]=0;
+	dataptr[ 3]=p_transform.elements[2][0];
+	dataptr[ 4]=p_transform.elements[0][1];
+	dataptr[ 5]=p_transform.elements[1][1];
+	dataptr[ 6]=0;
+	dataptr[ 7]=p_transform.elements[2][1];
+
+	multimesh->dirty_data=true;
+	multimesh->dirty_aabb=true;
 
+	if (!multimesh->update_list.in_list()) {
+		multimesh_update_list.add(&multimesh->update_list);
+	}
 }
 void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color){
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
+	ERR_FAIL_INDEX(p_index,multimesh->size);
+	ERR_FAIL_COND(multimesh->color_format==VS::MULTIMESH_COLOR_NONE);
+
+	int stride = multimesh->color_floats+multimesh->xform_floats;
+	float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats];
+
+	if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+		union {
+			uint32_t colu;
+			float colf;
+		} cu;
+
+		cu.colu=p_color.to_32();
+		dataptr[ 0]=cu.colf;
+
+	} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+		dataptr[ 0]=p_color.r;
+		dataptr[ 1]=p_color.g;
+		dataptr[ 2]=p_color.b;
+		dataptr[ 3]=p_color.a;
+	}
+
+
+	multimesh->dirty_data=true;
+	multimesh->dirty_aabb=true;
 
+	if (!multimesh->update_list.in_list()) {
+		multimesh_update_list.add(&multimesh->update_list);
+	}
 }
 
 RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const{
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh,RID());
 
-	return RID();
+	return multimesh->mesh;
 }
-AABB RasterizerStorageGLES3::multimesh_get_custom_aabb(RID p_multimesh) const{
 
-	return AABB();
-}
 
 Transform RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh,int p_index) const{
 
-	return Transform();
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh,Transform());
+	ERR_FAIL_INDEX_V(p_index,multimesh->size,Transform());
+	ERR_FAIL_COND_V(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D,Transform());
+
+	int stride = multimesh->color_floats+multimesh->xform_floats;
+	float *dataptr=&multimesh->data[stride*p_index];
+
+	Transform xform;
+
+	xform.basis.elements[0][0]=dataptr[ 0];
+	xform.basis.elements[0][1]=dataptr[ 1];
+	xform.basis.elements[0][2]=dataptr[ 2];
+	xform.origin.x=dataptr[ 3];
+	xform.basis.elements[1][0]=dataptr[ 4];
+	xform.basis.elements[1][1]=dataptr[ 5];
+	xform.basis.elements[1][2]=dataptr[ 6];
+	xform.origin.y=dataptr[ 7];
+	xform.basis.elements[2][0]=dataptr[ 8];
+	xform.basis.elements[2][1]=dataptr[ 9];
+	xform.basis.elements[2][2]=dataptr[10];
+	xform.origin.z=dataptr[11];
+
+	return xform;
 }
 Matrix32 RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const{
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh,Matrix32());
+	ERR_FAIL_INDEX_V(p_index,multimesh->size,Matrix32());
+	ERR_FAIL_COND_V(multimesh->transform_format==VS::MULTIMESH_TRANSFORM_3D,Matrix32());
+
+	int stride = multimesh->color_floats+multimesh->xform_floats;
+	float *dataptr=&multimesh->data[stride*p_index];
+
+	Matrix32 xform;
+
+	xform.elements[0][0]=dataptr[ 0];
+	xform.elements[1][0]=dataptr[ 1];
+	xform.elements[2][0]=dataptr[ 3];
+	xform.elements[0][1]=dataptr[ 4];
+	xform.elements[1][1]=dataptr[ 5];
+	xform.elements[2][1]=dataptr[ 7];
 
-	return Matrix32();
+	return xform;
 }
+
 Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh,int p_index) const{
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh,Color());
+	ERR_FAIL_INDEX_V(p_index,multimesh->size,Color());
+	ERR_FAIL_COND_V(multimesh->color_format==VS::MULTIMESH_COLOR_NONE,Color());
+
+	int stride = multimesh->color_floats+multimesh->xform_floats;
+	float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats];
+
+	if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
+		union {
+			uint32_t colu;
+			float colf;
+		} cu;
+
+		return Color::hex(cu.colu);
+
+	} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
+		Color c;
+		c.r=dataptr[ 0];
+		c.g=dataptr[ 1];
+		c.b=dataptr[ 2];
+		c.a=dataptr[ 3];
+
+		return c;
+	}
+
 	return Color();
+
 }
 
 void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh,int p_visible){
 
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND(!multimesh);
 
+	multimesh->visible_instances=p_visible;
 }
 int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const{
 
-	return 0;
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh,-1);
+
+	return multimesh->visible_instances;
 }
 
-AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_mesh) const{
+AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_multimesh) const{
 
-	return AABB();
+	MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+	ERR_FAIL_COND_V(!multimesh,AABB());
+
+	const_cast<RasterizerStorageGLES3*>(this)->update_dirty_multimeshes(); //update pending AABBs
+
+	return multimesh->aabb;
+}
+
+void RasterizerStorageGLES3::update_dirty_multimeshes() {
+
+	while(multimesh_update_list.first()) {
+
+		MultiMesh *multimesh = multimesh_update_list.first()->self();
+
+		if (multimesh->size && multimesh->dirty_data) {
+
+
+			glBindBuffer(GL_ARRAY_BUFFER,multimesh->buffer);
+			glBufferSubData(GL_ARRAY_BUFFER,0,multimesh->data.size()*sizeof(float),multimesh->data.ptr());
+			glBindBuffer(GL_ARRAY_BUFFER,0);
+
+
+		}
+
+
+
+		if (multimesh->size && multimesh->dirty_aabb) {
+
+			AABB mesh_aabb;
+
+			if (multimesh->mesh.is_valid()) {
+				mesh_aabb=mesh_get_aabb(multimesh->mesh,RID());
+			} else {
+				mesh_aabb.size+=Vector3(0.001,0.001,0.001);
+			}
+
+			int stride=multimesh->color_floats+multimesh->xform_floats;
+			int count = multimesh->data.size();
+			float *data=multimesh->data.ptr();
+
+			AABB aabb;
+
+			if (multimesh->transform_format==VS::MULTIMESH_TRANSFORM_2D) {
+
+				for(int i=0;i<count;i+=stride) {
+
+					float *dataptr=&data[i];
+					Transform xform;
+					xform.basis[0][0]=dataptr[ 0];
+					xform.basis[0][1]=dataptr[ 1];
+					xform.origin[0]=dataptr[ 3];
+					xform.basis[1][0]=dataptr[ 4];
+					xform.basis[1][1]=dataptr[ 5];
+					xform.origin[1]=dataptr[ 7];
+
+					AABB laabb = xform.xform(mesh_aabb);
+					if (i==0)
+						aabb=laabb;
+					else
+						aabb.merge_with(laabb);
+				}
+			} else {
+
+				for(int i=0;i<count;i+=stride) {
+
+					float *dataptr=&data[i];
+					Transform xform;
+
+					xform.basis.elements[0][0]=dataptr[ 0];
+					xform.basis.elements[0][1]=dataptr[ 1];
+					xform.basis.elements[0][2]=dataptr[ 2];
+					xform.origin.x=dataptr[ 3];
+					xform.basis.elements[1][0]=dataptr[ 4];
+					xform.basis.elements[1][1]=dataptr[ 5];
+					xform.basis.elements[1][2]=dataptr[ 6];
+					xform.origin.y=dataptr[ 7];
+					xform.basis.elements[2][0]=dataptr[ 8];
+					xform.basis.elements[2][1]=dataptr[ 9];
+					xform.basis.elements[2][2]=dataptr[10];
+					xform.origin.z=dataptr[11];
+
+					AABB laabb = xform.xform(mesh_aabb);
+					if (i==0)
+						aabb=laabb;
+					else
+						aabb.merge_with(laabb);
+				}
+			}
+
+			multimesh->aabb=aabb;
+		}
+		multimesh->dirty_aabb=false;
+		multimesh->dirty_data=false;
+
+		multimesh->instance_change_notify();
+
+		multimesh_update_list.remove(multimesh_update_list.first());
+	}
 }
 
 /* IMMEDIATE API */
@@ -3957,6 +4373,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene:
 			inst = mesh_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
 		} break;
+		case VS::INSTANCE_MULTIMESH: {
+			inst = multimesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
 		case VS::INSTANCE_REFLECTION_PROBE: {
 			inst = reflection_probe_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
@@ -3988,6 +4408,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce
 			ERR_FAIL_COND(!inst);
 
 		} break;
+		case VS::INSTANCE_MULTIMESH: {
+			inst = multimesh_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
 		case VS::INSTANCE_REFLECTION_PROBE: {
 			inst = reflection_probe_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
@@ -4482,6 +4906,9 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
 	if (mesh_owner.owns(p_rid)) {
 		return VS::INSTANCE_MESH;
 	}
+	if (multimesh_owner.owns(p_rid)) {
+		return VS::INSTANCE_MULTIMESH;
+	}
 	if (light_owner.owns(p_rid)) {
 		return VS::INSTANCE_LIGHT;
 	}
@@ -4580,6 +5007,17 @@ bool RasterizerStorageGLES3::free(RID p_rid){
 		mesh_owner.free(p_rid);
 		memdelete(mesh);
 
+	} else if (multimesh_owner.owns(p_rid)) {
+
+		// delete the texture
+		MultiMesh *multimesh = multimesh_owner.get(p_rid);
+
+		multimesh_allocate(p_rid,0,VS::MULTIMESH_TRANSFORM_2D,VS::MULTIMESH_COLOR_NONE); //frees multimesh
+		update_dirty_multimeshes();
+
+		multimesh_owner.free(p_rid);
+		memdelete(multimesh);
+
 	} else if (light_owner.owns(p_rid)) {
 
 		// delete the texture

+ 38 - 4
drivers/gles3/rasterizer_storage_gles3.h

@@ -482,6 +482,7 @@ public:
 		uint32_t format;
 
 		GLuint array_id;
+		GLuint instancing_array_id;
 		GLuint vertex_id;
 		GLuint index_id;
 
@@ -591,20 +592,53 @@ public:
 
 	/* MULTIMESH API */
 
+	struct MultiMesh : public GeometryOwner {
+		RID mesh;
+		int size;
+		VS::MultimeshTransformFormat transform_format;
+		VS::MultimeshColorFormat color_format;
+		Vector<float> data;
+		AABB aabb;
+		SelfList<MultiMesh> update_list;
+		GLuint buffer;
+		int visible_instances;
+
+		int xform_floats;
+		int color_floats;
+
+		bool dirty_aabb;
+		bool dirty_data;
+
+		MultiMesh() : update_list(this) {
+			dirty_aabb=true;
+			dirty_data=true;
+			xform_floats=0;
+			color_floats=0;
+			visible_instances=-1;
+			size=0;
+			buffer=0;
+			transform_format=VS::MULTIMESH_TRANSFORM_2D;
+			color_format=VS::MULTIMESH_COLOR_NONE;
+		}
+	};
+
+	mutable RID_Owner<MultiMesh> multimesh_owner;
+
+	SelfList<MultiMesh>::List multimesh_update_list;
+
+	void update_dirty_multimeshes();
 
 	virtual RID multimesh_create();
 
-	virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb=true);
+	virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format);
 	virtual int multimesh_get_instance_count(RID p_multimesh) const;
 
 	virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh);
-	virtual void multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb);
 	virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform);
 	virtual void multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform);
 	virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color);
 
 	virtual RID multimesh_get_mesh(RID p_multimesh) const;
-	virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const;
 
 	virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const;
 	virtual Matrix32 multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const;
@@ -613,7 +647,7 @@ public:
 	virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible);
 	virtual int multimesh_get_visible_instances(RID p_multimesh) const;
 
-	virtual AABB multimesh_get_aabb(RID p_mesh) const;
+	virtual AABB multimesh_get_aabb(RID p_multimesh) const;
 
 	/* IMMEDIATE API */
 

+ 22 - 4
drivers/gles3/shaders/scene.glsl

@@ -45,7 +45,7 @@ layout(location=6) in ivec4 bone_indices; // attrib:6
 layout(location=7) in vec4 bone_weights; // attrib:7
 #endif
 
-#ifdef USE_ATTRIBUTE_INSTANCING
+#ifdef USE_INSTANCING
 
 layout(location=8) in highp vec4 instance_xform0;
 layout(location=9) in highp vec4 instance_xform1;
@@ -171,6 +171,10 @@ void main() {
 	float binormalf = tangent_attrib.a;
 #endif
 
+#if defined(ENABLE_COLOR_INTERP)
+	color_interp = color_attrib;
+#endif
+
 
 #ifdef USE_SKELETON
 
@@ -191,6 +195,23 @@ void main() {
 #endif // USE_SKELETON1
 
 
+#ifdef USE_INSTANCING
+
+	{
+		highp mat3x4 m=mat3x4(instance_xform0,instance_xform1,instance_xform2);
+
+		vertex.xyz = vertex * m;
+		normal = vec4(normal,0.0) * m;
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+		tangent.xyz = vec4(tangent.xyz,0.0) * mn;
+#endif
+
+#if defined(ENABLE_COLOR_INTERP)
+		color_interp*=instance_color;
+#endif
+	}
+#endif //USE_INSTANCING
+
 #if !defined(SKIP_TRANSFORM_USED)
 
 	vertex = modelview * vertex;
@@ -207,9 +228,6 @@ void main() {
 
 
 
-#if defined(ENABLE_COLOR_INTERP)
-	color_interp = color_attrib;
-#endif
 
 #if defined(ENABLE_UV_INTERP)
 	uv_interp = uv_attrib;

+ 0 - 16
scene/main/viewport.cpp

@@ -462,22 +462,6 @@ void Viewport::_notification(int p_what) {
 
 				VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh,point_count);
 
-				if (point_count>0) {
-					AABB aabb;
-
-					Transform t;
-					for(int i=0;i<point_count;i++) {
-
-						if (i==0)
-							aabb.pos=points[i];
-						else
-							aabb.expand_to(points[i]);
-						t.origin=points[i];
-						VisualServer::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh,i,t);
-					}
-					aabb.grow(aabb.get_longest_axis_size()*0.01);
-					VisualServer::get_singleton()->multimesh_set_custom_aabb(contact_3d_debug_multimesh,aabb);
-				}
 			}
 
 

+ 4 - 39
scene/resources/multimesh.cpp

@@ -174,45 +174,13 @@ Color MultiMesh::get_instance_color(int p_instance) const {
 
 }
 
-void MultiMesh::set_aabb(const AABB& p_aabb) {
 
-	aabb=p_aabb;
-	VisualServer::get_singleton()->multimesh_set_custom_aabb(multimesh,p_aabb);
-
-
-}
 AABB MultiMesh::get_aabb() const {
 
-	return aabb;
+	return VisualServer::get_singleton()->multimesh_get_aabb(multimesh);
 
 }
 
-void MultiMesh::generate_aabb() {
-
-
-
-	ERR_EXPLAIN("Cannot generate AABB if mesh is null.");
-	ERR_FAIL_COND(mesh.is_null());
-
-	AABB base_aabb=mesh->get_aabb();
-
-	aabb=AABB();
-
-	int instance_count = get_instance_count();
-	for(int i=0;i<instance_count;i++) {
-
-
-		Transform xform = get_instance_transform(i);
-		if(i==0)
-			aabb=xform.xform(base_aabb);
-		else
-			aabb.merge_with(xform.xform(base_aabb));
-
-	}
-
-	set_aabb(aabb);
-
-}
 
 RID MultiMesh::get_rid() const {
 
@@ -256,10 +224,8 @@ void MultiMesh::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_instance_transform","instance"),&MultiMesh::get_instance_transform);
 	ObjectTypeDB::bind_method(_MD("set_instance_color","instance","color"),&MultiMesh::set_instance_color);
 	ObjectTypeDB::bind_method(_MD("get_instance_color","instance"),&MultiMesh::get_instance_color);
-	ObjectTypeDB::bind_method(_MD("set_aabb","visibility_aabb"),&MultiMesh::set_aabb);
 	ObjectTypeDB::bind_method(_MD("get_aabb"),&MultiMesh::get_aabb);
 
-	ObjectTypeDB::bind_method(_MD("generate_aabb"),&MultiMesh::generate_aabb);
 
 	ObjectTypeDB::bind_method(_MD("_set_transform_array"),&MultiMesh::_set_transform_array);
 	ObjectTypeDB::bind_method(_MD("_get_transform_array"),&MultiMesh::_get_transform_array);
@@ -268,15 +234,14 @@ void MultiMesh::_bind_methods() {
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"color_format",PROPERTY_HINT_ENUM,"None,Byte,Float"), _SCS("set_color_format"), _SCS("get_color_format"));
-	ADD_PROPERTY(PropertyInfo(Variant::INT,"transform_format",PROPERTY_HINT_ENUM,"None,2D,3D"), _SCS("set_transform_format"), _SCS("get_transform_format"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"transform_format",PROPERTY_HINT_ENUM,"2D,3D"), _SCS("set_transform_format"), _SCS("get_transform_format"));
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"instance_count",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_instance_count"), _SCS("get_instance_count"));
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"mesh",PROPERTY_HINT_RESOURCE_TYPE,"Mesh"), _SCS("set_mesh"), _SCS("get_mesh"));
-	ADD_PROPERTY(PropertyInfo(Variant::_AABB,"aabb"), _SCS("set_aabb"), _SCS("get_aabb") );
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3_ARRAY,"transform_array",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_transform_array"), _SCS("_get_transform_array"));
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR_ARRAY,"color_array",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_color_array"), _SCS("_get_color_array"));
 
 
-	BIND_CONSTANT( TRANSFORM_NONE );
+
 	BIND_CONSTANT( TRANSFORM_2D  );
 	BIND_CONSTANT( TRANSFORM_3D  );
 	BIND_CONSTANT( COLOR_NONE  );
@@ -289,7 +254,7 @@ MultiMesh::MultiMesh() {
 
 	multimesh = VisualServer::get_singleton()->multimesh_create();
 	color_format=COLOR_NONE;
-	transform_format=TRANSFORM_NONE;
+	transform_format=TRANSFORM_2D;
 }
 
 MultiMesh::~MultiMesh() {

+ 0 - 5
scene/resources/multimesh.h

@@ -39,7 +39,6 @@ class MultiMesh : public Resource {
 public:
 
 	enum TransformFormat {
-		TRANSFORM_NONE = VS::MULTIMESH_TRANSFORM_NONE,
 		TRANSFORM_2D = VS::MULTIMESH_TRANSFORM_2D,
 		TRANSFORM_3D = VS::MULTIMESH_TRANSFORM_3D
 	};
@@ -50,7 +49,6 @@ public:
 		COLOR_FLOAT = VS::MULTIMESH_COLOR_FLOAT,
 	};
 private:
-	AABB aabb;
 	Ref<Mesh> mesh;
 	RID multimesh;
 	TransformFormat transform_format;
@@ -87,11 +85,8 @@ public:
 	void set_instance_color(int p_instance, const Color& p_color);
 	Color get_instance_color(int p_instance) const;
 
-	void set_aabb(const AABB& p_aabb);
 	virtual AABB get_aabb() const;
 
-	void generate_aabb();
-
 	virtual RID get_rid() const;
 
 	MultiMesh();

+ 2 - 4
servers/visual/rasterizer.h

@@ -261,17 +261,15 @@ public:
 
 	virtual RID multimesh_create()=0;
 
-	virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format,bool p_gen_aabb=true)=0;
+	virtual void multimesh_allocate(RID p_multimesh,int p_instances,VS::MultimeshTransformFormat p_transform_format,VS::MultimeshColorFormat p_color_format)=0;
 	virtual int multimesh_get_instance_count(RID p_multimesh) const=0;
 
 	virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh)=0;
-	virtual void multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb)=0;
 	virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform)=0;
 	virtual void multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform)=0;
 	virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color)=0;
 
 	virtual RID multimesh_get_mesh(RID p_multimesh) const=0;
-	virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const=0;
 
 	virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const=0;
 	virtual Matrix32 multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const=0;
@@ -280,7 +278,7 @@ public:
 	virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible)=0;
 	virtual int multimesh_get_visible_instances(RID p_multimesh) const=0;
 
-	virtual AABB multimesh_get_aabb(RID p_mesh) const=0;
+	virtual AABB multimesh_get_aabb(RID p_multimesh) const=0;
 
 	/* IMMEDIATE API */
 

+ 2 - 3
servers/visual/visual_server_raster.h

@@ -707,17 +707,16 @@ public:
 
 	BIND0R(RID,multimesh_create)
 
-	BIND5(multimesh_allocate,RID,int,MultimeshTransformFormat,MultimeshColorFormat,bool)
+	BIND4(multimesh_allocate,RID,int,MultimeshTransformFormat,MultimeshColorFormat)
 	BIND1RC(int,multimesh_get_instance_count,RID)
 
 	BIND2(multimesh_set_mesh,RID,RID)
-	BIND2(multimesh_set_custom_aabb,RID,const AABB&)
 	BIND3(multimesh_instance_set_transform,RID,int,const Transform&)
 	BIND3(multimesh_instance_set_transform_2d,RID,int,const Matrix32& )
 	BIND3(multimesh_instance_set_color,RID,int,const Color&)
 
 	BIND1RC(RID,multimesh_get_mesh,RID)
-	BIND1RC(AABB,multimesh_get_custom_aabb,RID)
+	BIND1RC(AABB,multimesh_get_aabb,RID)
 
 	BIND2RC(Transform,multimesh_instance_get_transform,RID,int )
 	BIND2RC(Matrix32,multimesh_instance_get_transform_2d,RID,int)

+ 63 - 21
servers/visual/visual_server_scene.cpp

@@ -562,6 +562,11 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
 				InstanceGeometryData *geom = memnew( InstanceGeometryData );
 				instance->base_data=geom;
 			} break;
+			case VS::INSTANCE_MULTIMESH: {
+
+				InstanceGeometryData *geom = memnew( InstanceGeometryData );
+				instance->base_data=geom;
+			} break;
 			case VS::INSTANCE_REFLECTION_PROBE: {
 
 				InstanceReflectionProbeData *reflection_probe = memnew( InstanceReflectionProbeData );
@@ -764,8 +769,19 @@ void VisualServerScene::instance_attach_skeleton(RID p_instance,RID p_skeleton){
 	Instance *instance = instance_owner.get( p_instance );
 	ERR_FAIL_COND( !instance );
 
+	if (instance->skeleton==p_skeleton)
+		return;
+
+	if (instance->skeleton.is_valid()) {
+		VSG::storage->instance_remove_dependency(p_skeleton,instance);
+	}
+
 	instance->skeleton=p_skeleton;
 
+	if (instance->skeleton.is_valid()) {
+		VSG::storage->instance_add_dependency(p_skeleton,instance);
+	}
+
 	_instance_queue_update(instance,true);
 }
 
@@ -1125,12 +1141,13 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
 			new_aabb = VSG::storage->mesh_get_aabb(p_instance->base,p_instance->skeleton);
 
 		} break;
-#if 0
+
 		case VisualServer::INSTANCE_MULTIMESH: {
 
-			new_aabb = rasterizer->multimesh_get_aabb(p_instance->base);
+			new_aabb = VSG::storage->multimesh_get_aabb(p_instance->base);
 
 		} break;
+#if 0
 		case VisualServer::INSTANCE_IMMEDIATE: {
 
 			new_aabb = rasterizer->immediate_get_aabb(p_instance->base);
@@ -2238,39 +2255,64 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
 				can_cast_shadows=VSG::storage->material_casts_shadows(p_instance->material_override);
 			} else {
 
-				RID mesh;
 
-				if (p_instance->base_type==VS::INSTANCE_MESH) {
-					mesh=p_instance->base;
-				} else if (p_instance->base_type==VS::INSTANCE_MULTIMESH) {
 
-				}
+				if (p_instance->base_type==VS::INSTANCE_MESH) {
+					RID mesh=p_instance->base;
 
-				if (mesh.is_valid()) {
+					if (mesh.is_valid()) {
+						bool cast_shadows=false;
 
-					bool cast_shadows=false;
+						for(int i=0;i<p_instance->materials.size();i++) {
 
-					for(int i=0;i<p_instance->materials.size();i++) {
 
+							RID mat = p_instance->materials[i].is_valid()?p_instance->materials[i]:VSG::storage->mesh_surface_get_material(mesh,i);
 
-						RID mat = p_instance->materials[i].is_valid()?p_instance->materials[i]:VSG::storage->mesh_surface_get_material(mesh,i);
+							if (!mat.is_valid()) {
+								cast_shadows=true;
+								break;
+							}
 
-						if (!mat.is_valid()) {
-							cast_shadows=true;
-							break;
+							if (VSG::storage->material_casts_shadows(mat)) {
+								cast_shadows=true;
+								break;
+							}
 						}
 
-						if (VSG::storage->material_casts_shadows(mat)) {
-							cast_shadows=true;
-							break;
+						if (!cast_shadows) {
+							can_cast_shadows=false;
 						}
 					}
 
-					if (!cast_shadows) {
-						can_cast_shadows=false;
+				} else if (p_instance->base_type==VS::INSTANCE_MULTIMESH) {
+					RID mesh = VSG::storage->multimesh_get_mesh(p_instance->base);
+					if (mesh.is_valid()) {
+						bool cast_shadows=false;
+
+						int sc = VSG::storage->mesh_get_surface_count(mesh);
+						for(int i=0;i<sc;i++) {
+
+							RID mat =VSG::storage->mesh_surface_get_material(mesh,i);
+
+							if (!mat.is_valid()) {
+								cast_shadows=true;
+								break;
+							}
+
+							if (VSG::storage->material_casts_shadows(mat)) {
+								cast_shadows=true;
+								break;
+							}
+						}
+
+						if (!cast_shadows) {
+							can_cast_shadows=false;
+						}
 					}
 				}
 
+
+
 			}
 
 			if (can_cast_shadows!=geom->can_cast_shadows) {
@@ -2335,9 +2377,9 @@ bool VisualServerScene::free(RID p_rid) {
 		instance_set_scenario(p_rid,RID());
 		instance_set_base(p_rid,RID());
 		instance_geometry_set_material_override(p_rid,RID());
+		instance_attach_skeleton(p_rid,RID());
 
-		if (instance->skeleton.is_valid())
-			instance_attach_skeleton(p_rid,RID());
+		update_dirty_instances(); //in case something changed this
 
 		instance_owner.free(p_rid);
 		memdelete(instance);

+ 1 - 1
servers/visual_server.cpp

@@ -1282,7 +1282,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector<uint8_t> p
 						for(int j=0;j<p_vertex_len;j++) {
 
 							const uint16_t *v = (const uint16_t*)&r[j*total_elem_size+offsets[i]];
-							w[j]=Vector3(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1]),Math::halfptr_to_float(&v[1]));
+							w[j]=Vector3(Math::halfptr_to_float(&v[0]),Math::halfptr_to_float(&v[1]),Math::halfptr_to_float(&v[2]));
 						}
 					} else {
 

+ 2 - 4
servers/visual_server.h

@@ -285,7 +285,6 @@ public:
 	virtual RID multimesh_create()=0;
 
 	enum MultimeshTransformFormat {
-		MULTIMESH_TRANSFORM_NONE,
 		MULTIMESH_TRANSFORM_2D,
 		MULTIMESH_TRANSFORM_3D,
 	};
@@ -296,17 +295,16 @@ public:
 		MULTIMESH_COLOR_FLOAT,
 	};
 
-	virtual void multimesh_allocate(RID p_multimesh,int p_instances,MultimeshTransformFormat p_transform_format,MultimeshColorFormat p_color_format,bool p_gen_aabb=true)=0;
+	virtual void multimesh_allocate(RID p_multimesh,int p_instances,MultimeshTransformFormat p_transform_format,MultimeshColorFormat p_color_format)=0;
 	virtual int multimesh_get_instance_count(RID p_multimesh) const=0;
 
 	virtual void multimesh_set_mesh(RID p_multimesh,RID p_mesh)=0;
-	virtual void multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb)=0;
 	virtual void multimesh_instance_set_transform(RID p_multimesh,int p_index,const Transform& p_transform)=0;
 	virtual void multimesh_instance_set_transform_2d(RID p_multimesh,int p_index,const Matrix32& p_transform)=0;
 	virtual void multimesh_instance_set_color(RID p_multimesh,int p_index,const Color& p_color)=0;
 
 	virtual RID multimesh_get_mesh(RID p_multimesh) const=0;
-	virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const=0;
+	virtual AABB multimesh_get_aabb(RID p_multimesh) const=0;
 
 	virtual Transform multimesh_instance_get_transform(RID p_multimesh,int p_index) const=0;
 	virtual Matrix32 multimesh_instance_get_transform_2d(RID p_multimesh,int p_index) const=0;

+ 6 - 2
tools/editor/plugins/multimesh_editor_plugin.cpp

@@ -195,6 +195,8 @@ void MultiMeshEditor::_populate() {
 
 	int instance_count=populate_amount->get_val();
 
+	multimesh->set_transform_format(MultiMesh::TRANSFORM_3D);
+	multimesh->set_color_format(MultiMesh::COLOR_NONE);
 	multimesh->set_instance_count(instance_count);
 
 	float _tilt_random = populate_tilt_random->get_val();
@@ -247,10 +249,10 @@ void MultiMeshEditor::_populate() {
 
 
 		multimesh->set_instance_transform(i,xform);
-		multimesh->set_instance_color(i,Color(1,1,1,1));
+
 	}
 
-	multimesh->generate_aabb();
+
 
 	node->set_multimesh(multimesh);
 
@@ -386,6 +388,7 @@ MultiMeshEditor::MultiMeshEditor() {
 	populate_scale_random->set_min(0);
 	populate_scale_random->set_max(1);
 	populate_scale_random->set_val(0);
+	populate_scale_random->set_step(0.01);
 
 	vbc->add_margin_child(TTR("Random Scale:"),populate_scale_random);
 
@@ -393,6 +396,7 @@ MultiMeshEditor::MultiMeshEditor() {
 	populate_scale->set_min(0.001);
 	populate_scale->set_max(4096);
 	populate_scale->set_val(1);
+	populate_scale->set_step(0.01);
 
 	vbc->add_margin_child(TTR("Scale:"),populate_scale);