Merge branch 'develop' into feature-text

This commit is contained in:
Andrew Cassidy 2020-07-02 20:13:46 -07:00
commit a9b05a677e
41 changed files with 1661 additions and 1312 deletions

View File

@ -1,4 +1,5 @@
using UnityEngine; using System;
using UnityEngine;
[ExecuteInEditMode] [ExecuteInEditMode]
public class DecalProjectorTest : MonoBehaviour public class DecalProjectorTest : MonoBehaviour
@ -23,9 +24,6 @@ public class DecalProjectorTest : MonoBehaviour
void Awake() void Awake()
{ {
_projectionMatrix = Matrix4x4.identity; _projectionMatrix = Matrix4x4.identity;
_matrixID = Shader.PropertyToID("_ProjectionMatrix");
_normalID = Shader.PropertyToID("_DecalNormal");
_tangentID= Shader.PropertyToID("_DecalTangent");
targetRenderer = target.GetComponent<MeshRenderer>(); targetRenderer = target.GetComponent<MeshRenderer>();
} }
@ -40,8 +38,9 @@ public class DecalProjectorTest : MonoBehaviour
var projectorToTarget = targetRenderer.worldToLocalMatrix * transform.localToWorldMatrix; var projectorToTarget = targetRenderer.worldToLocalMatrix * transform.localToWorldMatrix;
_projectionMatrix = _OrthoMatrix * targetToProjector; _projectionMatrix = _OrthoMatrix * targetToProjector;
targetMaterial.SetMatrix(_matrixID, _projectionMatrix); targetMaterial.SetMatrix("_ProjectionMatrix", _projectionMatrix);
targetMaterial.SetVector(_normalID, projectorToTarget.MultiplyVector(Vector3.back).normalized); targetMaterial.SetVector("_DecalNormal", projectorToTarget.MultiplyVector(Vector3.back).normalized);
targetMaterial.SetVector(_tangentID, projectorToTarget.MultiplyVector(Vector3.right).normalized); targetMaterial.SetVector("_DecalTangent", projectorToTarget.MultiplyVector(Vector3.right).normalized);
} }
} }

View File

@ -1,130 +0,0 @@
Shader "ConformalDecals/Feature/Bumped"
{
Properties
{
[Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {}
_DecalBumpMap("Decal Bump Map", 2D) = "bump" {}
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
}
SubShader
{
Tags { "Queue" = "Geometry+100" }
Cull [_Cull]
Ztest LEqual
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap
#pragma multi_compile DECAL_PROJECT DECAL_PREVIEW
sampler2D _Decal;
sampler2D _DecalBumpMap;
float4 _Decal_ST;
float4 _DecalBumpMap_ST;
float _RimFalloff;
float4 _RimColor;
#define DECAL_NORMAL
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 normal = UnpackNormalDXT5nm(tex2D(_DecalBumpMap, IN.uv_bump));
decalClipAlpha(color.a - _Cutoff);
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
o.Normal = normal;
}
ENDCG
}
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
Blend One One
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap
#pragma multi_compile DECAL_PROJECT DECAL_PREVIEW
sampler2D _Decal;
sampler2D _DecalBumpMap;
float4 _Decal_ST;
float4 _DecalBumpMap_ST;
float _RimFalloff;
float4 _RimColor;
#define DECAL_NORMAL
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 normal = UnpackNormal(tex2D(_DecalBumpMap, IN.uv_bump));
decalClipAlpha(color.a - _Cutoff);
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
o.Normal = normal;
}
ENDCG
}
// shadow casting support
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}

View File

@ -1,143 +0,0 @@
Shader "ConformalDecals/Paint/Diffuse"
{
Properties
{
[Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
}
SubShader
{
Tags { "Queue" = "Geometry+100" }
Cull [_Cull]
Ztest LEqual
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
float4 _Decal_ST;
float _EdgeWearStrength;
float _EdgeWearOffset;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
decalClipAlpha(color.a - _Cutoff);
float3 normal = IN.normal;
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
}
ENDCG
}
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
Blend One One
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
float4 _Decal_ST;
float _EdgeWearStrength;
float _EdgeWearOffset;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
decalClipAlpha(color.a - _Cutoff);
float3 normal = IN.normal;
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
}
ENDCG
}
// shadow casting support
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}

View File

@ -1,159 +0,0 @@
Shader "ConformalDecals/Paint/DiffuseSDF"
{
Properties
{
[Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Smoothness ("SDF smoothness", Range(0,1)) = 0.15
_SmoothnessMipScale ("Smoothness fadeout", Range(0,1)) = 0.1
_DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
}
SubShader
{
Tags { "Queue" = "Geometry+100" }
Cull [_Cull]
Ztest LEqual
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
float4 _Decal_ST;
float4 _Decal_TexelSize;
float _Smoothness;
float _SmoothnessMipScale;
float _EdgeWearStrength;
float _EdgeWearOffset;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 normal = IN.normal;
float smoothScale = (1 - saturate(1-(CalcMipLevel(IN.uv_decal * _Decal_TexelSize.zw) * _SmoothnessMipScale))) / 2;
color.a = smoothstep(_Cutoff - smoothScale, saturate(_Smoothness + smoothScale + _Cutoff), color.a);
decalClipAlpha(color.a);
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
}
ENDCG
}
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
Blend One One
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
float4 _Decal_ST;
float4 _Decal_TexelSize;
float _Smoothness;
float _SmoothnessMipScale;
float _EdgeWearStrength;
float _EdgeWearOffset;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 normal = IN.normal;
float smoothScale = (1 - saturate(1-(CalcMipLevel(IN.uv_decal * _Decal_TexelSize.zw) * _SmoothnessMipScale))) / 2;
color.a = smoothstep(_Cutoff - smoothScale, saturate(_Smoothness + smoothScale + _Cutoff), color.a);
decalClipAlpha(color.a);
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
}
ENDCG
}
// shadow casting support
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}

View File

@ -1,165 +0,0 @@
Shader "ConformalDecals/Paint/Specular"
{
Properties
{
[Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {}
_SpecMap("Specular Map", 2D) = "black" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Header(Specularity)]
_SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1)
_Shininess ("Shininess", Range (0.03, 10)) = 0.3
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
}
SubShader
{
Tags { "Queue" = "Geometry+100" }
Cull [_Cull]
Ztest LEqual
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
sampler2D _SpecMap;
float4 _Decal_ST;
float4 _SpecMap_ST;
float _EdgeWearStrength;
float _EdgeWearOffset;
half _Shininess;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#define DECAL_SPECULAR
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 specular = tex2D(_SpecMap, IN.uv_spec);
decalClipAlpha(color.a - _Cutoff);
float3 normal = IN.normal;
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
color.a *= _DecalOpacity;
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a;
o.Emission = emission;
o.Specular = _Shininess;
o.Gloss = specular.r * color.a;
}
ENDCG
}
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
Blend One One
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
sampler2D _SpecMap;
float4 _Decal_ST;
float4 _SpecMap_ST;
float _EdgeWearStrength;
float _EdgeWearOffset;
half _Shininess;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#define DECAL_SPECULAR
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 specular = tex2D(_SpecMap, IN.uv_spec);
float3 normal = IN.normal;
decalClipAlpha(color.a - _Cutoff);
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
o.Specular = _Shininess;
o.Gloss = specular.r;
}
ENDCG
}
// shadow casting support
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}

View File

@ -1,180 +0,0 @@
Shader "ConformalDecals/Paint/SpecularSDF"
{
Properties
{
[Header(Texture Maps)]
_Decal("Decal Texture", 2D) = "gray" {}
_BumpMap("Bump Map", 2D) = "bump" {}
_SpecMap("Specular Map", 2D) = "black" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Smoothness ("SDF smoothness", Range(0,1)) = 0.15
_SmoothnessMipScale ("Smoothness fadeout", Range(0,1)) = 0.1
_DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Header(Specularity)]
_SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1)
_Shininess ("Shininess", Range (0.03, 10)) = 0.3
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
}
SubShader
{
Tags { "Queue" = "Geometry+100" }
Cull [_Cull]
Ztest LEqual
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
sampler2D _SpecMap;
float4 _Decal_ST;
float4 _Decal_TexelSize;
float4 _SpecMap_ST;
float _Smoothness;
float _SmoothnessMipScale;
float _EdgeWearStrength;
float _EdgeWearOffset;
half _Shininess;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#define DECAL_SPECULAR
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 specular = tex2D(_SpecMap, IN.uv_spec);
float3 normal = IN.normal;
float smoothScale = (1 - saturate(1-(CalcMipLevel(IN.uv_decal * _Decal_TexelSize.zw) * _SmoothnessMipScale))) / 2;
color.a = smoothstep(_Cutoff - smoothScale, saturate(_Smoothness + smoothScale + _Cutoff), color.a);
decalClipAlpha(color.a);
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
o.Specular = _Shininess;
o.Gloss = specular.r;
}
ENDCG
}
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
Blend One One
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap
#pragma multi_compile __ DECAL_PREVIEW
sampler2D _Decal;
sampler2D _SpecMap;
float4 _Decal_ST;
float4 _Decal_TexelSize;
float4 _SpecMap_ST;
float _Smoothness;
float _SmoothnessMipScale;
float _EdgeWearStrength;
float _EdgeWearOffset;
half _Shininess;
float _RimFalloff;
float4 _RimColor;
#define DECAL_BASE_NORMAL
#define DECAL_SPECULAR
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "LightingKSP.cginc"
#include "DecalsCommon.cginc"
void surf (DecalSurfaceInput IN, inout SurfaceOutput o)
{
float4 color = tex2D(_Decal, IN.uv_decal);
float3 specular = tex2D(_SpecMap, IN.uv_spec);
float3 normal = IN.normal;
float smoothScale = (1 - saturate(1-(CalcMipLevel(IN.uv_decal * _Decal_TexelSize.zw) * _SmoothnessMipScale))) / 2;
color.a = smoothstep(_Cutoff - smoothScale, saturate(_Smoothness + smoothScale + _Cutoff), color.a);
decalClipAlpha(color.a);
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal));
float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = color.a * _DecalOpacity;
o.Emission = emission;
o.Specular = _Shininess;
o.Gloss = specular.r;
}
ENDCG
}
// shadow casting support
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}

View File

