/// <summary> /// Sets the corners of the rectangle, in relative coordinates. /// </summary> /// <param name="left">Left position in screen relative coordinates, -1 = left edge, 1.0 = right edge.</param> /// <param name="top">Top position in screen relative coordinates, 1 = top edge, -1 = bottom edge.</param> /// <param name="right">Position in screen relative coordinates.</param> /// <param name="bottom">Position in screen relative coordinates.</param> /// <param name="updateAABB"></param> public void SetCorners( float left, float top, float right, float bottom, bool updateAABB ) { var data = new float[] { left, top, -1, left, bottom, -1, right, top, -1, // Fix for Issue #1187096 right, bottom, -1 }; var buffer = vertexData.vertexBufferBinding.GetBuffer( POSITION ); buffer.WriteData( 0, buffer.Size, data, true ); if ( updateAABB ) { box = new AxisAlignedBox(); box.SetExtents( new Vector3( left, top, 0 ), new Vector3( right, bottom, 0 ) ); } }
/// <summary> /// Internal method for locating a list of shadow casters which /// could be affecting the frustum for a given light. /// </summary> /// <remarks> /// Custom scene managers are encouraged to override this method to add optimizations, /// and to add their own custom shadow casters (perhaps for world geometry) /// </remarks> /// <param name="light"></param> /// <param name="camera"></param> protected virtual IList FindShadowCastersForLight( Light light, Camera camera ) { this.shadowCasterList.Clear(); if ( light.Type == LightType.Directional ) { // Basic AABB query encompassing the frustum and the extrusion of it AxisAlignedBox aabb = new AxisAlignedBox(); Vector3[] corners = camera.WorldSpaceCorners; Vector3 min, max; Vector3 extrude = light.DerivedDirection * -this.shadowDirLightExtrudeDist; // do first corner min = max = corners[ 0 ]; min.Floor( corners[ 0 ] + extrude ); max.Ceil( corners[ 0 ] + extrude ); for ( int c = 1; c < 8; ++c ) { min.Floor( corners[ c ] ); max.Ceil( corners[ c ] ); min.Floor( corners[ c ] + extrude ); max.Ceil( corners[ c ] + extrude ); } aabb.SetExtents( min, max ); if ( this.shadowCasterAABBQuery == null ) { this.shadowCasterAABBQuery = this.CreateAABBRegionQuery( aabb ); } else { this.shadowCasterAABBQuery.Box = aabb; } // Execute, use callback this.shadowCasterQueryListener.Prepare( false, light.GetFrustumClipVolumes( camera ), light, camera, this.shadowCasterList, light.ShadowFarDistanceSquared ); this.shadowCasterAABBQuery.Execute( this.shadowCasterQueryListener ); } else { Sphere s = new Sphere( light.DerivedPosition, light.AttenuationRange ); // eliminate early if camera cannot see light sphere if ( camera.IsObjectVisible( s ) ) { // create or init a sphere region query if ( this.shadowCasterSphereQuery == null ) { this.shadowCasterSphereQuery = this.CreateSphereRegionQuery( s ); } else { this.shadowCasterSphereQuery.Sphere = s; } // check if the light is within view of the camera bool lightInFrustum = camera.IsObjectVisible( light.DerivedPosition ); PlaneBoundedVolumeList volumeList = null; // Only worth building an external volume list if // light is outside the frustum if ( !lightInFrustum ) { volumeList = light.GetFrustumClipVolumes( camera ); } // prepare the query and execute using the callback this.shadowCasterQueryListener.Prepare( lightInFrustum, volumeList, light, camera, this.shadowCasterList, light.ShadowFarDistanceSquared ); this.shadowCasterSphereQuery.Execute( this.shadowCasterQueryListener ); } } return this.shadowCasterList; }
/// <summary> /// Utility method for extruding a bounding box. /// </summary> /// <param name="box">Original bounding box, will be updated in-place.</param> /// <param name="lightPosition">4D light position in object space, when w=0.0f this /// represents a directional light</param> /// <param name="extrudeDistance">The distance to extrude.</param> protected virtual void ExtrudeBounds( AxisAlignedBox box, Vector4 lightPosition, float extrudeDistance ) { Vector3 extrusionDir = Vector3.Zero; if ( lightPosition.w == 0 ) { extrusionDir.x = -lightPosition.x; extrusionDir.y = -lightPosition.y; extrusionDir.z = -lightPosition.z; extrusionDir.Normalize(); extrusionDir *= extrudeDistance; box.SetExtents( box.Minimum + extrusionDir, box.Maximum + extrusionDir ); } else { Vector3[] corners = box.Corners; Vector3 vmin = new Vector3(); Vector3 vmax = new Vector3(); for ( int i = 0; i < 8; i++ ) { extrusionDir.x = corners[ i ].x - lightPosition.x; extrusionDir.y = corners[ i ].y - lightPosition.y; extrusionDir.z = corners[ i ].z - lightPosition.z; extrusionDir.Normalize(); extrusionDir *= extrudeDistance; Vector3 res = corners[ i ] + extrusionDir; if ( i == 0 ) { vmin = res; vmax = res; } else { vmin.Floor( res ); vmax.Ceil( res ); } } box.SetExtents( vmin, vmax ); } }
/// <summary> /// IsObjectVisible() function for portals. /// </summary> /// <remarks> /// Everything needs to be updated spatially before this function is /// called including portal corners, frustum planes, etc. /// </remarks> /// <param name="portal"> /// The <see cref="Portal"/> to check visibility against. /// </param> /// <returns> /// true if the Portal is visible. /// </returns> public bool IsObjectVisible( Portal portal ) { // if portal isn't open, it's not visible if ( !portal.IsOpen ) { return false; } // if the frustum has no planes, just return true if ( mActiveCullingPlanes.Count == 0 ) { return true; } // check if this portal is already in the list of active culling planes (avoid // infinite recursion case) foreach ( PCPlane plane in mActiveCullingPlanes ) { if ( plane.Portal == portal ) { return false; } } // if portal is of type AABB or Sphere, then use simple bound check against planes if ( portal.Type == PORTAL_TYPE.PORTAL_TYPE_AABB ) { AxisAlignedBox aabb = new AxisAlignedBox(); aabb.SetExtents( portal.getDerivedCorner( 0 ), portal.getDerivedCorner( 1 ) ); return IsObjectVisible( aabb ); } else if ( portal.Type == PORTAL_TYPE.PORTAL_TYPE_SPHERE ) { return IsObjectVisible( portal.getDerivedSphere() ); } // check if the portal norm is facing the frustum Vector3 frustumToPortal = portal.getDerivedCP() - mOrigin; Vector3 portalDirection = portal.getDerivedDirection(); Real dotProduct = frustumToPortal.Dot( portalDirection ); if ( dotProduct > 0 ) { // portal is faced away from Frustum return false; } // check against frustum culling planes bool visible_flag; // Check originPlane if told to if ( mUseOriginPlane ) { // set the visible flag to false visible_flag = false; // we have to check each corner of the portal for ( int corner = 0; corner < 4; corner++ ) { PlaneSide side = mOriginPlane.GetSide( portal.getDerivedCorner( corner ) ); if ( side != PlaneSide.Negative ) { visible_flag = true; } } // if the visible_flag is still false, then the origin plane // culled all the portal points if ( visible_flag == false ) { // ALL corners on negative side therefore out of view return false; } } // For each active culling plane, see if all portal points are on the negative // side. If so, the portal is not visible foreach ( PCPlane plane in mActiveCullingPlanes ) { visible_flag = false; // we have to check each corner of the portal for ( int corner = 0; corner < 4; corner++ ) { PlaneSide side = plane.GetSide( portal.getDerivedCorner( corner ) ); if ( side != PlaneSide.Negative ) { visible_flag = true; } } // if the visible_flag is still false, then this plane // culled all the portal points if ( visible_flag == false ) { // ALL corners on negative side therefore out of view return false; } } // no plane culled all the portal points and the norm // was facing the frustum, so this portal is visible return true; }
public unsafe void Initialize( int startx, int startz, Real[] pageHeightData ) { if ( mOptions.maxGeoMipMapLevel != 0 ) { int i = (int)1 << ( mOptions.maxGeoMipMapLevel - 1 ); if ( ( i + 1 ) > mOptions.tileSize ) { LogManager.Instance.Write( "Invalid maximum mipmap specifed, must be n, such that 2^(n-1)+1 < tileSize \n" ); return; } } DeleteGeometry(); //calculate min and max heights; Real min = 256000, max = 0; mTerrain = new VertexData(); mTerrain.vertexStart = 0; mTerrain.vertexCount = mOptions.tileSize * mOptions.tileSize; renderOperation.useIndices = true; renderOperation.operationType = mOptions.useTriStrips ? OperationType.TriangleStrip : OperationType.TriangleList; renderOperation.vertexData = mTerrain; renderOperation.indexData = GetIndexData(); VertexDeclaration decl = mTerrain.vertexDeclaration; VertexBufferBinding bind = mTerrain.vertexBufferBinding; // positions int offset = 0; decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float3, VertexElementSemantic.Position ); offset += VertexElement.GetTypeSize( VertexElementType.Float3 ); if ( mOptions.lit ) { decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float3, VertexElementSemantic.Position ); offset += VertexElement.GetTypeSize( VertexElementType.Float3 ); } // texture coord sets decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 ); offset += VertexElement.GetTypeSize( VertexElementType.Float2 ); decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1 ); offset += VertexElement.GetTypeSize( VertexElementType.Float2 ); if ( mOptions.coloured ) { decl.AddElement( MAIN_BINDING, offset, VertexElementType.Color, VertexElementSemantic.Diffuse ); offset += VertexElement.GetTypeSize( VertexElementType.Color ); } // Create shared vertex buffer mMainBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( MAIN_BINDING ), mTerrain.vertexCount, BufferUsage.StaticWriteOnly ); // Create system memory copy with just positions in it, for use in simple reads //mPositionBuffer = OGRE_ALLOC_T(float, mTerrain.vertexCount * 3, MEMCATEGORY_GEOMETRY); mPositionBuffer = new float[ mTerrain.vertexCount * 3 ]; bind.SetBinding( MAIN_BINDING, mMainBuffer ); if ( mOptions.lodMorph ) { // Create additional element for delta decl.AddElement( DELTA_BINDING, 0, VertexElementType.Float1, VertexElementSemantic.BlendWeights ); // NB binding is not set here, it is set when deriving the LOD } mInit = true; mRenderLevel = 0; mMinLevelDistSqr = new Real[ mOptions.maxGeoMipMapLevel ]; int endx = startx + mOptions.tileSize; int endz = startz + mOptions.tileSize; Vector3 left, down, here; VertexElement poselem = decl.FindElementBySemantic( VertexElementSemantic.Position ); VertexElement texelem0 = decl.FindElementBySemantic( VertexElementSemantic.TexCoords, 0 ); VertexElement texelem1 = decl.FindElementBySemantic( VertexElementSemantic.TexCoords, 1 ); //fixed ( float* pSysPos = mPositionBuffer ) { int pos = 0; byte* pBase = (byte*)mMainBuffer.Lock( BufferLocking.Discard ); for ( int j = startz; j < endz; j++ ) { for ( int i = startx; i < endx; i++ ) { float* pPos = (float*)( pBase + poselem.Offset ); float* pTex0 = (float*)( pBase + texelem0.Offset ); float* pTex1 = (float*)( pBase + texelem1.Offset ); //poselem.baseVertexPointerToElement(pBase, &pPos); //texelem0.baseVertexPointerToElement(pBase, &pTex0); //texelem1.baseVertexPointerToElement(pBase, &pTex1); Real height = pageHeightData[ j * mOptions.pageSize + i ]; height = height * mOptions.scale.y; // scale height //*pSysPos++ = *pPos++ = (float) i*mOptions.scale.x; //x //*pSysPos++ = *pPos++ = height; // y //*pSysPos++ = *pPos++ = (float) j*mOptions.scale.z; //z mPositionBuffer[ pos++ ] = *pPos++ = (float)i * mOptions.scale.x; //x mPositionBuffer[ pos++ ] = *pPos++ = height; // y mPositionBuffer[ pos++ ] = *pPos++ = (float)j * mOptions.scale.z; //z *pTex0++ = (float)i / (float)( mOptions.pageSize - 1 ); *pTex0++ = (float)j / (float)( mOptions.pageSize - 1 ); *pTex1++ = ( (float)i / (float)( mOptions.tileSize - 1 ) ) * mOptions.detailTile; *pTex1++ = ( (float)j / (float)( mOptions.tileSize - 1 ) ) * mOptions.detailTile; if ( height < min ) min = (Real)height; if ( height > max ) max = (Real)height; pBase += mMainBuffer.VertexSize; } } mMainBuffer.Unlock(); mBounds = new AxisAlignedBox(); mBounds.SetExtents( new Vector3( (Real)startx * mOptions.scale.x, min, (Real)startz * mOptions.scale.z ), new Vector3( (Real)( endx - 1 ) * mOptions.scale.x, max, (Real)( endz - 1 ) * mOptions.scale.z ) ); mCenter = new Vector3( ( startx * mOptions.scale.x + ( endx - 1 ) * mOptions.scale.x ) / 2, ( min + max ) / 2, ( startz * mOptions.scale.z + ( endz - 1 ) * mOptions.scale.z ) / 2 ); boundingRadius = Math.Sqrt( Utility.Sqr( max - min ) + Utility.Sqr( ( endx - 1 - startx ) * mOptions.scale.x ) + Utility.Sqr( ( endz - 1 - startz ) * mOptions.scale.z ) ) / 2; // Create delta buffer list if required to morph if ( mOptions.lodMorph ) { // Create delta buffer for all except the lowest mip mDeltaBuffers = new AxiomSortedCollection<int, HardwareVertexBuffer>( mOptions.maxGeoMipMapLevel - 1 ); } Real C = CalculateCFactor(); CalculateMinLevelDist2( C ); } }