From 943d27f46ded993105928c4a46414aa16d84115e Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 22 Nov 2016 01:26:56 -0300 Subject: [PATCH] Instancing is working! (hooray) --- drivers/gles3/rasterizer_gles3.cpp | 1 + drivers/gles3/rasterizer_scene_gles3.cpp | 92 +++ drivers/gles3/rasterizer_storage_gles3.cpp | 542 ++++++++++++++++-- drivers/gles3/rasterizer_storage_gles3.h | 42 +- drivers/gles3/shaders/scene.glsl | 26 +- scene/main/viewport.cpp | 16 - scene/resources/multimesh.cpp | 43 +- scene/resources/multimesh.h | 5 - servers/visual/rasterizer.h | 6 +- servers/visual/visual_server_raster.h | 5 +- servers/visual/visual_server_scene.cpp | 90 ++- servers/visual_server.cpp | 2 +- servers/visual_server.h | 6 +- .../plugins/multimesh_editor_plugin.cpp | 8 +- 14 files changed, 726 insertions(+), 158 deletions(-) diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 63090e53a7..84fa349313 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/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(); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index e0a3dbd36e..54dc3b914b 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/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(e->owner); + RasterizerStorageGLES3::Surface *s = static_cast(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(e->owner); + RasterizerStorageGLES3::Surface *s = static_cast(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;isurfaces[i]; + _add_geometry(s,inst,multi_mesh,-1,p_shadow); + } + } break; case VS::INSTANCE_IMMEDIATE: { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index c2598e458f..e5a0cded8e 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/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;iarray_id); + glBindVertexArray(surface->array_id); + glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); } else { - glVertexAttribPointer(attribs[i].index,attribs[i].size,attribs[i].type,attribs[i].normalized,attribs[i].stride,((uint8_t*)0)+attribs[i].offset); + //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); + } - glEnableVertexAttribArray(attribs[i].index); + + for(int i=0;iindex_id) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); } - if (surface->index_id) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); - } - - 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;isurfaces.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;juse_2d) { + for(int j=0;jsurfaces.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;itransform_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); + multimesh->mesh=p_mesh; + + multimesh->dirty_aabb=true; + + if (!multimesh->update_list.in_list()) { + multimesh_update_list.add(&multimesh->update_list); + } } -void RasterizerStorageGLES3::multimesh_set_custom_aabb(RID p_multimesh,const AABB& p_aabb){ - -} 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()); - return 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 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(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;iaabb=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 diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b5eacacb4e..c6712bd8ea 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/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 data; + AABB aabb; + SelfList 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_owner; + + SelfList::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 */ diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index f3dade9e50..c198534728 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/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; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 0ca72eaa2a..bd5eb0a4e6 100644 --- a/scene/main/viewport.cpp +++ b/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;imultimesh_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); - } } diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index 0a005d8c54..8515cd28a3 100644 --- a/scene/resources/multimesh.cpp +++ b/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;imultimesh_create(); color_format=COLOR_NONE; - transform_format=TRANSFORM_NONE; + transform_format=TRANSFORM_2D; } MultiMesh::~MultiMesh() { diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h index be4ee38fcd..5e28900c32 100644 --- a/scene/resources/multimesh.h +++ b/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; 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(); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0f70b036a6..08d1995725 100644 --- a/servers/visual/rasterizer.h +++ b/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 */ diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 4e9110445b..675e2d4aef 100644 --- a/servers/visual/visual_server_raster.h +++ b/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) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 74d77c5262..f25e5bc943 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/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; + RID mesh=p_instance->base; + + if (mesh.is_valid()) { + bool cast_shadows=false; + + for(int i=0;imaterials.size();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 (VSG::storage->material_casts_shadows(mat)) { + cast_shadows=true; + break; + } + } + + 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;imesh_surface_get_material(mesh,i); - bool cast_shadows=false; + if (!mat.is_valid()) { + cast_shadows=true; + break; + } - for(int i=0;imaterials.size();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 (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; - } } + + } 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); diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 267a87930a..30d6b76b8e 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1282,7 +1282,7 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format,DVector p for(int j=0;jget_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);