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(); }
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); }