public MetalKitEssentialsSubmesh(MTKSubmesh mtkSubmesh, MDLSubmesh mdlSubmesh, IMTLDevice device)
        {
            materialUniforms = device.CreateBuffer((nuint)Marshal.SizeOf <MaterialUniforms> (), MTLResourceOptions.CpuCacheModeDefault);
            var uniforms = Marshal.PtrToStructure <MaterialUniforms> (materialUniforms.Contents);

            submesh = mtkSubmesh;

            for (nuint i = 0; i < mdlSubmesh.Material.Count; i++)
            {
                MDLMaterialProperty property = ObjectAtIndexedSubscript(mdlSubmesh.Material, i);

                if (property == null)
                {
                    continue;
                }

                if (property.Name == "baseColorMap")
                {
                    if (property.Type != MDLMaterialPropertyType.String)
                    {
                        continue;
                    }

                    var textureURL    = new NSUrl(string.Format("file://{0}", property.StringValue));
                    var textureLoader = new MTKTextureLoader(device);

                    NSError error;
                    diffuseTexture = textureLoader.FromUrl(textureURL, null, out error);

                    if (diffuseTexture == null)
                    {
                        throw new Exception(string.Format("Diffuse texture load: {0}", error.LocalizedDescription));
                    }
                }
                else if (property.Name == "BlinnSpecularColor")
                {
                    if (property.Type == MDLMaterialPropertyType.Float4)
                    {
                        uniforms.specularColor = property.Float4Value;
                    }
                    else if (property.Type == MDLMaterialPropertyType.Float3)
                    {
                        uniforms.specularColor = new Vector4(property.Float3Value);
                    }
                }
                else if (property.Name == "emission")
                {
                    if (property.Type == MDLMaterialPropertyType.Float4)
                    {
                        uniforms.emissiveColor = property.Float4Value;
                    }
                    else if (property.Type == MDLMaterialPropertyType.Float3)
                    {
                        uniforms.emissiveColor = new Vector4(property.Float3Value);
                    }
                }
            }

            Marshal.StructureToPtr(uniforms, materialUniforms.Contents, true);
        }
        void Render()
        {
            inflightSemaphore.WaitOne();

            Update();

            // Create a new command buffer for each renderpass to the current drawable
            IMTLCommandBuffer commandBuffer = commandQueue.CommandBuffer();

            commandBuffer.Label = "MyCommand";

            // Call the view's completion handler which is required by the view since it will signal its semaphore and set up the next buffer
            var drawable = view.CurrentDrawable;

            commandBuffer.AddCompletedHandler(buffer =>
            {
                drawable.Dispose();
                inflightSemaphore.Release();
            });

            // Obtain a renderPassDescriptor generated from the view's drawable textures
            MTLRenderPassDescriptor renderPassDescriptor = view.CurrentRenderPassDescriptor;

            // If we have a valid drawable, begin the commands to render into it
            if (renderPassDescriptor != null)
            {
                // Create a render command encoder so we can render into something
                IMTLRenderCommandEncoder renderEncoder = commandBuffer.CreateRenderCommandEncoder(renderPassDescriptor);
                renderEncoder.Label = "MyRenderEncoder";
                renderEncoder.SetDepthStencilState(depthState);

                // Set context state
                renderEncoder.PushDebugGroup("DrawCube");
                renderEncoder.SetRenderPipelineState(pipelineState);
                renderEncoder.SetVertexBuffer(boxMesh.VertexBuffers[0].Buffer, boxMesh.VertexBuffers[0].Offset, 0);
                renderEncoder.SetVertexBuffer(dynamicConstantBuffer, (nuint)Marshal.SizeOf <Uniforms>(), 1);

                MTKSubmesh submesh = boxMesh.Submeshes[0];
                // Tell the render context we want to draw our primitives
                renderEncoder.DrawIndexedPrimitives(submesh.PrimitiveType, submesh.IndexCount, submesh.IndexType, submesh.IndexBuffer.Buffer, submesh.IndexBuffer.Offset);
                renderEncoder.PopDebugGroup();

                // We're done encoding commands
                renderEncoder.EndEncoding();

                // Schedule a present once the framebuffer is complete using the current drawable
                commandBuffer.PresentDrawable(drawable);
            }

            // The render assumes it can now increment the buffer index and that the previous index won't be touched until we cycle back around to the same index
            constantDataBufferIndex = (constantDataBufferIndex + 1) % MaxInflightBuffers;

            // Finalize rendering here & push the command buffer to the GPU
            commandBuffer.Commit();
        }
