/// <summary> /// Sets the new submesh. /// </summary> /// <param name="context">The render context.</param> /// <param name="submesh">The submesh.</param> /// <param name="effectPassBinding">The effect pass binding.</param> /// <param name="effectPassParameterBindings"> /// The effect parameter bindings containing per-pass parameter bindings. /// (Can also contain other parameter binding, e.g. per-instance, which are ignored. /// </param> /// <remarks> /// The current batch is automatically flushed when the submesh is changed. /// </remarks> public void SetSubmesh(RenderContext context, Submesh submesh, EffectPassBinding effectPassBinding, EffectParameterBindingCollection effectPassParameterBindings) { Flush(); _renderContext = context; _submesh = submesh; _effectPassBinding = effectPassBinding; _effectPassParameterBindings = effectPassParameterBindings; }
/// <summary> /// Releases all resources used by an instance of the <see cref="RenderBatch{TVertex,TIndex}"/> class. /// </summary> public void Dispose() { if (IsDisposed) { return; } _renderContext = null; _submesh = null; _effectPassBinding = new EffectPassBinding(); _effectPassParameterBindings = null; _instanceVertexBuffer.Dispose(); IsDisposed = true; }
private void Draw(ref EffectPassBinding passBinding, RenderContext context, int index, int count, RenderOrder order) { var jobs = _jobs.Array; var cameraNode = context.CameraNode; var cameraPose = cameraNode.PoseWorld; var graphicsDevice = context.GraphicsService.GraphicsDevice; // Flag: true if the box vertex/index buffers are not set in the graphics device. bool setBoxBuffers = true; foreach (var pass in passBinding) { for (int i = index; i < index + count; i++) { var materialInstanceBinding = jobs[i].MaterialInstanceBinding; var decalNode = jobs[i].DecalNode; var decalPose = decalNode.PoseWorld; // Update and apply local, per-instance and per-pass bindings. foreach (var binding in materialInstanceBinding.ParameterBindings) { if (binding.Description.Hint == EffectParameterHint.PerPass) binding.Update(context); binding.Apply(context); } pass.Apply(); bool drawWithQuad = false; if (!ClipAtNearPlane) { // ----- Check if near plane intersects the decal box. // First make a simple AABB check in world space. if (GeometryHelper.HaveContact(_cameraNearPlaneAabbWorld, decalNode.Aabb)) { // Make exact check of decal box against camera near plane AABB in camera space. var decalBoxExtent = new Vector3(1, 1, 1); decalBoxExtent *= decalNode.ScaleLocal; var decalBoxCenter = new Vector3(0, 0, -decalNode.ScaleLocal.Z / 2); // Get pose of decal box in view space. var decalBoxPose = new Pose( cameraPose.ToLocalPosition(decalPose.Position + decalPose.Orientation * decalBoxCenter), cameraPose.Orientation.Transposed * decalPose.Orientation); // Aabb of camera near plane in view space. var projection = cameraNode.Camera.Projection; var cameraNearPlaneAabb = new Aabb( new Vector3(projection.Left, projection.Bottom, -projection.Near), new Vector3(projection.Right, projection.Top, -projection.Near)); drawWithQuad = GeometryHelper.HaveContact(cameraNearPlaneAabb, decalBoxExtent, decalBoxPose, true); } } if (!drawWithQuad) { // Draw a box primitive. if (setBoxBuffers) { graphicsDevice.SetVertexBuffer(_vertexBuffer); graphicsDevice.Indices = _indexBuffer; setBoxBuffers = false; } graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, NumberOfPrimitives); #else graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, NumberOfVertices, 0, NumberOfPrimitives); } else { // Draw a quad at the near plane because the camera is inside the box. // The quad vertices must be given decal space! var projection = cameraNode.Camera.Projection; Vector3 scale = decalNode.ScaleWorld; Pose cameraToDecalPose = decalPose.Inverse * cameraPose; Vector4 scissor = GraphicsHelper.GetBounds(cameraNode, decalNode); // Use a bias to avoid that this quad is clipped by the near plane. const float bias = 1.0001f; float left = InterpolationHelper.Lerp(projection.Left, projection.Right, scissor.X) * bias; float top = InterpolationHelper.Lerp(projection.Top, projection.Bottom, scissor.Y) * bias; float right = InterpolationHelper.Lerp(projection.Left, projection.Right, scissor.Z) * bias; float bottom = InterpolationHelper.Lerp(projection.Top, projection.Bottom, scissor.W) * bias; float z = -projection.Near * bias; _quadVertices[0] = cameraToDecalPose.ToWorldPosition(new Vector3(left, top, z)); _quadVertices[0].X /= scale.X; _quadVertices[0].Y /= scale.Y; _quadVertices[0].Z /= scale.Z; _quadVertices[1] = cameraToDecalPose.ToWorldPosition(new Vector3(right, top, z)); _quadVertices[1].X /= scale.X; _quadVertices[1].Y /= scale.Y; _quadVertices[1].Z /= scale.Z; _quadVertices[2] = cameraToDecalPose.ToWorldPosition(new Vector3(left, bottom, z)); _quadVertices[2].X /= scale.X; _quadVertices[2].Y /= scale.Y; _quadVertices[2].Z /= scale.Z; _quadVertices[3] = cameraToDecalPose.ToWorldPosition(new Vector3(right, bottom, z)); _quadVertices[3].X /= scale.X; _quadVertices[3].Y /= scale.Y; _quadVertices[3].Z /= scale.Z; graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _quadVertices, 0, 2, VertexPosition.VertexDeclaration); // Remember that the device vertex/index buffers are not set anymore. setBoxBuffers = true; } } } }