public void DumpShared() { var texturedFacesFile = uvSetsDirectory.File("textured-faces.array"); var textureToSpatialIdxMapFile = uvSetsDirectory.File("textured-to-spatial-idx-map.array"); if (texturedFacesFile.Exists && textureToSpatialIdxMapFile.Exists) { return; } int subdivisionLevel = surfaceProperties.SubdivisionLevel; var geometry = figure.Geometry; var spatialControlTopology = new QuadTopology(geometry.VertexCount, geometry.Faces); QuadTopology spatialTopology; using (var refinement = new Refinement(spatialControlTopology, subdivisionLevel)) { spatialTopology = refinement.GetTopology(); } var uvSet = figure.DefaultUvSet; var texturedControlTopology = new QuadTopology(uvSet.Uvs.Length, uvSet.Faces); QuadTopology texturedTopology; using (var refinement = new Refinement(texturedControlTopology, surfaceProperties.SubdivisionLevel, BoundaryInterpolation.EdgeAndCorner)) { texturedTopology = refinement.GetTopology(); } int[] texturedToSpatialIndexMap = QuadTopology.CalculateVertexIndexMap(texturedTopology, spatialTopology.Faces); uvSetsDirectory.CreateWithParents(); texturedFacesFile.WriteArray(texturedTopology.Faces); textureToSpatialIdxMapFile.WriteArray(texturedToSpatialIndexMap); }
public void Apply(HdMorph morph, float weight, int levelIdx, QuadTopology topology, Vector3[] positions) { var level = morph.GetLevel(levelIdx); if (level == null) { return; } foreach (var faceEdit in level.FaceEdits) { foreach (var vertexEdit in faceEdit.VertexEdits) { int pathLength = vertexEdit.PathLength; int refinedFaceIdx = faceEdit.ControlFaceIdx; for (int i = 0; i < pathLength - 1; ++i) { refinedFaceIdx = refinedFaceIdx * 4 + vertexEdit.GetPathElement(i); } int cornerIdx = vertexEdit.GetPathElement(pathLength - 1); int refinedVertexIdx = topology.Faces[refinedFaceIdx].GetCorner(cornerIdx); Vector3 tangentSpaceDelta = vertexEdit.Delta; int tangentToObjectSpaceTransformIdx = faceEdit.ControlFaceIdx * 4 + vertexEdit.GetPathElement(0); Matrix3x3 tangentToObjectSpaceTransform = tangentToObjectSpaceTransforms[tangentToObjectSpaceTransformIdx]; Vector3 objectSpaceDelta = Vector3.Transform(tangentSpaceDelta, tangentToObjectSpaceTransform); positions[refinedVertexIdx] += weight * objectSpaceDelta; } } }
/** * Given two topologies with the same faces but different vertex indices, returns a map from the vertex * indices of one topology to the vertex indices of the other topologies. * * Each vertex in the source topology must map to a single vertex in the dest topology. However, it's * allowable for multiple source vertices to map to the same dest vertex. Thus it's possible to map * from a source UV topology with seams to a dest spatial topology without seams. */ public static int[] CalculateVertexIndexMap(QuadTopology sourceTopology, Quad[] destFaces) { int faceCount = sourceTopology.Faces.Length; if (destFaces.Length != faceCount) { throw new InvalidOperationException("face count mismatch"); } int[] indexMap = new int[sourceTopology.VertexCount]; for (int faceIdx = 0; faceIdx < faceCount; ++faceIdx) { Quad sourceFace = sourceTopology.Faces[faceIdx]; Quad destFace = destFaces[faceIdx]; for (int i = 0; i < Quad.SideCount; ++i) { int sourceIdx = sourceFace.GetCorner(i); int destIdx = destFace.GetCorner(i); int previousMapping = indexMap[sourceIdx]; if (previousMapping != default(int) && previousMapping != destIdx) { throw new InvalidOperationException("mapping conflict"); } indexMap[sourceIdx] = destIdx; } } return(indexMap); }
public static int[] CalculateTextureToSpatialIndexMap(QuadTopology texturedTopology, Quad[] spatialFaces) { int faceCount = texturedTopology.Faces.Length; if (spatialFaces.Length != faceCount) { throw new InvalidOperationException("textured and spatial face count mismatch"); } int[] spatialIdxMap = new int[texturedTopology.VertexCount]; for (int faceIdx = 0; faceIdx < faceCount; ++faceIdx) { Quad texturedFace = texturedTopology.Faces[faceIdx]; Quad spatialFace = spatialFaces[faceIdx]; for (int i = 0; i < Quad.SideCount; ++i) { int texturedIdx = texturedFace.GetCorner(i); int spatialIdx = spatialFace.GetCorner(i); int previousMapping = spatialIdxMap[texturedIdx]; if (previousMapping != default(int) && previousMapping != spatialIdx) { throw new InvalidOperationException("mapping conflict"); } spatialIdxMap[texturedIdx] = spatialIdx; } } return(spatialIdxMap); }
public GpuOcclusionCalculator(Device device, ShaderCache shaderCache, QuadTopology topology, float[] faceTransparencies, uint[] faceMasks, uint[] vertexMasks) { if (topology.Faces.Length != faceTransparencies.Length) { throw new ArgumentException("face count mismatch"); } if (topology.Faces.Length != faceMasks.Length) { throw new ArgumentException("face count mismatch"); } if (topology.VertexCount != vertexMasks.Length) { throw new ArgumentException("vertex count mismatch"); } shader = shaderCache.GetComputeShader <GpuOcclusionCalculator>("occlusion/HemisphericalRasterizingComputeShader"); segmentBufferManager = new ConstantBufferManager <ArraySegment>(device); SetupHemispherePointsAndWeights(device); SetupRasterTable(device, shaderCache); SetupTopologyBuffers(device, topology, faceTransparencies); faceMasksView = BufferUtilities.ToStructuredBufferView(device, faceMasks); vertexMasksView = BufferUtilities.ToStructuredBufferView(device, vertexMasks); }
public void Run() { int controlVertexCount = 6; Quad[] controlFaces = new [] { new Quad(0, 1, 2, 3), new Quad(1, 4, 5, 2) }; QuadTopology controlTopology = new QuadTopology(controlVertexCount, controlFaces); int refinementLevel = 1; using (Refinement refinement = new Refinement(controlTopology, refinementLevel)) { QuadTopology topology = refinement.GetTopology(); int[] faceMap = refinement.GetFaceMap(); for (int faceIdx = 0; faceIdx < topology.Faces.Length; ++faceIdx) { Console.WriteLine(topology.Faces[faceIdx] + " -> " + faceMap[faceIdx]); } Console.WriteLine(); PackedLists <WeightedIndex> stencils = refinement.GetStencils(StencilKind.LimitStencils); Console.WriteLine("stencils: "); for (int vertexIdx = 0; vertexIdx < stencils.Count; ++vertexIdx) { Console.WriteLine(vertexIdx + ":"); foreach (WeightedIndex weightedIndex in stencils.GetElements(vertexIdx)) { Console.WriteLine("\t" + weightedIndex.Index + " -> " + weightedIndex.Weight); } } } }
public static HdMorphApplier Make(QuadTopology controlTopology, Vector3[] controlPositions) { Matrix3x3[] tangentToObjectSpaceTransforms = new Matrix3x3[controlTopology.Faces.Length * 4]; for (int faceIdx = 0; faceIdx < controlTopology.Faces.Length; ++faceIdx) { for (int cornerIdx = 0; cornerIdx < Quad.SideCount; ++cornerIdx) { Vector3 cur = controlPositions[controlTopology.Faces[faceIdx].GetCorner(cornerIdx)]; Vector3 prev = controlPositions[controlTopology.Faces[faceIdx].GetCorner(cornerIdx - 1)]; Vector3 next = controlPositions[controlTopology.Faces[faceIdx].GetCorner(cornerIdx + 1)]; Vector3 edge1 = (prev - cur); Vector3 edge2 = (cur - next); Vector3 tangent = Vector3.Normalize(edge1); Vector3 normal = Vector3.Normalize(Vector3.Cross(edge1, edge2)); Vector3 bitangent = Vector3.Cross(tangent, normal); Matrix3x3 tangentToObjectSpaceTransform = new Matrix3x3( tangent.X, tangent.Y, tangent.Z, normal.X, normal.Y, normal.Z, bitangent.X, bitangent.Y, bitangent.Z); tangentToObjectSpaceTransforms[faceIdx * 4 + cornerIdx] = tangentToObjectSpaceTransform; } } return(new HdMorphApplier(tangentToObjectSpaceTransforms)); }
private static Vector3[] ExtractTexturedPositions(QuadTopology topology, QuadTopology uvTopology, Vector3[] ldPositions) { int[] texturedToSpatialIndexMap = QuadTopology.CalculateVertexIndexMap(uvTopology, topology.Faces); return(texturedToSpatialIndexMap .Select(spatialIdx => ldPositions[spatialIdx]) .ToArray()); }
public PackedLists <WeightedIndex> MakeStencils(StencilKind kind, int refinementLevel) { var controlTopology = new QuadTopology(VertexCount, Faces); using (var refinement = new Refinement(controlTopology, refinementLevel)) { return(refinement.GetStencils(kind)); } }
private void SetupTopologyBuffers(Device device, QuadTopology topology, float[] faceTransparencies) { vertexCount = topology.VertexCount; facesView = BufferUtilities.ToStructuredBufferView(device, topology.Faces); transparenciesView = BufferUtilities.ToStructuredBufferView(device, faceTransparencies); outputBufferManager = new StageableStructuredBufferManager <OcclusionInfo>(device, vertexCount); }
public static SubdivisionMesh Combine(SubdivisionMesh meshA, SubdivisionMesh meshB) { int offset = meshA.ControlVertexCount; return(new SubdivisionMesh( meshA.ControlVertexCount + meshB.ControlVertexCount, QuadTopology.Combine(meshA.Topology, meshB.Topology), PackedLists <WeightedIndexWithDerivatives> .Concat( meshA.Stencils, meshB.Stencils.Map(w => w.Reindex(offset))))); }
public SubdivisionMesh(int controlVertexCount, QuadTopology topology, PackedLists <WeightedIndexWithDerivatives> stencils) { if (stencils.Count != topology.VertexCount) { throw new ArgumentException("vertex count mismatch"); } ControlVertexCount = controlVertexCount; Topology = topology; Stencils = stencils; }
public static void AssertTopologyAssumptions(QuadTopology topology, QuadTopology nextLevelTopology) { for (int faceIdx = 0; faceIdx < topology.Faces.Length; ++faceIdx) { for (int cornerIdx = 0; cornerIdx < Quad.SideCount; ++cornerIdx) { int vertexIdx = topology.Faces[faceIdx].GetCorner(cornerIdx); int nextLevelVertexIdx = nextLevelTopology.Faces[faceIdx * 4 + cornerIdx].GetCorner(cornerIdx); Debug.Assert(vertexIdx == nextLevelVertexIdx); } } }
private UvSet RemapToDefault(UvSet uvSet) { var defaultUvSet = figure.DefaultUvSet; var defaultUvSetTopology = new QuadTopology(defaultUvSet.Uvs.Length, defaultUvSet.Faces); var indexMap = QuadTopology.CalculateVertexIndexMap(defaultUvSetTopology, uvSet.Faces); Vector2[] remappedUvs = indexMap .Select(idx => uvSet.Uvs[idx]) .ToArray(); return(new UvSet(uvSet.Name, remappedUvs, defaultUvSet.Faces)); }
public static QuadTopology Combine(QuadTopology topologyA, QuadTopology topologyB) { int combinedVertexCount = topologyA.VertexCount + topologyB.VertexCount; Quad[] combinedFaces = topologyA.Faces .Concat( topologyB.Faces.Select(face => face.Reindex(topologyA.VertexCount)) ) .ToArray(); return(new QuadTopology(combinedVertexCount, combinedFaces)); }
public static SubdivisionMesh Load(IArchiveDirectory directory) { var stencilSegments = directory.File(StencilSegmentsFilename).ReadArray <ArraySegment>(); var stencilElements = directory.File(StencilElementsFilename).ReadArray <WeightedIndexWithDerivatives>(); var faces = directory.File(StencilFacesFilename).ReadArray <Quad>(); var stencils = new PackedLists <WeightedIndexWithDerivatives>(stencilSegments, stencilElements); int vertexCount = stencils.Count; var topology = new QuadTopology(vertexCount, faces); return(new SubdivisionMesh(0, topology, stencils)); }
public ApplyHdMorphDemo() { var fileLocator = new ContentFileLocator(); var objectLocator = new DsonObjectLocator(fileLocator); var contentPackConfs = ContentPackImportConfiguration.LoadAll(CommonPaths.ConfDir); var pathManager = ImporterPathManager.Make(contentPackConfs); var loader = new FigureRecipeLoader(fileLocator, objectLocator, pathManager); var figureRecipe = loader.LoadFigureRecipe("genesis-3-female", null); var figure = figureRecipe.Bake(fileLocator, null); var geometry = figure.Geometry; controlTopology = new QuadTopology(geometry.VertexCount, geometry.Faces); controlVertexPositions = geometry.VertexPositions; }
private static (QuadTopology, Vector3[]) ApplyHdMorph(HdMorph hdMorph, QuadTopology controlTopology, Vector3[] controlPositions, Refinement refinement) { var applier = HdMorphApplier.Make(controlTopology, controlPositions); var topology = controlTopology; var positions = controlPositions; for (int levelIdx = 1; levelIdx <= hdMorph.MaxLevel; ++levelIdx) { topology = refinement.GetTopology(levelIdx); positions = refinement.Refine(levelIdx, positions); applier.Apply(hdMorph, 1, levelIdx, topology, positions); } return(topology, positions); }
public static RefinementResult Make(QuadTopology controlTopology, int[] controlSurfaceMap, int refinementLevel, bool derivativesOnly) { if (controlTopology.Faces.Length == 0 && controlTopology.VertexCount == 0) { return(RefinementResult.Empty); } PackedLists <WeightedIndex> limitStencils, limitDuStencils, limitDvStencils; QuadTopology refinedTopology; SubdivisionTopologyInfo refinedTopologyInfo; int[] controlFaceMap; using (var refinement = new Refinement(controlTopology, refinementLevel)) { limitStencils = refinement.GetStencils(StencilKind.LimitStencils); limitDuStencils = refinement.GetStencils(StencilKind.LimitDuStencils); limitDvStencils = refinement.GetStencils(StencilKind.LimitDvStencils); refinedTopology = refinement.GetTopology(); var adjacentVertices = refinement.GetAdjacentVertices(); var rules = refinement.GetVertexRules(); refinedTopologyInfo = new SubdivisionTopologyInfo(adjacentVertices, rules); controlFaceMap = refinement.GetFaceMap(); } if (derivativesOnly) { if (refinementLevel != 0) { throw new InvalidOperationException("derivatives-only mode can only be used at refinement level 0"); } limitStencils = PackedLists <WeightedIndex> .Pack(Enumerable.Range(0, controlTopology.VertexCount) .Select(vertexIdx => { var selfWeight = new WeightedIndex(vertexIdx, 1); return(new List <WeightedIndex> { selfWeight }); }).ToList()); } PackedLists <WeightedIndexWithDerivatives> stencils = WeightedIndexWithDerivatives.Merge(limitStencils, limitDuStencils, limitDvStencils); var refinedMesh = new SubdivisionMesh(controlTopology.VertexCount, refinedTopology, stencils); return(new RefinementResult(refinedMesh, refinedTopologyInfo, controlFaceMap)); }
private static (QuadTopology, Vector3[]) ApplyHdMorph(HdMorph hdMorph, QuadTopology controlTopology, Vector3[] controlPositions) { using (var refinement = new Refinement(controlTopology, hdMorph.MaxLevel)) { return(ApplyHdMorph(hdMorph, controlTopology, controlPositions, refinement)); } }
public NormalMapRenderer MakeNormalMapRenderer(ChannelInputs ldChannelInputs, ChannelInputs hdChannelInputs, UvSet uvSet) { var ldChannelOutputs = figure.Evaluate(null, ldChannelInputs); var hdChannelOutputs = figure.Evaluate(null, hdChannelInputs); var ldControlPositions = figure.Geometry.VertexPositions.Select(p => p).ToArray(); figure.Morpher.Apply(ldChannelOutputs, ldControlPositions); var hdControlPositions = figure.Geometry.VertexPositions.Select(p => p).ToArray(); figure.Morpher.Apply(hdChannelOutputs, hdControlPositions); var activeHdMorphs = figure.Morpher.LoadActiveHdMorphs(hdChannelOutputs); int maxLevel = activeHdMorphs.Max(morph => morph.Morph.MaxLevel) + ExtraRefinementLevels; var controlTopology = new QuadTopology(figure.Geometry.VertexCount, figure.Geometry.Faces); var applier = HdMorphApplier.Make(controlTopology, hdControlPositions); var controlUvTopology = new QuadTopology(uvSet.Uvs.Length, uvSet.Faces); var controlUvs = uvSet.Uvs; var refinement = new Refinement(controlTopology, maxLevel); var uvRefinement = new Refinement(controlUvTopology, maxLevel, BoundaryInterpolation.EdgeAndCorner); var topology = controlTopology; var ldPositions = ldControlPositions; var hdPositions = hdControlPositions; var uvTopology = controlUvTopology; var uvs = controlUvs; var texturedLdPositions = ExtractTexturedPositions(topology, uvTopology, ldPositions); for (int levelIdx = 1; levelIdx <= maxLevel; ++levelIdx) { topology = refinement.GetTopology(levelIdx); ldPositions = refinement.Refine(levelIdx, ldPositions); hdPositions = refinement.Refine(levelIdx, hdPositions); foreach (var activeHdMorph in activeHdMorphs) { applier.Apply(activeHdMorph.Morph, activeHdMorph.Weight, levelIdx, topology, hdPositions); } uvTopology = uvRefinement.GetTopology(levelIdx); uvs = uvRefinement.Refine(levelIdx, uvs); texturedLdPositions = uvRefinement.Refine(levelIdx, texturedLdPositions); } var ldLimit = refinement.Limit(ldPositions); var hdLimit = refinement.Limit(hdPositions); var uvLimit = uvRefinement.Limit(uvs); var texturedLdLimit = uvRefinement.Limit(texturedLdPositions); int[] faceMap = refinement.GetFaceMap(); refinement.Dispose(); uvRefinement.Dispose(); var hdNormals = CalculateNormals(hdLimit); var ldNormals = CalculateNormals(ldLimit); var ldTangents = CalculateTangents(uvLimit, texturedLdLimit); int[] controlSurfaceMap = figure.Geometry.SurfaceMap; int[] surfaceMap = faceMap .Select(controlFaceIdx => controlSurfaceMap[controlFaceIdx]) .ToArray(); var renderer = new NormalMapRenderer(device, shaderCache, hdNormals, ldNormals, topology.Faces, uvLimit.values, ldTangents, uvTopology.Faces, surfaceMap); return(renderer); }
public void Dump(string name, UvSet uvSet) { DirectoryInfo uvSetDirectory = uvSetsDirectory.Subdirectory(name); if (uvSetDirectory.Exists) { return; } Console.WriteLine($"Dumping uv-set {name}..."); int subdivisionLevel = surfaceProperties.SubdivisionLevel; var geometry = figure.Geometry; var spatialControlTopology = new QuadTopology(geometry.VertexCount, geometry.Faces); var spatialControlPositions = geometry.VertexPositions; QuadTopology spatialTopology; LimitValues <Vector3> spatialLimitPositions; using (var refinement = new Refinement(spatialControlTopology, subdivisionLevel)) { spatialTopology = refinement.GetTopology(); spatialLimitPositions = refinement.LimitFully(spatialControlPositions); } uvSet = RemapToDefault(uvSet); var texturedControlTopology = new QuadTopology(uvSet.Uvs.Length, uvSet.Faces); Vector2[] controlTextureCoords = uvSet.Uvs; int[] controlSpatialIdxMap = QuadTopology.CalculateVertexIndexMap(texturedControlTopology, spatialControlTopology.Faces); Vector3[] texturedControlPositions = controlSpatialIdxMap .Select(spatialIdx => spatialControlPositions[spatialIdx]) .ToArray(); QuadTopology texturedTopology; LimitValues <Vector3> texturedLimitPositions; LimitValues <Vector2> limitTextureCoords; using (var refinement = new Refinement(texturedControlTopology, surfaceProperties.SubdivisionLevel, BoundaryInterpolation.EdgeAndCorner)) { texturedTopology = refinement.GetTopology(); texturedLimitPositions = refinement.LimitFully(texturedControlPositions); limitTextureCoords = refinement.LimitFully(controlTextureCoords); } Vector2[] textureCoords; if (geometry.Type == GeometryType.SubdivisionSurface) { textureCoords = limitTextureCoords.values; } else { if (subdivisionLevel != 0) { throw new InvalidOperationException("polygon meshes cannot be subdivided"); } Debug.Assert(limitTextureCoords.values.Length == controlTextureCoords.Length); textureCoords = controlTextureCoords; } int[] spatialIdxMap = QuadTopology.CalculateVertexIndexMap(texturedTopology, spatialTopology.Faces); TexturedVertexInfo[] texturedVertexInfos = Enumerable.Range(0, textureCoords.Length) .Select(idx => { int spatialVertexIdx = spatialIdxMap[idx]; Vector2 textureCoord = textureCoords[idx]; Vector3 positionDu = TangentSpaceUtilities.CalculatePositionDu( limitTextureCoords.tangents1[idx], limitTextureCoords.tangents2[idx], texturedLimitPositions.tangents1[idx], texturedLimitPositions.tangents2[idx]); Vector3 spatialPositionTan1 = spatialLimitPositions.tangents1[spatialVertexIdx]; Vector3 spatialPositionTan2 = spatialLimitPositions.tangents2[spatialVertexIdx]; Vector2 tangentUCoeffs = TangentSpaceUtilities.CalculateTangentSpaceRemappingCoeffs(spatialPositionTan1, spatialPositionTan2, positionDu); DebugUtilities.AssertFinite(tangentUCoeffs.X); DebugUtilities.AssertFinite(tangentUCoeffs.Y); return(new TexturedVertexInfo( textureCoord, tangentUCoeffs)); }) .ToArray(); uvSetDirectory.CreateWithParents(); uvSetDirectory.File("textured-vertex-infos.array").WriteArray(texturedVertexInfos); }