├── .editorconfig ├── .gitattributes ├── .github └── pull_request_template.md ├── .gitignore ├── .npmignore ├── .yamato ├── pack.yml ├── project.metafile ├── promote.yml ├── publish.yml └── test.yml ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── CONTRIBUTING.md ├── CONTRIBUTING.md.meta ├── Documentation~ └── com.unity.xrlinerenderer.md ├── Editor.meta ├── Editor ├── MeshChainShaderGUI.cs ├── MeshChainShaderGUI.cs.meta ├── Unity.XRLineRenderer.Editor.api ├── Unity.XRLineRenderer.Editor.api.meta ├── Unity.XRLineRenderer.Editor.asmdef ├── Unity.XRLineRenderer.Editor.asmdef.meta ├── XRLineRendererEditor.cs ├── XRLineRendererEditor.cs.meta ├── XRTrailRendererEditor.cs └── XRTrailRendererEditor.cs.meta ├── LICENSE.md ├── LICENSE.md.meta ├── Materials.meta ├── Materials ├── AdditiveLine.mat ├── AdditiveLine.mat.meta ├── AlphaLine.mat ├── AlphaLine.mat.meta ├── CleanLine.mat ├── CleanLine.mat.meta ├── MaxLine.mat ├── MaxLine.mat.meta ├── MinLine.mat ├── MinLine.mat.meta ├── PhotonBladeCore.mat ├── PhotonBladeCore.mat.meta ├── PhotonBladeGlow.mat ├── PhotonBladeGlow.mat.meta ├── Regular Line.mat ├── Regular Line.mat.meta ├── ShowcaseBox.mat ├── ShowcaseBox.mat.meta ├── SubtractiveLine.mat ├── SubtractiveLine.mat.meta ├── TrailLine.mat └── TrailLine.mat.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── MeshChainRenderer.cs ├── MeshChainRenderer.cs.meta ├── Unity.XRLineRenderer.api ├── Unity.XRLineRenderer.api.meta ├── Unity.XRLineRenderer.asmdef ├── Unity.XRLineRenderer.asmdef.meta ├── XRLineRenderer.cs ├── XRLineRenderer.cs.meta ├── XRMeshChain.cs ├── XRMeshChain.cs.meta ├── XRTrailRenderer.cs └── XRTrailRenderer.cs.meta ├── Scenes.meta ├── Scenes ├── ExampleScene.unity └── ExampleScene.unity.meta ├── Scratch.meta ├── Scratch ├── TrailExample.anim └── TrailExample.anim.meta ├── Shaders.meta ├── Shaders ├── MeshChain.cginc ├── MeshChain.cginc.meta ├── MeshChainAdd.shader ├── MeshChainAdd.shader.meta ├── MeshChainAlpha.shader ├── MeshChainAlpha.shader.meta ├── MeshChainMax.shader ├── MeshChainMax.shader.meta ├── MeshChainMin.shader ├── MeshChainMin.shader.meta ├── MeshChainSubtract.shader └── MeshChainSubtract.shader.meta ├── Tests.meta ├── Tests ├── Runtime.meta └── Runtime │ ├── Unity.Labs.XRLineRenderer.Tests.asmdef │ ├── Unity.Labs.XRLineRenderer.Tests.asmdef.meta │ ├── XRLineRendererTests.cs │ └── XRLineRendererTests.cs.meta ├── package.json └── package.json.meta /.editorconfig: -------------------------------------------------------------------------------- 1 | # see http://editorconfig.org/ for docs on this file 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf ; help with sharing files across os's (i.e. network share or through local vm) 7 | #charset temporarily disabled due to bug in VS2017 changing to UTF-8 with BOM (https://favro.com/card/c564ede4ed3337f7b17986b6/Uni-17877) 8 | #charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | # trailing whitespace is significant in markdown (bad choice, bad!) 13 | [*.{md,markdown}] 14 | trim_trailing_whitespace = false 15 | 16 | # keep these and the VS stuff below in sync with .hgeol's CRLF extensions 17 | [*.{vcproj,bat,cmd,xaml,tt,t4,ttinclude}] 18 | end_of_line = crlf 19 | 20 | # this VS-specific stuff is based on experiments to see how VS will modify a file after it has been manually edited. 21 | # the settings are meant to closely match what VS does to minimize unnecessary diffs. this duplicates some settings in * 22 | # but let's be explicit here to be safe (in case someone wants to copy-paste this out to another .editorconfig). 23 | [*.{vcxproj,vcxproj.filters}] 24 | indent_style = space 25 | indent_size = 2 26 | end_of_line = crlf 27 | charset = utf-8-bom 28 | trim_trailing_whitespace = true 29 | insert_final_newline = false 30 | # must be broken out because of 51-char bug (https://github.com/editorconfig/editorconfig-visualstudio/issues/21) 31 | [*.{csproj,pyproj,props,targets}] 32 | indent_style = space 33 | indent_size = 2 34 | end_of_line = crlf 35 | charset = utf-8-bom 36 | trim_trailing_whitespace = true 37 | insert_final_newline = false 38 | [*.{sln,sln.template}] 39 | indent_style = tab 40 | indent_size = 4 41 | end_of_line = crlf 42 | charset = utf-8 43 | trim_trailing_whitespace = true 44 | insert_final_newline = false 45 | 46 | [*.asmdef] 47 | scrape_api = true 48 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 3D models 2 | *.3dm filter=lfs diff=lfs merge=lfs -text 3 | *.3ds filter=lfs diff=lfs merge=lfs -text 4 | *.blend filter=lfs diff=lfs merge=lfs -text 5 | *.c4d filter=lfs diff=lfs merge=lfs -text 6 | *.collada filter=lfs diff=lfs merge=lfs -text 7 | *.dae filter=lfs diff=lfs merge=lfs -text 8 | *.dxf filter=lfs diff=lfs merge=lfs -text 9 | *.fbx filter=lfs diff=lfs merge=lfs -text 10 | *.jas filter=lfs diff=lfs merge=lfs -text 11 | *.lws filter=lfs diff=lfs merge=lfs -text 12 | *.lxo filter=lfs diff=lfs merge=lfs -text 13 | *.ma filter=lfs diff=lfs merge=lfs -text 14 | *.max filter=lfs diff=lfs merge=lfs -text 15 | *.mb filter=lfs diff=lfs merge=lfs -text 16 | *.obj filter=lfs diff=lfs merge=lfs -text 17 | *.ply filter=lfs diff=lfs merge=lfs -text 18 | *.skp filter=lfs diff=lfs merge=lfs -text 19 | *.stl filter=lfs diff=lfs merge=lfs -text 20 | *.ztl filter=lfs diff=lfs merge=lfs -text 21 | # Audio 22 | *.aif filter=lfs diff=lfs merge=lfs -text 23 | *.aiff filter=lfs diff=lfs merge=lfs -text 24 | *.it filter=lfs diff=lfs merge=lfs -text 25 | *.mod filter=lfs diff=lfs merge=lfs -text 26 | *.mp3 filter=lfs diff=lfs merge=lfs -text 27 | *.ogg filter=lfs diff=lfs merge=lfs -text 28 | *.s3m filter=lfs diff=lfs merge=lfs -text 29 | *.wav filter=lfs diff=lfs merge=lfs -text 30 | *.xm filter=lfs diff=lfs merge=lfs -text 31 | # Fonts 32 | *.otf filter=lfs diff=lfs merge=lfs -text 33 | *.ttf filter=lfs diff=lfs merge=lfs -text 34 | # Images 35 | *.bmp filter=lfs diff=lfs merge=lfs -text 36 | *.exr filter=lfs diff=lfs merge=lfs -text 37 | *.gif filter=lfs diff=lfs merge=lfs -text 38 | *.hdr filter=lfs diff=lfs merge=lfs -text 39 | *.iff filter=lfs diff=lfs merge=lfs -text 40 | *.jpeg filter=lfs diff=lfs merge=lfs -text 41 | *.jpg filter=lfs diff=lfs merge=lfs -text 42 | *.pict filter=lfs diff=lfs merge=lfs -text 43 | *.png filter=lfs diff=lfs merge=lfs -text 44 | *.psd filter=lfs diff=lfs merge=lfs -text 45 | *.tga filter=lfs diff=lfs merge=lfs -text 46 | *.tif filter=lfs diff=lfs merge=lfs -text 47 | *.tiff filter=lfs diff=lfs merge=lfs -text 48 | *.lfs.* filter=lfs diff=lfs merge=lfs -crlf 49 | 50 | # Collapse Unity-generated files on GitHub 51 | *.asset linguist-generated 52 | *.mat linguist-generated 53 | *.meta linguist-generated 54 | *.prefab linguist-generated 55 | *.unity linguist-generated 56 | 57 | # match .editorconfig 58 | *.vcproj eol=crlf 59 | *.bat eol=crlf 60 | *.cmd eol=crlf 61 | *.xaml eol=crlf 62 | *.tt eol=crlf 63 | *.t4 eol=crlf 64 | *.ttinclude eol=crlf 65 | 66 | *.vcxproj eol=crlf 67 | *.vcxproj.filters eol=crlf 68 | 69 | *.csproj eol=crlf 70 | *.pyproj eol=crlf 71 | *.props eol=crlf 72 | *.targets eol=crlf 73 | 74 | *.sln eol=crlf 75 | *.sln.template eol=crlf 76 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Purpose of this PR 2 | 3 | [Desc of feature/change. Links to screenshots, design docs, user docs, etc. Remember reviewers may be outside your team, and not know your feature/area that should be explained more.] 4 | 5 | [Links to related PRs go here near the top] 6 | 7 | ### Testing status 8 | 9 | [Explanation of what’s tested, how tested and existing or new automation tests. Can include manual testing by self and/or QA. Specify test plans. Rarely acceptable to have no testing.] 10 | 11 | ### Documentation status 12 | 13 | [Overview of how documentation is affected by this change. If there is no effect on documentation, explain why. Otherwise, state which sections are changed and why.] 14 | 15 | ### Changelog status 16 | 17 | [Overview of how the changelog is affected by this change. Add the appropriate section(s) if needed: Changed, Added, Fixed, or API Changes. If you don't think this change should be reflected in the changelog, mention why here.] 18 | 19 | ### Public API changes 20 | 21 | [Does this PR change existing or introduce new public methods? If possible, API changes should be exposed through the Interfaces repo and/or FI. If not, explain here.] 22 | 23 | ### Analytics update 24 | 25 | [Overview of how analytics events are affected by this change. If there is no effect on analytics events, explain why (eg. this change doesn't introduce or update user actions).] 26 | 27 | ### Technical risk 28 | 29 | [Overall product level assessment of risk of change. Need technical risk & halo effect.] 30 | 31 | ### Comments to reviewers 32 | 33 | [Info per person for what to focus on, or historical info to understand who have previously reviewed and coverage. Help them get context.] 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | artifacts/** 2 | build/** 3 | .build_script/** 4 | node_modules/** 5 | .DS_Store 6 | .npmrc 7 | !Documentation~ 8 | !.Documentation 9 | npm-debug.log 10 | build.sh.meta 11 | build.bat.meta 12 | .idea/ 13 | 14 | # Local upm-ci runs 15 | upm-ci~ 16 | .Editor 17 | .bin 18 | .download -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | artifacts/** 2 | build/** 3 | .build_script/** 4 | node_modules/** 5 | Documentation/ApiDocs/** 6 | Documentation~/ApiDocs/** 7 | .DS_Store 8 | .npmrc 9 | .npmignore 10 | .gitignore 11 | .gitattributes 12 | CONTRIBUTING.md 13 | CONTRIBUTING.md.meta 14 | QAReport.md 15 | QAReport.md.meta 16 | .gitlab-ci.yml 17 | build.sh 18 | build.sh.meta 19 | build.bat 20 | build.bat.meta 21 | 22 | .github/** 23 | 24 | upm-ci~/** 25 | .Editor/** 26 | .yamato/** 27 | *.zip* 28 | TestRunnerOptions.json 29 | .idea/** 30 | .bin/** 31 | .download/** 32 | 33 | *.api 34 | *.api.meta 35 | 36 | .editorconfig 37 | -------------------------------------------------------------------------------- /.yamato/pack.yml: -------------------------------------------------------------------------------- 1 | pack: 2 | name: Pack 3 | agent: 4 | type: Unity::VM 5 | image: package-ci/ubuntu:stable 6 | flavor: b1.large 7 | commands: 8 | - git submodule update --init --recursive 9 | - npm install upm-ci-utils@stable -g --registry https://artifactory.prd.it.unity3d.com/artifactory/api/npm/upm-npm 10 | - upm-ci package pack --package-path . 11 | artifacts: 12 | packages: 13 | paths: 14 | - "upm-ci~/packages/**/*" -------------------------------------------------------------------------------- /.yamato/project.metafile: -------------------------------------------------------------------------------- 1 | # Editors used for test before publication 2 | blocking_test_editors: 3 | - version: 2019.1.14f1 4 | 5 | # Other editor versions used for tests 6 | nonblocking_test_editors: 7 | - version: 2019.4 8 | - version: 2020.1 9 | - version: 2020.2 10 | - version: 2020.3 11 | - version: 2021.1 12 | - version: 2021.2 13 | 14 | # Platforms that will be tested 15 | test_platforms: 16 | - name: Windows 17 | type: Unity::VM 18 | image: package-ci/win10:stable 19 | flavor: b1.large 20 | - name: MacOS 21 | type: Unity::VM::osx 22 | image: package-ci/mac:stable 23 | flavor: m1.mac 24 | 25 | urls: 26 | upm: https://artifactory.prd.it.unity3d.com/artifactory/api/npm/upm-npm 27 | -------------------------------------------------------------------------------- /.yamato/promote.yml: -------------------------------------------------------------------------------- 1 | {% metadata_file .yamato/project.metafile %} 2 | --- 3 | 4 | {% for editor in blocking_test_editors %} 5 | {% for platform in test_platforms %} 6 | promotion_test_{{ platform.name }}_{{ editor.version }}: 7 | name : Promotion Test {{ editor.version }} on {{ platform.name }} 8 | agent: 9 | type: {{ platform.type }} 10 | image: {{ platform.image }} 11 | flavor: {{ platform.flavor}} 12 | variables: 13 | UPMCI_PROMOTION: 1 14 | commands: 15 | - npm install upm-ci-utils@stable -g --registry {{ urls.upm }} 16 | - upm-ci package test --unity-version {{ editor.version }} --package-path . 17 | artifacts: 18 | logs: 19 | paths: 20 | - "upm-ci~/test-results/**/*" 21 | dependencies: 22 | - .yamato/pack.yml#pack 23 | {% endfor %} 24 | {% endfor %} 25 | 26 | promotion_test_trigger: 27 | name: Promotion Tests Trigger 28 | dependencies: 29 | {% for editor in blocking_test_editors %} 30 | {% for platform in test_platforms %} 31 | - .yamato/promote.yml#promotion_test_{{platform.name}}_{{editor.version}} 32 | {% endfor %} 33 | {% endfor %} 34 | 35 | promote: 36 | name: Promote to Production 37 | agent: 38 | type: Unity::VM 39 | image: package-ci/win10:stable 40 | flavor: b1.large 41 | variables: 42 | UPMCI_PROMOTION: 1 43 | commands: 44 | - npm install upm-ci-utils@stable -g --registry {{ urls.upm }} 45 | - upm-ci package promote --package-path . 46 | triggers: 47 | tags: 48 | only: 49 | - /^(r|R)elease-\d+\.\d+\.\d+(-preview(\.\d+)?)?$/ 50 | artifacts: 51 | artifacts: 52 | paths: 53 | - "upm-ci~/packages/*.tgz" 54 | dependencies: 55 | - .yamato/pack.yml#pack 56 | {% for editor in blocking_test_editors %} 57 | {% for platform in test_platforms %} 58 | - .yamato/promote.yml#promotion_test_{{ platform.name }}_{{ editor.version }} 59 | {% endfor %} 60 | {% endfor %} -------------------------------------------------------------------------------- /.yamato/publish.yml: -------------------------------------------------------------------------------- 1 | {% metadata_file .yamato/project.metafile %} 2 | --- 3 | 4 | publish: 5 | name: Publish to Internal Registry 6 | agent: 7 | type: Unity::VM 8 | image: package-ci/win10:stable 9 | flavor: b1.large 10 | commands: 11 | - npm install upm-ci-utils@stable -g --registry {{ urls.upm }} 12 | - upm-ci package publish --package-path . 13 | triggers: 14 | tags: 15 | only: 16 | - /^(r|R)(c|C)-\d+\.\d+\.\d+(-preview(\.\d+)?)?$/ 17 | artifacts: 18 | artifacts: 19 | paths: 20 | - "upm-ci~/packages/*.tgz" 21 | dependencies: 22 | - .yamato/pack.yml#pack 23 | {% for editor in blocking_test_editors %} 24 | {% for platform in test_platforms %} 25 | - .yamato/test.yml#test_{{ platform.name }}_{{ editor.version }} 26 | - .yamato/test.yml#validate_{{ platform.name }}_{{ editor.version }} 27 | {% endfor %} 28 | {% endfor %} 29 | -------------------------------------------------------------------------------- /.yamato/test.yml: -------------------------------------------------------------------------------- 1 | {% metadata_file .yamato/project.metafile %} 2 | --- 3 | 4 | {% for editor in blocking_test_editors %} 5 | {% for platform in test_platforms %} 6 | test_{{ platform.name }}_{{ editor.version }}: 7 | name : Test {{ editor.version }} on {{ platform.name }} 8 | agent: 9 | type: {{ platform.type }} 10 | image: {{ platform.image }} 11 | flavor: {{ platform.flavor}} 12 | commands: 13 | - npm install upm-ci-utils@stable -g --registry {{ urls.upm }} 14 | - upm-ci package test -u {{ editor.version }} --package-path . --type package-tests --extra-create-project-arg="-upmNoDefaultPackages" 15 | artifacts: 16 | logs: 17 | paths: 18 | - "upm-ci~/test-results/**/*" 19 | dependencies: 20 | - .yamato/pack.yml#pack 21 | {% endfor %} 22 | {% endfor %} 23 | 24 | {% for editor in nonblocking_test_editors %} 25 | {% for platform in test_platforms %} 26 | test_{{ platform.name }}_{{ editor.version }}: 27 | name : Test {{ editor.version }} on {{ platform.name }} 28 | agent: 29 | type: {{ platform.type }} 30 | image: {{ platform.image }} 31 | flavor: {{ platform.flavor}} 32 | commands: 33 | - npm install upm-ci-utils@stable -g --registry {{ urls.upm }} 34 | - upm-ci package test -u {{ editor.version }} --package-path . --type package-tests --extra-create-project-arg="-upmNoDefaultPackages" 35 | artifacts: 36 | logs: 37 | paths: 38 | - "upm-ci~/test-results/**/*" 39 | dependencies: 40 | - .yamato/pack.yml#pack 41 | {% endfor %} 42 | {% endfor %} 43 | 44 | # Validate the package on each editor version and each platform 45 | # Validation only occurs in editmode. 46 | {% for editor in blocking_test_editors %} 47 | {% for platform in test_platforms %} 48 | validate_{{ platform.name }}_{{ editor.version }}: 49 | name : Validate {{ editor.version }} on {{ platform.name }} 50 | agent: 51 | type: {{ platform.type }} 52 | image: {{ platform.image }} 53 | flavor: {{ platform.flavor}} 54 | commands: 55 | - npm install upm-ci-utils@stable -g --registry {{ urls.upm }} 56 | - upm-ci package test -u {{ editor.version }} --package-path . --type vetting-tests --platform editmode --extra-create-project-arg="-upmNoDefaultPackages" 57 | artifacts: 58 | logs: 59 | paths: 60 | - "upm-ci~/test-results/**/*" 61 | dependencies: 62 | - .yamato/pack.yml#pack 63 | {% endfor %} 64 | {% endfor %} 65 | 66 | test_trigger: 67 | name: Tests Trigger 68 | triggers: 69 | branches: 70 | only: 71 | - "main" 72 | pull_requests: 73 | - targets: 74 | only: 75 | - "/.*/" 76 | dependencies: 77 | - .yamato/pack.yml#pack 78 | {% for editor in blocking_test_editors %} 79 | {% for platform in test_platforms %} 80 | - .yamato/test.yml#test_{{platform.name}}_{{editor.version}} 81 | - .yamato/test.yml#validate_{{platform.name}}_{{editor.version}} 82 | {% endfor %} 83 | {% endfor %} 84 | {% for editor in nonblocking_test_editors %} 85 | {% for platform in test_platforms %} 86 | - .yamato/test.yml#test_{{platform.name}}_{{editor.version}} 87 | {% endfor %} 88 | {% endfor %} 89 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this package will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.1.3-preview] - 2021-05-27 8 | - Add api "RefreshMesh" to MeshChainRenderer to manually trigger the mesh to be updated. 9 | This is normally already done if needed in LateUpdate, but this method can be used to force the mesh to update, such as in Application.BeforeRender to stay aligned with an XR controller updating pose during that callback 10 | 11 | ## [0.1.2-preview] - 2020-07-31 12 | - Replace "Labs" with "XRTools" in package name and namespaces 13 | 14 | ## [0.1.1-preview] - 2020-01-03 15 | Clean up for package release 16 | 17 | ## [0.1.0-preview.1] - 2019-12-09 18 | Fix an issue where m_Width was not taken into account for startWidth and endWidth properties 19 | 20 | ## [0.1.0-preview] - 2019-11-25 21 | 22 | ### This is the first release of *Unity Package \*. 23 | -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c2a55c0f54054f4d8093d6c66d7946b 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## If you are interested in contributing, here are some ground rules: 4 | * ... Define guidelines & rules for what contributors need to know to successfully make Pull requests against your repo ... 5 | 6 | ## All contributions are subject to the [Unity Contribution Agreement(UCA)](https://unity3d.com/legal/licenses/Unity_Contribution_Agreement) 7 | By making a pull request, you are confirming agreement to the terms and conditions of the UCA, including that your Contributions are your original creation and that you have complete right and authority to make your Contributions. 8 | 9 | ## Once you have a change ready following these ground rules. Simply make a pull request 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c2a56c0f54064f4d8094d6c66d7946b 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Documentation~/com.unity.xrlinerenderer.md: -------------------------------------------------------------------------------- 1 | # XR Line Renderer 2 | An XR-Optimized line renderer that is also capable of producing very inexpensive glow effects. The XRLineRenderer mimics rendering with 3d capsules while only using two quads worth of geometry. 3 | 4 | ## Setup and usage 5 | 6 | 1. Import the XRLineRenderer package in your project. 7 | 8 | 2. Add a XRLineRenderer or XRTrailRenderer component to your gameobject. The interface is nearly identical to the built in Unity Line and Trail Renderers. 9 | 10 | 3. Create a new material using the XRLineRenderer shaders. You can find some examples in XRLineRenderer\Materials 11 | 12 | 4. Apply this material to the mesh renderer of your XRLineRenderer or XRTrailRenderer. 13 | 14 | 15 | ## VRLineRenderer Shader 16 | You will find five shader variants under the XRLineRenderer category. Each of these corresponds to a shader blend mode. 17 | Max Color and Min Color are the cheapest variants - if you are using the line renderer to mimic glow effects these variants also are stable in that color will not blow out. 18 | 19 | Explanation of interesting shader parameters: 20 | Line Rendering Levels - This allows control over the blend between the inner(most opaque/intense) part of the line and outer(transparent) area. Adjust the level curve to 0 will give a very glow-like effect while setting the cruve to 1 will make the line completely solid. 21 | 22 | Line Scaled by Depth - Turning this option off means the line will stay the same thickness regardless of your distance from it. This is excellent for drafting lines and also for simulating glow. Radius minimum and maximum allow you to clamp this size adjustment. 23 | 24 | 25 | ## Custom VR Line Rendering 26 | The Scripts\Meshchain class provides everything you need to make your own custom line rendering constructs. XRLineRenderer and XRTrailRenderer emulate what the classic Unity components provide, but there are many more use cases out there. 27 | 28 | 29 | ### Project Settings 30 | If you plan on making changes to The XR Line Renderer and/or contributing back, then you'll need to set the `Asset Serialization` property under Edit->Project Settings->Editor to `Force Text` -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4fd9fe4d6579634459e5e84b3e164981 3 | folderAsset: yes 4 | timeCreated: 1461004779 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Editor/MeshChainShaderGUI.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Unity.XRTools.Rendering 5 | { 6 | class MeshChainShaderGUI : ShaderGUI 7 | { 8 | static class Styles 9 | { 10 | public static GUIContent colorText = new GUIContent("Line Tint", "Line Color (RGB) and Transparency (A)"); 11 | public static GUIContent lineDataSpaceText = new GUIContent("World Space Data", "If true, the data " + 12 | "will not be transformed before rendering"); 13 | 14 | public static string lineSettingsText = "Line Rendering Levels"; 15 | public static GUIContent lineCurveMinText = new GUIContent("Minimum Cutoff", "How far from the edge" + 16 | " of the geometry to start fading in line"); 17 | public static GUIContent lineCurveMaxText = new GUIContent("Maximum Cutoff", "How far from the center " + 18 | "of the geometry to start fading out the line"); 19 | public static GUIContent lineCurveBendText = new GUIContent("Level Curve", "The intensity curve from " + 20 | "line edge to line center"); 21 | 22 | public static string lineRadiusText = "Line Radius Settings"; 23 | public static GUIContent lineRadiusDepthText = new GUIContent("Line Scaled by Depth", "Set to false to " + 24 | "get fixed width lines - useful for debugging or drafting views"); 25 | public static GUIContent lineRadiusScaleText = new GUIContent("Radius Scale", "How much to scale the " + 26 | "width of the line in total"); 27 | public static GUIContent lineRadiusMinText = new GUIContent("Radius Minimum", "Minimum size the line " + 28 | "width must be regardless of distance"); 29 | public static GUIContent lineRadiusMaxText = new GUIContent("Radius Maximum", "Maximum size the line " + 30 | "widht must be regardless of distance"); 31 | } 32 | 33 | MaterialEditor m_MaterialEditor; 34 | bool m_FirstTimeApply = true; 35 | 36 | MaterialProperty m_LineColor; 37 | MaterialProperty m_LineSettings; 38 | MaterialProperty m_LineRadius; 39 | 40 | MaterialProperty m_LineDataSpace; 41 | MaterialProperty m_LineDepthScaleMode; 42 | 43 | public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) 44 | { 45 | FindProperties(properties); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly 46 | m_MaterialEditor = materialEditor; 47 | Material material = materialEditor.target as Material; 48 | 49 | ShaderPropertiesGUI(material); 50 | 51 | // Make sure that needed setup (ie keywords/renderqueue) are set up 52 | if (m_FirstTimeApply) 53 | { 54 | MaterialChanged(material); 55 | m_FirstTimeApply = false; 56 | } 57 | } 58 | 59 | void FindProperties(MaterialProperty[] props) 60 | { 61 | m_LineColor = FindProperty("_Color", props); 62 | m_LineSettings = FindProperty("_lineSettings", props); 63 | m_LineRadius = FindProperty("_lineRadius", props); 64 | 65 | // CCS Customizations 66 | m_LineDataSpace = FindProperty("_WorldData", props, false); 67 | m_LineDepthScaleMode = FindProperty("_LineDepthScale", props, false); 68 | } 69 | 70 | void ShaderPropertiesGUI(Material material) 71 | { 72 | // Use default labelWidth 73 | EditorGUIUtility.labelWidth = 0f; 74 | 75 | // Detect any changes to the material 76 | EditorGUI.BeginChangeCheck(); 77 | { 78 | // Color 79 | m_MaterialEditor.ShaderProperty(m_LineColor, Styles.colorText.text); 80 | 81 | EditorGUILayout.Space(); 82 | 83 | // World space flag 84 | if (m_LineDataSpace != null) 85 | { 86 | bool inWorldSpace = !Mathf.Approximately(m_LineDataSpace.floatValue, 0.0f); 87 | var newWorldSpace = EditorGUILayout.Toggle(Styles.lineDataSpaceText, inWorldSpace); 88 | if (newWorldSpace != inWorldSpace) 89 | { 90 | if (newWorldSpace == true) 91 | { 92 | m_LineDataSpace.floatValue = 1.0f; 93 | } 94 | else 95 | { 96 | m_LineDataSpace.floatValue = 0.0f; 97 | } 98 | } 99 | } 100 | 101 | 102 | EditorGUILayout.Space(); 103 | // Line thickness curve settings 104 | GUILayout.Label(Styles.lineSettingsText, EditorStyles.boldLabel); 105 | var lineLevels = m_LineSettings.vectorValue; 106 | var newLineMin = EditorGUILayout.Slider(Styles.lineCurveMinText, lineLevels.x, 0.0f, 1.0f); 107 | var newLineMax = EditorGUILayout.Slider(Styles.lineCurveMaxText, lineLevels.y, 0.0f, 1.0f); 108 | var newLineBend = EditorGUILayout.Slider(Styles.lineCurveBendText, lineLevels.z, 0.0f, 1.0f); 109 | 110 | if (newLineMin != lineLevels.x || newLineMax != lineLevels.y || newLineBend != lineLevels.z) 111 | { 112 | lineLevels.x = newLineMin; 113 | lineLevels.y = newLineMax; 114 | lineLevels.z = newLineBend; 115 | m_LineSettings.vectorValue = lineLevels; 116 | } 117 | 118 | EditorGUILayout.Space(); 119 | // Maximum line radius 120 | GUILayout.Label(Styles.lineRadiusText, EditorStyles.boldLabel); 121 | var radiusSettings = m_LineRadius.vectorValue; 122 | var depthScaleMode = true; 123 | if (m_LineDepthScaleMode != null) 124 | { 125 | depthScaleMode = !Mathf.Approximately(m_LineDepthScaleMode.floatValue, 0.0f); 126 | var newDepthScaleMode = EditorGUILayout.Toggle(Styles.lineRadiusDepthText, depthScaleMode); 127 | if (newDepthScaleMode != depthScaleMode) 128 | { 129 | if (newDepthScaleMode == true) 130 | { 131 | m_LineDepthScaleMode.floatValue = 1.0f; 132 | } 133 | else 134 | { 135 | m_LineDepthScaleMode.floatValue = 0.0f; 136 | } 137 | } 138 | } 139 | var newRadiusScale = EditorGUILayout.FloatField(Styles.lineRadiusScaleText, radiusSettings.x); 140 | var newRadiusMin = Mathf.Max(EditorGUILayout.FloatField(Styles.lineRadiusMinText, radiusSettings.y), 0.0f); 141 | var newRadiusMax = radiusSettings.z; 142 | 143 | if (depthScaleMode == false) 144 | { 145 | newRadiusMax = Mathf.Max(EditorGUILayout.FloatField(Styles.lineRadiusMaxText, radiusSettings.z), newRadiusMin); 146 | } 147 | 148 | if (newRadiusScale != radiusSettings.x || newRadiusMin != radiusSettings.y || newRadiusMax != radiusSettings.z) 149 | { 150 | radiusSettings.x = newRadiusScale; 151 | radiusSettings.y = newRadiusMin; 152 | radiusSettings.z = newRadiusMax; 153 | m_LineRadius.vectorValue = radiusSettings; 154 | } 155 | } 156 | if (EditorGUI.EndChangeCheck()) 157 | { 158 | MaterialChanged(material); 159 | } 160 | } 161 | 162 | static void MaterialChanged(Material material) 163 | { 164 | var worldDataMode = false; 165 | var depthScaleMode = true; 166 | if (material.HasProperty("_WorldData")) 167 | { 168 | worldDataMode = !Mathf.Approximately(material.GetFloat("_WorldData"), 0.0f); 169 | } 170 | if (material.HasProperty("_LineDepthScale")) 171 | { 172 | depthScaleMode = !Mathf.Approximately(material.GetFloat("_LineDepthScale"), 0.0f); 173 | } 174 | if (worldDataMode) 175 | { 176 | SetKeyword(material, "LINE_MODEL_SPACE", false); 177 | SetKeyword(material, "LINE_WORLD_SPACE", true); 178 | } 179 | else 180 | { 181 | SetKeyword(material, "LINE_MODEL_SPACE", true); 182 | SetKeyword(material, "LINE_WORLD_SPACE", false); 183 | } 184 | 185 | if (depthScaleMode) 186 | { 187 | SetKeyword(material, "LINE_FIXED_WIDTH", false); 188 | SetKeyword(material, "LINE_PERSPECTIVE_WIDTH", true); 189 | } 190 | else 191 | { 192 | SetKeyword(material, "LINE_FIXED_WIDTH", true); 193 | SetKeyword(material, "LINE_PERSPECTIVE_WIDTH", false); 194 | } 195 | } 196 | 197 | static void SetKeyword(Material m, string keyword, bool state) 198 | { 199 | if (state) 200 | m.EnableKeyword(keyword); 201 | else 202 | m.DisableKeyword(keyword); 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /Editor/MeshChainShaderGUI.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2ab884b866da2f9428e66d9b6b4b5488 3 | timeCreated: 1461005730 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Editor/Unity.XRLineRenderer.Editor.api: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not modify by hand. 2 | // XML documentation file not found. To check if public methods have XML comments, 3 | // make sure the XML doc file is present and located next to the scraped dll 4 | -------------------------------------------------------------------------------- /Editor/Unity.XRLineRenderer.Editor.api.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c30cd6f560caa499b9cd23c7f53a0cc8 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Unity.XRLineRenderer.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Unity.XRLineRenderer.Editor", 3 | "references": [ 4 | "Unity.XRLineRenderer" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /Editor/Unity.XRLineRenderer.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e484b69e484584edd9f645b14ea9e149 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/XRLineRendererEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Unity.XRTools.Rendering 5 | { 6 | [CustomEditor(typeof(XRLineRenderer))] 7 | [CanEditMultipleObjects] 8 | class XRLineRendererEditor : Editor 9 | { 10 | SerializedProperty m_Materials; 11 | SerializedProperty m_Positions; 12 | SerializedProperty m_UseWorldSpace; 13 | SerializedProperty m_Loop; 14 | SerializedProperty m_Width; 15 | SerializedProperty m_WidthCurve; 16 | SerializedProperty m_Color; 17 | 18 | void OnEnable() 19 | { 20 | m_Materials = serializedObject.FindProperty("m_Materials"); 21 | m_Positions = serializedObject.FindProperty("m_Positions"); 22 | m_UseWorldSpace = serializedObject.FindProperty("m_UseWorldSpace"); 23 | m_Loop = serializedObject.FindProperty("m_Loop"); 24 | m_Width = serializedObject.FindProperty("m_Width"); 25 | m_WidthCurve = serializedObject.FindProperty("m_WidthCurve"); 26 | m_Color = serializedObject.FindProperty("m_Color"); 27 | } 28 | 29 | public override void OnInspectorGUI() 30 | { 31 | serializedObject.Update(); 32 | EditorGUILayout.PropertyField(m_Materials, true); 33 | EditorGUILayout.PropertyField(m_Positions, true); 34 | 35 | using (new EditorGUI.DisabledGroupScope(true)) 36 | { 37 | EditorGUILayout.PropertyField(m_UseWorldSpace, true); 38 | } 39 | 40 | EditorGUILayout.PropertyField(m_Loop, true); 41 | EditorGUILayout.PropertyField(m_Width, true); 42 | EditorGUILayout.CurveField(m_WidthCurve, Color.red, new Rect(0, 0, 1, 1)); 43 | EditorGUILayout.PropertyField(m_Color, true); 44 | serializedObject.ApplyModifiedProperties(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Editor/XRLineRendererEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4c5ea26f559a1142a56ad844b2636ad 3 | timeCreated: 1461105823 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Editor/XRTrailRendererEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Unity.XRTools.Rendering 5 | { 6 | [CustomEditor(typeof(XRTrailRenderer))] 7 | [CanEditMultipleObjects] 8 | class XRTrailRendererEditor : Editor 9 | { 10 | SerializedProperty m_Materials; 11 | SerializedProperty m_Time; 12 | SerializedProperty m_MinVertexDistance; 13 | SerializedProperty m_Autodestruct; 14 | SerializedProperty m_Width; 15 | SerializedProperty m_WidthCurve; 16 | SerializedProperty m_Color; 17 | SerializedProperty m_MaxTrailPoints; 18 | SerializedProperty m_StealLastPointWhenEmpty; 19 | SerializedProperty m_SmoothInterpolation; 20 | 21 | void OnEnable() 22 | { 23 | m_Materials = serializedObject.FindProperty("m_Materials"); 24 | m_Time = serializedObject.FindProperty("m_Time"); 25 | m_MinVertexDistance = serializedObject.FindProperty("m_MinVertexDistance"); 26 | m_Autodestruct = serializedObject.FindProperty("m_Autodestruct"); 27 | m_Width = serializedObject.FindProperty("m_Width"); 28 | m_WidthCurve = serializedObject.FindProperty("m_WidthCurve"); 29 | m_Color = serializedObject.FindProperty("m_Color"); 30 | m_MaxTrailPoints = serializedObject.FindProperty("m_MaxTrailPoints"); 31 | m_StealLastPointWhenEmpty = serializedObject.FindProperty("m_StealLastPointWhenEmpty"); 32 | m_SmoothInterpolation = serializedObject.FindProperty("m_SmoothInterpolation"); 33 | } 34 | 35 | public override void OnInspectorGUI() 36 | { 37 | serializedObject.Update(); 38 | EditorGUILayout.PropertyField(m_Materials, true); 39 | EditorGUILayout.PropertyField(m_Time, true); 40 | EditorGUILayout.PropertyField(m_MinVertexDistance, true); 41 | EditorGUILayout.PropertyField(m_Autodestruct, true); 42 | EditorGUILayout.PropertyField(m_Width, true); 43 | EditorGUILayout.CurveField(m_WidthCurve, Color.red, new Rect(0, 0, 1, 1)); 44 | EditorGUILayout.PropertyField(m_Color, true); 45 | EditorGUILayout.PropertyField(m_MaxTrailPoints, true); 46 | EditorGUILayout.PropertyField(m_StealLastPointWhenEmpty, true); 47 | EditorGUILayout.PropertyField(m_SmoothInterpolation, true); 48 | serializedObject.ApplyModifiedProperties(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Editor/XRTrailRendererEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 60c20f5e263661c4cb1756073a77fa2f 3 | timeCreated: 1461105823 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | XR Line Renderer copyright © 2020 Unity Technologies ApS 2 | 3 | Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License). 4 | 5 | Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions. 6 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d7c689de92b8439a8ba59e4ebe085ab 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9c486c724e0c9764e965b8ef889b9974 3 | folderAsset: yes 4 | timeCreated: 1460416554 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Materials/AdditiveLine.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: AdditiveLine 11 | m_Shader: {fileID: 4800000, guid: d689c77434e9ecb4084bd09df8d53140, type: 3} 12 | m_ShaderKeywords: LINE_MODEL_SPACE LINE_PERSPECTIVE_WIDTH 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 1 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.5 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 0, g: 0.21568628, b: 1, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 0, g: 0.21379282, b: 1, a: 1} 43 | - _lineRadius: {r: 1, g: 0, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 1, b: 0.5019608, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/AdditiveLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e381d940f0ee33445b16f286c175a437 3 | timeCreated: 1460657499 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/AlphaLine.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: AlphaLine 11 | m_Shader: {fileID: 4800000, guid: d2d82e816970e9849bc93f1842c33050, type: 3} 12 | m_ShaderKeywords: LINE_MODEL_SPACE LINE_PERSPECTIVE_WIDTH 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 1 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.5 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 0.4679156, g: 0.9411765, b: 0.42906576, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 1, g: 1, b: 1, a: 1} 43 | - _lineRadius: {r: 0.15, g: 0.05, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 1, b: 0.5019608, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/AlphaLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a10e4f88372c8d488aaeb8a2a406e04 3 | timeCreated: 1460592339 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/CleanLine.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: CleanLine 11 | m_Shader: {fileID: 4800000, guid: d2d82e816970e9849bc93f1842c33050, type: 3} 12 | m_ShaderKeywords: LINE_FIXED_WIDTH LINE_MODEL_SPACE 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 0 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.05 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 0, g: 0, b: 0, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 0, g: 0, b: 0, a: 1} 43 | - _lineRadius: {r: 0.05, g: 0, b: 0.1, a: 1} 44 | - _lineSettings: {r: 0, g: 0.65, b: 1, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/CleanLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8a2e408edfc70b4429dd0a23d491b3fe 3 | timeCreated: 1460503976 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/MaxLine.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: MaxLine 11 | m_Shader: {fileID: 4800000, guid: c03eb3285154f9d48aef80b7b148e361, type: 3} 12 | m_ShaderKeywords: LINE_MODEL_SPACE LINE_PERSPECTIVE_WIDTH 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 1 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.5 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 1, g: 1, b: 1, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 1, g: 1, b: 1, a: 1} 43 | - _lineRadius: {r: 2, g: 0, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 1, b: 0.5019608, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/MaxLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dd3701db925467648931a23810852797 3 | timeCreated: 1460488272 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/MinLine.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: MinLine 11 | m_Shader: {fileID: 4800000, guid: 9e975b2c6a84c4f479b8ef83f0a88e6f, type: 3} 12 | m_ShaderKeywords: LINE_MODEL_SPACE LINE_PERSPECTIVE_WIDTH 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 1 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.5 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 0, g: 0, b: 0, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 0, g: 0, b: 0, a: 1} 43 | - _lineRadius: {r: 2, g: 0, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 1, b: 0.5, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/MinLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6aa5f808098ddc646b19ec1b94158659 3 | timeCreated: 1460503971 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/PhotonBladeCore.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: PhotonBladeCore 11 | m_Shader: {fileID: 4800000, guid: d2d82e816970e9849bc93f1842c33050, type: 3} 12 | m_ShaderKeywords: LINE_MODEL_SPACE LINE_PERSPECTIVE_WIDTH 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 1 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.05 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 1, g: 1, b: 1, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 1, g: 1, b: 1, a: 1} 43 | - _lineRadius: {r: 1, g: 0, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 0.447, b: 0.5019608, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/PhotonBladeCore.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6f3e05c2aa6d9cb4a9d0835514837ac3 3 | timeCreated: 1460768986 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/PhotonBladeGlow.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: PhotonBladeGlow 11 | m_Shader: {fileID: 4800000, guid: d689c77434e9ecb4084bd09df8d53140, type: 3} 12 | m_ShaderKeywords: LINE_FIXED_WIDTH LINE_MODEL_SPACE 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 0 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.5 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 1, g: 0, b: 0, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 1, g: 0, b: 0, a: 1} 43 | - _lineRadius: {r: 0.75, g: 0, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 1, b: 0.308, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/PhotonBladeGlow.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d901fe6933510974e963164c35e7aa36 3 | timeCreated: 1460768991 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/Regular Line.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: Regular Line 11 | m_Shader: {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 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_Floats: 23 | - PixelSnap: 0 24 | - _BumpScale: 1 25 | - _Cutoff: 0.5 26 | - _DetailNormalMapScale: 1 27 | - _DstBlend: 0 28 | - _EnableExternalAlpha: 0 29 | - _GlossMapScale: 1 30 | - _Glossiness: 0.5 31 | - _GlossyReflections: 1 32 | - _Metallic: 0 33 | - _Mode: 0 34 | - _OcclusionStrength: 1 35 | - _Parallax: 0.02 36 | - _SmoothnessTextureChannel: 0 37 | - _SpecularHighlights: 1 38 | - _SrcBlend: 1 39 | - _UVSec: 0 40 | - _ZWrite: 1 41 | m_Colors: 42 | - _Color: {r: 1, g: 1, b: 1, a: 1} 43 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 44 | - _Flip: {r: 1, g: 1, b: 1, a: 1} 45 | - _RendererColor: {r: 1, g: 1, b: 1, a: 1} 46 | -------------------------------------------------------------------------------- /Materials/Regular Line.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7f19429fe1ca8945b318015cdce8f98 3 | timeCreated: 1500761077 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 2100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Materials/ShowcaseBox.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: ShowcaseBox 11 | m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} 12 | m_ShaderKeywords: _EMISSION 13 | m_LightmapFlags: 1 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: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _MainTex: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 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_Floats: 59 | - _BumpScale: 1 60 | - _Cutoff: 0.5 61 | - _DetailNormalMapScale: 1 62 | - _DstBlend: 0 63 | - _GlossMapScale: 1 64 | - _Glossiness: 0 65 | - _GlossyReflections: 1 66 | - _Metallic: 0 67 | - _Mode: 0 68 | - _OcclusionStrength: 1 69 | - _Parallax: 0.02 70 | - _SmoothnessTextureChannel: 0 71 | - _SpecularHighlights: 1 72 | - _SrcBlend: 1 73 | - _UVSec: 0 74 | - _ZWrite: 1 75 | m_Colors: 76 | - _Color: {r: 1, g: 1, b: 1, a: 1} 77 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 78 | -------------------------------------------------------------------------------- /Materials/ShowcaseBox.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec1c961e32d65a94b9872bd36cdba0c7 3 | timeCreated: 1482362887 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/SubtractiveLine.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: SubtractiveLine 11 | m_Shader: {fileID: 4800000, guid: 9d1af3afcc83db644b8abe552f6a0e05, type: 3} 12 | m_ShaderKeywords: LINE_MODEL_SPACE LINE_PERSPECTIVE_WIDTH 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 1 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 0 36 | - _ZWrite: 1 37 | - _lineRadius: 0.5 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 0.5882353, g: 0.5882353, b: 0.5882353, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 0.5882352, g: 0.5882352, b: 0.5882352, a: 1} 43 | - _lineRadius: {r: 2, g: 0, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 1, b: 0.5, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/SubtractiveLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7be3ae795c98f64cbcd52badad12c94 3 | timeCreated: 1460657505 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials/TrailLine.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: TrailLine 11 | m_Shader: {fileID: 4800000, guid: d2d82e816970e9849bc93f1842c33050, type: 3} 12 | m_ShaderKeywords: LINE_PERSPECTIVE_WIDTH LINE_WORLD_SPACE 13 | m_LightmapFlags: 5 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: 3000 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: [] 22 | m_Floats: 23 | - _BumpScale: 1 24 | - _Cutoff: 0.5 25 | - _DetailNormalMapScale: 1 26 | - _DstBlend: 0 27 | - _Glossiness: 0.5 28 | - _LineDepthScale: 1 29 | - _Metallic: 0 30 | - _Mode: 0 31 | - _OcclusionStrength: 1 32 | - _Parallax: 0.02 33 | - _SrcBlend: 1 34 | - _UVSec: 0 35 | - _WorldData: 1 36 | - _ZWrite: 1 37 | - _lineRadius: 0.5 38 | - _lineRadiusMin: 0 39 | m_Colors: 40 | - _Color: {r: 1, g: 1, b: 1, a: 1} 41 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 42 | - _lineColor: {r: 1, g: 1, b: 1, a: 1} 43 | - _lineRadius: {r: 1, g: 0, b: 100, a: 1} 44 | - _lineSettings: {r: 0, g: 0.12, b: 0.5019608, a: 1} 45 | -------------------------------------------------------------------------------- /Materials/TrailLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad3c41a831eb2514ebdff29205b96b60 3 | timeCreated: 1461966782 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XR Line Renderer 2 | An XR-Optimized line renderer that is also capable of producing very inexpensive glow effects. The XRLineRenderer mimics rendering with 3d capsules while only using two quads worth of geometry. 3 | 4 | ## Setup and usage 5 | 6 | 1. Import the XRLineRenderer package in your project. 7 | 8 | 2. Add a XRLineRenderer or XRTrailRenderer component to your gameobject. The interface is nearly identical to the built in Unity Line and Trail Renderers. 9 | 10 | 3. Create a new material using the XRLineRenderer shaders. You can find some examples in XRLineRenderer\Materials 11 | 12 | 4. Apply this material to the mesh renderer of your XRLineRenderer or XRTrailRenderer. 13 | 14 | 15 | ## VRLineRenderer Shader 16 | You will find five shader variants under the XRLineRenderer category. Each of these corresponds to a shader blend mode. 17 | Max Color and Min Color are the cheapest variants - if you are using the line renderer to mimic glow effects these variants also are stable in that color will not blow out. 18 | 19 | Explanation of interesting shader parameters: 20 | Line Rendering Levels - This allows control over the blend between the inner(most opaque/intense) part of the line and outer(transparent) area. Adjust the level curve to 0 will give a very glow-like effect while setting the cruve to 1 will make the line completely solid. 21 | 22 | Line Scaled by Depth - Turning this option off means the line will stay the same thickness regardless of your distance from it. This is excellent for drafting lines and also for simulating glow. Radius minimum and maximum allow you to clamp this size adjustment. 23 | 24 | 25 | ## Custom VR Line Rendering 26 | The Scripts\Meshchain class provides everything you need to make your own custom line rendering constructs. XRLineRenderer and XRTrailRenderer emulate what the classic Unity components provide, but there are many more use cases out there. 27 | 28 | 29 | ### Project Settings 30 | If you plan on making changes to The XR Line Renderer and/or contributing back, then you'll need to set the `Asset Serialization` property under Edit->Project Settings->Editor to `Force Text` -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 643ade27617b1bd4bb0b64de11085d28 3 | timeCreated: 1486337121 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3723a07280d304a4b9436306b61dfafc 3 | folderAsset: yes 4 | timeCreated: 1460396598 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Runtime/MeshChainRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Unity.XRTools.Rendering 5 | { 6 | /// 7 | /// A unified base class for the XR Line Renderer and XR Trail Renderer 8 | /// 9 | [RequireComponent(typeof(MeshRenderer))] 10 | [RequireComponent(typeof(MeshFilter))] 11 | [ExecuteInEditMode] 12 | [DisallowMultipleComponent] 13 | public abstract class MeshChainRenderer : MonoBehaviour 14 | { 15 | static readonly GradientColorKey k_DefaultStartColor = new GradientColorKey(Color.white, 0); 16 | static readonly GradientColorKey k_DefaultEndColor = new GradientColorKey(Color.white, 1); 17 | static readonly GradientAlphaKey k_DefaultStartAlpha = new GradientAlphaKey(1, 0); 18 | static readonly GradientAlphaKey k_DefaultEndAlpha = new GradientAlphaKey(1, 1); 19 | 20 | /// 21 | /// Materials to use when rendering. 22 | /// 23 | [SerializeField] 24 | [Tooltip("Materials to use when rendering.")] 25 | protected Material[] m_Materials; 26 | 27 | /// 28 | /// The multiplier applied to the curve, describing the width (in world space) along the line. 29 | /// 30 | [SerializeField] 31 | [Tooltip("The multiplier applied to the curve, describing the width (in world space) along the line.")] 32 | protected float m_Width = 1.0f; 33 | 34 | /// 35 | /// The curve describing the width of the line at various points along its length. 36 | /// 37 | [SerializeField] 38 | [Tooltip("The curve describing the width of the line at various points along its length.")] 39 | protected AnimationCurve m_WidthCurve = new AnimationCurve(); 40 | 41 | /// 42 | /// The gradient describing color along the line. 43 | /// 44 | [SerializeField] 45 | [Tooltip("The gradient describing color along the line.")] 46 | protected Gradient m_Color = new Gradient(); 47 | 48 | /// 49 | /// The MeshRenderer used to render the line 50 | /// 51 | [SerializeField] 52 | [HideInInspector] 53 | protected MeshRenderer m_MeshRenderer; 54 | 55 | /// 56 | /// Cached mesh data 57 | /// 58 | protected XRMeshChain m_XRMeshData; 59 | 60 | /// 61 | /// Whether the mesh data needs to be refreshed 62 | /// 63 | protected bool m_MeshNeedsRefreshing; 64 | 65 | /// 66 | /// The step size 67 | /// 68 | protected float m_StepSize = 1.0f; 69 | 70 | /// 71 | /// Returns the first instantiated Material assigned to the renderer. 72 | /// 73 | public virtual Material material 74 | { 75 | get { return m_MeshRenderer.material; } 76 | set { m_MeshRenderer.material = value; } 77 | } 78 | 79 | /// 80 | /// Returns all the instantiated materials of this object. 81 | /// 82 | public virtual Material[] materials 83 | { 84 | get { return m_MeshRenderer.materials; } 85 | set { m_MeshRenderer.materials = value; } 86 | } 87 | 88 | /// 89 | /// Returns the shared material of this object. 90 | /// 91 | public virtual Material sharedMaterial 92 | { 93 | get { return m_MeshRenderer.sharedMaterial; } 94 | set { m_MeshRenderer.sharedMaterial = value; } 95 | } 96 | 97 | /// 98 | /// Returns all shared materials of this object. 99 | /// 100 | public virtual Material[] SharedMaterials 101 | { 102 | get { return m_MeshRenderer.materials; } 103 | set { m_MeshRenderer.sharedMaterials = value; } 104 | } 105 | 106 | /// 107 | /// Set the width at the start of the line. 108 | /// 109 | public float widthStart 110 | { 111 | get { return m_WidthCurve.Evaluate(0) * m_Width; } 112 | set 113 | { 114 | if (m_Width == 0 || float.IsNaN(m_Width)) 115 | return; 116 | 117 | var keys = m_WidthCurve.keys; 118 | keys[0].value = value / m_Width; 119 | m_WidthCurve.keys = keys; 120 | UpdateWidth(); 121 | } 122 | } 123 | 124 | /// 125 | /// Set the width at the end of the line. 126 | /// 127 | public float widthEnd 128 | { 129 | get { return m_WidthCurve.Evaluate(1) * m_Width; } 130 | set 131 | { 132 | if (m_Width == 0 || float.IsNaN(m_Width)) 133 | return; 134 | 135 | var keys = m_WidthCurve.keys; 136 | var lastIndex = keys.Length - 1; 137 | keys[lastIndex].value = value / m_Width; 138 | m_WidthCurve.keys = keys; 139 | UpdateWidth(); 140 | } 141 | } 142 | 143 | /// 144 | /// Set an overall multiplier that is applied to the LineRenderer.widthCurve to get the final width of the line. 145 | /// 146 | public float widthMultiplier 147 | { 148 | get { return m_Width; } 149 | set 150 | { 151 | m_Width = value; 152 | UpdateWidth(); 153 | } 154 | } 155 | 156 | /// 157 | /// Set the curve describing the width of the line at various points along its length. 158 | /// 159 | public AnimationCurve widthCurve 160 | { 161 | get { return m_WidthCurve; } 162 | set 163 | { 164 | m_WidthCurve = value ?? new AnimationCurve(new Keyframe(0, 1.0f)); 165 | UpdateWidth(); 166 | } 167 | } 168 | 169 | /// 170 | /// Set the color gradient describing the color of the line at various points along its length. 171 | /// 172 | public Gradient colorGradient 173 | { 174 | get { return m_Color; } 175 | set 176 | { 177 | if (m_Color == value) 178 | { 179 | return; 180 | } 181 | 182 | m_Color = value ?? new Gradient 183 | { 184 | alphaKeys = new[] { k_DefaultStartAlpha, k_DefaultEndAlpha }, 185 | colorKeys = new[] { k_DefaultStartColor, k_DefaultEndColor }, 186 | mode = GradientMode.Blend 187 | }; 188 | UpdateColors(); 189 | } 190 | } 191 | 192 | /// 193 | /// Set the color at the start of the line. 194 | /// 195 | public Color colorStart 196 | { 197 | get { return m_Color.Evaluate(0); } 198 | set 199 | { 200 | var colorKeys = m_Color.colorKeys; 201 | var alphaKeys = m_Color.alphaKeys; 202 | var flatColor = value; 203 | flatColor.a = 1.0f; 204 | colorKeys[0].color = flatColor; 205 | alphaKeys[0].alpha = value.a; 206 | m_Color.colorKeys = colorKeys; 207 | m_Color.alphaKeys = alphaKeys; 208 | UpdateColors(); 209 | } 210 | } 211 | 212 | /// 213 | /// Set the color at the end of the line. 214 | /// 215 | public Color colorEnd 216 | { 217 | get { return m_Color.Evaluate(1); } 218 | set 219 | { 220 | var colorKeys = m_Color.colorKeys; 221 | var alphaKeys = m_Color.alphaKeys; 222 | var lastColorIndex = colorKeys.Length - 1; 223 | var lastAlphaIndex = alphaKeys.Length - 1; 224 | var flatColor = value; 225 | flatColor.a = 1.0f; 226 | colorKeys[lastColorIndex].color = flatColor; 227 | alphaKeys[lastAlphaIndex].alpha = value.a; 228 | m_Color.colorKeys = colorKeys; 229 | m_Color.alphaKeys = alphaKeys; 230 | UpdateColors(); 231 | } 232 | } 233 | 234 | /// 235 | /// Resets the width to a straight curve at the given value 236 | /// 237 | /// The new width for the curve to display 238 | public void SetTotalWidth(float newWidth) 239 | { 240 | m_Width = newWidth; 241 | m_WidthCurve = new AnimationCurve(new Keyframe(0, 1.0f)); 242 | UpdateWidth(); 243 | } 244 | 245 | /// 246 | /// Resets the color to a single value 247 | /// 248 | /// The new color for the curve to display 249 | public void SetTotalColor(Color newColor) 250 | { 251 | var flatColor = newColor; 252 | flatColor.a = 1.0f; 253 | m_Color = new Gradient 254 | { 255 | alphaKeys = new[] { new GradientAlphaKey(newColor.a, 0), new GradientAlphaKey(newColor.a, 1), }, 256 | colorKeys = new[] { new GradientColorKey(flatColor, 0), new GradientColorKey(flatColor, 1) }, 257 | mode = GradientMode.Blend 258 | }; 259 | UpdateColors(); 260 | } 261 | 262 | void OnValidate() 263 | { 264 | SetupMeshBackend(); 265 | if (NeedsReinitialize()) 266 | { 267 | #if UNITY_EDITOR 268 | UnityEditor.EditorApplication.delayCall += EditorCheckForUpdate; 269 | #endif 270 | } 271 | else 272 | { 273 | EditorCheckForUpdate(); 274 | } 275 | } 276 | 277 | /// 278 | /// Manually trigger the mesh data to be refreshed. This is automatically done in LateUpdate if anything has changed. 279 | /// 280 | public void RefreshMesh() 281 | { 282 | m_XRMeshData.RefreshMesh(); 283 | m_MeshNeedsRefreshing = false; 284 | } 285 | 286 | /// 287 | /// Cleans up the visible interface of the MeshRenderer by hiding unneeded components 288 | /// Also makes sure the animation curves are set up properly to defaults 289 | /// 290 | void SetupMeshBackend() 291 | { 292 | if (m_MeshRenderer == null) 293 | m_MeshRenderer = GetComponent(); 294 | 295 | if (m_MeshRenderer.hideFlags == HideFlags.None) 296 | m_MeshRenderer.hideFlags = HideFlags.HideInInspector; 297 | 298 | var meshFilter = GetComponent(); 299 | if (meshFilter.hideFlags == HideFlags.None) 300 | meshFilter.hideFlags = HideFlags.HideInInspector; 301 | 302 | if (m_Materials == null || m_Materials.Length == 0) 303 | { 304 | m_Materials = m_MeshRenderer.sharedMaterials; 305 | } 306 | 307 | var sharedMaterials = m_MeshRenderer.sharedMaterials; 308 | var length = sharedMaterials.Length; 309 | var materialsEqual = true; 310 | for (var i = 0; i < length; i++) 311 | { 312 | if (sharedMaterials[i] != m_Materials[i]) 313 | { 314 | materialsEqual = false; 315 | break; 316 | } 317 | } 318 | 319 | if (!materialsEqual) 320 | { 321 | m_MeshRenderer.sharedMaterials = m_Materials; 322 | } 323 | 324 | if (m_WidthCurve == null || m_WidthCurve.keys == null || m_WidthCurve.keys.Length == 0) 325 | { 326 | m_WidthCurve = new AnimationCurve(new Keyframe(0, 1.0f)); 327 | } 328 | 329 | if (m_Color == null) 330 | { 331 | m_Color = new Gradient 332 | { 333 | alphaKeys = new[] { k_DefaultStartAlpha, k_DefaultEndAlpha }, 334 | colorKeys = new[] { k_DefaultStartColor, k_DefaultEndColor }, 335 | mode = GradientMode.Blend 336 | }; 337 | } 338 | } 339 | 340 | /// 341 | /// Makes the sure mesh renderer reference is initialized before any functions try to access it 342 | /// 343 | protected virtual void Awake() 344 | { 345 | SetupMeshBackend(); 346 | Initialize(); 347 | } 348 | 349 | /// 350 | /// Makes the sure mesh renderer reference is initialized on reset of the component 351 | /// 352 | void Reset() 353 | { 354 | SetupMeshBackend(); 355 | Initialize(); 356 | } 357 | 358 | /// 359 | /// Ensures the lines have all their data precached upon loading 360 | /// 361 | void Start() 362 | { 363 | Initialize(); 364 | } 365 | 366 | #if UNITY_EDITOR 367 | /// 368 | /// Ensures the hidden mesh/meshfilters are destroyed if users are messing with the components in edit mode 369 | /// 370 | void OnDestroy() 371 | { 372 | if (!Application.isPlaying) 373 | { 374 | var rendererToDestroy = m_MeshRenderer; 375 | var filterToDestroy = gameObject.GetComponent(); 376 | 377 | UnityEditor.EditorApplication.delayCall += () => 378 | { 379 | if (!Application.isPlaying) 380 | { 381 | if (rendererToDestroy != null) 382 | { 383 | DestroyImmediate(rendererToDestroy); 384 | } 385 | 386 | if (filterToDestroy != null) 387 | { 388 | DestroyImmediate(filterToDestroy); 389 | } 390 | } 391 | }; 392 | 393 | } 394 | } 395 | #endif 396 | 397 | /// 398 | /// Does the actual internal mesh updating as late as possible so nothing ends up a frame behind 399 | /// 400 | protected virtual void LateUpdate() 401 | { 402 | if (m_MeshNeedsRefreshing == true) 403 | { 404 | m_XRMeshData.RefreshMesh(); 405 | m_MeshNeedsRefreshing = false; 406 | } 407 | } 408 | 409 | /// 410 | /// Allows the component to be referenced as a renderer, forwarding the MeshRenderer ahead 411 | /// 412 | /// 413 | /// The MeshChainRenderer's MeshRenderer 414 | public static implicit operator Renderer(MeshChainRenderer meshChainRenderer) 415 | { 416 | return meshChainRenderer.m_MeshRenderer; 417 | } 418 | 419 | 420 | /// 421 | /// Triggered by validation - forced initialization to make sure data changed 422 | /// in the editor is reflected immediately to the user. 423 | /// 424 | void EditorCheckForUpdate() 425 | { 426 | // Because this gets delay-called, it can be referring to a destroyed component when a scene starts 427 | if (this != null) 428 | { 429 | // If we did not initialize, refresh all the properties instead 430 | Initialize(false); 431 | } 432 | } 433 | 434 | /// 435 | /// Updates any internal variables to represent the new color that has been applied 436 | /// 437 | protected virtual void UpdateColors() { } 438 | 439 | /// 440 | /// Updates any internal variables to represent the new width that has been applied 441 | /// 442 | protected virtual void UpdateWidth() { } 443 | 444 | /// 445 | /// Creates or updates the underlying mesh data 446 | /// 447 | protected virtual void Initialize(bool generate = true) { } 448 | 449 | /// 450 | /// Tests if the mesh data needs to be created or rebuilt 451 | /// 452 | /// true if the mesh data needs recreation, false if it is already set up properly 453 | protected virtual bool NeedsReinitialize() 454 | { 455 | return true; 456 | } 457 | 458 | /// 459 | /// Enables the internal mesh representing the line 460 | /// 461 | protected virtual void OnEnable() 462 | { 463 | m_MeshRenderer.enabled = true; 464 | } 465 | 466 | /// 467 | /// Disables the internal mesh representing the line 468 | /// 469 | protected virtual void OnDisable() 470 | { 471 | m_MeshRenderer.enabled = false; 472 | } 473 | } 474 | } 475 | -------------------------------------------------------------------------------- /Runtime/MeshChainRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c6fac5da14f92a142bf4a9db96769d61 3 | timeCreated: 1460396552 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Runtime/Unity.XRLineRenderer.api: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not modify by hand. 2 | // XML documentation file not found. To check if public methods have XML comments, 3 | // make sure the XML doc file is present and located next to the scraped dll 4 | namespace Unity.XRTools.Rendering 5 | { 6 | [UnityEngine.DisallowMultipleComponent] [UnityEngine.ExecuteInEditMode] [UnityEngine.RequireComponent(typeof(UnityEngine.MeshFilter))] [UnityEngine.RequireComponent(typeof(UnityEngine.MeshRenderer))] public abstract class MeshChainRenderer : UnityEngine.MonoBehaviour 7 | { 8 | [UnityEngine.SerializeField] [UnityEngine.Tooltip(@"The gradient describing color along the line.")] protected UnityEngine.Gradient m_Color; 9 | [UnityEngine.SerializeField] [UnityEngine.Tooltip(@"Materials to use when rendering.")] protected UnityEngine.Material[] m_Materials; 10 | protected bool m_MeshNeedsRefreshing; 11 | [UnityEngine.HideInInspector] [UnityEngine.SerializeField] protected UnityEngine.MeshRenderer m_MeshRenderer; 12 | protected float m_StepSize; 13 | [UnityEngine.SerializeField] [UnityEngine.Tooltip(@"The multiplier applied to the curve, describing the width (in world space) along the line.")] protected float m_Width; 14 | [UnityEngine.SerializeField] [UnityEngine.Tooltip(@"The curve describing the width of the line at various points along its length.")] protected UnityEngine.AnimationCurve m_WidthCurve; 15 | protected Unity.XRTools.Rendering.XRMeshChain m_XRMeshData; 16 | public UnityEngine.Color colorEnd { get; set; } 17 | public UnityEngine.Gradient colorGradient { get; set; } 18 | public UnityEngine.Color colorStart { get; set; } 19 | public virtual UnityEngine.Material material { get; set; } 20 | public virtual UnityEngine.Material[] materials { get; set; } 21 | public virtual UnityEngine.Material sharedMaterial { get; set; } 22 | public virtual UnityEngine.Material[] SharedMaterials { get; set; } 23 | public UnityEngine.AnimationCurve widthCurve { get; set; } 24 | public float widthEnd { get; set; } 25 | public float widthMultiplier { get; set; } 26 | public float widthStart { get; set; } 27 | protected MeshChainRenderer() {} 28 | protected virtual void Awake(); 29 | protected virtual void Initialize(bool generate = True); 30 | protected virtual void LateUpdate(); 31 | protected virtual bool NeedsReinitialize(); 32 | protected virtual void OnDisable(); 33 | protected virtual void OnEnable(); 34 | public static UnityEngine.Renderer op_Implicit(Unity.XRTools.Rendering.MeshChainRenderer meshChainRenderer); 35 | public void RefreshMesh(); 36 | public void SetTotalColor(UnityEngine.Color newColor); 37 | public void SetTotalWidth(float newWidth); 38 | protected virtual void UpdateColors(); 39 | protected virtual void UpdateWidth(); 40 | } 41 | 42 | [UnityEngine.ExecuteInEditMode] [UnityEngine.RequireComponent(typeof(UnityEngine.MeshFilter))] [UnityEngine.RequireComponent(typeof(UnityEngine.MeshRenderer))] public class XRLineRenderer : Unity.XRTools.Rendering.MeshChainRenderer 43 | { 44 | public bool loop { get; set; } 45 | public virtual UnityEngine.Material material { get; set; } 46 | public virtual UnityEngine.Material[] materials { get; set; } 47 | public virtual UnityEngine.Material sharedMaterial { get; set; } 48 | public virtual UnityEngine.Material[] SharedMaterials { get; set; } 49 | public bool useWorldSpace { get; set; } 50 | public XRLineRenderer() {} 51 | public UnityEngine.Vector3 GetPosition(int index); 52 | public int GetPositions(UnityEngine.Vector3[] positions); 53 | public int GetVertexCount(); 54 | protected virtual void Initialize(bool setMesh = True); 55 | protected virtual bool NeedsReinitialize(); 56 | public void SetPosition(int index, UnityEngine.Vector3 position); 57 | public void SetPositions(UnityEngine.Vector3[] newPositions, bool knownSizeChange = False); 58 | public void SetVertexCount(int count); 59 | protected virtual void UpdateColors(); 60 | protected virtual void UpdateWidth(); 61 | } 62 | 63 | public class XRMeshChain 64 | { 65 | public bool centerAtRoot { get; set; } 66 | public int reservedElements { get; } 67 | public bool worldSpaceData { get; set; } 68 | public XRMeshChain() {} 69 | public void GenerateMesh(UnityEngine.GameObject owner, bool dynamic, int totalElements, bool setMesh = True); 70 | public void RefreshMesh(); 71 | public void SetElementColor(int elementIndex, ref UnityEngine.Color color); 72 | public void SetElementColor(int elementIndex, ref UnityEngine.Color startColor, ref UnityEngine.Color endColor); 73 | public void SetElementColor32(int elementIndex, ref UnityEngine.Color32 color); 74 | public void SetElementColor32(int elementIndex, ref UnityEngine.Color32 startColor, ref UnityEngine.Color32 endColor); 75 | public void SetElementPipe(int elementIndex, ref UnityEngine.Vector3 startPoint, ref UnityEngine.Vector3 endPoint); 76 | public void SetElementPosition(int elementIndex, ref UnityEngine.Vector3 position); 77 | public void SetElementSize(int elementIndex, float sizeModification); 78 | public void SetElementSize(int elementIndex, float startSize, float endSize); 79 | public void SetMeshDataDirty(Unity.XRTools.Rendering.XRMeshChain.MeshRefreshFlag dataThatNeedsUpdate); 80 | [System.Flags] public enum MeshRefreshFlag 81 | { 82 | public const Unity.XRTools.Rendering.XRMeshChain.MeshRefreshFlag All = 7; 83 | public const Unity.XRTools.Rendering.XRMeshChain.MeshRefreshFlag Colors = 2; 84 | public const Unity.XRTools.Rendering.XRMeshChain.MeshRefreshFlag None = 0; 85 | public const Unity.XRTools.Rendering.XRMeshChain.MeshRefreshFlag Positions = 1; 86 | public const Unity.XRTools.Rendering.XRMeshChain.MeshRefreshFlag Sizes = 4; 87 | public int value__; 88 | } 89 | } 90 | 91 | [UnityEngine.ExecuteInEditMode] [UnityEngine.RequireComponent(typeof(UnityEngine.MeshFilter))] [UnityEngine.RequireComponent(typeof(UnityEngine.MeshRenderer))] public class XRTrailRenderer : Unity.XRTools.Rendering.MeshChainRenderer 92 | { 93 | public bool autodestruct { get; set; } 94 | public float minVertexDistance { get; set; } 95 | public int positionCount { get; } 96 | public bool smoothInterpolation { get; set; } 97 | public float time { get; set; } 98 | public XRTrailRenderer() {} 99 | public void Clear(); 100 | public void EditorCheckForUpdate(); 101 | protected virtual void Initialize(bool setMesh = True); 102 | protected virtual void LateUpdate(); 103 | protected virtual bool NeedsReinitialize(); 104 | protected virtual void OnEnable(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Runtime/Unity.XRLineRenderer.api.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9a0996ab90ab74483914dba64dadc3f5 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/Unity.XRLineRenderer.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Unity.XRLineRenderer", 3 | "references": [], 4 | "optionalUnityReferences": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false 8 | } -------------------------------------------------------------------------------- /Runtime/Unity.XRLineRenderer.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 507fb7fe0a2794ac481eab674e8b99cf 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/XRLineRenderer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Serialization; 3 | 4 | namespace Unity.XRTools.Rendering 5 | { 6 | /// 7 | /// An XR-Focused drop-in replacement for the Line Renderer 8 | /// This renderer draws fixed-width lines with simulated volume and glow. 9 | /// This has many of the advantages of the traditional Line Renderer, old-school system-level line rendering functions, 10 | /// and volumetric (a linked series of capsules or cubes) rendering 11 | /// 12 | [RequireComponent(typeof(MeshRenderer))] 13 | [RequireComponent(typeof(MeshFilter))] 14 | [ExecuteInEditMode] 15 | public class XRLineRenderer : MeshChainRenderer 16 | { 17 | // Stored Line Data 18 | [SerializeField] 19 | [Tooltip("All of the connected points to render as a line.")] 20 | Vector3[] m_Positions; 21 | 22 | [SerializeField] 23 | [FormerlySerializedAs("m_WorldSpaceData")] 24 | [Tooltip("Draw lines in worldspace (or local space) - driven via shader.")] 25 | bool m_UseWorldSpace; 26 | 27 | [SerializeField] 28 | [Tooltip("Connect the first and last vertices, to create a loop.")] 29 | bool m_Loop; 30 | 31 | /// 32 | /// Connect the first and last vertices, to create a loop. 33 | /// 34 | public bool loop 35 | { 36 | get { return m_Loop; } 37 | set 38 | { 39 | m_Loop = value; 40 | if (NeedsReinitialize()) 41 | Initialize(); 42 | } 43 | } 44 | 45 | /// 46 | /// Draw lines in worldspace (or local space) 47 | /// 48 | public bool useWorldSpace 49 | { 50 | get { return m_UseWorldSpace; } 51 | set { m_UseWorldSpace = value; } 52 | } 53 | 54 | /// 55 | /// Returns the first instantiated Material assigned to the renderer. 56 | /// 57 | public override Material material 58 | { 59 | get { return m_MeshRenderer.material; } 60 | set 61 | { 62 | m_MeshRenderer.material = value; 63 | CopyWorldSpaceDataFromMaterial(); 64 | } 65 | } 66 | 67 | /// 68 | /// Returns all the instantiated materials of this object. 69 | /// 70 | public override Material[] materials 71 | { 72 | get { return m_MeshRenderer.materials; } 73 | set 74 | { 75 | m_MeshRenderer.materials = value; 76 | CopyWorldSpaceDataFromMaterial(); 77 | } 78 | } 79 | 80 | /// 81 | /// Returns the shared material of this object. 82 | /// 83 | public override Material sharedMaterial 84 | { 85 | get { return m_MeshRenderer.sharedMaterial; } 86 | set 87 | { 88 | m_MeshRenderer.sharedMaterial = value; 89 | CopyWorldSpaceDataFromMaterial(); 90 | } 91 | } 92 | 93 | /// 94 | /// Returns all shared materials of this object. 95 | /// 96 | public override Material[] SharedMaterials 97 | { 98 | get { return m_MeshRenderer.materials; } 99 | set 100 | { 101 | m_MeshRenderer.sharedMaterials = value; 102 | CopyWorldSpaceDataFromMaterial(); 103 | } 104 | } 105 | 106 | /// 107 | /// Makes sure that the internal world space flag of the line renderer 108 | /// matches the world space flag of the first material on the object 109 | /// 110 | void CopyWorldSpaceDataFromMaterial() 111 | { 112 | var firstMaterial = m_MeshRenderer.sharedMaterial; 113 | if (firstMaterial == null) 114 | { 115 | return; 116 | } 117 | 118 | if (firstMaterial.HasProperty("_WorldData")) 119 | { 120 | m_UseWorldSpace = !Mathf.Approximately(firstMaterial.GetFloat("_WorldData"), 0.0f); 121 | } 122 | else 123 | { 124 | m_UseWorldSpace = false; 125 | } 126 | } 127 | 128 | /// 129 | /// Gets the position of the vertex in the line. 130 | /// 131 | /// The index of the position to retrieve 132 | /// The position at the specified index of the array 133 | public Vector3 GetPosition(int index) 134 | { 135 | return m_Positions[index]; 136 | } 137 | 138 | /// 139 | /// Sets the position of the vertex in the line. 140 | /// 141 | /// Which vertex to set 142 | /// The new location in space of this vertex 143 | public void SetPosition(int index, Vector3 position) 144 | { 145 | // Update internal data 146 | m_Positions[index] = position; 147 | 148 | // See if the data needs initializing 149 | if (NeedsReinitialize()) 150 | { 151 | Initialize(); 152 | return; 153 | } 154 | 155 | // Otherwise, do fast setting 156 | var prevIndex = (index - 1 + m_Positions.Length) % m_Positions.Length; 157 | var endIndex = (index + 1) % m_Positions.Length; 158 | 159 | if (index > 0 || m_Loop) 160 | { 161 | m_XRMeshData.SetElementPipe((index * 2) - 1, ref m_Positions[prevIndex], ref m_Positions[index]); 162 | } 163 | 164 | m_XRMeshData.SetElementPosition(index * 2, ref m_Positions[index]); 165 | if (index < (m_Positions.Length - 1) || m_Loop) 166 | { 167 | m_XRMeshData.SetElementPipe((index * 2) + 1, ref m_Positions[index], ref m_Positions[endIndex]); 168 | } 169 | 170 | m_XRMeshData.SetMeshDataDirty(XRMeshChain.MeshRefreshFlag.Positions); 171 | m_MeshNeedsRefreshing = true; 172 | } 173 | 174 | /// 175 | /// Get the position of all vertices in the line. 176 | /// 177 | /// The array of positions to retrieve. The array passed should be of at least numPositions in size. 178 | /// How many positions were actually stored in the output array. 179 | public int GetPositions(Vector3[] positions) 180 | { 181 | if (m_Positions != null) 182 | { 183 | m_Positions.CopyTo(positions, 0); 184 | return m_Positions.Length; 185 | } 186 | 187 | return 0; 188 | } 189 | 190 | /// 191 | /// Sets all positions in the line. Cheaper than calling SetPosition repeatedly 192 | /// 193 | /// All of the new endpoints of the line 194 | /// Turn on to run a safety check to make sure the number of endpoints does not change (bad for garbage collection) 195 | public void SetPositions(Vector3[] newPositions, bool knownSizeChange = false) 196 | { 197 | // Update internal data 198 | m_Positions = newPositions; 199 | if (NeedsReinitialize()) 200 | { 201 | if (knownSizeChange == false) 202 | { 203 | Debug.LogWarning("New positions does not match size of existing array. Adjusting vertex count as well"); 204 | } 205 | 206 | Initialize(); 207 | return; 208 | } 209 | 210 | if (m_Positions.Length <= 0) 211 | { 212 | return; 213 | } 214 | 215 | // Otherwise, do fast setting 216 | var pointCounter = 0; 217 | var elementCounter = 0; 218 | m_XRMeshData.SetElementPosition(elementCounter, ref m_Positions[pointCounter]); 219 | elementCounter++; 220 | pointCounter++; 221 | while (pointCounter < m_Positions.Length) 222 | { 223 | m_XRMeshData.SetElementPipe(elementCounter, ref m_Positions[pointCounter - 1], ref m_Positions[pointCounter]); 224 | elementCounter++; 225 | m_XRMeshData.SetElementPosition(elementCounter, ref m_Positions[pointCounter]); 226 | 227 | elementCounter++; 228 | pointCounter++; 229 | } 230 | 231 | if (m_Loop) 232 | { 233 | m_XRMeshData.SetElementPipe(elementCounter, ref m_Positions[pointCounter - 1], ref m_Positions[0]); 234 | } 235 | 236 | // Dirty all the VRMeshChain flags so everything gets refreshed 237 | m_XRMeshData.SetMeshDataDirty(XRMeshChain.MeshRefreshFlag.Positions); 238 | m_MeshNeedsRefreshing = true; 239 | } 240 | 241 | /// 242 | /// Sets the number of billboard-line chains. This function regenerates the point list if the 243 | /// number of vertex points changes, so use it sparingly. 244 | /// 245 | /// The new number of vertices in the line 246 | public void SetVertexCount(int count) 247 | { 248 | // See if anything needs updating 249 | if (m_Positions.Length == count) 250 | { 251 | return; 252 | } 253 | 254 | // Adjust this array 255 | var newPositions = new Vector3[count]; 256 | var copyCount = Mathf.Min(m_Positions.Length, count); 257 | var copyIndex = 0; 258 | 259 | while (copyIndex < copyCount) 260 | { 261 | newPositions[copyIndex] = m_Positions[copyIndex]; 262 | copyIndex++; 263 | } 264 | 265 | m_Positions = newPositions; 266 | 267 | // Do an initialization, this changes everything 268 | Initialize(); 269 | } 270 | 271 | /// 272 | /// Get the number of billboard-line chains. 273 | /// 274 | /// The number of chains 275 | public int GetVertexCount() 276 | { 277 | return m_Positions.Length; 278 | } 279 | 280 | /// 281 | /// Updates any internal variables to represent the new color that has been applied 282 | /// 283 | protected override void UpdateColors() 284 | { 285 | // See if the data needs initializing 286 | if (NeedsReinitialize()) 287 | { 288 | Initialize(); 289 | return; 290 | } 291 | 292 | if (m_Positions.Length <= 0) 293 | { 294 | return; 295 | } 296 | 297 | // If it doesn't, go through each point and set the data 298 | var pointCounter = 0; 299 | var elementCounter = 0; 300 | var stepPercent = 0.0f; 301 | 302 | var lastColor = m_Color.Evaluate(stepPercent); 303 | m_XRMeshData.SetElementColor(elementCounter, ref lastColor); 304 | elementCounter++; 305 | pointCounter++; 306 | stepPercent += m_StepSize; 307 | 308 | while (pointCounter < m_Positions.Length) 309 | { 310 | var currentColor = m_Color.Evaluate(stepPercent); 311 | m_XRMeshData.SetElementColor(elementCounter, ref lastColor, ref currentColor); 312 | elementCounter++; 313 | 314 | m_XRMeshData.SetElementColor(elementCounter, ref currentColor); 315 | 316 | lastColor = currentColor; 317 | elementCounter++; 318 | pointCounter++; 319 | stepPercent += m_StepSize; 320 | } 321 | 322 | if (m_Loop) 323 | { 324 | lastColor = m_Color.Evaluate(stepPercent); 325 | m_XRMeshData.SetElementColor(elementCounter, ref lastColor); 326 | } 327 | 328 | // Dirty the color meshChain flags so the mesh gets new data 329 | m_XRMeshData.SetMeshDataDirty(XRMeshChain.MeshRefreshFlag.Colors); 330 | m_MeshNeedsRefreshing = true; 331 | } 332 | 333 | /// 334 | /// Updates any internal variables to represent the new width that has been applied 335 | /// 336 | protected override void UpdateWidth() 337 | { 338 | // See if the data needs initializing 339 | if (NeedsReinitialize()) 340 | { 341 | Initialize(); 342 | return; 343 | } 344 | 345 | if (m_Positions.Length <= 0) 346 | { 347 | return; 348 | } 349 | 350 | // Otherwise, do fast setting 351 | var pointCounter = 0; 352 | var elementCounter = 0; 353 | var stepPercent = 0.0f; 354 | 355 | // We go through the element list, much like initialization, but only update the width part of the variables 356 | var lastWidth = m_WidthCurve.Evaluate(stepPercent) * m_Width; 357 | m_XRMeshData.SetElementSize(elementCounter, lastWidth); 358 | elementCounter++; 359 | pointCounter++; 360 | 361 | stepPercent += m_StepSize; 362 | 363 | while (pointCounter < m_Positions.Length) 364 | { 365 | var currentWidth = m_WidthCurve.Evaluate(stepPercent) * m_Width; 366 | 367 | m_XRMeshData.SetElementSize(elementCounter, lastWidth, currentWidth); 368 | elementCounter++; 369 | m_XRMeshData.SetElementSize(elementCounter, currentWidth); 370 | lastWidth = currentWidth; 371 | elementCounter++; 372 | pointCounter++; 373 | stepPercent += m_StepSize; 374 | } 375 | 376 | if (m_Loop) 377 | { 378 | var currentWidth = m_WidthCurve.Evaluate(stepPercent) * m_Width; 379 | m_XRMeshData.SetElementSize(elementCounter, lastWidth, currentWidth); 380 | } 381 | 382 | // Dirty all the VRMeshChain flags so everything gets refreshed 383 | m_XRMeshData.SetMeshDataDirty(XRMeshChain.MeshRefreshFlag.Sizes); 384 | m_MeshNeedsRefreshing = true; 385 | } 386 | 387 | /// 388 | /// Creates or updates the underlying mesh data 389 | /// 390 | protected override void Initialize(bool setMesh = true) 391 | { 392 | base.Initialize(); 393 | CopyWorldSpaceDataFromMaterial(); 394 | 395 | if (m_Positions == null) 396 | m_Positions = new Vector3[0]; 397 | 398 | // For a line renderer we assume one big chain 399 | // We need a control point for each billboard and a control point for each pipe connecting them together 400 | // Except for the end, which must be capped with another billboard. This gives us (positions * 2) - 1 401 | // If we're looping, then we do need one more pipe 402 | var neededPoints = m_Loop ? 1 : 0; 403 | neededPoints = Mathf.Max(neededPoints + (m_Positions.Length * 2) - 1, 0); 404 | 405 | if (m_XRMeshData == null) 406 | { 407 | m_XRMeshData = new XRMeshChain(); 408 | } 409 | 410 | if (m_XRMeshData.reservedElements != neededPoints) 411 | { 412 | m_XRMeshData.worldSpaceData = useWorldSpace; 413 | m_XRMeshData.GenerateMesh(gameObject, true, neededPoints, setMesh); 414 | } 415 | 416 | // If we have no points, then just assume that stepping through a single point would take us through the whole line 417 | if (neededPoints == 0) 418 | { 419 | m_StepSize = 1.0f; 420 | return; 421 | } 422 | 423 | m_StepSize = 1.0f / Mathf.Max(m_Loop ? m_Positions.Length : m_Positions.Length - 1, 1.0f); 424 | 425 | var pointCounter = 0; 426 | var elementCounter = 0; 427 | var stepPercent = 0.0f; 428 | 429 | var lastColor = m_Color.Evaluate(stepPercent); 430 | var lastWidth = m_WidthCurve.Evaluate(stepPercent) * m_Width; 431 | 432 | // Initialize the single starting point 433 | m_XRMeshData.SetElementSize(elementCounter, lastWidth); 434 | m_XRMeshData.SetElementPosition(elementCounter, ref m_Positions[pointCounter]); 435 | m_XRMeshData.SetElementColor(elementCounter, ref lastColor); 436 | elementCounter++; 437 | pointCounter++; 438 | 439 | stepPercent += m_StepSize; 440 | 441 | // Now do the chain 442 | while (pointCounter < m_Positions.Length) 443 | { 444 | var currentWidth = m_WidthCurve.Evaluate(stepPercent) * m_Width; 445 | var currentColor = m_Color.Evaluate(stepPercent); 446 | 447 | // Create a pipe from the previous point to here 448 | m_XRMeshData.SetElementSize(elementCounter, lastWidth, currentWidth); 449 | m_XRMeshData.SetElementPipe(elementCounter, ref m_Positions[pointCounter - 1], ref m_Positions[pointCounter]); 450 | m_XRMeshData.SetElementColor(elementCounter, ref lastColor, ref currentColor); 451 | elementCounter++; 452 | 453 | // Now record our own point data 454 | m_XRMeshData.SetElementSize(elementCounter, currentWidth); 455 | m_XRMeshData.SetElementPosition(elementCounter, ref m_Positions[pointCounter]); 456 | m_XRMeshData.SetElementColor(elementCounter, ref currentColor); 457 | 458 | // Go onto the next point while retaining previous values we might need to lerp between 459 | lastWidth = currentWidth; 460 | lastColor = currentColor; 461 | elementCounter++; 462 | pointCounter++; 463 | stepPercent += m_StepSize; 464 | } 465 | 466 | if (m_Loop) 467 | { 468 | var currentWidth = m_WidthCurve.Evaluate(stepPercent) * m_Width; 469 | var currentColor = m_Color.Evaluate(stepPercent); 470 | m_XRMeshData.SetElementSize(elementCounter, lastWidth, currentWidth); 471 | m_XRMeshData.SetElementPipe(elementCounter, ref m_Positions[pointCounter - 1], ref m_Positions[0]); 472 | m_XRMeshData.SetElementColor(elementCounter, ref lastColor, ref currentColor); 473 | } 474 | 475 | // Dirty all the VRMeshChain flags so everything gets refreshed 476 | m_XRMeshData.SetMeshDataDirty(XRMeshChain.MeshRefreshFlag.All); 477 | m_MeshNeedsRefreshing = true; 478 | } 479 | 480 | /// 481 | /// Tests if the mesh data needs to be created or rebuilt 482 | /// 483 | /// true if the mesh data needs recreation, false if it is already set up properly 484 | protected override bool NeedsReinitialize() 485 | { 486 | // No mesh data means we definitely need to reinitialize 487 | if (m_XRMeshData == null) 488 | { 489 | return true; 490 | } 491 | 492 | // If we have any positions, figure out how many points we need to render a line along it 493 | var neededPoints = 0; 494 | if (m_Positions != null) 495 | { 496 | neededPoints = Mathf.Max((m_Positions.Length * 2) - 1, 0); 497 | if (m_Loop) 498 | { 499 | neededPoints++; 500 | } 501 | } 502 | 503 | return (m_XRMeshData.reservedElements != neededPoints); 504 | } 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /Runtime/XRLineRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d580b86a6ae18014293c9b5059b2121b 3 | timeCreated: 1460396552 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Runtime/XRMeshChain.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Unity.XRTools.Rendering 5 | { 6 | /// 7 | /// The mesh chain handles all the translation between Unity's mesh class, 8 | /// what the line renderers want to do, and what the billboard-pipe based shaders expect 9 | /// If you need more custom/optimized access to this kind of mesh information, feel 10 | /// free to hook into this structure directly. 11 | /// 12 | public class XRMeshChain 13 | { 14 | /// 15 | /// What part of the mesh to refresh 16 | /// 17 | [System.Flags] 18 | public enum MeshRefreshFlag 19 | { 20 | /// 21 | /// Don't refresh any of the mesh 22 | /// 23 | None = 0, 24 | 25 | /// 26 | /// Refresh positions 27 | /// 28 | Positions = 1, 29 | 30 | /// 31 | /// Refresh colors 32 | /// 33 | Colors = 2, 34 | 35 | /// 36 | /// Refresh sizes 37 | /// 38 | Sizes = 4, 39 | 40 | /// 41 | /// Refresh all mesh components 42 | /// 43 | All = 7 44 | } 45 | 46 | Vector3[] m_Verts; 47 | Color32[] m_Colors; 48 | List m_ShapeData; // xy: UV coordinates for GPU expansion zw: Size of this vertex, size of the neighbor 49 | List m_NeighborPoints; // Location of the next point this pipe connects to, or itself if it is a billboard 50 | 51 | // Update flags to prevent unnecessary mesh data generation 52 | MeshRefreshFlag m_DataThatNeedsUpdate = MeshRefreshFlag.All; 53 | 54 | // Cached runtime data 55 | Mesh m_Mesh; 56 | Transform m_OwnerTransform; 57 | 58 | bool m_WorldSpaceData; 59 | 60 | /// 61 | /// Whether the control points of this mesh chain have been referenced in world or local space 62 | /// This makes sure the bounding box of the mesh is updated appropriately for culling 63 | /// 64 | public bool worldSpaceData 65 | { 66 | get { return m_WorldSpaceData; } 67 | set { m_WorldSpaceData = value; } 68 | } 69 | 70 | /// 71 | /// How many primitives/quads this mesh chain supports and has reserved memory for 72 | /// 73 | public int reservedElements { get; private set; } 74 | 75 | /// 76 | /// If using world space data, this option will force the center of the bounding box to be the root 77 | /// 78 | public bool centerAtRoot { get; set; } 79 | 80 | /// 81 | /// Initialize a new XRMeshChain 82 | /// 83 | public XRMeshChain() 84 | { 85 | reservedElements = 0; 86 | } 87 | 88 | /// 89 | /// Creates or re-creates the mesh with all the data needed for billboard-pipe based line rendering 90 | /// 91 | /// The gameobject that will own the created mesh 92 | /// Whether this mesh is going to updated frequently or not 93 | /// How many total billboards and pipes are needed for this renderer 94 | public void GenerateMesh(GameObject owner, bool dynamic, int totalElements, bool setMesh = true) 95 | { 96 | // Precache neccessary data 97 | // The mesh, vertex and triangle counts 98 | if (m_Mesh == null) 99 | { 100 | m_Mesh = new Mesh(); 101 | } 102 | 103 | if (dynamic == true) 104 | { 105 | m_Mesh.MarkDynamic(); 106 | } 107 | 108 | if (setMesh) 109 | owner.GetComponent().mesh = m_Mesh; 110 | 111 | m_OwnerTransform = owner.transform; 112 | 113 | reservedElements = totalElements; 114 | 115 | var vertCount = 4 * reservedElements; 116 | var triCount = 6 * reservedElements; 117 | 118 | m_Verts = new Vector3[vertCount]; 119 | m_Colors = new Color32[vertCount]; 120 | m_ShapeData = new List(vertCount); 121 | m_NeighborPoints = new List(vertCount); 122 | 123 | var triangles = new int[triCount]; 124 | 125 | var defaultWhite = new Color32(255, 255, 255, 255); 126 | 127 | var uvSet1 = new Vector4(0, 0, 1, 1); 128 | var uvSet2 = new Vector4(1, 0, 1, 1); 129 | var uvSet3 = new Vector4(1, 1, 1, 1); 130 | var uvSet4 = new Vector4(0, 1, 1, 1); 131 | 132 | // Set up the basic data for all of our geometry 133 | var pointCounter = 0; 134 | while (pointCounter < reservedElements) 135 | { 136 | // Get where in the various indices we need to write 137 | var vertOffset = pointCounter * 4; 138 | var triOffset = pointCounter * 6; 139 | 140 | // Store default color 141 | m_Colors[vertOffset] = defaultWhite; 142 | m_Colors[vertOffset + 1] = defaultWhite; 143 | m_Colors[vertOffset + 2] = defaultWhite; 144 | m_Colors[vertOffset + 3] = defaultWhite; 145 | 146 | // Write traditional billboard coordinates 147 | // We use the UV coordinates to determine direction each 148 | // individual vertex will expand in, in screen space 149 | // Last two coordinates are size expansion 150 | m_ShapeData.Add(uvSet1); 151 | m_ShapeData.Add(uvSet2); 152 | m_ShapeData.Add(uvSet3); 153 | m_ShapeData.Add(uvSet4); 154 | 155 | // Zero out neighbor points 156 | m_NeighborPoints.Add(Vector3.zero); 157 | m_NeighborPoints.Add(Vector3.zero); 158 | m_NeighborPoints.Add(Vector3.zero); 159 | m_NeighborPoints.Add(Vector3.zero); 160 | 161 | // And a proper index buffer for this element 162 | triangles[triOffset] = vertOffset; 163 | triangles[triOffset + 1] = vertOffset + 1; 164 | triangles[triOffset + 2] = vertOffset + 2; 165 | triangles[triOffset + 3] = vertOffset; 166 | triangles[triOffset + 4] = vertOffset + 2; 167 | triangles[triOffset + 5] = vertOffset + 3; 168 | 169 | pointCounter++; 170 | } 171 | 172 | // Now set any values we can 173 | m_Mesh.triangles = null; 174 | m_Mesh.vertices = m_Verts; 175 | m_Mesh.SetUVs(0, m_ShapeData); 176 | m_Mesh.SetUVs(1, m_NeighborPoints); 177 | m_Mesh.triangles = triangles; 178 | } 179 | 180 | /// 181 | /// Updates any mesh vertex data that is marked as dirty 182 | /// 183 | public void RefreshMesh() 184 | { 185 | if ((m_DataThatNeedsUpdate & MeshRefreshFlag.Positions) != 0) 186 | { 187 | m_Mesh.vertices = m_Verts; 188 | m_Mesh.SetUVs(1, m_NeighborPoints); 189 | } 190 | 191 | if ((m_DataThatNeedsUpdate & MeshRefreshFlag.Colors) != 0) 192 | { 193 | m_Mesh.colors32 = m_Colors; 194 | } 195 | 196 | if ((m_DataThatNeedsUpdate & MeshRefreshFlag.Sizes) != 0) 197 | { 198 | m_Mesh.SetUVs(0, m_ShapeData); 199 | } 200 | 201 | m_DataThatNeedsUpdate = MeshRefreshFlag.None; 202 | 203 | m_Mesh.RecalculateBounds(); 204 | if (m_WorldSpaceData == true) 205 | { 206 | var newBounds = m_Mesh.bounds; 207 | newBounds.center = centerAtRoot ? Vector3.zero : m_OwnerTransform.InverseTransformPoint(newBounds.center); 208 | m_Mesh.bounds = newBounds; 209 | } 210 | } 211 | 212 | /// 213 | /// Used by external classes to alert the mesh chain that they have modified its data 214 | /// 215 | /// Which type of data (position, color, size) has been changed 216 | public void SetMeshDataDirty(MeshRefreshFlag dataThatNeedsUpdate) 217 | { 218 | m_DataThatNeedsUpdate |= dataThatNeedsUpdate; 219 | } 220 | 221 | /// 222 | /// Sets the position of a specific point in the chain 223 | /// 224 | /// Which control point to update 225 | /// The updated position of the control point 226 | public void SetElementPosition(int elementIndex, ref Vector3 position) 227 | { 228 | var offset = elementIndex * 4; 229 | m_Verts[offset] = position; 230 | m_Verts[offset + 1] = position; 231 | m_Verts[offset + 2] = position; 232 | m_Verts[offset + 3] = position; 233 | 234 | m_NeighborPoints[offset] = position; 235 | m_NeighborPoints[offset + 1] = position; 236 | m_NeighborPoints[offset + 2] = position; 237 | m_NeighborPoints[offset + 3] = position; 238 | } 239 | 240 | /// 241 | /// Sets the endpoints of a pipe in the chain - The pipe equivalent of SetElementPosition 242 | /// 243 | /// Which control pipe to update 244 | /// The position of the previous control point being connected to 245 | /// The position of the next control point being connected to 246 | public void SetElementPipe(int elementIndex, ref Vector3 startPoint, ref Vector3 endPoint) 247 | { 248 | var offset = elementIndex * 4; 249 | m_Verts[offset] = startPoint; 250 | m_Verts[offset + 1] = startPoint; 251 | m_Verts[offset + 2] = endPoint; 252 | m_Verts[offset + 3] = endPoint; 253 | 254 | m_NeighborPoints[offset] = endPoint; 255 | m_NeighborPoints[offset + 1] = endPoint; 256 | m_NeighborPoints[offset + 2] = startPoint; 257 | m_NeighborPoints[offset + 3] = startPoint; 258 | } 259 | 260 | 261 | /// 262 | /// Sets the size of the billboard or pipe being rendered 263 | /// 264 | /// The index of the control point to update 265 | /// What the radius or width of the element should be 266 | public void SetElementSize(int elementIndex, float sizeModification) 267 | { 268 | var offset = elementIndex * 4; 269 | m_ShapeData[offset] = new Vector4(0, 0, sizeModification, sizeModification); 270 | m_ShapeData[offset + 1] = new Vector4(1, 0, sizeModification, sizeModification); 271 | m_ShapeData[offset + 2] = new Vector4(1, 1, sizeModification, sizeModification); 272 | m_ShapeData[offset + 3] = new Vector4(0, 1, sizeModification, sizeModification); 273 | } 274 | 275 | /// 276 | /// Sets the size of the pipe being rendered 277 | /// 278 | /// The index of the pipe control point to update 279 | /// The start size of the pipe 280 | /// The end size of the pipe 281 | public void SetElementSize(int elementIndex, float startSize, float endSize) 282 | { 283 | var offset = elementIndex * 4; 284 | 285 | m_ShapeData[offset] = new Vector4(0, 0, startSize, endSize); 286 | m_ShapeData[offset + 1] = new Vector4(1, 0, startSize, endSize); 287 | m_ShapeData[offset + 2] = new Vector4(1, 1, endSize, startSize); 288 | m_ShapeData[offset + 3] = new Vector4(0, 1, endSize, startSize); 289 | } 290 | 291 | /// 292 | /// Sets the color of a billboard or pipe in the chain 293 | /// 294 | /// The index of the element we are coloring 295 | /// What the color of this element should be 296 | public void SetElementColor(int elementIndex, ref Color color) 297 | { 298 | var offset = elementIndex * 4; 299 | m_Colors[offset] = color; 300 | m_Colors[offset + 1] = m_Colors[offset]; 301 | m_Colors[offset + 2] = m_Colors[offset]; 302 | m_Colors[offset + 3] = m_Colors[offset]; 303 | } 304 | 305 | /// 306 | /// Sets the color of a billboard or pipe in the chain 307 | /// 308 | /// The index of the element we are coloring 309 | /// What the color of this element should be 310 | public void SetElementColor32(int elementIndex, ref Color32 color) 311 | { 312 | var offset = elementIndex * 4; 313 | m_Colors[offset] = color; 314 | m_Colors[offset + 1] = color; 315 | m_Colors[offset + 2] = color; 316 | m_Colors[offset + 3] = color; 317 | } 318 | 319 | /// 320 | /// Sets the colors of a pipe in the chain 321 | /// 322 | /// The index of the pipe we are coloring 323 | /// The color of the startpoint of the pipe 324 | /// The color of the endpoint of the pipe 325 | public void SetElementColor(int elementIndex, ref Color startColor, ref Color endColor) 326 | { 327 | var offset = elementIndex * 4; 328 | m_Colors[offset] = startColor; 329 | m_Colors[offset + 1] = m_Colors[offset]; 330 | m_Colors[offset + 2] = endColor; 331 | m_Colors[offset + 3] = m_Colors[offset + 2]; 332 | } 333 | 334 | /// 335 | /// Sets the colors of a pipe in the chain 336 | /// 337 | /// The index of the pipe we are coloring 338 | /// The color of the startpoint of the pipe 339 | /// The color of the endpoint of the pipe 340 | public void SetElementColor32(int elementIndex, ref Color32 startColor, ref Color32 endColor) 341 | { 342 | var offset = elementIndex * 4; 343 | m_Colors[offset] = startColor; 344 | m_Colors[offset + 1] = m_Colors[offset]; 345 | m_Colors[offset + 2] = endColor; 346 | m_Colors[offset + 3] = m_Colors[offset + 2]; 347 | } 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /Runtime/XRMeshChain.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23f2c633373418648b62a3777231015b 3 | timeCreated: 1460396386 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Runtime/XRTrailRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Unity.XRTools.Rendering 5 | { 6 | /// 7 | /// An XR-Focused drop-in replacement for the Trail Renderer 8 | /// This renderer draws fixed-width lines with simulated volume and glow. 9 | /// This has many of the advantages of the traditional Line Renderer, old-school system-level line rendering functions, 10 | /// and volumetric (a linked series of capsules or cubes) rendering 11 | /// 12 | [RequireComponent(typeof(MeshRenderer))] 13 | [RequireComponent(typeof(MeshFilter))] 14 | [ExecuteInEditMode] 15 | public class XRTrailRenderer : MeshChainRenderer 16 | { 17 | const float k_AbsoluteMinVertexDistance = 0.01f; 18 | 19 | // Stored Trail Data 20 | [SerializeField] 21 | [Tooltip("How many points to store for tracing.")] 22 | int m_MaxTrailPoints = 20; 23 | 24 | [SerializeField] 25 | [Tooltip("Whether to use the last point or the first point of the trail when more are needed and none are available.")] 26 | bool m_StealLastPointWhenEmpty = true; 27 | 28 | [SerializeField] 29 | [Tooltip("How long the tail should be (second) [ 0, infinity ].")] 30 | float m_Time = 5.0f; 31 | 32 | [SerializeField] 33 | [Tooltip("The minimum distance to spawn a new point on the trail [ 0, infinity ].")] 34 | float m_MinVertexDistance = 0.1f; 35 | 36 | [SerializeField] 37 | [Tooltip("Destroy GameObject when there is no trail?")] 38 | bool m_Autodestruct = false; 39 | 40 | [SerializeField] 41 | [Tooltip("With this enabled, the last point will smooth lerp between the last recorded anchor point and the one after it")] 42 | bool m_SmoothInterpolation = false; 43 | 44 | // Circular array support for trail point recording 45 | Vector3[] m_Points; 46 | float[] m_PointTimes; 47 | int m_PointIndexStart = 0; 48 | int m_PointIndexEnd = 0; 49 | 50 | // Cached Data 51 | Vector3 m_LastRecordedPoint = Vector3.zero; 52 | float m_LastPointTime; 53 | 54 | float m_EditorDeltaHelper; // This lets us have access to a time data while not in play mode 55 | 56 | 57 | /// 58 | /// How long does the trail take to fade out. 59 | /// 60 | public float time 61 | { 62 | get { return m_Time; } 63 | set { m_Time = Mathf.Max(value, 0); } 64 | } 65 | 66 | /// 67 | /// Set the minimum distance the trail can travel before a new vertex is added to it. 68 | /// 69 | public float minVertexDistance 70 | { 71 | get { return m_MinVertexDistance; } 72 | set { m_MinVertexDistance = Mathf.Max(value, k_AbsoluteMinVertexDistance); } 73 | } 74 | 75 | /// 76 | /// Get the number of line segments in the trail 77 | /// 78 | public int positionCount { get; private set; } 79 | 80 | /// 81 | /// Destroy GameObject when there is no trail? 82 | /// 83 | public bool autodestruct 84 | { 85 | get { return m_Autodestruct; } 86 | set { m_Autodestruct = value; } 87 | } 88 | 89 | /// 90 | /// Set if the last point will smooth lerp between the last recorded anchor point and the one after it 91 | /// 92 | public bool smoothInterpolation 93 | { 94 | get { return m_SmoothInterpolation; } 95 | set { m_SmoothInterpolation = value; } 96 | } 97 | 98 | /// 99 | /// Updates the built-in mesh data for each control point of the trail 100 | /// 101 | protected override void LateUpdate() 102 | { 103 | // We do the actual internal mesh updating as late as possible so nothing ends up a frame behind 104 | var deltaTime = Time.deltaTime; 105 | 106 | // We give the editor a little help with handling delta time in edit mode 107 | if (Application.isPlaying == false) 108 | { 109 | deltaTime = Time.realtimeSinceStartup - m_EditorDeltaHelper; 110 | m_EditorDeltaHelper = Time.realtimeSinceStartup; 111 | } 112 | 113 | // Get the current position of the renderer 114 | var currentPoint = transform.position; 115 | var pointDistance = (currentPoint - m_LastRecordedPoint).sqrMagnitude; 116 | var shrunkThisFrame = false; 117 | 118 | // Is it more than minVertexDistance from the last position? 119 | if (pointDistance > (m_MinVertexDistance * m_MinVertexDistance)) 120 | { 121 | // In the situation we have no points, we need to record the start point as well 122 | if (m_PointIndexStart == m_PointIndexEnd) 123 | { 124 | m_Points[m_PointIndexStart] = m_LastRecordedPoint; 125 | m_PointTimes[m_PointIndexStart] = m_Time; 126 | } 127 | 128 | // Make space for a new point 129 | var newEndIndex = (m_PointIndexEnd + 1) % m_MaxTrailPoints; 130 | 131 | // In the situation that we are rendering all available vertices 132 | // We can either keep using the current point, or take the last point, depending on the user's preference 133 | if (newEndIndex != m_PointIndexStart) 134 | { 135 | m_PointIndexEnd = newEndIndex; 136 | m_PointTimes[m_PointIndexEnd] = 0; 137 | positionCount++; 138 | } 139 | else 140 | { 141 | if (m_StealLastPointWhenEmpty) 142 | { 143 | m_XRMeshData.SetElementSize(m_PointIndexStart * 2, 0); 144 | m_XRMeshData.SetElementSize((m_PointIndexStart * 2) + 1, 0); 145 | m_PointIndexStart = (m_PointIndexStart + 1) % m_MaxTrailPoints; 146 | m_PointIndexEnd = newEndIndex; 147 | m_PointTimes[m_PointIndexEnd] = 0; 148 | m_LastPointTime = m_PointTimes[m_PointIndexStart]; 149 | } 150 | } 151 | 152 | m_Points[m_PointIndexEnd] = currentPoint; 153 | 154 | // Update the last recorded point 155 | m_LastRecordedPoint = currentPoint; 156 | } 157 | 158 | // Do time processing 159 | // The end point counts up to a maximum of 'time' 160 | m_PointTimes[m_PointIndexEnd] = Mathf.Min(m_PointTimes[m_PointIndexEnd] + deltaTime, m_Time); 161 | 162 | if (m_PointIndexStart != m_PointIndexEnd) 163 | { 164 | // Run down the counter on the start point 165 | m_PointTimes[m_PointIndexStart] -= deltaTime; 166 | 167 | // If we've hit 0, this point is done for 168 | if (m_PointTimes[m_PointIndexStart] <= 0.0f) 169 | { 170 | m_XRMeshData.SetElementSize(m_PointIndexStart * 2, 0); 171 | m_XRMeshData.SetElementSize((m_PointIndexStart * 2) + 1, 0); 172 | m_PointIndexStart = (m_PointIndexStart + 1) % m_MaxTrailPoints; 173 | m_LastPointTime = m_PointTimes[m_PointIndexStart]; 174 | positionCount--; 175 | shrunkThisFrame = true; 176 | } 177 | } 178 | 179 | if (m_PointIndexStart != m_PointIndexEnd) 180 | { 181 | m_MeshNeedsRefreshing = true; 182 | m_MeshRenderer.enabled = true; 183 | } 184 | else 185 | { 186 | m_MeshNeedsRefreshing = false; 187 | m_MeshRenderer.enabled = false; 188 | if (m_Autodestruct && Application.isPlaying && shrunkThisFrame) 189 | { 190 | Destroy(gameObject); 191 | } 192 | } 193 | 194 | if (m_MeshNeedsRefreshing) 195 | { 196 | m_MeshRenderer.enabled = true; 197 | 198 | // Update first and last points position-wise 199 | var nextIndex = (m_PointIndexStart + 1) % m_MaxTrailPoints; 200 | if (m_SmoothInterpolation) 201 | { 202 | var toNextPoint = 1.0f - (m_PointTimes[m_PointIndexStart] / m_LastPointTime); 203 | var lerpPoint = Vector3.Lerp(m_Points[m_PointIndexStart], m_Points[nextIndex], toNextPoint); 204 | m_XRMeshData.SetElementPosition((m_PointIndexStart * 2), ref lerpPoint); 205 | m_XRMeshData.SetElementPipe((m_PointIndexStart * 2) + 1, ref lerpPoint, ref m_Points[nextIndex]); 206 | } 207 | else 208 | { 209 | m_XRMeshData.SetElementPosition((m_PointIndexStart * 2), ref m_Points[m_PointIndexStart]); 210 | m_XRMeshData.SetElementPipe((m_PointIndexStart * 2) + 1, ref m_Points[m_PointIndexStart], ref m_Points[nextIndex]); 211 | } 212 | 213 | var prevIndex = m_PointIndexEnd - 1; 214 | if (prevIndex < 0) 215 | { 216 | prevIndex = m_MaxTrailPoints - 1; 217 | } 218 | 219 | m_XRMeshData.SetElementPipe((prevIndex * 2) + 1, ref m_Points[prevIndex], ref m_Points[m_PointIndexEnd]); 220 | m_XRMeshData.SetElementPosition((m_PointIndexEnd * 2), ref m_Points[m_PointIndexEnd]); 221 | 222 | 223 | // Go through all points and update size and color 224 | var pointUpdateCounter = m_PointIndexStart; 225 | var pointCount = 0; 226 | m_StepSize = (positionCount > 0) ? (1.0f / positionCount) : 1.0f; 227 | 228 | var percent = 0.0f; 229 | var lastWidth = m_WidthCurve.Evaluate(percent) * m_Width; 230 | var lastColor = m_Color.Evaluate(percent); 231 | percent += m_StepSize; 232 | 233 | while (pointUpdateCounter != m_PointIndexEnd) 234 | { 235 | var nextWidth = m_WidthCurve.Evaluate(percent) * m_Width; 236 | m_XRMeshData.SetElementSize(pointUpdateCounter * 2, lastWidth); 237 | m_XRMeshData.SetElementSize((pointUpdateCounter * 2) + 1, lastWidth, nextWidth); 238 | lastWidth = nextWidth; 239 | 240 | var nextColor = m_Color.Evaluate(percent); 241 | m_XRMeshData.SetElementColor(pointUpdateCounter * 2, ref lastColor); 242 | m_XRMeshData.SetElementColor((pointUpdateCounter * 2) + 1, ref lastColor, ref nextColor); 243 | lastColor = nextColor; 244 | 245 | pointUpdateCounter = (pointUpdateCounter + 1) % m_MaxTrailPoints; 246 | pointCount++; 247 | percent += m_StepSize; 248 | } 249 | 250 | lastWidth = m_WidthCurve.Evaluate(1) * m_Width; 251 | m_XRMeshData.SetElementSize((m_PointIndexEnd * 2), lastWidth); 252 | lastColor = m_Color.Evaluate(1); 253 | m_XRMeshData.SetElementColor((m_PointIndexEnd * 2), ref lastColor); 254 | m_XRMeshData.SetMeshDataDirty(XRMeshChain.MeshRefreshFlag.All); 255 | m_XRMeshData.RefreshMesh(); 256 | } 257 | } 258 | 259 | /// 260 | /// Editor helper function to ensure changes are reflected in edit-mode 261 | /// 262 | public void EditorCheckForUpdate() 263 | { 264 | // If we did not initialize, refresh all the properties instead 265 | Initialize(); 266 | } 267 | 268 | /// 269 | /// Removes all points from the TrailRenderer. Useful for restarting a trail from a new position. 270 | /// 271 | public void Clear() 272 | { 273 | var zeroVec = Vector3.zero; 274 | var zeroColor = Color.clear; 275 | 276 | var elementCounter = 0; 277 | var pointCounter = 0; 278 | while (pointCounter < m_Points.Length) 279 | { 280 | // Start point 281 | m_XRMeshData.SetElementSize(elementCounter, 0); 282 | m_XRMeshData.SetElementPosition(elementCounter, ref zeroVec); 283 | m_XRMeshData.SetElementColor(elementCounter, ref zeroColor); 284 | elementCounter++; 285 | 286 | // Pipe to the next point 287 | m_XRMeshData.SetElementSize(elementCounter, 0); 288 | m_XRMeshData.SetElementPipe(elementCounter, ref zeroVec, ref zeroVec); 289 | m_XRMeshData.SetElementColor(elementCounter, ref zeroColor); 290 | 291 | // Go onto the next point while retaining previous values we might need to lerp between 292 | elementCounter++; 293 | pointCounter++; 294 | } 295 | 296 | m_PointIndexStart = 0; 297 | m_PointIndexEnd = 0; 298 | positionCount = 0; 299 | m_LastRecordedPoint = transform.position; 300 | } 301 | 302 | /// 303 | /// Creates or updates the underlying mesh data 304 | /// 305 | protected override void Initialize(bool setMesh = true) 306 | { 307 | base.Initialize(setMesh); 308 | 309 | m_MaxTrailPoints = Mathf.Max(m_MaxTrailPoints, 3); 310 | 311 | // If we already have the right amount of points and mesh, then we can get away with just clearing the curve out 312 | if (m_Points != null && m_MaxTrailPoints == m_Points.Length && m_XRMeshData != null) 313 | { 314 | Clear(); 315 | return; 316 | } 317 | 318 | m_Points = new Vector3[m_MaxTrailPoints]; 319 | m_PointTimes = new float[m_MaxTrailPoints]; 320 | 321 | // For a trail renderer we assume one big chain 322 | // We need a control point for each billboard and a control point for each pipe connecting them together 323 | // We make this a circular trail so the update logic is easier. This gives us (position * 2) 324 | var neededPoints = Mathf.Max((m_MaxTrailPoints * 2), 0); 325 | 326 | if (m_XRMeshData == null) 327 | { 328 | m_XRMeshData = new XRMeshChain(); 329 | } 330 | 331 | if (m_XRMeshData.reservedElements != neededPoints) 332 | { 333 | m_XRMeshData.worldSpaceData = true; 334 | m_XRMeshData.centerAtRoot = true; 335 | m_XRMeshData.GenerateMesh(gameObject, true, neededPoints, setMesh); 336 | 337 | if (neededPoints == 0) 338 | { 339 | return; 340 | } 341 | 342 | // Dirty all the VRMeshChain flags so everything gets refreshed 343 | m_MeshRenderer.enabled = false; 344 | m_XRMeshData.SetMeshDataDirty(XRMeshChain.MeshRefreshFlag.All); 345 | m_MeshNeedsRefreshing = true; 346 | } 347 | 348 | Clear(); 349 | } 350 | 351 | /// 352 | /// Tests if the mesh data needs to be created or rebuilt 353 | /// 354 | /// true if the mesh data needs recreation, false if it is already set up properly 355 | protected override bool NeedsReinitialize() 356 | { 357 | // No mesh data means we definitely need to reinitialize 358 | if (m_XRMeshData == null) 359 | { 360 | return true; 361 | } 362 | 363 | // Mismatched point data means we definitely need to reinitialize 364 | if (m_Points == null || m_MaxTrailPoints != m_Points.Length) 365 | { 366 | return true; 367 | } 368 | 369 | m_MaxTrailPoints = Mathf.Max(m_MaxTrailPoints, 3); 370 | var neededPoints = Mathf.Max((m_MaxTrailPoints * 2), 0); 371 | 372 | return (m_XRMeshData.reservedElements != neededPoints); 373 | } 374 | 375 | /// 376 | /// Enables the internal mesh representing the line 377 | /// 378 | protected override void OnEnable() 379 | { 380 | m_MeshRenderer.enabled = (m_PointIndexStart != m_PointIndexEnd); 381 | } 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /Runtime/XRTrailRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a52ac20b8c7e8274e965d22ace23d416 3 | timeCreated: 1461798751 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 13c323b825ff3df4b8498d6d9b660d6b 3 | folderAsset: yes 4 | timeCreated: 1460484083 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/ExampleScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e0801b08091f624ba508298a0c5f538 3 | timeCreated: 1500666306 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scratch.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a336e70424915bc45923b94630e45131 3 | folderAsset: yes 4 | timeCreated: 1462396705 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scratch/TrailExample.anim: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!74 &7400000 4 | AnimationClip: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_Name: TrailExample 10 | serializedVersion: 6 11 | m_Legacy: 1 12 | m_Compressed: 0 13 | m_UseHighQualityCurve: 1 14 | m_RotationCurves: [] 15 | m_CompressedRotationCurves: [] 16 | m_EulerCurves: [] 17 | m_PositionCurves: 18 | - curve: 19 | serializedVersion: 2 20 | m_Curve: 21 | - serializedVersion: 3 22 | time: 0 23 | value: {x: 1.43, y: 3.87, z: -5.699} 24 | inSlope: {x: -1.0699999, y: 8.379311, z: 3.1427588} 25 | outSlope: {x: -1.0699999, y: 8.379311, z: 3.1427588} 26 | tangentMode: 0 27 | weightedMode: 0 28 | inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 29 | outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 30 | - serializedVersion: 3 31 | time: 0.48333332 32 | value: {x: -0.623, y: 6.803, z: -4.18} 33 | inSlope: {x: -1.0699999, y: 2.5541713, z: 5.1036377} 34 | outSlope: {x: -1.0699999, y: 2.5541713, z: 5.1036377} 35 | tangentMode: 0 36 | weightedMode: 0 37 | inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 38 | outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 39 | - serializedVersion: 3 40 | time: 1 41 | value: {x: 0.36, y: 6.23, z: -0.53} 42 | inSlope: {x: -0.34500003, y: -5.7454844, z: 4.262258} 43 | outSlope: {x: -0.34500003, y: -5.7454844, z: 4.262258} 44 | tangentMode: 0 45 | weightedMode: 0 46 | inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 47 | outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 48 | - serializedVersion: 3 49 | time: 1.5 50 | value: {x: 4.06, y: 3.55, z: 0.2} 51 | inSlope: {x: 0.38, y: -8.22, z: 1.4599999} 52 | outSlope: {x: 0.38, y: -8.22, z: 1.4599999} 53 | tangentMode: 0 54 | weightedMode: 0 55 | inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 56 | outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 57 | - serializedVersion: 3 58 | time: 2 59 | value: {x: 1.43, y: 3.87, z: -5.699} 60 | inSlope: {x: 0, y: 0, z: 0} 61 | outSlope: {x: 0, y: 0, z: 0} 62 | tangentMode: 0 63 | weightedMode: 0 64 | inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 65 | outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} 66 | m_PreInfinity: 2 67 | m_PostInfinity: 2 68 | m_RotationOrder: 4 69 | path: 70 | m_ScaleCurves: [] 71 | m_FloatCurves: [] 72 | m_PPtrCurves: [] 73 | m_SampleRate: 60 74 | m_WrapMode: 2 75 | m_Bounds: 76 | m_Center: {x: 0, y: 0, z: 0} 77 | m_Extent: {x: 0, y: 0, z: 0} 78 | m_ClipBindingConstant: 79 | genericBindings: [] 80 | pptrCurveMapping: [] 81 | m_AnimationClipSettings: 82 | serializedVersion: 2 83 | m_AdditiveReferencePoseClip: {fileID: 0} 84 | m_AdditiveReferencePoseTime: 0 85 | m_StartTime: 0 86 | m_StopTime: 2 87 | m_OrientationOffsetY: 0 88 | m_Level: 0 89 | m_CycleOffset: 0 90 | m_HasAdditiveReferencePose: 0 91 | m_LoopTime: 1 92 | m_LoopBlend: 0 93 | m_LoopBlendOrientation: 0 94 | m_LoopBlendPositionY: 0 95 | m_LoopBlendPositionXZ: 0 96 | m_KeepOriginalOrientation: 0 97 | m_KeepOriginalPositionY: 1 98 | m_KeepOriginalPositionXZ: 0 99 | m_HeightFromFeet: 0 100 | m_Mirror: 0 101 | m_EditorCurves: 102 | - curve: 103 | serializedVersion: 2 104 | m_Curve: 105 | - serializedVersion: 3 106 | time: 0 107 | value: 1.43 108 | inSlope: -1.0699999 109 | outSlope: -1.0699999 110 | tangentMode: 0 111 | weightedMode: 0 112 | inWeight: 0.33333334 113 | outWeight: 0.33333334 114 | - serializedVersion: 3 115 | time: 0.48333332 116 | value: -0.623 117 | inSlope: -1.0699999 118 | outSlope: -1.0699999 119 | tangentMode: 0 120 | weightedMode: 0 121 | inWeight: 0.33333334 122 | outWeight: 0.33333334 123 | - serializedVersion: 3 124 | time: 1 125 | value: 0.36 126 | inSlope: -0.34500003 127 | outSlope: -0.34500003 128 | tangentMode: 0 129 | weightedMode: 0 130 | inWeight: 0.33333334 131 | outWeight: 0.33333334 132 | - serializedVersion: 3 133 | time: 1.5 134 | value: 4.06 135 | inSlope: 0.38 136 | outSlope: 0.38 137 | tangentMode: 0 138 | weightedMode: 0 139 | inWeight: 0.33333334 140 | outWeight: 0.33333334 141 | - serializedVersion: 3 142 | time: 2 143 | value: 1.43 144 | inSlope: 0 145 | outSlope: 0 146 | tangentMode: 0 147 | weightedMode: 0 148 | inWeight: 0.33333334 149 | outWeight: 0.33333334 150 | m_PreInfinity: 2 151 | m_PostInfinity: 2 152 | m_RotationOrder: 4 153 | attribute: m_LocalPosition.x 154 | path: 155 | classID: 4 156 | script: {fileID: 0} 157 | - curve: 158 | serializedVersion: 2 159 | m_Curve: 160 | - serializedVersion: 3 161 | time: 0 162 | value: 3.87 163 | inSlope: 8.379311 164 | outSlope: 8.379311 165 | tangentMode: 0 166 | weightedMode: 0 167 | inWeight: 0.33333334 168 | outWeight: 0.33333334 169 | - serializedVersion: 3 170 | time: 0.48333332 171 | value: 6.803 172 | inSlope: 2.5541713 173 | outSlope: 2.5541713 174 | tangentMode: 0 175 | weightedMode: 0 176 | inWeight: 0.33333334 177 | outWeight: 0.33333334 178 | - serializedVersion: 3 179 | time: 1 180 | value: 6.23 181 | inSlope: -5.7454844 182 | outSlope: -5.7454844 183 | tangentMode: 0 184 | weightedMode: 0 185 | inWeight: 0.33333334 186 | outWeight: 0.33333334 187 | - serializedVersion: 3 188 | time: 1.5 189 | value: 3.55 190 | inSlope: -8.22 191 | outSlope: -8.22 192 | tangentMode: 0 193 | weightedMode: 0 194 | inWeight: 0.33333334 195 | outWeight: 0.33333334 196 | - serializedVersion: 3 197 | time: 2 198 | value: 3.87 199 | inSlope: 0 200 | outSlope: 0 201 | tangentMode: 0 202 | weightedMode: 0 203 | inWeight: 0.33333334 204 | outWeight: 0.33333334 205 | m_PreInfinity: 2 206 | m_PostInfinity: 2 207 | m_RotationOrder: 4 208 | attribute: m_LocalPosition.y 209 | path: 210 | classID: 4 211 | script: {fileID: 0} 212 | - curve: 213 | serializedVersion: 2 214 | m_Curve: 215 | - serializedVersion: 3 216 | time: 0 217 | value: -5.699 218 | inSlope: 3.1427588 219 | outSlope: 3.1427588 220 | tangentMode: 0 221 | weightedMode: 0 222 | inWeight: 0.33333334 223 | outWeight: 0.33333334 224 | - serializedVersion: 3 225 | time: 0.48333332 226 | value: -4.18 227 | inSlope: 5.1036377 228 | outSlope: 5.1036377 229 | tangentMode: 0 230 | weightedMode: 0 231 | inWeight: 0.33333334 232 | outWeight: 0.33333334 233 | - serializedVersion: 3 234 | time: 1 235 | value: -0.53 236 | inSlope: 4.262258 237 | outSlope: 4.262258 238 | tangentMode: 0 239 | weightedMode: 0 240 | inWeight: 0.33333334 241 | outWeight: 0.33333334 242 | - serializedVersion: 3 243 | time: 1.5 244 | value: 0.2 245 | inSlope: 1.4599999 246 | outSlope: 1.4599999 247 | tangentMode: 0 248 | weightedMode: 0 249 | inWeight: 0.33333334 250 | outWeight: 0.33333334 251 | - serializedVersion: 3 252 | time: 2 253 | value: -5.699 254 | inSlope: 0 255 | outSlope: 0 256 | tangentMode: 0 257 | weightedMode: 0 258 | inWeight: 0.33333334 259 | outWeight: 0.33333334 260 | m_PreInfinity: 2 261 | m_PostInfinity: 2 262 | m_RotationOrder: 4 263 | attribute: m_LocalPosition.z 264 | path: 265 | classID: 4 266 | script: {fileID: 0} 267 | m_EulerEditorCurves: [] 268 | m_HasGenericRootTransform: 0 269 | m_HasMotionFloatCurves: 0 270 | m_Events: [] 271 | -------------------------------------------------------------------------------- /Scratch/TrailExample.anim.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7d49c1611fbf01478922b466af91d61 3 | timeCreated: 1462396705 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 301b199c2a561924d909ab2069898931 3 | folderAsset: yes 4 | timeCreated: 1460416660 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Shaders/MeshChain.cginc: -------------------------------------------------------------------------------- 1 | #ifndef MESH_CHAIN 2 | #define MESH_CHAIN 3 | // UNITY_SHADER_NO_UPGRADE 4 | 5 | half4 _Color; // What color to tint the line 6 | half4 _lineSettings; // Settings for how to shade the line - basically applying a levels filter to the gradient 7 | 8 | half3 _lineRadius; // x: Element size multiplier, y: min, z: max 9 | 10 | struct appdata_meshChain 11 | { 12 | float4 vertex : POSITION; 13 | float4 texcoord : TEXCOORD0; 14 | float4 texcoord1 : TEXCOORD1; 15 | fixed4 color : COLOR; 16 | }; 17 | 18 | struct meshChain_vertex 19 | { 20 | float4 pos : SV_POSITION; 21 | float4 uv : TEXCOORD0; 22 | fixed4 color : COLOR; 23 | }; 24 | 25 | meshChain_vertex vert(appdata_meshChain v) 26 | { 27 | meshChain_vertex o; 28 | 29 | // In 5.4 and later we have stereo instance rendering so we go through the 30 | // ClipPos function which is aware of the proper projection matrix per-eye 31 | #if LINE_WORLD_SPACE 32 | o.pos = mul(UNITY_MATRIX_VP, v.vertex); 33 | #elif UNITY_VERSION < 540 34 | o.pos = UnityObjectToClipPos(v.vertex); 35 | #else 36 | o.pos = UnityObjectToClipPos(v.vertex); 37 | #endif 38 | 39 | // We calculate the aspect ratio since the lines are 40 | // being transformed into a psuedo-screen space area 41 | half aspectRatio = _ScreenParams.x / _ScreenParams.y; 42 | 43 | // Determine the location of our neighbor 44 | #if LINE_WORLD_SPACE 45 | half4 neighborPos = mul(UNITY_MATRIX_VP, v.texcoord1); 46 | #elif UNITY_VERSION < 540 47 | half4 neighborPos = UnityObjectToClipPos(v.texcoord1); 48 | #else 49 | half4 neighborPos = UnityObjectToClipPos(v.texcoord1); 50 | #endif 51 | 52 | // We calculate the distance this billboard or pipe expands at each end 53 | // We use this for the vertex deformation and proper non-perspective texture mapping 54 | #if LINE_FIXED_WIDTH 55 | half expandDistanceSource = clamp(_lineRadius.x * o.pos.w * .1, _lineRadius.y, _lineRadius.z) * v.texcoord.z; 56 | half expandDistanceDest = clamp(_lineRadius.x * neighborPos.w * .1, _lineRadius.y, _lineRadius.z) * v.texcoord.w; 57 | #else 58 | half expandDistanceSource = max(_lineRadius * .1, _lineRadius.y) * v.texcoord.z; 59 | half expandDistanceDest = max(_lineRadius * .1, _lineRadius.y) * v.texcoord.w; 60 | #endif 61 | 62 | // If the screen space distance between these two points is under a threshold, we are a billboard 63 | // Otherwise, we are a pipe 64 | half2 perpVec = (neighborPos.xy / neighborPos.w) - (o.pos.xy / o.pos.w); 65 | half pipeFlag = step(.001, length(perpVec)); 66 | perpVec = normalize(perpVec).yx; 67 | perpVec.y *= -1; 68 | perpVec.xy *= (2 * (v.texcoord.x - .5)) * (2 * (v.texcoord.y - .5)); 69 | 70 | // Billboard logic 71 | // We billboard based off the UV's we had stored 72 | // Since the UV's represent each corner, we convert these into offsets 73 | half2 billboardVec = 2 * (v.texcoord.xy - .5); 74 | 75 | // Whether this element is a billboard or a pipe is encoded in the secondary texture coordinates 76 | // A 0 on the u coordinate specifies using the billboard rendering mode 77 | // A 1 on the u coordinate specifies using the pipe rendering mode 78 | o.pos.x += lerp(billboardVec.x, perpVec.x, pipeFlag) * expandDistanceSource; 79 | o.pos.y += lerp(billboardVec.y, perpVec.y, pipeFlag) * expandDistanceSource*aspectRatio; 80 | 81 | // We store the w coordinate of the worldspace position separately here 82 | // We need to conditionally undo the perspective correction on these UV coordinates 83 | // And the w coordinate is needed for that 84 | float sizeRatio = ((expandDistanceSource + expandDistanceDest) / expandDistanceDest); 85 | o.uv = float4(v.texcoord.x, v.texcoord.y, pipeFlag, sizeRatio); 86 | o.uv.y = o.uv.y * (1.0 - pipeFlag) + .5 * pipeFlag; 87 | o.uv.xy *= sizeRatio; 88 | 89 | o.color = v.color * _Color; 90 | return o; 91 | } 92 | 93 | //---------------------------------------------- 94 | // Function that takes an input brightness, 95 | // and applies the levels logic we've described 96 | //---------------------------------------------- 97 | // curve.x : min range (0 - 1, based on brightness) 98 | // curve.y : max range (1 - 0, based on brightness) 99 | // curve.z : bend (.5 is linear) 100 | fixed applyLevels(fixed original, fixed3 curve) 101 | { 102 | // Any value less than 1/256 (the minimum the color variable can represent in the editor) 103 | // is clamped to 0 to prevent texture bleeding 104 | fixed inRange = saturate((original - curve.x) / (curve.y - curve.x)) * step(1.0 / 256.0, original); 105 | 106 | // We take this in-range value and apply a power function to it 107 | // We calculate the power from our bend value with the following logic 108 | // Any curve value from 0 to .5 goes from 1/32 to 1 109 | // Any curve value from .5 to 1 goes from 1 to 32 110 | // This lets us have really strong curve controls 111 | // Pow is not necessarily cheap, but equivalent perf to lerping 112 | // between a curve that bows out and one that bows in 113 | half bendValue = curve.z; 114 | fixed powValue = (saturate(-(bendValue - .5)) * 5) + (1 / (saturate(bendValue - .5) * 5 + 1)); 115 | return pow(inRange, powValue); 116 | } 117 | 118 | half4 frag(meshChain_vertex i) : COLOR 119 | { 120 | // This used to be a texture lookup, we have now turned it into pure math 121 | // Undo the perspective correction 122 | float2 texCoord = i.uv.xy / i.uv.w; 123 | 124 | // Calculate the how close to the center of the billboard or pipe we are, and convert 125 | // that to a brightness value 126 | half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0))); 127 | // Apply our curve logic and color tint 128 | return applyLevels(lineAlpha*i.color.a, _lineSettings.rgb) * i.color; 129 | } 130 | 131 | half4 fragInvert(meshChain_vertex i) : COLOR 132 | { 133 | // This used to be a texture lookup, we have now turned it into pure math 134 | // Undo the perspective correction 135 | float2 texCoord = i.uv.xy / i.uv.w; 136 | 137 | // Calculate the how close to the center of the billboard or pipe we are, and convert 138 | // that to a brightness value 139 | half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0))); 140 | // Apply our curve logic and color tint 141 | return lerp(i.color, half4(1,1,1,1), 1 - applyLevels(lineAlpha * i.color.a, _lineSettings.rgb)); 142 | } 143 | 144 | half4 fragAlphaMask(meshChain_vertex i) : COLOR 145 | { 146 | // This used to be a texture lookup, we have now turned it into pure math 147 | // Undo the perspective correction 148 | float2 texCoord = i.uv.xy / i.uv.w; 149 | 150 | // Calculate the how close to the center of the billboard or pipe we are, and convert 151 | // that to a brightness value 152 | half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0))); 153 | lineAlpha = lerp(1, 1 - applyLevels(lineAlpha, _lineSettings.rgb), i.color.a); 154 | return half4(0, 0, 0, lineAlpha); 155 | } 156 | 157 | half4 fragColor(meshChain_vertex i) : COLOR 158 | { 159 | return half4(i.color.rgb,1); 160 | } 161 | #endif // MESH_CHAIN 162 | -------------------------------------------------------------------------------- /Shaders/MeshChain.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 28d4fa881b1b2df4e92e693c84774031 3 | timeCreated: 1460504260 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Shaders/MeshChainAdd.shader: -------------------------------------------------------------------------------- 1 | Shader "XRLineRenderer/MeshChain - Additive" 2 | { 3 | Properties 4 | { 5 | _Color("Color Tint", COLOR) = (1,1,1,1) 6 | _lineSettings ("Line Thickness Settings", VECTOR) = (0, 1, .5, 1) 7 | 8 | _lineRadius("Line Radius Scale, Min, Max", VECTOR) = (1, 0, 100) 9 | 10 | // Local space or world space data 11 | [HideInInspector] _WorldData("__worlddata", Float) = 0.0 12 | 13 | // Depth effects line width 14 | [HideInInspector] _LineDepthScale("__linedepthscale", Float) = 1.0 15 | } 16 | SubShader 17 | { 18 | Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } 19 | LOD 100 20 | 21 | // We don't want the line segments and caps to draw over top 22 | // one another as it breaks the continuous segment illusion 23 | // To alpha blend with the background, we use a three-pass technique 24 | Pass 25 | { 26 | // In the first pass we 'clear' the alpha channel to 1, 27 | // so that the inner segments can mask this out 28 | Blend One One 29 | BlendOp Max 30 | Cull Off 31 | Lighting Off 32 | ZWrite Off 33 | ColorMask A 34 | Offset 0, -.1 35 | 36 | CGPROGRAM 37 | 38 | #pragma vertex vert 39 | #pragma fragment fragColor 40 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 41 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 42 | 43 | #include "UnityCG.cginc" 44 | #include "MeshChain.cginc" 45 | 46 | ENDCG 47 | } 48 | Pass 49 | { 50 | // Next we write the line shape and fade only to the alpha channel. 51 | // This lets us punch a hole in the background that our 52 | // line color then shows through 53 | Blend One One 54 | BlendOp Min 55 | Cull Off 56 | Lighting Off 57 | ZWrite Off 58 | ColorMask A 59 | Offset 0, -.1 60 | 61 | CGPROGRAM 62 | 63 | #pragma vertex vert 64 | #pragma fragment fragAlphaMask 65 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 66 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 67 | 68 | #include "UnityCG.cginc" 69 | #include "MeshChain.cginc" 70 | 71 | ENDCG 72 | } 73 | Pass 74 | { 75 | // In this second pass, we write our line color only as much 76 | // as the alpha value we wrote before allows through. To 77 | // prevent overlapping lines from adding too much color, 78 | // we set the alpha value to one after visiting a pixel. 79 | Blend OneMinusDstAlpha One, One One 80 | BlendOp Add, Max 81 | Cull Off 82 | Lighting Off 83 | ZWrite Off 84 | Offset 0, -.1 85 | 86 | CGPROGRAM 87 | 88 | #pragma vertex vert 89 | #pragma fragment fragColor 90 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 91 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 92 | 93 | #include "UnityCG.cginc" 94 | #include "MeshChain.cginc" 95 | 96 | ENDCG 97 | } 98 | } 99 | FallBack "Diffuse" 100 | CustomEditor "Unity.XRTools.Rendering.MeshChainShaderGUI" 101 | } 102 | -------------------------------------------------------------------------------- /Shaders/MeshChainAdd.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d689c77434e9ecb4084bd09df8d53140 3 | timeCreated: 1460657575 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Shaders/MeshChainAlpha.shader: -------------------------------------------------------------------------------- 1 | Shader "XRLineRenderer/MeshChain - Alpha Blended" 2 | { 3 | Properties 4 | { 5 | _Color("Color Tint", COLOR) = (1,1,1,1) 6 | _lineSettings ("Line Thickness Settings", VECTOR) = (0, 1, .5, 1) 7 | 8 | _lineRadius("Line Radius Scale, Min, Max", VECTOR) = (1, 0, 100) 9 | 10 | // Local space or world space data 11 | [HideInInspector] _WorldData("__worlddata", Float) = 0.0 12 | 13 | // Depth effects line width 14 | [HideInInspector] _LineDepthScale("__linedepthscale", Float) = 1.0 15 | } 16 | SubShader 17 | { 18 | Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } 19 | LOD 100 20 | 21 | // We don't want the line segments and caps to draw over top 22 | // one another as it breaks the continuous segment illusion 23 | // To alpha blend with the background, we use a three-pass technique 24 | Pass 25 | { 26 | // In the first pass we 'clear' the alpha channel to 1, 27 | // so that the inner segments can mask this out 28 | Blend One One 29 | BlendOp Max 30 | Cull Off 31 | Lighting Off 32 | ZWrite Off 33 | ColorMask A 34 | Offset 0, -.1 35 | 36 | CGPROGRAM 37 | 38 | #pragma vertex vert 39 | #pragma fragment fragColor 40 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 41 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 42 | 43 | #include "UnityCG.cginc" 44 | #include "MeshChain.cginc" 45 | 46 | ENDCG 47 | } 48 | Pass 49 | { 50 | // Next we write the line shape and fade only to the alpha channel. 51 | // This lets us punch a hole in the background that our 52 | // line color then shows through 53 | Blend One One 54 | BlendOp Min 55 | Cull Off 56 | Lighting Off 57 | ZWrite Off 58 | ColorMask A 59 | Offset 0, -.1 60 | 61 | CGPROGRAM 62 | 63 | #pragma vertex vert 64 | #pragma fragment fragAlphaMask 65 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 66 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 67 | 68 | #include "UnityCG.cginc" 69 | #include "MeshChain.cginc" 70 | 71 | ENDCG 72 | } 73 | Pass 74 | { 75 | // In this second pass, we write our line color only as much 76 | // as the alpha value we wrote before allows through. To 77 | // prevent overlapping lines from adding too much color, 78 | // we set the alpha value to one after visiting a pixel. 79 | Blend OneMinusDstAlpha DstAlpha, One One 80 | BlendOp Add, Max 81 | Cull Off 82 | Lighting Off 83 | ZWrite Off 84 | Offset 0, -.1 85 | 86 | CGPROGRAM 87 | 88 | #pragma vertex vert 89 | #pragma fragment fragColor 90 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 91 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 92 | 93 | #include "UnityCG.cginc" 94 | #include "MeshChain.cginc" 95 | 96 | ENDCG 97 | } 98 | } 99 | FallBack "Diffuse" 100 | CustomEditor "Unity.XRTools.Rendering.MeshChainShaderGUI" 101 | } 102 | -------------------------------------------------------------------------------- /Shaders/MeshChainAlpha.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2d82e816970e9849bc93f1842c33050 3 | timeCreated: 1460591258 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Shaders/MeshChainMax.shader: -------------------------------------------------------------------------------- 1 | Shader "XRLineRenderer/MeshChain - Max Color" 2 | { 3 | Properties 4 | { 5 | _Color("Color Tint", COLOR) = (1,1,1,1) 6 | _lineSettings ("Line Thickness Settings", VECTOR) = (0, 1, .5, 1) 7 | 8 | _lineRadius ("Line Radius Scale, Min, Max", VECTOR) = (1, 0, 100) 9 | 10 | // Local space or world space data 11 | [HideInInspector] _WorldData("__worlddata", Float) = 0.0 12 | 13 | // Depth effects line width 14 | [HideInInspector] _LineDepthScale("__linedepthscale", Float) = 1.0 15 | } 16 | SubShader 17 | { 18 | Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } 19 | LOD 100 20 | 21 | Pass 22 | { 23 | // This version of the shader writes any pixel brighter than the background 24 | // It uses the 'max' operation so it won't blow out the screen 25 | Blend One One 26 | BlendOp Max 27 | Cull Off 28 | Lighting Off 29 | ZWrite Off 30 | Offset 0, -.1 31 | 32 | CGPROGRAM 33 | 34 | #pragma vertex vert 35 | #pragma fragment frag 36 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 37 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 38 | 39 | #include "UnityCG.cginc" 40 | #include "MeshChain.cginc" 41 | 42 | ENDCG 43 | } 44 | } 45 | FallBack "Diffuse" 46 | CustomEditor "Unity.XRTools.Rendering.MeshChainShaderGUI" 47 | } 48 | -------------------------------------------------------------------------------- /Shaders/MeshChainMax.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c03eb3285154f9d48aef80b7b148e361 3 | timeCreated: 1460416660 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Shaders/MeshChainMin.shader: -------------------------------------------------------------------------------- 1 | Shader "XRLineRenderer/MeshChain - Min Color" 2 | { 3 | Properties 4 | { 5 | _Color("Color Tint", COLOR) = (1,1,1,1) 6 | _lineSettings ("Line Thickness Settings", VECTOR) = (0, 1, .5, 1) 7 | 8 | _lineRadius("Line Radius Scale, Min, Max", VECTOR) = (1, 0, 100) 9 | 10 | // Local space or world space data 11 | [HideInInspector] _WorldData("__worlddata", Float) = 0.0 12 | 13 | // Depth effects line width 14 | [HideInInspector] _LineDepthScale("__linedepthscale", Float) = 1.0 15 | } 16 | SubShader 17 | { 18 | Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } 19 | LOD 100 20 | 21 | Pass 22 | { 23 | // This version of the shader writes any pixel darker than the background 24 | // It uses the 'min' operation to keep line consistency 25 | Blend One One 26 | BlendOp Min 27 | Cull Off 28 | Lighting Off 29 | ZWrite Off 30 | Offset 0, -.1 31 | 32 | CGPROGRAM 33 | 34 | #pragma vertex vert 35 | #pragma fragment fragInvert 36 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 37 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 38 | 39 | #include "UnityCG.cginc" 40 | #include "MeshChain.cginc" 41 | 42 | ENDCG 43 | } 44 | } 45 | FallBack "Diffuse" 46 | CustomEditor "Unity.XRTools.Rendering.MeshChainShaderGUI" 47 | } 48 | -------------------------------------------------------------------------------- /Shaders/MeshChainMin.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9e975b2c6a84c4f479b8ef83f0a88e6f 3 | timeCreated: 1460504404 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Shaders/MeshChainSubtract.shader: -------------------------------------------------------------------------------- 1 | Shader "XRLineRenderer/MeshChain - Subtractive" 2 | { 3 | Properties 4 | { 5 | _Color("Color Tint", COLOR) = (1,1,1,1) 6 | _lineSettings ("Line Thickness Settings", VECTOR) = (0, 1, .5, 1) 7 | 8 | _lineRadius("Line Radius Scale, Min, Max", VECTOR) = (1, 0, 100) 9 | 10 | // Local space or world space data 11 | [HideInInspector] _WorldData("__worlddata", Float) = 0.0 12 | 13 | // Depth effects line width 14 | [HideInInspector] _LineDepthScale("__linedepthscale", Float) = 1.0 15 | } 16 | SubShader 17 | { 18 | Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" } 19 | LOD 100 20 | 21 | // We don't want the line segments and caps to draw overtop 22 | // one another as it breaks the continous segment illusion 23 | // To alpha blend with the background, we use a two-pass technique 24 | Pass 25 | { 26 | // In the first pass we 'clear' the alpha channel to 1, 27 | // so that the inner segments can mask this out 28 | Blend One One 29 | BlendOp Max 30 | Cull Off 31 | Lighting Off 32 | ZWrite Off 33 | ColorMask A 34 | Offset 0, -.1 35 | 36 | CGPROGRAM 37 | 38 | #pragma vertex vert 39 | #pragma fragment fragColor 40 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 41 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 42 | 43 | #include "UnityCG.cginc" 44 | #include "MeshChain.cginc" 45 | 46 | ENDCG 47 | } 48 | Pass 49 | { 50 | // Next we write the line shape and fade only to the alpha channel. 51 | // This lets us punch a hole in the background that our 52 | // line color then shows through 53 | Blend One One 54 | BlendOp Min 55 | Cull Off 56 | Lighting Off 57 | ZWrite Off 58 | ColorMask A 59 | Offset 0, -.1 60 | 61 | CGPROGRAM 62 | 63 | #pragma vertex vert 64 | #pragma fragment fragAlphaMask 65 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 66 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 67 | 68 | #include "UnityCG.cginc" 69 | #include "MeshChain.cginc" 70 | 71 | ENDCG 72 | } 73 | Pass 74 | { 75 | // In this second pass, we write our line color only as much 76 | // as the alpha value we wrote before allows through. To 77 | // prevent overlapping lines from adding too much color, 78 | // we set the alpha value to one after visiting a pixel. 79 | Blend OneMinusDstAlpha One, One One 80 | BlendOp RevSub, Max 81 | Cull Off 82 | Lighting Off 83 | ZWrite Off 84 | Offset 0, -.1 85 | 86 | CGPROGRAM 87 | 88 | #pragma vertex vert 89 | #pragma fragment fragColor 90 | #pragma multi_compile LINE_PERSPECTIVE_WIDTH LINE_FIXED_WIDTH 91 | #pragma multi_compile LINE_MODEL_SPACE LINE_WORLD_SPACE 92 | 93 | #include "UnityCG.cginc" 94 | #include "MeshChain.cginc" 95 | 96 | ENDCG 97 | } 98 | } 99 | FallBack "Diffuse" 100 | CustomEditor "Unity.XRTools.Rendering.MeshChainShaderGUI" 101 | } 102 | -------------------------------------------------------------------------------- /Shaders/MeshChainSubtract.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d1af3afcc83db644b8abe552f6a0e05 3 | timeCreated: 1460657638 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 443613d63ae4747d9951c09280c994df 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a1474d1c2d2448c1ad2cf2b45f968bf 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Runtime/Unity.Labs.XRLineRenderer.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Unity.XRLineRenderer.Tests", 3 | "optionalUnityReferences": [ 4 | "TestAssemblies" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Runtime/Unity.Labs.XRLineRenderer.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b435ccf8bd6a473a97f57e603de1b23 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests/Runtime/XRLineRendererTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using NUnit.Framework; 4 | using UnityEngine; 5 | using UnityEngine.TestTools; 6 | 7 | namespace Tests 8 | { 9 | public class XRLineRendererTests 10 | { 11 | // A Test behaves as an ordinary method 12 | [Test] 13 | public void XRLineRendererTestsSimplePasses() 14 | { 15 | // Use the Assert class to test conditions 16 | } 17 | 18 | // A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use 19 | // `yield return null;` to skip a frame. 20 | [UnityTest] 21 | public IEnumerator XRLineRendererTestsWithEnumeratorPasses() 22 | { 23 | // Use the Assert class to test conditions. 24 | // Use yield to skip a frame. 25 | yield return null; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Runtime/XRLineRendererTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 681b1399acda446198090d56d5fae167 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.unity.xr-line-renderer", 3 | "displayName": "XR Line Renderer", 4 | "version": "0.1.3-preview", 5 | "unity": "2019.1", 6 | "unityRelease": "14f1", 7 | "description": "An XR-Optimized line renderer that is also capable of producing very inexpensive glow effects. The XRLineRenderer mimics rendering with 3d capsules while only using two quads worth of geometry." 8 | } 9 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7dee6506f0c1e4df68474718c56c6e6f 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------