public WavefrontObj(Stream stream) { Obj? obj = null; Span <char> buffer = stackalloc char[1024]; using var reader = new StreamReader(stream); var remaining = buffer.Slice(0, reader.Read(buffer)); var eof = false; while (remaining.Length > 0) { var index = 0; while ((index = remaining.IndexOf('\n')) >= 0 || (remaining.Length > 0 && eof)) { if (index <= 0) { index = remaining.Length; } var line = remaining.Slice(0, index); remaining = remaining.Slice(Math.Min(remaining.Length, index + 1)); while (line.Length > 0 && char.IsWhiteSpace(line[0])) { line = line.Slice(1); } while (line.Length > 0 && char.IsWhiteSpace(line[line.Length - 1])) { line = line.Slice(0, line.Length - 1); } if (line.Length <= 0) { continue; } // obj if (line[0] == 'o' && line.Length > 3) { obj = new Obj(line.Slice(2).ToString()); Objects.Add(obj.Name, obj); } else if (line[0] == 'v' && line.Length > 3) { // normal if (line[1] == 'n') { if (Calc.ParseVector3(line.Slice(3), ' ', out var normal)) { Normals.Add(normal); } } // tex-coord else if (line[1] == 't') { if (Calc.ParseVector2(line.Slice(3), ' ', out var texcoord)) { Texcoords.Add(texcoord); } } // position else { if (Calc.ParseVector3(line.Slice(2), ' ', out var position)) { Positions.Add(position); } } } else if (line[0] == 'f' && line.Length > 3) { if (obj == null) { obj = new Obj("Unnamed"); Objects.Add(obj.Name, obj); } var face = new Face { VertexIndex = obj.Vertices.Count }; var data = line.Slice(2); var next = data; while ((next = NextSplit(ref data, ' ')).Length > 0) { var vertex = new Vertex(); var i = 0; while (next.Length > 0) { var sub = NextSplit(ref next, '/'); if (sub.Length > 0) { if (i == 0) { vertex.PositionIndex = int.Parse(sub) - 1; } else if (i == 1) { vertex.NormalIndex = int.Parse(sub) - 1; } else if (i == 2) { vertex.TexcoordIndex = int.Parse(sub) - 1; } } i++; } obj.Vertices.Add(vertex); face.VertexCount++; } obj.Faces.Add(face); } } // shift memory back & read more remaining.CopyTo(buffer); var offset = buffer.Slice(remaining.Length); var read = reader.Read(offset); // how much is left to read remaining = buffer.Slice(0, remaining.Length + read); // reached the end if (read < offset.Length) { eof = true; } } }
protected override void CreateGeometry() { base.CreateGeometry(); if (!GenerateGeometry) { return; } //create buffer descriptions var vDesc = new BufferDesc() { Width = (uint)Positions.Count, Format = Format.Float3, Type = BufferType.Input }; var nDesc = new BufferDesc() { Width = (uint)Normals.Count, Format = Format.Float3, Type = BufferType.Input }; var tcDesc = new BufferDesc() { Width = (uint)Texcoords.Count, Format = Format.Float2, Type = BufferType.Input }; // Create the buffers to hold our geometry data var vBuffer = new OptixBuffer(Context, vDesc); var nBuffer = new OptixBuffer(Context, nDesc); var tcBuffer = new OptixBuffer(Context, tcDesc); vBuffer.SetData <Vector3>(Positions.ToArray()); nBuffer.SetData <Vector3>(Normals.ToArray()); tcBuffer.SetData <Vector2>(Texcoords.ToArray()); List <GeometryInstance> instances = new List <GeometryInstance>(); foreach (ObjGroup group in Groups) { //empty group if (group.VIndices.Count == 0 && group.NIndices.Count == 0 && group.TIndices.Count == 0) { continue; } //ValidateGroup( group ); var normalsUseVIndices = GenerateNormals && group.NIndices.Count == 0 && Normals.Count > 0; if (normalsUseVIndices) { Debug.Assert(Normals.Count == Positions.Count); } var numNormIndices = normalsUseVIndices ? group.VIndices.Count : group.NIndices.Count; var viDesc = new BufferDesc { Width = (uint)group.VIndices.Count, Format = Format.Int3, Type = BufferType.Input }; var niDesc = new BufferDesc { Width = (uint)numNormIndices, Format = Format.Int3, Type = BufferType.Input }; var tiDesc = new BufferDesc { Width = (uint)group.TIndices.Count, Format = Format.Int3, Type = BufferType.Input }; var viBuffer = new OptixBuffer(Context, viDesc); var niBuffer = new OptixBuffer(Context, niDesc); var tiBuffer = new OptixBuffer(Context, tiDesc); viBuffer.SetData(group.VIndices.ToArray()); //if normals weren't in the obj and we genereated them, use the vertex indices niBuffer.SetData(normalsUseVIndices ? group.VIndices.ToArray() : group.NIndices.ToArray()); tiBuffer.SetData(group.TIndices.ToArray()); //create a geometry node and set the buffers var geometry = new Geometry(Context); geometry.IntersectionProgram = new OptixProgram(Context, IntersecitonProgPath, IntersecitonProgName); geometry.BoundingBoxProgram = new OptixProgram(Context, BoundingBoxProgPath, BoundingBoxProgName); geometry.PrimitiveCount = (uint)group.VIndices.Count; geometry["vertex_buffer"].Set(vBuffer); geometry["normal_buffer"].Set(nBuffer); geometry["texcoord_buffer"].Set(tcBuffer); geometry["vindex_buffer"].Set(viBuffer); geometry["nindex_buffer"].Set(niBuffer); geometry["tindex_buffer"].Set(tiBuffer); //create a geometry instance GeometryInstance instance = new GeometryInstance(Context); instance.Geometry = geometry; instance.AddMaterial(_materialResolveFunc(group.mtrl) ?? DefaultMaterial); if (group.mtrl != null) { ObjMaterial mtrl = mMtrls[group.mtrl]; instance["diffuse_color"].SetFloat3(ref mtrl.Kd); instance["emission_color"].SetFloat3(ref mtrl.Ke); } else { instance["diffuse_color"].Set(1.0f, 1.0f, 1.0f); } instances.Add(instance); } //create an acceleration structure for the geometry var accel = new Acceleration(Context, Builder, Traverser); if (Builder == AccelBuilder.Sbvh || Builder == AccelBuilder.TriangleKdTree) { accel.VertexBufferName = "vertex_buffer"; accel.IndexBufferName = "vindex_buffer"; } //now attach the instance and accel to the geometry group GeoGroup.Acceleration = accel; GeoGroup.AddChildren(instances); }