diff --git a/.gitignore b/.gitignore index 205a2d3..a8539d2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ Logs/ Packages/ ProjectSettings/ Temp/ +Distribution/GameData/ConformalDecals/Resources/Resources +Distribution/GameData/ConformalDecals/Resources/Resources.manifest +Distribution/GameData/ConformalDecals/Resources/conformaldecals.shab.manifest # Unity Project Files PartTools.cfg diff --git a/Assets/Shaders/DecalFeatureBumped.shader b/Assets/Shaders/DecalFeatureBumped.shader index 8b2a830..bd7dfe7 100644 --- a/Assets/Shaders/DecalFeatureBumped.shader +++ b/Assets/Shaders/DecalFeatureBumped.shader @@ -4,13 +4,17 @@ Shader "ConformalDecals/Feature/Bumped" { [Header(Texture Maps)] _Decal("Decal Texture", 2D) = "gray" {} - _BumpMap("Decal Bump Map", 2D) = "bump" {} + _DecalBumpMap("Decal Bump Map", 2D) = "bump" {} _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 - _Opacity("_Opacity", Range(0,1) ) = 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", Float) = 0 + [Toggle(DECAL_PREVIEW)] _Preview ("Preview", Float) = 0 [Header(Effects)] - [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 + [PerRendererData]_Opacity("_Opacity", Range(0,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 @@ -18,9 +22,9 @@ Shader "ConformalDecals/Feature/Bumped" SubShader { Tags { "Queue" = "Geometry+100" } - Cull Off - Zwrite Off - Ztest LEqual + Cull [_Cull] + Ztest LEqual + Pass { Name "FORWARD" @@ -32,15 +36,14 @@ Shader "ConformalDecals/Feature/Bumped" #pragma fragment frag_forward #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap + #pragma multi_compile DECAL_PROJECT DECAL_PREVIEW sampler2D _Decal; - sampler2D _BumpMap; + sampler2D _DecalBumpMap; float4 _Decal_ST; - float4 _BumpMap_ST; - - float _Cutoff; - float _Opacity; + float4 _DecalBumpMap_ST; + float _RimFalloff; float4 _RimColor; @@ -55,16 +58,18 @@ Shader "ConformalDecals/Feature/Bumped" void surf (DecalSurfaceInput IN, inout SurfaceOutput o) { float4 color = tex2D(_Decal, IN.uv_decal); - float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_bump)); + float3 normal = UnpackNormal(tex2D(_DecalBumpMap, IN.uv_bump)); - // clip alpha - clip(color.a - saturate(_Cutoff + 0.01)); + #ifdef DECAL_PROJECT + // clip alpha + clip(color.a - _Cutoff + 0.01); + #endif //DECAL_PROJECT 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 * _Opacity; + o.Alpha = color.a * _DecalOpacity; o.Emission = emission; o.Normal = normal; } @@ -83,15 +88,14 @@ Shader "ConformalDecals/Feature/Bumped" #pragma fragment frag_forward #pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap + #pragma multi_compile DECAL_PROJECT DECAL_PREVIEW sampler2D _Decal; - sampler2D _BumpMap; + sampler2D _DecalBumpMap; float4 _Decal_ST; - float4 _BumpMap_ST; + float4 _DecalBumpMap_ST; - float _Cutoff; - float _Opacity; float _RimFalloff; float4 _RimColor; @@ -106,16 +110,18 @@ Shader "ConformalDecals/Feature/Bumped" void surf (DecalSurfaceInput IN, inout SurfaceOutput o) { float4 color = tex2D(_Decal, IN.uv_decal); - float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_bump)); + float3 normal = UnpackNormal(tex2D(_DecalBumpMap, IN.uv_bump)); - // clip alpha - clip(color.a - saturate(_Cutoff + 0.01)); + #ifdef DECAL_PROJECT + // clip alpha + clip(color.a - _Cutoff + 0.01); + #endif //DECAL_PROJECT 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 * _Opacity; + o.Alpha = color.a * _DecalOpacity; o.Emission = emission; o.Normal = normal; } diff --git a/Assets/Shaders/DecalPaint.shader b/Assets/Shaders/DecalPaint.shader index 09189b9..868e009 100644 --- a/Assets/Shaders/DecalPaint.shader +++ b/Assets/Shaders/DecalPaint.shader @@ -6,24 +6,27 @@ Shader "ConformalDecals/Paint/Diffuse" _Decal("Decal Texture", 2D) = "gray" {} _BumpMap("Bump Map", 2D) = "bump" {} - _EdgeWearStrength("Edge Wear Strength", Range(0,100)) = 0 - _EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0 + _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 - _Opacity("_Opacity", Range(0,1) ) = 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", Float) = 0 + [Toggle(DECAL_PREVIEW)] _Preview ("Preview", Float) = 0 + [Header(Effects)] - [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 + [PerRendererData]_Opacity("_Opacity", Range(0,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+400" } - ZWrite Off - ZTest LEqual - Offset -1, -1 + Tags { "Queue" = "Geometry+100" } + Cull [_Cull] + Ztest LEqual Pass { @@ -36,18 +39,15 @@ Shader "ConformalDecals/Paint/Diffuse" #pragma fragment frag_forward #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap + #pragma multi_compile __ DECAL_PREVIEW sampler2D _Decal; - sampler2D _BumpMap; float4 _Decal_ST; - float4 _BumpMap_ST; float _EdgeWearStrength; float _EdgeWearOffset; - - float _Cutoff; - float _Opacity; + float _RimFalloff; float4 _RimColor; @@ -62,11 +62,10 @@ Shader "ConformalDecals/Paint/Diffuse" void surf (DecalSurfaceInput IN, inout SurfaceOutput o) { float4 color = tex2D(_Decal, IN.uv_decal); - float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_base)); - // clip alpha - clip(color.a - _Cutoff); + decalClipAlpha(color.a); + float3 normal = IN.normal; half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal)); float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a; @@ -76,9 +75,8 @@ Shader "ConformalDecals/Paint/Diffuse" color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor)); o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb; - o.Alpha = color.a * _Opacity; + o.Alpha = color.a * _DecalOpacity; o.Emission = emission; - o.Normal = normal; } ENDCG @@ -95,18 +93,15 @@ Shader "ConformalDecals/Paint/Diffuse" #pragma fragment frag_forward #pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap + #pragma multi_compile __ DECAL_PREVIEW sampler2D _Decal; - sampler2D _BumpMap; float4 _Decal_ST; - float4 _BumpMap_ST; float _EdgeWearStrength; float _EdgeWearOffset; - float _Cutoff; - float _Opacity; float _RimFalloff; float4 _RimColor; @@ -121,11 +116,10 @@ Shader "ConformalDecals/Paint/Diffuse" void surf (DecalSurfaceInput IN, inout SurfaceOutput o) { float4 color = tex2D(_Decal, IN.uv_decal); - float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_base)); - // clip alpha - clip(color.a - _Cutoff); + decalClipAlpha(color.a); + float3 normal = IN.normal; half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal)); float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a; @@ -135,9 +129,8 @@ Shader "ConformalDecals/Paint/Diffuse" color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor)); o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb; - o.Alpha = color.a * _Opacity; + o.Alpha = color.a * _DecalOpacity; o.Emission = emission; - o.Normal = normal; } ENDCG diff --git a/Assets/Shaders/DecalPaintSpecular.shader b/Assets/Shaders/DecalPaintSpecular.shader index 0f95716..0e68414 100644 --- a/Assets/Shaders/DecalPaintSpecular.shader +++ b/Assets/Shaders/DecalPaintSpecular.shader @@ -7,16 +7,19 @@ Shader "ConformalDecals/Paint/Specular" _BumpMap("Bump Map", 2D) = "bump" {} _SpecMap("Specular Map", 2D) = "black" {} - _EdgeWearStrength("Edge Wear Strength", Range(0,100)) = 0 - _EdgeWearOffset("Edge Wear Offset", Range(0,1)) = 0 + _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 - _Opacity("_Opacity", Range(0,1) ) = 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.5, 0.5, 0.5, 1) - _Shininess ("Shininess", Range (0.03, 10)) = 0.4 + _SpecColor ("_SpecColor", Color) = (0.25, 0.25, 0.25, 1) + _Shininess ("Shininess", Range (0.03, 10)) = 0.3 + [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", Float) = 0 + [Toggle(DECAL_PREVIEW)] _Preview ("Preview", Float) = 0 [Header(Effects)] [PerRendererData]_Opacity("_Opacity", Range(0,1) ) = 1 @@ -26,10 +29,9 @@ Shader "ConformalDecals/Paint/Specular" } SubShader { - Tags { "Queue" = "Geometry+400" } - ZWrite Off - ZTest LEqual - Offset -1, -1 + Tags { "Queue" = "Geometry+100" } + Cull [_Cull] + Ztest LEqual Pass { @@ -42,22 +44,19 @@ Shader "ConformalDecals/Paint/Specular" #pragma fragment frag_forward #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap + #pragma multi_compile __ DECAL_PREVIEW sampler2D _Decal; - sampler2D _BumpMap; sampler2D _SpecMap; float4 _Decal_ST; - float4 _BumpMap_ST; float4 _SpecMap_ST; float _EdgeWearStrength; float _EdgeWearOffset; half _Shininess; - - float _Cutoff; - float _Opacity; + float _RimFalloff; float4 _RimColor; @@ -73,11 +72,13 @@ Shader "ConformalDecals/Paint/Specular" void surf (DecalSurfaceInput IN, inout SurfaceOutput o) { float4 color = tex2D(_Decal, IN.uv_decal); - float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_base)); float3 specular = tex2D(_SpecMap, IN.uv_spec); - - // clip alpha - clip(color.a - _Cutoff); + float3 normal = IN.normal; + + #ifdef DECAL_PROJECT + // clip alpha + clip(color.a - _Cutoff + 0.01); + #endif //DECAL_PROJECT half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal)); float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a; @@ -86,12 +87,11 @@ Shader "ConformalDecals/Paint/Specular" float wearFactorAlpha = saturate(_EdgeWearStrength * wearFactor); color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor)); - color.a *= _Opacity; + color.a *= _DecalOpacity; o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb; o.Alpha = color.a; o.Emission = emission; - o.Normal = normal; o.Specular = _Shininess; o.Gloss = specular.r * color.a; } @@ -110,22 +110,19 @@ Shader "ConformalDecals/Paint/Specular" #pragma fragment frag_forward #pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap - + #pragma multi_compile __ DECAL_PREVIEW + sampler2D _Decal; - sampler2D _BumpMap; sampler2D _SpecMap; float4 _Decal_ST; - float4 _BumpMap_ST; float4 _SpecMap_ST; float _EdgeWearStrength; float _EdgeWearOffset; half _Shininess; - - float _Cutoff; - float _Opacity; + float _RimFalloff; float4 _RimColor; @@ -141,11 +138,13 @@ Shader "ConformalDecals/Paint/Specular" void surf (DecalSurfaceInput IN, inout SurfaceOutput o) { float4 color = tex2D(_Decal, IN.uv_decal); - float3 normal = UnpackNormal(tex2D(_BumpMap, IN.uv_base)); float3 specular = tex2D(_SpecMap, IN.uv_spec); + float3 normal = IN.normal; - // clip alpha - clip(color.a - _Cutoff); + #ifdef DECAL_PROJECT + // clip alpha + clip(color.a - _Cutoff + 0.01); + #endif //DECAL_PROJECT half rim = 1.0 - saturate(dot (normalize(IN.viewDir), normal)); float3 emission = (_RimColor.rgb * pow(rim, _RimFalloff)) * _RimColor.a; @@ -156,9 +155,8 @@ Shader "ConformalDecals/Paint/Specular" color.a *= saturate(1 + _EdgeWearOffset - saturate(_EdgeWearStrength * wearFactor)); o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb; - o.Alpha = color.a * _Opacity; + o.Alpha = color.a * _DecalOpacity; o.Emission = emission; - o.Normal = normal; o.Specular = _Shininess; o.Gloss = specular.r; } diff --git a/Assets/Shaders/DecalsCommon.cginc b/Assets/Shaders/DecalsCommon.cginc index 6382817..5008743 100644 --- a/Assets/Shaders/DecalsCommon.cginc +++ b/Assets/Shaders/DecalsCommon.cginc @@ -18,10 +18,9 @@ struct DecalSurfaceInput #endif //DECAL_EMISSIVE #ifdef DECAL_BASE_NORMAL - float2 uv_base; - #endif //DECAL_BASE_NORMAL + float3 normal; + #endif - float3 normal; float3 viewDir; float3 worldPosition; }; @@ -30,10 +29,10 @@ struct appdata_decal { float4 vertex : POSITION; float3 normal : NORMAL; - #ifdef DECAL_BASE_NORMAL + #if defined(DECAL_BASE_NORMAL) || defined(DECAL_PREVIEW) float4 texcoord : TEXCOORD0; float4 tangent : TANGENT; - #endif //DECAL_BASE_NORMAL + #endif }; struct v2f @@ -65,6 +64,23 @@ 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) { + #ifndef DECAL_PREVIEW + clip(alpha - _Cutoff + 0.01); + #endif +} + // declare surf function, // this must be defined in any shader using this cginc void surf (DecalSurfaceInput IN, inout SurfaceOutput o); @@ -76,7 +92,12 @@ v2f vert_forward(appdata_decal v) o.pos = UnityObjectToClipPos(v.vertex); o.normal = v.normal; - o.uv_decal = mul (_ProjectionMatrix, v.vertex); + + #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); @@ -85,7 +106,7 @@ v2f vert_forward(appdata_decal v) float3 worldPosition = mul(unity_ObjectToWorld, v.vertex).xyz; float3 worldNormal = UnityObjectToWorldNormal(v.normal); - #ifdef DECAL_BASE_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; @@ -95,7 +116,7 @@ v2f vert_forward(appdata_decal v) fixed3 decalTangent = UnityObjectToWorldDir(_DecalTangent); fixed3 worldBinormal = cross(decalTangent, worldNormal); fixed3 worldTangent = cross(worldNormal, worldBinormal); - #endif //DECAL_BASE_NORMAL + #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); @@ -148,22 +169,26 @@ fixed4 frag_forward(v2f IN) : SV_Target float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPosition)); float3 viewDir = _unity_tbn_0 * worldViewDir.x + _unity_tbn_1 * worldViewDir.y + _unity_tbn_2 * worldViewDir.z; - // perform decal projection - fixed4 uv_projected = UNITY_PROJ_COORD(IN.uv_decal); + #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)); + // 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, _BumpMap); + i.uv_bump = TRANSFORM_TEX(uv_projected, _DecalBumpMap); #endif //DECAL_NORMAL #ifdef DECAL_SPECULAR @@ -173,12 +198,16 @@ fixed4 frag_forward(v2f IN) : SV_Target #ifdef DECAL_EMISSIVE i.uv_glow = TRANSFORM_TEX(uv_projected, _GlowMap); #endif //DECAL_EMISSIVE - + #ifdef DECAL_BASE_NORMAL - i.uv_base = IN.uv_base; - #endif //DECAL_BASE_NORMAL + #ifdef DECAL_PREVIEW + i.normal = fixed3(0,0,1); + #else + i.normal = UnpackNormal(tex2D(_BumpMap, IN.uv_base)); + #endif //DECAL_PREVIEW + #endif //DECAL_BASE_NORMAL - i.normal = IN.normal; + //i.normal = IN.normal; i.viewDir = viewDir; i.worldPosition = worldPosition; @@ -192,6 +221,14 @@ fixed4 frag_forward(v2f IN) : SV_Target // call surface function surf(i, o); + + #ifdef DECAL_PREVIEW + o.Albedo = lerp(_Background.rgb,o.Albedo, o.Alpha); + 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) @@ -203,7 +240,6 @@ fixed4 frag_forward(v2f IN) : SV_Target WorldNormal.z = dot(_unity_tbn_2, o.Normal); WorldNormal = normalize(WorldNormal); o.Normal = WorldNormal; - //KSP lighting function c += LightingBlinnPhongSmooth(o, lightDir, worldViewDir, atten); diff --git a/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg b/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg index 4125aa1..eb33229 100644 --- a/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg +++ b/Distribution/GameData/ConformalDecals/Parts/decal-blank.cfg @@ -64,18 +64,18 @@ PART name = ModuleConformalDecalGeneric } DATA { - decalShader = ConformalDecals/Feature/Bumped + shader = ConformalDecals/Feature/Bumped TEXTURE { name = _Decal - textureURL = ConformalDecals/Assets/Tortilla-diffuse + textureUrl = ConformalDecals/Assets/Tortilla-diffuse isMain = true } TEXTURE { - name = _BumpMap - textureURL = ConformalDecals/Assets/Tortilla-normal + name = _DecalBumpMap + textureUrl = ConformalDecals/Assets/Tortilla-normal isNormalMap = true } } @@ -90,11 +90,11 @@ PART name = ModuleConformalDecalGeneric } DATA { - decalShader = ConformalDecals/Paint/Diffuse + shader = ConformalDecals/Paint/Diffuse useBaseNormal = true TEXTURE { name = _Decal - textureURL = ConformalDecals/Assets/Sign-HighVoltage-2 + textureUrl = ConformalDecals/Assets/Sign-HighVoltage-2 isMain = true } } diff --git a/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll b/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll index 34ff6f8..36522d2 100644 Binary files a/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll and b/Distribution/GameData/ConformalDecals/Plugins/ConformalDecals.dll differ diff --git a/Distribution/GameData/ConformalDecals/Resources/conformaldecals.shab b/Distribution/GameData/ConformalDecals/Resources/conformaldecals.shab index e6f56b6..1f4e5e1 100644 Binary files a/Distribution/GameData/ConformalDecals/Resources/conformaldecals.shab and b/Distribution/GameData/ConformalDecals/Resources/conformaldecals.shab differ diff --git a/Source/ConformalDecals/MaterialModifiers/MaterialColorProperty.cs b/Source/ConformalDecals/MaterialModifiers/MaterialColorProperty.cs index 4aba7f0..f60d388 100644 --- a/Source/ConformalDecals/MaterialModifiers/MaterialColorProperty.cs +++ b/Source/ConformalDecals/MaterialModifiers/MaterialColorProperty.cs @@ -3,18 +3,18 @@ using UnityEngine; namespace ConformalDecals.MaterialModifiers { public class MaterialColorProperty : MaterialProperty { - private readonly Color _color; + [SerializeField] public Color color; - public MaterialColorProperty(ConfigNode node) : base(node) { - _color = ParsePropertyColor(node, "color", false); - } + public override void ParseNode(ConfigNode node) { + base.ParseNode(node); - public MaterialColorProperty(string name, Color value) : base(name) { - _color = value; + color = ParsePropertyColor(node, "color", true, color); } public override void Modify(Material material) { - material.SetColor(_propertyID, _color); + if (material == null) throw new ArgumentNullException("material cannot be null"); + + material.SetColor(_propertyID, color); } } } \ No newline at end of file diff --git a/Source/ConformalDecals/MaterialModifiers/MaterialFloatProperty.cs b/Source/ConformalDecals/MaterialModifiers/MaterialFloatProperty.cs index a92ab95..1dad8df 100644 --- a/Source/ConformalDecals/MaterialModifiers/MaterialFloatProperty.cs +++ b/Source/ConformalDecals/MaterialModifiers/MaterialFloatProperty.cs @@ -3,18 +3,18 @@ using UnityEngine; namespace ConformalDecals.MaterialModifiers { public class MaterialFloatProperty : MaterialProperty { - private readonly float _value; + [SerializeField] public float value; - public MaterialFloatProperty(ConfigNode node) : base(node) { - _value = ParsePropertyFloat(node, "value", false); - } + public override void ParseNode(ConfigNode node) { + base.ParseNode(node); - public MaterialFloatProperty(string name, float value) : base(name) { - _value = value; + value = ParsePropertyFloat(node, "value", true, value); } public override void Modify(Material material) { - material.SetFloat(_propertyID, _value); + if (material == null) throw new ArgumentNullException("material cannot be null"); + + material.SetFloat(_propertyID, value); } } } \ No newline at end of file diff --git a/Source/ConformalDecals/MaterialModifiers/MaterialProperty.cs b/Source/ConformalDecals/MaterialModifiers/MaterialProperty.cs index a8ea801..629a7e9 100644 --- a/Source/ConformalDecals/MaterialModifiers/MaterialProperty.cs +++ b/Source/ConformalDecals/MaterialModifiers/MaterialProperty.cs @@ -1,24 +1,24 @@ using System; using UnityEngine; +using Object = UnityEngine.Object; namespace ConformalDecals.MaterialModifiers { - public abstract class MaterialProperty { - public string PropertyName { get; } - - protected readonly int _propertyID; - - - protected MaterialProperty(ConfigNode node) : this(node.GetValue("name")) { } + public abstract class MaterialProperty : ScriptableObject { + public string Name { + get => _propertyName; + set { + _propertyName = value; + _propertyID = Shader.PropertyToID(_propertyName); + } + } - protected MaterialProperty(string name) { - if (name == null) - throw new FormatException("name not found, cannot create material modifier"); + [SerializeField] protected int _propertyID; + [SerializeField] protected string _propertyName; - if (name == string.Empty) - throw new FormatException("name is empty, cannot create material modifier"); + public virtual void ParseNode(ConfigNode node) { + if (node == null) throw new ArgumentNullException("node cannot be null"); - PropertyName = name; - _propertyID = Shader.PropertyToID(PropertyName); + Name = node.GetValue("name"); } public abstract void Modify(Material material); @@ -57,10 +57,10 @@ namespace ConformalDecals.MaterialModifiers { } else { if (valueString == null) - throw new FormatException($"Missing {typeof(T)} value for {valueName} in property '{PropertyName}'"); + throw new FormatException($"Missing {typeof(T)} value for {valueName} in property '{Name}'"); if (valueString == string.Empty) - throw new FormatException($"Empty {typeof(T)} value for {valueName} in property '{PropertyName}'"); + throw new FormatException($"Empty {typeof(T)} value for {valueName} in property '{Name}'"); } if (tryParse(valueString, out var value)) { @@ -72,7 +72,7 @@ namespace ConformalDecals.MaterialModifiers { } else { - throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} in property '{PropertyName}' : '{valueString}"); + throw new FormatException($"Improperly formatted {typeof(T)} value for {valueName} in property '{Name}' : '{valueString}"); } } } diff --git a/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs b/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs index 8f80426..0e1322a 100644 --- a/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs +++ b/Source/ConformalDecals/MaterialModifiers/MaterialPropertyCollection.cs @@ -4,18 +4,18 @@ using UnityEngine; namespace ConformalDecals.MaterialModifiers { public class MaterialPropertyCollection : ScriptableObject { - private static readonly int OpacityId = Shader.PropertyToID("_Opacity"); + private static readonly int OpacityId = Shader.PropertyToID("_DecalOpacity"); private static readonly int CutoffId = Shader.PropertyToID("_Cutoff"); - public MaterialTextureProperty MainMaterialTextureProperty { get; set; } + public MaterialTextureProperty MainMaterialTextureProperty => _mainTexture; - private List _materialProperties; - private List _textureMaterialProperties; + public Shader DecalShader => _shader; public Material DecalMaterial { get { + Debug.Log($"{_textureMaterialProperties == null}"); if (_decalMaterial == null) { - _decalMaterial = new Material(_decalShader); + _decalMaterial = new Material(_shader); UpdateMaterial(_decalMaterial); } @@ -23,13 +23,32 @@ namespace ConformalDecals.MaterialModifiers { } } - public Shader DecalShader => _decalShader; + public Material PreviewMaterial { + get { + if (_previewMaterial == null) { + _previewMaterial = new Material(_shader); + UpdateMaterial(_previewMaterial); + _previewMaterial.EnableKeyword("DECAL_PREVIEW"); + } - public float AspectRatio => MainMaterialTextureProperty?.AspectRatio ?? 1f; + return _previewMaterial; + } + } + + public float AspectRatio { + get { + if (MainMaterialTextureProperty == null) return 1; + return MainMaterialTextureProperty.AspectRatio; + } + } - [SerializeField] private Shader _decalShader; + [SerializeField] private Shader _shader; + [SerializeField] private List _materialProperties; + [SerializeField] private List _textureMaterialProperties; + [SerializeField] private MaterialTextureProperty _mainTexture; private Material _decalMaterial; + private Material _previewMaterial; public void Initialize() { _materialProperties = new List(); @@ -44,7 +63,7 @@ namespace ConformalDecals.MaterialModifiers { } foreach (var p in _materialProperties) { - if (p.PropertyName == property.PropertyName) { + if (p.Name == property.Name) { _materialProperties.Remove(property); } } @@ -53,20 +72,20 @@ namespace ConformalDecals.MaterialModifiers { if (property is MaterialTextureProperty textureProperty) { foreach (var p in _textureMaterialProperties) { - if (p.PropertyName == textureProperty.PropertyName) { + if (p.Name == textureProperty.Name) { _textureMaterialProperties.Remove(textureProperty); } } _textureMaterialProperties.Add(textureProperty); - if (textureProperty.IsMain) MainMaterialTextureProperty ??= textureProperty; + if (textureProperty.isMain) _mainTexture ??= textureProperty; } } public void SetShader(string shaderName) { if (string.IsNullOrEmpty(shaderName)) { - if (_decalShader == null) { + if (_shader == null) { Debug.Log("Using default decal shader"); shaderName = "ConformalDecals/Paint/Diffuse"; } @@ -79,13 +98,15 @@ namespace ConformalDecals.MaterialModifiers { if (shader == null) throw new FormatException($"Unable to find specified shader '{shaderName}'"); - _decalShader = shader; + _shader = shader; + _decalMaterial = null; + _previewMaterial = null; } public void SetRenderQueue(int queue) { DecalMaterial.renderQueue = queue; } - + public void SetScale(Vector2 scale) { foreach (var textureProperty in _textureMaterialProperties) { textureProperty.UpdateScale(DecalMaterial, scale); @@ -101,10 +122,21 @@ namespace ConformalDecals.MaterialModifiers { } public void UpdateMaterials() { + if (_decalMaterial == null) { + _decalMaterial = DecalMaterial; + } + + if (_previewMaterial == null) { + _previewMaterial = PreviewMaterial; + } + UpdateMaterial(_decalMaterial); + UpdateMaterial(_previewMaterial); } public void UpdateMaterial(Material material) { + if (material == null) throw new ArgumentNullException("material cannot be null"); + foreach (var property in _materialProperties) { property.Modify(material); } diff --git a/Source/ConformalDecals/MaterialModifiers/MaterialTextureProperty.cs b/Source/ConformalDecals/MaterialModifiers/MaterialTextureProperty.cs index 03dda7d..3008167 100644 --- a/Source/ConformalDecals/MaterialModifiers/MaterialTextureProperty.cs +++ b/Source/ConformalDecals/MaterialModifiers/MaterialTextureProperty.cs @@ -3,29 +3,54 @@ using UnityEngine; namespace ConformalDecals.MaterialModifiers { public class MaterialTextureProperty : MaterialProperty { - public Texture2D texture; + [SerializeField] public Texture2D texture; + + [SerializeField] public bool isNormal; + [SerializeField] public bool isMain; + [SerializeField] public bool autoScale; + + [SerializeField] private bool _hasTile; + [SerializeField] private Rect _tileRect; + [SerializeField] private Vector2 _textureOffset = Vector2.zero; + [SerializeField] private Vector2 _textureScale = Vector2.one; + + public float AspectRatio { + get { + if (texture == null) return 1; + if (!_hasTile || Mathf.Approximately(0, _tileRect.width)) return ((float) texture.height) / ((float) texture.width); + return _tileRect.height / _tileRect.width; + } + } - public bool IsNormal { get; } - public bool IsMain { get; } - public bool AutoScale { get; } + public Rect TileRect { + get => _tileRect; + set { + _hasTile = !(Mathf.Abs(value.width) < 0.1) || !(Mathf.Abs(value.height) < 0.1); - private readonly Rect _tileRect; + _tileRect = value; + UpdateTiling(); + } + } - public float AspectRatio => _tileRect.height / _tileRect.width; + public override void ParseNode(ConfigNode node) { + base.ParseNode(node); - private readonly Vector2 _textureOffset; - private readonly Vector2 _textureScale; + isNormal = ParsePropertyBool(node, "isNormalMap", true, (Name == "_BumpMap") || isNormal); + isMain = ParsePropertyBool(node, "isMain", true, isMain); + autoScale = ParsePropertyBool(node, "autoScale", true, autoScale); - public MaterialTextureProperty(ConfigNode node) : base(node) { - IsNormal = ParsePropertyBool(node, "isNormalMap", true, PropertyName == "_BumpMap"); - IsMain = ParsePropertyBool(node, "isMain", true); - AutoScale = ParsePropertyBool(node, "autoScale", true); - var textureUrl = node.GetValue("textureURL"); + SetTexture(node.GetValue("textureUrl")); + + if (node.HasValue("tileRect")) { + TileRect = ParsePropertyRect(node, "tileRect", true, _tileRect); + } + } - if ((textureUrl == null && IsNormal) || textureUrl == "Bump") { + public void SetTexture(string textureUrl) { + if ((textureUrl == null && isNormal) || textureUrl == "Bump") { texture = Texture2D.normalTexture; } - else if ((textureUrl == null && !IsNormal) || textureUrl == "White") { + else if ((textureUrl == null && !isNormal) || textureUrl == "White") { texture = Texture2D.whiteTexture; } else if (textureUrl == "Black") { @@ -36,48 +61,43 @@ namespace ConformalDecals.MaterialModifiers { if (textureInfo == null) throw new Exception($"Cannot find texture: '{textureUrl}'"); - texture = IsNormal ? textureInfo.normalMap : textureInfo.texture; + texture = isNormal ? textureInfo.normalMap : textureInfo.texture; } - if (texture == null) throw new Exception($"Cannot get texture from texture info '{textureUrl}' isNormalMap = {IsNormal}"); - - _tileRect = ParsePropertyRect(node, "tileRect", true, new Rect(0, 0, texture.width, texture.height)); - - _textureScale.x = _tileRect.width / texture.width; - _textureScale.y = _tileRect.height / texture.height; - - _textureOffset.x = _tileRect.x / texture.width; - _textureOffset.y = _tileRect.y / texture.height; + if (texture == null) throw new Exception($"Cannot get texture from texture info '{textureUrl}', isNormalMap = {isNormal}"); + UpdateTiling(); } - public MaterialTextureProperty(string name, Texture2D texture, Rect tileRect = default, - bool isNormal = false, bool isMain = false, bool autoScale = false) : base(name) { - - this.texture = texture; - - _tileRect = tileRect == default ? new Rect(0, 0, this.texture.width, this.texture.height) : tileRect; - - IsNormal = isNormal; - IsMain = isMain; - AutoScale = autoScale; - - _textureScale.x = _tileRect.width / this.texture.width; - _textureScale.y = _tileRect.height / this.texture.height; - - _textureOffset.x = _tileRect.x / this.texture.width; - _textureOffset.y = _tileRect.y / this.texture.height; - } - public override void Modify(Material material) { + if (material == null) throw new ArgumentNullException(nameof(material)); + if (texture == null) { + texture = Texture2D.whiteTexture; + throw new NullReferenceException("texture is null, but should not be"); + } + material.SetTexture(_propertyID, texture); material.SetTextureOffset(_propertyID, _textureOffset); material.SetTextureScale(_propertyID, _textureScale); } public void UpdateScale(Material material, Vector2 scale) { - if (AutoScale) { + if (autoScale) { material.SetTextureScale(_propertyID, new Vector2(_textureScale.x * scale.x, _textureScale.y * scale.y)); } } + + private void UpdateTiling() { + if (_hasTile) { + _textureScale.x = Mathf.Approximately(0, _tileRect.width) ? 1 : _tileRect.width / texture.width; + _textureScale.y = Mathf.Approximately(0, _tileRect.height) ? 1 : _tileRect.height / texture.height; + + _textureOffset.x = _tileRect.x / texture.width; + _textureOffset.y = _tileRect.y / texture.height; + } + else { + _textureScale = Vector2.one; + _textureOffset = Vector2.zero; + } + } } } \ No newline at end of file diff --git a/Source/ConformalDecals/ModuleConformalDecalBase.cs b/Source/ConformalDecals/ModuleConformalDecalBase.cs index e3715ad..73bb99a 100644 --- a/Source/ConformalDecals/ModuleConformalDecalBase.cs +++ b/Source/ConformalDecals/ModuleConformalDecalBase.cs @@ -7,26 +7,27 @@ using UnityEngine; namespace ConformalDecals { public abstract class ModuleConformalDecalBase : PartModule { [KSPField(guiName = "#LOC_ConformalDecals_gui-scale", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"), - UI_FloatRange(minValue = 0.05f, maxValue = 4f, stepIncrement = 0.05f)] + UI_FloatRange(stepIncrement = 0.05f)] public float scale = 1.0f; [KSPField(guiName = "#LOC_ConformalDecals_gui-depth", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "F2", guiUnits = "m"), - UI_FloatRange(minValue = 0.05f, maxValue = 4f, stepIncrement = 0.05f)] - public float depth = 1.0f; + UI_FloatRange(stepIncrement = 0.02f)] + public float depth = 0.2f; [KSPField(guiName = "#LOC_ConformalDecals_gui-opacity", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"), - UI_FloatRange(minValue = 0.0f, maxValue = 1f, stepIncrement = 0.05f)] + UI_FloatRange(stepIncrement = 0.05f)] public float opacity = 1.0f; [KSPField(guiName = "#LOC_ConformalDecals_gui-cutoff", guiActive = false, guiActiveEditor = true, isPersistant = true, guiFormat = "P0"), - UI_FloatRange(minValue = 0.0f, maxValue = 1f, stepIncrement = 0.05f)] + UI_FloatRange(stepIncrement = 0.05f)] public float cutoff = 0.5f; + [KSPField] public string shader = "ConformalDecals/Paint/Diffuse"; + [KSPField] public string decalFront = string.Empty; [KSPField] public string decalBack = string.Empty; [KSPField] public string decalModel = string.Empty; [KSPField] public string decalProjector = string.Empty; - [KSPField] public string decalShader = "ConformalDecals/Paint/Diffuse"; [KSPField] public Transform decalFrontTransform; [KSPField] public Transform decalBackTransform; @@ -38,11 +39,10 @@ namespace ConformalDecals { [KSPField] public bool opacityAdjustable = true; [KSPField] public bool cutoffAdjustable = true; - [KSPField] public Vector2 scaleRange = new Vector2(0, 4); - [KSPField] public Vector2 depthRange = new Vector2(0, 4); - [KSPField] public Vector2 opacityRange = new Vector2(0, 1); - [KSPField] public Vector2 cutoffRange = new Vector2(0, 1); - [KSPField] public Vector2 decalQueueRange = new Vector2(2100, 2400); + [KSPField] public Vector2 scaleRange = new Vector2(0, 4); + [KSPField] public Vector2 depthRange = new Vector2(0, 2); + [KSPField] public Vector2 opacityRange = new Vector2(0, 1); + [KSPField] public Vector2 cutoffRange = new Vector2(0, 1); [KSPField] public bool updateBackScale = true; [KSPField] public bool useBaseNormal = true; @@ -50,7 +50,10 @@ namespace ConformalDecals { [KSPField] public MaterialPropertyCollection materialProperties; [KSPField] public Material backMaterial; + [KSPField] public Vector2 backTextureBaseScale; + private const int DecalQueueMin = 2100; + private const int DecalQueueMax = 2400; private static int _decalQueueCounter = -1; private List _targets; @@ -58,13 +61,16 @@ namespace ConformalDecals { private bool _isAttached; private Matrix4x4 _orthoMatrix; private Bounds _decalBounds; - private Vector2 _backTextureBaseScale; + + private Material _decalMaterial; + private Material _previewMaterial; + private int DecalQueue { get { _decalQueueCounter++; - if (_decalQueueCounter > decalQueueRange.y || _decalQueueCounter < decalQueueRange.x) { - _decalQueueCounter = (int) decalQueueRange.x; + if (_decalQueueCounter > DecalQueueMax || _decalQueueCounter < DecalQueueMin) { + _decalQueueCounter = DecalQueueMin; } return _decalQueueCounter; @@ -74,10 +80,6 @@ namespace ConformalDecals { public override void OnLoad(ConfigNode node) { this.Log("Loading module"); try { - if (HighLogic.LoadedSceneIsEditor) { - UpdateTweakables(); - } - // find front transform decalFrontTransform = part.FindModelTransform(decalFront); if (decalFrontTransform == null) throw new FormatException($"Could not find decalFront transform: '{decalFront}'."); @@ -112,32 +114,25 @@ namespace ConformalDecals { decalProjectorTransform = part.FindModelTransform(decalProjector); if (decalProjectorTransform == null) throw new FormatException($"Could not find decalProjector transform: '{decalProjector}'."); } - - // get back material if necessary - if (updateBackScale) { - this.Log("Getting material and base scale for back material"); - var backRenderer = decalBackTransform.GetComponent(); - if (backRenderer == null) { - this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false."); - updateBackScale = false; - } - else { - backMaterial = backRenderer.material; - if (backMaterial == null) { - this.LogError($"Specified decalBack transform {decalBack} has a renderer but no material! Setting updateBackScale to false."); - updateBackScale = false; - } - else { - _backTextureBaseScale = backMaterial.GetTextureScale(PropertyIDs._MainTex); - } - } + + + if (HighLogic.LoadedSceneIsEditor) { + UpdateTweakables(); } - // update EVERYTHING if currently attached - if (_isAttached) { - UpdateScale(); - UpdateTargets(); + // setup material properties + if (HighLogic.LoadedSceneIsGame) { + // additional load, in flight or in the editor + materialProperties = ScriptableObject.Instantiate(materialProperties); } + else { + // first load, so get everything set up + materialProperties = ScriptableObject.CreateInstance(); + materialProperties.Initialize(); + } + + // set shader + materialProperties.SetShader(shader); } catch (Exception e) { this.LogException("Exception parsing partmodule", e); @@ -147,6 +142,7 @@ namespace ConformalDecals { public override void OnStart(StartState state) { this.Log("Starting module"); + // handle tweakables if (HighLogic.LoadedSceneIsEditor) { GameEvents.onEditorPartEvent.Add(OnEditorEvent); GameEvents.onVariantApplied.Add(OnVariantApplied); @@ -154,21 +150,22 @@ namespace ConformalDecals { UpdateTweakables(); } - // generate orthogonal projection matrix and offset it by 0.5 on x and y axes - _orthoMatrix = Matrix4x4.identity; - _orthoMatrix[0, 3] = 0.5f; - _orthoMatrix[1, 3] = 0.5f; - - // instantiate decal material and set uniqueish queue - materialProperties.SetRenderQueue(DecalQueue); + // clone materialProperties and setup queue + if (HighLogic.LoadedSceneIsGame) { + materialProperties = ScriptableObject.Instantiate(materialProperties); + materialProperties.SetRenderQueue(DecalQueue); - // set initial attachment state - if (part.parent == null) { - OnDetach(); - } - else { - OnAttach(); + // set initial attachment state + if (part.parent == null) { + _isAttached = false; + } + else { + OnAttach(); + } } + + UpdateMaterials(); + UpdateScale(); } public void OnDestroy() { @@ -179,25 +176,25 @@ namespace ConformalDecals { Camera.onPreCull -= Render; } - private void OnSizeTweakEvent(BaseField field, object obj) { + protected void OnSizeTweakEvent(BaseField field, object obj) { // scale or depth values have been changed, so update scale // and update projection matrices if attached UpdateScale(); if (_isAttached) UpdateProjection(); } - private void OnMaterialTweakEvent(BaseField field, object obj) { + protected void OnMaterialTweakEvent(BaseField field, object obj) { materialProperties.SetOpacity(opacity); materialProperties.SetCutoff(cutoff); } - private void OnVariantApplied(Part eventPart, PartVariant variant) { + protected void OnVariantApplied(Part eventPart, PartVariant variant) { if (_isAttached && eventPart == part.parent) { UpdateTargets(); } } - private void OnEditorEvent(ConstructionEventType eventType, Part eventPart) { + protected void OnEditorEvent(ConstructionEventType eventType, Part eventPart) { if (eventPart != this.part) return; switch (eventType) { case ConstructionEventType.PartAttached: @@ -213,7 +210,7 @@ namespace ConformalDecals { } } - private void OnAttach() { + protected void OnAttach() { if (part.parent == null) { this.LogError("Attach function called but part has no parent!"); _isAttached = false; @@ -224,7 +221,6 @@ namespace ConformalDecals { this.Log($"Decal attached to {part.parent.partName}"); - UpdateTargets(); // hide preview model decalFrontTransform.gameObject.SetActive(false); @@ -233,11 +229,12 @@ namespace ConformalDecals { // add to preCull delegate Camera.onPreCull += Render; - UpdateScale(); + //UpdateScale(); + UpdateTargets(); UpdateProjection(); } - private void OnDetach() { + protected void OnDetach() { _isAttached = false; // unhide preview model @@ -247,13 +244,19 @@ namespace ConformalDecals { // remove from preCull delegate Camera.onPreCull -= Render; - UpdateScale(); + //UpdateScale(); } - private void UpdateScale() { + protected void UpdateScale() { + var aspectRatio = materialProperties.AspectRatio; + this.Log($"Aspect ratio is {aspectRatio}"); var size = new Vector2(scale, scale * materialProperties.AspectRatio); // update orthogonal matrix scale + _orthoMatrix = Matrix4x4.identity; + _orthoMatrix[0, 3] = 0.5f; + _orthoMatrix[1, 3] = 0.5f; + _orthoMatrix[0, 0] = 1 / size.x; _orthoMatrix[1, 1] = 1 / size.y; _orthoMatrix[2, 2] = 1 / depth; @@ -262,28 +265,67 @@ namespace ConformalDecals { _decalBounds.center = Vector3.forward * (depth / 2); _decalBounds.extents = new Vector3(size.x / 2, size.y / 2, depth / 2); + if (decalModelTransform == null) { + this.LogError("decalModelTransform is null!"); + } + // rescale preview model decalModelTransform.localScale = new Vector3(size.x, size.y, (size.x + size.y) / 2); // update back material scale if (updateBackScale) { - backMaterial.SetTextureScale(PropertyIDs._MainTex, new Vector2(size.x * _backTextureBaseScale.x, size.y * _backTextureBaseScale.y)); + backMaterial.SetTextureScale(PropertyIDs._MainTex, new Vector2(size.x * backTextureBaseScale.x, size.y * backTextureBaseScale.y)); } // update material scale materialProperties.SetScale(size); } - private void UpdateProjection() { + protected void UpdateMaterials() { + materialProperties.UpdateMaterials(); + _decalMaterial = materialProperties.DecalMaterial; + _previewMaterial = materialProperties.PreviewMaterial; + + // get back material if necessary + if (updateBackScale) { + this.Log("Getting material and base scale for back material"); + var backRenderer = decalBackTransform.GetComponent(); + if (backRenderer == null) { + this.LogError($"Specified decalBack transform {decalBack} has no renderer attached! Setting updateBackScale to false."); + updateBackScale = false; + } + else { + backMaterial = backRenderer.material; + if (backMaterial == null) { + this.LogError($"Specified decalBack transform {decalBack} has a renderer but no material! Setting updateBackScale to false."); + updateBackScale = false; + } + else { + if (backTextureBaseScale == default) backTextureBaseScale = backMaterial.GetTextureScale(PropertyIDs._MainTex); + } + } + } + + if (decalFrontTransform == null) { + this.LogError("No reference to decal front transform"); + return; + } + + decalFrontTransform.GetComponent().material = _previewMaterial; + } + + protected void UpdateProjection() { if (!_isAttached) return; + var bounds = new OrientedBounds(decalProjectorTransform.localToWorldMatrix, _decalBounds); + // project to each target object foreach (var target in _targets) { - target.Project(_orthoMatrix, new OrientedBounds(decalProjectorTransform.localToWorldMatrix, _decalBounds), decalProjectorTransform); + target.Project(_orthoMatrix, bounds, decalProjectorTransform, useBaseNormal); } } - private void UpdateTargets() { + protected void UpdateTargets() { if (_targets == null) { _targets = new List(); } @@ -319,7 +361,7 @@ namespace ConformalDecals { } } - private void UpdateTweakables() { + protected void UpdateTweakables() { // setup tweakable fields var scaleField = Fields[nameof(scale)]; var depthField = Fields[nameof(depth)]; @@ -369,12 +411,12 @@ namespace ConformalDecals { } } - private void Render(Camera camera) { + protected void Render(Camera camera) { if (!_isAttached) return; // render on each target object foreach (var target in _targets) { - target.Render(materialProperties.DecalMaterial, part.mpb, camera); + target.Render(_decalMaterial, part.mpb, camera); } } } diff --git a/Source/ConformalDecals/ModuleConformalDecalFlag.cs b/Source/ConformalDecals/ModuleConformalDecalFlag.cs index 1585c4e..1c53cef 100644 --- a/Source/ConformalDecals/ModuleConformalDecalFlag.cs +++ b/Source/ConformalDecals/ModuleConformalDecalFlag.cs @@ -1,4 +1,3 @@ -using System; using ConformalDecals.MaterialModifiers; using ConformalDecals.Util; using UnityEngine; @@ -7,29 +6,35 @@ namespace ConformalDecals { public class ModuleConformalDecalFlag : ModuleConformalDecalBase { [KSPField] public MaterialTextureProperty flagTextureProperty; - public override void OnLoad(ConfigNode node) { + private const string defaultFlag = "Squad/Flags/default"; - if (materialProperties == null) { - // materialProperties is null, so make a new one - materialProperties = ScriptableObject.CreateInstance(); - materialProperties.Initialize(); - } - else { - // materialProperties already exists, so make a copy - materialProperties = ScriptableObject.Instantiate(materialProperties); - } + public override void OnLoad(ConfigNode node) { + base.OnLoad(node); - // set shader - materialProperties.SetShader(decalShader); - base.OnLoad(node); + if (HighLogic.LoadedSceneIsGame) { + UpdateMaterials(); + UpdateScale(); + UpdateProjection(); + } } public override void OnStart(StartState state) { base.OnStart(state); - UpdateFlag(EditorLogic.FlagURL != string.Empty ? EditorLogic.FlagURL : HighLogic.CurrentGame.flagURL); - GameEvents.onMissionFlagSelect.Add(UpdateFlag); + if (HighLogic.LoadedSceneIsGame) { + UpdateFlag(EditorLogic.FlagURL != string.Empty ? EditorLogic.FlagURL : HighLogic.CurrentGame.flagURL); + GameEvents.onMissionFlagSelect.Add(UpdateFlag); + } + else { + UpdateFlag(defaultFlag); + } + } + + public override void OnIconCreate() { + this.Log("called OnIconCreate"); + OnStart(StartState.None); + UpdateScale(); } private void UpdateFlag(string flagUrl) { @@ -42,14 +47,17 @@ namespace ConformalDecals { if (flagTextureProperty == null) { this.Log("Initializing flag property"); - flagTextureProperty = new MaterialTextureProperty("_Decal", flagTexture, isMain: true); + flagTextureProperty = ScriptableObject.CreateInstance(); + flagTextureProperty.Name = "_Decal"; + flagTextureProperty.isMain = true; materialProperties.AddProperty(flagTextureProperty); } - else { - flagTextureProperty.texture = flagTexture; - } + else { } + + flagTextureProperty.texture = flagTexture; + - materialProperties.UpdateMaterials(); + UpdateMaterials(); } } } \ No newline at end of file diff --git a/Source/ConformalDecals/ModuleConformalDecalGeneric.cs b/Source/ConformalDecals/ModuleConformalDecalGeneric.cs index 7a2fa76..1025710 100644 --- a/Source/ConformalDecals/ModuleConformalDecalGeneric.cs +++ b/Source/ConformalDecals/ModuleConformalDecalGeneric.cs @@ -5,35 +5,42 @@ using UnityEngine; namespace ConformalDecals { public class ModuleConformalDecalGeneric : ModuleConformalDecalBase { public override void OnLoad(ConfigNode node) { - - if (materialProperties == null) { - // materialProperties is null, so make a new one - materialProperties = ScriptableObject.CreateInstance(); - materialProperties.Initialize(); - } - else { - // materialProperties already exists, so make a copy - materialProperties = ScriptableObject.Instantiate(materialProperties); - } + base.OnLoad(node); // set shader - materialProperties.SetShader(decalShader); + materialProperties.SetShader(shader); // add texture nodes foreach (var textureNode in node.GetNodes("TEXTURE")) { - materialProperties.AddProperty(new MaterialTextureProperty(textureNode)); + var textureProperty = ScriptableObject.CreateInstance(); + textureProperty.ParseNode(textureNode); + materialProperties.AddProperty(textureProperty); } // add float nodes foreach (var floatNode in node.GetNodes("FLOAT")) { - materialProperties.AddProperty(new MaterialFloatProperty(floatNode)); + var floatProperty = ScriptableObject.CreateInstance(); + floatProperty.ParseNode(floatNode); + materialProperties.AddProperty(floatProperty); } // add color nodes foreach (var colorNode in node.GetNodes("COLOR")) { - materialProperties.AddProperty(new MaterialColorProperty(colorNode)); + var colorProperty = ScriptableObject.CreateInstance(); + colorProperty.ParseNode(colorNode); + materialProperties.AddProperty(colorProperty); } - base.OnLoad(node); + if (HighLogic.LoadedSceneIsGame) { + UpdateMaterials(); + UpdateScale(); + UpdateProjection(); + } + } + + public override void OnIconCreate() { + this.Log("called OnIconCreate"); + OnStart(StartState.None); + UpdateScale(); } } } \ No newline at end of file diff --git a/Source/ConformalDecals/ProjectionTarget.cs b/Source/ConformalDecals/ProjectionTarget.cs index ce69143..9d559b6 100644 --- a/Source/ConformalDecals/ProjectionTarget.cs +++ b/Source/ConformalDecals/ProjectionTarget.cs @@ -17,36 +17,23 @@ namespace ConformalDecals { // property block private readonly MaterialPropertyBlock _decalMPB; - - private static readonly int normalID = Shader.PropertyToID("_BumpMap"); - private static readonly int normalIDST = Shader.PropertyToID("_BumpMap_ST"); + + private static readonly int normalID = Shader.PropertyToID("_BumpMap"); + private static readonly int normalIDST = Shader.PropertyToID("_BumpMap_ST"); public ProjectionTarget(MeshRenderer targetRenderer, Mesh targetMesh, bool useBaseNormal) { target = targetRenderer.transform; _targetRenderer = targetRenderer; _targetMesh = targetMesh; - var targetMaterial = targetRenderer.sharedMaterial; - _decalMPB = new MaterialPropertyBlock(); - - if (useBaseNormal && targetMaterial.HasProperty(normalID)) { - var normal = targetMaterial.GetTexture(normalID); - if (normal != null) { - - _decalMPB.SetTexture(normalID, targetMaterial.GetTexture(normalID)); - - var normalScale = targetMaterial.GetTextureScale(normalID); - var normalOffset = targetMaterial.GetTextureOffset(normalID); - - _decalMPB.SetVector(normalIDST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y)); - } - } } - public void Project(Matrix4x4 orthoMatrix, OrientedBounds projectorBounds, Transform projector) { + public void Project(Matrix4x4 orthoMatrix, OrientedBounds projectorBounds, Transform projector, bool useBaseNormal) { var targetBounds = _targetRenderer.bounds; if (projectorBounds.Intersects(targetBounds)) { _projectionEnabled = true; + + var targetMaterial = _targetRenderer.sharedMaterial; var projectorToTargetMatrix = target.worldToLocalMatrix * projector.localToWorldMatrix; var projectionMatrix = orthoMatrix * projectorToTargetMatrix.inverse; @@ -57,6 +44,19 @@ namespace ConformalDecals { _decalMPB.SetVector(_decalNormalID, decalNormal); _decalMPB.SetVector(_decalTangentID, decalTangent); Debug.Log($"Projection enabled for {target.gameObject}"); + + if (useBaseNormal && targetMaterial.HasProperty(normalID)) { + var normal = targetMaterial.GetTexture(normalID); + if (normal != null) { + + _decalMPB.SetTexture(normalID, targetMaterial.GetTexture(normalID)); + + var normalScale = targetMaterial.GetTextureScale(normalID); + var normalOffset = targetMaterial.GetTextureOffset(normalID); + + _decalMPB.SetVector(normalIDST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y)); + } + } } else { _projectionEnabled = false;