├── Assets ├── ConvexPolyhedra.blend ├── ConvexPolyhedra.blend.meta ├── ExampleScenes.meta ├── ExampleScenes │ ├── NoRaytracing.meta │ ├── NoRaytracing │ │ ├── ConvexNoRT.unity │ │ ├── ConvexNoRT.unity.meta │ │ ├── NonConvexNoRT.unity │ │ └── NonConvexNoRT.unity.meta │ ├── Raytracing.meta │ └── Raytracing │ │ ├── ConvexRT.unity │ │ ├── ConvexRT.unity.meta │ │ ├── NonStarShapedRT.unity │ │ ├── NonStarShapedRT.unity.meta │ │ ├── StarShapedRT.unity │ │ └── StarShapedRT.unity.meta ├── LUTs.meta ├── LUTs │ ├── GGX.asset │ ├── GGX.asset.meta │ ├── ggxAmplitude.asset │ ├── ggxAmplitude.asset.meta │ ├── ggxMatrix.asset │ └── ggxMatrix.asset.meta ├── Materials.meta ├── Materials │ ├── AdditiveBlit.mat │ ├── AdditiveBlit.mat.meta │ ├── Grid.mat │ ├── Grid.mat.meta │ ├── LightSource.mat │ └── LightSource.mat.meta ├── NonConvexPolyhedra.blend ├── NonConvexPolyhedra.blend.meta ├── PostProcessing Profile.asset ├── PostProcessing Profile.asset.meta ├── Precomputed Data.meta ├── Precomputed Data │ ├── Corner.asset │ ├── Corner.asset.meta │ ├── Cube.asset │ ├── Cube.asset.meta │ ├── ExtrudedCube.asset │ ├── ExtrudedCube.asset.meta │ ├── Hole.asset │ ├── Hole.asset.meta │ ├── HoleTriangulation.asset │ └── HoleTriangulation.asset.meta ├── Scripts.meta ├── Scripts │ ├── BSP.cs │ ├── BSP.cs.meta │ ├── Double3.cs │ ├── Double3.cs.meta │ ├── Editor.meta │ ├── Editor │ │ ├── ConvexSilhouetteBSPEditor.cs │ │ ├── ConvexSilhouetteBSPEditor.cs.meta │ │ ├── NonConvexSilhouetteBSPEditor.cs │ │ ├── NonConvexSilhouetteBSPEditor.cs.meta │ │ ├── SilhouetteTriangulationBSPEditor.cs │ │ └── SilhouetteTriangulationBSPEditor.cs.meta │ ├── FastList.cs │ ├── FastList.cs.meta │ ├── FreeCamera.cs │ ├── FreeCamera.cs.meta │ ├── Lights.meta │ ├── Lights │ │ ├── ConvexLTCLight.cs │ │ ├── ConvexLTCLight.cs.meta │ │ ├── ConvexRaytracedLight.cs │ │ ├── ConvexRaytracedLight.cs.meta │ │ ├── CustomDeferredLight.cs │ │ ├── CustomDeferredLight.cs.meta │ │ ├── NonConvexLTCLight.cs │ │ ├── NonConvexLTCLight.cs.meta │ │ ├── NonStarShapedRaytracedLight.cs │ │ ├── NonStarShapedRaytracedLight.cs.meta │ │ ├── StarShapedRaytracedLight.cs │ │ └── StarShapedRaytracedLight.cs.meta │ ├── LtcLookupTable.cs │ ├── LtcLookupTable.cs.meta │ ├── Plane.cs │ ├── Plane.cs.meta │ ├── Polyhedron.cs │ ├── Polyhedron.cs.meta │ ├── Raytracing.cs │ ├── Raytracing.cs.meta │ ├── Silhouettes.meta │ ├── Silhouettes │ │ ├── ConvexSilhouetteBSP.cs │ │ ├── ConvexSilhouetteBSP.cs.meta │ │ ├── ConvexSilhouettes.cs │ │ ├── ConvexSilhouettes.cs.meta │ │ ├── NonConvexSilhouetteBSP.cs │ │ ├── NonConvexSilhouetteBSP.cs.meta │ │ ├── NonConvexSilhouettes.cs │ │ ├── NonConvexSilhouettes.cs.meta │ │ ├── SilhouetteEdge.cs │ │ ├── SilhouetteEdge.cs.meta │ │ ├── SilhouetteTriangle.cs │ │ ├── SilhouetteTriangle.cs.meta │ │ ├── SilhouetteTriangulationBSP.cs │ │ ├── SilhouetteTriangulationBSP.cs.meta │ │ ├── SilhouetteVertex.cs │ │ ├── SilhouetteVertex.cs.meta │ │ ├── SphericalTriangulation.cs │ │ ├── SphericalTriangulation.cs.meta │ │ ├── TriangulatedSilhouettes.cs │ │ └── TriangulatedSilhouettes.cs.meta │ ├── TwoPassBSP.cs │ ├── TwoPassBSP.cs.meta │ ├── Utility.cs │ └── Utility.cs.meta ├── Shaders.meta ├── Shaders │ ├── Resources.meta │ └── Resources │ │ ├── AdditiveBlit.shader │ │ ├── AdditiveBlit.shader.meta │ │ ├── BspCommon.hlsl │ │ ├── BspCommon.hlsl.meta │ │ ├── ConvexLTCLight.shader │ │ ├── ConvexLTCLight.shader.meta │ │ ├── ConvexRaytracedLight.raytrace │ │ ├── ConvexRaytracedLight.raytrace.meta │ │ ├── DeferredLight.hlsl │ │ ├── DeferredLight.hlsl.meta │ │ ├── LightSourceUnlit.shader │ │ ├── LightSourceUnlit.shader.meta │ │ ├── LtcCommon.hlsl │ │ ├── LtcCommon.hlsl.meta │ │ ├── LtcLut.hlsl │ │ ├── LtcLut.hlsl.meta │ │ ├── NonConvexLTCLight.shader │ │ ├── NonConvexLTCLight.shader.meta │ │ ├── NonStarShapedRaytracedLight.raytrace │ │ ├── NonStarShapedRaytracedLight.raytrace.meta │ │ ├── RaytracedDeferredLight.hlsl │ │ ├── RaytracedDeferredLight.hlsl.meta │ │ ├── SolidAngleSampling.hlsl │ │ ├── SolidAngleSampling.hlsl.meta │ │ ├── StarShapedRaytracedLight.raytrace │ │ └── StarShapedRaytracedLight.raytrace.meta ├── Textures.meta └── Textures │ ├── Grid.png │ └── Grid.png.meta ├── Packages ├── manifest.json └── packages-lock.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── HDRPProjectSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── PackageManagerSettings.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── SceneTemplateSettings.json ├── TagManager.asset ├── TimeManager.asset ├── UnityConnectSettings.asset ├── VFXManager.asset ├── VersionControlSettings.asset └── XRSettings.asset └── README.md /Assets/ConvexPolyhedra.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BastianUrbach/rtswplusd/6152d65d13221e4803c0cab2be6d2220f3ea75d9/Assets/ConvexPolyhedra.blend -------------------------------------------------------------------------------- /Assets/ConvexPolyhedra.blend.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8457d03241413464f8105e48f96edd9a 3 | ModelImporter: 4 | serializedVersion: 21100 5 | internalIDToNameTable: [] 6 | externalObjects: {} 7 | materials: 8 | materialImportMode: 0 9 | materialName: 0 10 | materialSearch: 1 11 | materialLocation: 1 12 | animations: 13 | legacyGenerateAnimations: 4 14 | bakeSimulation: 0 15 | resampleCurves: 1 16 | optimizeGameObjects: 0 17 | motionNodeName: 18 | rigImportErrors: 19 | rigImportWarnings: 20 | animationImportErrors: 21 | animationImportWarnings: 22 | animationRetargetingWarnings: 23 | animationDoRetargetingWarnings: 0 24 | importAnimatedCustomProperties: 0 25 | importConstraints: 0 26 | animationCompression: 1 27 | animationRotationError: 0.5 28 | animationPositionError: 0.5 29 | animationScaleError: 0.5 30 | animationWrapMode: 0 31 | extraExposedTransformPaths: [] 32 | extraUserProperties: [] 33 | clipAnimations: [] 34 | isReadable: 1 35 | meshes: 36 | lODScreenPercentages: [] 37 | globalScale: 1 38 | meshCompression: 0 39 | addColliders: 0 40 | useSRGBMaterialColor: 1 41 | sortHierarchyByName: 1 42 | importVisibility: 1 43 | importBlendShapes: 1 44 | importCameras: 1 45 | importLights: 1 46 | fileIdsGeneration: 2 47 | swapUVChannels: 0 48 | generateSecondaryUV: 0 49 | useFileUnits: 1 50 | keepQuads: 0 51 | weldVertices: 1 52 | bakeAxisConversion: 0 53 | preserveHierarchy: 0 54 | skinWeightsMode: 0 55 | maxBonesPerVertex: 4 56 | minBoneWeight: 0.001 57 | meshOptimizationFlags: -1 58 | indexFormat: 0 59 | secondaryUVAngleDistortion: 8 60 | secondaryUVAreaDistortion: 15.000001 61 | secondaryUVHardAngle: 88 62 | secondaryUVMarginMethod: 1 63 | secondaryUVMinLightmapResolution: 40 64 | secondaryUVMinObjectScale: 1 65 | secondaryUVPackMargin: 4 66 | useFileScale: 1 67 | tangentSpace: 68 | normalSmoothAngle: 60 69 | normalImportMode: 0 70 | tangentImportMode: 3 71 | normalCalculationMode: 4 72 | legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 73 | blendShapeNormalImportMode: 1 74 | normalSmoothingSource: 0 75 | referencedClips: [] 76 | importAnimation: 1 77 | humanDescription: 78 | serializedVersion: 3 79 | human: [] 80 | skeleton: [] 81 | armTwist: 0.5 82 | foreArmTwist: 0.5 83 | upperLegTwist: 0.5 84 | legTwist: 0.5 85 | armStretch: 0.05 86 | legStretch: 0.05 87 | feetSpacing: 0 88 | globalScale: 1 89 | rootMotionBoneName: 90 | hasTranslationDoF: 0 91 | hasExtraRoot: 0 92 | skeletonHasParents: 1 93 | lastHumanDescriptionAvatarSource: {instanceID: 0} 94 | autoGenerateAvatarMappingIfUnspecified: 1 95 | animationType: 2 96 | humanoidOversampling: 1 97 | avatarSetup: 0 98 | addHumanoidExtraRootOnlyWhenUsingAvatar: 1 99 | additionalBone: 0 100 | userData: 101 | assetBundleName: 102 | assetBundleVariant: 103 | -------------------------------------------------------------------------------- /Assets/ExampleScenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6ffdbddbf5056bb48ad7d46834829e15 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/ExampleScenes/NoRaytracing.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20bbfa52de209b04597def82e6ad824f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/ExampleScenes/NoRaytracing/ConvexNoRT.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e331b1f4c12b584bac23c64977cbf47 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/ExampleScenes/NoRaytracing/NonConvexNoRT.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b9438f5f9aa89c64f93fe159f444ca89 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/ExampleScenes/Raytracing.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e590cb8300d7264ba74ec44ac0c3309 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/ExampleScenes/Raytracing/ConvexRT.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2d36dea09cb0ba94caa31071a263b34e 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/ExampleScenes/Raytracing/NonStarShapedRT.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7fc422669c1832d4cbf06b3a267abd9b 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/ExampleScenes/Raytracing/StarShapedRT.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa07e6ed3d9e93c4f86ab485dfde5285 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/LUTs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70800e0e3f4d9124d94839414a80735f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LUTs/GGX.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: bee70f2751d308e48875767d8a5c0066, type: 3} 13 | m_Name: GGX 14 | m_EditorClassIdentifier: 15 | matrixLUT: {fileID: 2800000, guid: 2588e32cc4a3e424faffc3947b852140, type: 2} 16 | amplitudeLUT: {fileID: 2800000, guid: f0055d36b09dd8b408e887c9b84b09a1, type: 2} 17 | -------------------------------------------------------------------------------- /Assets/LUTs/GGX.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed545418c52aa2f49b3fc947eb07027b 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LUTs/ggxAmplitude.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f0055d36b09dd8b408e887c9b84b09a1 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2800000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/LUTs/ggxMatrix.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2588e32cc4a3e424faffc3947b852140 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2800000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4fc364d573645d84381c96acba861a9b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials/AdditiveBlit.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: AdditiveBlit 11 | m_Shader: {fileID: 4800000, guid: eca7d6c3aa12a5243be2cd9081e0394d, type: 3} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Ints: [] 23 | m_Floats: [] 24 | m_Colors: [] 25 | m_BuildTextureStacks: [] 26 | -------------------------------------------------------------------------------- /Assets/Materials/AdditiveBlit.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aaa7d692effc835498880f9e36bc9aaa 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials/Grid.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: Grid 11 | m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} 12 | m_ShaderKeywords: _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _BumpMap: 23 | m_Texture: {fileID: 0} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _DetailAlbedoMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailMask: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailNormalMap: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _EmissionMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 50, y: 50} 41 | m_Offset: {x: 0, y: 0} 42 | - _MainTex: 43 | m_Texture: {fileID: 2800000, guid: cb60e5d1155872440b4ad41d306c3292, type: 3} 44 | m_Scale: {x: 50, y: 50} 45 | m_Offset: {x: 0, y: 0} 46 | - _MetallicGlossMap: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _OcclusionMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _ParallaxMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | m_Ints: [] 59 | m_Floats: 60 | - _BumpScale: 1 61 | - _Cutoff: 0.5 62 | - _DetailNormalMapScale: 1 63 | - _DstBlend: 0 64 | - _GlossMapScale: 0.8 65 | - _Glossiness: 0.651 66 | - _GlossyReflections: 1 67 | - _Metallic: 0 68 | - _Mode: 0 69 | - _OcclusionStrength: 1 70 | - _Parallax: 0.02 71 | - _SmoothnessTextureChannel: 1 72 | - _SpecularHighlights: 1 73 | - _SrcBlend: 1 74 | - _UVSec: 0 75 | - _ZWrite: 1 76 | m_Colors: 77 | - _Color: {r: 1, g: 0.19607843, b: 0, a: 1} 78 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 79 | m_BuildTextureStacks: [] 80 | -------------------------------------------------------------------------------- /Assets/Materials/Grid.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cbfe42ffac0a57d4182997f43edacc56 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials/LightSource.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: LightSource 11 | m_Shader: {fileID: 4800000, guid: 4e69ed530f7023a4f94a96103fbb853d, type: 3} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Ints: [] 23 | m_Floats: [] 24 | m_Colors: 25 | - _Color: {r: 1, g: 1, b: 1, a: 1} 26 | m_BuildTextureStacks: [] 27 | -------------------------------------------------------------------------------- /Assets/Materials/LightSource.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 06b70259956805b41b0e1e1aa030628c 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/NonConvexPolyhedra.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BastianUrbach/rtswplusd/6152d65d13221e4803c0cab2be6d2220f3ea75d9/Assets/NonConvexPolyhedra.blend -------------------------------------------------------------------------------- /Assets/NonConvexPolyhedra.blend.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c1c8fbf0a20eef479b7abfceff15ee9 3 | ModelImporter: 4 | serializedVersion: 21100 5 | internalIDToNameTable: [] 6 | externalObjects: {} 7 | materials: 8 | materialImportMode: 0 9 | materialName: 0 10 | materialSearch: 1 11 | materialLocation: 1 12 | animations: 13 | legacyGenerateAnimations: 4 14 | bakeSimulation: 0 15 | resampleCurves: 1 16 | optimizeGameObjects: 0 17 | motionNodeName: 18 | rigImportErrors: 19 | rigImportWarnings: 20 | animationImportErrors: 21 | animationImportWarnings: 22 | animationRetargetingWarnings: 23 | animationDoRetargetingWarnings: 0 24 | importAnimatedCustomProperties: 0 25 | importConstraints: 0 26 | animationCompression: 1 27 | animationRotationError: 0.5 28 | animationPositionError: 0.5 29 | animationScaleError: 0.5 30 | animationWrapMode: 0 31 | extraExposedTransformPaths: [] 32 | extraUserProperties: [] 33 | clipAnimations: [] 34 | isReadable: 1 35 | meshes: 36 | lODScreenPercentages: [] 37 | globalScale: 1 38 | meshCompression: 0 39 | addColliders: 0 40 | useSRGBMaterialColor: 1 41 | sortHierarchyByName: 1 42 | importVisibility: 1 43 | importBlendShapes: 1 44 | importCameras: 1 45 | importLights: 1 46 | fileIdsGeneration: 2 47 | swapUVChannels: 0 48 | generateSecondaryUV: 0 49 | useFileUnits: 1 50 | keepQuads: 0 51 | weldVertices: 1 52 | bakeAxisConversion: 0 53 | preserveHierarchy: 0 54 | skinWeightsMode: 0 55 | maxBonesPerVertex: 4 56 | minBoneWeight: 0.001 57 | meshOptimizationFlags: -1 58 | indexFormat: 0 59 | secondaryUVAngleDistortion: 8 60 | secondaryUVAreaDistortion: 15.000001 61 | secondaryUVHardAngle: 88 62 | secondaryUVMarginMethod: 1 63 | secondaryUVMinLightmapResolution: 40 64 | secondaryUVMinObjectScale: 1 65 | secondaryUVPackMargin: 4 66 | useFileScale: 1 67 | tangentSpace: 68 | normalSmoothAngle: 60 69 | normalImportMode: 0 70 | tangentImportMode: 3 71 | normalCalculationMode: 4 72 | legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 73 | blendShapeNormalImportMode: 1 74 | normalSmoothingSource: 0 75 | referencedClips: [] 76 | importAnimation: 1 77 | humanDescription: 78 | serializedVersion: 3 79 | human: [] 80 | skeleton: [] 81 | armTwist: 0.5 82 | foreArmTwist: 0.5 83 | upperLegTwist: 0.5 84 | legTwist: 0.5 85 | armStretch: 0.05 86 | legStretch: 0.05 87 | feetSpacing: 0 88 | globalScale: 1 89 | rootMotionBoneName: 90 | hasTranslationDoF: 0 91 | hasExtraRoot: 0 92 | skeletonHasParents: 1 93 | lastHumanDescriptionAvatarSource: {instanceID: 0} 94 | autoGenerateAvatarMappingIfUnspecified: 1 95 | animationType: 2 96 | humanoidOversampling: 1 97 | avatarSetup: 0 98 | addHumanoidExtraRootOnlyWhenUsingAvatar: 1 99 | additionalBone: 0 100 | userData: 101 | assetBundleName: 102 | assetBundleVariant: 103 | -------------------------------------------------------------------------------- /Assets/PostProcessing Profile.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0191122fa452dda449cf33bce5724b04 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Precomputed Data.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36912a84d57f62a42b91c354f43def93 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Precomputed Data/Corner.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bfae2d3901feee6478e6e1793b403184 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Precomputed Data/Cube.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 68ee6ab8c3a32e945a4137ac3aa8e59c, type: 3} 13 | m_Name: Cube 14 | m_EditorClassIdentifier: 15 | mesh: {fileID: -5495902117074765545, guid: 8457d03241413464f8105e48f96edd9a, type: 3} 16 | nodes: 17 | - plane: {x: 1, y: 0, z: 0, w: -0.5} 18 | left: 1 19 | right: 9 20 | - plane: {x: 0, y: 0, z: 1, w: -0.5} 21 | left: 2 22 | right: 4 23 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 24 | left: 26 25 | right: 3 26 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 27 | left: 27 28 | right: 28 29 | - plane: {x: 0, y: -0, z: -1, w: -0.5} 30 | left: 5 31 | right: 7 32 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 33 | left: 29 34 | right: 6 35 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 36 | left: 30 37 | right: 31 38 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 39 | left: 32 40 | right: 8 41 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 42 | left: 33 43 | right: 34 44 | - plane: {x: -1, y: 0, z: 0, w: -0.5} 45 | left: 10 46 | right: 18 47 | - plane: {x: 0, y: 0, z: 1, w: -0.5} 48 | left: 11 49 | right: 13 50 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 51 | left: 35 52 | right: 12 53 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 54 | left: 36 55 | right: 37 56 | - plane: {x: 0, y: -0, z: -1, w: -0.5} 57 | left: 14 58 | right: 16 59 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 60 | left: 38 61 | right: 15 62 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 63 | left: 39 64 | right: 40 65 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 66 | left: 41 67 | right: 17 68 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 69 | left: 42 70 | right: 43 71 | - plane: {x: 0, y: 0, z: 1, w: -0.5} 72 | left: 19 73 | right: 21 74 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 75 | left: 44 76 | right: 20 77 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 78 | left: 45 79 | right: 46 80 | - plane: {x: 0, y: -0, z: -1, w: -0.5} 81 | left: 22 82 | right: 24 83 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 84 | left: 47 85 | right: 23 86 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 87 | left: 48 88 | right: 49 89 | - plane: {x: 0, y: -1, z: 0, w: -0.5} 90 | left: 50 91 | right: 25 92 | - plane: {x: 0, y: 1, z: 0, w: -0.5} 93 | left: 51 94 | right: 52 95 | - plane: {x: 0, y: 0, z: 0, w: 0} 96 | left: -1 97 | right: -7 98 | - plane: {x: 0, y: 0, z: 0, w: 0} 99 | left: -7 100 | right: -13 101 | - plane: {x: 0, y: 0, z: 0, w: 0} 102 | left: -13 103 | right: -19 104 | - plane: {x: 0, y: 0, z: 0, w: 0} 105 | left: -19 106 | right: -25 107 | - plane: {x: 0, y: 0, z: 0, w: 0} 108 | left: -25 109 | right: -31 110 | - plane: {x: 0, y: 0, z: 0, w: 0} 111 | left: -31 112 | right: -37 113 | - plane: {x: 0, y: 0, z: 0, w: 0} 114 | left: -37 115 | right: -43 116 | - plane: {x: 0, y: 0, z: 0, w: 0} 117 | left: -43 118 | right: -49 119 | - plane: {x: 0, y: 0, z: 0, w: 0} 120 | left: -49 121 | right: -53 122 | - plane: {x: 0, y: 0, z: 0, w: 0} 123 | left: -53 124 | right: -59 125 | - plane: {x: 0, y: 0, z: 0, w: 0} 126 | left: -59 127 | right: -65 128 | - plane: {x: 0, y: 0, z: 0, w: 0} 129 | left: -65 130 | right: -71 131 | - plane: {x: 0, y: 0, z: 0, w: 0} 132 | left: -71 133 | right: -77 134 | - plane: {x: 0, y: 0, z: 0, w: 0} 135 | left: -77 136 | right: -83 137 | - plane: {x: 0, y: 0, z: 0, w: 0} 138 | left: -83 139 | right: -89 140 | - plane: {x: 0, y: 0, z: 0, w: 0} 141 | left: -89 142 | right: -95 143 | - plane: {x: 0, y: 0, z: 0, w: 0} 144 | left: -95 145 | right: -101 146 | - plane: {x: 0, y: 0, z: 0, w: 0} 147 | left: -101 148 | right: -105 149 | - plane: {x: 0, y: 0, z: 0, w: 0} 150 | left: -105 151 | right: -111 152 | - plane: {x: 0, y: 0, z: 0, w: 0} 153 | left: -111 154 | right: -117 155 | - plane: {x: 0, y: 0, z: 0, w: 0} 156 | left: -117 157 | right: -121 158 | - plane: {x: 0, y: 0, z: 0, w: 0} 159 | left: -121 160 | right: -127 161 | - plane: {x: 0, y: 0, z: 0, w: 0} 162 | left: -127 163 | right: -133 164 | - plane: {x: 0, y: 0, z: 0, w: 0} 165 | left: -133 166 | right: -137 167 | - plane: {x: 0, y: 0, z: 0, w: 0} 168 | left: -137 169 | right: -141 170 | - plane: {x: 0, y: 0, z: 0, w: 0} 171 | left: -141 172 | right: -145 173 | - plane: {x: 0, y: 0, z: 0, w: 0} 174 | left: -145 175 | right: -145 176 | silhouettes: 00000000050000000400000001000000000000000300000007000000020000000100000000000000060000000700000005000000020000000100000000000000030000000700000005000000020000000100000004000000060000000700000003000000050000000400000006000000000000000300000002000000020000000100000004000000060000000000000003000000020000000100000000000000060000000700000003000000050000000400000001000000000000000300000002000000020000000100000000000000030000000400000005000000020000000300000000000000060000000100000002000000030000000700000006000000040000000400000005000000020000000300000007000000060000000400000005000000070000000300000000000000010000000100000002000000050000000700000006000000000000000400000005000000070000000600000000000000010000000400000005000000070000000300000000000000060000000100000002000000050000000700000006000000040000000400000005000000070000000600000003000000000000000600000007000000050000000200000001000000020000000300000007000000050000000400000007000000050000000200000003000000030000000000000001000000040000000600000007000000010000000200000005000000040000000600000000000000000000000100000004000000060000000300000000000000060000000700000001000000020000000500000004000000 177 | vertices: 178 | - {x: 0.5, y: -0.5, z: -0.5} 179 | - {x: 0.5, y: 0.5, z: -0.5} 180 | - {x: 0.5, y: 0.5, z: 0.5} 181 | - {x: 0.5, y: -0.5, z: 0.5} 182 | - {x: -0.5, y: 0.5, z: -0.5} 183 | - {x: -0.5, y: 0.5, z: 0.5} 184 | - {x: -0.5, y: -0.5, z: -0.5} 185 | - {x: -0.5, y: -0.5, z: 0.5} 186 | root: 0 187 | isInitialized: 1 188 | -------------------------------------------------------------------------------- /Assets/Precomputed Data/Cube.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b69970ac98d62874fb51648baa992278 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Precomputed Data/ExtrudedCube.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db8f762c377b46745a897cfda3194166 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Precomputed Data/Hole.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1816b41c0c02c2349aa0c52b5fe348a8 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Precomputed Data/HoleTriangulation.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b74d4c28e46df854289a16ac85df90e6 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e1d843ac97b2bc4b914fba136f5f1ac 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/BSP.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7465147249c783143b89cf51579b7653 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Double3.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using static System.Math; 19 | using static Utility; 20 | 21 | public struct Double3 { 22 | public double x, y, z; 23 | 24 | public Double3(double x, double y, double z) { 25 | this.x = x; 26 | this.y = y; 27 | this.z = z; 28 | } 29 | 30 | public double sqrMagnitude => x * x + y * y + z * z; 31 | public double magnitude => Sqrt(sqrMagnitude); 32 | public Double3 normalized => Normalize(this); 33 | 34 | public override bool Equals(object obj) { 35 | if (obj is Double3 other) { 36 | if (Abs(other.x - this.x) > epsilon) return false; 37 | if (Abs(other.y - this.y) > epsilon) return false; 38 | if (Abs(other.z - this.z) > epsilon) return false; 39 | 40 | return true; 41 | } else { 42 | return false; 43 | } 44 | } 45 | 46 | public static Double3 operator +(Double3 a, Double3 b) { 47 | return new Double3(a.x + b.x, a.y + b.y, a.z + b.z); 48 | } 49 | 50 | public static Double3 operator -(Double3 a, Double3 b) { 51 | return new Double3(a.x - b.x, a.y - b.y, a.z - b.z); 52 | } 53 | 54 | public static Double3 operator *(Double3 a, Double3 b) { 55 | return new Double3(a.x * b.x, a.y * b.y, a.z * b.z); 56 | } 57 | 58 | public static Double3 operator /(Double3 a, Double3 b) { 59 | return new Double3(a.x / b.x, a.y / b.y, a.z / b.z); 60 | } 61 | 62 | public static bool operator ==(Double3 a, Double3 b) => a.Equals(b); 63 | public static bool operator !=(Double3 a, Double3 b) => !a.Equals(b); 64 | public static Double3 operator -(Double3 a) => new Double3(-a.x, -a.y, -a.z); 65 | 66 | public static implicit operator Double3(double d) { 67 | return new Double3(d, d, d); 68 | } 69 | 70 | public static implicit operator Double3(UnityEngine.Vector3 v) { 71 | return new Double3(v.x, v.y, v.z); 72 | } 73 | 74 | public static explicit operator UnityEngine.Vector3(Double3 v) { 75 | return new UnityEngine.Vector3((float)v.x, (float)v.y, (float)v.z); 76 | } 77 | 78 | public static implicit operator Double3((float x, float y, float z) v) { 79 | return new Double3(v.x, v.y, v.z); 80 | } 81 | 82 | public static double Dot(Double3 a, Double3 b) { 83 | return a.x * b.x + a.y * b.y + a.z * b.z; 84 | } 85 | 86 | public static Double3 Cross(Double3 a, Double3 b) { 87 | return new Double3( 88 | a.y * b.z - a.z * b.y, 89 | a.z * b.x - a.x * b.z, 90 | a.x * b.y - a.y * b.x 91 | ); 92 | } 93 | 94 | public static double SqrDistance(Double3 a, Double3 b) { 95 | return (b - a).sqrMagnitude; 96 | } 97 | 98 | public static double Distance(Double3 a, Double3 b) { 99 | return (b - a).magnitude; 100 | } 101 | 102 | public static double Angle(Double3 a, Double3 b) { 103 | var denominator = Sqrt(Dot(a, a) * Dot(b, b)); 104 | if (denominator < 0.000001) return 0; 105 | 106 | var dot = Dot(a, b) / denominator; 107 | dot = dot < -1 ? -1 : dot > 1 ? 1 : dot; // clamp 108 | 109 | return Acos(dot); 110 | } 111 | 112 | public static double SignedAngle(Double3 from, Double3 to, Double3 axis) { 113 | var sign = Dot(Cross(from, to), axis) > 0 ? 1 : -1; 114 | return sign * Angle(Cross(axis, from), Cross(axis, to)); 115 | } 116 | 117 | public static Double3 Normalize(Double3 a) => a / a.magnitude; 118 | 119 | public static Double3 Lerp(Double3 a, Double3 b, double t) { 120 | t = t < 0 ? 0 : t > 1 ? 1 : t; 121 | return a + (b - a) * t; 122 | } 123 | 124 | public override int GetHashCode() { 125 | int hashCode = -1255691586; 126 | hashCode = hashCode * -1521134295 + x.GetHashCode(); 127 | hashCode = hashCode * -1521134295 + y.GetHashCode(); 128 | hashCode = hashCode * -1521134295 + z.GetHashCode(); 129 | return hashCode; 130 | } 131 | 132 | public static readonly Double3 zero = new Double3(0, 0, 0); 133 | public static readonly Double3 left = new Double3(-1, 0, 0); 134 | public static readonly Double3 right = new Double3(+1, 0, 0); 135 | public static readonly Double3 down = new Double3(0, -1, 0); 136 | public static readonly Double3 up = new Double3(0, +1, 0); 137 | public static readonly Double3 back = new Double3(0, 0, -1); 138 | public static readonly Double3 forward = new Double3(0, 0, +1); 139 | } -------------------------------------------------------------------------------- /Assets/Scripts/Double3.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f9fb93a3ee57d1f4b80960dbb1c8ec81 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a76ec7177b9305a43a18e2d95c1625ae 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/Editor/ConvexSilhouetteBSPEditor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEditor; 19 | using UnityEngine; 20 | 21 | [CustomEditor(typeof(ConvexSilhouetteBSP))] 22 | public class ConvexSilhouetteBSPEditor : Editor { 23 | static string infoText = $"A {nameof(ConvexSilhouetteBSP)} stores precomputed data that is required for {nameof(ConvexLTCLight)} and {nameof(ConvexRaytracedLight)}. Note that this method only works well for relatively simple convex polyhedra. Precomputation time and size of precomputed data grow rapidly with the complexity of the polyhedron."; 24 | 25 | public override void OnInspectorGUI() { 26 | GUILayout.Label(infoText, EditorStyles.wordWrappedLabel); 27 | GUILayout.Space(EditorGUIUtility.singleLineHeight); 28 | 29 | serializedObject.Update(); 30 | 31 | var meshProperty = serializedObject.FindProperty("mesh"); 32 | EditorGUILayout.PropertyField(meshProperty); 33 | 34 | serializedObject.ApplyModifiedProperties(); 35 | 36 | if (GUILayout.Button("Bake")) { 37 | var target = this.target as ConvexSilhouetteBSP; 38 | target.isInitialized = false; 39 | target.Initialize(); 40 | serializedObject.Update(); 41 | } 42 | 43 | var isInitializedProperty = serializedObject.FindProperty("isInitialized"); 44 | 45 | if (isInitializedProperty.boolValue) { 46 | EditorGUILayout.HelpBox("Precomputation has been completed", MessageType.Info); 47 | } else { 48 | EditorGUILayout.HelpBox("Precomputation is required. Press \"Bake\" to start the precomputation phase. This operation may take a while.", MessageType.Warning); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Assets/Scripts/Editor/ConvexSilhouetteBSPEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4ec004d4ac4e9c2499c309b07deb2f7c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Editor/NonConvexSilhouetteBSPEditor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEditor; 19 | using UnityEngine; 20 | 21 | [CustomEditor(typeof(NonConvexSilhouetteBSP))] 22 | public class NonConvexSilhouetteBSPEditor : Editor { 23 | static string infoText = $"A {nameof(NonConvexSilhouetteBSP)} stores precomputed data that is required for {nameof(NonConvexLTCLight)} and {nameof(StarShapedRaytracedLight)}. Note that this method only works well for very simple polyhedra. Precomputation time and size of precomputed data grow rapidly with the complexity of the polyhedron."; 24 | 25 | public override void OnInspectorGUI() { 26 | GUILayout.Label(infoText, EditorStyles.wordWrappedLabel); 27 | GUILayout.Space(EditorGUIUtility.singleLineHeight); 28 | 29 | serializedObject.Update(); 30 | 31 | var meshProperty = serializedObject.FindProperty("mesh"); 32 | EditorGUILayout.PropertyField(meshProperty); 33 | 34 | serializedObject.ApplyModifiedProperties(); 35 | 36 | if (GUILayout.Button("Bake")) { 37 | var target = this.target as NonConvexSilhouetteBSP; 38 | target.isInitialized = false; 39 | target.Initialize(); 40 | serializedObject.Update(); 41 | } 42 | 43 | var isInitializedProperty = serializedObject.FindProperty("isInitialized"); 44 | 45 | if (isInitializedProperty.boolValue) { 46 | EditorGUILayout.HelpBox("Precomputation has been completed", MessageType.Info); 47 | } else { 48 | EditorGUILayout.HelpBox("Precomputation is required. Press \"Bake\" to start the precomputation phase. This operation may take a while.", MessageType.Warning); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Assets/Scripts/Editor/NonConvexSilhouetteBSPEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3adcef570fc282468776e08748a1d21 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Editor/SilhouetteTriangulationBSPEditor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEditor; 19 | using UnityEngine; 20 | 21 | [CustomEditor(typeof(SilhouetteTriangulationBSP))] 22 | public class SilhouetteTriangulationBSPEditor : Editor { 23 | static string infoText = $"A {nameof(SilhouetteTriangulationBSP)} stores precomputed data that is required for {nameof(NonStarShapedRaytracedLight)}. Note that this method only works well for very simple polyhedra. Precomputation time and size of precomputed data grow rapidly with the complexity of the polyhedron."; 24 | 25 | public override void OnInspectorGUI() { 26 | GUILayout.Label(infoText, EditorStyles.wordWrappedLabel); 27 | GUILayout.Space(EditorGUIUtility.singleLineHeight); 28 | 29 | serializedObject.Update(); 30 | 31 | var meshProperty = serializedObject.FindProperty("mesh"); 32 | EditorGUILayout.PropertyField(meshProperty); 33 | 34 | serializedObject.ApplyModifiedProperties(); 35 | 36 | if (GUILayout.Button("Bake")) { 37 | var target = this.target as SilhouetteTriangulationBSP; 38 | target.isInitialized = false; 39 | target.Initialize(); 40 | serializedObject.Update(); 41 | } 42 | 43 | var isInitializedProperty = serializedObject.FindProperty("isInitialized"); 44 | 45 | if (isInitializedProperty.boolValue) { 46 | EditorGUILayout.HelpBox("Precomputation has been completed", MessageType.Info); 47 | } else { 48 | EditorGUILayout.HelpBox("Precomputation is required. Press \"Bake\" to start the precomputation phase. This operation may take a while.", MessageType.Warning); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Assets/Scripts/Editor/SilhouetteTriangulationBSPEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fd63051bf4c2f184f8c678e218d6279d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/FastList.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | // A simple array list that can start large and never shrinks to avoid unnecessary allocations 19 | public struct FastList { 20 | public T[] data; 21 | public int count; 22 | int length; 23 | 24 | public FastList(int startLength) { 25 | data = new T[startLength]; 26 | length = startLength; 27 | count = 0; 28 | } 29 | 30 | public void Add(T item) { 31 | if (count == length) { 32 | var newData = new T[length * 2]; 33 | System.Array.Copy(data, newData, length); 34 | data = newData; 35 | length *= 2; 36 | } 37 | 38 | data[count++] = item; 39 | } 40 | 41 | public void RemoveAt(int i) { 42 | data[i] = data[--count]; 43 | } 44 | 45 | public T this[int i] { 46 | get => data[i]; 47 | set => data[i] = value; 48 | } 49 | } -------------------------------------------------------------------------------- /Assets/Scripts/FastList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 513b65b0fce2fb743a96e48cca43cb75 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/FreeCamera.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEngine; 19 | 20 | public class FreeCamera : MonoBehaviour { 21 | public float speed; 22 | public float acceleration; 23 | public float sensitivity; 24 | 25 | private Vector3 velocity; 26 | 27 | void Update() { 28 | transform.Rotate(Vector3.up, Input.GetAxis("Mouse X") * sensitivity, Space.World); 29 | transform.Rotate(Vector3.left, Input.GetAxis("Mouse Y") * sensitivity, Space.Self); 30 | 31 | Vector3 targetVelocity = transform.forward * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal"); 32 | velocity = Vector3.MoveTowards(velocity, targetVelocity * speed, acceleration * Time.deltaTime); 33 | transform.Translate(velocity * Time.deltaTime, Space.World); 34 | } 35 | } -------------------------------------------------------------------------------- /Assets/Scripts/FreeCamera.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 94807de7fe1a25849b2ecadb80e2c1f1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7b9bc0c7db01b9c48abc01e9f23283d2 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights/ConvexLTCLight.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEngine; 19 | using UnityEngine.Rendering; 20 | using static Utility; 21 | 22 | public class ConvexLTCLight : CustomDeferredLight { 23 | public ConvexSilhouetteBSP bsp; 24 | public LtcLookupTable ggxLookupTable; 25 | public Material material; 26 | 27 | [ColorUsage(false, true)] 28 | public Color color; 29 | 30 | Material lightMaterial; 31 | ComputeBuffer vertices; 32 | ComputeBuffer nodes; 33 | ComputeBuffer silhouettes; 34 | CommandBuffer commandBuffer; 35 | MaterialPropertyBlock materialProperties; 36 | 37 | public override void InitializeLight() { 38 | lightMaterial = new Material(Shader.Find("CustomDeferredLights/ConvexLTCLight")); 39 | 40 | vertices = bsp.GetVertexBuffer(); 41 | nodes = bsp.GetNodeBuffer(); 42 | silhouettes = bsp.GetSilhouetteBuffer(); 43 | 44 | SetShaderProperty(lightMaterial, "_Vertices", vertices); 45 | SetShaderProperty(lightMaterial, "_Nodes", nodes); 46 | SetShaderProperty(lightMaterial, "_SilhouetteVertices", silhouettes); 47 | SetShaderProperty(lightMaterial, "_Root", bsp.root); 48 | SetShaderProperty(lightMaterial, "_LtcMatrixGgx", ggxLookupTable.matrixLUT); 49 | SetShaderProperty(lightMaterial, "_LtcAmplitudeGgx", ggxLookupTable.amplitudeLUT); 50 | 51 | materialProperties = new MaterialPropertyBlock(); 52 | commandBuffer = new CommandBuffer(); 53 | } 54 | 55 | public override void UpdateLight() { 56 | SetShaderProperty(lightMaterial, "_Color", color); 57 | SetShaderProperty(lightMaterial, "_LightToWorld", transform.localToWorldMatrix); 58 | SetShaderProperty(lightMaterial, "_WorldToLight", transform.worldToLocalMatrix); 59 | 60 | commandBuffer.Clear(); 61 | Blit(commandBuffer, BuiltinRenderTextureType.CurrentActive, lightMaterial); 62 | 63 | if (material) { 64 | Color.RGBToHSV(color, out var h, out var s, out var v); 65 | SetShaderProperty(materialProperties, "_Color", Color.HSVToRGB(h, s, 1)); 66 | Graphics.DrawMesh(bsp.mesh, transform.localToWorldMatrix, material, 0, null, 0, materialProperties); 67 | } 68 | } 69 | 70 | public override void DisposeLight() { 71 | Dispose(vertices); 72 | Dispose(nodes); 73 | Dispose(silhouettes); 74 | } 75 | 76 | public override void InitializeCamera(Camera camera, out object state) { 77 | camera.AddCommandBuffer(CameraEvent.AfterLighting, commandBuffer); 78 | state = null; 79 | } 80 | 81 | public override void DisposeCamera(Camera camera, object state) { 82 | if (camera) { 83 | camera.RemoveCommandBuffer(CameraEvent.AfterLighting, commandBuffer); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Assets/Scripts/Lights/ConvexLTCLight.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 53fc06ca419544f4e9d3301e7a8f579a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - bsp: {instanceID: 0} 8 | - ggxLookupTable: {fileID: 11400000, guid: ed545418c52aa2f49b3fc947eb07027b, type: 2} 9 | - material: {instanceID: 0} 10 | executionOrder: 0 11 | icon: {instanceID: 0} 12 | userData: 13 | assetBundleName: 14 | assetBundleVariant: 15 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights/ConvexRaytracedLight.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEngine; 19 | using UnityEngine.Experimental.Rendering; 20 | using UnityEngine.Rendering; 21 | using static Utility; 22 | 23 | [RequireComponent(typeof(MeshFilter))] 24 | [RequireComponent(typeof(MeshRenderer))] 25 | public class ConvexRaytracedLight : CustomDeferredLight { 26 | public ConvexSilhouetteBSP bsp; 27 | public LtcLookupTable ggxLookupTable; 28 | public RayTracingShader shader; 29 | 30 | public int raysPerPixel; 31 | public Material additiveBlit; 32 | 33 | [ColorUsage(false, true)] 34 | public Color color; 35 | 36 | ComputeBuffer vertices; 37 | ComputeBuffer nodes; 38 | ComputeBuffer silhouettes; 39 | MaterialPropertyBlock materialProperties; 40 | 41 | struct State { 42 | public CommandBuffer commandBuffer; 43 | } 44 | 45 | public override void InitializeLight() { 46 | vertices = bsp.GetVertexBuffer(); 47 | nodes = bsp.GetNodeBuffer(); 48 | silhouettes = bsp.GetSilhouetteBuffer(); 49 | 50 | materialProperties = new MaterialPropertyBlock(); 51 | materialProperties.SetInt("_LightSourceID", gameObject.GetInstanceID()); 52 | 53 | var renderer = GetComponent(); 54 | renderer.SetPropertyBlock(materialProperties); 55 | 56 | var meshFilter = GetComponent(); 57 | meshFilter.sharedMesh = bsp.mesh; 58 | } 59 | 60 | public override void UpdateLight() { 61 | Color.RGBToHSV(color, out var h, out var s, out var v); 62 | materialProperties.SetVector("_Color", Color.HSVToRGB(h, s, 1)); 63 | var renderer = GetComponent(); 64 | renderer.SetPropertyBlock(materialProperties); 65 | } 66 | 67 | public override void InitializeCamera(Camera camera, out object state) { 68 | State s = default; 69 | 70 | s.commandBuffer = new CommandBuffer(); 71 | s.commandBuffer.name = gameObject.name; 72 | camera.AddCommandBuffer(CameraEvent.AfterLighting, s.commandBuffer); 73 | 74 | state = s; 75 | } 76 | 77 | public override void UpdateCamera(Camera camera, ref object state) { 78 | var s = (State)state; 79 | 80 | var target = Raytracing.GetTarget(camera); 81 | var accelerator = Raytracing.GetAccelerator(); 82 | var lightSourceID = gameObject.GetInstanceID(); 83 | 84 | s.commandBuffer.Clear(); 85 | 86 | SetShaderProperty(s.commandBuffer, shader, "_Color", color); 87 | SetShaderProperty(s.commandBuffer, shader, "_LightToWorld", transform.localToWorldMatrix); 88 | SetShaderProperty(s.commandBuffer, shader, "_WorldToLight", transform.worldToLocalMatrix); 89 | SetShaderProperty(s.commandBuffer, shader, "_Vertices", vertices); 90 | SetShaderProperty(s.commandBuffer, shader, "_Nodes", nodes); 91 | SetShaderProperty(s.commandBuffer, shader, "_SilhouetteVertices", silhouettes); 92 | SetShaderProperty(s.commandBuffer, shader, "_Root", bsp.root); 93 | SetShaderProperty(s.commandBuffer, shader, "_RaysPerPixel", raysPerPixel); 94 | SetShaderProperty(s.commandBuffer, shader, "_LtcMatrixGgx", ggxLookupTable.matrixLUT); 95 | SetShaderProperty(s.commandBuffer, shader, "_LtcAmplitudeGgx", ggxLookupTable.amplitudeLUT); 96 | SetShaderProperty(s.commandBuffer, shader, "_Target", target); 97 | SetShaderProperty(s.commandBuffer, shader, "_Accelerator", accelerator); 98 | SetShaderProperty(s.commandBuffer, shader, "_LightSourceID", lightSourceID); 99 | SetShaderProperty(s.commandBuffer, shader, "_Center", transform.position); 100 | 101 | s.commandBuffer.SetRayTracingShaderPass(shader, "Raytracing"); 102 | s.commandBuffer.DispatchRays(shader, "RayGeneration", (uint)camera.pixelWidth, (uint)camera.pixelHeight, 1, camera); 103 | s.commandBuffer.Blit(target, BuiltinRenderTextureType.CurrentActive, additiveBlit); 104 | } 105 | 106 | public override void DisposeLight() { 107 | Dispose(vertices); 108 | Dispose(nodes); 109 | Dispose(silhouettes); 110 | } 111 | 112 | public override void DisposeCamera(Camera camera, object state) { 113 | var s = (State)state; 114 | 115 | if (camera) camera.RemoveCommandBuffer(CameraEvent.AfterLighting, s.commandBuffer); 116 | 117 | Dispose(s.commandBuffer); 118 | } 119 | } -------------------------------------------------------------------------------- /Assets/Scripts/Lights/ConvexRaytracedLight.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6805dc41fbde3c64984f4f8f1ecd0074 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - bsp: {instanceID: 0} 8 | - ggxLookupTable: {fileID: 11400000, guid: ed545418c52aa2f49b3fc947eb07027b, type: 2} 9 | - shader: {fileID: 4807578003741378534, guid: 3c0a0eec915eec244891afd39e1f154c, type: 3} 10 | - additiveBlit: {fileID: 2100000, guid: aaa7d692effc835498880f9e36bc9aaa, type: 2} 11 | executionOrder: 0 12 | icon: {instanceID: 0} 13 | userData: 14 | assetBundleName: 15 | assetBundleVariant: 16 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights/CustomDeferredLight.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | using UnityEngine; 20 | 21 | // Base class for custom deferred lights 22 | public class CustomDeferredLight : MonoBehaviour { 23 | Dictionary states = new Dictionary(); 24 | 25 | public virtual void InitializeLight() { } 26 | public virtual void UpdateLight() { } 27 | public virtual void DisposeLight() { } 28 | 29 | public virtual void InitializeCamera(Camera camera, out object state) => state = null; 30 | public virtual void UpdateCamera(Camera camera, ref object state) { } 31 | public virtual void DisposeCamera(Camera camera, object state) { } 32 | public virtual void UpdateCameraResolution(Camera camera, ref object state) { } 33 | 34 | struct InternalState { 35 | public int width; 36 | public int height; 37 | public object state; 38 | } 39 | 40 | void Start() { 41 | InitializeLight(); 42 | } 43 | 44 | void Update() { 45 | UpdateLight(); 46 | 47 | foreach (var pair in states) { 48 | if (!pair.Key) { 49 | DisposeCamera(pair.Key, pair.Value.state); 50 | states.Remove(pair.Key); 51 | } 52 | } 53 | 54 | foreach (var camera in Camera.allCameras) { 55 | if (!camera) continue; 56 | 57 | InternalState state; 58 | 59 | if (!states.TryGetValue(camera, out state)) { 60 | InitializeCamera(camera, out state.state); 61 | } 62 | 63 | if (state.width != camera.pixelWidth | state.height != camera.pixelHeight) { 64 | UpdateCameraResolution(camera, ref state.state); 65 | state.width = camera.pixelWidth; 66 | state.height = camera.pixelHeight; 67 | } 68 | 69 | UpdateCamera(camera, ref state.state); 70 | states[camera] = state; 71 | } 72 | } 73 | 74 | void OnDestroy() { 75 | foreach (var pair in states) { 76 | DisposeCamera(pair.Key, pair.Value.state); 77 | } 78 | 79 | DisposeLight(); 80 | } 81 | } -------------------------------------------------------------------------------- /Assets/Scripts/Lights/CustomDeferredLight.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56553fc80cfbe7c479ddfad39d1c076f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights/NonConvexLTCLight.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEngine; 19 | using UnityEngine.Rendering; 20 | using static Utility; 21 | 22 | public class NonConvexLTCLight : CustomDeferredLight { 23 | public NonConvexSilhouetteBSP bsp; 24 | public LtcLookupTable ggxLookupTable; 25 | public Material material; 26 | 27 | [ColorUsage(false, true)] 28 | public Color color; 29 | 30 | Material lightMaterial; 31 | ComputeBuffer vertices; 32 | ComputeBuffer nodes; 33 | ComputeBuffer silhouettes; 34 | CommandBuffer commandBuffer; 35 | MaterialPropertyBlock materialProperties; 36 | 37 | public override void InitializeLight() { 38 | lightMaterial = new Material(Shader.Find("CustomDeferredLights/NonConvexLTCLight")); 39 | 40 | vertices = bsp.GetVertexBuffer(); 41 | nodes = bsp.GetNodeBuffer(); 42 | silhouettes = bsp.GetSilhouetteBuffer(); 43 | 44 | SetShaderProperty(lightMaterial, "_Vertices", vertices); 45 | SetShaderProperty(lightMaterial, "_Nodes", nodes); 46 | SetShaderProperty(lightMaterial, "_SilhouetteEdges", silhouettes); 47 | SetShaderProperty(lightMaterial, "_Root", bsp.root); 48 | SetShaderProperty(lightMaterial, "_LtcMatrixGgx", ggxLookupTable.matrixLUT); 49 | SetShaderProperty(lightMaterial, "_LtcAmplitudeGgx", ggxLookupTable.amplitudeLUT); 50 | 51 | materialProperties = new MaterialPropertyBlock(); 52 | commandBuffer = new CommandBuffer(); 53 | } 54 | 55 | public override void UpdateLight() { 56 | SetShaderProperty(lightMaterial, "_Color", color); 57 | SetShaderProperty(lightMaterial, "_LightToWorld", transform.localToWorldMatrix); 58 | SetShaderProperty(lightMaterial, "_WorldToLight", transform.worldToLocalMatrix); 59 | 60 | commandBuffer.Clear(); 61 | Blit(commandBuffer, BuiltinRenderTextureType.CurrentActive, lightMaterial); 62 | 63 | if (material) { 64 | Color.RGBToHSV(color, out var h, out var s, out var v); 65 | SetShaderProperty(materialProperties, "_Color", Color.HSVToRGB(h, s, 1)); 66 | Graphics.DrawMesh(bsp.mesh, transform.localToWorldMatrix, material, 0, null, 0, materialProperties); 67 | } 68 | } 69 | 70 | public override void DisposeLight() { 71 | Dispose(vertices); 72 | Dispose(nodes); 73 | Dispose(silhouettes); 74 | } 75 | 76 | public override void InitializeCamera(Camera camera, out object state) { 77 | camera.AddCommandBuffer(CameraEvent.AfterLighting, commandBuffer); 78 | state = null; 79 | } 80 | 81 | public override void DisposeCamera(Camera camera, object state) { 82 | if (camera) { 83 | camera.RemoveCommandBuffer(CameraEvent.AfterLighting, commandBuffer); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights/NonConvexLTCLight.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b375b0acbb913cf46bfe5b1d7aed13e5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - bsp: {instanceID: 0} 8 | - ggxLookupTable: {fileID: 11400000, guid: ed545418c52aa2f49b3fc947eb07027b, type: 2} 9 | - material: {instanceID: 0} 10 | executionOrder: 0 11 | icon: {instanceID: 0} 12 | userData: 13 | assetBundleName: 14 | assetBundleVariant: 15 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights/NonStarShapedRaytracedLight.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEngine; 19 | using UnityEngine.Experimental.Rendering; 20 | using UnityEngine.Rendering; 21 | using static Utility; 22 | 23 | [RequireComponent(typeof(MeshFilter))] 24 | [RequireComponent(typeof(MeshRenderer))] 25 | public class NonStarShapedRaytracedLight : CustomDeferredLight { 26 | public NonConvexSilhouetteBSP silhouetteBSP; 27 | public SilhouetteTriangulationBSP triangulationBSP; 28 | public LtcLookupTable ggxLookupTable; 29 | public RayTracingShader shader; 30 | 31 | public int raysPerPixel; 32 | public Material additiveBlit; 33 | 34 | [ColorUsage(false, true)] 35 | public Color color; 36 | 37 | ComputeBuffer vertices; 38 | ComputeBuffer nodes; 39 | ComputeBuffer silhouettes; 40 | ComputeBuffer triangulations; 41 | ComputeBuffer triangulationNodes; 42 | MaterialPropertyBlock materialProperties; 43 | 44 | struct State { 45 | public CommandBuffer commandBuffer; 46 | } 47 | 48 | public override void InitializeLight() { 49 | vertices = silhouetteBSP.GetVertexBuffer(); 50 | nodes = silhouetteBSP.GetNodeBuffer(); 51 | silhouettes = silhouetteBSP.GetSilhouetteBuffer(); 52 | 53 | triangulations = triangulationBSP.GetSilhouetteBuffer(); 54 | triangulationNodes = triangulationBSP.GetNodeBuffer(); 55 | 56 | materialProperties = new MaterialPropertyBlock(); 57 | materialProperties.SetInt("_LightSourceID", gameObject.GetInstanceID()); 58 | 59 | var renderer = GetComponent(); 60 | renderer.SetPropertyBlock(materialProperties); 61 | 62 | var meshFilter = GetComponent(); 63 | meshFilter.sharedMesh = silhouetteBSP.mesh; 64 | } 65 | 66 | public override void UpdateLight() { 67 | Color.RGBToHSV(color, out var h, out var s, out var v); 68 | materialProperties.SetVector("_Color", Color.HSVToRGB(h, s, 1)); 69 | var renderer = GetComponent(); 70 | renderer.SetPropertyBlock(materialProperties); 71 | } 72 | 73 | public override void InitializeCamera(Camera camera, out object state) { 74 | State s = default; 75 | 76 | s.commandBuffer = new CommandBuffer(); 77 | s.commandBuffer.name = gameObject.name; 78 | camera.AddCommandBuffer(CameraEvent.AfterLighting, s.commandBuffer); 79 | 80 | state = s; 81 | } 82 | 83 | public override void UpdateCamera(Camera camera, ref object state) { 84 | var s = (State)state; 85 | 86 | var target = Raytracing.GetTarget(camera); 87 | var accelerator = Raytracing.GetAccelerator(); 88 | var lightSourceID = gameObject.GetInstanceID(); 89 | 90 | s.commandBuffer.Clear(); 91 | 92 | SetShaderProperty(s.commandBuffer, shader, "_Color", color); 93 | SetShaderProperty(s.commandBuffer, shader, "_LightToWorld", transform.localToWorldMatrix); 94 | SetShaderProperty(s.commandBuffer, shader, "_WorldToLight", transform.worldToLocalMatrix); 95 | SetShaderProperty(s.commandBuffer, shader, "_Vertices", vertices); 96 | SetShaderProperty(s.commandBuffer, shader, "_Nodes", nodes); 97 | SetShaderProperty(s.commandBuffer, shader, "_TriangulationNodes", triangulationNodes); 98 | SetShaderProperty(s.commandBuffer, shader, "_SilhouetteEdges", silhouettes); 99 | SetShaderProperty(s.commandBuffer, shader, "_SilhouetteTriangles", triangulations); 100 | SetShaderProperty(s.commandBuffer, shader, "_Root", silhouetteBSP.root); 101 | SetShaderProperty(s.commandBuffer, shader, "_RaysPerPixel", raysPerPixel); 102 | SetShaderProperty(s.commandBuffer, shader, "_LtcMatrixGgx", ggxLookupTable.matrixLUT); 103 | SetShaderProperty(s.commandBuffer, shader, "_LtcAmplitudeGgx", ggxLookupTable.amplitudeLUT); 104 | SetShaderProperty(s.commandBuffer, shader, "_Target", target); 105 | SetShaderProperty(s.commandBuffer, shader, "_Accelerator", accelerator); 106 | SetShaderProperty(s.commandBuffer, shader, "_LightSourceID", lightSourceID); 107 | SetShaderProperty(s.commandBuffer, shader, "_Center", transform.position); 108 | 109 | s.commandBuffer.SetRayTracingShaderPass(shader, "Raytracing"); 110 | s.commandBuffer.DispatchRays(shader, "RayGeneration", (uint)camera.pixelWidth, (uint)camera.pixelHeight, 1, camera); 111 | s.commandBuffer.Blit(target, BuiltinRenderTextureType.CurrentActive, additiveBlit); 112 | } 113 | 114 | public override void DisposeLight() { 115 | Dispose(vertices); 116 | Dispose(nodes); 117 | Dispose(silhouettes); 118 | } 119 | 120 | public override void DisposeCamera(Camera camera, object state) { 121 | var s = (State)state; 122 | 123 | if (camera) camera.RemoveCommandBuffer(CameraEvent.AfterLighting, s.commandBuffer); 124 | 125 | Dispose(s.commandBuffer); 126 | } 127 | } -------------------------------------------------------------------------------- /Assets/Scripts/Lights/NonStarShapedRaytracedLight.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 322cc00ca3363a64bb80382070ca1ccd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - silhouetteBSP: {instanceID: 0} 8 | - triangulationBSP: {instanceID: 0} 9 | - ggxLookupTable: {fileID: 11400000, guid: ed545418c52aa2f49b3fc947eb07027b, type: 2} 10 | - shader: {fileID: 4807578003741378534, guid: d1c0094f9bcada94fbee1c2a3f232533, type: 3} 11 | - additiveBlit: {fileID: 2100000, guid: aaa7d692effc835498880f9e36bc9aaa, type: 2} 12 | executionOrder: 0 13 | icon: {instanceID: 0} 14 | userData: 15 | assetBundleName: 16 | assetBundleVariant: 17 | -------------------------------------------------------------------------------- /Assets/Scripts/Lights/StarShapedRaytracedLight.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEngine; 19 | using UnityEngine.Experimental.Rendering; 20 | using UnityEngine.Rendering; 21 | using static Utility; 22 | 23 | [RequireComponent(typeof(MeshFilter))] 24 | [RequireComponent(typeof(MeshRenderer))] 25 | public class StarShapedRaytracedLight : CustomDeferredLight { 26 | public NonConvexSilhouetteBSP bsp; 27 | public LtcLookupTable ggxLookupTable; 28 | public RayTracingShader shader; 29 | 30 | public int raysPerPixel; 31 | public Material additiveBlit; 32 | 33 | [ColorUsage(false, true)] 34 | public Color color; 35 | 36 | ComputeBuffer vertices; 37 | ComputeBuffer nodes; 38 | ComputeBuffer silhouettes; 39 | MaterialPropertyBlock materialProperties; 40 | 41 | struct State { 42 | public CommandBuffer commandBuffer; 43 | } 44 | 45 | public override void InitializeLight() { 46 | vertices = bsp.GetVertexBuffer(); 47 | nodes = bsp.GetNodeBuffer(); 48 | silhouettes = bsp.GetSilhouetteBuffer(); 49 | 50 | materialProperties = new MaterialPropertyBlock(); 51 | materialProperties.SetInt("_LightSourceID", gameObject.GetInstanceID()); 52 | 53 | var renderer = GetComponent(); 54 | renderer.SetPropertyBlock(materialProperties); 55 | 56 | var meshFilter = GetComponent(); 57 | meshFilter.sharedMesh = bsp.mesh; 58 | } 59 | 60 | public override void UpdateLight() { 61 | Color.RGBToHSV(color, out var h, out var s, out var v); 62 | materialProperties.SetVector("_Color", Color.HSVToRGB(h, s, 1)); 63 | var renderer = GetComponent(); 64 | renderer.SetPropertyBlock(materialProperties); 65 | } 66 | 67 | public override void InitializeCamera(Camera camera, out object state) { 68 | State s = default; 69 | 70 | s.commandBuffer = new CommandBuffer(); 71 | s.commandBuffer.name = gameObject.name; 72 | camera.AddCommandBuffer(CameraEvent.AfterLighting, s.commandBuffer); 73 | 74 | state = s; 75 | } 76 | 77 | public override void UpdateCamera(Camera camera, ref object state) { 78 | var s = (State)state; 79 | 80 | var target = Raytracing.GetTarget(camera); 81 | var accelerator = Raytracing.GetAccelerator(); 82 | var lightSourceID = gameObject.GetInstanceID(); 83 | 84 | s.commandBuffer.Clear(); 85 | 86 | SetShaderProperty(s.commandBuffer, shader, "_Color", color); 87 | SetShaderProperty(s.commandBuffer, shader, "_LightToWorld", transform.localToWorldMatrix); 88 | SetShaderProperty(s.commandBuffer, shader, "_WorldToLight", transform.worldToLocalMatrix); 89 | SetShaderProperty(s.commandBuffer, shader, "_Vertices", vertices); 90 | SetShaderProperty(s.commandBuffer, shader, "_Nodes", nodes); 91 | SetShaderProperty(s.commandBuffer, shader, "_SilhouetteEdges", silhouettes); 92 | SetShaderProperty(s.commandBuffer, shader, "_Root", bsp.root); 93 | SetShaderProperty(s.commandBuffer, shader, "_RaysPerPixel", raysPerPixel); 94 | SetShaderProperty(s.commandBuffer, shader, "_LtcMatrixGgx", ggxLookupTable.matrixLUT); 95 | SetShaderProperty(s.commandBuffer, shader, "_LtcAmplitudeGgx", ggxLookupTable.amplitudeLUT); 96 | SetShaderProperty(s.commandBuffer, shader, "_Target", target); 97 | SetShaderProperty(s.commandBuffer, shader, "_Accelerator", accelerator); 98 | SetShaderProperty(s.commandBuffer, shader, "_LightSourceID", lightSourceID); 99 | SetShaderProperty(s.commandBuffer, shader, "_Center", transform.position); 100 | 101 | s.commandBuffer.SetRayTracingShaderPass(shader, "Raytracing"); 102 | s.commandBuffer.DispatchRays(shader, "RayGeneration", (uint)camera.pixelWidth, (uint)camera.pixelHeight, 1, camera); 103 | s.commandBuffer.Blit(target, BuiltinRenderTextureType.CurrentActive, additiveBlit); 104 | } 105 | 106 | public override void DisposeLight() { 107 | Dispose(vertices); 108 | Dispose(nodes); 109 | Dispose(silhouettes); 110 | } 111 | 112 | public override void DisposeCamera(Camera camera, object state) { 113 | var s = (State)state; 114 | 115 | if (camera) camera.RemoveCommandBuffer(CameraEvent.AfterLighting, s.commandBuffer); 116 | 117 | Dispose(s.commandBuffer); 118 | } 119 | } -------------------------------------------------------------------------------- /Assets/Scripts/Lights/StarShapedRaytracedLight.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 78c4a83699be71d4fac99ff203fc6eae 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - bsp: {instanceID: 0} 8 | - ggxLookupTable: {fileID: 11400000, guid: ed545418c52aa2f49b3fc947eb07027b, type: 2} 9 | - shader: {fileID: 4807578003741378534, guid: 68f6123689559864bb99099db42a0201, type: 3} 10 | - additiveBlit: {fileID: 2100000, guid: aaa7d692effc835498880f9e36bc9aaa, type: 2} 11 | executionOrder: 0 12 | icon: {instanceID: 0} 13 | userData: 14 | assetBundleName: 15 | assetBundleVariant: 16 | -------------------------------------------------------------------------------- /Assets/Scripts/LtcLookupTable.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using UnityEngine; 19 | 20 | [CreateAssetMenu] 21 | public class LtcLookupTable : ScriptableObject { 22 | public Texture2D matrixLUT; 23 | public Texture2D amplitudeLUT; 24 | } -------------------------------------------------------------------------------- /Assets/Scripts/LtcLookupTable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bee70f2751d308e48875767d8a5c0066 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Plane.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using static Double3; 19 | using static System.Math; 20 | using static Utility; 21 | 22 | public struct Plane { 23 | public double x, y, z, d; 24 | public Double3 normal => new Double3(x, y, z); 25 | 26 | public Plane(double x, double y, double z, double d) { 27 | this.x = x; 28 | this.y = y; 29 | this.z = z; 30 | this.d = d; 31 | } 32 | 33 | public Plane(Double3 normal, double distance) { 34 | normal = Normalize(normal); 35 | x = normal.x; 36 | y = normal.y; 37 | z = normal.z; 38 | d = distance; 39 | } 40 | 41 | public Plane(Double3 a, Double3 b, Double3 c) { 42 | var normal = Normalize(Cross(b - a, c - a)); 43 | x = normal.x; 44 | y = normal.y; 45 | z = normal.z; 46 | d = -Dot(normal, a); 47 | } 48 | 49 | public Plane(Double3 normal, Double3 point) { 50 | x = normal.x; 51 | y = normal.y; 52 | z = normal.z; 53 | d = -Dot(normal, point); 54 | } 55 | 56 | public Plane flipped => new Plane(-x, -y, -z, -d); 57 | public double GetDistanceToPoint(Double3 p) => x * p.x + y * p.y + z * p.z + d; 58 | public bool GetSide(Double3 p) => GetDistanceToPoint(p) > 0; 59 | public Double3 ClosestPointOnPlane(Double3 p) => p - normal * GetDistanceToPoint(p); 60 | 61 | public static bool operator ==(Plane a, Plane b) => a.Equals(b); 62 | public static bool operator !=(Plane a, Plane b) => !a.Equals(b); 63 | 64 | public static explicit operator UnityEngine.Vector4(Plane a) => new UnityEngine.Vector4((float)a.x, (float)a.y, (float)a.z, (float)a.d); 65 | 66 | public override bool Equals(object obj) { 67 | if (obj is Plane other) { 68 | if (Abs(other.x - this.x) > epsilon) return false; 69 | if (Abs(other.y - this.y) > epsilon) return false; 70 | if (Abs(other.z - this.z) > epsilon) return false; 71 | if (Abs(other.d - this.d) > epsilon) return false; 72 | 73 | return true; 74 | } else { 75 | return false; 76 | } 77 | } 78 | 79 | public override int GetHashCode() { 80 | int hashCode = -1371227472; 81 | hashCode = hashCode * -1521134295 + x.GetHashCode(); 82 | hashCode = hashCode * -1521134295 + y.GetHashCode(); 83 | hashCode = hashCode * -1521134295 + z.GetHashCode(); 84 | hashCode = hashCode * -1521134295 + d.GetHashCode(); 85 | return hashCode; 86 | } 87 | } -------------------------------------------------------------------------------- /Assets/Scripts/Plane.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f78ea18e1d45d174d871cf9c6b2d8909 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Polyhedron.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 716c3c1f4411c164bb49cec973d76948 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Raytracing.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | using UnityEngine; 20 | using UnityEngine.Experimental.Rendering; 21 | using static Utility; 22 | 23 | // Builds and stores the RayTracingAccelerationStructure used for GPU ray tracing and provides easy 24 | // access to random write buffers for each camera. 25 | public class Raytracing : MonoBehaviour { 26 | public LayerMask layers; 27 | public RayTracingAccelerationStructure.RayTracingModeMask modeMask; 28 | static RayTracingAccelerationStructure accelerator; 29 | 30 | static Dictionary renderTargets; 31 | 32 | void Start() { 33 | var settings = new RayTracingAccelerationStructure.RASSettings(); 34 | settings.layerMask = layers; 35 | settings.managementMode = RayTracingAccelerationStructure.ManagementMode.Automatic; 36 | settings.rayTracingModeMask = modeMask; 37 | accelerator = new RayTracingAccelerationStructure(settings); 38 | accelerator.Build(); 39 | 40 | renderTargets = new Dictionary(); 41 | } 42 | 43 | public static RayTracingAccelerationStructure GetAccelerator() { 44 | return accelerator; 45 | } 46 | 47 | void OnDestroy() { 48 | accelerator.Release(); 49 | } 50 | 51 | void Update() { 52 | foreach (var pair in renderTargets) { 53 | if (!pair.Key) { 54 | Dispose(pair.Value); 55 | renderTargets.Remove(pair.Key); 56 | } 57 | } 58 | } 59 | 60 | public static RenderTexture GetTarget(Camera camera) { 61 | if (!camera) return null; 62 | 63 | if ( 64 | !renderTargets.TryGetValue(camera, out var renderTarget) || 65 | renderTarget.width != camera.pixelWidth || 66 | renderTarget.height != camera.pixelHeight 67 | ) { 68 | Dispose(renderTarget); 69 | renderTarget = new RenderTexture(camera.pixelWidth, camera.pixelHeight, 0, DefaultFormat.HDR); 70 | renderTarget.enableRandomWrite = true; 71 | renderTarget.Create(); 72 | renderTargets[camera] = renderTarget; 73 | } 74 | 75 | return renderTarget; 76 | } 77 | } -------------------------------------------------------------------------------- /Assets/Scripts/Raytracing.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 41d6534abfc86fa449ee9468de247c02 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 100 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0be20737b66dacb4e90185f5473d2140 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/ConvexSilhouetteBSP.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | using System.Linq; 20 | using UnityEngine; 21 | using static Utility; 22 | 23 | [CreateAssetMenu] 24 | public class ConvexSilhouetteBSP : ScriptableObject { 25 | public Mesh mesh; 26 | 27 | public Node[] nodes; 28 | public uint[] silhouettes; 29 | public Vector3[] vertices; 30 | public int root; 31 | public bool isInitialized = false; 32 | 33 | Polyhedron _polyhedron; 34 | public Polyhedron polyhedron => _polyhedron ??= new Polyhedron(mesh); 35 | 36 | [ContextMenu("Bake")] 37 | public void Initialize() { 38 | var bounds = new Bounds(Vector3.zero, Vector3.one * 100); 39 | var planes = polyhedron.planes; 40 | var bsp = new TwoPassBSP(planes, bounds); 41 | 42 | root = bsp.root; 43 | 44 | var nodes = new List(); 45 | 46 | foreach (var node in bsp.nodes) { 47 | nodes.Add(new Node { 48 | plane = (Vector4)node.plane, 49 | left = node.left, 50 | right = node.right 51 | }); 52 | } 53 | 54 | // Create silhouette list and add dummy element to prevent index 0 from being used because 55 | // leaves are recognized by the sign of the index 56 | var silhouettes = new List(); 57 | silhouettes.Add(0); 58 | 59 | for (int i = 0; i < bsp.nodes.Count; i++) { 60 | var node = nodes[i]; 61 | 62 | if (node.left < 0) { 63 | node.left = MakeLeaf(-node.left, bsp, silhouettes, nodes); 64 | } 65 | 66 | if (node.right < 0) { 67 | node.right = MakeLeaf(-node.right, bsp, silhouettes, nodes); 68 | } 69 | 70 | nodes[i] = node; 71 | } 72 | 73 | this.silhouettes = silhouettes.ToArray(); 74 | this.nodes = nodes.ToArray(); 75 | this.vertices = polyhedron.vertices.Select(v => (Vector3)v).ToArray(); 76 | 77 | isInitialized = true; 78 | } 79 | 80 | int MakeLeaf(int index, TwoPassBSP bsp, List silhouettes, List nodes) { 81 | var silhouette = polyhedron.GetOrderedConvexSilhouette(bsp.leaves[index]); 82 | 83 | var left = silhouettes.Count; 84 | silhouettes.AddRange(silhouette); 85 | var right = silhouettes.Count; 86 | 87 | nodes.Add(new Node { left = -left, right = -right }); 88 | 89 | return nodes.Count - 1; 90 | } 91 | 92 | public ComputeBuffer GetNodeBuffer() { 93 | if (!isInitialized) Initialize(); 94 | return Buffer(nodes); 95 | } 96 | 97 | public ComputeBuffer GetSilhouetteBuffer() { 98 | if (!isInitialized) Initialize(); 99 | return Buffer(silhouettes); 100 | } 101 | 102 | public ComputeBuffer GetVertexBuffer() { 103 | if (!isInitialized) Initialize(); 104 | return Buffer(vertices); 105 | } 106 | 107 | [System.Serializable] 108 | public struct Node { 109 | public Vector4 plane; 110 | public int left; 111 | public int right; 112 | } 113 | } -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/ConvexSilhouetteBSP.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68ee6ab8c3a32e945a4137ac3aa8e59c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/ConvexSilhouettes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | using static Utility; 20 | using static Polyhedron; 21 | using static Double3; 22 | 23 | public static class ConvexSilhouettes { 24 | // Enumerates the contour edges of a polyhedron as seen from the given point. For convex 25 | // polyhedra these are the silhouette edges. 26 | // This is significantly faster than GetSilhouette() (implemented in NonConvexSilhouettes) 27 | public static IEnumerable GetConvexSilhouette(this Polyhedron polyhedron, Double3 point) { 28 | foreach (var edge in polyhedron.edges) { 29 | if (polyhedron.IsContourEdge(edge, point, out var orientedEdge)) { 30 | yield return orientedEdge; 31 | } 32 | } 33 | } 34 | 35 | // Enumerates the ordered silhouette vertices of a polyhedron as seen from the given point. 36 | // This is significantly faster than GetOrderedSilhouette() (implemented in NonConvexSilhouettes) 37 | public static IEnumerable GetOrderedConvexSilhouette(this Polyhedron polyhedron, Double3 point) { 38 | var silhouetteEdgeCount = 0; 39 | var edges = polyhedron.silhouetteCalculationBuffer; 40 | 41 | foreach (var edge in polyhedron.GetConvexSilhouette(point)) { 42 | edges[silhouetteEdgeCount++] = edge; 43 | } 44 | 45 | if (silhouetteEdgeCount == 0) yield break; 46 | 47 | var first = edges[0].start; 48 | var current = first; 49 | 50 | while (silhouetteEdgeCount > 0) { 51 | bool foundNextEdge = false; 52 | 53 | for (int i = 0; i < silhouetteEdgeCount; i++) { 54 | var edge = edges[i]; 55 | 56 | if (edge.start == current) { 57 | yield return (uint)current; 58 | current = edge.end; 59 | Swap(ref edges[--silhouetteEdgeCount], ref edges[i]); 60 | foundNextEdge = true; 61 | break; 62 | } 63 | } 64 | 65 | if (!foundNextEdge) break; 66 | } 67 | } 68 | 69 | // Check if an edge is a contour edge when viewed from a given point. If it is then orientedEdge 70 | // is either the edge or a flipped version of it such that all silhouette edges go around the 71 | // polyhedron in the same direction 72 | public static bool IsContourEdge(this Polyhedron polyhedron, Edge edge, Double3 point, out Edge orientedEdge) { 73 | var normal1 = polyhedron.planes[edge.plane1].normal; 74 | var normal2 = polyhedron.planes[edge.plane2].normal; 75 | 76 | var relative = polyhedron.vertices[edge.start] - point; 77 | 78 | var visible1 = Dot(relative, normal1) > 0; 79 | var visible2 = Dot(relative, normal2) > 0; 80 | 81 | if (visible1) { 82 | orientedEdge = edge; 83 | } else { 84 | orientedEdge = new Edge { start = edge.end, end = edge.start, plane1 = edge.plane2, plane2 = edge.plane1 }; 85 | } 86 | 87 | return visible1 != visible2; 88 | } 89 | } -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/ConvexSilhouettes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 682353cd6de22074c9b45189ba963741 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/NonConvexSilhouetteBSP.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | using UnityEngine; 20 | using static Utility; 21 | using static Double3; 22 | using System.Linq; 23 | 24 | [CreateAssetMenu] 25 | public class NonConvexSilhouetteBSP : ScriptableObject { 26 | public Mesh mesh; 27 | 28 | public Node[] nodes; 29 | public SilhouetteEdge[] silhouettes; 30 | public Vector3[] vertices; 31 | public int root; 32 | public bool isInitialized = false; 33 | 34 | Polyhedron _polyhedron; 35 | public Polyhedron polyhedron => _polyhedron ??= new Polyhedron(mesh); 36 | 37 | [ContextMenu("Bake")] 38 | public void Initialize() { 39 | var bounds = new Bounds(UnityEngine.Vector3.zero, UnityEngine.Vector3.one * 100); 40 | var planes = FindPlanes(); 41 | 42 | var bsp = new BSP(planes, bounds); 43 | 44 | root = bsp.root; 45 | 46 | var nodes = new List(); 47 | 48 | foreach (var node in bsp.nodes) { 49 | nodes.Add(new Node { 50 | plane = (Vector4)node.plane, 51 | left = node.left, 52 | right = node.right 53 | }); 54 | } 55 | 56 | // Create silhouette lists and add dummy element to prevent index 0 from being used because 57 | // leaves are recognized by the sign of the index 58 | var silhouettes = new List(); 59 | silhouettes.Add(new SilhouetteEdge(new SilhouetteVertex(0), new SilhouetteVertex(0))); 60 | 61 | for (int i = 0; i < bsp.nodes.Count; i++) { 62 | var node = nodes[i]; 63 | 64 | if (node.left < 0) { 65 | node.left = MakeLeaf(-node.left, bsp, silhouettes, nodes); 66 | } 67 | 68 | if (node.right < 0) { 69 | node.right = MakeLeaf(-node.right, bsp, silhouettes, nodes); 70 | } 71 | 72 | nodes[i] = node; 73 | } 74 | 75 | this.nodes = nodes.ToArray(); 76 | this.silhouettes = silhouettes.ToArray(); 77 | this.vertices = polyhedron.vertices.Select(v => (Vector3)v).ToArray(); 78 | 79 | isInitialized = true; 80 | } 81 | 82 | Plane[] FindPlanes() { 83 | var planes = new List(); 84 | 85 | for (int i = 0; i < polyhedron.edges.Length; i++) { 86 | var edge1 = polyhedron.edges[i]; 87 | 88 | var pointA1 = polyhedron.vertices[edge1.start]; 89 | var pointA2 = polyhedron.vertices[edge1.end]; 90 | 91 | var normalA1 = polyhedron.planes[edge1.plane1].normal; 92 | var normalA2 = polyhedron.planes[edge1.plane2].normal; 93 | 94 | for (int j = i + 1; j < polyhedron.edges.Length; j++) { 95 | var edge2 = polyhedron.edges[j]; 96 | 97 | var pointB1 = polyhedron.vertices[edge2.start]; 98 | var pointB2 = polyhedron.vertices[edge2.end]; 99 | 100 | var normalB1 = polyhedron.planes[edge2.plane1].normal; 101 | var normalB2 = polyhedron.planes[edge2.plane2].normal; 102 | 103 | if (CanVisiblyOverlap(pointA1, pointA2, pointB1, pointB2, normalA1, normalA2, normalB1, normalB2)) { 104 | InsertPlane(planes, pointA2, pointB1, pointB2); 105 | InsertPlane(planes, pointA1, pointB1, pointB2); 106 | InsertPlane(planes, pointA1, pointA2, pointB2); 107 | InsertPlane(planes, pointA1, pointA2, pointB1); 108 | } 109 | } 110 | } 111 | 112 | planes.AddRange(polyhedron.planes); 113 | 114 | return planes.ToArray(); 115 | } 116 | 117 | void InsertPlane(List list, Double3 a, Double3 b, Double3 c) { 118 | if (a == b || b == c || c == a) return; 119 | 120 | var plane = new Plane(a, b, c); 121 | 122 | for (int i = 0; i < list.Count; i++) { 123 | var other = list[i]; 124 | 125 | if (Dot(plane.normal, other.normal) < 0) { 126 | other = other.flipped; 127 | } 128 | 129 | if (other == plane) return; 130 | } 131 | 132 | list.Add(plane); 133 | } 134 | 135 | int MakeLeaf(int index, BSP bsp, List silhouettes, List nodes) { 136 | var position = bsp.leaves[index]; 137 | 138 | MakeLeaf(position, silhouettes, nodes); 139 | 140 | return nodes.Count - 1; 141 | } 142 | 143 | void MakeLeaf(Double3 position, List silhouettes, List nodes) { 144 | var silhouette = polyhedron.GetSilhouette(position); 145 | 146 | var left = silhouettes.Count; 147 | silhouettes.AddRange(silhouette); 148 | var right = silhouettes.Count; 149 | 150 | nodes.Add(new Node { 151 | left = -left, 152 | right = -right, 153 | plane = new Vector4((float)position.x, (float)position.y, (float)position.z, 0) 154 | }); 155 | } 156 | 157 | // We only care about pairs of edges that can overlap when seen from a point where both are contour edges 158 | bool CanVisiblyOverlap(Double3 a1, Double3 a2, Double3 b1, Double3 b2, Double3 normalA1, Double3 normalA2, Double3 normalB1, Double3 normalB2) { 159 | if (IsContour(a1 - b1, normalA1, normalA2) && IsContour(a1 - b1, normalB1, normalB2)) return true; 160 | if (IsContour(a2 - b1, normalA1, normalA2) && IsContour(a2 - b1, normalB1, normalB2)) return true; 161 | if (IsContour(a1 - b2, normalA1, normalA2) && IsContour(a1 - b2, normalB1, normalB2)) return true; 162 | if (IsContour(a2 - b2, normalA1, normalA2) && IsContour(a2 - b2, normalB1, normalB2)) return true; 163 | 164 | return false; 165 | } 166 | 167 | bool IsContour(Double3 viewDirection, Double3 normal1, Double3 normal2) { 168 | var d1 = Dot(viewDirection, normal1); 169 | var d2 = Dot(viewDirection, normal2); 170 | 171 | return d1 > epsilon & d2 < -epsilon || d1 < -epsilon & d2 > epsilon; 172 | } 173 | 174 | public ComputeBuffer GetSilhouetteBuffer() { 175 | if (!isInitialized) Initialize(); 176 | return Buffer(silhouettes); 177 | } 178 | 179 | public ComputeBuffer GetNodeBuffer() { 180 | if (!isInitialized) Initialize(); 181 | return Buffer(nodes); 182 | } 183 | 184 | public ComputeBuffer GetVertexBuffer() { 185 | if (!isInitialized) Initialize(); 186 | return Buffer(vertices); 187 | } 188 | 189 | [System.Serializable] 190 | public struct Node { 191 | public Vector4 plane; 192 | public int left; 193 | public int right; 194 | } 195 | } -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/NonConvexSilhouetteBSP.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1e5cc5ee94f7fe64d8ca60a424da6f9b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/NonConvexSilhouettes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | using System.Linq; 20 | using static Double3; 21 | using static Utility; 22 | 23 | public static class NonConvexSilhouettes { 24 | // Enumerates the silhouette edges of a polyhedron as seen from the given point. 25 | // Algorithm outline: 26 | // 1. Find contour edges 27 | // 2. Find apparent intersections of contour edges 28 | // 3. Split contour edges at intersections so that only non-intersecting segments remain 29 | // 4. Eliminate all segments where the ray through the center hits a triangle 30 | public static IEnumerable GetSilhouette(this Polyhedron polyhedron, Double3 point) { 31 | // if (polyhedron.IsInside(point)) return Enumerable.Empty(); 32 | 33 | // Find contour edges. Every silhouette edge is a segment of a contour edge 34 | var contourEdges = polyhedron.GetConvexSilhouette(point).ToList(); 35 | 36 | // Holds intersections of the current contour edge with other contour edges. 37 | // Despite being declared outside the loop for performance reasons, the content of this 38 | // array only has a meaning within one iteration 39 | // The first value is the index of the intersecting edge, the second one the position of the 40 | // intersection on the current edge as an interpolation parameter in range [0, 1] 41 | var intersections = new (int, double)[contourEdges.Count]; 42 | 43 | // Holds silhouette edges and their midpoints (for performance reasons) 44 | var silhouetteEdges = new List<(SilhouetteVertex, SilhouetteVertex, Double3)>(); 45 | 46 | // A comparer to sort intersections by their position on the edge 47 | var comparer = Comparer<(int, double)>.Create((a, b) => a.Item2.CompareTo(b.Item2)); 48 | 49 | // Split contour edges at intersections 50 | for (int i = 0; i < contourEdges.Count; i++) { 51 | var count = 0; 52 | 53 | var a = contourEdges[i]; 54 | var a1 = polyhedron.vertices[a.start]; 55 | var a2 = polyhedron.vertices[a.end]; 56 | 57 | // Find all intersections with other edges 58 | for (int j = 0; j < contourEdges.Count; j++) { 59 | if (i == j) continue; 60 | 61 | var b = contourEdges[j]; 62 | var b1 = polyhedron.vertices[b.start]; 63 | var b2 = polyhedron.vertices[b.end]; 64 | 65 | if (Polyhedron.ApparentIntersection(a1, a2, b1, b2, point, out var ta, out var tb)) { 66 | intersections[count++] = (j, ta); 67 | } 68 | } 69 | 70 | // Sort intersections by position along the edge 71 | // This often does nothing because the vast majority of contour edges have just one 72 | // or no intersections. But if there are more intersections, they need to be sorted. 73 | System.Array.Sort(intersections, 0, count, comparer); 74 | 75 | // Generate edge segments 76 | var previousVertex = new SilhouetteVertex(a.start); 77 | var previousT = 0.0; 78 | 79 | for (int j = 0; j < count; j++) { 80 | var (edgeIndex, t) = intersections[j]; 81 | var b = contourEdges[edgeIndex]; 82 | var currentVertex = new SilhouetteVertex(a.start, a.end, b.start, b.end); 83 | var midPoint = Lerp(a1, a2, (previousT + t) / 2) - point; 84 | 85 | silhouetteEdges.Add((previousVertex, currentVertex, midPoint)); 86 | previousVertex = currentVertex; 87 | previousT = t; 88 | } 89 | 90 | silhouetteEdges.Add((previousVertex, new SilhouetteVertex(a.end), Lerp(a1, a2, (previousT + 1) / 2) - point)); 91 | } 92 | 93 | // Cast a ray through the midpoint of each segment. If the ray hits a triangle of the 94 | // light source, the segment is not a silhouette edge 95 | foreach (var (a, b, c) in polyhedron.triangles) { 96 | var A = polyhedron.vertices[a] - point; 97 | var B = polyhedron.vertices[b] - point; 98 | var C = polyhedron.vertices[c] - point; 99 | 100 | var normalAB = Cross(A, B).normalized; 101 | var normalBC = Cross(B, C).normalized; 102 | var normalCA = Cross(C, A).normalized; 103 | 104 | normalAB = Dot(normalAB, C) > 0 ? normalAB : -normalAB; 105 | normalBC = Dot(normalBC, A) > 0 ? normalBC : -normalBC; 106 | normalCA = Dot(normalCA, B) > 0 ? normalCA : -normalCA; 107 | 108 | var plane = new Plane(Cross(B - A, C - A), zero); 109 | 110 | for (int j = 0; j < silhouetteEdges.Count; j++) { 111 | var (v1, v2, m) = silhouetteEdges[j]; 112 | 113 | if (Dot(normalAB, m) < epsilon) continue; 114 | if (Dot(normalBC, m) < epsilon) continue; 115 | if (Dot(normalCA, m) < epsilon) continue; 116 | if (Dot(A + B + C, m) < 0) continue; 117 | 118 | // Remove segment as it's not a silhouette edge 119 | silhouetteEdges[j] = silhouetteEdges[silhouetteEdges.Count - 1]; 120 | silhouetteEdges.RemoveAt(silhouetteEdges.Count - 1); 121 | j--; 122 | } 123 | } 124 | 125 | return silhouetteEdges.Select(e => new SilhouetteEdge(e.Item1, e.Item2)); 126 | } 127 | 128 | // Like GetSilhouette but sorts closed polygons (outer boundary and holes) together 129 | public static IEnumerable GetOrderedSilhouette(this Polyhedron polyhedron, Double3 point) { 130 | var edges = polyhedron.GetSilhouette(point).ToList(); 131 | 132 | for (int i = 0; i < edges.Count; i++) { 133 | var end = edges[i].end; 134 | 135 | for (int j = i + 1; j < edges.Count; j++) { 136 | var start = edges[j].start; 137 | 138 | if (end == start) { 139 | var temp = edges[j]; 140 | edges[j] = edges[i + 1]; 141 | edges[i + 1] = temp; 142 | break; 143 | } 144 | } 145 | } 146 | 147 | return edges; 148 | } 149 | } -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/NonConvexSilhouettes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9cdf7d8a49f627f45bd75643519196de 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SilhouetteEdge.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | [System.Serializable] 19 | public struct SilhouetteEdge { 20 | public SilhouetteVertex start; 21 | public SilhouetteVertex end; 22 | 23 | public SilhouetteEdge(SilhouetteVertex start, SilhouetteVertex end) { 24 | this.start = start; 25 | this.end = end; 26 | } 27 | } -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SilhouetteEdge.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8562ee81ca88e33469a6359b9e367a64 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SilhouetteTriangle.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | [System.Serializable] 19 | public struct SilhouetteTriangle { 20 | public SilhouetteVertex a, b, c; 21 | 22 | public SilhouetteTriangle(SilhouetteVertex a, SilhouetteVertex b, SilhouetteVertex c) { 23 | this.a = a; 24 | this.b = b; 25 | this.c = c; 26 | } 27 | } -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SilhouetteTriangle.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e3803ece466f664aa1ff029bd6e6030 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SilhouetteTriangulationBSP.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4900225f5202bb84d8d37c190a260812 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SilhouetteVertex.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System; 19 | using static Double3; 20 | 21 | // One vertex of the silhouette of a polyhedron, given in one of two different ways: 22 | // 23 | // Case 1: the vertex is a vertex of the polyhedron 24 | // Case 2: the vertex is the apparent intersection of two edges as seen from a point 25 | // 26 | // Indices are encoded as bytes so the polyhedron can only have up to 256 vertices. 27 | // This struct can be passed to a shader as an uint 28 | [Serializable] 29 | public struct SilhouetteVertex { 30 | public uint data; 31 | 32 | uint a1 => (data >> 0) & 0xff; 33 | uint a2 => (data >> 8) & 0xff; 34 | uint b1 => (data >> 16) & 0xff; 35 | uint b2 => (data >> 24) & 0xff; 36 | 37 | bool isPolyhedronVertex => a1 == a2; 38 | public bool isEdgeIntersection => a1 != b1; 39 | 40 | // Vertex is a vertex of the polyhedron 41 | public SilhouetteVertex(uint index) { 42 | data = index | index << 8 | index << 16 | index << 24; 43 | } 44 | 45 | // Vertex is the apparent intersection of two edges 46 | public SilhouetteVertex(uint a1, uint a2, uint b1, uint b2) { 47 | if (b1 < a1) (a1, a2, b1, b2) = (b1, b2, a1, a2); 48 | 49 | data = a1 | a2 << 8 | b1 << 16 | b2 << 24; 50 | } 51 | 52 | public override bool Equals(object other) { 53 | return other is SilhouetteVertex v && v.data == data; 54 | } 55 | 56 | public override int GetHashCode() => data.GetHashCode(); 57 | public static bool operator ==(SilhouetteVertex a, SilhouetteVertex b) => a.data == b.data; 58 | public static bool operator !=(SilhouetteVertex a, SilhouetteVertex b) => a.data != b.data; 59 | 60 | // Returns the edge that both a and b lie on 61 | public static (uint, uint) GetSharedEdge(SilhouetteVertex a, SilhouetteVertex b) { 62 | if (a.isPolyhedronVertex && b.isPolyhedronVertex) { 63 | return (a.a1, b.a1); 64 | } 65 | 66 | if (a.isEdgeIntersection && b.isEdgeIntersection) { 67 | if (a.a1 == b.a1 || a.a1 == b.b1) return (a.a1, a.a2); 68 | if (a.b1 == b.a1 || a.b1 == b.b1) return (a.b1, a.b2); 69 | } 70 | 71 | if (a.isEdgeIntersection) { 72 | if (a.a1 == b.a1 || a.a2 == b.a1) { 73 | return (a.a1, a.a2); 74 | } else { 75 | return (a.b1, a.b2); 76 | } 77 | } else if (b.isEdgeIntersection) { 78 | if (b.a1 == a.a1 || b.a2 == a.a1) { 79 | return (b.a1, b.a2); 80 | } else { 81 | return (b.b1, b.b2); 82 | } 83 | } 84 | 85 | throw new Exception("Unexpected silhouette edge configuration. This exception should be unreachable"); 86 | } 87 | 88 | public Double3 GetPosition(Polyhedron polyhedron, Double3 observer) { 89 | if (isEdgeIntersection) { 90 | var A1 = polyhedron.vertices[a1]; 91 | var A2 = polyhedron.vertices[a2]; 92 | var B1 = polyhedron.vertices[b1]; 93 | var B2 = polyhedron.vertices[b2]; 94 | 95 | Polyhedron.ApparentIntersection(A1, A2, B1, B2, observer, out var ta, out var tb); 96 | 97 | return Lerp(A1, A2, ta); 98 | } else { 99 | return polyhedron.vertices[data & 0xff]; 100 | } 101 | } 102 | 103 | public Double3 GetDirection(Polyhedron polyhedron, Double3 observer) { 104 | return (GetPosition(polyhedron, observer) - observer).normalized; 105 | } 106 | } -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SilhouetteVertex.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2e9585093b1c23649bb9bd6139381261 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/SphericalTriangulation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2c5ba842fca36245a10d8d24087bb60 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/TriangulatedSilhouettes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | using System.Linq; 20 | using static Double3; 21 | 22 | public static class TriangulatedSilhouettes { 23 | const double epsilon = 0.000001; 24 | 25 | // Like GetSilhouette but triangulates the silhouette 26 | public static IEnumerable GetTriangulatedSilhouette(this Polyhedron polyhedron, Double3 point, bool random = true) { 27 | var vertices = new List(); 28 | var edges = new List<(int, int)>(); 29 | 30 | foreach (var edge in polyhedron.GetSilhouette(point)) { 31 | var a1 = FindOrInsert(vertices, edge.start); 32 | var a2 = FindOrInsert(vertices, edge.end); 33 | edges.Add((a1, a2)); 34 | } 35 | 36 | if (edges.Count == 0) yield break; 37 | 38 | var vertexDirections = vertices.Select(v => v.GetDirection(polyhedron, point)).ToList(); 39 | var optionals = polyhedron.concaveVertices.Select(v => (v - point).normalized).ToList(); 40 | var triangulation = new SphericalTriangulation(edges, vertexDirections, polyhedron.concaveVertices); 41 | 42 | triangulation.Triangulate(random); 43 | 44 | var triangles = triangulation.FindTriangles().ToArray(); 45 | 46 | var rayDirections = triangles.Select(t => { 47 | var (a, b, c) = t; 48 | var A = triangulation.vertices[a]; 49 | var B = triangulation.vertices[b]; 50 | var C = triangulation.vertices[c]; 51 | return (Double3)(A + B + C); 52 | }).ToArray(); 53 | 54 | var r = polyhedron.Raycast(point, rayDirections); 55 | 56 | for (int i = 0; i < triangles.Length; i++) { 57 | var (a, b, c) = triangles[i]; 58 | 59 | a = triangulation.TranslateIndex(a, out bool aIsOptional); 60 | b = triangulation.TranslateIndex(b, out bool bIsOptional); 61 | c = triangulation.TranslateIndex(c, out bool cIsOptional); 62 | 63 | var A = aIsOptional ? new SilhouetteVertex((uint)polyhedron.concaveVertexIndices[a]) : vertices[a]; 64 | var B = bIsOptional ? new SilhouetteVertex((uint)polyhedron.concaveVertexIndices[b]) : vertices[b]; 65 | var C = cIsOptional ? new SilhouetteVertex((uint)polyhedron.concaveVertexIndices[c]) : vertices[c]; 66 | 67 | if (r[i]) yield return new SilhouetteTriangle(A, B, C); 68 | } 69 | } 70 | 71 | static int FindOrInsert(List list, SilhouetteVertex element) { 72 | for (int i = 0; i < list.Count; i++) { 73 | if (list[i] == element) return i; 74 | } 75 | 76 | list.Add(element); 77 | return list.Count - 1; 78 | } 79 | 80 | public static bool[] Raycast(this Polyhedron polyhedron, Double3 point, Double3[] directions) { 81 | bool[] r = new bool[directions.Length]; 82 | 83 | for (var i = 0; i < directions.Length; i++) { 84 | var direction = directions[i]; 85 | 86 | foreach (var (a, b, c) in polyhedron.triangles) { 87 | var A = polyhedron.vertices[a] - point; 88 | var B = polyhedron.vertices[b] - point; 89 | var C = polyhedron.vertices[c] - point; 90 | 91 | var normalAB = Cross(A, B).normalized; 92 | var normalBC = Cross(B, C).normalized; 93 | var normalCA = Cross(C, A).normalized; 94 | 95 | normalAB = Dot(normalAB, C) > 0 ? normalAB : -normalAB; 96 | normalBC = Dot(normalBC, A) > 0 ? normalBC : -normalBC; 97 | normalCA = Dot(normalCA, B) > 0 ? normalCA : -normalCA; 98 | 99 | var plane = new Plane(Cross(B - A, C - A), zero); 100 | 101 | if (Dot(normalAB, direction) < epsilon) continue; 102 | if (Dot(normalBC, direction) < epsilon) continue; 103 | if (Dot(normalCA, direction) < epsilon) continue; 104 | if (Dot(A + B + C, direction) < 0) continue; 105 | 106 | r[i] = true; 107 | } 108 | } 109 | 110 | return r; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Assets/Scripts/Silhouettes/TriangulatedSilhouettes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1476bcf2002c8b74fb8f4e43271a92ef 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/TwoPassBSP.cs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | using System.Collections.Generic; 19 | 20 | using static System.Math; 21 | using static BSP; 22 | 23 | // Binary space partitioning 24 | // 25 | // Partitions space into convex cells using the given planes and organizes these cells in a binary 26 | // tree. Each cell is a leaf in the tree and stores one representative point. 27 | // 28 | // This version builds two trees: one to find the cells and one for the structure of the tree. When 29 | // building the second tree, the resulting cells are already known. This is used to build the second 30 | // tree in a way that results in a lower average depth. 31 | public class TwoPassBSP { 32 | public List nodes = new List(); 33 | public List leaves; 34 | 35 | FastList planes = new FastList(256); 36 | FastList<(int, Double3)> points = new FastList<(int, Double3)>(256); 37 | 38 | public int root; 39 | public float averageDepth; 40 | public int leafCount = 0, depth = 0; 41 | 42 | BSP firstPass; 43 | 44 | public TwoPassBSP(IEnumerable planes, UnityEngine.Bounds bounds) { 45 | firstPass = new BSP(planes, bounds); 46 | leaves = new List(); 47 | 48 | // dummy to make sure no element 0 exists so that leaf indices are always negative and node 49 | // indices always positive 50 | leaves.Add(Double3.zero); 51 | 52 | foreach (var plane in planes) { 53 | this.planes.Add(plane); 54 | } 55 | 56 | for (int i = 1; i < firstPass.leaves.Count; i++) { 57 | points.Add((i, firstPass.leaves[i])); 58 | } 59 | 60 | root = MakeNode((0, this.planes.count), (0, points.count)); 61 | 62 | averageDepth /= leafCount; 63 | firstPass = null; 64 | } 65 | 66 | int MakeNode((int, int) planeSpan, (int, int) pointSpan) { 67 | var (planeStart, planeEnd) = planeSpan; 68 | var (pointStart, pointEnd) = pointSpan; 69 | var bestRating = 0; 70 | var bestIndex = -1; 71 | 72 | for (int i = planeStart; i < planeEnd; i++) { 73 | var plane = planes[i]; 74 | var rating = EvaluateCut(plane, pointSpan); 75 | 76 | if (rating > bestRating) { 77 | bestRating = rating; 78 | bestIndex = planes.count; 79 | } 80 | 81 | if (rating != 0) { 82 | planes.Add(plane); 83 | } 84 | } 85 | 86 | if (bestIndex < 0) { 87 | return MakeLeaf(pointStart, pointEnd); 88 | } 89 | 90 | var bestPlane = planes[bestIndex]; 91 | planes.RemoveAt(bestIndex); 92 | 93 | return MakeInnerNode((planeEnd, planes.count), pointSpan, bestPlane); 94 | } 95 | 96 | int EvaluateCut(Plane plane, (int, int) pointSpan) { 97 | var (pointStart, pointEnd) = pointSpan; 98 | 99 | int count1 = 0, count2 = 0; 100 | 101 | for (int i = pointStart; i < pointEnd; i++) { 102 | var (index, point) = points[i]; 103 | var distance = plane.GetDistanceToPoint(point); 104 | 105 | count1 += distance > 0 ? 1 : 0; 106 | count2 += distance < 0 ? 1 : 0; 107 | } 108 | 109 | return Min(count1, count2); 110 | } 111 | 112 | int MakeInnerNode((int, int) planeSpan, (int, int) pointSpan, Plane plane) { 113 | depth++; 114 | 115 | var (planeStart, planeEnd) = planeSpan; 116 | var (pointStart, pointEnd) = pointSpan; 117 | 118 | var node = new Node { plane = plane }; 119 | var nodeIndex = nodes.Count; 120 | nodes.Add(node); 121 | 122 | node.left = MakeNode(planeSpan, Split(plane, pointSpan)); 123 | node.right = MakeNode(planeSpan, Split(plane.flipped, pointSpan)); 124 | 125 | points.count = pointStart; 126 | planes.count = planeStart; 127 | 128 | nodes[nodeIndex] = node; 129 | 130 | depth--; 131 | 132 | return nodeIndex; 133 | } 134 | 135 | int MakeLeaf(int pointStart, int pointEnd) { 136 | Double3 position = Double3.zero; 137 | 138 | for (int i = pointStart; i < pointEnd; i++) { 139 | position += points[i].Item2; 140 | } 141 | 142 | position /= pointEnd - pointStart; 143 | 144 | leaves.Add(position); 145 | 146 | leafCount++; 147 | averageDepth += depth; 148 | 149 | return -(leaves.Count - 1); 150 | } 151 | 152 | (int, int) Split(Plane plane, (int, int) pointSpan) { 153 | var (pointStart, pointEnd) = pointSpan; 154 | var newPointStart = points.count; 155 | 156 | for (int i = pointStart; i < pointEnd; i++) { 157 | var (index, point) = points[i]; 158 | var distance = plane.GetDistanceToPoint(point); 159 | 160 | if (distance > 0) points.Add((index, point)); 161 | } 162 | 163 | return (newPointStart, points.count); 164 | } 165 | } -------------------------------------------------------------------------------- /Assets/Scripts/TwoPassBSP.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9cf6573495adde2418168eda15158c45 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Utility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 49714d757e4365d48a30a013f2e1ad0b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5394e255359de7444b80b58508b813f1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2cd9fccbaf21ba44eacbf38fd36179f6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/AdditiveBlit.shader: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | Shader "Hidden/AdditiveBlit" { 19 | Properties { 20 | _MainTex ("Texture", 2D) = "black" {} 21 | } 22 | 23 | SubShader { 24 | Cull Off ZWrite Off ZTest Always Blend One One 25 | 26 | Pass { 27 | CGPROGRAM 28 | #pragma vertex vert 29 | #pragma fragment frag 30 | 31 | #include "UnityCG.cginc" 32 | 33 | struct appdata { 34 | float4 vertex : POSITION; 35 | float2 uv : TEXCOORD0; 36 | }; 37 | 38 | struct v2f { 39 | float2 uv : TEXCOORD0; 40 | float4 vertex : SV_POSITION; 41 | }; 42 | 43 | v2f vert (appdata v) { 44 | v2f o; 45 | o.vertex = UnityObjectToClipPos(v.vertex); 46 | o.uv = v.uv; 47 | return o; 48 | } 49 | 50 | sampler2D _MainTex; 51 | 52 | float4 frag (v2f i) : SV_Target { 53 | return tex2D(_MainTex, i.uv); 54 | } 55 | ENDCG 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/AdditiveBlit.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eca7d6c3aa12a5243be2cd9081e0394d 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/BspCommon.hlsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | struct Node { 19 | float4 plane; 20 | int left; 21 | int right; 22 | }; 23 | 24 | float4x4 _LightToWorld; 25 | float4x4 _WorldToLight; 26 | uint _Root; 27 | float3 _Center; 28 | 29 | StructuredBuffer _Nodes; 30 | StructuredBuffer _Vertices; 31 | StructuredBuffer _SilhouetteVertices; 32 | StructuredBuffer _SilhouetteEdges; 33 | StructuredBuffer _SilhouetteTriangles; 34 | StructuredBuffer _TriangulationNodes; 35 | 36 | bool IsLeaf(Node node) { 37 | return node.left < 0; 38 | } 39 | 40 | bool IsInnerNode(Node node) { 41 | return node.left > 0; 42 | } 43 | 44 | bool GetSide(Node node, float3 position) { 45 | return dot(node.plane, float4(position, 1)) > 0; 46 | } 47 | 48 | float3 WorldToLightPos(float3 worldPosition) { 49 | float4 localPosition = mul(_WorldToLight, float4(worldPosition, 1)); 50 | return localPosition.xyz / localPosition.w; 51 | } 52 | 53 | float3 LightToWorldPos(float3 localPosition) { 54 | float4 worldPosition = mul(_LightToWorld, float4(localPosition, 1)); 55 | return worldPosition.xyz / worldPosition.w; 56 | } 57 | 58 | // Apparent intersection of edges a and b as seen from p 59 | float3 GetApparentIntersection(float3 a1, float3 a2, float3 b1, float3 b2, float3 p) { 60 | float3 normal = cross(b1 - p, b2 - p); 61 | float t = dot(p - a1, normal) / dot(a2 - a1, normal); 62 | return lerp(a1, a2, t); 63 | } 64 | 65 | float3 ComputeVertexPositionConvex(uint encoded) { 66 | float4 vertex = float4(_Vertices[encoded], 1); 67 | 68 | vertex = mul(_LightToWorld, vertex); 69 | return vertex.xyz / vertex.w; 70 | } 71 | 72 | float3 ComputeVertexPositionNonConvex(uint encoded, float3 p) { 73 | uint4 indices = (encoded >> uint4(0, 8, 16, 24)) & 0xff; 74 | float4 vertex = 1; 75 | 76 | if (indices.x == indices.y) { 77 | // Vertex is a vertex of the light source 78 | vertex.xyz = _Vertices[indices.x]; 79 | } else { 80 | // Vertex is an intersection of two polyhedron edges 81 | float3 a1 = _Vertices[indices.x]; 82 | float3 a2 = _Vertices[indices.y]; 83 | float3 b1 = _Vertices[indices.z]; 84 | float3 b2 = _Vertices[indices.w]; 85 | 86 | vertex.xyz = GetApparentIntersection(a1, a2, b1, b2, p); 87 | } 88 | 89 | vertex = mul(_LightToWorld, vertex); 90 | return vertex.xyz / vertex.w; 91 | } 92 | 93 | uint2 FindSilhouette(float3 localPosition) { 94 | Node node = _Nodes[_Root]; 95 | 96 | while (IsInnerNode(node)) { 97 | bool side = GetSide(node, localPosition); 98 | node = _Nodes[side ? node.left : node.right]; 99 | } 100 | 101 | return uint2(-node.left, -node.right); 102 | } 103 | 104 | uint2 FindTriangulation(float3 localPosition) { 105 | Node node = _TriangulationNodes[_Root]; 106 | 107 | while (IsInnerNode(node)) { 108 | bool side = GetSide(node, localPosition); 109 | node = _TriangulationNodes[side ? node.left : node.right]; 110 | } 111 | 112 | return uint2(-node.left, -node.right); 113 | } 114 | 115 | void GetTriangleConvex(uint index, uint2 range, out float3 A, out float3 B, out float3 C) { 116 | uint count = range.y - range.x; 117 | uint i1 = range.x + index; 118 | uint i2 = range.x + (index - 1 + count) % count; 119 | 120 | uint encodedB = _SilhouetteVertices[i1]; 121 | uint encodedC = _SilhouetteVertices[i2]; 122 | 123 | A = _Center; 124 | B = ComputeVertexPositionConvex(encodedB); 125 | C = ComputeVertexPositionConvex(encodedC); 126 | } 127 | 128 | void GetTriangleStarShaped(uint index, uint2 range, float3 localPosition, out float3 A, out float3 B, out float3 C) { 129 | uint2 edge = _SilhouetteEdges[index + range.x]; 130 | 131 | A = _Center; 132 | B = ComputeVertexPositionNonConvex(edge.x, localPosition); 133 | C = ComputeVertexPositionNonConvex(edge.y, localPosition); 134 | } 135 | 136 | void GetTriangleNonStarShaped(uint index, uint2 range, float3 localPosition, out float3 A, out float3 B, out float3 C) { 137 | uint3 tri = _SilhouetteTriangles[index + range.x]; 138 | 139 | A = ComputeVertexPositionNonConvex(tri.x, localPosition); 140 | B = ComputeVertexPositionNonConvex(tri.y, localPosition); 141 | C = ComputeVertexPositionNonConvex(tri.z, localPosition); 142 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/BspCommon.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 48220b593fa67244da694f183901ad8d 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/ConvexLTCLight.shader: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | Shader "CustomDeferredLights/ConvexLTCLight" { 19 | SubShader { 20 | Cull Off 21 | ZWrite Off 22 | ZTest Always 23 | Blend One One 24 | 25 | Pass { 26 | CGPROGRAM 27 | #pragma vertex Vertex 28 | #pragma fragment Fragment 29 | 30 | #include "DeferredLight.hlsl" 31 | #include "LtcCommon.hlsl" 32 | #include "LtcLut.hlsl" 33 | #include "BspCommon.hlsl" 34 | 35 | float4 _Color; 36 | 37 | float3 Lighting(float3 world, float3 view, float3 diffuseColor, float3 specularColor, float3 normal, float roughness) { 38 | float3 localPosition = WorldToLightPos(world); 39 | float NdotV = dot(normal, view); 40 | float3x3 shadingSpace = BuildShadingSpace(normal, view); 41 | 42 | float2 ggxAmplitude; 43 | 44 | LTC specular = NewLTC(GetLtcInverseTransformGgx(roughness, NdotV, ggxAmplitude), shadingSpace); 45 | LTC diffuse = NewLTC(GetLtcInverseTransformLambert(roughness, NdotV), shadingSpace); 46 | 47 | // Find silhouette start and end indices 48 | uint2 silhouette = FindSilhouette(localPosition); 49 | 50 | // Get last vertex of the silhouette and use it as first vertex of the first edge 51 | float3 vertex = ComputeVertexPositionConvex(_SilhouetteVertices[silhouette.y - 1]) - world; 52 | SetFirstVertex(diffuse, vertex); 53 | SetFirstVertex(specular, vertex); 54 | 55 | // Iterate over silhouette vertices and sum up edge contributions 56 | for (uint i = silhouette.x; i < silhouette.y; i++) { 57 | vertex = ComputeVertexPositionConvex(_SilhouetteVertices[i]) - world; 58 | 59 | SilhouetteEdge(specular, vertex); 60 | SilhouetteEdge(diffuse, vertex); 61 | } 62 | 63 | float3 d = diffuseColor * GetIntegral(diffuse) * 0; 64 | float3 s = lerp(ggxAmplitude.y, ggxAmplitude.x, specularColor) * GetIntegral(specular); 65 | 66 | return (d + s) * _Color; 67 | } 68 | ENDCG 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/ConvexLTCLight.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c213c5819d297141b08bee6e9bb98be 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/ConvexRaytracedLight.raytrace: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | #define MAX_POLYGON_VERTEX_COUNT 32 19 | 20 | #include "RaytracedDeferredLight.hlsl" 21 | #include "LtcCommon.hlsl" 22 | #include "LtcLut.hlsl" 23 | #include "BspCommon.hlsl" 24 | #include "SolidAngleSampling.hlsl" 25 | 26 | float4 _Color; 27 | uint _RaysPerPixel; 28 | 29 | float3 Lighting(float3 world, float3 view, float3 diffuseColor, float3 specularColor, float3 normal, float roughness, uint seed) { 30 | if (distance(world, _WorldSpaceCameraPos) > 100) return 0; 31 | 32 | float3 localPosition = WorldToLightPos(world); 33 | float NdotV = dot(normal, view); 34 | float3x3 shadingSpace = BuildShadingSpace(normal, view); 35 | 36 | float2 ggxAmplitude; 37 | 38 | LTC specular = NewLTC(GetLtcInverseTransformGgx(roughness, NdotV, ggxAmplitude), shadingSpace); 39 | LTC diffuse = NewLTC(GetLtcInverseTransformLambert(roughness, NdotV), shadingSpace); 40 | 41 | // Find silhouette start and end indices 42 | uint2 silhouette = FindSilhouette(localPosition); 43 | 44 | // Get last vertex of the silhouette and use it as first vertex of the first edge 45 | float3 vertex = ComputeVertexPositionConvex(_SilhouetteVertices[silhouette.y - 1]) - world; 46 | float3 previousVertex = vertex; 47 | SetFirstVertex(diffuse, vertex); 48 | SetFirstVertex(specular, vertex); 49 | 50 | float solidAngle = 0; 51 | float solidAngles[MAX_POLYGON_VERTEX_COUNT]; 52 | 53 | // Iterate over silhouette vertices and sum up edge contributions 54 | for (uint i = silhouette.x; i < silhouette.y; i++) { 55 | vertex = ComputeVertexPositionConvex(_SilhouetteVertices[i]) - world; 56 | 57 | SilhouetteEdge(specular, vertex); 58 | SilhouetteEdge(diffuse, vertex); 59 | 60 | float s = SolidAngle(_Center - world, previousVertex, vertex); 61 | solidAngle += s; 62 | solidAngles[i - silhouette.x] = s; 63 | previousVertex = vertex; 64 | } 65 | 66 | float3 d = GetIntegral(diffuse) * diffuseColor; 67 | float3 s = GetIntegral(specular) * lerp(ggxAmplitude.y, ggxAmplitude.x, specularColor); 68 | 69 | // Stochastic shadows 70 | float2 specularShadowRatio = 0; 71 | float2 diffuseShadowRatio = 0; 72 | float3 rayOrigin = world + normal * distance(_WorldSpaceCameraPos, world) / 1000; 73 | 74 | for (uint i = 0; i < _RaysPerPixel; i++) { 75 | float3 random = float3(Random(seed), Random(seed), Random(seed)); 76 | 77 | // Select triangle 78 | uint triangleIndex = 0; 79 | float partialSolidAngle = solidAngles[0]; 80 | float selectedSolidAngle = random.z * solidAngle; 81 | 82 | while (partialSolidAngle < selectedSolidAngle) { 83 | partialSolidAngle += solidAngles[++triangleIndex]; 84 | } 85 | 86 | // Calculate sample direction 87 | float3 A, B, C; 88 | GetTriangleConvex(triangleIndex, silhouette, A, B, C); 89 | SphericalTriangle t = CreateSphericalTriangle(A - world, B - world, C - world, solidAngles[triangleIndex]); 90 | float3 direction = SampleSphericalTriangle(random.xy, t); 91 | 92 | // Raytrace and evaluate BRDF 93 | float2 m = float2(!IsShadowed(rayOrigin, direction), 1); 94 | specularShadowRatio += m * Evaluate(specular, direction); 95 | diffuseShadowRatio += m * Evaluate(diffuse, direction); 96 | } 97 | 98 | d *= diffuseShadowRatio.x / max(0.0001, diffuseShadowRatio.y); 99 | s *= specularShadowRatio.x / max(0.0001, specularShadowRatio.y); 100 | 101 | return (d + s) * _Color; 102 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/ConvexRaytracedLight.raytrace.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3c0a0eec915eec244891afd39e1f154c 3 | RayTracingShaderImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/DeferredLight.hlsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | #include "UnityCG.cginc" 19 | 20 | sampler2D _CameraGBufferTexture0; 21 | sampler2D _CameraGBufferTexture1; 22 | sampler2D _CameraGBufferTexture2; 23 | sampler2D _CameraDepthTexture; 24 | 25 | float3 Lighting(float3 world, float3 view, float3 albedo, float3 specular, float3 normal, float roughness); 26 | 27 | float3 ComputeWorldRay(float2 uv) { 28 | float4 pos = float4(uv * 2 - 1, 1, 1); 29 | float3 ray = mul(unity_CameraInvProjection, pos).xyz; 30 | ray.z = -ray.z; 31 | return mul(unity_CameraToWorld, ray); 32 | } 33 | 34 | float3 ComputeWorldPos(float2 screenPos, float3 ray) { 35 | float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screenPos); 36 | depth = LinearEyeDepth(depth); 37 | return _WorldSpaceCameraPos + ray * depth; 38 | } 39 | 40 | void Vertex( 41 | in float4 vertex : POSITION, 42 | in float2 uv : TEXCOORD0, 43 | 44 | out float4 position : SV_POSITION, 45 | out float2 screenPos : TEXCOORD0, 46 | out float3 worldRay : TEXCOORD1 47 | ) { 48 | position = UnityObjectToClipPos(vertex); 49 | worldRay = ComputeWorldRay(uv); 50 | screenPos = uv; 51 | } 52 | 53 | void Fragment( 54 | in float4 position : SV_POSITION, 55 | in float2 screenPos : TEXCOORD0, 56 | in float3 worldRay : TEXCOORD1, 57 | 58 | out float4 target : SV_Target 59 | ) { 60 | float4 gbuffer0 = tex2D(_CameraGBufferTexture0, screenPos); 61 | float4 gbuffer1 = tex2D(_CameraGBufferTexture1, screenPos); 62 | float4 gbuffer2 = tex2D(_CameraGBufferTexture2, screenPos); 63 | 64 | float3 worldPos = ComputeWorldPos(screenPos, worldRay); 65 | 66 | target.a = 0; 67 | 68 | target.rgb = Lighting( 69 | worldPos, 70 | -normalize(worldRay), 71 | gbuffer0.rgb, 72 | gbuffer1.rgb, 73 | gbuffer2.xyz * 2 - 1, 74 | 1 - gbuffer1.a 75 | ); 76 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/DeferredLight.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f5ce0bbb510d0eb46904b4dca86c1980 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/LightSourceUnlit.shader: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | Shader "Unlit/LightSourceUnlit" { 19 | Properties { 20 | _Color ("Color", Color) = (1, 1, 1, 1) 21 | _LightSourceID ("Light source ID", Int) = 0 22 | } 23 | 24 | SubShader { 25 | Tags { "RenderType"="Opaque" } 26 | LOD 100 27 | 28 | Pass { 29 | CGPROGRAM 30 | #pragma vertex vert 31 | #pragma fragment frag 32 | 33 | #include "UnityCG.cginc" 34 | 35 | struct appdata { 36 | float4 vertex : POSITION; 37 | }; 38 | 39 | struct v2f { 40 | float4 vertex : SV_POSITION; 41 | }; 42 | 43 | v2f vert (appdata v) { 44 | v2f o; 45 | o.vertex = UnityObjectToClipPos(v.vertex); 46 | return o; 47 | } 48 | 49 | float4 _Color; 50 | 51 | float4 frag (v2f i) : SV_Target { 52 | return _Color; 53 | } 54 | ENDCG 55 | } 56 | } 57 | 58 | SubShader { 59 | Tags { "LightMode"="Raytracing" } 60 | 61 | Pass { 62 | Name "Raytracing" 63 | 64 | HLSLPROGRAM 65 | #pragma raytracing ClosestHit 66 | 67 | int _LightSourceID; 68 | 69 | struct Payload { int lightSourceID; }; 70 | struct AttributeData { float2 barycentrics; }; 71 | 72 | [shader("closesthit")] 73 | void ClosestHit(inout Payload payload : SV_RayPayload, AttributeData attributes : SV_IntersectionAttributes) { 74 | payload.lightSourceID = _LightSourceID; 75 | } 76 | ENDHLSL 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/LightSourceUnlit.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4e69ed530f7023a4f94a96103fbb853d 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/LtcCommon.hlsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | // Functions and data structures for dealing with Linearly Transformed Cosines as presented in 19 | // https://doi.org/10.1145/2897824.2925895 20 | 21 | struct LTC { 22 | float3x3 M_inv; 23 | float integral; 24 | 25 | // When a silhouette is clipped to the upper hemisphere, new edges may be created on the 26 | // clipping plane. These edges are all segments of the same circle and their integral is the sum 27 | // of their angles (see IntegrateEdge(a, b)). Instead of calculating the angles individually the 28 | // atan2 angle sum and difference identities are used (see Atan2Sum(a, b) and Atan2Diff(a, b)) 29 | float2 clippingSum; 30 | 31 | // For ordered silhouette traversal we remember the last transformed point so that 32 | // we don't have to calculate it again for the next edge 33 | float3 previousPoint; 34 | 35 | // Determinant 36 | float det; 37 | }; 38 | 39 | LTC NewLTC(float3x3 M_inv, float3x3 tSpace) { 40 | LTC r; 41 | 42 | r.M_inv = mul(M_inv, tSpace); 43 | r.integral = 0; 44 | r.clippingSum = float2(1, 0); 45 | r.previousPoint = 0; 46 | r.det = determinant(M_inv); 47 | 48 | return r; 49 | } 50 | 51 | // Calculate the contribution of an edge given the already transformed end points of the edge 52 | // Slower version but easier to read: 53 | float IntegrateEdge_Slow(float3 a, float3 b) { 54 | a = normalize(a); 55 | b = normalize(b); 56 | float AdotB = clamp(dot(a, b), -1, 1); 57 | return acos(AdotB) * normalize(cross(a, b)).z; 58 | } 59 | 60 | // Slightly faster version that's actually used: 61 | float IntegrateEdge(float3 a, float3 b) { 62 | float3 c = cross(a, b); 63 | float2 n = rsqrt(float2(dot(a, a) * dot(b, b), dot(c, c))); 64 | float AdotB = clamp(dot(a, b) * n.x, -1, 1); 65 | return acos(AdotB) * c.z * n.y; 66 | } 67 | 68 | // Returns a vector c such that atan2(a.y, a.x) + atan2(b.y, b.x) = atan2(c.y, c.x) 69 | float2 Atan2Sum(float2 a, float2 b) { 70 | float4 m = a.xxyy * b.xyxy; 71 | return m.xz + float2(-m.w, m.y); 72 | 73 | // Readable version: 74 | // return float2(a.x * b.x - a.y * b.y, a.y * b.x + a.x * b.y); 75 | } 76 | 77 | // Returns a vector c such that atan2(a.y, a.x) - atan2(b.y, b.x) = atan2(c.y, c.x) 78 | float2 Atan2Diff(float2 a, float2 b) { 79 | float4 m = a.xxyy * b.xyxy; 80 | return m.xz + float2(m.w, -m.y); 81 | 82 | // Readable version: 83 | // return float2(a.x * b.x + a.y * b.y, a.y * b.x - a.x * b.y); 84 | } 85 | 86 | // Construct a matrix that transforms to a coordinate system where z is the normal and x is the 87 | // tangent that's closest to the view direction 88 | float3x3 BuildShadingSpace(float3 normal, float3 view) { 89 | float3 t2 = normal; 90 | float3 t1 = normalize(cross(t2, view)); 91 | float3 t0 = cross(t1, t2); 92 | return float3x3(t0, t1, t2); 93 | } 94 | 95 | float3 EquatorIntersection(float3 a, float3 b) { 96 | return normalize(lerp(a, b, a.z / (a.z - b.z))); 97 | } 98 | 99 | // Unordered silhouette traversal, consecutive edges don't necessarily share a point 100 | void SilhouetteEdge(inout LTC ltc, float3 a, float3 b) { 101 | // Transform 102 | a = mul(ltc.M_inv, a); 103 | b = mul(ltc.M_inv, b); 104 | 105 | // Clip to upper hemisphere 106 | bool aBelowEquator = a.z < 0; 107 | bool bBelowEquator = b.z < 0; 108 | bool bothBelowEquator = aBelowEquator & bBelowEquator; 109 | 110 | if (aBelowEquator != bBelowEquator) { 111 | float3 p = EquatorIntersection(a, b); 112 | 113 | if (aBelowEquator) { 114 | a = p; 115 | ltc.clippingSum = Atan2Sum(ltc.clippingSum, p.xy); 116 | } else { 117 | b = p; 118 | ltc.clippingSum = Atan2Diff(ltc.clippingSum, p.xy); 119 | } 120 | } 121 | 122 | // Integrate 123 | if (!bothBelowEquator) { 124 | ltc.integral += IntegrateEdge(a, b); 125 | } 126 | } 127 | 128 | // Ordered silhouette traversal, consecutive edges always share a point 129 | void SilhouetteEdge(inout LTC ltc, float3 b) { 130 | // The first point of this edge is the second point of the previous edge 131 | float3 a = ltc.previousPoint; 132 | 133 | // Transform 134 | b = mul(ltc.M_inv, b); 135 | 136 | // Remember b for next edge 137 | ltc.previousPoint = b; 138 | 139 | // Clip to upper hemisphere 140 | bool aBelowEquator = a.z < 0; 141 | bool bBelowEquator = b.z < 0; 142 | bool bothBelowEquator = aBelowEquator & bBelowEquator; 143 | 144 | if (aBelowEquator != bBelowEquator) { 145 | float3 p = EquatorIntersection(a, b); 146 | 147 | if (aBelowEquator) { 148 | a = p; 149 | ltc.clippingSum = Atan2Sum(ltc.clippingSum, p.xy); 150 | } else { 151 | b = p; 152 | ltc.clippingSum = Atan2Diff(ltc.clippingSum, p.xy); 153 | } 154 | } 155 | 156 | // Integrate 157 | if (!bothBelowEquator) { 158 | ltc.integral += IntegrateEdge(a, b); 159 | } 160 | } 161 | 162 | // Set the vertex to be used as the first vertex of the first edge in ordered silhouette traversal 163 | void SetFirstVertex(inout LTC ltc, float3 vertex) { 164 | ltc.previousPoint = mul(ltc.M_inv, vertex); 165 | } 166 | 167 | // Get integral (including edges created by clipping) 168 | float GetIntegral(LTC ltc) { 169 | float angle = atan2(ltc.clippingSum.y, ltc.clippingSum.x); 170 | return (ltc.integral + (angle + 6.28318531) % 6.28318531) / 6.28318531; 171 | } 172 | 173 | float Evaluate(LTC ltc, float3 direction) { 174 | float3 d = mul(ltc.M_inv, direction); 175 | float l = dot(d, d); 176 | 177 | return max(0, d.z * ltc.det / (l * l)); 178 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/LtcCommon.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c7151b66ec012e440bf64077c1fa676e 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/LtcLut.hlsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | #if defined(SHADER_STAGE_FRAGMENT) | defined(SHADER_STAGE_VERTEX) 19 | 20 | sampler2D _LtcMatrixGgx; 21 | sampler2D _LtcAmplitudeGgx; 22 | 23 | float3x3 GetLtcInverseTransformGgx(float roughness, float NdotV, out float2 amplitude) { 24 | const float size = 32; 25 | float2 uv = float2(roughness, acos(NdotV) / 3.14159 * 2); 26 | uv = (uv * (size - 1) + 0.5) / size; 27 | 28 | amplitude = tex2D(_LtcAmplitudeGgx, uv).rg; 29 | 30 | float4 v = tex2D(_LtcMatrixGgx, uv); 31 | 32 | return float3x3( 33 | 1.0, 0.0, v.w, 34 | 0.0, v.z, 0.0, 35 | v.y, 0.0, v.x 36 | ); 37 | } 38 | 39 | float3x3 GetLtcInverseTransformLambert(float roughness, float NdotV) { 40 | return float3x3( 41 | 1.0, 0.0, 0.0, 42 | 0.0, 1.0, 0.0, 43 | 0.0, 0.0, 1.0 44 | ); 45 | } 46 | 47 | #else 48 | 49 | Texture2D _LtcMatrixGgx; 50 | Texture2D _LtcAmplitudeGgx; 51 | SamplerState _LtcLutLinearClampSampler; 52 | 53 | float3x3 GetLtcInverseTransformGgx(float roughness, float NdotV, out float2 amplitude) { 54 | const float size = 32; 55 | float2 uv = float2(roughness, acos(NdotV) / 3.14159 * 2); 56 | uv = (uv * (size - 1) + 0.5) / size; 57 | 58 | amplitude = _LtcAmplitudeGgx.SampleLevel(_LtcLutLinearClampSampler, uv, 0).rg; 59 | 60 | float4 v = _LtcMatrixGgx.SampleLevel(_LtcLutLinearClampSampler, uv, 0); 61 | 62 | return float3x3( 63 | 1.0, 0.0, v.w, 64 | 0.0, v.z, 0.0, 65 | v.y, 0.0, v.x 66 | ); 67 | } 68 | 69 | float3x3 GetLtcInverseTransformLambert(float roughness, float NdotV) { 70 | return float3x3( 71 | 1.0, 0.0, 0.0, 72 | 0.0, 1.0, 0.0, 73 | 0.0, 0.0, 1.0 74 | ); 75 | } 76 | 77 | #endif -------------------------------------------------------------------------------- /Assets/Shaders/Resources/LtcLut.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f519e77ab5ce83c4498b0bdb87c5e597 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/NonConvexLTCLight.shader: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | Shader "CustomDeferredLights/NonConvexLTCLight" { 19 | SubShader { 20 | Cull Off 21 | ZWrite Off 22 | ZTest Always 23 | Blend One One 24 | 25 | Pass { 26 | CGPROGRAM 27 | #pragma vertex Vertex 28 | #pragma fragment Fragment 29 | 30 | #include "DeferredLight.hlsl" 31 | #include "LtcCommon.hlsl" 32 | #include "LtcLut.hlsl" 33 | #include "BspCommon.hlsl" 34 | 35 | float4 _Color; 36 | 37 | float3 Lighting(float3 world, float3 view, float3 diffuseColor, float3 specularColor, float3 normal, float roughness) { 38 | float3 localPosition = WorldToLightPos(world); 39 | float NdotV = dot(normal, view); 40 | float3x3 shadingSpace = BuildShadingSpace(normal, view); 41 | 42 | float2 ggxAmplitude; 43 | 44 | LTC specular = NewLTC(GetLtcInverseTransformGgx(roughness, NdotV, ggxAmplitude), shadingSpace); 45 | LTC diffuse = NewLTC(GetLtcInverseTransformLambert(roughness, NdotV), shadingSpace); 46 | 47 | // Find silhouette start and end indices 48 | uint2 silhouette = FindSilhouette(localPosition); 49 | 50 | // Iterate over silhouette vertices and sum up edge contributions 51 | for (uint i = silhouette.x; i < silhouette.y; i++) { 52 | uint2 edge = _SilhouetteEdges[i]; 53 | 54 | float3 a = ComputeVertexPositionNonConvex(edge.x, localPosition) - world; 55 | float3 b = ComputeVertexPositionNonConvex(edge.y, localPosition) - world; 56 | 57 | SilhouetteEdge(specular, a, b); 58 | SilhouetteEdge(diffuse, a, b); 59 | } 60 | 61 | float3 d = GetIntegral(diffuse) * diffuseColor; 62 | float3 s = GetIntegral(specular) * lerp(ggxAmplitude.y, ggxAmplitude.x, specularColor); 63 | 64 | return (d + s) * _Color; 65 | } 66 | ENDCG 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/NonConvexLTCLight.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: edc140cece0b00e4d893a0232854a881 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/NonStarShapedRaytracedLight.raytrace: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | #define MAX_POLYGON_VERTEX_COUNT 32 19 | 20 | #include "RaytracedDeferredLight.hlsl" 21 | #include "LtcCommon.hlsl" 22 | #include "LtcLut.hlsl" 23 | #include "BspCommon.hlsl" 24 | #include "SolidAngleSampling.hlsl" 25 | 26 | float4 _Color; 27 | uint _RaysPerPixel; 28 | 29 | float3 Lighting(float3 world, float3 view, float3 diffuseColor, float3 specularColor, float3 normal, float roughness, uint seed) { 30 | if (distance(world, _WorldSpaceCameraPos) > 100) return 0; 31 | 32 | float3 localPosition = WorldToLightPos(world); 33 | float NdotV = dot(normal, view); 34 | float3x3 shadingSpace = BuildShadingSpace(normal, view); 35 | 36 | float2 ggxAmplitude; 37 | 38 | LTC specular = NewLTC(GetLtcInverseTransformGgx(roughness, NdotV, ggxAmplitude), shadingSpace); 39 | LTC diffuse = NewLTC(GetLtcInverseTransformLambert(roughness, NdotV), shadingSpace); 40 | 41 | // Find silhouette start and end indices 42 | uint2 silhouette = FindSilhouette(localPosition); 43 | 44 | // Iterate over silhouette vertices and sum up edge contributions 45 | for (uint i = silhouette.x; i < silhouette.y; i++) { 46 | uint2 edge = _SilhouetteEdges[i]; 47 | 48 | float3 a = ComputeVertexPositionNonConvex(edge.x, localPosition) - world; 49 | float3 b = ComputeVertexPositionNonConvex(edge.y, localPosition) - world; 50 | 51 | SilhouetteEdge(specular, a, b); 52 | SilhouetteEdge(diffuse, a, b); 53 | } 54 | 55 | float3 d = GetIntegral(diffuse) * diffuseColor; 56 | float3 s = GetIntegral(specular) * lerp(ggxAmplitude.y, ggxAmplitude.x, specularColor); 57 | 58 | // Calculate solid angles 59 | uint2 triangulation = FindTriangulation(localPosition); 60 | float solidAngle = 0; 61 | float solidAngles[MAX_POLYGON_VERTEX_COUNT]; 62 | 63 | for (uint i = triangulation.x; i < triangulation.y; i++) { 64 | float3 A, B, C; 65 | GetTriangleNonStarShaped(i - triangulation.x, triangulation, localPosition, A, B, C); 66 | float s = SolidAngle(A - world, B - world, C - world); 67 | 68 | solidAngle += s; 69 | solidAngles[i - triangulation.x] = s; 70 | } 71 | 72 | // Stochastic shadows 73 | float2 specularShadowRatio = 0; 74 | float2 diffuseShadowRatio = 0; 75 | float3 rayOrigin = world + normal * distance(_WorldSpaceCameraPos, world) / 1000; 76 | 77 | for (uint i = 0; i < _RaysPerPixel; i++) { 78 | float3 random = float3(Random(seed), Random(seed), Random(seed)); 79 | 80 | // Select triangle 81 | uint triangleIndex = 0; 82 | float partialSolidAngle = solidAngles[0]; 83 | float selectedSolidAngle = random.z * solidAngle; 84 | uint panic = 100; 85 | 86 | while (partialSolidAngle < selectedSolidAngle && panic-- > 0) { 87 | partialSolidAngle += solidAngles[++triangleIndex]; 88 | } 89 | 90 | // Calculate sample direction 91 | float3 A, B, C; 92 | GetTriangleNonStarShaped(triangleIndex, triangulation, localPosition, A, B, C); 93 | SphericalTriangle t = CreateSphericalTriangle(A - world, B - world, C - world, solidAngles[triangleIndex]); 94 | float3 direction = SampleSphericalTriangle(random.xy, t); 95 | 96 | // Raytrace and evaluate BRDF 97 | float2 m = float2(!IsShadowed(rayOrigin, direction), 1); 98 | // float2 m = 1; 99 | specularShadowRatio += m * Evaluate(specular, direction); 100 | diffuseShadowRatio += m * Evaluate(diffuse, direction); 101 | } 102 | 103 | d *= diffuseShadowRatio.x / max(0.0001, diffuseShadowRatio.y); 104 | s *= specularShadowRatio.x / max(0.0001, specularShadowRatio.y); 105 | 106 | return (d + s) * _Color; 107 | // return specularShadowRatio.x * solidAngle / _RaysPerPixel; 108 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/NonStarShapedRaytracedLight.raytrace.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1c0094f9bcada94fbee1c2a3f232533 3 | RayTracingShaderImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/RaytracedDeferredLight.hlsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | #pragma max_recursion_depth 1 19 | 20 | Texture2D _CameraGBufferTexture0; 21 | Texture2D _CameraGBufferTexture1; 22 | Texture2D _CameraGBufferTexture2; 23 | Texture2D _CameraDepthTexture; 24 | RWTexture2D _Target; 25 | 26 | SamplerState _PointClampSampler; 27 | 28 | float4x4 unity_CameraInvProjection; 29 | float4x4 unity_CameraToWorld; 30 | float4 _ZBufferParams; 31 | float3 _WorldSpaceCameraPos; 32 | float4 _ScreenParams; 33 | 34 | RaytracingAccelerationStructure _Accelerator; 35 | uint _LightSourceID; 36 | 37 | float3 Lighting(float3 world, float3 view, float3 albedo, float3 specular, float3 normal, float roughness, uint seed); 38 | 39 | float LinearEyeDepth(float z) { 40 | return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w); 41 | } 42 | 43 | float3 ComputeWorldRay(float2 uv) { 44 | float4 pos = float4(uv * 2 - 1, 1, 1); 45 | float3 ray = mul(unity_CameraInvProjection, pos).xyz; 46 | ray.z = -ray.z; 47 | return mul((float3x3)unity_CameraToWorld, ray); 48 | } 49 | 50 | float3 ComputeWorldPos(float2 screenPos, float3 ray) { 51 | float depth = _CameraDepthTexture.SampleLevel(_PointClampSampler, screenPos, 0).r; 52 | depth = LinearEyeDepth(depth); 53 | return _WorldSpaceCameraPos + ray * depth; 54 | } 55 | 56 | struct Payload { int lightSourceID; }; 57 | 58 | bool IsShadowed(float3 origin, float3 direction) { 59 | Payload p; 60 | p.lightSourceID = -1; 61 | 62 | RayDesc r; 63 | r.Origin = origin; 64 | r.Direction = direction; 65 | r.TMin = 0; 66 | r.TMax = 1000; 67 | 68 | TraceRay(_Accelerator, 0, 0xff, 0, 1, 0, r, p); 69 | 70 | return p.lightSourceID != _LightSourceID; 71 | } 72 | 73 | uint Hash(uint seed) { 74 | seed = (seed ^ 61) ^ (seed >> 16); 75 | seed *= 9; 76 | seed = seed ^ (seed >> 4); 77 | seed *= 0x27d4eb2d; 78 | seed = seed ^ (seed >> 15); 79 | return seed; 80 | } 81 | 82 | float Random(inout uint seed) { 83 | seed ^= (seed << 13); 84 | seed ^= (seed >> 17); 85 | seed ^= (seed << 5); 86 | return ((float)seed / 4294967296.0); 87 | } 88 | 89 | [shader("raygeneration")] 90 | void RayGeneration() { 91 | uint2 id = DispatchRaysIndex().xy; 92 | float2 uv = id / _ScreenParams.xy; 93 | uint seed = Hash(id.x ^ (id.y << 16)); 94 | 95 | float3 worldRay = ComputeWorldRay(uv); 96 | float3 worldPos = ComputeWorldPos(uv, worldRay); 97 | 98 | float4 gbuffer0 = _CameraGBufferTexture0.SampleLevel(_PointClampSampler, uv, 0); 99 | float4 gbuffer1 = _CameraGBufferTexture1.SampleLevel(_PointClampSampler, uv, 0); 100 | float4 gbuffer2 = _CameraGBufferTexture2.SampleLevel(_PointClampSampler, uv, 0); 101 | 102 | float4 target; 103 | 104 | target.a = 0; 105 | 106 | target.rgb = Lighting( 107 | worldPos, 108 | -normalize(worldRay), 109 | gbuffer0.rgb, 110 | gbuffer1.rgb, 111 | gbuffer2.xyz * 2 - 1, 112 | 1 - gbuffer1.a, 113 | seed 114 | ); 115 | 116 | _Target[id] = target; 117 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/RaytracedDeferredLight.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 54a3a0e0fea3cc348ae316d779743f50 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/SolidAngleSampling.hlsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | struct SphericalTriangle { 19 | float3 A, B, C; 20 | float3 angles; 21 | float solidAngle; 22 | }; 23 | 24 | SphericalTriangle CreateSphericalTriangle(float3 A, float3 B, float3 C) { 25 | SphericalTriangle t; 26 | 27 | t.A = normalize(A); 28 | t.B = normalize(B); 29 | t.C = normalize(C); 30 | 31 | float dotAB = dot(t.A, t.B); 32 | float dotBC = dot(t.B, t.C); 33 | float dotCA = dot(t.C, t.A); 34 | 35 | float3 AonB = t.A - t.B * dotAB; 36 | float3 AonC = t.A - t.C * dotCA; 37 | float3 BonA = t.B - t.A * dotAB; 38 | float3 BonC = t.B - t.C * dotBC; 39 | float3 ConA = t.C - t.A * dotCA; 40 | float3 ConB = t.C - t.B * dotBC; 41 | 42 | float3 l = rsqrt(float3( 43 | dot(ConA, ConA) * dot(BonA, BonA), 44 | dot(AonB, AonB) * dot(ConB, ConB), 45 | dot(BonC, BonC) * dot(AonC, AonC) 46 | )); 47 | 48 | t.angles = acos(float3( 49 | dot(ConA, BonA), 50 | dot(AonB, ConB), 51 | dot(BonC, AonC) 52 | ) * l); 53 | 54 | t.solidAngle = t.angles.x + t.angles.y + t.angles.z - 3.14159265; 55 | 56 | return t; 57 | } 58 | 59 | SphericalTriangle CreateSphericalTriangle(float3 A, float3 B, float3 C, float solidAngle) { 60 | SphericalTriangle t; 61 | 62 | t.A = normalize(A); 63 | t.B = normalize(B); 64 | t.C = normalize(C); 65 | 66 | float3 BonA = t.B - t.A * dot(t.A, t.B); 67 | float3 ConA = t.C - t.A * dot(t.C, t.A); 68 | 69 | t.angles.x = acos(dot(ConA, BonA) * rsqrt(dot(ConA, ConA) * dot(BonA, BonA))); 70 | t.solidAngle = solidAngle; 71 | 72 | return t; 73 | } 74 | 75 | float SolidAngle(float3 A, float3 B, float3 C) { 76 | float a = length(A); 77 | float b = length(B); 78 | float c = length(C); 79 | 80 | float ABC = dot(A, cross(B, C)); 81 | float abc = a * b * c; 82 | 83 | return 2 * atan(ABC / (abc + a * dot(B, C) + b * dot(C, A) + c * dot(A, B))); 84 | } 85 | 86 | float3 OrthonormalComponent(float3 x, float3 y) { 87 | return normalize(x - dot(x, y) * y); 88 | } 89 | 90 | // https://dl.acm.org/doi/10.1145/218380.218500 91 | float3 SampleSphericalTriangle(float2 random, SphericalTriangle t) { 92 | // Use one random variable to select the new solidAngle 93 | float partialSolidAngle = t.solidAngle * random.x; 94 | 95 | // Save the sine and cosine of the angles Phi and Alpha 96 | float sinP, cosP; sincos(partialSolidAngle - t.angles.x, sinP, cosP); 97 | float sinA, cosA; sincos(t.angles.x, sinA, cosA); 98 | 99 | // Compute the pair (u, v) that determines beta2 100 | float u = cosP - cosA; 101 | float v = sinP + sinA * dot(t.A, t.B); 102 | 103 | // Let q be the cosine of the new edge length b2 104 | float q = ((v * cosP - u * sinP) * cosA - v) / ((v * sinP + u * cosP) * sinA); 105 | 106 | // Compute the third vertex of the sub-triangle 107 | float3 C2 = q * t.A + sqrt(1 - q * q) * OrthonormalComponent(t.C, t.A); 108 | 109 | // Use the other random variable to select cos(Theta) 110 | float z = 1 - random.y * (1 - dot(C2, t.B)); 111 | 112 | // Construct the corresponding point on the sphere 113 | return z * t.B + sqrt(1 - z * z) * OrthonormalComponent(C2, t.B); 114 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/SolidAngleSampling.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee4d7a1a1d283f74aa36cfbe2c7dd3e7 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | preprocessorOverride: 0 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/Shaders/Resources/StarShapedRaytracedLight.raytrace: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021, Bastian Urbach 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 4 | // associated documentation files (the "Software"), to deal in the Software without restriction, 5 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 6 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // 9 | // The above copyright notice and this permission notice shall be included in all copies or 10 | // substantial portions of the Software. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 13 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | #define MAX_POLYGON_VERTEX_COUNT 32 19 | 20 | #include "RaytracedDeferredLight.hlsl" 21 | #include "LtcCommon.hlsl" 22 | #include "LtcLut.hlsl" 23 | #include "BspCommon.hlsl" 24 | #include "SolidAngleSampling.hlsl" 25 | 26 | float4 _Color; 27 | uint _RaysPerPixel; 28 | 29 | float3 Lighting(float3 world, float3 view, float3 diffuseColor, float3 specularColor, float3 normal, float roughness, uint seed) { 30 | if (distance(world, _WorldSpaceCameraPos) > 100) return 0; 31 | 32 | float3 localPosition = WorldToLightPos(world); 33 | float NdotV = dot(normal, view); 34 | float3x3 shadingSpace = BuildShadingSpace(normal, view); 35 | 36 | float2 ggxAmplitude; 37 | 38 | LTC specular = NewLTC(GetLtcInverseTransformGgx(roughness, NdotV, ggxAmplitude), shadingSpace); 39 | LTC diffuse = NewLTC(GetLtcInverseTransformLambert(roughness, NdotV), shadingSpace); 40 | 41 | // Find silhouette start and end indices 42 | uint2 silhouette = FindSilhouette(localPosition); 43 | 44 | float solidAngle = 0; 45 | float solidAngles[MAX_POLYGON_VERTEX_COUNT]; 46 | 47 | // Iterate over silhouette vertices and sum up edge contributions 48 | for (uint i = silhouette.x; i < silhouette.y; i++) { 49 | uint2 edge = _SilhouetteEdges[i]; 50 | 51 | float3 a = ComputeVertexPositionNonConvex(edge.x, localPosition) - world; 52 | float3 b = ComputeVertexPositionNonConvex(edge.y, localPosition) - world; 53 | 54 | SilhouetteEdge(specular, a, b); 55 | SilhouetteEdge(diffuse, a, b); 56 | 57 | float s = abs(SolidAngle(_Center - world, a, b)); 58 | solidAngle += s; 59 | solidAngles[i - silhouette.x] = s; 60 | } 61 | 62 | float3 d = GetIntegral(diffuse) * diffuseColor; 63 | float3 s = GetIntegral(specular) * lerp(ggxAmplitude.y, ggxAmplitude.x, specularColor); 64 | 65 | // Stochastic shadows 66 | float2 specularShadowRatio = 0; 67 | float2 diffuseShadowRatio = 0; 68 | float3 rayOrigin = world + normal * distance(_WorldSpaceCameraPos, world) / 1000; 69 | 70 | for (uint i = 0; i < _RaysPerPixel; i++) { 71 | float3 random = float3(Random(seed), Random(seed), Random(seed)); 72 | 73 | // Select triangle 74 | uint triangleIndex = 0; 75 | float partialSolidAngle = solidAngles[0]; 76 | float selectedSolidAngle = random.z * solidAngle; 77 | uint panic = 100; 78 | 79 | while (partialSolidAngle < selectedSolidAngle && panic-- > 0) { 80 | partialSolidAngle += solidAngles[++triangleIndex]; 81 | } 82 | 83 | // Calculate sample direction 84 | float3 A, B, C; 85 | GetTriangleStarShaped(triangleIndex, silhouette, localPosition, A, B, C); 86 | SphericalTriangle t = CreateSphericalTriangle(A - world, B - world, C - world, solidAngles[triangleIndex]); 87 | float3 direction = SampleSphericalTriangle(random.xy, t); 88 | 89 | // Raytrace and evaluate BRDF 90 | float2 m = float2(!IsShadowed(rayOrigin, direction), 1); 91 | specularShadowRatio += m * Evaluate(specular, direction); 92 | diffuseShadowRatio += m * Evaluate(diffuse, direction); 93 | } 94 | 95 | d *= diffuseShadowRatio.x / max(0.0001, diffuseShadowRatio.y); 96 | s *= specularShadowRatio.x / max(0.0001, specularShadowRatio.y); 97 | 98 | return (d + s) * _Color; 99 | } -------------------------------------------------------------------------------- /Assets/Shaders/Resources/StarShapedRaytracedLight.raytrace.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68f6123689559864bb99099db42a0201 3 | RayTracingShaderImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Textures.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b93259ab84212f4894a30c6b4aaef0f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Textures/Grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BastianUrbach/rtswplusd/6152d65d13221e4803c0cab2be6d2220f3ea75d9/Assets/Textures/Grid.png -------------------------------------------------------------------------------- /Assets/Textures/Grid.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb60e5d1155872440b4ad41d306c3292 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 1 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | - serializedVersion: 3 79 | buildTarget: Standalone 80 | maxTextureSize: 2048 81 | resizeAlgorithm: 0 82 | textureFormat: -1 83 | textureCompression: 1 84 | compressionQuality: 50 85 | crunchedCompression: 0 86 | allowsAlphaSplitting: 0 87 | overridden: 0 88 | androidETC2FallbackOverride: 0 89 | forceMaximumCompressionQuality_BC6H_BC7: 0 90 | spriteSheet: 91 | serializedVersion: 2 92 | sprites: [] 93 | outline: [] 94 | physicsShape: [] 95 | bones: [] 96 | spriteID: 97 | internalID: 0 98 | vertices: [] 99 | indices: 100 | edges: [] 101 | weights: [] 102 | secondaryTextures: [] 103 | spritePackingTag: 104 | pSDRemoveMatte: 0 105 | pSDShowRemoveMatteOption: 0 106 | userData: 107 | assetBundleName: 108 | assetBundleVariant: 109 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.ide.vscode": "1.2.3", 4 | "com.unity.postprocessing": "3.1.1", 5 | "com.unity.modules.ai": "1.0.0", 6 | "com.unity.modules.androidjni": "1.0.0", 7 | "com.unity.modules.animation": "1.0.0", 8 | "com.unity.modules.assetbundle": "1.0.0", 9 | "com.unity.modules.audio": "1.0.0", 10 | "com.unity.modules.cloth": "1.0.0", 11 | "com.unity.modules.director": "1.0.0", 12 | "com.unity.modules.imageconversion": "1.0.0", 13 | "com.unity.modules.imgui": "1.0.0", 14 | "com.unity.modules.jsonserialize": "1.0.0", 15 | "com.unity.modules.particlesystem": "1.0.0", 16 | "com.unity.modules.physics": "1.0.0", 17 | "com.unity.modules.physics2d": "1.0.0", 18 | "com.unity.modules.screencapture": "1.0.0", 19 | "com.unity.modules.terrain": "1.0.0", 20 | "com.unity.modules.terrainphysics": "1.0.0", 21 | "com.unity.modules.tilemap": "1.0.0", 22 | "com.unity.modules.ui": "1.0.0", 23 | "com.unity.modules.uielements": "1.0.0", 24 | "com.unity.modules.umbra": "1.0.0", 25 | "com.unity.modules.unityanalytics": "1.0.0", 26 | "com.unity.modules.unitywebrequest": "1.0.0", 27 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 28 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 29 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 30 | "com.unity.modules.unitywebrequestwww": "1.0.0", 31 | "com.unity.modules.vehicles": "1.0.0", 32 | "com.unity.modules.video": "1.0.0", 33 | "com.unity.modules.vr": "1.0.0", 34 | "com.unity.modules.wind": "1.0.0", 35 | "com.unity.modules.xr": "1.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Volume: 1 8 | Rolloff Scale: 1 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_SampleRate: 0 12 | m_DSPBufferSize: 1024 13 | m_VirtualVoiceCount: 512 14 | m_RealVoiceCount: 32 15 | m_SpatializerPlugin: 16 | m_AmbisonicDecoderPlugin: 17 | m_DisableAudio: 0 18 | m_VirtualizeEffects: 1 19 | m_RequestedDSPBufferSize: 1024 20 | -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | m_FrictionType: 0 32 | m_EnableEnhancedDeterminism: 0 33 | m_EnableUnifiedHeightmaps: 1 34 | m_DefaultMaxAngluarSpeed: 7 35 | -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: 8 | - enabled: 1 9 | path: Assets/Scenes/Lights.unity 10 | guid: abea8e4d779d0444897882f3d974fd75 11 | m_configObjects: {} 12 | -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 0 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_EnterPlayModeOptionsEnabled: 0 27 | m_EnterPlayModeOptions: 3 28 | m_ShowLightmapResolutionOverlay: 1 29 | m_UseLegacyProbeSampleCount: 0 30 | m_SerializeInlineMappingsOnOneLine: 1 -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 13 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_VideoShadersIncludeMode: 2 32 | m_AlwaysIncludedShaders: 33 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 38 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 39 | m_PreloadedShaders: [] 40 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} 41 | m_CustomRenderPipeline: {fileID: 0} 42 | m_TransparencySortMode: 0 43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 44 | m_DefaultRenderingPath: 1 45 | m_DefaultMobileRenderingPath: 1 46 | m_TierSettings: 47 | - serializedVersion: 5 48 | m_BuildTarget: 1 49 | m_Tier: 0 50 | m_Settings: 51 | standardShaderQuality: 2 52 | renderingPath: 3 53 | hdrMode: 1 54 | realtimeGICPUUsage: 25 55 | useReflectionProbeBoxProjection: 1 56 | useReflectionProbeBlending: 1 57 | useHDR: 1 58 | useDetailNormalMap: 1 59 | useCascadedShadowMaps: 1 60 | prefer32BitShadowMaps: 0 61 | enableLPPV: 1 62 | useDitherMaskForAlphaBlendedShadows: 1 63 | m_Automatic: 0 64 | - serializedVersion: 5 65 | m_BuildTarget: 1 66 | m_Tier: 1 67 | m_Settings: 68 | standardShaderQuality: 2 69 | renderingPath: 3 70 | hdrMode: 1 71 | realtimeGICPUUsage: 25 72 | useReflectionProbeBoxProjection: 1 73 | useReflectionProbeBlending: 1 74 | useHDR: 1 75 | useDetailNormalMap: 1 76 | useCascadedShadowMaps: 1 77 | prefer32BitShadowMaps: 0 78 | enableLPPV: 1 79 | useDitherMaskForAlphaBlendedShadows: 1 80 | m_Automatic: 0 81 | - serializedVersion: 5 82 | m_BuildTarget: 1 83 | m_Tier: 2 84 | m_Settings: 85 | standardShaderQuality: 2 86 | renderingPath: 3 87 | hdrMode: 1 88 | realtimeGICPUUsage: 50 89 | useReflectionProbeBoxProjection: 1 90 | useReflectionProbeBlending: 1 91 | useHDR: 1 92 | useDetailNormalMap: 1 93 | useCascadedShadowMaps: 1 94 | prefer32BitShadowMaps: 0 95 | enableLPPV: 1 96 | useDitherMaskForAlphaBlendedShadows: 1 97 | m_Automatic: 0 98 | m_LightmapStripping: 0 99 | m_FogStripping: 0 100 | m_InstancingStripping: 0 101 | m_LightmapKeepPlain: 1 102 | m_LightmapKeepDirCombined: 1 103 | m_LightmapKeepDynamicPlain: 1 104 | m_LightmapKeepDynamicDirCombined: 1 105 | m_LightmapKeepShadowMask: 1 106 | m_LightmapKeepSubtractive: 1 107 | m_FogKeepLinear: 1 108 | m_FogKeepExp: 1 109 | m_FogKeepExp2: 1 110 | m_AlbedoSwatchInfos: [] 111 | m_LightsUseLinearIntensity: 0 112 | m_LightsUseColorTemperature: 0 113 | m_DefaultRenderingLayerMask: 1 114 | m_LogWhenShaderIsCompiled: 0 115 | -------------------------------------------------------------------------------- /ProjectSettings/HDRPProjectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 63a2978a97e4fc04cb9d905947216f3d, type: 3} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | version: 1 16 | m_ProjectSettingFolderPath: HDRPDefaultResources 17 | m_WizardPopupAtStart: 0 18 | m_WizardPopupAlreadyShownOnce: 0 19 | m_WizardActiveTab: 0 20 | m_WizardNeedRestartAfterChangingToDX12: 0 21 | m_WizardNeedToRunFixAllAgainAfterDomainReload: 0 22 | m_LastMaterialVersion: 11 23 | -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /ProjectSettings/PackageManagerSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | m_EnablePreReleasePackages: 0 16 | m_EnablePackageDependencies: 0 17 | m_AdvancedSettingsExpanded: 1 18 | m_ScopedRegistriesSettingsExpanded: 1 19 | m_SeeAllPackageVersions: 0 20 | oneTimeWarningShown: 0 21 | m_Registries: 22 | - m_Id: main 23 | m_Name: 24 | m_Url: https://packages.unity.com 25 | m_Scopes: [] 26 | m_IsDefault: 1 27 | m_Capabilities: 7 28 | m_UserSelectedRegistryName: 29 | m_UserAddingNewScopedRegistry: 0 30 | m_RegistryInfoDraft: 31 | m_ErrorMessage: 32 | m_Original: 33 | m_Id: 34 | m_Name: 35 | m_Url: 36 | m_Scopes: [] 37 | m_IsDefault: 0 38 | m_Capabilities: 0 39 | m_Modified: 0 40 | m_Name: 41 | m_Url: 42 | m_Scopes: 43 | - 44 | m_SelectedScopeIndex: 0 45 | m_LoadAssets: 0 46 | -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_DefaultPresets: {} 8 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2021.1.13f1 2 | m_EditorVersionWithRevision: 2021.1.13f1 (a03098edbbe0) 3 | -------------------------------------------------------------------------------- /ProjectSettings/SceneTemplateSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "templatePinStates": [], 3 | "dependencyTypeInfos": [ 4 | { 5 | "userAdded": false, 6 | "type": "UnityEngine.AnimationClip", 7 | "ignore": false, 8 | "defaultInstantiationMode": 0, 9 | "supportsModification": true 10 | }, 11 | { 12 | "userAdded": false, 13 | "type": "UnityEditor.Animations.AnimatorController", 14 | "ignore": false, 15 | "defaultInstantiationMode": 0, 16 | "supportsModification": true 17 | }, 18 | { 19 | "userAdded": false, 20 | "type": "UnityEngine.AnimatorOverrideController", 21 | "ignore": false, 22 | "defaultInstantiationMode": 0, 23 | "supportsModification": true 24 | }, 25 | { 26 | "userAdded": false, 27 | "type": "UnityEditor.Audio.AudioMixerController", 28 | "ignore": false, 29 | "defaultInstantiationMode": 0, 30 | "supportsModification": true 31 | }, 32 | { 33 | "userAdded": false, 34 | "type": "UnityEngine.ComputeShader", 35 | "ignore": true, 36 | "defaultInstantiationMode": 1, 37 | "supportsModification": true 38 | }, 39 | { 40 | "userAdded": false, 41 | "type": "UnityEngine.Cubemap", 42 | "ignore": false, 43 | "defaultInstantiationMode": 0, 44 | "supportsModification": true 45 | }, 46 | { 47 | "userAdded": false, 48 | "type": "UnityEngine.GameObject", 49 | "ignore": false, 50 | "defaultInstantiationMode": 0, 51 | "supportsModification": true 52 | }, 53 | { 54 | "userAdded": false, 55 | "type": "UnityEditor.LightingDataAsset", 56 | "ignore": false, 57 | "defaultInstantiationMode": 0, 58 | "supportsModification": false 59 | }, 60 | { 61 | "userAdded": false, 62 | "type": "UnityEngine.LightingSettings", 63 | "ignore": false, 64 | "defaultInstantiationMode": 0, 65 | "supportsModification": true 66 | }, 67 | { 68 | "userAdded": false, 69 | "type": "UnityEngine.Material", 70 | "ignore": false, 71 | "defaultInstantiationMode": 0, 72 | "supportsModification": true 73 | }, 74 | { 75 | "userAdded": false, 76 | "type": "UnityEditor.MonoScript", 77 | "ignore": true, 78 | "defaultInstantiationMode": 1, 79 | "supportsModification": true 80 | }, 81 | { 82 | "userAdded": false, 83 | "type": "UnityEngine.PhysicMaterial", 84 | "ignore": false, 85 | "defaultInstantiationMode": 0, 86 | "supportsModification": true 87 | }, 88 | { 89 | "userAdded": false, 90 | "type": "UnityEngine.PhysicsMaterial2D", 91 | "ignore": false, 92 | "defaultInstantiationMode": 0, 93 | "supportsModification": true 94 | }, 95 | { 96 | "userAdded": false, 97 | "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", 98 | "ignore": false, 99 | "defaultInstantiationMode": 0, 100 | "supportsModification": true 101 | }, 102 | { 103 | "userAdded": false, 104 | "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", 105 | "ignore": false, 106 | "defaultInstantiationMode": 0, 107 | "supportsModification": true 108 | }, 109 | { 110 | "userAdded": false, 111 | "type": "UnityEngine.Rendering.VolumeProfile", 112 | "ignore": false, 113 | "defaultInstantiationMode": 0, 114 | "supportsModification": true 115 | }, 116 | { 117 | "userAdded": false, 118 | "type": "UnityEditor.SceneAsset", 119 | "ignore": false, 120 | "defaultInstantiationMode": 0, 121 | "supportsModification": false 122 | }, 123 | { 124 | "userAdded": false, 125 | "type": "UnityEngine.Shader", 126 | "ignore": true, 127 | "defaultInstantiationMode": 1, 128 | "supportsModification": true 129 | }, 130 | { 131 | "userAdded": false, 132 | "type": "UnityEngine.ShaderVariantCollection", 133 | "ignore": true, 134 | "defaultInstantiationMode": 1, 135 | "supportsModification": true 136 | }, 137 | { 138 | "userAdded": false, 139 | "type": "UnityEngine.Texture", 140 | "ignore": false, 141 | "defaultInstantiationMode": 0, 142 | "supportsModification": true 143 | }, 144 | { 145 | "userAdded": false, 146 | "type": "UnityEngine.Texture2D", 147 | "ignore": false, 148 | "defaultInstantiationMode": 0, 149 | "supportsModification": true 150 | }, 151 | { 152 | "userAdded": false, 153 | "type": "UnityEngine.Timeline.TimelineAsset", 154 | "ignore": false, 155 | "defaultInstantiationMode": 0, 156 | "supportsModification": true 157 | } 158 | ], 159 | "defaultDependencyTypeInfo": { 160 | "userAdded": false, 161 | "type": "", 162 | "ignore": false, 163 | "defaultInstantiationMode": 1, 164 | "supportsModification": true 165 | }, 166 | "newSceneOverride": 0 167 | } -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - PostProcessing 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_DashboardUrl: https://dashboard.unity3d.com 13 | m_TestInitMode: 0 14 | CrashReportingSettings: 15 | m_EventUrl: https://perf-events.cloud.unity3d.com 16 | m_Enabled: 0 17 | m_LogBufferSize: 10 18 | m_CaptureEditorExceptions: 1 19 | UnityPurchasingSettings: 20 | m_Enabled: 0 21 | m_TestMode: 0 22 | UnityAnalyticsSettings: 23 | m_Enabled: 0 24 | m_TestMode: 0 25 | m_InitializeOnStartup: 1 26 | UnityAdsSettings: 27 | m_Enabled: 0 28 | m_InitializeOnStartup: 1 29 | m_TestMode: 0 30 | m_IosGameId: 31 | m_AndroidGameId: 32 | m_GameIds: {} 33 | m_GameId: 34 | PerformanceReportingSettings: 35 | m_Enabled: 0 36 | -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 7200000, guid: 84a17cfa13e40ae4082ef42714f0a81c, type: 3} 7 | m_CopyBufferShader: {fileID: 7200000, guid: 23c51f21a3503f6428b527b01f8a2f4e, type: 3} 8 | m_SortShader: {fileID: 7200000, guid: ea257ca3cfb12a642a5025e612af6b2a, type: 3} 9 | m_StripUpdateShader: {fileID: 7200000, guid: 8fa6c4009fe2a4d4486c62736fc30ad8, type: 3} 10 | m_RenderPipeSettingsPath: 11 | m_FixedTimeStep: 0.016666668 12 | m_MaxDeltaTime: 0.05 13 | m_CompiledVersion: 2 14 | m_RuntimeVersion: 16 15 | -------------------------------------------------------------------------------- /ProjectSettings/VersionControlSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!890905787 &1 4 | VersionControlSettings: 5 | m_ObjectHideFlags: 0 6 | m_Mode: Visible Meta Files 7 | m_CollabEditorSettings: 8 | inProgressEnabled: 1 9 | -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Real-Time Shading with Polyhedral Lights Using Silhouette Detection 2 | This is my implementation of the techniques presented in my bachelor thesis [Real-Time Shading with Polyhedral Lights Using Silhouette Detection](http://bastian.urbach.one/rtswplusd). The implementation is a Unity Project (version 2021.1.13f1). To run it, open it in the Unity Editor, open one of the scenes in the "Example Scenes" folder and press "Play". To create a new light source, add one of the light source scripts (Scripts/Lights) to a GameObject and configure it to your liking. The script requires precomputed data in some format depending on the type of the light source. For example, a ConvexLTCLight requires a ConvexSilhouetteBSP. To create one, select Assets > Create > Convex Silhouette BSP. This will create a new asset in the project folder that you can select and configure. You can then assign it to the light source. Note that the polyhedral light sources currently only work in play mode and only in the deferred shading path of the builtin render pipeline. They also don't work for transparent objects or any other object that does not use deferred shading. 3 | --------------------------------------------------------------------------------