/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> public void Dispose() { for (int i = 0; i < _volumeRtSections.Length; ++i) { _volumeSections[i]?.Dispose(); _volumeRtSections[i]?.Dispose(); } _textureView = null; _cube?.Dispose(); _volumeScaleFactor?.Dispose(); _volumeRayParams?.Dispose(); _cubeTransform?.Dispose(); _cubePosShader?.Dispose(); _cubeDirShader?.Dispose(); _cubeVs?.Dispose(); _inputLayout?.Dispose(); _cubeTransform = null; _inputLayout = null; _cube = null; _volumeScaleFactor = null; _volumeRayParams = null; _cubePosShader = null; _cubeDirShader = null; _cubeVs = null; }
/// <summary> /// Initializes a new instance of the <see cref="Cube"/> class. /// </summary> /// <param name="graphics">The graphics object used to create the buffers needed by this object.</param> /// <param name="inputLayout">The input layout describing how a vertex is laid out.</param> public Cube(GorgonGraphics graphics, GorgonInputLayout inputLayout) { CubeVertex[] vertices = { new CubeVertex(new DX.Vector3(-0.5f, 0.5f, -0.5f), new DX.Vector3(0, 0, 0)), new CubeVertex(new DX.Vector3(0.5f, 0.5f, -0.5f), new DX.Vector3(1.0f, 1.0f, 0)), new CubeVertex(new DX.Vector3(0.5f, -0.5f, -0.5f), new DX.Vector3(0.0f, 1.0f, 0)), new CubeVertex(new DX.Vector3(-0.5f, -0.5f, -0.5f), new DX.Vector3(1.0f, 0.0f, 0)), new CubeVertex(new DX.Vector3(-0.5f, 0.5f, 0.5f), new DX.Vector3(0, 0, 0)), new CubeVertex(new DX.Vector3(0.5f, 0.5f, 0.5f), new DX.Vector3(1.0f, 1.0f, 0)), new CubeVertex(new DX.Vector3(0.5f, -0.5f, 0.5f), new DX.Vector3(0.0f, 1.0f, 0)), new CubeVertex(new DX.Vector3(-0.5f, -0.5f, 0.5f), new DX.Vector3(1.0f, 0.0f, 0)), }; ushort[] indices = { // Front face. 0, 1, 2, 2, 3, 0, // Back face. 5, 4, 6, 4, 7, 6, // Left face. 4, 0, 3, 3, 7, 4, // Right face. 1, 5, 6, 6, 2, 1, // Top face 4, 5, 1, 1, 0, 4, // Bottom face 2, 6, 7, 7, 3, 2 }; // Create our index buffer and vertex buffer and populate with our cube data. using (var indexPtr = GorgonNativeBuffer <ushort> .Pin(indices)) using (var vertexPtr = GorgonNativeBuffer <CubeVertex> .Pin(vertices)) { IndexBuffer = new GorgonIndexBuffer(graphics, new GorgonIndexBufferInfo("Volume Index Buffer") { Usage = ResourceUsage.Immutable, IndexCount = indices.Length, Use16BitIndices = true }, indexPtr); VertexBuffer = new GorgonVertexBufferBindings(inputLayout) { [0] = GorgonVertexBufferBinding.CreateVertexBuffer(graphics, vertices.Length, ResourceUsage.Immutable, initialData: vertexPtr, bufferName: "Volume Vertex Buffer") }; } }
/// <summary> /// Initializes a new instance of the <see cref="DrawCallFactory"/> class. /// </summary> /// <param name="graphics">The graphics interface to use when creating states.</param> /// <param name="defaultTexture">The default texture to use as a fallback when no texture is passed by renderable.</param> /// <param name="inputLayout">The input layout defining a vertex type.</param> public DrawCallFactory(GorgonGraphics graphics, GorgonTexture2DView defaultTexture, GorgonInputLayout inputLayout) { _inputLayout = inputLayout; _drawIndexAllocator = new GorgonDrawCallPoolAllocator <GorgonDrawIndexCall>(128); _drawAllocator = new GorgonDrawCallPoolAllocator <GorgonDrawCall>(128); _drawIndexBuilder = new GorgonDrawIndexCallBuilder(); _drawBuilder = new GorgonDrawCallBuilder(); _stateBuilder = new GorgonPipelineStateBuilder(graphics); _defaultTexture = defaultTexture; }
/// <summary> /// Function to load the resources for the layer. /// </summary> public override void LoadResources() { _drawCalls = new List <GorgonDrawIndexCall>(); BuildConstantBuffers(); for (int i = 0; i < Planets.Count; ++i) { Planet planet = Planets[i]; for (int j = 0; j < planet.Layers.Count; ++j) { PlanetaryLayer layer = planet.Layers[j]; GorgonVertexShader vertexShader = _resources.VertexShaders[layer.Mesh.Material.VertexShader]; GorgonPixelShader pixelShader = _resources.PixelShaders[layer.Mesh.Material.PixelShader]; // Create our vertex layout now. if (_vertexLayout == null) { _vertexLayout = _vertexLayout = GorgonInputLayout.CreateUsingType <Vertex3D>(_graphics, vertexShader); } // Set up a pipeline state for the mesh. GorgonPipelineState pipelineState = _stateBuilder.Clear() .PixelShader(pixelShader) .VertexShader(vertexShader) .BlendState(layer.Mesh.Material.BlendState) .PrimitiveType(PrimitiveType.TriangleList) .Build(); _drawCallBuilder.Clear() .PipelineState(pipelineState) .IndexBuffer(layer.Mesh.IndexBuffer, 0, layer.Mesh.IndexCount) .VertexBuffer(_vertexLayout, new GorgonVertexBufferBinding(layer.Mesh.VertexBuffer, Vertex3D.Size)) .ConstantBuffer(ShaderType.Vertex, _viewProjectionBuffer) .ConstantBuffer(ShaderType.Vertex, _worldBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _cameraBuffer) .ConstantBuffer(ShaderType.Pixel, _lightBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _materialBuffer, 2); (int startTexture, int textureCount) = layer.Mesh.Material.Textures.GetDirtyItems(); for (int k = startTexture; k < startTexture + textureCount; ++k) { GorgonTexture2DView texture = _resources.Textures[layer.Mesh.Material.Textures[k]]; _drawCallBuilder.ShaderResource(ShaderType.Pixel, texture, k); // We should have this in the material, but since we know what we've got here, this will be fine. _drawCallBuilder.SamplerState(ShaderType.Pixel, GorgonSamplerState.Wrapping, k); } _drawCalls.Add(_drawCallBuilder.Build()); } } UpdateLightTransforms(); }
/// <summary> /// Function to save the state information to this object. /// </summary> private void Save() { _targets = _graphics.Output.GetRenderTargets(); _uavs = _graphics.Output.GetUnorderedAccessViews(); _indexBuffer = _graphics.Input.IndexBuffer; _vertexBuffer = _graphics.Input.VertexBuffers[0]; _inputLayout = _graphics.Input.Layout; _primitiveType = _graphics.Input.PrimitiveType; _pixelShader = _graphics.Shaders.PixelShader.Current; _vertexShader = _graphics.Shaders.VertexShader.Current; _blendStates = _graphics.Output.BlendingState.States; _blendFactor = _graphics.Output.BlendingState.BlendFactor; _blendSampleMask = _graphics.Output.BlendingState.BlendSampleMask; _rasterStates = _graphics.Rasterizer.States; _samplerState = _graphics.Shaders.PixelShader.TextureSamplers[0]; _resource = _graphics.Shaders.PixelShader.Resources[0]; _depthStencilState = _graphics.Output.DepthStencilState.States; _depthStencilReference = _graphics.Output.DepthStencilState.StencilReference; _rasterStates.IsScissorTestingEnabled = false; _depthStencil = _graphics.Output.DepthStencilView; _viewports = _graphics.Rasterizer.GetViewports(); _scissorTests = _graphics.Rasterizer.GetScissorRectangles(); _alphaTest = new Gorgon2DAlphaTest(Gorgon2D.IsAlphaTestEnabled, GorgonRangeF.Empty); _vsConstantBuffers = new Dictionary <int, GorgonConstantBuffer>(); _psConstantBuffers = new Dictionary <int, GorgonConstantBuffer>(); // Only store the constant buffers that we were using. // We need to store all the constant buffers because the effects // make use of multiple constant slots. Unlike the resource views, // where we know that we're only using the first item (all bets are // off if a user decides to use another resource view slot), there's no // guarantee that we'll be only using 1 or 2 constant buffer slots. for (int i = 0; i < _graphics.Shaders.VertexShader.ConstantBuffers.Count; i++) { if (_graphics.Shaders.VertexShader.ConstantBuffers[i] != null) { _vsConstantBuffers[i] = _graphics.Shaders.VertexShader.ConstantBuffers[i]; } } for (int i = 0; i < _graphics.Shaders.PixelShader.ConstantBuffers.Count; i++) { if (_graphics.Shaders.PixelShader.ConstantBuffers[i] != null) { _psConstantBuffers[i] = _graphics.Shaders.PixelShader.ConstantBuffers[i]; } } }
/// <summary> /// Initializes a new instance of the <see cref="Plane" /> class. /// </summary> /// <param name="graphics">The graphics interface used to create the buffers for this object.</param> /// <param name="inputLayout">The input layout for the vertices in this mesh.</param> /// <param name="size">The width and height of the plane.</param> /// <param name="textureCoordinates">Texture coordinates.</param> public Plane(GorgonGraphics graphics, GorgonInputLayout inputLayout, DX.Vector2 size, DX.RectangleF textureCoordinates) : base(inputLayout) { Size = size; // Create our vertices. Vertices = new[] { new BoingerVertex(new DX.Vector3(-size.X, size.Y, 0.0f), textureCoordinates.Location), new BoingerVertex(new DX.Vector3(size.X, size.Y, 0.0f), new DX.Vector2(textureCoordinates.Right, textureCoordinates.Top)), new BoingerVertex(new DX.Vector3(-size.X, -size.Y, 0.0f), new DX.Vector2(textureCoordinates.Left, textureCoordinates.Bottom)), new BoingerVertex(new DX.Vector3(size.X, -size.Y, 0.0f), new DX.Vector2(textureCoordinates.Right, textureCoordinates.Bottom)) }; // Create our indices. Indices = new ushort[] { 0, 1, 2, 2, 1, 3 }; // Copy the above vertex/index data into a vertex and index buffer so we can render our plane. using (var vertexPtr = GorgonNativeBuffer <BoingerVertex> .Pin(Vertices)) using (var indexPtr = GorgonNativeBuffer <ushort> .Pin(Indices)) { VertexBufferBindings[0] = GorgonVertexBufferBinding.CreateVertexBuffer(graphics, new GorgonVertexBufferInfo("Plane Vertex Buffer") { SizeInBytes = Vertices.Length * BoingerVertex.Size, Usage = ResourceUsage.Immutable }, vertexPtr); IndexBuffer = new GorgonIndexBuffer(graphics, new GorgonIndexBufferInfo("Plane Index Buffer") { Usage = ResourceUsage.Immutable, IndexCount = Indices.Length, Use16BitIndices = true }, indexPtr); } }
/// <summary> /// Function to create a draw call based on a mesh. /// </summary> /// <param name="mesh">The mesh to evaluate.</param> private void AddDrawCall(Mesh mesh) { // Find out which shaders are used by the mesh and retrieve them from the cache. if (!ShaderCache.TryGetValue(mesh.Material.VertexShader, out GorgonShader shader)) { return; } var vertexShader = (GorgonVertexShader)shader; if (!ShaderCache.TryGetValue(mesh.Material.PixelShader, out shader)) { return; } // Not an ideal place for this, but since we don't know when a vertex shader will be added to our renderer, and we require a vertex shader for our // input layout, then this will have to suffice. In a real renderer, we'd cache the vertex inputs per shader and just look it up because the type // of vertex may not be what we expect. In this case, we *know* that we're using Vertex3D and no other vertex type, so we're 100% safe doing it // here in this example. if ((_vertexLayout == null) && (vertexShader != null)) { _vertexLayout = GorgonInputLayout.CreateUsingType <Vertex3D>(_graphics, vertexShader); } var pixelShader = (GorgonPixelShader)shader; GorgonPipelineState pipelineState = _stateBuilder.Clear() .DepthStencilState(mesh.IsDepthWriteEnabled ? GorgonDepthStencilState.DepthEnabled : GorgonDepthStencilState.DepthEnabledNoWrite) .PixelShader(pixelShader) .VertexShader(vertexShader) .BlendState(mesh.Material.BlendState) .PrimitiveType(mesh.PrimitiveType) .Build(); _drawBuilder.Clear() .PipelineState(pipelineState) .IndexBuffer(mesh.IndexBuffer, 0, mesh.IndexCount) .VertexBuffer(_vertexLayout, new GorgonVertexBufferBinding(mesh.VertexBuffer, Vertex3D.Size)) .ConstantBuffer(ShaderType.Vertex, _viewProjectionBuffer) .ConstantBuffer(ShaderType.Vertex, _worldBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _cameraBuffer) .ConstantBuffer(ShaderType.Pixel, _lightBuffer, 1) .ConstantBuffer(ShaderType.Pixel, _materialBuffer, 2); ref readonly (int Start, int Count)textures = ref mesh.Material.Textures.GetDirtyItems();
/// <summary> /// Function to retrieve a draw indexed call from the pool and, initialize it. /// </summary> /// <param name="renderable">The renderable to evaluate.</param> /// <param name="batchState">The current global state for the batch.</param> /// <param name="indexBuffer">The index buffer to use when creating the draw call.</param> /// <param name="vertexBuffer">The vertex buffer binding to use when creating the draw call.</param> /// <param name="layout">The vertex input layout.</param> /// <returns>The draw call.</returns> public GorgonDrawIndexCall GetDrawIndexCall(BatchRenderable renderable, Gorgon2DBatchState batchState, GorgonIndexBuffer indexBuffer, GorgonVertexBufferBinding vertexBuffer, GorgonInputLayout layout) { SetCommonStates(_drawIndexBuilder, renderable, batchState, null); return(_drawIndexBuilder.VertexBuffer(layout, vertexBuffer) .IndexBuffer(indexBuffer) .Build(_drawIndexAllocator)); }
/// <summary> /// Function to initialize the blitter. /// </summary> public void Initialize() { try { // We've been initialized, so leave. if ((_vertexShader != null) || (Interlocked.Increment(ref _initializedFlag) > 1)) { // Trap other threads until we're done initializing and then release them. while ((_vertexShader == null) && (_initializedFlag > 0)) { var wait = new SpinWait(); wait.SpinOnce(); } return; } _vertexShader = GorgonShaderFactory.Compile <GorgonVertexShader>(_graphics, Resources.GraphicsShaders, "GorgonBltVertexShader", GorgonGraphics.IsDebugEnabled); _pixelShader = GorgonShaderFactory.Compile <GorgonPixelShader>(_graphics, Resources.GraphicsShaders, "GorgonBltPixelShader", GorgonGraphics.IsDebugEnabled); _inputLayout = GorgonInputLayout.CreateUsingType <BltVertex>(_graphics, _vertexShader); _vertexBufferBindings = new GorgonVertexBufferBindings(_inputLayout) { [0] = GorgonVertexBufferBinding.CreateVertexBuffer <BltVertex>(_graphics, 4, ResourceUsage.Dynamic, bufferName: "Gorgon Blitter Vertex Buffer") }; _wvpBuffer = GorgonConstantBufferView.CreateConstantBuffer(_graphics, new GorgonConstantBufferInfo("Gorgon Blitter WVP Buffer") { Usage = ResourceUsage.Dynamic, SizeInBytes = DX.Matrix.SizeInBytes }); // Finish initalizing the draw call. _pipelineState = _pipeStateBuilder.VertexShader(_vertexShader) .BlendState(GorgonBlendState.NoBlending) .DepthStencilState(GorgonDepthStencilState.Default) .PrimitiveType(PrimitiveType.TriangleStrip) .RasterState(GorgonRasterState.Default) .PixelShader(_pixelShader) .Build(); _drawCallBuilder.VertexBuffers(_inputLayout, _vertexBufferBindings) .VertexRange(0, 4) .SamplerState(ShaderType.Pixel, GorgonSamplerState.Default) .PipelineState(_pipelineState) .ConstantBuffer(ShaderType.Vertex, _wvpBuffer); _defaultTexture = Resources.White_2x2.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Gorgon_Default_White_Texture", Usage = ResourceUsage.Immutable, Binding = TextureBinding.ShaderResource }).GetShaderResourceView(); } finally { Interlocked.Decrement(ref _initializedFlag); } }
/// <summary> /// Function to initialize the GPU resource objects. /// </summary> private static void InitializeGpuResources() { _graphics = CreateGraphicsInterface(); // If we couldn't create the graphics interface, then leave. if (_graphics == null) { return; } // Create a 1280x800 window with a depth buffer. // We can modify the resolution in the config file for the application, but like other Gorgon examples, the default is 1280x800. _swap = new GorgonSwapChain(_graphics, _mainForm, new GorgonSwapChainInfo("Main") { // Set up for 32 bit RGBA normalized display. Format = BufferFormat.R8G8B8A8_UNorm, Width = Settings.Default.Resolution.Width, Height = Settings.Default.Resolution.Height }); // Build the depth buffer for our swap chain. BuildDepthBuffer(_swap.Width, _swap.Height); if (!Settings.Default.IsWindowed) { // Get the output for the main window. var currentScreen = Screen.FromControl(_mainForm); IGorgonVideoOutputInfo output = _graphics.VideoAdapter.Outputs[currentScreen.DeviceName]; // If we've asked for full screen mode, then locate the correct video mode and set us up. _selectedVideoMode = new GorgonVideoMode(Settings.Default.Resolution.Width, Settings.Default.Resolution.Height, BufferFormat.R8G8B8A8_UNorm); _swap.EnterFullScreen(in _selectedVideoMode, output); } // Handle resizing because the projection matrix and depth buffer needs to be updated to reflect the new view size. _swap.BeforeSwapChainResized += Swap_BeforeResized; _swap.AfterSwapChainResized += Swap_AfterResized; // Set the current render target output so we can see something. _graphics.SetRenderTarget(_swap.RenderTargetView, _depthBuffer); // Create our shaders. // Our vertex shader. This is a simple shader, it just processes a vertex by multiplying it against // the world/view/projection matrix and spits it back out. _vertexShader = GorgonShaderFactory.Compile <GorgonVertexShader>(_graphics, Resources.Shader, "BoingerVS"); // Our main pixel shader. This is a very simple shader, it just reads a texture and spits it back out. Has no // diffuse capability. _pixelShader = GorgonShaderFactory.Compile <GorgonPixelShader>(_graphics, Resources.Shader, "BoingerPS"); // Create the vertex input layout. // We need to create a layout for our vertex type because the shader won't know how to interpret the data we're sending it otherwise. // This is why we need a vertex shader before we even create the layout. _inputLayout = GorgonInputLayout.CreateUsingType <BoingerVertex>(_graphics, _vertexShader); // Resources are stored as System.Drawing.Bitmap files, so we need to convert into an IGorgonImage so we can upload it to a texture. // We also will generate mip-map levels for this image so that scaling the texture will look better. using (IGorgonImage image = Resources.Texture.ToGorgonImage()) { _texture = image.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Usage = ResourceUsage.Immutable, Name = "Texture" }) .GetShaderResourceView(); } // Create our constant buffer. // Our constant buffers are how we send data to our shaders. This one in particular will be responsible for sending our world/view/projection matrix // to the vertex shader. _wvpBuffer = GorgonConstantBufferView.CreateConstantBuffer(_graphics, new GorgonConstantBufferInfo("WVPBuffer") { Usage = ResourceUsage.Dynamic, SizeInBytes = DX.Matrix.SizeInBytes }); // This one will hold our material information. _materialBuffer = GorgonConstantBufferView.CreateConstantBuffer(_graphics, new GorgonConstantBufferInfo("MaterialBuffer") { Usage = ResourceUsage.Dynamic, SizeInBytes = Unsafe.SizeOf <GorgonColor>() }); GorgonColor defaultMaterialColor = GorgonColor.White; _materialBuffer.Buffer.SetData(ref defaultMaterialColor); GorgonExample.LoadResources(_graphics); }
/// <summary> /// Function to initialize the application. /// </summary> private static void Initialize() { var depthFormat = BufferFormat.D24_UIntNormal_S8_UInt; // Depth buffer format. // Create our form. _mainForm = new formMain(); // Add a keybinding to switch to full screen or windowed. _mainForm.KeyDown += _mainForm_KeyDown; // Create the main graphics interface. Graphics = new GorgonGraphics(); // Validate depth buffer for this device. // Odds are good that if this fails, you should probably invest in a // better video card. Preferably something created after 2005. if (!Graphics.VideoDevice.SupportsDepthFormat(depthFormat)) { depthFormat = BufferFormat.D16_UIntNormal; if (Graphics.VideoDevice.SupportsDepthFormat(depthFormat)) { return; } GorgonDialogs.ErrorBox(_mainForm, "Video device does not support a 24 or 16 bit depth buffer."); return; } // Create a 1280x800 window with a depth buffer. // We can modify the resolution in the config file for the application, but // like other Gorgon examples, the default is 1280x800. _swap = Graphics.Output.CreateSwapChain("Main", new GorgonSwapChainSettings { Window = _mainForm, // Assign to our form. Format = BufferFormat.R8G8B8A8_UIntNormal, // Set up for 32 bit RGBA normalized display. Size = Settings.Default.Resolution, // Get the resolution from the config file. DepthStencilFormat = depthFormat, // Get our depth format. IsWindowed = Settings.Default.IsWindowed // Set up for windowed or full screen (depending on config file). }); // Center on the primary monitor. // This is necessary because we already created the window, so it'll be off center at this point. _mainForm.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width / 2 - _mainForm.Width / 2, Screen.PrimaryScreen.WorkingArea.Height / 2 - _mainForm.Height / 2); // Handle any resizing. // This is here because the base graphics library will NOT handle state loss due to resizing. // This is up to the developer to handle. _swap.AfterSwapChainResized += _swap_Resized; // Create the 2D interface for our text. _2D = Graphics.Output.Create2DRenderer(_swap); // Create our shaders. // Our vertex shader. This is a simple shader, it just processes a vertex by multiplying it against // the world/view/projection matrix and spits it back out. _vertexShader = Graphics.Shaders.CreateShader <GorgonVertexShader>("VertexShader", "BoingerVS", Resources.Shader); // Our main pixel shader. This is a very simple shader, it just reads a texture and spits it back out. Has no // diffuse capability. _pixelShader = Graphics.Shaders.CreateShader <GorgonPixelShader>("PixelShader", "BoingerPS", Resources.Shader); // Our shadow shader for our ball "shadow". This is hard coded to send back black (R:0, G:0, B:0) at 50% opacity (A: 0.5). _pixelShaderShadow = Graphics.Shaders.CreateShader <GorgonPixelShader>("ShadowShader", "BoingerShadowPS", Resources.Shader); // Create the vertex input layout. // We need to create a layout for our vertex type because the shader won't know // how to interpret the data we're sending it otherwise. This is why we need a // vertex shader before we even create the layout. _inputLayout = Graphics.Input.CreateInputLayout("InputLayout", typeof(BoingerVertex), _vertexShader); // Create the view port. // This just tells the renderer how big our display is. var view = new GorgonViewport(0, 0, _mainForm.ClientSize.Width, _mainForm.ClientSize.Height, 0.0f, 1.0f); // Load our textures from the resources. // This contains our textures for the walls and ball. _texture = Graphics.Textures.CreateTexture <GorgonTexture2D>("PlaneTexture", Resources.Texture); // Set up our view matrix. // Move the camera (view matrix) back 2.2 units. This will give us enough room to see what's // going on. Matrix.Translation(0, 0, 2.2f, out _viewMatrix); // Set up our projection matrix. // This matrix is probably the cause of almost EVERY problem you'll ever run into in 3D programming. // Basically we're telling the renderer that we want to have a vertical FOV of 75 degrees, with the aspect ratio // based on our form width and height. The final values indicate how to distribute Z values across depth (tip: // it's not linear). _projMatrix = Matrix.PerspectiveFovLH((75.0f).Radians(), _mainForm.Width / (float)_mainForm.Height, 0.125f, 500.0f); // Create our constant buffer and backing store. // Our constant buffers are how we send data to our shaders. This one in particular will be responsible // for sending our world/view/projection matrix to the vertex shader. The stream we're creating after // the constant buffer is our system memory store for the data. Basically we write to the system // memory and then upload that data to the video card. This is very different from how things used to // work, but allows a lot more flexibility. _wvpBuffer = Graphics.Buffers.CreateConstantBuffer("WVPBuffer", new GorgonConstantBufferSettings { SizeInBytes = Matrix.SizeInBytes }); _wvpBufferStream = new GorgonDataStream(_wvpBuffer.SizeInBytes); // Create our planes. // Here's where we create the 2 planes for our rear wall and floor. We set the texture size to texel units // because that's how the video card expects them. However, it's a little hard to eyeball 0.67798223f by looking // at the texture image display, so we use the ToTexel function to determine our texel size. var textureSize = _texture.ToTexel(new Vector2(500, 500)); _planes = new[] { new Plane(new Vector2(3.5f), new RectangleF(Vector2.Zero, textureSize)), new Plane(new Vector2(3.5f), new RectangleF(Vector2.Zero, textureSize)) }; // Set up default positions and orientations. _planes[0].Position = new Vector3(0, 0, 3.0f); _planes[1].Position = new Vector3(0, -3.5f, 3.5f); _planes[1].Rotation = new Vector3(90.0f, 0, 0); // Create our sphere. // Again, here we're using texels to align the texture coordinates to the other image // packed into the texture (atlasing). var textureOffset = _texture.ToTexel(new Vector2(516, 0)); // This is to scale our texture coordinates because the actual image is much smaller // (256x256) than the full texture (1024x512). textureSize.X = 0.245f; textureSize.Y = 0.5f; // Give the sphere a place to live. _sphere = new Sphere(1.0f, textureOffset, textureSize) { Position = new Vector3(2.2f, 1.5f, 2.5f) }; // Bind our objects to the pipeline and set default states. // At this point we need to give the graphics card a bunch of things // it needs to do its job. // Give our current input layout. Graphics.Input.Layout = _inputLayout; // We're drawing individual triangles for this (and this is usyally the case). Graphics.Input.PrimitiveType = PrimitiveType.TriangleList; // Bind our current vertex shader and send over our world/view/projection matrix // constant buffer. Graphics.Shaders.VertexShader.Current = _vertexShader; Graphics.Shaders.VertexShader.ConstantBuffers[0] = _wvpBuffer; // Do the same with the pixel shader, only we're binding our texture to it as well. // We also need to bind a sampler to the texture because without it, the shader won't // know how to interpret the texture data (e.g. how will the shader know if the texture // is supposed to be bilinear filtered or point filtered?) Graphics.Shaders.PixelShader.Current = _pixelShader; Graphics.Shaders.PixelShader.Resources[0] = _texture; Graphics.Shaders.PixelShader.TextureSamplers[0] = GorgonTextureSamplerStates.LinearFilter; // Turn on alpha blending. Graphics.Output.BlendingState.States = GorgonBlendStates.ModulatedBlending; // Turn on depth writing. // This is our depth writing state. When this is on, all polygon data sent to the card // will write to our depth buffer. Normally we want this, but for translucent objects, it's // problematic.... _depth = new GorgonDepthStencilStates { DepthComparison = ComparisonOperator.LessEqual, IsDepthEnabled = true, IsDepthWriteEnabled = true, IsStencilEnabled = false }; // Turn off depth writing. // So, we copy the depth state and turn off depth writing so that translucent objects // won't write to the depth buffer but can still read it. _noDepth = _depth; _noDepth.IsDepthWriteEnabled = false; Graphics.Output.DepthStencilState.States = _depth; // Bind our swap chain and set up the default rasterizer states. Graphics.Output.SetRenderTarget(_swap, _swap.DepthStencilBuffer); Graphics.Rasterizer.States = GorgonRasterizerStates.CullBackFace; Graphics.Rasterizer.SetViewport(view); // I know, there's a lot in here. Thing is, if this were Direct 3D 11 code, it'd probably MUCH // more code and that's even before creating our planes and sphere. }
public void Init() { _form = new TestForm { ShowTestPanel = true, ClientSize = new Size(1280, 800) }; _form.WindowState = FormWindowState.Minimized; _form.Show(); _form.WindowState = FormWindowState.Normal; _graphics = new GorgonGraphics(); _swap = _graphics.Output.CreateSwapChain("Screen", new GorgonSwapChainSettings() { Window = _form.panelDisplay, DepthStencilFormat = BufferFormat.D24_UIntNormal_S8_UInt }); _swap.AfterSwapChainResized += (sender, args) => { var currentMatrix = new MatrixBuffer(); _graphics.Rasterizer.SetViewport(_swap.Viewport); _aspect = (_swap.Settings.VideoMode.Width) / (float)(_swap.Settings.VideoMode.Height); currentMatrix.Projection = Matrix.PerspectiveFovLH(100.39f.Radians(), _aspect, 0.1f, 1000.0f); currentMatrix.View = Matrix.LookAtLH(new Vector3(0, 0, -0.75f), new Vector3(0, 0, 1.0f), Vector3.UnitY); _graphics.Output.SetRenderTarget(_swap, _swap.DepthStencilBuffer); pvw = currentMatrix.View * currentMatrix.Projection; }; _swap.AfterStateTransition += (sender, args) => { var currentMatrix = new MatrixBuffer(); _graphics.Rasterizer.SetViewport(_swap.Viewport); _aspect = (_swap.Settings.VideoMode.Width) / (float)(_swap.Settings.VideoMode.Height); currentMatrix.Projection = Matrix.PerspectiveFovLH(100.39f.Radians(), _aspect, 0.1f, 1000.0f); currentMatrix.View = Matrix.LookAtLH(new Vector3(0, 0, -0.75f), new Vector3(0, 0, 1.0f), Vector3.UnitY); _graphics.Output.SetRenderTarget(_swap, _swap.DepthStencilBuffer); pvw = currentMatrix.View * currentMatrix.Projection; }; var button = new Button() { Text = "3D", Location = new Point(90, 3) }; button.Click += (sender, args) => { _3d = !_3d; Matrix currentMatrix = Matrix.LookAtLH(new Vector3(0, 0, _camPos), new Vector3(0, 0, 1.0f), Vector3.UnitY); Matrix projection = Matrix.PerspectiveFovLH(100.39f.Radians(), _aspect, 0.1f, 1000.0f); pvw = currentMatrix * projection; }; _form.panelInput.Controls.Add(button); _sprite = new vertex[Count * 4]; for (int i = 0; i < Count; i++) { _balls[i].Scale = 1.0f; _balls[i].ScaleDelta = (GorgonRandom.RandomSingle() * 1.5f) + 0.25f; _balls[i].AlphaBounce = _balls[i].ScaleBouce = false; _balls[i].XBounce = GorgonRandom.RandomInt32(0, 100) > 50; _balls[i].YBounce = GorgonRandom.RandomInt32(0, 100) > 50; _balls[i].ZBounce = GorgonRandom.RandomInt32(0, 100) > 50; _balls[i].Velocity = new Vector3((GorgonRandom.RandomSingle() * 0.5f), (GorgonRandom.RandomSingle() * 0.5f), (GorgonRandom.RandomSingle() * 0.5f)); _balls[i].Angle = 0.0f; _balls[i].AngleDelta = 1.0f; _balls[i].Color = new Vector4(1.0f); _balls[i].AlphaDelta = GorgonRandom.RandomSingle() * 0.5f; _balls[i].Checkered = true; // GorgonRandom.RandomInt32(0, 100) > 50; _balls[i].Position = new Vector3((GorgonRandom.RandomSingle() * 2.0f) - 1.0f, (GorgonRandom.RandomSingle() * 2.0f) - 1.0f, GorgonRandom.RandomSingle()); } _vs = _graphics.Shaders.CreateShader <GorgonVertexShader>("TestVShader", "VS", _shader, null, true); _ps = _graphics.Shaders.CreateShader <GorgonPixelShader>("TestPShader", "PS", _shader, null, true); _layout = _graphics.Input.CreateInputLayout("Input", typeof(vertex), _vs); int vertexSize = _layout.Size; int index = 0; var indices = new int[Count * 6 * sizeof(int)]; for (int i = 0; i < indices.Length; i += 6) { indices[i] = index; indices[i + 1] = index + 1; indices[i + 2] = index + 2; indices[i + 3] = index + 1; indices[i + 4] = index + 3; indices[i + 5] = index + 2; index += 4; } _vertices = _graphics.Buffers.CreateVertexBuffer("Vertex", new GorgonBufferSettings() { SizeInBytes = 4 * vertexSize * Count, Usage = BufferUsage.Dynamic }); _index = _graphics.Buffers.CreateIndexBuffer("Index", indices, BufferUsage.Immutable); _texture = _graphics.Textures.FromFile <GorgonTexture2D>("Balls", @"..\..\..\..\Resources\BallDemo\BallDemo.png", new GorgonCodecPNG()); _texture2 = _graphics.Textures.FromFile <GorgonTexture2D>("VBBack", @"..\..\..\..\Resources\Images\VBback.jpg", new GorgonCodecJPEG()); var matrix = new MatrixBuffer(); _aspect = _swap.Settings.VideoMode.Width / (float)(_swap.Settings.VideoMode.Height); matrix.Projection = Matrix.PerspectiveFovLH(100.39f.Radians(), _aspect, 0.1f, 1000.0f); matrix.View = Matrix.LookAtLH(new Vector3(0, 0, _camPos), new Vector3(0, 0, 1.0f), Vector3.UnitY); matrix.Array = new Vector4[3]; matrix.Array[0] = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); matrix.Array[1] = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); matrix.Array[2] = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); matrix.valueType = new TEMPGUY { value2 = matrix.View, tempArray = new Vector4[3] }; _depthStateAlpha.IsDepthEnabled = false; _depthStateAlpha.IsDepthWriteEnabled = false; _graphics.Input.Layout = _layout; _graphics.Shaders.VertexShader.Current = _vs; _graphics.Shaders.PixelShader.Current = _ps; _graphics.Shaders.PixelShader.TextureSamplers.SetRange(0, new[] { GorgonTextureSamplerStates.LinearFilter, GorgonTextureSamplerStates.LinearFilter }); _graphics.Rasterizer.SetViewport(_swap.Viewport); _graphics.Output.DepthStencilState.States = _depthStateAlpha; _graphics.Output.SetRenderTarget(_swap, _swap.DepthStencilBuffer); _graphics.Input.VertexBuffers[0] = new GorgonVertexBufferBinding(_vertices, vertexSize); _graphics.Input.IndexBuffer = _index; _graphics.Shaders.PixelShader.Resources.SetRange(0, new GorgonShaderView[] { _texture, _texture2 }); _graphics.Output.BlendingState.States = GorgonBlendStates.ModulatedBlending; pvw = matrix.valueType.value2 * matrix.Projection; _tempStream = new GorgonDataStream(_sprite.Length * vertexSize); }
/// <summary> /// Function to initialize the application. /// </summary> private static void Initialize() { _form = new FormMain(); _graphics = new GorgonGraphics(); _swapChain = _graphics.Output.CreateSwapChain("Swap", new GorgonSwapChainSettings { Window = _form, IsWindowed = true, DepthStencilFormat = BufferFormat.D24_UIntNormal_S8_UInt, Format = BufferFormat.R8G8B8A8_UIntNormal }); _renderer2D = _graphics.Output.Create2DRenderer(_swapChain); _font = _graphics.Fonts.CreateFont("AppFont", new GorgonFontSettings { FontFamilyName = "Calibri", FontStyle = FontStyle.Bold, FontHeightMode = FontHeightMode.Pixels, AntiAliasingMode = FontAntiAliasMode.AntiAlias, OutlineSize = 1, OutlineColor1 = Color.Black, Size = 16.0f }); _vertexShader = _graphics.Shaders.CreateShader <GorgonVertexShader>("VertexShader", "PrimVS", Resources.Shaders); _pixelShader = _graphics.Shaders.CreateShader <GorgonPixelShader>("PixelShader", "PrimPS", Resources.Shaders); _bumpShader = _graphics.Shaders.CreateShader <GorgonPixelShader>("PixelShader", "PrimPSBump", Resources.Shaders); _waterShader = _graphics.Shaders.CreateShader <GorgonPixelShader>("PixelShader", "PrimPSWaterBump", Resources.Shaders); _normalVertexShader = _graphics.Shaders.CreateShader <GorgonVertexShader>("NormalVertexShader", "NormalVS", Resources.Shaders); _normalPixelShader = _graphics.Shaders.CreateShader <GorgonPixelShader>("NormalPixelShader", "NormalPS", Resources.Shaders); _vertexLayout = _graphics.Input.CreateInputLayout("Vertex3D", typeof(Vertex3D), _vertexShader); _normalVertexLayout = _graphics.Input.CreateInputLayout("NormalVertex", new[] { new GorgonInputElement("SV_POSITION", BufferFormat.R32G32B32A32_Float, 0, 0, 0, false, 0), }, _normalVertexShader); _graphics.Shaders.VertexShader.Current = _vertexShader; _graphics.Shaders.PixelShader.Current = _pixelShader; _graphics.Input.Layout = _vertexLayout; _graphics.Input.PrimitiveType = PrimitiveType.TriangleList; _texture = _graphics.Textures.CreateTexture <GorgonTexture2D>("UVTexture", Resources.UV); _earf = _graphics.Textures.CreateTexture <GorgonTexture2D>("Earf", Resources.earthmap1k); _normalMap = _graphics.Textures.FromMemory <GorgonTexture2D>("RainNRM", Resources.Rain_Height_NRM, new GorgonCodecDDS()); _normalEarfMap = _graphics.Textures.FromMemory <GorgonTexture2D>("EarfNRM", Resources.earthbump1k_NRM, new GorgonCodecDDS()); _specMap = _graphics.Textures.FromMemory <GorgonTexture2D>("RainSPC", Resources.Rain_Height_SPEC, new GorgonCodecDDS()); _specEarfMap = _graphics.Textures.CreateTexture <GorgonTexture2D>("EarfSPC", Resources.earthspec1k); _cloudMap = _graphics.Textures.CreateTexture <GorgonTexture2D>("EarfClouds", Resources.earthcloudmap); _gorgNrm = _graphics.Textures.CreateTexture <GorgonTexture2D>("EarfClouds", Resources.normalmap); var depth = new GorgonDepthStencilStates { DepthComparison = ComparisonOperator.LessEqual, IsDepthEnabled = true, IsDepthWriteEnabled = true }; _graphics.Output.DepthStencilState.States = depth; _graphics.Output.SetRenderTarget(_swapChain, _swapChain.DepthStencilBuffer); _graphics.Rasterizer.States = GorgonRasterizerStates.CullBackFace; _graphics.Rasterizer.SetViewport(new GorgonViewport(0, 0, _form.ClientSize.Width, _form.ClientSize.Height, 0, 1.0f)); _graphics.Shaders.PixelShader.TextureSamplers[0] = GorgonTextureSamplerStates.LinearFilter; _wvp = new WorldViewProjection(_graphics); _wvp.UpdateProjection(75.0f, _form.ClientSize.Width, _form.ClientSize.Height); // When we resize, update the projection and viewport to match our client size. _form.Resize += (sender, args) => { _graphics.Rasterizer.SetViewport(new GorgonViewport(0, 0, _form.ClientSize.Width, _form.ClientSize.Height, 0, 1.0f)); _wvp.UpdateProjection(75.0f, _form.ClientSize.Width, _form.ClientSize.Height); }; var fnU = new Vector3(0.5f, 1.0f, 0); var fnV = new Vector3(1.0f, 1.0f, 0); Vector3 faceNormal; Vector3.Cross(ref fnU, ref fnV, out faceNormal); faceNormal.Normalize(); _triangle = new Triangle(_graphics, new Vertex3D { Position = new Vector4(-12.5f, -1.5f, 12.5f, 1), Normal = faceNormal, UV = new Vector2(0, 1.0f) }, new Vertex3D { Position = new Vector4(0, 24.5f, 12.5f, 1), Normal = faceNormal, UV = new Vector2(0.5f, 0.0f) }, new Vertex3D { Position = new Vector4(12.5f, -1.5f, 12.5f, 1), Normal = faceNormal, UV = new Vector2(1.0f, 1.0f) }) { Texture = _texture, Position = new Vector3(0, 0, 1.0f) }; _plane = new Plane(_graphics, new Vector2(25.0f, 25.0f), new RectangleF(0, 0, 1.0f, 1.0f), new Vector3(90, 0, 0), 32, 32) { Position = new Vector3(0, -1.5f, 1.0f), Texture = _texture }; _cube = new Cube(_graphics, new Vector3(1, 1, 1), new RectangleF(0, 0, 1.0f, 1.0f), new Vector3(45.0f, 0, 0), 1, 1) { Position = new Vector3(0, 0, 1.5f), Texture = _texture }; _sphere = new Sphere(_graphics, 1.0f, new RectangleF(0.0f, 0.0f, 1.0f, 1.0f), Vector3.Zero, 64, 64) { Position = new Vector3(-2.0f, 1.0f, 0.75f), Texture = _earf }; _clouds = new Sphere(_graphics, 5.175f, new RectangleF(0.0f, 0.0f, 1.0f, 1.0f), Vector3.Zero, 16, 16) { Position = new Vector3(10, 2, 9.5f), Texture = _cloudMap }; _icoSphere = new IcoSphere(_graphics, 5.0f, new RectangleF(0, 0, 1, 1), Vector3.Zero, 3) { Rotation = new Vector3(0, -45.0f, 0), Position = new Vector3(10, 2, 9.5f), Texture = _earf }; _graphics.Shaders.PixelShader.TextureSamplers[0] = new GorgonTextureSamplerStates { TextureFilter = TextureFilter.Linear, HorizontalAddressing = TextureAddressing.Wrap, VerticalAddressing = TextureAddressing.Wrap, DepthAddressing = TextureAddressing.Wrap, ComparisonFunction = ComparisonOperator.Always }; _graphics.Shaders.PixelShader.TextureSamplers[2] = new GorgonTextureSamplerStates { TextureFilter = TextureFilter.Linear, HorizontalAddressing = TextureAddressing.Wrap, VerticalAddressing = TextureAddressing.Wrap, DepthAddressing = TextureAddressing.Wrap, ComparisonFunction = ComparisonOperator.Always }; _graphics.Shaders.PixelShader.TextureSamplers[1] = new GorgonTextureSamplerStates { TextureFilter = TextureFilter.Linear, HorizontalAddressing = TextureAddressing.Wrap, VerticalAddressing = TextureAddressing.Wrap, DepthAddressing = TextureAddressing.Wrap, ComparisonFunction = ComparisonOperator.Always }; _material = new Material { UVOffset = Vector2.Zero, SpecularPower = 1.0f }; _materialBuffer = _graphics.Buffers.CreateConstantBuffer("uvOffset", ref _material, BufferUsage.Default); _graphics.Shaders.PixelShader.ConstantBuffers[2] = _materialBuffer; _light = new Light(_graphics); var lightPosition = new Vector3(1.0f, 1.0f, -1.0f); _light.UpdateLightPosition(ref lightPosition, 0); GorgonColor color = GorgonColor.White; _light.UpdateSpecular(ref color, 256.0f, 0); lightPosition = new Vector3(-5.0f, 5.0f, 8.0f); _light.UpdateLightPosition(ref lightPosition, 1); color = Color.Yellow; _light.UpdateColor(ref color, 1); _light.UpdateSpecular(ref color, 2048.0f, 1); _light.UpdateAttenuation(10.0f, 1); lightPosition = new Vector3(5.0f, 3.0f, 10.0f); _light.UpdateLightPosition(ref lightPosition, 2); color = Color.Red; _light.UpdateColor(ref color, 2); _light.UpdateAttenuation(16.0f, 2); var eye = Vector3.Zero; var lookAt = Vector3.UnitZ; var up = Vector3.UnitY; _wvp.UpdateViewMatrix(ref eye, ref lookAt, ref up); _cameraRotation = Vector2.Zero; Gorgon.PlugIns.LoadPlugInAssembly(Application.StartupPath + @"\Gorgon.Input.Raw.dll"); _input = GorgonInputFactory.CreateInputFactory("GorgonLibrary.Input.GorgonRawPlugIn"); _keyboard = _input.CreateKeyboard(_form); _mouse = _input.CreatePointingDevice(_form); _keyboard.KeyDown += (sender, args) => { if (args.Key == KeyboardKeys.L) { _lock = !_lock; } }; _mouse.PointingDeviceDown += Mouse_Down; _mouse.PointingDeviceUp += Mouse_Up; _mouse.PointingDeviceWheelMove += (sender, args) => { if (args.WheelDelta < 0) { _sensitivity -= 0.05f; if (_sensitivity < 0.05f) { _sensitivity = 0.05f; } } else if (args.WheelDelta > 0) { _sensitivity += 0.05f; if (_sensitivity > 2.0f) { _sensitivity = 2.0f; } } }; _mouse.PointingDeviceMove += (sender, args) => { if (!_mouse.Exclusive) { return; } var delta = args.RelativePosition; _cameraRotation.Y += delta.Y * _sensitivity; //((360.0f * 0.002f) * delta.Y.Sign()); _cameraRotation.X += delta.X * _sensitivity; //((360.0f * 0.002f) * delta.X.Sign()); _mouseStart = _mouse.Position; _mouse.RelativePosition = PointF.Empty; }; }
/// <summary> /// Initializes a new instance of the <see cref="Sphere" /> class. /// </summary> /// <param name="graphics">The graphics interface used to create the buffers for this object.</param> /// <param name="inputLayout">The input layout for the vertices in this mesh.</param> /// <param name="radius">Radius of the sphere</param> /// <param name="textureOffset">Offset of the texture.</param> /// <param name="textureScale">Scale of the texture.</param> /// <param name="ringCount">Number of rings in the sphere.</param> /// <param name="segmentCount">Number of segments in the sphere.</param> public Sphere(GorgonGraphics graphics, GorgonInputLayout inputLayout, float radius, DX.Vector2 textureOffset, DX.Size2F textureScale, int ringCount = 8, int segmentCount = 16) : base(inputLayout) { ushort index = 0; // Current index. int vertexIndex = 0; // Current vertex index. int indexIndex = 0; // Current index array index. float deltaRingAngle = ((float)System.Math.PI) / ringCount; float deltaSegAngle = (((float)System.Math.PI) * 2.0f) / segmentCount; // Calculate number of vertices and indices required for our sphere. int vertexCount = (ringCount + 1) * (segmentCount + 1); int indexCount = 6 * ringCount * (segmentCount + 1); Vertices = new BoingerVertex[vertexCount]; Indices = new ushort[indexCount]; Radius = radius; // Build our sphere. for (int ring = 0; ring <= ringCount; ring++) { float angle = deltaRingAngle * ring; float ringSin = angle.Sin(); var position = new DX.Vector3(0, angle.Cos() * radius, 0); for (int segment = 0; segment <= segmentCount; segment++) { var textureDelta = new DX.Vector2(1.0f - (segment / (float)segmentCount), 1.0f - (ring / (float)ringCount)); float segmentAngle = deltaSegAngle * segment; position.X = ringSin * segmentAngle.Sin() * radius; position.Z = ringSin * segmentAngle.Cos() * radius; // Create the vertex. textureDelta.X *= textureScale.Width; textureDelta.Y *= textureScale.Height; textureDelta.X += textureOffset.X; textureDelta.Y += textureOffset.Y; Vertices[vertexIndex++] = new BoingerVertex( position, textureDelta ); // Add the indices and skip the last ring. if (ring == ringCount) { continue; } Indices[indexIndex++] = (ushort)(index + segmentCount + 1); Indices[indexIndex++] = index; Indices[indexIndex++] = (ushort)(index + segmentCount); Indices[indexIndex++] = (ushort)(index + segmentCount + 1); Indices[indexIndex++] = (ushort)(index + 1); Indices[indexIndex++] = index; index++; } } // Copy the above vertex/index data into a vertex and index buffer so we can render our sphere. using (var indexPtr = GorgonNativeBuffer <ushort> .Pin(Indices)) using (var vertexPtr = GorgonNativeBuffer <BoingerVertex> .Pin(Vertices)) { VertexBufferBindings[0] = GorgonVertexBufferBinding.CreateVertexBuffer(graphics, new GorgonVertexBufferInfo("Sphere Vertex Buffer") { SizeInBytes = Vertices.Length * BoingerVertex.Size, Usage = ResourceUsage.Immutable }, vertexPtr); IndexBuffer = new GorgonIndexBuffer(graphics, new GorgonIndexBufferInfo("Sphere Index Buffer") { Usage = ResourceUsage.Immutable, IndexCount = Indices.Length }, indexPtr); } }
/// <summary> /// Function used to build the resources required by the volume renderer. /// </summary> public void CreateResources() { _cubeVs = GorgonShaderFactory.Compile <GorgonVertexShader>(_graphics, Resources.VolumeRenderShaders, "VolumeVS", true); _cubePosShader = GorgonShaderFactory.Compile <GorgonPixelShader>(_graphics, Resources.VolumeRenderShaders, "VolumePositionPS", true); _cubeDirShader = GorgonShaderFactory.Compile <GorgonPixelShader>(_graphics, Resources.VolumeRenderShaders, "VolumeRayCastPS", true); _inputLayout = GorgonInputLayout.CreateUsingType <CubeVertex>(_graphics, _cubeVs); _cube = new Cube(_graphics, _inputLayout); _cubeTransform = new GorgonConstantBuffer(_graphics, new GorgonConstantBufferInfo { SizeInBytes = DX.Matrix.SizeInBytes }); _volumeRayParams = new GorgonConstantBuffer(_graphics, new GorgonConstantBufferInfo { SizeInBytes = Unsafe.SizeOf <VolumeRayParameters>() }); _volumeScaleFactor = new GorgonConstantBuffer(_graphics, new GorgonConstantBufferInfo { SizeInBytes = DX.Vector4.SizeInBytes }); // Our camera is never changing, so we only need to define it here. DX.Matrix.Translation(0, 0, 1.5f, out _view); ResizeRenderRegion(); UpdateCubeTransform(); var pipelineBuilder = new GorgonPipelineStateBuilder(_graphics); var drawBuilder = new GorgonDrawIndexCallBuilder(); pipelineBuilder .PixelShader(_cubePosShader) .VertexShader(_cubeVs); // Position draw calls. _cubePosDrawCull = drawBuilder .ConstantBuffer(ShaderType.Vertex, _cubeTransform.GetView()) .ConstantBuffer(ShaderType.Vertex, _volumeScaleFactor.GetView(), 1) .PipelineState(pipelineBuilder) .IndexBuffer(_cube.IndexBuffer, indexCount: _cube.IndexBuffer.IndexCount) .VertexBuffer(_inputLayout, _cube.VertexBuffer[0]) .Build(); pipelineBuilder .RasterState(GorgonRasterState.CullFrontFace); _cubePosDrawFrontCull = drawBuilder .PipelineState(pipelineBuilder) .Build(); // Raycasting draw call. pipelineBuilder .PixelShader(_cubeDirShader) .RasterState(GorgonRasterState.Default); _cubeDirDrawCall = drawBuilder .ConstantBuffer(ShaderType.Pixel, _volumeRayParams.GetView(), 0) .PipelineState(pipelineBuilder) .Build(); }
/// <summary> /// Function to initialize the application. /// </summary> /// <returns>The main window.</returns> private static FormMain Initialize() { // Create our form and center on the primary monitor. FormMain window = GorgonExample.Initialize(new DX.Size2(1280, 800), "Gorgon MiniTri"); try { // First we create and enumerate the list of video devices installed in the computer. // We must do this in order to tell Gorgon which video device we intend to use. Note that this method may be quite slow (particularly when running DEBUG versions of // Direct 3D). To counter this, this object and its Enumerate method are thread safe so this can be run in the background while keeping the main UI responsive. // Find out which devices we have installed in the system. // If no suitable device was found (no Direct 3D 12.0 support) in the computer, this method will throw an exception. However, if it succeeds, then the devices object // will be populated with the IGorgonVideoDeviceInfo for each video device in the system. // // Using this method, we could also enumerate the software rasterizer. These devices are typically used to determine if there's a driver error, and can be terribly slow to render // It is recommended that these only be used in diagnostic scenarios only. IReadOnlyList <IGorgonVideoAdapterInfo> deviceList = GorgonGraphics.EnumerateAdapters(); if (deviceList.Count == 0) { throw new NotSupportedException("There are no suitable video adapters available in the system. This example is unable to continue and will now exit."); } // Now we create the main graphics interface with the first applicable video device. _graphics = new GorgonGraphics(deviceList[0]); // Check to ensure that we can support the format required for our swap chain. // If a video device can't support this format, then the odds are good it won't render anything. Since we're asking for a very common display format, this will // succeed nearly 100% of the time (unless you've somehow gotten an ancient video device to work with Direct 3D 11.1). Regardless, it's good form to the check for a // working display format prior to setting up the swap chain. // // This method is also used to determine if a format can be used for other objects (e.g. a texture, render target, etc...) Like the swap chain format, this is also a // best practice to check if the object you're creating supports the desired format. if ((_graphics.FormatSupport[BufferFormat.R8G8B8A8_UNorm].FormatSupport & BufferFormatSupport.Display) != BufferFormatSupport.Display) { // We should never see this unless you've performed some form of black magic. GorgonDialogs.ErrorBox(window, "We should not see this error."); return(window); } // Finally, create a swap chain to display our output. // In this case we're setting up our swap chain to bind with our main window, and we use its client size to determine the width/height of the swap chain back buffers. // This width/height does not need to be the same size as the window, but, except for some scenarios, that would produce undesirable image quality. _swap = new GorgonSwapChain(_graphics, window, new GorgonSwapChainInfo("Main Swap Chain") { Format = BufferFormat.R8G8B8A8_UNorm, Width = window.ClientSize.Width, Height = window.ClientSize.Height }) { DoNotAutoResizeBackBuffer = true }; // Create the shaders used to render the triangle. // These shaders provide transformation and coloring for the output pixel data. CreateShaders(); // Set up our input layout. // // We'll be using this to describe to Direct 3D how the elements of a vertex is laid out in memory. // In order to provide synchronization between the layout on the CPU side and the GPU side, we have to pass the vertex shader because it will contain the vertex // layout to match with our C# input layout. _inputLayout = GorgonInputLayout.CreateUsingType <MiniTriVertex>(_graphics, _vertexShader); // Set up the triangle vertices. CreateVertexBuffer(); // Set up the constant buffer. // // This is used (but could be used for more) to transform the vertex data from 3D space into 2D space. CreateConstantBuffer(window); // This defines where to send the pixel data when rendering. For now, this goes to our swap chain. _graphics.SetRenderTarget(_swap.RenderTargetView); // Create our draw call. // // This will pass all the necessary information to the GPU to render the triangle // // Since draw calls are immutable objects, we use builders to create them (and any pipeline state). Once a draw // call is built, it cannot be changed (except for the vertex, and if applicable, index, and instance ranges). // // Builders work on a fluent interface. Much like LINQ and can be used to create multiple draw calls from the same // builder. var drawCallBuilder = new GorgonDrawCallBuilder(); var pipelineStateBuilder = new GorgonPipelineStateBuilder(_graphics); _drawCall = drawCallBuilder.VertexBuffer(_inputLayout, _vertexBuffer) .VertexRange(0, 3) .ConstantBuffer(ShaderType.Vertex, _constantBuffer) .PipelineState(pipelineStateBuilder .PixelShader(_pixelShader) .VertexShader(_vertexShader) .RasterState(GorgonRasterState.NoCulling)) .Build(); GorgonExample.LoadResources(_graphics); return(window); } finally { GorgonExample.EndInit(); } }
/// <summary> /// Initializes a new instance of the <see cref="Cube"/> class. /// </summary> /// <param name="graphics">The graphics object used to create the buffers needed by this object.</param> /// <param name="inputLayout">The input layout describing how a vertex is laid out.</param> public Cube(GorgonGraphics graphics, GorgonInputLayout inputLayout) { GlassCubeVertex[] vertices = { // Front face. new GlassCubeVertex(new DX.Vector3(-0.5f, 0.5f, -0.5f), new DX.Vector2(0, 0)), new GlassCubeVertex(new DX.Vector3(0.5f, -0.5f, -0.5f), new DX.Vector2(1.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(-0.5f, -0.5f, -0.5f), new DX.Vector2(0.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(0.5f, 0.5f, -0.5f), new DX.Vector2(1.0f, 0.0f)), // Right face. new GlassCubeVertex(new DX.Vector3(0.5f, 0.5f, -0.5f), new DX.Vector2(0, 0)), new GlassCubeVertex(new DX.Vector3(0.5f, -0.5f, 0.5f), new DX.Vector2(1.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(0.5f, -0.5f, -0.5f), new DX.Vector2(0.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(0.5f, 0.5f, 0.5f), new DX.Vector2(1.0f, 0.0f)), // Back face. new GlassCubeVertex(new DX.Vector3(0.5f, 0.5f, 0.5f), new DX.Vector2(0, 0)), new GlassCubeVertex(new DX.Vector3(-0.5f, -0.5f, 0.5f), new DX.Vector2(1.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(0.5f, -0.5f, 0.5f), new DX.Vector2(0.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(-0.5f, 0.5f, 0.5f), new DX.Vector2(1.0f, 0.0f)), // Left face. new GlassCubeVertex(new DX.Vector3(-0.5f, 0.5f, 0.5f), new DX.Vector2(0, 0)), new GlassCubeVertex(new DX.Vector3(-0.5f, -0.5f, -0.5f), new DX.Vector2(1.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(-0.5f, -0.5f, 0.5f), new DX.Vector2(0.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(-0.5f, 0.5f, -0.5f), new DX.Vector2(1.0f, 0.0f)), // Top face. new GlassCubeVertex(new DX.Vector3(-0.5f, 0.5f, 0.5f), new DX.Vector2(0, 0)), new GlassCubeVertex(new DX.Vector3(0.5f, 0.5f, -0.5f), new DX.Vector2(1.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(-0.5f, 0.5f, -0.5f), new DX.Vector2(0.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(0.5f, 0.5f, 0.5f), new DX.Vector2(1.0f, 0.0f)), // Bottom face. new GlassCubeVertex(new DX.Vector3(-0.5f, -0.5f, -0.5f), new DX.Vector2(0, 0)), new GlassCubeVertex(new DX.Vector3(0.5f, -0.5f, 0.5f), new DX.Vector2(1.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(-0.5f, -0.5f, 0.5f), new DX.Vector2(0.0f, 1.0f)), new GlassCubeVertex(new DX.Vector3(0.5f, -0.5f, -0.5f), new DX.Vector2(1.0f, 0.0f)) }; ushort[] indices = { 8, 9, 10, 8, 11, 9, 12, 13, 14, 12, 15, 13, 4, 5, 6, 4, 7, 5, 16, 17, 18, 16, 19, 17, 20, 21, 22, 20, 23, 21, 0, 1, 2, 0, 3, 1 }; // Create our index buffer and vertex buffer and populate with our cube data. using (var indexPtr = GorgonNativeBuffer <ushort> .Pin(indices)) using (var vertexPtr = GorgonNativeBuffer <GlassCubeVertex> .Pin(vertices)) { IndexBuffer = new GorgonIndexBuffer(graphics, new GorgonIndexBufferInfo("GlassCube Index Buffer") { Usage = ResourceUsage.Immutable, IndexCount = indices.Length, Use16BitIndices = true }, indexPtr); VertexBuffer = new GorgonVertexBufferBindings(inputLayout) { [0] = GorgonVertexBufferBinding.CreateVertexBuffer(graphics, vertices.Length, ResourceUsage.Immutable, initialData: vertexPtr, bufferName: "GlassCube Vertex Buffer") }; } }