DSprtn / GTFO_VR_Plugin

A plugin to add full roomscale Virtual Reality support to your favorite game!
MIT License
143 stars 13 forks source link

Add laser, holographic sight to thermal sight #38

Closed Nordskog closed 2 years ago

Nordskog commented 2 years ago

What?

The new thermal sights in R7 use a shader that, while having multiple reticles ( turns out that is the correct spelling, not "reticule" ) defined with most of the properties from the standard 3-layer holographic sight shader, does not actually support anything but plastering them all at the same depth, making it unusable in VR. To make matters worse, the VR aiming laser is not rendered at all through the thermal sight, making it impossible to aim it accurately.

This PR makes the aiming laser visible as a bright-white object through the thermal sight, and also adds a 3-layer holographic sight to it, resulting in this: https://youtu.be/JnATkNCAO8Y?t=33

Is the laser actually needed? ... a strong maybe.

How?

Holographic Sight It turns out both of the thermal sights have a default 3-layer sight object named e.g. Sight_10_Glass buried behind the thermal sight, deactivated. Activate, shift backwards by a bit so it's visible, and you're good. The thermal shader doesn't use the same set of values to determine the layout of its reticles as the 3-layer holographic shader, so rather than transplant anything the reticles that come with the default material have been left alone.

Had I know it would be so simple I would probably not have bothered with the laser.

Laser

GTFO uses deferred rendering, with the deferred pass spitting out

all in one pass. Encoded in the alpha channel of the emission buffer you will find the_ShadingType property present on many of GTFO's materials. This value is extracted further down the pipe, and along with the normal and spec/SSS values determine how brightly things will glow in the thermal sight.

If you just use any one of the GTFO materials that include this property, you will encounter 2 problems:

  1. The normal to the camera greatly affects the brightness.
  2. The object will have an outline that is affected by light ( or lack thereof ) even with emission cranked.

The existing laser mesh is not affected by any of this because it is rendered after the thermal shader. It is also not a deferred shader, so it renders separately after the deferred pass, skipping some of its logic. If you do lower its renderqueue to render before the thermal sight, it will render as a blurry blob, as it is assigned the default _ShadingType, which blurs surfaces to give the impression of a gradual heat gradient.

The solution to this is to write our own deferred shader that:

Ramping the emission way up gives a cool looking glow in the thermal sight, but unfortunately reacts poorly with glass surfaces, and had to be toned down significantly.

This shader is assigned to children of the existing pointer/dot and just scale with them, so no extra logic beyond parenting them.

The Shader asset

The shader is added as its own asset in \StreamingAssets: vrthermal along with its manifest vrthermal.manifest. Like the existing AssetBundles, I have included its SecondaryAsssetBundles, but I guess ultimately neither of these are actually used and not actually required. But they're there.

Presumably they can be merged somehow, if that matters.

The code for any of the custom VR shaders is actually committed to the repo at the moment. Maybe do that, but for now I'll just attach it here.

GTFOVR/Thermal_Glow ```glsl Shader "GTFOVR/Thermal_Glow" { Properties { _MainTex("Texture", 2D) = "white" {} _Bump("Bump", Color) = (1,1,1,0.750) _Color("Color", Color) = (1,1,1,1) _EmissionColor("Emission", Color) = (1,1,1,1) [Enum(Normal,0,Translucent,1,Skin,2,Cloth,3,NormalWarm,4,SkinCold,5,SkinWarm,6)] _ShadingType("Shading Type", Float) = 2 } SubShader { Tags { "LightMode" = "Deferred" "RenderType" = "Opaque" "Queue" = "Geometry+10"} // Queue ignored? LOD 100 Pass { Cull Off ZWrite Off // Off to avoid outline CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct Attributes { float4 position : POSITION; float3 normal : NORMAL; float4 tangent : TANGENT; float2 uv : TEXCOORD; uint instance : SV_InstanceID; }; struct Varyings { float4 position : SV_POSITION; float2 uv : TEXCOORD0; float3 normal : TEXCOORD1; float3 uv1 : TEXCOORD2; float3 uv3 : TEXCOORD4; float4 uv4 : TEXCOORD5; float4 uv5 : TEXCOORD6; uint instance : SV_InstanceID; }; float4 _Color; float4 _Bump; float4 _EmissionColor; float _ShadingType; sampler2D _MainTex; float4 _MainTex_ST; struct FragmentOutput { float4 diffuse : SV_Target; float4 bump : SV_Target1; float4 normal : SV_Target2; float4 emission : SV_Target3; }; Varyings vert(Attributes v) { Varyings o; o.position = UnityObjectToClipPos(v.position); o.uv = TRANSFORM_TEX(v.uv, _MainTex); //Normal facing camera o.normal = (unity_CameraToWorld._m02_m12_m22) * -0.5 + 0.5; return o; } FragmentOutput frag(Varyings i) { FragmentOutput o; float shadingTypeMagicNumber = 0.003921569; o.diffuse = _Color; o.bump = _Bump; o.normal = float4(i.normal.x, i.normal.y, i.normal.z, 1); o.emission = float4( _EmissionColor.x, _EmissionColor.y, _EmissionColor.z, _ShadingType * shadingTypeMagicNumber + shadingTypeMagicNumber); // Converted to a very low alpha value, e.g. 2 maps to 0.012 return o; } ENDCG } } } ```

Minor stuff

The dot would be deactivated when the laser hit is more than 100 units away, but it is never reactivated and will not reappearing until you switch to a different weapon. This has been fixed. Many colliders are not very accurate and the pointer dot will often get buried in geometry. It has been shifted by 0.1 units to help with this a bit.

DSprtn commented 2 years ago

Great work! Didn't you say you didn't have much exposure to these things before?

Nordskog commented 2 years ago

A constant color opengl shader I made about 10 years back was about the extent of my existing shader knoweldge; there was a bit of a learning curve. Getting NSight working was a gamechanger; your previous conversations in the GTFO modding server proved very helpful.