internal static void AddAttributeDescriptions( int binding, ResizeArray <VertexInputAttributeDescription> attributes) { //Float4x4 matrix takes 4 'locations' and needs to be bound as 4 separate float4's attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32B32A32SFloat, //float4 offset: 0)); //In bytes from the beginning of the struct attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32B32A32SFloat, //float4 offset: Float4.SIZE)); //In bytes from the beginning of the struct attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32B32A32SFloat, //float4 offset: Float4.SIZE * 2)); //In bytes from the beginning of the struct attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32B32A32SFloat, //float4 offset: Float4.SIZE * 3)); //In bytes from the beginning of the struct //Age attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32SFloat, //float offset: Float4x4.SIZE)); }
internal Chunk( Device logicalDevice, HostDevice hostDevice, Location location, int supportedMemoryTypesFilter, long size = 128 *ByteUtils.MEGABYTE_TO_BYTE) { if (logicalDevice == null) { throw new ArgumentNullException(nameof(logicalDevice)); } if (hostDevice == null) { throw new ArgumentNullException(nameof(hostDevice)); } this.logicalDevice = logicalDevice; this.location = location; totalSize = size; //Add a block the size of the entire chunk to the free set freeBlocks.Add(new Block(container: this, offset: 0, size: size)); //Find the memory type on the gpu to place this pool in memoryTypeIndex = hostDevice.GetMemoryType( properties: location == Location.Device ? MemoryProperties.DeviceLocal : MemoryProperties.HostVisible, supportedTypesFilter: supportedMemoryTypesFilter); //Allocate the memory memory = logicalDevice.AllocateMemory(new MemoryAllocateInfo( allocationSize: size, memoryTypeIndex: memoryTypeIndex)); }
internal static void AddAttributeDescriptions( int binding, ResizeArray <VertexInputAttributeDescription> attributes) { int offset = 0; for (int i = 0; i < 5; i++) { switch (i) { case 0: //Position attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32B32SFloat, //float3 offset: offset)); //In bytes from the beginning of the struct offset += Float3.SIZE; break; case 1: //Color attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32B32A32SFloat, //float4 offset: offset)); //In bytes from the beginning of the struct offset += Float4.SIZE; break; case 2: //Normal attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32B32SFloat, //float3 offset: offset)); //In bytes from the beginning of the struct offset += Float3.SIZE; break; case 3: //Uv1 attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32SFloat, //float2 offset: offset)); //In bytes from the beginning of the struct offset += Float2.SIZE; break; case 4: //Uv2 attributes.Add(new VertexInputAttributeDescription( location: attributes.Count, binding: binding, format: Format.R32G32SFloat, //float2 offset: offset)); //In bytes from the beginning of the struct offset += Float2.SIZE; break; } } }
private void ParseFloatSetArray <T>(XmlElement element, ResizeArray <T> output) where T : struct, IFloatSet { output.Clear(); //Get meta data XmlElement accessorElement = element.GetChild("technique_common")?.GetChild("accessor"); if (accessorElement == null) { throw new Exception($"[{nameof(ColladaParser)}] 'accessor' element"); } int count = int.Parse(accessorElement.Tag.GetAttributeValue("count")); int stride = int.Parse(accessorElement.Tag.GetAttributeValue("stride")); //Get raw data XmlElement arrayElement = element.GetChild("float_array"); if (arrayElement == null) { throw new Exception($"[{nameof(ColladaParser)}] 'float_array' missing"); } XmlDataEntry?dataEntry = arrayElement.FirstData; if (dataEntry == null) { throw new Exception($"[{nameof(ColladaParser)}] Data is missing"); } int componentCount = FloatSetUtils.GetComponentCount <T>(); if (componentCount > stride) { throw new Exception( $"[{nameof(ColladaParser)}] Data has too little component for given type, expected: {componentCount}, got: {stride}"); } int dataToSkip = stride - componentCount; par.Seek(dataEntry.Value.StartBytePosition); for (int i = 0; i < count; i++) { output.Add(par.ConsumeFloatSet <T>()); //If there is extra data we don't want to load then we skip over that for (int j = 0; j < dataToSkip; j++) { par.ExpectConsume(' '); par.ConsumeFloat(); } par.ConsumeWhitespace(includeNewline: true); } if (par.CurrentBytePosition > dataEntry.Value.EndBytePosition) { throw new Exception($"[{nameof(ColladaParser)}] Data was bigger then expected"); } }
internal Chunk(Device logicalDevice, ReadOnlySpan <IShaderInput> inputs, int size = 5) { types = new DescriptorType[inputs.Length]; for (int i = 0; i < types.Length; i++) { types[i] = inputs[i].DescriptorType; } //Gather how many inputs of each type we have var poolSizes = new ResizeArray <DescriptorPoolSize>(); for (int i = 0; i < types.Length; i++) { for (int j = 0; j < poolSizes.Count; j++) { if (poolSizes.Data[j].Type == types[i]) { poolSizes.Data[j].DescriptorCount += size; continue; } } poolSizes.Add(new DescriptorPoolSize(types[i], size)); } //Create a pool for 'size' types the amount of resources of one set pool = logicalDevice.CreateDescriptorPool(new DescriptorPoolCreateInfo( maxSets: size, poolSizes: poolSizes.ToArray(), flags: DescriptorPoolCreateFlags.None)); //Create a layout that matches the inputs layout = CreateLayout(logicalDevice, inputs); //Even tho we use the same layout for the entire pool the 'VkDescriptorSetAllocateInfo' //expects a layout per allocation so we create a array of layouts all pointing to the //same layout var layouts = new DescriptorSetLayout[size]; for (int i = 0; i < layouts.Length; i++) { layouts[i] = layout; } //Pre-allocate all the sets from the pool sets = pool.AllocateSets(new DescriptorSetAllocateInfo( descriptorSetCount: size, setLayouts: layouts)); //Mark all the sets as being free isFree = new bool[size]; for (int i = 0; i < isFree.Length; i++) { isFree[i] = true; } }
public int Add <T>() where T : struct { ThrowIfDisposed(); int size = Unsafe.SizeOf <T>(); int binding = entries.Count; entries.Add(new Entry(currentSize, size)); currentSize += size; return(binding); }
public static Mesh CreatePlane(int segments, float size) { //Create the vertices Vertex[] vertices = new Vertex[segments * segments]; Float3 offset = (x : size * .5f, y : 0f, z : size * .5f); for (int z = 0; z < segments; z++) { for (int x = 0; x < segments; x++) { float xProg = (float)x / (segments - 1); float zProg = (float)z / (segments - 1); vertices[x + z * segments] = new Vertex( position: (xProg * size, 0f, zProg * size) - offset, color: Float4.One, normal: Float3.Up, uv1: new Float2(xProg, zProg), uv2: new Float2(xProg, zProg)); } } //Create the indices ResizeArray <UInt16> indices = new ResizeArray <UInt16>(); for (int z = 1; z < segments; z++) //Start at 1 because we handle 2 'rows' in one iteration { //Strip row for (int x = 0; x < segments; x++) { indices.Add((UInt16)(x + segments * z)); indices.Add((UInt16)(x + segments * (z - 1))); } //Restart strip indices.Add(Mesh.RESTART_INDEX); } return(new Mesh(vertices, indices.ToArray(), Mesh.TopologyType.TriangleStrip)); }
public void Add <T>(T data) where T : struct { ThrowIfDisposed(); int dataSize = Unsafe.SizeOf <T>(); memory.Write(data, currentSize); entries.Add(new SpecializationMapEntry( constantId: entries.Count, offset: (int)currentSize, size: new Size(dataSize))); currentSize += dataSize; }
public Mesh Parse() { if (par.Current.IsEndOfFile) { throw new Exception($"[{nameof(WavefrontObjParser)}] Stream allready at the end"); } while (!par.Current.IsEndOfFile) { par.ConsumeWhitespace(); //Ignore whitespace before the id string id = par.ConsumeWord(); par.ConsumeWhitespace(); //Ignore whitespace after the id switch (id) { case "v": positions.Add(par.ConsumeFloatSet <Float3>()); break; case "vn": normals.Add(par.ConsumeFloatSet <Float3>()); break; case "vt": texcoords.Add(par.ConsumeFloatSet <Float2>()); break; case "f": { elementCache.Clear(); while (!par.Current.IsEndOfLine) { elementCache.Add(ConsumeFaceElement()); par.ConsumeWhitespace(); } if (elementCache.Count < 3) { throw par.CreateError("At least 3 vertices are required to create a face"); } faces.Add(new Face(elementCache.ToArray())); } break; } //Ignore everything we don't know about par.ConsumeRestOfLine(); //End the token with a newline if (!par.Current.IsEndOfFile) { par.ConsumeNewline(); } } return(CreateMesh()); }
public void PushVertex(Vertex vertex) { //Filter out similar vertices to reduce vertex count int index = FindSimilar(vertex); if (index < 0) { if (vertices.Count >= UInt16.MaxValue) { throw new Exception( $"[{nameof(MeshBuilder)}] Only '{UInt16.MaxValue}' vertices are supported"); } index = vertices.Count; vertices.Add(vertex); } indices.Add((UInt16)index); }
public void Update() { if (!assigned && enter && Application.isEditor && !Application.isPlaying) { LightmapData data = new LightmapData(); // copy to folder and import the copied and assign them if (far != null) { data.lightmapColor = far; } if (near != null) { data.lightmapDir = near; } int i = 0; bool exists = false; foreach (LightmapData dt in LightmapSettings.lightmaps) { if (dt.lightmapColor == far && dt.lightmapDir == near) { this.GetComponent <Renderer>().lightmapIndex = i; exists = true; break; } i++; } if (!exists) { ResizeArray.Add(LightmapSettings.lightmaps.Length, data); this.GetComponent <Renderer>().lightmapIndex = LightmapSettings.lightmaps.Length - 1; } assigned = true; DestroyImmediate(this); } }
internal static Pipeline CreatePipeline( Device logicalDevice, RenderPass renderpass, PipelineLayout layout, ShaderModule vertModule, ShaderModule fragModule, SpecializationContainer specializationContainer, bool depthClamp, bool depthBias, ReadOnlySpan <DeviceTexture> targets, IInternalRenderObject renderObject) { if (logicalDevice == null) { throw new ArgumentNullException(nameof(logicalDevice)); } if (renderpass == null) { throw new ArgumentNullException(nameof(renderpass)); } var shaderStages = new [] { new PipelineShaderStageCreateInfo( stage: ShaderStages.Vertex, module: vertModule, name: "main", specializationInfo: specializationContainer?.GetInfo()), new PipelineShaderStageCreateInfo( stage: ShaderStages.Fragment, module: fragModule, name: "main", specializationInfo: specializationContainer?.GetInfo()) }; var depthTest = new PipelineDepthStencilStateCreateInfo { DepthTestEnable = true, DepthWriteEnable = true, DepthCompareOp = CompareOp.LessOrEqual, DepthBoundsTestEnable = false, StencilTestEnable = false }; var rasterizer = new PipelineRasterizationStateCreateInfo( depthClampEnable: depthClamp, rasterizerDiscardEnable: false, polygonMode: PolygonMode.Fill, cullMode: CullModes.Back, frontFace: renderObject.GetFrontFace(), depthBiasEnable: depthBias, depthBiasConstantFactor: .1f, depthBiasSlopeFactor: 1.75f, lineWidth: 1f ); //Gather all the color targets and setup a blend-state for them ResizeArray <PipelineColorBlendAttachmentState> blendAttachments = new ResizeArray <PipelineColorBlendAttachmentState>(); for (int i = 0; i < targets.Length; i++) { if (!targets[i].DepthTexture) { blendAttachments.Add(new PipelineColorBlendAttachmentState( colorWriteMask: ColorComponents.All, blendEnable: false)); } } var blending = new PipelineColorBlendStateCreateInfo( attachments: blendAttachments.ToArray(), logicOpEnable: false ); var multisampleState = new PipelineMultisampleStateCreateInfo( rasterizationSamples: SampleCounts.Count1, sampleShadingEnable: false ); //Pass the viewport and scissor-rect as dynamic so we are not tied to swapchain size //the advantage is this is that we don't need to recreate the pipeline on swapchain //resize var dynamicState = new PipelineDynamicStateCreateInfo( DynamicState.Viewport, DynamicState.Scissor ); return(logicalDevice.CreateGraphicsPipeline(new GraphicsPipelineCreateInfo( layout: layout, renderPass: renderpass, subpass: 0, stages: shaderStages, inputAssemblyState: renderObject.GetInputAssemblyStateInfo(), vertexInputState: renderObject.GetVertexInputState(), rasterizationState: rasterizer, tessellationState: null, //Pass empty viewport and scissor-rect as we set them dynamically viewportState: new PipelineViewportStateCreateInfo(new Viewport(), new Rect2D()), multisampleState: multisampleState, depthStencilState: depthTest, colorBlendState: blending, dynamicState: dynamicState, flags: PipelineCreateFlags.None ))); }
private void ParseTriangles(XmlElement meshElement) { XmlElement trianglesElement = meshElement.GetChild("triangles"); XmlElement polygonsElement = trianglesElement ?? meshElement.GetChild("polygons"); if (polygonsElement == null || !polygonsElement.HasChildren) { throw new Exception($"[{nameof(ColladaParser)}] Triangles / Polygons element missing"); } //Parse all the triangles data triangleCount = int.Parse(polygonsElement.Tag.GetAttributeValue("count")); for (int i = 0; i < polygonsElement.Children.Count; i++) { ParseTriangleElement(polygonsElement.Children[i]); } if (indices.Count != triangleCount * 3 * inputStride) { throw new Exception($"[{nameof(ColladaParser)}] Incorrect indices count found"); } //The triangle input can contain a VERTEX element with more data, we want to resolve //that here so we end of with just a flat list of attributes for (int i = 0; i < inputs.Count; i++) { Input input = inputs.Data[i]; if (input.Semantic == "VERTEX") { XmlElement vertexElement = meshElement.GetChildWithAttribute( name: "vertices", attributeName: "id", attributeValue: input.Source); for (int j = 0; j < vertexElement.Children.Count; j++) { XmlElement vertexInput = vertexElement.Children[j]; if (vertexInput.HasName("input")) { string semantic = vertexInput.Tag.GetAttributeValue("semantic"); string sourceReference = GetSourceReference(vertexInput); inputs.Add(new Input(semantic, input.Offset, set: -1, sourceReference)); } } } } void ParseTriangleElement(XmlElement triangleElement) { //The input elements contain info about what is in the indices if (triangleElement.HasName("input")) { string semantic = triangleElement.Tag.GetAttributeValue("semantic"); int offset = int.Parse(triangleElement.Tag.GetAttributeValue("offset")); int set = int.Parse(triangleElement.Tag.GetAttributeValue("set", "-1")); string sourceReference = GetSourceReference(triangleElement); inputStride = Max(inputStride, offset + 1); inputs.Add(new Input(semantic, offset, set, sourceReference)); } // The 'p' (primitive) element contains the actual indices if (triangleElement.HasName("p")) { XmlDataEntry?dataEntry = triangleElement.FirstData; if (dataEntry == null) { throw new Exception($"[{nameof(ColladaParser)}] Data is missing"); } //Read the indices par.Seek(dataEntry.Value.StartBytePosition); while (par.CurrentBytePosition < dataEntry.Value.EndBytePosition) { par.ConsumeWhitespace(includeNewline: true); indices.Add(par.ConsumeInt()); } } } }
private static RenderPass CreateRenderPass( Device logicalDevice, ReadOnlySpan <DeviceTexture> targets) { ResizeArray <AttachmentReference> colorReferences = new ResizeArray <AttachmentReference>(); AttachmentReference?depthReference = null; var attachmentDescriptions = new AttachmentDescription[targets.Length]; for (int i = 0; i < targets.Length; i++) { //Create the description attachmentDescriptions[i] = new AttachmentDescription( flags: AttachmentDescriptions.MayAlias, format: targets[i].Format, samples: SampleCounts.Count1, loadOp: AttachmentLoadOp.Clear, storeOp: AttachmentStoreOp.Store, stencilLoadOp: AttachmentLoadOp.DontCare, stencilStoreOp: AttachmentStoreOp.DontCare, initialLayout: ImageLayout.Undefined, finalLayout: targets[i].DesiredLayout); //Add the reference (either color or depth) if (targets[i].DepthTexture) { if (depthReference != null) { throw new Exception( $"[{nameof(Renderer)}] Only 1 depth target can be used at a time"); } else { depthReference = new AttachmentReference(i, ImageLayout.DepthStencilAttachmentOptimal); } } else { colorReferences.Add(new AttachmentReference(i, ImageLayout.ColorAttachmentOptimal)); } } //Dependency at the beginning to transition the attachments to the proper layout var beginTransitionDependency = new SubpassDependency( srcSubpass: Constant.SubpassExternal, dstSubpass: 0, //Our subpass srcStageMask: PipelineStages.BottomOfPipe, srcAccessMask: Accesses.MemoryRead, dstStageMask: PipelineStages.ColorAttachmentOutput, dstAccessMask: Accesses.ColorAttachmentWrite, dependencyFlags: Dependencies.None ); //Dependency at the end to transition the attachments to the final layout var endTransitionDependency = new SubpassDependency( srcSubpass: 0, //Our subpass dstSubpass: Constant.SubpassExternal, srcStageMask: PipelineStages.ColorAttachmentOutput, srcAccessMask: Accesses.ColorAttachmentWrite, dstStageMask: PipelineStages.BottomOfPipe, dstAccessMask: Accesses.MemoryRead, dependencyFlags: Dependencies.None ); return(logicalDevice.CreateRenderPass(new RenderPassCreateInfo( subpasses: new [] { new SubpassDescription ( flags: SubpassDescriptionFlags.None, colorAttachments: colorReferences.ToArray(), depthStencilAttachment: depthReference ) }, attachments: attachmentDescriptions, dependencies: new [] { beginTransitionDependency, endTransitionDependency } ))); }