Result::Name RegisterAsPlanarMirror( CCopyEntity& entity, BasicMesh& mesh, int subset_index ) { const AABB3& aabb = mesh.GetAABB(subset_index); EntityRenderManager& entity_render_mgr = *(entity.GetStage()->GetEntitySet()->GetRenderManager()); // >>> TODO: support planes that are not axis-aligned or facing along the negative half-space SPlane plane; int plane_axis = 1; if( aabb.vMax.x - aabb.vMin.x < 0.001f ) plane_axis = 0; else if( aabb.vMax.y - aabb.vMin.y < 0.001f ) plane_axis = 1; else if( aabb.vMax.z - aabb.vMin.z < 0.001f ) plane_axis = 2; else plane_axis = 1; plane.normal = Vector3(0,0,0); plane.normal[plane_axis] = 1; plane.dist = aabb.vMax[plane_axis]; Result::Name res = entity_render_mgr.AddPlanarReflector( EntityHandle<>( entity.Self() ), plane ); if( res != Result::SUCCESS ) return Result::UNKNOWN_ERROR; entity.RaiseEntityFlags( BETYPE_PLANAR_REFLECTOR ); // Create shader variable loader for mirror if( !entity.m_pMeshRenderMethod ) { if( entity.pBaseEntity->MeshProperty().m_pMeshRenderMethod ) { entity.m_pMeshRenderMethod = entity.pBaseEntity->MeshProperty().m_pMeshRenderMethod->CreateCopy(); if( !entity.m_pMeshRenderMethod ) return Result::UNKNOWN_ERROR; } else return Result::UNKNOWN_ERROR; } // create a planar reflection entity // shared_ptr<MeshContainerRenderMethod> pMeshRenderMethodCopy // = entity.m_pMeshRenderMethod->CreateCopy(); shared_ptr<MirroredSceneTextureParam> pTexParam; pTexParam.reset( new MirroredSceneTextureParam( EntityHandle<>( entity.Self() ) ) ); pTexParam->m_fReflection = mesh.GetMaterial(subset_index).m_Mat.fReflection; // pMeshRenderMethodCopy->SetShaderParamsLoaderToAllMeshRenderMethods( pTexParam ); // test - we assume that the entity's mesh is composed of polygons that belong to a single plane. entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pTexParam ); // Move the indices of the planar reflection subset(s) // to the render method of the planar reflection entity return Result::SUCCESS; }
/// Update shader params loaders for the entity. /// Shader params loaders are shared by entities, and need to be updated every time an entity is rendered. void UpdateEntityForRendering( CCopyEntity& entity ) { BaseEntity& base_entity = *(entity.pBaseEntity); // light params writer if( entity.GetEntityFlags() & BETYPE_LIGHTING ) { UpdateLightInfo( entity ); if( base_entity.MeshProperty().m_pShaderLightParamsLoader ) { // Set the entity to the light params loader, because a single light params loader // is shared by all the entities of this base entity. base_entity.MeshProperty().m_pShaderLightParamsLoader->SetEntity( entity.Self().lock() ); } } const float offset_world_transform_threshold = 150000.0f; if( square(offset_world_transform_threshold) < Vec3LengthSq(entity.GetWorldPose().vPosition) ) { Camera* pCam = entity.GetStage()->GetCurrentCamera(); if( pCam ) { sg_pWorldTransLoader->SetActive( true ); sg_pWorldTransLoader->SetCameraPosition( pCam->GetPosition() ); } else sg_pWorldTransLoader->SetActive( false ); } else sg_pWorldTransLoader->SetActive( false ); }
EntityHandle<> CStage::LoadStaticGeometryFromFile( const std::string filename ) { SafeDelete( m_pStaticGeometry ); m_pStaticGeometry = CreateStaticGeometry( this, filename ); if( !m_pStaticGeometry ) return EntityHandle<>(); // register the static geometry as an entity // - the entity is used to render the static geometry BaseEntityHandle baseentity_handle; baseentity_handle.SetBaseEntityName( "StaticGeometry" ); CCopyEntityDesc desc; desc.strName = filename; desc.pBaseEntityHandle = &baseentity_handle; desc.pUserData = m_pStaticGeometry; CCopyEntity *pStaticGeometryEntity = CreateEntity( desc ); if( !pStaticGeometryEntity ) return EntityHandle<>(); // shared_ptr<CStaticGeometryEntity> pEntity( new CStaticGeometryEntity ); // pEntity->SetStaticGeometry( m_pStaticGeometry ); // EntityHandle<CStaticGeometryEntity> entity // = CreateEntity( pEntity, baseentity_handle ); m_pEntitySet->WriteEntityTreeToFile( "debug/entity_tree - loaded static geometry.txt" ); // load the static geometry from file this->PauseTimer(); bool loaded = m_pStaticGeometry->LoadFromFile( filename ); this->ResumeTimer(); return EntityHandle<>( pStaticGeometryEntity->Self() ); // return entity; }
// sets the following shader params loaders to the render method of an entity // - CEntityShaderLightParamsLoader // - Set if the BETYPE_LIGHTING flag is on // - BlendTransformsLoader // - Set if pEntity->m_MeshHandle is a skeletal mesh void InitMeshRenderMethod( CCopyEntity &entity, shared_ptr<BlendTransformsLoader> pBlendTransformsLoader ) { if( !entity.m_pMeshRenderMethod ) { entity.m_pMeshRenderMethod.reset( new MeshContainerRenderMethod ); // entity.m_pMeshRenderMethod->MeshRenderMethod().resize( 1 ); } if( entity.GetEntityFlags() & BETYPE_LIGHTING ) { shared_ptr<CEntityShaderLightParamsLoader> pLightParamsLoader( new CEntityShaderLightParamsLoader() ); pLightParamsLoader->SetEntity( entity.Self() ); entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pLightParamsLoader ); } // Not used now. // Item entities set this in its own member function ItemEntity::InitMesh(). // Does any entity other than item entty need this? if( pBlendTransformsLoader ) entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pBlendTransformsLoader ); /* shared_ptr<BasicMesh> pMesh = entity.m_MeshHandle.GetMesh(); if( pMesh && pMesh->GetMeshType() == MeshType::SKELETAL ) { // shared_ptr<SkeletalMesh> pSkeletalMesh // = boost::dynamic_pointer_cast<SkeletalMesh,BasicMesh>(pMesh); if( !pBlendTransformsLoader ) pBlendTransformsLoader.reset( new BlendTransformsLoader() ); entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( pBlendTransformsLoader ); }*/ if( true /* world position of entity has large values */ ) { entity.m_pMeshRenderMethod->SetShaderParamsLoaderToAllMeshRenderMethods( sg_pWorldTransLoader ); } }
// Initializes CCopyEntity::m_pMeshRenderMethod // - Initialize the mesh render method // - Initialize shader parameter loaders // - Create alpha entities // - Creates a shader void BaseEntity::InitEntityGraphics( CCopyEntity &entity, ShaderHandle& shader, ShaderTechniqueHandle& tech ) { if( shader.IsLoaded() && tech.GetTechniqueName() && 0 < strlen(tech.GetTechniqueName()) ) { CreateMeshRenderMethod( EntityHandle<>( entity.Self() ), shader, tech ); } else { InitMeshRenderMethod( entity ); } // create transparent parts of the model as separate entities if( m_EntityFlag & BETYPE_SUPPORT_TRANSPARENT_PARTS ) { // Remove any previous alpha entities int next_child_index = 0; while( next_child_index < entity.GetNumChildren() ) // for( int i=0; i<entity.GetNumChildren(); i++ ) { shared_ptr<CCopyEntity> pChild = entity.m_aChild[next_child_index].Get(); if( IsValidEntity(pChild.get()) && pChild->GetEntityTypeID() == CCopyEntityTypeID::ALPHA_ENTITY ) { CCopyEntity *pChildRawPtr = pChild.get(); m_pStage->TerminateEntity( pChildRawPtr ); } else next_child_index += 1; } CreateAlphaEntities( &entity ); } shared_ptr<BasicMesh> pMesh = entity.m_MeshHandle.GetMesh(); if( !pMesh ) return; BasicMesh& mesh = *pMesh; const int num_mesh_materials = mesh.GetNumMaterials(); std::vector<GenericShaderDesc> shader_descs; shader_descs.resize( num_mesh_materials ); std::vector<int> mirror_subsets_indices; // std::vector<int> non_mirror_subsets_indices; if( m_MeshProperty.m_MeshDesc.IsValid() ) // if( true ) { // The mesh is specified in the base entity } else { // base entity has no mesh // - entity's mesh is individual shader_descs.resize( num_mesh_materials ); for( int i=0; i<num_mesh_materials; i++ ) { // Fill out the shader desc based on the parameter values of the material // reflection bool registered_as_mirror = RegisterAsMirrorIfReflective( entity, mesh, i, shader_descs[i] ); if( registered_as_mirror ) mirror_subsets_indices.push_back( i ); // specularity if( 0.001f < mesh.GetMaterial(i).m_Mat.fSpecularity ) shader_descs[i].Specular = SpecularSource::UNIFORM; else shader_descs[i].Specular = SpecularSource::NONE; } vector< pair< GenericShaderDesc, vector<unsigned int> > > grouped_descs; group_elements( shader_descs, grouped_descs ); // Do a NULL check just in case // The mesh render method is initialized by InitMeshRenderMethod() above. if( !entity.m_pMeshRenderMethod ) entity.m_pMeshRenderMethod.reset( new MeshContainerRenderMethod ); bool shader_loaded = false; if( grouped_descs.size() == 1 ) { SubsetRenderMethod& render_method = entity.m_pMeshRenderMethod->PrimaryMeshRenderMethod(); render_method.m_Technique.SetTechniqueName( "Default" ); render_method.m_ShaderDesc.pShaderGenerator.reset( new GenericShaderGenerator( grouped_descs[0].first ) ); // shader_loaded = render_method.Load(); shader_loaded = render_method.m_Shader.Load( render_method.m_ShaderDesc ); } else { LOG_PRINT_WARNING( "Mesh materials need different shaders. This situation is not supported yet (the total number of materials: " + to_string(num_mesh_materials) + ")." ); } } }