@ -1,26 +1,93 @@
#ifndef DECALS_COMMON_INCLUDED #ifndef DECALS_COMMON_INCLUDED
#define DECALS_COMMON_INCLUDED #define DECALS_COMMON_INCLUDED
#include "AutoLight.cginc"
#include "Lighting.cginc"
#define CLIP_MARGIN 0.1
#define EDGE_MARGIN 0.01
// UNIFORM VARIABLES
// Projection matrix, normal, and tangent vectors
float4x4 _ProjectionMatrix;
float3 _DecalNormal;
float3 _DecalTangent;
// Common Shading Paramaters
float _Cutoff;
float _DecalOpacity;
float4 _Background;
sampler2D _Decal;
float4 _Decal_ST;
// Variant Shading Parameters
#ifdef DECAL_BASE_NORMAL
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _EdgeWearStrength;
float _EdgeWearOffset;
#endif //DECAL_BASE_NORMAL
#ifdef DECAL_BUMPMAP
sampler2D _BumpMap;
float4 _BumpMap_ST;
#endif //DECAL_BUMPMAP
#ifdef DECAL_SPECMAP
sampler2D _SpecMap;
float4 _SpecMap_ST;
// specular color is declared in a unity CGINC for some reason??
fixed _Shininess;
#endif //DECAL_SPECMAP
#ifdef DECAL_EMISSIVE
sampler2D _Emissive;
float4 _Emissive_ST;
fixed4 _Emissive_Color;
#endif //DECAL_EMISSIVE
// KSP EFFECTS
// opacity and color
float _Opacity;
float4 _Color;
float _RimFalloff;
float4 _RimColor;
// fog
float4 _LocalCameraPos;
float4 _LocalCameraDir;
float4 _UnderwaterFogColor;
float _UnderwaterMinAlphaFogDistance;
float _UnderwaterMaxAlbedoFog;
float _UnderwaterMaxAlphaFog;
float _UnderwaterAlbedoDistanceScalar;
float _UnderwaterAlphaDistanceScalar;
float _UnderwaterFogFactor;
// SURFACE INPUT STRUCT
struct DecalSurfaceInput struct DecalSurfaceInput
{ {
float3 uv;
float2 uv_decal; float2 uv_decal;
#ifdef DECAL_NORMAL #ifdef DECAL_BUMPMAP
float2 uv_bump; float2 uv_bumpmap;
#endif //DECAL_NORMAL #endif //DECAL_BUMPMAP
#ifdef DECAL_SPECULAR #ifdef DECAL_SPECMAP
float2 uv_spec; float2 uv_specmap;
#endif //DECAL_SPECULAR #endif //DECAL_SPECMAP
#ifdef DECAL_EMISSIVE #ifdef DECAL_EMISSIVE
float2 uv_glow; float2 uv_emissive;
#endif //DECAL_EMISSIVE #endif //DECAL_EMISSIVE
#ifdef DECAL_BASE_NORMAL #ifdef DECAL_BASE_NORMAL
float3 normal; float3 normal;
#endif #endif
float3 vertex_normal;
float3 viewDir; float3 viewDir;
float3 worldPosition; float3 worldPosition;
}; };
@ -59,20 +126,6 @@ struct v2f
#endif //UNITY_PASS_FORWARDADD #endif //UNITY_PASS_FORWARDADD
}; };
// Projection matrix, normal, and tangent vectors
float4x4 _ProjectionMatrix;
float3 _DecalNormal;
float3 _DecalTangent;
#ifdef DECAL_BASE_NORMAL
sampler2D _BumpMap;
float4 _BumpMap_ST;
#endif //DECAL_BASE_NORMAL
float _Cutoff;
float _DecalOpacity;
float _Opacity;
float4 _Background;
inline void decalClipAlpha(float alpha) { inline void decalClipAlpha(float alpha) {
#ifndef DECAL_PREVIEW #ifndef DECAL_PREVIEW
@ -88,200 +141,23 @@ inline float CalcMipLevel(float2 texture_coord) {
return 0.5 * log2(delta_max_sqr); return 0.5 * log2(delta_max_sqr);
} }
// modifed version of the KSP BlinnPhong because it does some weird things inline float BoundsDist(float3 p, float3 normal, float3 projNormal) {
inline fixed4 LightingBlinnPhongDecal(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) float3 q = abs(p - 0.5) - 0.5; // 1x1 square/cube centered at (0.5,0.5)
{ //float dist = length(max(q,0)) + min(max(q.x,max(q.y,q.z)),0.0); // true SDF
s.Normal = normalize(s.Normal); #ifdef DECAL_PREVIEW
half3 h = normalize(lightDir + viewDir); return 10 * max(q.x, q.y); // 2D pseudo SDF
#else
fixed diff = max(0, dot(s.Normal, lightDir)); float dist = max(max(q.x, q.y), q.z); // pseudo SDF
float ndist = EDGE_MARGIN - dot(normal, projNormal); // SDF to normal
float nh = max(0, dot(s.Normal, h)); return 10 * max(dist, ndist); // return intersection
float spec = pow(nh, s.Specular*128.0) * s.Gloss; #endif
fixed4 c = 0;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten);
return c;
} }
// declare surf function, inline float SDFAA(float dist) {
// this must be defined in any shader using this cginc float ddist = length(float2(ddx(dist), ddy(dist)));
void surf (DecalSurfaceInput IN, inout SurfaceOutput o); float pixelDist = dist / ddist;
return saturate(0.5-pixelDist);
v2f vert_forward(appdata_decal v) return saturate(0.5 - dist);
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = v.normal;
#ifdef DECAL_PREVIEW
o.uv_decal = v.texcoord;
#else
o.uv_decal = mul (_ProjectionMatrix, v.vertex);
#endif //DECAL_PREVIEW
#ifdef DECAL_BASE_NORMAL
o.uv_base = TRANSFORM_TEX(v.texcoord, _BumpMap);
#endif //DECAL_BASE_NORMAL
float3 worldPosition = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
#if defined(DECAL_BASE_NORMAL) || defined(DECAL_PREVIEW)
// use tangent of base geometry
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
#else
// use tangent of projector
fixed3 decalTangent = UnityObjectToWorldDir(_DecalTangent);
fixed3 worldBinormal = cross(decalTangent, worldNormal);
fixed3 worldTangent = cross(worldNormal, worldBinormal);
#endif //defined(DECAL_BASE_NORMAL) || defined(DECAL_PREVIEW)
o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPosition.x);
o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPosition.y);
o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPosition.z);
// forward base pass specific lighting code
#ifdef UNITY_PASS_FORWARDBASE
// SH/ambient light
#if UNITY_SHOULD_SAMPLE_SH
float3 shlight = ShadeSH9 (float4(worldNormal,1.0));
o.vlight = shlight;
#else
o.vlight = 0.0;
#endif // UNITY_SHOULD_SAMPLE_SH
// vertex light
#ifdef VERTEXLIGHT_ON
o.vlight += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, worldPosition, worldNormal );
#endif // VERTEXLIGHT_ON
#endif // UNITY_PASS_FORWARDBASE
// pass shadow and, possibly, light cookie coordinates to pixel shader
UNITY_TRANSFER_LIGHTING(o, 0.0);
return o;
}
fixed4 frag_forward(v2f IN) : SV_Target
{
// declare data
DecalSurfaceInput i;
SurfaceOutput o;
fixed4 c = 0;
// setup world-space TBN vectors
UNITY_EXTRACT_TBN(IN);
float3 worldPosition = float3(IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w);
float3 worldTangent = float3(IN.tSpace0.x, IN.tSpace1.x, IN.tSpace2.x);
// setup world-space light and view direction vectors
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPosition));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPosition));
float3 viewDir = _unity_tbn_0 * worldViewDir.x + _unity_tbn_1 * worldViewDir.y + _unity_tbn_2 * worldViewDir.z;
#ifdef DECAL_PREVIEW
fixed4 uv_projected = IN.uv_decal;
#else
// perform decal projection
fixed4 uv_projected = UNITY_PROJ_COORD(IN.uv_decal);
// clip texture outside of xyz bounds
clip(uv_projected.xyz);
clip(1-uv_projected.xyz);
// clip backsides
clip(dot(_DecalNormal, IN.normal));
#endif //DECAL_PREVIEW
// initialize surface input
UNITY_INITIALIZE_OUTPUT(DecalSurfaceInput, i)
i.uv_decal = TRANSFORM_TEX(uv_projected, _Decal);
#ifdef DECAL_NORMAL
i.uv_bump = TRANSFORM_TEX(uv_projected, _DecalBumpMap);
#endif //DECAL_NORMAL
#ifdef DECAL_SPECULAR
i.uv_spec = TRANSFORM_TEX(uv_projected, _SpecMap);
#endif //DECAL_SPECULAR
#ifdef DECAL_EMISSIVE
i.uv_glow = TRANSFORM_TEX(uv_projected, _GlowMap);
#endif //DECAL_EMISSIVE
#ifdef DECAL_BASE_NORMAL
#ifdef DECAL_PREVIEW
i.normal = fixed3(0,0,1);
#else
i.normal = UnpackNormalDXT5nm(tex2D(_BumpMap, IN.uv_base));
#endif //DECAL_PREVIEW
#endif //DECAL_BASE_NORMAL
//i.normal = IN.normal;
i.viewDir = viewDir;
i.worldPosition = worldPosition;
// initialize surface output
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
o.Normal = fixed3(0,0,1);
// call surface function
surf(i, o);
#ifdef DECAL_PREVIEW
if (any(IN.uv_decal > 1) || any(IN.uv_decal < 0)) o.Alpha = 0;
o.Albedo = lerp(_Background.rgb, o.Albedo, o.Alpha) * _Color.rgb;
o.Normal = lerp(float3(0,0,1), o.Normal, o.Alpha);
o.Gloss = lerp(_Background.a, o.Gloss, o.Alpha);
o.Emission = lerp(0, o.Emission, o.Alpha);
o.Alpha = _Opacity;
#endif //DECAL_PREVIEW
// compute lighting & shadowing factor
UNITY_LIGHT_ATTENUATION(atten, IN, worldPosition)
// compute world normal
float3 WorldNormal;
WorldNormal.x = dot(_unity_tbn_0, o.Normal);
WorldNormal.y = dot(_unity_tbn_1, o.Normal);
WorldNormal.z = dot(_unity_tbn_2, o.Normal);
WorldNormal = normalize(WorldNormal);
o.Normal = WorldNormal;
//call modified KSP lighting function
c += LightingBlinnPhongDecal(o, lightDir, worldViewDir, atten);
// Forward base emission and ambient/vertex lighting
#ifdef UNITY_PASS_FORWARDBASE
c.rgb += o.Emission;
c.rgb += o.Albedo * IN.vlight;
c.a = o.Alpha;
#endif //UNITY_PASS_FORWARDBASE
// Forward add multiply by alpha
#ifdef UNITY_PASS_FORWARDADD
c.rgb *= o.Alpha;
#endif
return c;
} }
#endif #endif

View File

@ -0,0 +1,33 @@
#ifndef DECALS_LIGHTING_INCLUDED
#define DECALS_LIGHTING_INCLUDED
// modifed version of the KSP BlinnPhong because it does some weird things
inline fixed4 LightingBlinnPhongDecal(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{
s.Normal = normalize(s.Normal);
half3 h = normalize(lightDir + viewDir);
fixed diff = max(0, dot(s.Normal, lightDir));
float nh = max(0, dot(s.Normal, h));
float spec = pow(nh, s.Specular*128.0) * s.Gloss;
fixed4 c = 0;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten);
return c;
}
// KSP underwater fog function
float4 UnderwaterFog(float3 worldPos, float3 color)
{
float3 toPixel = worldPos - _LocalCameraPos.xyz;
float toPixelLength = length(toPixel);
float underwaterDetection = _UnderwaterFogFactor * _LocalCameraDir.w;
float albedoLerpValue = underwaterDetection * (_UnderwaterMaxAlbedoFog * saturate(toPixelLength * _UnderwaterAlbedoDistanceScalar));
float alphaFactor = 1 - underwaterDetection * (_UnderwaterMaxAlphaFog * saturate((toPixelLength - _UnderwaterMinAlphaFogDistance) * _UnderwaterAlphaDistanceScalar));
return float4(lerp(color, _UnderwaterFogColor.rgb, albedoLerpValue), alphaFactor);
}
#endif

View File

@ -0,0 +1,183 @@
#ifndef DECALS_SURFACE_INCLUDED
#define DECALS_SURFACE_INCLUDED
#include "DecalsCommon.cginc"
#include "DecalsLighting.cginc"
// declare surf function,
// this must be defined in any shader using this cginc
void surf (DecalSurfaceInput IN, inout SurfaceOutput o);
v2f vert_forward(appdata_decal v)
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = v.normal;
#ifdef DECAL_PREVIEW
o.uv_decal = v.texcoord;
#else
o.uv_decal = mul (_ProjectionMatrix, v.vertex);
#endif //DECAL_PREVIEW
#ifdef DECAL_BASE_NORMAL
o.uv_base = TRANSFORM_TEX(v.texcoord, _BumpMap);
#endif //DECAL_BASE_NORMAL
float3 worldPosition = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
#if defined(DECAL_BASE_NORMAL) || defined(DECAL_PREVIEW)
// use tangent of base geometry
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
#else
// use tangent of projector
fixed3 decalTangent = UnityObjectToWorldDir(_DecalTangent);
fixed3 worldBinormal = cross(decalTangent, worldNormal);
fixed3 worldTangent = cross(worldNormal, worldBinormal);
#endif //defined(DECAL_BASE_NORMAL) || defined(DECAL_PREVIEW)
o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPosition.x);
o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPosition.y);
o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPosition.z);
// forward base pass specific lighting code
#ifdef UNITY_PASS_FORWARDBASE
// SH/ambient light
#if UNITY_SHOULD_SAMPLE_SH
float3 shlight = ShadeSH9 (float4(worldNormal,1.0));
o.vlight = shlight;
#else
o.vlight = 0.0;
#endif // UNITY_SHOULD_SAMPLE_SH
// vertex light
#ifdef VERTEXLIGHT_ON
o.vlight += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, worldPosition, worldNormal );
#endif // VERTEXLIGHT_ON
#endif // UNITY_PASS_FORWARDBASE
// pass shadow and, possibly, light cookie coordinates to pixel shader
UNITY_TRANSFER_LIGHTING(o, 0.0);
return o;
}
fixed4 frag_forward(v2f IN) : SV_Target
{
#ifdef DECAL_PREVIEW
fixed4 uv_projected = IN.uv_decal;
#else
// perform decal projection
fixed4 uv_projected = UNITY_PROJ_COORD(IN.uv_decal);
clip(uv_projected.xyz + CLIP_MARGIN);
clip(CLIP_MARGIN + (1-uv_projected.xyz));
#endif //DECAL_PREVIEW
// declare data
DecalSurfaceInput i;
SurfaceOutput o;
// setup world-space TBN vectors
UNITY_EXTRACT_TBN(IN);
float3 worldPosition = float3(IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w);
float3 worldTangent = float3(IN.tSpace0.x, IN.tSpace1.x, IN.tSpace2.x);
// setup world-space light and view direction vectors
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPosition));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPosition));
float3 viewDir = _unity_tbn_0 * worldViewDir.x + _unity_tbn_1 * worldViewDir.y + _unity_tbn_2 * worldViewDir.z;
// initialize surface input
UNITY_INITIALIZE_OUTPUT(DecalSurfaceInput, i)
i.uv_decal = TRANSFORM_TEX(uv_projected, _Decal);
i.uv = uv_projected;
#ifdef DECAL_BUMPMAP
i.uv_bumpmap = TRANSFORM_TEX(uv_projected, _BumpMap);
#endif //DECAL_BUMPMAP
#ifdef DECAL_SPECMAP
i.uv_specmap = TRANSFORM_TEX(uv_projected, _SpecMap);
#endif //DECAL_SPECMAP
#ifdef DECAL_EMISSIVE
i.uv_emissive = TRANSFORM_TEX(uv_projected, _Emissive);
#endif //DECAL_EMISSIVE
#ifdef DECAL_BASE_NORMAL
#ifdef DECAL_PREVIEW
i.normal = fixed3(0,0,1);
#else
i.normal = UnpackNormalDXT5nm(tex2D(_BumpMap, IN.uv_base));
#endif //DECAL_PREVIEW
#endif //DECAL_BASE_NORMAL
i.vertex_normal = IN.normal;
i.viewDir = viewDir;
i.worldPosition = worldPosition;
// initialize surface output
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
o.Normal = fixed3(0,0,1);
// call surface function
surf(i, o);
#ifdef DECAL_PREVIEW
if (any(IN.uv_decal > 1) || any(IN.uv_decal < 0)) o.Alpha = 0;
o.Albedo = lerp(_Background.rgb, o.Albedo, o.Alpha) * _Color.rgb;
o.Normal = lerp(float3(0,0,1), o.Normal, o.Alpha);
o.Gloss = lerp(_Background.a, o.Gloss, o.Alpha);
o.Emission = lerp(0, o.Emission, o.Alpha);
o.Alpha = _Opacity;
#endif //DECAL_PREVIEW
// compute lighting & shadowing factor
UNITY_LIGHT_ATTENUATION(atten, IN, worldPosition)
// compute world normal
float3 WorldNormal;
WorldNormal.x = dot(_unity_tbn_0, o.Normal);
WorldNormal.y = dot(_unity_tbn_1, o.Normal);
WorldNormal.z = dot(_unity_tbn_2, o.Normal);
WorldNormal = normalize(WorldNormal);
o.Normal = WorldNormal;
//call modified KSP lighting function
float4 c = LightingBlinnPhongDecal(o, lightDir, worldViewDir, atten);
// Forward base emission and ambient/vertex lighting
#ifdef UNITY_PASS_FORWARDBASE
c.rgb += o.Emission;
c.rgb += o.Albedo * IN.vlight;
c.a = o.Alpha;
#endif //UNITY_PASS_FORWARDBASE
// Forward add multiply by alpha
#ifdef UNITY_PASS_FORWARDADD
c.rgb *= o.Alpha;
#endif
return c;
}
#endif