Exemple #3
0
        public void Draw(MTKView view)
        {
            // Update
            var time          = clock.ElapsedMilliseconds / 1000.0f;
            var viewProj      = Matrix4.Mult(this.view, this.proj);
            var worldViewProj = Matrix4.CreateRotationY(time * 2) * Matrix4.Scale(0.0015f) * viewProj;

            worldViewProj = Matrix4.Transpose(worldViewProj);
            this.param.WorldViewProjection = worldViewProj;
            SetConstantBuffer(this.param, constantBuffer);

            // Create a new command buffer for each renderpass to the current drawable
            IMTLCommandBuffer commandBuffer = commandQueue.CommandBuffer();

            // Call the view's completion handler which is required by the view since it will signal its semaphore and set up the next buffer
            var drawable = view.CurrentDrawable;

            // Obtain a renderPassDescriptor generated from the view's drawable textures
            MTLRenderPassDescriptor renderPassDescriptor = view.CurrentRenderPassDescriptor;

            // If we have a valid drawable, begin the commands to render into it
            if (renderPassDescriptor != null)
            {
                // Create a render command encoder so we can render into something
                IMTLRenderCommandEncoder renderEncoder = commandBuffer.CreateRenderCommandEncoder(renderPassDescriptor);

                // Set context state
                renderEncoder.SetDepthStencilState(depthState);
                renderEncoder.SetRenderPipelineState(pipelineState);
                renderEncoder.SetVertexBuffer(objMesh.VertexBuffers[0].Buffer, objMesh.VertexBuffers[0].Offset, 0);
                renderEncoder.SetVertexBuffer(constantBuffer, (nuint)Marshal.SizeOf <Matrix4>(), 1);
                renderEncoder.SetFragmentTexture(this.texture, 0);
                renderEncoder.SetFragmentSamplerState(this.sampler, 0);

                for (int i = 0; i < objMesh.Submeshes.Length; i++)
                {
                    MTKSubmesh submesh = objMesh.Submeshes[i];
                    renderEncoder.DrawIndexedPrimitives(submesh.PrimitiveType, submesh.IndexCount, submesh.IndexType, submesh.IndexBuffer.Buffer, submesh.IndexBuffer.Offset);
                }

                // We're done encoding commands
                renderEncoder.EndEncoding();

                // Schedule a present once the framebuffer is complete using the current drawable
                commandBuffer.PresentDrawable(drawable);
            }

            // Finalize rendering here & push the command buffer to the GPU
            commandBuffer.Commit();
        }
        public MetalKitEssentialsSubmesh(MTKSubmesh mtkSubmesh, MDLSubmesh mdlSubmesh, IMTLDevice device)
        {
            materialUniforms = device.CreateBuffer ((nuint)Marshal.SizeOf <MaterialUniforms> (), MTLResourceOptions.CpuCacheModeDefault);
            var uniforms = Marshal.PtrToStructure <MaterialUniforms> (materialUniforms.Contents);
            submesh = mtkSubmesh;

            for (nuint i = 0; i < mdlSubmesh.Material.Count; i++) {
                MDLMaterialProperty property = ObjectAtIndexedSubscript (mdlSubmesh.Material, i);

                if (property == null)
                    continue;

                if (property.Name == "baseColorMap") {

                    if (property.Type != MDLMaterialPropertyType.String)
                        continue;

                    var textureURL = new NSUrl (string.Format ("file://{0}", property.StringValue));
                    var textureLoader = new MTKTextureLoader (device);

                    NSError error;
                    diffuseTexture = textureLoader.FromUrl (textureURL, null, out error);

                    if (diffuseTexture == null)
                        throw new Exception (string.Format ("Diffuse texture load: {0}", error.LocalizedDescription));
                } else if (property.Name == "BlinnSpecularColor") {
                    if (property.Type == MDLMaterialPropertyType.Float4)
                        uniforms.specularColor = property.Float4Value;
                    else if (property.Type == MDLMaterialPropertyType.Float3)
                        uniforms.specularColor = new Vector4 (property.Float3Value);
                } else if (property.Name == "emission") {
                    if(property.Type == MDLMaterialPropertyType.Float4)
                        uniforms.emissiveColor = property.Float4Value;
                    else if (property.Type == MDLMaterialPropertyType.Float3)
                        uniforms.emissiveColor = new Vector4 (property.Float3Value);
                }
            }

            Marshal.StructureToPtr (uniforms, materialUniforms.Contents, true);
        }