├── .gitignore ├── LICENSE ├── ReadMe.md ├── Scripts └── HeightMapGenerator.cs └── Shaders └── HeightMapComputeShader.compute /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # MemoryCaptures can get excessive in size. 14 | # They also could contain extremely sensitive data 15 | /[Mm]emoryCaptures/ 16 | 17 | # Asset meta data should only be ignored when the corresponding asset is also ignored 18 | /**/*.meta 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | 23 | # Autogenerated Jetbrains Rider plugin 24 | /[Aa]ssets/Plugins/Editor/JetBrains* 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Gradle cache directory 30 | .gradle/ 31 | 32 | # Autogenerated VS/MD/Consulo solution and project files 33 | ExportedObj/ 34 | .consulo/ 35 | *.csproj 36 | *.unityproj 37 | *.sln 38 | *.suo 39 | *.tmp 40 | *.user 41 | *.userprefs 42 | *.pidb 43 | *.booproj 44 | *.svd 45 | *.pdb 46 | *.mdb 47 | *.opendb 48 | *.VC.db 49 | 50 | # Unity3D generated meta files 51 | *.pidb.meta 52 | *.pdb.meta 53 | *.mdb.meta 54 | 55 | # Unity3D generated file on crash reports 56 | sysinfo.txt 57 | 58 | # Builds 59 | *.apk 60 | *.aab 61 | *.unitypackage 62 | 63 | # Crashlytics generated file 64 | crashlytics-build.properties 65 | 66 | # Packed Addressables 67 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 68 | 69 | # Temporary auto-generated Android Assets 70 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 71 | /[Aa]ssets/[Ss]treamingAssets/aa/* 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 HappyTurtle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # Contours2HeightMap 2 | A Compute shader that generates a height map from 2D vector contours. In combination with a tesselation shader this can be used to generate three-dimensional geometry out of two-dimensional polygons. 3 | We extracted contours out of a video with OpenCV and used these contours as input for the compute shader. Using the height map with a tesselation shader you get a three-dimensional geometry out of a simple video. 4 | Changing the mapping function `1.0 - rcp(1.0 + smallestDistance * curviness)` at the end of the shader will result in different shaping of the geometry. 5 | 6 | This shader was written as part of the research publication [Real-Time Relighting of Video Streams for Augmented Virtuality Scenes](https://vsvr.medien.hs-duesseldorf.de/publications/gi-vrar2021-relighting/) and a corresponding [master's thesis](https://vsvr.medien.hs-duesseldorf.de/education/diplom/2021/davin-master2021.html) at the Virtual Sets and Virtual Environments Laboratory of the University of Applied Sciences Düsseldorf. 7 | 8 | | Contours | Height Map | Rendered geometry | 9 | | --- | --- | --- | 10 | |![contour](https://user-images.githubusercontent.com/18415215/109659645-2c996e00-7b68-11eb-9fbb-36491a0db6e9.gif)|![height_map](https://user-images.githubusercontent.com/18415215/109654972-1341f300-7b63-11eb-8a35-9a8d28d6a9a0.gif)|![wald](https://user-images.githubusercontent.com/18415215/109654981-14732000-7b63-11eb-8e4c-de145747146e.gif) 11 | -------------------------------------------------------------------------------- /Scripts/HeightMapGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | [RequireComponent(typeof(ContourGenerator))] 5 | public class HeightMapGenerator : MonoBehaviour 6 | { 7 | public Material[] materials; 8 | public ComputeShader heightMapShader; 9 | public enum TextureSize { x512 = 512, x1024 = 1024, x2048 = 2048, x4096 = 4096 } 10 | public TextureSize textureSize = TextureSize.x1024; 11 | public float curviness = 10f; 12 | 13 | private RenderTexture heightMap; 14 | private ComputeBuffer polygonBuffer; 15 | private ComputeBuffer polygonIndicesBuffer; 16 | private int kernelHandle; 17 | private uint threadSizeX, threadSizeY, threadSizeZ; 18 | private int polygonBufferID; 19 | private int polygonIndicesBufferID; 20 | private int curvinessID; 21 | 22 | private readonly List flattened = new List(); 23 | private readonly List polygonIndices = new List(); 24 | 25 | private const int vector2Stride = sizeof(float) * 2; 26 | 27 | private void Awake() 28 | { 29 | heightMap = new RenderTexture((int)textureSize, (int)textureSize, 0, RenderTextureFormat.RFloat) 30 | { 31 | enableRandomWrite = true, 32 | wrapMode = TextureWrapMode.Repeat 33 | }; 34 | heightMap.Create(); 35 | 36 | kernelHandle = heightMapShader.FindKernel("CSMain"); 37 | heightMapShader.GetKernelThreadGroupSizes(kernelHandle, out threadSizeX, out threadSizeY, out threadSizeZ); 38 | heightMapShader.SetTexture(kernelHandle, "Result", heightMap); 39 | 40 | polygonBufferID = Shader.PropertyToID("polygonOutline"); 41 | polygonIndicesBufferID = Shader.PropertyToID("polygonIndices"); 42 | curvinessID = Shader.PropertyToID("curviness"); 43 | 44 | foreach (Material mat in materials) 45 | { 46 | //prevent height map from not being loaded in unity hdrp tesselation shader 47 | mat.EnableKeyword("_HEIGHTMAP"); 48 | mat.SetTexture("_HeightMap", heightMap); 49 | } 50 | } 51 | 52 | public void GenerateHeightMap(List> polygons) 53 | { 54 | if (polygons == null || polygons.Count == 0) 55 | return; 56 | 57 | //flatten the list 58 | flattened.Clear(); 59 | //where are the polygons in the flattened list 60 | polygonIndices.Clear(); 61 | foreach(List polygon in polygons) 62 | { 63 | flattened.AddRange(polygon); 64 | polygonIndices.Add((uint)polygon.Count); 65 | } 66 | 67 | if(flattened != null && flattened.Count > 0) 68 | { 69 | polygonBuffer = new ComputeBuffer(flattened.Count, vector2Stride); 70 | polygonBuffer.SetData(flattened); 71 | heightMapShader.SetBuffer(kernelHandle, polygonBufferID, polygonBuffer); 72 | 73 | polygonIndicesBuffer = new ComputeBuffer(polygonIndices.Count, sizeof(int)); 74 | polygonIndicesBuffer.SetData(polygonIndices); 75 | heightMapShader.SetBuffer(kernelHandle, polygonIndicesBufferID, polygonIndicesBuffer); 76 | 77 | heightMapShader.SetFloat(curvinessID, curviness); 78 | 79 | heightMapShader.Dispatch(kernelHandle, heightMap.width / (int)threadSizeX, heightMap.height / (int)threadSizeY, (int)threadSizeZ); 80 | 81 | polygonBuffer.Release(); 82 | polygonIndicesBuffer.Release(); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Shaders/HeightMapComputeShader.compute: -------------------------------------------------------------------------------- 1 | // Each #kernel tells which function to compile; you can have many kernels 2 | #pragma kernel CSMain 3 | 4 | RWTexture2D Result; 5 | StructuredBuffer polygonOutline; 6 | StructuredBuffer polygonIndices; 7 | float curviness; 8 | 9 | inline float IfLessThan(float x, float y) 10 | { 11 | return max(sign(y - x), 0.0); 12 | } 13 | 14 | inline float IfGreaterOrEqual(float x, float y) 15 | { 16 | return 1 - IfLessThan(x, y); 17 | } 18 | 19 | inline uint IfNotEqual(uint x, uint y) 20 | { 21 | return abs(sign(x - y)); 22 | } 23 | 24 | inline uint IfEqual(uint x, uint y) 25 | { 26 | return 1 - IfNotEqual(x, y); 27 | } 28 | 29 | float DistancePointToLine(float2 pnt, float2 lineStart, float2 lineEnd) 30 | { 31 | float2 lineSegment = lineEnd - lineStart; 32 | float2 pointVector = pnt - lineStart; 33 | float2 pointVectorScaled = pointVector * (rcp(length(lineSegment))); 34 | float2 lineUnitSegment = normalize(lineSegment); 35 | float t = clamp(dot(lineUnitSegment, pointVectorScaled), 0.0, 1.0); 36 | float2 nearestPoint = lineSegment * t; 37 | float dist = distance(pointVector, nearestPoint); 38 | return dist; 39 | } 40 | 41 | [numthreads(32,32,1)] 42 | void CSMain (uint3 id : SV_DispatchThreadID) 43 | { 44 | float texWidth, texHeight; 45 | Result.GetDimensions(texWidth, texHeight); 46 | uint numPolygons, stride; 47 | polygonIndices.GetDimensions(numPolygons, stride); 48 | 49 | float pntDistance; 50 | float smallestDistance = 1.0; 51 | uint j; 52 | float2 pnt = float2(id.x / texWidth, id.y / texHeight); 53 | uint start = 0; 54 | 55 | for (uint k = 0; k < numPolygons; k++) 56 | { 57 | uint end = start + (uint) polygonIndices[k]; 58 | for (uint i = start; i < end; i++) 59 | { 60 | //for the last point, we want to draw the line to the first point with index 0 61 | j = IfNotEqual(i, end - 1) * (i + 1) + IfEqual(i, end - 1) * start; 62 | float2 outline0 = float2(polygonOutline[i].x, polygonOutline[i].y); 63 | float2 outline1 = float2(polygonOutline[j].x, polygonOutline[j].y); 64 | pntDistance = DistancePointToLine(pnt, outline0, outline1); 65 | smallestDistance = pntDistance * IfLessThan(pntDistance, smallestDistance) + smallestDistance * IfGreaterOrEqual(pntDistance, smallestDistance); 66 | } 67 | start += (uint) polygonIndices[k]; 68 | } 69 | 70 | Result[id.xy] = 1.0 - rcp(1.0 + smallestDistance * curviness); 71 | } 72 | --------------------------------------------------------------------------------