View File

@ -12,8 +12,9 @@ Shader "ConformalDecals/SelectionGlow"
} }
SubShader SubShader
{ {
Tags { "Queue" = "Transparent" } Tags { "Queue" = "Transparent" "IgnoreProjector" = "true" }
Cull Back Cull Back
ZWrite Off
Pass Pass
{ {

View File

@ -0,0 +1,38 @@
void surf(DecalSurfaceInput IN, inout SurfaceOutput o) {
float4 color = tex2D(_Decal, IN.uv_decal);
o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb;
o.Alpha = _DecalOpacity;
#ifdef DECAL_BASE_NORMAL
float3 normal = IN.normal;
float wearFactor = 1 - normal.z;
float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor);
o.Alpha *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor));
#endif
#ifdef DECAL_BUMPMAP
o.Normal = tex2D(_BumpMap, IN.uv_bumpmap);
#endif
#ifdef DECAL_SPECMAP
float4 specular = tex2D(_SpecMap, IN.uv_specmap);
o.Gloss = specular.r;
o.Specular = _Shininess;
#endif
half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
o.Emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a;
#ifdef DECAL_EMISSIVE
o.Emission += tex2D(_Emissive, IN.uv_emissive).rgb * _Emissive_Color.rgb * _Emissive_Color.a;
#endif
float dist = BoundsDist(IN.uv, IN.vertex_normal, _DecalNormal);
#ifdef DECAL_SDF_ALPHA
float decalDist = _Cutoff - color.a;
o.Alpha *= SDFAA(max(decalDist, dist));
#else
o.Alpha *= SDFAA(dist);
o.Alpha *= color.a;
#endif
}

View File

@ -0,0 +1,109 @@
Shader "ConformalDecals/Decal/Standard"
{
Properties
{
[Header(Decal)]
_Decal("Decal Texture", 2D) = "gray" {}
[Toggle(DECAL_SDF_ALPHA)] _Decal_SDF_Alpha ("SDF in Alpha", int) = 0
[Header(Normal)]
[Toggle(DECAL_BASE_NORMAL)] _BaseNormal ("Use Base Normal", int) = 0
[Toggle(DECAL_BUMPMAP)] _Decal_BumpMap ("Has BumpMap", int) = 0
_BumpMap("Bump Map", 2D) = "bump" {}
_EdgeWearStrength("Edge Wear Strength", Range(0,500)) = 100
_EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0.1
[Header(Specularity)]
[Toggle(DECAL_SPECMAP)] _Decal_SpecMap ("Has SpecMap", int) = 0
_SpecMap ("Specular Map)", 2D) = "black" {}
_SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1)
_Shininess ("Shininess", Range (0.03, 10)) = 0.3
[Header(Emissive)]
[Toggle(DECAL_EMISSIVE)] _Decal_Emissive ("Has Emissive", int) = 0
_Emissive("_Emissive", 2D) = "black" {}
_EmissiveColor("_EmissiveColor", Color) = (0,0,0,1)
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_DecalOpacity("Opacity", Range(0,1) ) = 1
_Background("Background Color", Color) = (0.9,0.9,0.9,0.7)
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", int) = 2
[Toggle] _ZWrite ("ZWrite", Float) = 1.0
[Toggle(DECAL_PREVIEW)] _Preview ("Preview", int) = 0
[Header(Effects)]
[PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1
[PerRendererData]_Color("_Color", Color) = (1,1,1,1)
[PerRendererData]_RimFalloff("_RimFalloff", Range(0.01,5) ) = 0.1
[PerRendererData]_RimColor("_RimColor", Color) = (0,0,0,0)
[PerRendererData]_UnderwaterFogFactor ("Underwater Fog Factor", Range(0,1)) = 0
}
SubShader
{
Tags { "Queue" = "Geometry+100" "IgnoreProjector" = "true" "DisableBatching" = "true"}
Cull [_Cull]
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
ZWrite [_ZWrite]
ZTest LEqual
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap
#pragma skip_variants SHADOWS_DEPTH SHADOWS_CUBE SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING POINT_COOKIE
#pragma multi_compile_local __ DECAL_PREVIEW
#pragma multi_compile_local __ DECAL_BASE_NORMAL DECAL_BUMPMAP
#pragma multi_compile_local __ DECAL_SPECMAP
#pragma multi_compile_local __ DECAL_EMISSIVE
#pragma multi_compile_local __ DECAL_SDF_ALPHA
#include "UnityCG.cginc"
#include "DecalsCommon.cginc"
#include "DecalsSurface.cginc"
#include "StandardDecal.cginc"
ENDCG
}
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
ZWrite Off
ZTest LEqual
Blend One One
Offset -1, -1
CGPROGRAM
#pragma vertex vert_forward
#pragma fragment frag_forward
#pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap
#pragma skip_variants SHADOWS_DEPTH SHADOWS_CUBE SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING POINT_COOKIE
#pragma multi_compile_local __ DECAL_PREVIEW
#pragma multi_compile_local __ DECAL_BASE_NORMAL DECAL_BUMPMAP
#pragma multi_compile_local __ DECAL_SPECMAP
#pragma multi_compile_local __ DECAL_EMISSIVE
#pragma multi_compile_local __ DECAL_SDF_ALPHA
#include "UnityCG.cginc"
#include "DecalsCommon.cginc"
#include "DecalsSurface.cginc"
#include "StandardDecal.cginc"
ENDCG
}
// shadow casting support
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

View File

@ -64,7 +64,7 @@ Localization
// Semiotic Decals // Semiotic Decals
#LOC_ConformalDecals_semiotic-title = CDL-2 Semiotic Standard Decal #LOC_ConformalDecals_semiotic-title = CDL-2 Semiotic Standard Decal
#LOC_ConformalDecals_semiotic-description = After several unfortunate mishaps with confusing signage on spacecraft, The Peel-N-Stik™ Corporation teamed up with Kerland-Mutani to unveil the Semiotic Standard for Kerbal Vessels, a set of standardized icons for use on ships and stations. #LOC_ConformalDecals_semiotic-description = After several unfortunate mishaps with confusing signage on spacecraft, The Peel-N-Stik™ Corporation teamed up with Kerland-Mutani to unveil the Semiotic Standard for Kerbal Vessels, a set of standardized icons for use on ships and stations. (Based on the work of Ron Cobb)
#LOC_ConformalDecals_semiotic-tags = conformal decal sticker semiotic standard for kerbal vessels Ron Cobb Alien #LOC_ConformalDecals_semiotic-tags = conformal decal sticker semiotic standard for kerbal vessels Ron Cobb Alien
#LOC_ConformalDecals_semiotic-variant-00 = Hazard #LOC_ConformalDecals_semiotic-variant-00 = Hazard
#LOC_ConformalDecals_semiotic-variant-01 = Blank #LOC_ConformalDecals_semiotic-variant-01 = Blank
@ -98,5 +98,47 @@ Localization
#LOC_ConformalDecals_semiotic-variant-29 = Radiation Hazard #LOC_ConformalDecals_semiotic-variant-29 = Radiation Hazard
#LOC_ConformalDecals_semiotic-variant-30 = Radiation Bunker #LOC_ConformalDecals_semiotic-variant-30 = Radiation Bunker
#LOC_ConformalDecals_semiotic-variant-31 = Exhaust #LOC_ConformalDecals_semiotic-variant-31 = Exhaust
// Munar Decals
#LOC_ConformalDecals_munar-title = CDL-3 Surface Base Decal
#LOC_ConformalDecals_munar-description = Munar Industries Ltd. saw the wild success of the CDL-2 decal, and wanted to develop a decal set for their own line of Heluim mining bases. These decals are more explicit than the Semiotic Standard and aimed at the hazards that come with more advanced techonologies. (Based on the work of Gavin Rothery)
#LOC_ConformalDecals_munar-tag = conformal decal sticker Moon munar lunar industries Gavin Rothery Sarang
#LOC_ConformalDecals_munar-variant-severe-danger = Severe Danger
#LOC_ConformalDecals_munar-variant-danger = Danger
#LOC_ConformalDecals_munar-variant-hazard = Hazard
#LOC_ConformalDecals_munar-variant-warning = Warning
#LOC_ConformalDecals_munar-variant-bulkhead = Bulkhead
#LOC_ConformalDecals_munar-variant-hatch = Hatch
#LOC_ConformalDecals_munar-variant-pressure-hatch = Hatch (Pressurized)
#LOC_ConformalDecals_munar-variant-door = Doorway
#LOC_ConformalDecals_munar-variant-door-danger = Do Not Obstruct
#LOC_ConformalDecals_munar-variant-airlock-interior = Airlock (Interior)
#LOC_ConformalDecals_munar-variant-airlock-exterior = Airlock (Exterior)
#LOC_ConformalDecals_munar-variant-check-seals = Check All Seals
#LOC_ConformalDecals_munar-variant-pressure-seal = Pressure Seal
#LOC_ConformalDecals_munar-variant-vacuum = Danger Vacuum
#LOC_ConformalDecals_munar-variant-gas-mask = Breathing Apparatus Required
#LOC_ConformalDecals_munar-variant-oxygen-rich = Oxygen Rich Environment
#LOC_ConformalDecals_munar-variant-robotic-work = Heavy Robotic Work Ahead
#LOC_ConformalDecals_munar-variant-explosion = Explosion Hazard
#LOC_ConformalDecals_munar-variant-radiation = Radiation Hazard
#LOC_ConformalDecals_munar-variant-antimatter = Annihilation Hazard
#LOC_ConformalDecals_munar-variant-high-voltage = High Voltage
#LOC_ConformalDecals_munar-variant-extreme-voltage = Extreme Voltage
#LOC_ConformalDecals_munar-variant-explosive-bolts = Explosive Bolts
#LOC_ConformalDecals_munar-variant-autonomous-device = Autonomous Device
#LOC_ConformalDecals_munar-variant-gravity-adjust = Gravity Adjust
#LOC_ConformalDecals_munar-variant-electromagnetic = Strong EM Field
#LOC_ConformalDecals_munar-variant-mind-step = Mind Step
#LOC_ConformalDecals_munar-variant-class-1 = Class 1 Hazard: Flammable Liquid
#LOC_ConformalDecals_munar-variant-class-2 = Class 2 Hazard: Flammable Solid
#LOC_ConformalDecals_munar-variant-class-3 = Class 3 Hazard: Magnetic Field
#LOC_ConformalDecals_munar-variant-class-4 = Class 4 Hazard: Electric Field
#LOC_ConformalDecals_munar-variant-class-5 = Class 5 Hazard: Pressurized Fuel
#LOC_ConformalDecals_munar-variant-class-6 = Class 6 Hazard: Pressurized Coolant
#LOC_ConformalDecals_munar-variant-class-7 = Class 7 Hazard: Cryogenic Liquid
#LOC_ConformalDecals_munar-variant-class-8 = Class 8 Hazard: Radioactive
#LOC_ConformalDecals_munar-variant-class-9 = Class 9 Hazard: Ionized Gas
#LOC_ConformalDecals_munar-variant-class-10 = Class 10 Hazard: Antimatter
} }
} }

View File

@ -65,7 +65,12 @@ PART
scaleRange = 0.1, 4 scaleRange = 0.1, 4
scaleMode = AVERAGE scaleMode = AVERAGE
shader = ConformalDecals/Paint/Specular shader = ConformalDecals/Decal/Standard
KEYWORD {
name = DECAL_SDF_ALPHA
value = false
}
TEXTURE { TEXTURE {
name = _Decal name = _Decal
@ -108,7 +113,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 128, 2, 128, 112 tile = 128, 2, 128, 112
} }
} }
@ -123,7 +128,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 256, 2, 128, 112 tile = 256, 2, 128, 112
} }
} }
@ -138,7 +143,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 384, 2, 128, 112 tile = 384, 2, 128, 112
} }
} }
@ -153,7 +158,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 690, 4, 330, 118 tile = 690, 4, 330, 118
} }
} }
@ -168,7 +173,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 898, 4, 122, 118 tile = 898, 4, 122, 118
} }
} }
@ -183,7 +188,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 6, 126, 196, 132 tile = 6, 126, 196, 132
} }
} }
@ -198,7 +203,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 210, 122, 94, 94 tile = 210, 122, 94, 94
} }
} }
@ -213,7 +218,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 8, 262, 192, 70 tile = 8, 262, 192, 70
} }
} }
@ -242,7 +247,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 508, 332, 262, 112 tile = 508, 332, 262, 112
} }
} }
@ -257,7 +262,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 202, 218, 164, 114 tile = 202, 218, 164, 114
} }
} }
@ -272,7 +277,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 366, 218, 164, 114 tile = 366, 218, 164, 114
} }
} }
@ -347,7 +352,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 326, 426, 164, 20 tile = 326, 426, 164, 20
} }
} }
@ -363,7 +368,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 776, 388, 48, 48 tile = 776, 388, 48, 48
} }
} }
@ -378,7 +383,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 328, 456, 48, 48 tile = 328, 456, 48, 48
} }
} }
@ -393,7 +398,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 376, 456, 48, 48 tile = 376, 456, 48, 48
} }
} }
@ -408,7 +413,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 424, 456, 48, 48 tile = 424, 456, 48, 48
} }
} }
@ -423,7 +428,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 472, 456, 48, 48 tile = 472, 456, 48, 48
} }
} }
@ -438,7 +443,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 520, 456, 48, 48 tile = 520, 456, 48, 48
} }
} }
@ -453,7 +458,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 568, 456, 48, 48 tile = 568, 456, 48, 48
} }
} }
@ -468,7 +473,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 614, 456, 48, 48 tile = 614, 456, 48, 48
} }
} }
@ -483,7 +488,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 662, 456, 48, 48 tile = 662, 456, 48, 48
} }
} }
@ -498,7 +503,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 710, 456, 48, 48 tile = 710, 456, 48, 48
} }
} }
@ -513,7 +518,7 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/SpecularSDF KEYWORD { name = DECAL_SDF_ALPHA }
tile = 758, 456, 48, 48 tile = 758, 456, 48, 48
} }
} }
@ -528,7 +533,10 @@ PART
MODULE { MODULE {
IDENTIFIER { name = ModuleConformalDecal } IDENTIFIER { name = ModuleConformalDecal }
DATA { DATA {
shader = ConformalDecals/Paint/Diffuse TEXTURE {
name = _SpecMap
remove = true
}
tile = 826, 360, 196, 150 tile = 826, 360, 196, 150
opacity = 1 opacity = 1

Binary file not shown.

View File

@ -0,0 +1,537 @@
PART
{
name = conformaldecals-munar
module = Part
author = Andrew Cassidy
MODEL
{
model = ConformalDecals/Assets/decal-blank
scale = 1.0, 1.0, 1.0
}
rescaleFactor = 1
// Attachment
attachRules = 1,1,0,0,1
node_attach = 0.0, 0.0, 0.05, 0.0, 0.0, -1.0
// Tech
TechRequired = start
// Info
cost = 75
category = Structural
// CDL-3 Surface Base Decal
title = #LOC_ConformalDecals_munar-title
// Peel-N-Stik Adhesive Decals
manufacturer = #LOC_ConformalDecals_agent-peel-n-stick_title
// Munar Industries Ltd. saw the wild success of the CDL-2 decal, and wanted to develop a decal set for their own line of Heluim mining bases. These decals are more explicit than the Semiotic Standard and aimed at the hazards that come with more advanced techonologies. (Based on the work of Gavin Rothery)
description = #LOC_ConformalDecals_munar-description
// conformal decal sticker Moon munar lunar industries Gavin Rothery Sarang
tags = #LOC_ConformalDecals_munar-tags
bulkheadProfiles = srf
// Parameters
mass = 0.0005
dragModel = NONE
angularDrag = 0.0
crashTolerance = 10
maxTemp = 2000
breakingForce = 350
breakingTorque = 150
physicalSignificance = NONE
MODULE
{
name = ModuleConformalDecal
useBaseNormal = true
tile = -1, -1, 0, 0
tileSize = 96, 96
tileIndex = 0
defaultScale = 0.1
defaultDepth = 0.1
defaultOpacity = 0.8
defaultCutoff = 0
scaleRange = 0.05, 0.5
scaleMode = MINIMUM
cutoffAdjustable = false
shader = ConformalDecals/Decal/Standard
TEXTURE {
name = _Decal
textureUrl = ConformalDecals/Parts/Munar/Munar-Atlas
isMain = true
autoTile = true
}
TEXTURE {
name = _SpecMap
textureUrl = ConformalDecals/Assets/Decal-Spec
autoScale = true
}
}
MODULE {
name = ModuleB9PartSwitch
SUBTYPE {
name = severe-danger
title = #LOC_ConformalDecals_munar-variant-severe-danger
primaryColor = #2B250D
secondaryColor = #F78000
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 0 }
}
}
SUBTYPE {
name = danger
title = #LOC_ConformalDecals_munar-variant-danger
primaryColor = #93927E
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 2 }
}
}
SUBTYPE {
name = hazard
title = #LOC_ConformalDecals_munar-variant-hazard
primaryColor = #2B250D
secondaryColor = #CC1F01
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 6 }
}
}
SUBTYPE {
name = warning
title = #LOC_ConformalDecals_munar-variant-warning
primaryColor = #2B250D
secondaryColor = #93927E
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 5 }
}
}
SUBTYPE {
name = bulkhead
title = #LOC_ConformalDecals_munar-variant-bulkhead
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 7 }
}
}
SUBTYPE {
name = hatch
title = #LOC_ConformalDecals_munar-variant-hatch
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 3 }
}
}
SUBTYPE {
name = pressure-hatch
title = #LOC_ConformalDecals_munar-variant-pressure-hatch
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 4 }
}
}
SUBTYPE {
name = door
title = #LOC_ConformalDecals_munar-variant-door
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 5 }
}
}
SUBTYPE {
name = door-danger
title = #LOC_ConformalDecals_munar-variant-door-danger
primaryColor = #2B250D
secondaryColor = #CC1F01
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA {
tile = 960, 0, 64, 96
scaleMode = HEIGHT
}
}
}
SUBTYPE {
name = airlock-interior
title = #LOC_ConformalDecals_munar-variant-airlock-interior
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 866, 96, 142, 96 }
}
}
SUBTYPE {
name = airlock-exterior
title = #LOC_ConformalDecals_munar-variant-airlock-exterior
primaryColor = #CC1F01
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 768, 96, 142, 96 }
}
}
SUBTYPE {
name = check-seals
title = #LOC_ConformalDecals_munar-variant-check-seals
primaryColor = White
secondaryColor = #93927E
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 8 }
}
}
SUBTYPE {
name = pressure-seal
title = #LOC_ConformalDecals_munar-variant-pressure-seal
primaryColor = White
secondaryColor = #93927E
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 9 }
}
}
SUBTYPE {
name = vacuum
title = #LOC_ConformalDecals_munar-variant-vacuum
primaryColor = #93927E
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 17 }
}
}
SUBTYPE {
name = gas-mask
title = #LOC_ConformalDecals_munar-variant-gas-mask
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 96, 320, 96, 116 }
}
}
SUBTYPE {
name = oxygen-rich
title = #LOC_ConformalDecals_munar-variant-oxygen-rich
primaryColor = #CC1F01
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 288, 416, 96, 96 }
}
}
SUBTYPE {
name = robotic-work
title = #LOC_ConformalDecals_munar-variant-robotic-work
primaryColor = #F78000
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 10 }
}
}
SUBTYPE {
name = explosion
title = #LOC_ConformalDecals_munar-variant-explosion
primaryColor = #F78000
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 0, 320, 96, 116 }
}
}
SUBTYPE {
name = radiation
title = #LOC_ConformalDecals_munar-variant-radiation
primaryColor = #F78000
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 1 }
}
}
SUBTYPE {
name = antimatter
title = #LOC_ConformalDecals_munar-variant-antimatter
primaryColor = #F78000
secondaryColor = #2B250D
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 11 }
}
}
SUBTYPE {
name = high-voltage
title = #LOC_ConformalDecals_munar-variant-high-voltage
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 13 }
}
}
SUBTYPE {
name = extreme-voltage
title = #LOC_ConformalDecals_munar-variant-extreme-voltage
primaryColor = #2B250D
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 14 }
}
}
SUBTYPE {
name = explosive-bolts
title = #LOC_ConformalDecals_munar-variant-explosive-bolts
primaryColor = #93927E
secondaryColor = #CC1F01
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 15 }
}
}
SUBTYPE {
name = autonomous-device
title = #LOC_ConformalDecals_munar-variant-autonomous-device
primaryColor = #2B250D
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tileIndex = 16 }
}
}
SUBTYPE {
name = gravity-adjust
title = #LOC_ConformalDecals_munar-variant-gravity-adjust
primaryColor = White
secondaryColor = #CC1F01
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 288, 320, 96, 96 }
}
}
SUBTYPE {
name = electromagnetic
title = #LOC_ConformalDecals_munar-variant-electromagnetic
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA {
tile = 967, 195, 50, 90
scaleMode = HEIGHT
}
}
}
SUBTYPE {
name = mind-step
title = #LOC_ConformalDecals_munar-variant-mind-step
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 1, 447, 230, 64 }
}
}
SUBTYPE {
name = class-1
title = #LOC_ConformalDecals_munar-variant-class-1
primaryColor = #CC1F01
secondaryColor = #93927E
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 0, 192, 96, 128 }
}
}
SUBTYPE {
name = class-2
title = #LOC_ConformalDecals_munar-variant-class-2
primaryColor = #93927E
secondaryColor = #CC1F01
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 96, 192, 96, 128 }
}
}
SUBTYPE {
name = class-3
title = #LOC_ConformalDecals_munar-variant-class-3
primaryColor = #93927E
secondaryColor = #93927E
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 192, 192, 96, 128 }
}
}
SUBTYPE {
name = class-4
title = #LOC_ConformalDecals_munar-variant-class-4
primaryColor = #93927E
secondaryColor = #93927E
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 288, 192, 96, 128 }
}
}
SUBTYPE {
name = class-5
title = #LOC_ConformalDecals_munar-variant-class-5
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 384, 192, 96, 128 }
}
}
SUBTYPE {
name = class-6
title = #LOC_ConformalDecals_munar-variant-class-6
primaryColor = #93927E
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 480, 192, 96, 128 }
}
}
SUBTYPE {
name = class-7
title = #LOC_ConformalDecals_munar-variant-class-7
primaryColor = #F78000
secondaryColor = #93927E
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 576, 192, 96, 128 }
}
}
SUBTYPE {
name = class-8
title = #LOC_ConformalDecals_munar-variant-class-8
primaryColor = #93927E
secondaryColor = #F78000
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 672, 192, 96, 128 }
}
}
SUBTYPE {
name = class-9
title = #LOC_ConformalDecals_munar-variant-class-9
primaryColor = #93927E
secondaryColor = #F78000
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 768, 192, 96, 128 }
}
}
SUBTYPE {
name = class-10
title = #LOC_ConformalDecals_munar-variant-class-10
primaryColor = #F78000
secondaryColor = White
MODULE {
IDENTIFIER { name = ModuleConformalDecal }
DATA { tile = 864, 192, 96, 128 }
}
}
}
}

View File

@ -21,13 +21,13 @@ PART
cost = 75 cost = 75
category = Structural category = Structural
// CDL-1 Semiotic Standard Decal // CDL-2 Semiotic Standard Decal
title = #LOC_ConformalDecals_semiotic-title title = #LOC_ConformalDecals_semiotic-title
// Peel-N-Stik Adhesive Decals // Peel-N-Stik Adhesive Decals
manufacturer = #LOC_ConformalDecals_agent-peel-n-stick_title manufacturer = #LOC_ConformalDecals_agent-peel-n-stick_title
// After several unfortunate mishaps with confusing signage on spacecraft, The Peel-N-Stik™ Corporation teamed up with Kerland-Mutani to unveil the Semiotic Standard for Kerbal Vessels, a set of standardized icons for use on ships and stations. // After several unfortunate mishaps with confusing signage on spacecraft, The Peel-N-Stik™ Corporation teamed up with Kerland-Mutani to unveil the Semiotic Standard for Kerbal Vessels, a set of standardized icons for use on ships and stations. (Based on the work of Ron Cobb)
description = #LOC_ConformalDecals_semiotic-description description = #LOC_ConformalDecals_semiotic-description
// conformal decal sticker semiotic standard for kerbal vessels Ron Cobb Alien // conformal decal sticker semiotic standard for kerbal vessels Ron Cobb Alien
@ -62,7 +62,7 @@ PART
scaleRange = 0.05, 0.5 scaleRange = 0.05, 0.5
cutoffAdjustable = false cutoffAdjustable = false
shader = ConformalDecals/Paint/Specular shader = ConformalDecals/Decal/Standard
TEXTURE { TEXTURE {
name = _Decal name = _Decal

View File

@ -53,5 +53,13 @@ PART
defaultDepth = 0.2 defaultDepth = 0.2
defaultCutoff = 0 defaultCutoff = 0
shader = ConformalDecals/Decal/Standard
TEXTURE {
name = _SpecMap
textureUrl = ConformalDecals/Assets/Decal-Spec
autoScale = true
}
} }
} }

View File

@ -1,4 +1,7 @@
CONFORMALDECALS { CONFORMALDECALS {
decalLayer = 31
selectableInFlight = false
SHADERBLACKLIST { SHADERBLACKLIST {
shader = DepthMask shader = DepthMask
shader = KSP/Alpha/Cutoff shader = KSP/Alpha/Cutoff

View File

@ -5,8 +5,8 @@
"VERSION": "VERSION":
{ {
"MAJOR":0, "MAJOR":0,
"MINOR":1, "MINOR":2,
"PATCH":1, "PATCH":0,
"BUILD":0 "BUILD":0
}, },
"KSP_VERSION": "KSP_VERSION":

View File

@ -1,4 +1,4 @@
# Conformal Decals v0.1.1 # Conformal Decals v0.2.0
[![Build Status](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals.svg?branch=release)](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals) [![Art: CC BY-SA 4.0](https://img.shields.io/badge/Art%20License-CC%20BY--SA%204.0-orange.svg)](https://creativecommons.org/licenses/by-sa/4.0/) [![Code: GPL v3](https://img.shields.io/badge/Code%20License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Build Status](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals.svg?branch=release)](https://travis-ci.org/drewcassidy/KSP-Conformal-Decals) [![Art: CC BY-SA 4.0](https://img.shields.io/badge/Art%20License-CC%20BY--SA%204.0-orange.svg)](https://creativecommons.org/licenses/by-sa/4.0/) [![Code: GPL v3](https://img.shields.io/badge/Code%20License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
![Screenshot](http://pileof.rocks/KSP/images/ConformalDecalsHeader.png) ![Screenshot](http://pileof.rocks/KSP/images/ConformalDecalsHeader.png)
@ -20,6 +20,7 @@ Optional:
- Art and Plugin code: Andrew Cassidy (Cineboxandrew) - Art and Plugin code: Andrew Cassidy (Cineboxandrew)
- Semiotic decal pack based on the work of Ron Cobb - Semiotic decal pack based on the work of Ron Cobb
- Munar decal pack based on the work of Gavin Rothery
## Installation ## Installation

View File

@ -60,23 +60,25 @@
<Compile Include="DecalConfig.cs" /> <Compile Include="DecalConfig.cs" />
<Compile Include="DecalIconFixer.cs" /> <Compile Include="DecalIconFixer.cs" />
<Compile Include="DecalPropertyIDs.cs" /> <Compile Include="DecalPropertyIDs.cs" />
<Compile Include="MaterialModifiers\MaterialColorProperty.cs" /> <Compile Include="MaterialProperties\MaterialColorProperty.cs" />
<Compile Include="MaterialModifiers\MaterialFloatProperty.cs" /> <Compile Include="MaterialProperties\MaterialFloatProperty.cs" />
<Compile Include="MaterialModifiers\MaterialProperty.cs" /> <Compile Include="MaterialProperties\MaterialKeywordProperty.cs" />
<Compile Include="MaterialModifiers\MaterialPropertyCollection.cs" /> <Compile Include="MaterialProperties\MaterialProperty.cs" />
<Compile Include="MaterialModifiers\MaterialTextureProperty.cs" /> <Compile Include="MaterialProperties\MaterialPropertyCollection.cs" />
<Compile Include="MaterialProperties\MaterialTextureProperty.cs" />
<Compile Include="ModuleConformalFlag.cs" /> <Compile Include="ModuleConformalFlag.cs" />
<Compile Include="ModuleConformalText.cs" /> <Compile Include="ModuleConformalText.cs" />
<Compile Include="ProjectionTarget.cs" /> <Compile Include="ProjectionTarget.cs" />
<Compile Include="ModuleConformalDecal.cs" /> <Compile Include="ModuleConformalDecal.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Text\DecalFont.cs" />
<Compile Include="Text\FontLoader.cs" /> <Compile Include="Text\FontLoader.cs" />
<Compile Include="Text\TextRenderer.cs" /> <Compile Include="Text\TextRenderer.cs" />
<Compile Include="Text\TextSettings.cs" /> <Compile Include="Text\TextSettings.cs" />
<Compile Include="Test\TestLayers.cs" />
<Compile Include="Util\Logging.cs" /> <Compile Include="Util\Logging.cs" />
<Compile Include="Util\OrientedBounds.cs" /> <Compile Include="Util\OrientedBounds.cs" />
<Compile Include="Util\TextureUtils.cs" /> <Compile Include="Util\TextureUtils.cs" />
<Compile Include="Util\ParseUtil.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View File

@ -1,14 +1,48 @@
using System.Collections.Generic; using System.Collections.Generic;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace ConformalDecals { namespace ConformalDecals {
public static class DecalConfig { public static class DecalConfig {
private static Texture2D _blankNormal; private static Texture2D _blankNormal;
private static List<string> _shaderBlacklist; private static List<string> _shaderBlacklist;
private static int _decalLayer = 31;
private static bool _selectableInFlight;
private struct LegacyShaderEntry {
public string name;
public string[] keywords;
}
private static readonly Dictionary<string, LegacyShaderEntry> LegacyShaderPairs = new Dictionary<string, LegacyShaderEntry>() {
["ConformalDecals/Feature/Bumped"] = new LegacyShaderEntry() {
name = "ConformalDecals/Decal/Standard",
keywords = new[] {"DECAL_BUMPMAP"}
},
["ConformalDecals/Paint/Diffuse"] = new LegacyShaderEntry() {
name = "ConformalDecals/Decal/Standard",
keywords = new string[] { }
},
["ConformalDecals/Paint/Specular"] = new LegacyShaderEntry() {
name = "ConformalDecals/Decal/Standard",
keywords = new[] {"DECAL_SPECMAP"}
},
["ConformalDecals/Paint/DiffuseSDF"] = new LegacyShaderEntry() {
name = "ConformalDecals/Decal/Standard",
keywords = new[] {"DECAL_SDF_ALPHA"}
},
["ConformalDecals/Paint/SpecularSDF"] = new LegacyShaderEntry() {
name = "ConformalDecals/Decal/Standard",
keywords = new[] {"DECAL_SDF_ALPHA", "DECAL_SPECMAP"}
},
};
public static Texture2D BlankNormal => _blankNormal; public static Texture2D BlankNormal => _blankNormal;
public static int DecalLayer => _decalLayer;
public static bool SelectableInFlight => _selectableInFlight;
public static bool IsBlacklisted(Shader shader) { public static bool IsBlacklisted(Shader shader) {
return IsBlacklisted(shader.name); return IsBlacklisted(shader.name);
} }
@ -17,11 +51,26 @@ namespace ConformalDecals {
return _shaderBlacklist.Contains(shaderName); return _shaderBlacklist.Contains(shaderName);
} }
public static bool IsLegacy(string shaderName, out string newShader, out string[] keywords) {
if (LegacyShaderPairs.TryGetValue(shaderName, out var entry)) {
newShader = entry.name;
keywords = entry.keywords;
return true;
}
newShader = null;
keywords = null;
return false;
}
private static void ParseConfig(ConfigNode node) { private static void ParseConfig(ConfigNode node) {
foreach (var blacklist in node.GetNodes("SHADERBLACKLIST")) { foreach (var blacklist in node.GetNodes("SHADERBLACKLIST")) {
foreach (var shaderName in blacklist.GetValuesList("shader")) { foreach (var shaderName in blacklist.GetValuesList("shader")) {
_shaderBlacklist.Add(shaderName); _shaderBlacklist.Add(shaderName);
} }
ParseUtil.ParseIntIndirect(ref _decalLayer, node, "decalLayer");
ParseUtil.ParseBoolIndirect(ref _selectableInFlight, node, "selectableInFlight");
} }
} }
@ -30,7 +79,7 @@ namespace ConformalDecals {
var width = 2; var width = 2;
var height = 2; var height = 2;
var color = new Color32(255, 128, 128, 128); var color = new Color32(255, 128, 128, 128);
var colors = new Color32[] { color, color, color, color }; var colors = new[] {color, color, color, color};
var tex = new Texture2D(width, height, TextureFormat.RGBA32, false); var tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
for (var x = 0; x <= width; x++) { for (var x = 0; x <= width; x++) {
@ -38,11 +87,13 @@ namespace ConformalDecals {
tex.SetPixels32(colors); tex.SetPixels32(colors);
} }
} }
tex.Apply(); tex.Apply();
return tex; return tex;
} }
// ReSharper disable once UnusedMember.Global
public static void ModuleManagerPostLoad() { public static void ModuleManagerPostLoad() {
_shaderBlacklist = new List<string>(); _shaderBlacklist = new List<string>();
@ -55,6 +106,14 @@ namespace ConformalDecals {
} }
} }
// setup physics for decals, ignore collision with everything
Physics.IgnoreLayerCollision(_decalLayer, 1, true); // default
Physics.IgnoreLayerCollision(_decalLayer, 17, true); // EVA
Physics.IgnoreLayerCollision(_decalLayer, 19, true); // PhysicalObjects
Physics.IgnoreLayerCollision(_decalLayer, 23, true); // AeroFXIgnore
Physics.IgnoreLayerCollision(_decalLayer, 26, true); // wheelCollidersIgnore
Physics.IgnoreLayerCollision(_decalLayer, 27, true); // wheelColliders
_blankNormal = MakeBlankNormal(); _blankNormal = MakeBlankNormal();
} }
} }

View File

@ -1,4 +1,5 @@
using UnityEngine; using UnityEngine;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace ConformalDecals { namespace ConformalDecals {
@ -12,5 +13,6 @@ namespace ConformalDecals {
public static readonly int _DecalTangent = Shader.PropertyToID("_DecalTangent"); public static readonly int _DecalTangent = Shader.PropertyToID("_DecalTangent");
public static readonly int _EdgeWearStrength = Shader.PropertyToID("_EdgeWearStrength"); public static readonly int _EdgeWearStrength = Shader.PropertyToID("_EdgeWearStrength");
public static readonly int _ProjectionMatrix = Shader.PropertyToID("_ProjectionMatrix"); public static readonly int _ProjectionMatrix = Shader.PropertyToID("_ProjectionMatrix");
public static readonly int _ZWrite = Shader.PropertyToID("_ZWrite");
} }
} }

View File

@ -1,79 +0,0 @@
using System;
using UnityEngine;
namespace ConformalDecals.MaterialModifiers {
public abstract class MaterialProperty : ScriptableObject {
public string PropertyName {
get => _propertyName;
set {
_propertyName = value;
_propertyID = Shader.PropertyToID(_propertyName);
}
}
[SerializeField] protected int _propertyID;
[SerializeField] protected string _propertyName;
public virtual void ParseNode(ConfigNode node) {
if (node == null) throw new ArgumentNullException(nameof(node));
PropertyName = node.GetValue("name");
Debug.Log($"Parsing material property {_propertyName}");
}
public abstract void Modify(Material material);
private delegate bool TryParseDelegate<T>(string valueString, out T value);
protected bool ParsePropertyBool(ConfigNode node, string valueName, bool isOptional = false, bool defaultValue = false) {
return ParsePropertyValue(node, valueName, bool.TryParse, isOptional, defaultValue);
}
protected float ParsePropertyFloat(ConfigNode node, string valueName, bool isOptional = false, float defaultValue = 0.0f) {
return ParsePropertyValue(node, valueName, float.TryParse, isOptional, defaultValue);
}
protected int ParsePropertyInt(ConfigNode node, string valueName, bool isOptional = false, int defaultValue = 0) {
return ParsePropertyValue(node, valueName, int.TryParse, isOptional, defaultValue);
}
protected Color ParsePropertyColor(ConfigNode node, string valueName, bool isOptional = false, Color defaultValue = default) {
return ParsePropertyValue(node, valueName, ParseExtensions.TryParseColor, isOptional, defaultValue);
}
protected Rect ParsePropertyRect(ConfigNode node, string valueName, bool isOptional = false, Rect defaultValue = default) {
return ParsePropertyValue(node, valueName, ParseExtensions.TryParseRect, isOptional, defaultValue);
}
protected Vector2 ParsePropertyVector2(ConfigNode node, string valueName, bool isOptional = false, Vector2 defaultValue = default) {
return ParsePropertyValue(node, valueName, ParseExtensions.TryParseVector2, isOptional, defaultValue);
}
private T ParsePropertyValue<T>(ConfigNode node, string valueName, TryParseDelegate<T> tryParse, bool isOptional = false, T defaultValue = default) {
string valueString = node.GetValue(valueName);
if (isOptional) {
if (string.IsNullOrEmpty(valueString)) return defaultValue;
}
else {
if (valueString == null)
throw new FormatException($"Missing {typeof(T)} value for {valueName} in property '{PropertyName}'");
if (valueString == string.Empty)
throw new FormatException($"Empty {typeof(T)} value for {valueName} in property '{PropertyName}'");
}
if (tryParse(valueString, out var value)) {
return value;
}
if (isOptional) {
return defaultValue;
}
else {
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} in property '{PropertyName}' : '{valueString}");
}
}
}
}

View File

@ -1,18 +1,19 @@
using System; using System;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialColorProperty : MaterialProperty { public class MaterialColorProperty : MaterialProperty {
[SerializeField] public Color color; [SerializeField] public Color32 color = new Color32(0, 0, 0, byte.MaxValue);
public override void ParseNode(ConfigNode node) { public override void ParseNode(ConfigNode node) {
base.ParseNode(node); base.ParseNode(node);
color = ParsePropertyColor(node, "color", true, color); ParseUtil.ParseColor32Indirect(ref color, node, "color");
} }
public override void Modify(Material material) { public override void Modify(Material material) {
if (material == null) throw new ArgumentNullException("material cannot be null"); if (material == null) throw new ArgumentNullException(nameof(material));
material.SetColor(_propertyID, color); material.SetColor(_propertyID, color);
} }

View File

@ -1,18 +1,19 @@
using System; using System;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialFloatProperty : MaterialProperty { public class MaterialFloatProperty : MaterialProperty {
[SerializeField] public float value; [SerializeField] public float value;
public override void ParseNode(ConfigNode node) { public override void ParseNode(ConfigNode node) {
base.ParseNode(node); base.ParseNode(node);
value = ParsePropertyFloat(node, "value", true, value); ParseUtil.ParseFloatIndirect(ref value, node, "value");
} }
public override void Modify(Material material) { public override void Modify(Material material) {
if (material == null) throw new ArgumentNullException("material cannot be null"); if (material == null) throw new ArgumentNullException(nameof(material));
material.SetFloat(_propertyID, value); material.SetFloat(_propertyID, value);
} }

View File

@ -0,0 +1,19 @@
using ConformalDecals.Util;
using UnityEngine;
namespace ConformalDecals.MaterialProperties {
public class MaterialKeywordProperty : MaterialProperty {
[SerializeField] public bool value = true;
public override void ParseNode(ConfigNode node) {
base.ParseNode(node);
ParseUtil.ParseBoolIndirect(ref value, node, "value");
}
public override void Modify(Material material) {
if (value) material.EnableKeyword(_propertyName);
else material.DisableKeyword(_propertyName);
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using UnityEngine;
namespace ConformalDecals.MaterialProperties {
public abstract class MaterialProperty : ScriptableObject {
public string PropertyName {
get => _propertyName;
set {
_propertyName = value;
_propertyID = Shader.PropertyToID(_propertyName);
}
}
[SerializeField] protected int _propertyID;
[SerializeField] protected string _propertyName;
public abstract void Modify(Material material);
public virtual void ParseNode(ConfigNode node) {
if (node == null) throw new ArgumentNullException(nameof(node));
PropertyName = node.GetValue("name");
}
public virtual void Remove(Material material) { }
}
}

View File

@ -1,11 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using ConformalDecals.Util;
using UniLinq; using UniLinq;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialPropertyCollection : ScriptableObject, ISerializationCallbackReceiver { public class MaterialPropertyCollection : ScriptableObject, ISerializationCallbackReceiver {
public int RenderQueue { public int RenderQueue {
get => _renderQueue; get => _renderQueue;
@ -29,12 +30,20 @@ namespace ConformalDecals.MaterialModifiers {
public Shader DecalShader => _shader; public Shader DecalShader => _shader;
public IEnumerable<Material> Materials {
get {
yield return PreviewMaterial;
yield return DecalMaterial;
}
}
public Material DecalMaterial { public Material DecalMaterial {
get { get {
if (_decalMaterial == null) { if (_decalMaterial == null) {
_decalMaterial = new Material(_shader); _decalMaterial = new Material(_shader);
_decalMaterial.SetInt(DecalPropertyIDs._Cull, (int) CullMode.Off); _decalMaterial.SetInt(DecalPropertyIDs._Cull, (int) CullMode.Off);
_decalMaterial.SetInt(DecalPropertyIDs._ZWrite, 0);
_decalMaterial.renderQueue = RenderQueue; _decalMaterial.renderQueue = RenderQueue;
} }
@ -49,6 +58,7 @@ namespace ConformalDecals.MaterialModifiers {
_previewMaterial.EnableKeyword("DECAL_PREVIEW"); _previewMaterial.EnableKeyword("DECAL_PREVIEW");
_previewMaterial.SetInt(DecalPropertyIDs._Cull, (int) CullMode.Back); _previewMaterial.SetInt(DecalPropertyIDs._Cull, (int) CullMode.Back);
_previewMaterial.SetInt(DecalPropertyIDs._ZWrite, 1);
} }
return _previewMaterial; return _previewMaterial;
@ -68,7 +78,6 @@ namespace ConformalDecals.MaterialModifiers {
public float AspectRatio => MainTexture == null ? 1 : MainTexture.AspectRatio; public float AspectRatio => MainTexture == null ? 1 : MainTexture.AspectRatio;
public void OnBeforeSerialize() { public void OnBeforeSerialize() {
Debug.Log($"Serializing MaterialPropertyCollection {this.GetInstanceID()}");
if (_materialProperties == null) throw new SerializationException("Tried to serialize an uninitialized MaterialPropertyCollection"); if (_materialProperties == null) throw new SerializationException("Tried to serialize an uninitialized MaterialPropertyCollection");
_serializedNames = _materialProperties.Keys.ToArray(); _serializedNames = _materialProperties.Keys.ToArray();
@ -76,7 +85,6 @@ namespace ConformalDecals.MaterialModifiers {
} }
public void OnAfterDeserialize() { public void OnAfterDeserialize() {
Debug.Log($"Deserializing MaterialPropertyCollection {this.GetInstanceID()}");
if (_serializedNames == null) throw new SerializationException("ID array is null"); if (_serializedNames == null) throw new SerializationException("ID array is null");
if (_serializedProperties == null) throw new SerializationException("Property array is null"); if (_serializedProperties == null) throw new SerializationException("Property array is null");
if (_serializedProperties.Length != _serializedNames.Length) throw new SerializationException("Material property arrays are different lengths."); if (_serializedProperties.Length != _serializedNames.Length) throw new SerializationException("Material property arrays are different lengths.");
@ -94,7 +102,6 @@ namespace ConformalDecals.MaterialModifiers {
} }
public void Awake() { public void Awake() {
Debug.Log($"MaterialPropertyCollection {this.GetInstanceID()} onAwake");
_materialProperties ??= new Dictionary<string, MaterialProperty>(); _materialProperties ??= new Dictionary<string, MaterialProperty>();
} }
@ -144,6 +151,20 @@ namespace ConformalDecals.MaterialModifiers {
} }
} }
public bool RemoveProperty(string propertyName) {
if (_materialProperties.TryGetValue(propertyName, out var property)) {
foreach (var material in Materials) {
property.Remove(material);
}
_materialProperties.Remove(propertyName);
Destroy(property);
return true;
}
return false;
}
public MaterialTextureProperty AddTextureProperty(string propertyName, bool isMain = false) { public MaterialTextureProperty AddTextureProperty(string propertyName, bool isMain = false) {
var newProperty = AddProperty<MaterialTextureProperty>(propertyName); var newProperty = AddProperty<MaterialTextureProperty>(propertyName);
if (isMain) _mainTexture = newProperty; if (isMain) _mainTexture = newProperty;
@ -163,8 +184,10 @@ namespace ConformalDecals.MaterialModifiers {
} }
public T ParseProperty<T>(ConfigNode node) where T : MaterialProperty { public T ParseProperty<T>(ConfigNode node) where T : MaterialProperty {
var propertyName = node.GetValue("name"); string propertyName = "";
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentException("node has no name"); if (!ParseUtil.ParseStringIndirect(ref propertyName, node, "name")) throw new ArgumentException("node has no name");
if (ParseUtil.ParseBool(node, "remove", true)) RemoveProperty(propertyName);
var newProperty = AddOrGetProperty<T>(propertyName); var newProperty = AddOrGetProperty<T>(propertyName);
newProperty.ParseNode(node); newProperty.ParseNode(node);
@ -180,13 +203,22 @@ namespace ConformalDecals.MaterialModifiers {
if (string.IsNullOrEmpty(shaderName)) { if (string.IsNullOrEmpty(shaderName)) {
if (_shader == null) { if (_shader == null) {
Debug.Log("Using default decal shader"); Debug.Log("Using default decal shader");
shaderName = "ConformalDecals/Paint/Diffuse"; shaderName = "ConformalDecals/Decal/Standard";
} }
else { else {
return; return;
} }
} }
if (DecalConfig.IsLegacy(shaderName, out var newShader, out var keywords)) {
Debug.LogWarning($"[ConformalDecals] Part is using shader {shaderName}, which has been replaced by {newShader}.");
shaderName = newShader;
foreach (var keyword in keywords) {
var newProperty = AddOrGetProperty<MaterialKeywordProperty>(keyword);
newProperty.value = true;
}
}
var shader = Shabby.Shabby.FindShader(shaderName); var shader = Shabby.Shabby.FindShader(shaderName);
if (shader == null) throw new FormatException($"Unable to find specified shader '{shaderName}'"); if (shader == null) throw new FormatException($"Unable to find specified shader '{shaderName}'");
@ -208,8 +240,6 @@ namespace ConformalDecals.MaterialModifiers {
if (_mainTexture == null) throw new InvalidOperationException("UpdateTile called but no main texture is specified!"); if (_mainTexture == null) throw new InvalidOperationException("UpdateTile called but no main texture is specified!");
var mainTexSize = _mainTexture.Dimensions; var mainTexSize = _mainTexture.Dimensions;
Debug.Log($"Main texture is {_mainTexture.PropertyName} and its size is {mainTexSize}");
foreach (var entry in _materialProperties) { foreach (var entry in _materialProperties) {
if (entry.Value is MaterialTextureProperty textureProperty && textureProperty.autoTile) { if (entry.Value is MaterialTextureProperty textureProperty && textureProperty.autoTile) {
textureProperty.SetTile(tile, mainTexSize); textureProperty.SetTile(tile, mainTexSize);
@ -243,8 +273,9 @@ namespace ConformalDecals.MaterialModifiers {
} }
public void UpdateMaterials() { public void UpdateMaterials() {
UpdateMaterial(DecalMaterial); foreach (var material in Materials) {
UpdateMaterial(PreviewMaterial); UpdateMaterial(material);
}
} }
public void UpdateMaterial(Material material) { public void UpdateMaterial(Material material) {

View File

@ -1,7 +1,8 @@
using System; using System;
using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals.MaterialModifiers { namespace ConformalDecals.MaterialProperties {
public class MaterialTextureProperty : MaterialProperty { public class MaterialTextureProperty : MaterialProperty {
[SerializeField] public bool isNormal; [SerializeField] public bool isNormal;
[SerializeField] public bool isMain; [SerializeField] public bool isMain;
@ -9,7 +10,7 @@ namespace ConformalDecals.MaterialModifiers {
[SerializeField] public bool autoTile; [SerializeField] public bool autoTile;
[SerializeField] private string _textureUrl; [SerializeField] private string _textureUrl;
[SerializeField] private Texture2D _texture; [SerializeField] private Texture2D _texture = Texture2D.whiteTexture;
[SerializeField] private bool _hasTile; [SerializeField] private bool _hasTile;
[SerializeField] private Rect _tileRect; [SerializeField] private Rect _tileRect;
@ -45,24 +46,17 @@ namespace ConformalDecals.MaterialModifiers {
public override void ParseNode(ConfigNode node) { public override void ParseNode(ConfigNode node) {
base.ParseNode(node); base.ParseNode(node);
isNormal = ParsePropertyBool(node, "isNormalMap", true, (PropertyName == "_BumpMap") || (PropertyName == "_DecalBumpMap") || isNormal); ParseUtil.ParseBoolIndirect(ref isMain, node, "isMain");
isMain = ParsePropertyBool(node, "isMain", true, isMain); ParseUtil.ParseBoolIndirect(ref isNormal, node, "isNormalMap");
autoScale = ParsePropertyBool(node, "autoScale", true, autoScale); ParseUtil.ParseBoolIndirect(ref autoScale, node, "autoScale");
autoTile = ParsePropertyBool(node, "autoTile", true, autoTile); ParseUtil.ParseBoolIndirect(ref autoTile, node, "autoTile");
var textureUrl = node.GetValue("textureUrl"); if (!autoTile) {
ParseUtil.ParseRectIndirect(ref _tileRect, node, "tile");
if (string.IsNullOrEmpty(textureUrl)) {
if (string.IsNullOrEmpty(_textureUrl)) {
TextureUrl = "";
}
}
else {
TextureUrl = node.GetValue("textureUrl");
} }
if (node.HasValue("tile") && !autoTile) { if (ParseUtil.ParseStringIndirect(ref _textureUrl, node, "textureUrl")) {
SetTile(ParsePropertyRect(node, "tile", true, _tileRect)); _texture = LoadTexture(_textureUrl, isNormal);
} }
} }
@ -76,6 +70,14 @@ namespace ConformalDecals.MaterialModifiers {
material.SetTexture(_propertyID, _texture); material.SetTexture(_propertyID, _texture);
material.SetTextureOffset(_propertyID, _textureOffset); material.SetTextureOffset(_propertyID, _textureOffset);
material.SetTextureScale(_propertyID, _textureScale * _scale); material.SetTextureScale(_propertyID, _textureScale * _scale);
if (_propertyName != "_Decal") material.EnableKeyword("DECAL" + _propertyName.ToUpper());
}
public override void Remove(Material material) {
if (material == null) throw new ArgumentNullException(nameof(material));
base.Remove(material);
if (_propertyName != "_Decal") material.DisableKeyword("DECAL" + _propertyName.ToUpper());
} }
public void SetScale(Vector2 scale) { public void SetScale(Vector2 scale) {

View File

@ -1,11 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ConformalDecals.MaterialModifiers; using System.Diagnostics.CodeAnalysis;
using ConformalDecals.MaterialProperties;
using ConformalDecals.Util; using ConformalDecals.Util;
using UnityEngine; using UnityEngine;
namespace ConformalDecals { namespace ConformalDecals {
public class ModuleConformalDecal : PartModule { public class ModuleConformalDecal : PartModule {
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DecalScaleMode { public enum DecalScaleMode {
HEIGHT, HEIGHT,
WIDTH, WIDTH,
@ -17,42 +19,20 @@ namespace ConformalDecals {
// CONFIGURABLE VALUES // CONFIGURABLE VALUES
/// <summary> [KSPField] public string shader = "ConformalDecals/Decal/Standard";
/// Shader name. Should be one that supports decal projection.
/// </summary>
[KSPField] public string shader = "ConformalDecals/Paint/Diffuse";
/// <summary>
/// Decal front transform name. Required
/// </summary>
[KSPField] public string decalFront = "Decal-Front"; [KSPField] public string decalFront = "Decal-Front";
/// <summary>
/// Decal back transform name. Required if <see cref="updateBackScale"/> is true.
/// </summary>
[KSPField] public string decalBack = "Decal-Back"; [KSPField] public string decalBack = "Decal-Back";
/// <summary>
/// Decal model transform name. Is rescaled to preview the decal scale when unattached.
/// </summary>
/// <remarks>
/// If unspecified, the decal front transform is used instead.
/// </remarks>
[KSPField] public string decalModel = "Decal-Model"; [KSPField] public string decalModel = "Decal-Model";
/// <summary>
/// Decal projector transform name. The decal will project along the +Z axis of this transform.
/// </summary>
/// <remarks>
/// if unspecified, the part "model" transform will be used instead.
/// </remarks>
[KSPField] public string decalProjector = "Decal-Projector"; [KSPField] public string decalProjector = "Decal-Projector";
[KSPField] public string decalCollider = "Decal-Collider";
// Parameters // Parameters
[KSPField] public bool scaleAdjustable = true; [KSPField] public bool scaleAdjustable = true;
[KSPField] public float defaultScale = 1; [KSPField] public float defaultScale = 1;
[KSPField] public Vector2 scaleRange = new Vector2(0, 4); [KSPField] public Vector2 scaleRange = new Vector2(0, 4);
[KSPField] public DecalScaleMode scaleMode = DecalScaleMode.HEIGHT; [KSPField] public DecalScaleMode scaleMode = DecalScaleMode.HEIGHT;
[KSPField] public bool depthAdjustable = true; [KSPField] public bool depthAdjustable = true;
@ -75,55 +55,39 @@ namespace ConformalDecals {
[KSPField] public Vector2 tileSize; [KSPField] public Vector2 tileSize;
[KSPField] public int tileIndex = -1; [KSPField] public int tileIndex = -1;
/// <summary>
/// Should the back material scale be updated automatically?
/// </summary>
[KSPField] public bool updateBackScale = true; [KSPField] public bool updateBackScale = true;
[KSPField] public bool selectableInFlight;
// INTERNAL VALUES // INTERNAL VALUES
/// <summary>
/// Decal scale factor, in meters.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-scale", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"), [KSPField(guiName = "#LOC_ConformalDecals_gui-scale", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"),
UI_FloatRange(stepIncrement = 0.05f)] UI_FloatRange(stepIncrement = 0.05f)]
public float scale = 1.0f; public float scale = 1.0f;
/// <summary>
/// Projection depth value for the decal projector, in meters.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-depth", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"), [KSPField(guiName = "#LOC_ConformalDecals_gui-depth", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"),
UI_FloatRange(stepIncrement = 0.02f)] UI_FloatRange(stepIncrement = 0.02f)]
public float depth = 0.2f; public float depth = 0.2f;
/// <summary>
/// Opacity value for the decal shader.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-opacity", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"), [KSPField(guiName = "#LOC_ConformalDecals_gui-opacity", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"),
UI_FloatRange(stepIncrement = 0.05f)] UI_FloatRange(stepIncrement = 0.05f)]
public float opacity = 1.0f; public float opacity = 1.0f;
/// <summary>
/// Alpha cutoff value for the decal shader.
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-cutoff", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"), [KSPField(guiName = "#LOC_ConformalDecals_gui-cutoff", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"),
UI_FloatRange(stepIncrement = 0.05f)] UI_FloatRange(stepIncrement = 0.05f)]
public float cutoff = 0.5f; public float cutoff = 0.5f;
/// <summary>
/// Edge wear value for the decal shader. Only relevent when useBaseNormal is true and the shader is a paint shader
/// </summary>
[KSPField(guiName = "#LOC_ConformalDecals_gui-wear", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F0"), [KSPField(guiName = "#LOC_ConformalDecals_gui-wear", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F0"),
UI_FloatRange()] UI_FloatRange()]
public float wear = 100; public float wear = 100;
[KSPField(isPersistant = true)] public bool projectMultiple; // reserved for future features. do not modify
[KSPField] public MaterialPropertyCollection materialProperties; [KSPField] public MaterialPropertyCollection materialProperties;
[KSPField] public Transform decalFrontTransform; [KSPField] public Transform decalFrontTransform;
[KSPField] public Transform decalBackTransform; [KSPField] public Transform decalBackTransform;
[KSPField] public Transform decalModelTransform; [KSPField] public Transform decalModelTransform;
[KSPField] public Transform decalProjectorTransform; [KSPField] public Transform decalProjectorTransform;
[KSPField] public Transform decalColliderTransform;
[KSPField] public Material backMaterial; [KSPField] public Material backMaterial;
[KSPField] public Vector2 backTextureBaseScale; [KSPField] public Vector2 backTextureBaseScale;
@ -139,7 +103,7 @@ namespace ConformalDecals {
private Material _decalMaterial; private Material _decalMaterial;
private Material _previewMaterial; private Material _previewMaterial;
private BoxCollider _boundsCollider; private MeshRenderer _boundsRenderer;
private int DecalQueue { private int DecalQueue {
get { get {
@ -166,48 +130,25 @@ namespace ConformalDecals {
/// <inheritdoc /> /// <inheritdoc />
public override void OnLoad(ConfigNode node) { public override void OnLoad(ConfigNode node) {
this.Log("Loading module");
try { try {
// SETUP TRANSFORMS // SETUP TRANSFORMS
// find front transform
decalFrontTransform = part.FindModelTransform(decalFront); decalFrontTransform = part.FindModelTransform(decalFront);
if (decalFrontTransform == null) throw new FormatException($"Could not find decalFront transform: '{decalFront}'."); if (decalFrontTransform == null) throw new FormatException($"Could not find decalFront transform: '{decalFront}'.");
// find back transform
if (string.IsNullOrEmpty(decalBack)) {
if (updateBackScale) {
this.LogWarning("updateBackScale is true but has no specified decalBack transform!");
this.LogWarning("Setting updateBackScale to false.");
updateBackScale = false;
}
}
else {
decalBackTransform = part.FindModelTransform(decalBack); decalBackTransform = part.FindModelTransform(decalBack);
if (decalBackTransform == null) throw new FormatException($"Could not find decalBack transform: '{decalBack}'."); if (decalBackTransform == null) throw new FormatException($"Could not find decalBack transform: '{decalBack}'.");
}
// find model transform
if (string.IsNullOrEmpty(decalModel)) {
decalModelTransform = decalFrontTransform;
}
else {
decalModelTransform = part.FindModelTransform(decalModel); decalModelTransform = part.FindModelTransform(decalModel);
if (decalModelTransform == null) throw new FormatException($"Could not find decalModel transform: '{decalModel}'."); if (decalModelTransform == null) throw new FormatException($"Could not find decalModel transform: '{decalModel}'.");
}
// find projector transform
if (string.IsNullOrEmpty(decalProjector)) {
decalProjectorTransform = part.transform;
}
else {
decalProjectorTransform = part.FindModelTransform(decalProjector); decalProjectorTransform = part.FindModelTransform(decalProjector);
if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'."); if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'.");
}
// get back material if necessary decalColliderTransform = part.FindModelTransform(decalCollider);
if (decalColliderTransform == null) throw new FormatException($"Could not find decalCollider transform: '{decalCollider}'.");
// SETUP BACK MATERIAL
if (updateBackScale) { if (updateBackScale) {
this.Log("Getting material and base scale for back material");
var backRenderer = decalBackTransform.GetComponent<MeshRenderer>(); var backRenderer = decalBackTransform.GetComponent<MeshRenderer>();
if (backRenderer == null) { if (backRenderer == null) {
this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false."); this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false.");
@ -229,6 +170,12 @@ namespace ConformalDecals {
// set shader // set shader
materialProperties.SetShader(shader); materialProperties.SetShader(shader);
materialProperties.AddOrGetProperty<MaterialKeywordProperty>("DECAL_BASE_NORMAL").value = useBaseNormal;
// add keyword nodes
foreach (var keywordNode in node.GetNodes("KEYWORD")) {
materialProperties.ParseProperty<MaterialKeywordProperty>(keywordNode);
}
// add texture nodes // add texture nodes
foreach (var textureNode in node.GetNodes("TEXTURE")) { foreach (var textureNode in node.GetNodes("TEXTURE")) {
@ -247,7 +194,6 @@ namespace ConformalDecals {
// handle texture tiling parameters // handle texture tiling parameters
var tileString = node.GetValue("tile"); var tileString = node.GetValue("tile");
this.Log(tileString);
if (!string.IsNullOrEmpty(tileString)) { if (!string.IsNullOrEmpty(tileString)) {
var tileValid = ParseExtensions.TryParseRect(tileString, out tileRect); var tileValid = ParseExtensions.TryParseRect(tileString, out tileRect);
if (!tileValid) throw new FormatException($"Invalid rect value for tile '{tileString}'"); if (!tileValid) throw new FormatException($"Invalid rect value for tile '{tileString}'");
@ -259,9 +205,6 @@ namespace ConformalDecals {
else if (tileIndex >= 0) { else if (tileIndex >= 0) {
materialProperties.UpdateTile(tileIndex, tileSize); materialProperties.UpdateTile(tileIndex, tileSize);
} }
// QUEUE PART FOR ICON FIXING IN VAB
DecalIconFixer.QueuePart(part.name);
} }
catch (Exception e) { catch (Exception e) {
this.LogException("Exception parsing partmodule", e); this.LogException("Exception parsing partmodule", e);
@ -269,6 +212,10 @@ namespace ConformalDecals {
UpdateMaterials(); UpdateMaterials();
foreach (var keyword in _decalMaterial.shaderKeywords) {
this.Log($"keyword: {keyword}");
}
if (HighLogic.LoadedSceneIsEditor) { if (HighLogic.LoadedSceneIsEditor) {
UpdateTweakables(); UpdateTweakables();
} }
@ -282,6 +229,9 @@ namespace ConformalDecals {
opacity = defaultOpacity; opacity = defaultOpacity;
cutoff = defaultCutoff; cutoff = defaultCutoff;
wear = defaultWear; wear = defaultWear;
// QUEUE PART FOR ICON FIXING IN VAB
DecalIconFixer.QueuePart(part.name);
} }
} }
@ -292,7 +242,11 @@ namespace ConformalDecals {
/// <inheritdoc /> /// <inheritdoc />
public override void OnStart(StartState state) { public override void OnStart(StartState state) {
this.Log("Starting module"); materialProperties.RenderQueue = DecalQueue;
_boundsRenderer = decalProjectorTransform.GetComponent<MeshRenderer>();
UpdateMaterials();
// handle tweakables // handle tweakables
if (HighLogic.LoadedSceneIsEditor) { if (HighLogic.LoadedSceneIsEditor) {
@ -301,13 +255,10 @@ namespace ConformalDecals {
UpdateTweakables(); UpdateTweakables();
} }
}
materialProperties.RenderQueue = DecalQueue; public override void OnStartFinished(StartState state) {
// handle game events
_boundsCollider = decalProjectorTransform.GetComponent<BoxCollider>();
UpdateMaterials();
if (HighLogic.LoadedSceneIsGame) { if (HighLogic.LoadedSceneIsGame) {
// set initial attachment state // set initial attachment state
if (part.parent == null) { if (part.parent == null) {
@ -317,12 +268,33 @@ namespace ConformalDecals {
OnAttach(); OnAttach();
} }
} }
// handle flight events
if (HighLogic.LoadedSceneIsFlight) {
GameEvents.onPartWillDie.Add(OnPartWillDie);
if (part.parent == null) part.explode();
Part.layerMask |= 1 << DecalConfig.DecalLayer;
decalColliderTransform.gameObject.layer = DecalConfig.DecalLayer;
if (!selectableInFlight || !DecalConfig.SelectableInFlight) {
decalColliderTransform.GetComponent<Collider>().enabled = false;
_boundsRenderer.enabled = false;
}
}
} }
public virtual void OnDestroy() { public virtual void OnDestroy() {
// remove GameEvents // remove GameEvents
if (HighLogic.LoadedSceneIsEditor) {
GameEvents.onEditorPartEvent.Remove(OnEditorEvent); GameEvents.onEditorPartEvent.Remove(OnEditorEvent);
GameEvents.onVariantApplied.Remove(OnVariantApplied); GameEvents.onVariantApplied.Remove(OnVariantApplied);
}
if (HighLogic.LoadedSceneIsFlight) {
GameEvents.onPartWillDie.Remove(OnPartWillDie);
}
// remove from preCull delegate // remove from preCull delegate
Camera.onPreCull -= Render; Camera.onPreCull -= Render;
@ -381,6 +353,13 @@ namespace ConformalDecals {
} }
} }
protected void OnPartWillDie(Part willDie) {
if (willDie == part.parent) {
this.Log("Parent part about to be destroyed! Killing decal part.");
part.Die();
}
}
protected void OnAttach() { protected void OnAttach() {
if (part.parent == null) { if (part.parent == null) {
this.LogError("Attach function called but part has no parent!"); this.LogError("Attach function called but part has no parent!");
@ -390,8 +369,6 @@ namespace ConformalDecals {
_isAttached = true; _isAttached = true;
this.Log($"Decal attached to {part.parent.partName}");
// hide model // hide model
decalModelTransform.gameObject.SetActive(false); decalModelTransform.gameObject.SetActive(false);
@ -423,16 +400,18 @@ namespace ConformalDecals {
} }
protected void UpdateScale() { protected void UpdateScale() {
scale = Mathf.Max(0.01f, scale);
depth = Mathf.Max(0.01f, depth);
var aspectRatio = materialProperties.AspectRatio; var aspectRatio = materialProperties.AspectRatio;
Vector2 size; Vector2 size;
switch (scaleMode) { switch (scaleMode) {
default: default:
case DecalScaleMode.HEIGHT: case DecalScaleMode.HEIGHT:
size = new Vector2(scale, scale * aspectRatio); size = new Vector2(scale / aspectRatio, scale);
break; break;
case DecalScaleMode.WIDTH: case DecalScaleMode.WIDTH:
size = new Vector2(scale / aspectRatio, scale); size = new Vector2(scale, scale * aspectRatio);
break; break;
case DecalScaleMode.AVERAGE: case DecalScaleMode.AVERAGE:
var width1 = 2 * scale / (1 + aspectRatio); var width1 = 2 * scale / (1 + aspectRatio);
@ -463,7 +442,7 @@ namespace ConformalDecals {
// update projection // update projection
foreach (var target in _targets) { foreach (var target in _targets) {
target.Project(_orthoMatrix, decalProjectorTransform, _boundsCollider.bounds, useBaseNormal); target.Project(_orthoMatrix, decalProjectorTransform, _boundsRenderer.bounds, useBaseNormal);
} }
} }
else { else {

View File

@ -32,7 +32,7 @@ namespace ConformalDecals {
} }
} }
materialProperties.AddOrGetTextureProperty("_Decal", true).Texture = TextRenderer.RenderToTexture(fonts[0], newText); //materialProperties.AddOrGetTextureProperty("_Decal", true).Texture = TextRenderer.RenderToTexture(fonts[0], newText);
UpdateMaterials(); UpdateMaterials();
} }

View File

@ -0,0 +1,34 @@
using System;
using UnityEngine;
namespace ConformalDecals.Test {
public class TestLayers : PartModule {
[KSPField(guiActive = true)]
public int layer = 2;
public override void OnStart(StartState state) {
base.OnStart(state);
Part.layerMask.value |= (1 << 3);
}
public void Update() {
foreach (var collider in GameObject.FindObjectsOfType<Collider>()) {
if (collider.gameObject.layer == 3) {
Debug.Log($"Has layer 3: {collider.gameObject.name}");
}
}
}
[KSPEvent(guiActive = true, guiActiveEditor = true, guiName = "switch layers")]
public void Switch() {
Debug.Log(Part.layerMask.value);
var cube = part.FindModelTransform("test");
layer = (layer + 1) % 32;
cube.gameObject.layer = layer;
}
}
}

View File

@ -64,49 +64,5 @@ namespace ConformalDecals.Text {
_blitMaterial = new Material(Shabby.Shabby.FindShader(BlitShader)); _blitMaterial = new Material(Shabby.Shabby.FindShader(BlitShader));
} }
public Texture2D RenderToTexture(Texture2D texture2D, TMP_FontAsset font, string text, float fontSize, float pixelDensity) {
// generate text mesh
_tmp.SetText(text);
_tmp.font = font;
_tmp.fontSize = fontSize;
_tmp.ForceMeshUpdate();
// calculate camera and texture size
var mesh = _tmp.mesh;
var bounds = mesh.bounds;
var width = Mathf.NextPowerOfTwo((int) (bounds.size.x * pixelDensity));
var height = Mathf.NextPowerOfTwo((int) (bounds.size.y * pixelDensity));
_camera.orthographicSize = height / pixelDensity / 2;
_camera.aspect = (float) width / height;
_cameraObject.transform.localPosition = new Vector3(bounds.center.x, bounds.center.y, -1);
width = Mathf.Min(width, MaxTextureSize);
height = Mathf.Max(height, MaxTextureSize);
// setup render texture
var renderTex = RenderTexture.GetTemporary(width, height, 0, TextRenderTextureFormat, RenderTextureReadWrite.Linear, 1);
_camera.targetTexture = renderTex;
// setup material
_blitMaterial.SetTexture(PropertyIDs._MainTex, font.atlas);
_blitMaterial.SetPass(0);
// draw the mesh
Graphics.DrawMeshNow(mesh, _tmp.renderer.localToWorldMatrix);
var request = AsyncGPUReadback.Request(renderTex, 0, TextTextureFormat);
request.WaitForCompletion();
if (request.hasError) {
throw new Exception("[ConformalDecals] Error encountered trying to request render texture data from the GPU!");
}
}
} }
} }

View File

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
namespace ConformalDecals.Util {
public static class ParseUtil {
private static readonly Dictionary<string, Color> NamedColors = new Dictionary<string, Color>();
private static readonly char[] Separator = {',', ' ', '\t'};
public delegate bool TryParseDelegate<T>(string valueString, out T value);
static ParseUtil() {
// setup named colors
foreach (var propertyInfo in typeof(Color).GetProperties(BindingFlags.Static | BindingFlags.Public)) {
if (!propertyInfo.CanRead) continue;
if (propertyInfo.PropertyType != typeof(Color)) continue;
NamedColors.Add(propertyInfo.Name, (Color) propertyInfo.GetValue(null, null));
}
foreach (var propertyInfo in typeof(XKCDColors).GetProperties(BindingFlags.Static | BindingFlags.Public)) {
if (!propertyInfo.CanRead) continue;
if (propertyInfo.PropertyType != typeof(Color)) continue;
if (NamedColors.ContainsKey(propertyInfo.Name)) throw new Exception("duplicate key " + propertyInfo.Name);
NamedColors.Add(propertyInfo.Name, (Color) propertyInfo.GetValue(null, null));
}
}
public static string ParseString(ConfigNode node, string valueName, bool isOptional = false, string defaultValue = "") {
if (!node.HasValue(valueName)) throw new FormatException($"Missing value for {valueName}");
return node.GetValue(valueName);
}
public static bool ParseStringIndirect(ref string value, ConfigNode node, string valueName) {
if (node.HasValue(valueName)) {
value = node.GetValue(valueName);
return true;
}
return false;
}
public static bool ParseBool(ConfigNode node, string valueName, bool isOptional = false, bool defaultValue = false) {
return ParseValue(node, valueName, bool.TryParse, isOptional, defaultValue);
}
public static bool ParseBoolIndirect(ref bool value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, bool.TryParse);
}
public static float ParseFloat(ConfigNode node, string valueName, bool isOptional = false, float defaultValue = 0.0f) {
return ParseValue(node, valueName, float.TryParse, isOptional, defaultValue);
}
public static bool ParseFloatIndirect(ref float value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, float.TryParse);
}
public static int ParseInt(ConfigNode node, string valueName, bool isOptional = false, int defaultValue = 0) {
return ParseValue(node, valueName, int.TryParse, isOptional, defaultValue);
}
public static bool ParseIntIndirect(ref int value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, int.TryParse);
}
public static Color32 ParseColor32(ConfigNode node, string valueName, bool isOptional = false, Color32 defaultValue = default) {
return ParseValue(node, valueName, TryParseColor32, isOptional, defaultValue);
}
public static bool ParseColor32Indirect(ref Color32 value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, TryParseColor32);
}
public static Rect ParseRect(ConfigNode node, string valueName, bool isOptional = false, Rect defaultValue = default) {
return ParseValue(node, valueName, ParseExtensions.TryParseRect, isOptional, defaultValue);
}
public static bool ParseRectIndirect(ref Rect value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, ParseExtensions.TryParseRect);
}
public static Vector2 ParseVector2(ConfigNode node, string valueName, bool isOptional = false, Vector2 defaultValue = default) {
return ParseValue(node, valueName, ParseExtensions.TryParseVector2, isOptional, defaultValue);
}
public static bool ParseVector2Indirect(ref Vector2 value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, ParseExtensions.TryParseVector2);
}
public static Vector3 ParseVector3(ConfigNode node, string valueName, bool isOptional = false, Vector3 defaultValue = default) {
return ParseValue(node, valueName, ParseExtensions.TryParseVector3, isOptional, defaultValue);
}
public static bool ParseVector3Indirect(ref Vector3 value, ConfigNode node, string valueName) {
return ParseValueIndirect(ref value, node, valueName, ParseExtensions.TryParseVector3);
}
public static T ParseValue<T>(ConfigNode node, string valueName, TryParseDelegate<T> tryParse, bool isOptional = false, T defaultValue = default) {
string valueString = node.GetValue(valueName);
if (isOptional) {
if (string.IsNullOrEmpty(valueString)) return defaultValue;
}
else {
if (valueString == null)
throw new FormatException($"Missing {typeof(T)} value for {valueName}");
if (valueString == string.Empty)
throw new FormatException($"Empty {typeof(T)} value for {valueName}");
}
if (tryParse(valueString, out var value)) {
return value;
}
if (isOptional) {
return defaultValue;
}
else {
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} : '{valueString}");
}
}
public static bool ParseValueIndirect<T>(ref T value, ConfigNode node, string valueName, TryParseDelegate<T> tryParse) {
if (!node.HasValue(valueName)) return false;
var valueString = node.GetValue(valueName);
if (tryParse(valueString, out var newValue)) {
value = newValue;
return true;
}
throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} : '{valueString}");
}
public static bool TryParseColor32(string valueString, out Color32 value) {
value = new Color32(0, 0, 0, byte.MaxValue);
// HTML-style hex color
if (valueString[0] == '#') {
var hexColorString = valueString.Substring(1);
if (!int.TryParse(hexColorString, System.Globalization.NumberStyles.HexNumber, null, out var hexColor)) return false;
switch (hexColorString.Length) {
case 8: // RRGGBBAA
value.a = (byte) (hexColor & 0xFF);
hexColor >>= 8;
goto case 6;
case 6: // RRGGBB
value.b = (byte) (hexColor & 0xFF);
hexColor >>= 8;
value.g = (byte) (hexColor & 0xFF);
hexColor >>= 8;
value.r = (byte) (hexColor & 0xFF);
return true;
case 4: // RGBA
value.a = (byte) ((hexColor & 0xF) << 4);
hexColor >>= 4;
goto case 3;
case 3: // RGB
value.b = (byte) (hexColor & 0xF << 4);
hexColor >>= 4;
value.g = (byte) (hexColor & 0xF << 4);
hexColor >>= 4;
value.r = (byte) (hexColor & 0xF << 4);
return true;
default:
return false;
}
}
// named color
if (NamedColors.TryGetValue(valueString, out var namedColor)) {
value = namedColor;
return true;
}
// float color
var split = valueString.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < split.Length; i++) {
split[i] = split[i].Trim();
}
switch (split.Length) {
case 4:
if (!float.TryParse(split[4], out var alpha)) return false;
value.a = (byte) (alpha * 0xFF);
goto case 3;
case 3:
if (!float.TryParse(split[0], out var red)) return false;
if (!float.TryParse(split[1], out var green)) return false;
if (!float.TryParse(split[2], out var blue)) return false;
value.r = (byte) (red * 0xFF);
value.g = (byte) (green * 0xFF);
value.b = (byte) (blue * 0xFF);
return true;
default:
return false;
}
}
}
}

View File

@ -1,3 +1,42 @@
v0.2.0
------
- New Parts:
- CDL-3 Surface Base Decal: A set of conformal decals based on the symbols from the movie Moon designed by Gavin Rothery
- Changes:
- New "KEYWORD" material modifier, allowing for shader features to be enabled and disabled.
- material modifiers can now be removed in variants by setting `remove = true` inside them.
- Unified all shaders into a single "Standard" shader with variants supporting any combination of bump, specular and emissive maps, plus SDF alphas.
- Old shaders are remapped to Standard shader plus keywords automatically.
- New SDF-based antialiasing for when decals extend to their borders, i.e. on opaque flags.
- Fixes:
- Fixed WIDTH and HEIGHT scale modes being flipped
- Removed debug log statements
v0.1.4
------
- Fixes:
- Fixed decals rendering onto disabled B9PS part variants
- Decals will still not update whan their parent part's B9PS variant is changed, both in flight and in the editor. This is known and awaiting a change to B9PS to be fixed.
- Fixed decal bounds rendering as dark cubes when shadowed by EVE clouds.
- Fixed decals being shadowed by EVE clouds, causing the part underneath to appear overly dark.
v0.1.3
------
Fixes:
- Fixed decals being able to be scaled down to 0
Changes:
- Made decal bounds no longer collide in flight, this is done by repurposing layer 31 (which is configurable in the ConformalDecals.cfg file)
- Decals will now be unselectable in flight by default. This can be disabled with the `selectableInFlight` value in ConformalDecals.cfg, or in the module config itself.
- Decal parts will now destroy themselves automatically when the parent part is destroyed
- Small refactor of node parsing code
- Colors can now be specified in hex (#RGB, #RGBA, #RRGGBB, or #RRGGBBAA) or using the colors specified in the XKCDColors class
v0.1.2
------
Fixes:
- Disabled writing to the zbuffer in the decal bounds shader. Should fix any issues with Scatterer or EVE.
v0.1.1 v0.1.1
------ ------
Fixes: Fixes:
@ -7,7 +46,6 @@ Fixes:
v0.1.0 v0.1.0
------ ------
Initial release! Initial release!
New parts: New parts: