Raycast any object for pipette and read foreign materials texel-accurately
The pipette now raycasts the nearest collider of any object, not just the paint mesh. On a foreign hit it reads all channels texel-accurately from the object's material maps (BaseMap/MetallicGloss/Occlusion/Emission) combined with the material scalars per URP/Lit conventions, falling back to scalar properties where a map is missing or the collider yields no UV. Includes scene test props and materials for verifying foreign-object picking. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
3df855597a
commit
9df8c6076d
10 files changed
+976
-27
No files matched your search
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9977e3f116d56d546ac6d24e57d3684a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,137 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Blue Mirror
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AddPrecomputedVelocity: 0
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 1
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 1
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _XRMotionVectorsPass: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 0.2591703, g: 0.22327036, b: 1, a: 1}
|
||||
- _Color: {r: 0.25917026, g: 0.22327033, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
--- !u!114 &5288681647234694520
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||
version: 10
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27e7e012d216e0143b94df13179d62dc
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,137 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Red Metal
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AddPrecomputedVelocity: 0
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 1
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0.75
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _XRMotionVectorsPass: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _Color: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
--- !u!114 &5288681647234694520
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||
version: 10
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d826f81581c9314fb1c2cd886cd78c1
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,138 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Yellow Glow
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- _EMISSION
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 2
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties: _BaseColor _BaseMap
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AddPrecomputedVelocity: 0
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _XRMotionVectorsPass: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 1, g: 0.85953015, b: 0.4433961, a: 1}
|
||||
- _Color: {r: 1, g: 0.85953015, b: 0.44339606, a: 1}
|
||||
- _EmissionColor: {r: 89.45407, g: 89.45407, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
--- !u!114 &5288681647234694520
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||
version: 10
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bc5b774ad58c8740b5705e96c54ade6
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -446,6 +446,7 @@ MonoBehaviour:
|
||||
brushShader: {fileID: 0}
|
||||
dilateShader: {fileID: 0}
|
||||
packMsShader: {fileID: 0}
|
||||
pipette: 0
|
||||
spray: 0
|
||||
sprayDots: 24
|
||||
sprayDotSizeMin: 0.05
|
||||
@@ -460,7 +461,9 @@ MonoBehaviour:
|
||||
brushColor: {r: 0.6, g: 0.6, b: 1, a: 1}
|
||||
metallic: 1
|
||||
smoothness: 1
|
||||
metallicSmoothnessOpacity: 1
|
||||
occlusion: 1
|
||||
occlusionOpacity: 1
|
||||
emissionColor: {r: 1, g: 0.6, b: 0, a: 1}
|
||||
emissionIntensity: 200
|
||||
brushSize: 100
|
||||
@@ -1352,6 +1355,118 @@ Transform:
|
||||
m_CorrespondingSourceObject: {fileID: 6779641804511181039, guid: 930b7a19d446f4b4c9c810e37e84e625, type: 3}
|
||||
m_PrefabInstance: {fileID: 788444}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1 &468175225
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 468175226}
|
||||
- component: {fileID: 468175229}
|
||||
- component: {fileID: 468175228}
|
||||
- component: {fileID: 468175227}
|
||||
m_Layer: 0
|
||||
m_Name: Sphere
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &468175226
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 468175225}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -1, y: 0.5, z: 1}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 686187287}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!135 &468175227
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 468175225}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Radius: 0.5
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &468175228
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 468175225}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_ForceMeshLod: -1
|
||||
m_MeshLodSelectionBias: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 8d826f81581c9314fb1c2cd886cd78c1, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_MaskInteraction: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!33 &468175229
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 468175225}
|
||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!4 &523455893 stripped
|
||||
Transform:
|
||||
m_CorrespondingSourceObject: {fileID: 4597260953850914690, guid: 930b7a19d446f4b4c9c810e37e84e625, type: 3}
|
||||
@@ -1419,6 +1534,7 @@ MonoBehaviour:
|
||||
brushShader: {fileID: 0}
|
||||
dilateShader: {fileID: 0}
|
||||
packMsShader: {fileID: 0}
|
||||
pipette: 0
|
||||
spray: 0
|
||||
sprayDots: 24
|
||||
sprayDotSizeMin: 0.05
|
||||
@@ -1433,7 +1549,9 @@ MonoBehaviour:
|
||||
brushColor: {r: 0.6, g: 0.6, b: 1, a: 1}
|
||||
metallic: 1
|
||||
smoothness: 1
|
||||
metallicSmoothnessOpacity: 1
|
||||
occlusion: 1
|
||||
occlusionOpacity: 1
|
||||
emissionColor: {r: 1, g: 0.6, b: 0, a: 1}
|
||||
emissionIntensity: 20
|
||||
brushSize: 50
|
||||
@@ -1492,6 +1610,9 @@ Transform:
|
||||
- {fileID: 1478475841}
|
||||
- {fileID: 1746495279}
|
||||
- {fileID: 200502122}
|
||||
- {fileID: 468175226}
|
||||
- {fileID: 1504466455}
|
||||
- {fileID: 829281441}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!4 &691617530 stripped
|
||||
@@ -1762,6 +1883,118 @@ PrefabInstance:
|
||||
insertIndex: -1
|
||||
addedObject: {fileID: 682237521}
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 554c0bdf86263754d862d7effd04045b, type: 3}
|
||||
--- !u!1 &829281440
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 829281441}
|
||||
- component: {fileID: 829281444}
|
||||
- component: {fileID: 829281443}
|
||||
- component: {fileID: 829281442}
|
||||
m_Layer: 0
|
||||
m_Name: Sphere
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &829281441
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 829281440}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -2, y: 0.5, z: 1}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 686187287}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!135 &829281442
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 829281440}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Radius: 0.5
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &829281443
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 829281440}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_ForceMeshLod: -1
|
||||
m_MeshLodSelectionBias: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 27e7e012d216e0143b94df13179d62dc, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_MaskInteraction: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!33 &829281444
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 829281440}
|
||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!1 &832575517
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -2635,6 +2868,118 @@ Transform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 686187287}
|
||||
m_LocalEulerAnglesHint: {x: 60, y: 0, z: 0}
|
||||
--- !u!1 &1504466454
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1504466455}
|
||||
- component: {fileID: 1504466458}
|
||||
- component: {fileID: 1504466457}
|
||||
- component: {fileID: 1504466456}
|
||||
m_Layer: 0
|
||||
m_Name: Sphere (1)
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1504466455
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1504466454}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 1.5, y: 0.5, z: 1}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 686187287}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!135 &1504466456
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1504466454}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Radius: 0.5
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &1504466457
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1504466454}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_ForceMeshLod: -1
|
||||
m_MeshLodSelectionBias: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 3bc5b774ad58c8740b5705e96c54ade6, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_MaskInteraction: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!33 &1504466458
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1504466454}
|
||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!1 &1516578026
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -2770,6 +3115,7 @@ MonoBehaviour:
|
||||
brushShader: {fileID: 0}
|
||||
dilateShader: {fileID: 0}
|
||||
packMsShader: {fileID: 0}
|
||||
pipette: 0
|
||||
spray: 0
|
||||
sprayDots: 24
|
||||
sprayDotSizeMin: 0.05
|
||||
@@ -2784,7 +3130,9 @@ MonoBehaviour:
|
||||
brushColor: {r: 0.6, g: 0.6, b: 1, a: 1}
|
||||
metallic: 1
|
||||
smoothness: 1
|
||||
metallicSmoothnessOpacity: 1
|
||||
occlusion: 1
|
||||
occlusionOpacity: 1
|
||||
emissionColor: {r: 1, g: 0.6, b: 0, a: 1}
|
||||
emissionIntensity: 200
|
||||
brushSize: 100
|
||||
@@ -3685,8 +4033,8 @@ SceneRoots:
|
||||
- {fileID: 172071436}
|
||||
- {fileID: 832575519}
|
||||
- {fileID: 410087041}
|
||||
- {fileID: 2025317892}
|
||||
- {fileID: 1141039639}
|
||||
- {fileID: 1129539841}
|
||||
- {fileID: 1006134333}
|
||||
- {fileID: 686187287}
|
||||
- {fileID: 2025317892}
|
||||
@@ -6,16 +6,23 @@ public partial class MeshPainter
|
||||
// --- Pipette (eyedropper) ---
|
||||
//
|
||||
// A sampling MODE rather than a paint channel: while active, a left-click raycasts onto
|
||||
// the mesh, reads ALL painted channel values at the hit texel (albedo, metallic,
|
||||
// smoothness, occlusion, emission) and adopts them into the brush properties - with every
|
||||
// opacity/alpha forced to 1 so re-painting reproduces the picked look at full strength.
|
||||
// The values are read through ReadCanonical(), which already converts both backends (GPU
|
||||
// RenderTextures / CPU Texture2D mirrors) into the same canonical material layout, so the
|
||||
// pick matches what is stored without any new colour-space handling.
|
||||
// ANY surface (not just the paint mesh) and reads every channel value at the hit point
|
||||
// (albedo, metallic, smoothness, occlusion, emission) into the brush properties - with
|
||||
// every opacity/alpha forced to 1 so re-painting reproduces the picked look at full
|
||||
// strength.
|
||||
//
|
||||
// Two read paths, chosen by what was hit:
|
||||
// - Our own paint mesh: read texel-exact from the painted maps via ReadCanonical(),
|
||||
// which converts both backends (GPU RenderTextures / CPU Texture2D mirrors) into the
|
||||
// same canonical layout, so the pick matches what is stored bit-for-bit.
|
||||
// - Any foreign object: read texel-exact from its material maps at the hit UV
|
||||
// (BaseMap/MetallicGloss/Occlusion/Emission) combined with the material scalars, per
|
||||
// the URP/Lit conventions, falling back to scalar properties where a map is absent or
|
||||
// the collider carries no UV (non-MeshCollider).
|
||||
|
||||
[Header("Brush - pipette (eyedropper)")]
|
||||
[Tooltip("Pipette mode: a click samples ALL channel values at the hit point (albedo, " +
|
||||
"metallic, smoothness, occlusion, emission) and adopts them into the brush " +
|
||||
[Tooltip("Pipette mode: a click samples ALL channel values at the hit point on ANY surface " +
|
||||
"(albedo, metallic, smoothness, occlusion, emission) and adopts them into the brush " +
|
||||
"(all alphas set to 1) instead of painting. Held button picks only once.")]
|
||||
public bool pipette = false;
|
||||
|
||||
@@ -28,18 +35,42 @@ public partial class MeshPainter
|
||||
private bool _pickHeld; // edge tracking so a held button picks once, not every frame
|
||||
|
||||
/// <summary>
|
||||
/// Raycasts at a screen position, finds the hit texel UV and copies every painted channel
|
||||
/// value there into the brush (albedo color, metallic, smoothness, occlusion, emission
|
||||
/// color), forcing all opacities/alphas to 1. Reads regardless of which channels are
|
||||
/// currently toggled for painting.
|
||||
/// Raycasts at a screen position against ANY collider, samples every channel value at the hit
|
||||
/// (texel-exact where possible) and copies it into the brush, forcing all opacities/alphas to
|
||||
/// 1 and enabling every paint channel. Reads regardless of which channels are currently toggled.
|
||||
/// </summary>
|
||||
private void PickAtScreen(Vector2 screenPos)
|
||||
{
|
||||
if (!TryRaycastPaintMesh(screenPos, out RaycastHit hit)) return;
|
||||
if (_verts == null || _uvs == null || _tris == null || hit.triangleIndex < 0) return;
|
||||
if (!TryRaycastAny(screenPos, out RaycastHit hit)) return;
|
||||
|
||||
bool ok = (hit.collider == _collider)
|
||||
? PickFromPaintTextures(hit)
|
||||
: PickFromForeignMaterial(hit);
|
||||
if (!ok) return;
|
||||
|
||||
// "Set all alpha values to 1": full-strength adoption across every opacity control.
|
||||
metallicSmoothnessOpacity = 1f;
|
||||
occlusionOpacity = 1f;
|
||||
|
||||
// Picking a whole material implies repainting all of it, so enable every channel.
|
||||
paintAlbedo = true;
|
||||
paintMetallicSmoothness = true;
|
||||
paintOcclusion = true;
|
||||
paintEmission = true;
|
||||
|
||||
// Let listeners (the in-game HUD) refresh their widgets to the adopted values + flags.
|
||||
Picked?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Picks from our own painted maps at the hit texel (bit-exact, backend-agnostic).
|
||||
/// </summary>
|
||||
private bool PickFromPaintTextures(RaycastHit hit)
|
||||
{
|
||||
if (_verts == null || _uvs == null || _tris == null || hit.triangleIndex < 0) return false;
|
||||
|
||||
int t = hit.triangleIndex;
|
||||
if (t * 3 + 2 >= _tris.Length) return;
|
||||
if (t * 3 + 2 >= _tris.Length) return false;
|
||||
int i0 = _tris[t * 3], i1 = _tris[t * 3 + 1], i2 = _tris[t * 3 + 2];
|
||||
|
||||
// UV at the hit via barycentric interpolation of the cached UVs - same UV space the
|
||||
@@ -58,7 +89,7 @@ public partial class MeshPainter
|
||||
Color32[] alb = ReadCanonical(MAP_ALBEDO);
|
||||
Color32[] mso = ReadCanonical(MAP_MSO);
|
||||
Color32[] em = ReadCanonical(MAP_EM);
|
||||
if (idx < 0 || idx >= alb.Length || idx >= mso.Length || idx >= em.Length) return;
|
||||
if (idx < 0 || idx >= alb.Length || idx >= mso.Length || idx >= em.Length) return false;
|
||||
|
||||
Color32 a = alb[idx];
|
||||
Color32 m = mso[idx];
|
||||
@@ -70,18 +101,132 @@ public partial class MeshPainter
|
||||
occlusion = m.g / 255f;
|
||||
smoothness = m.a / 255f;
|
||||
emissionColor = new Color(e.r / 255f, e.g / 255f, e.b / 255f, 1f);
|
||||
return true;
|
||||
}
|
||||
|
||||
// "Set all alpha values to 1": full-strength adoption across every opacity control.
|
||||
metallicSmoothnessOpacity = 1f;
|
||||
occlusionOpacity = 1f;
|
||||
/// <summary>
|
||||
/// Picks from a foreign object's material at the hit UV: texel-exact texture samples
|
||||
/// (where the surface has a MeshCollider and the map exists) combined with the material
|
||||
/// scalars per the URP/Lit conventions, with scalar fallbacks everywhere else.
|
||||
/// </summary>
|
||||
private bool PickFromForeignMaterial(RaycastHit hit)
|
||||
{
|
||||
Collider col = hit.collider;
|
||||
if (!col) return false;
|
||||
Renderer rend = col.GetComponent<Renderer>();
|
||||
if (!rend) rend = col.GetComponentInParent<Renderer>();
|
||||
if (!rend) return false;
|
||||
Material mat = rend.sharedMaterial;
|
||||
if (!mat) return false;
|
||||
|
||||
// Picking a whole material implies repainting all of it, so enable every channel.
|
||||
paintAlbedo = true;
|
||||
paintMetallicSmoothness = true;
|
||||
paintOcclusion = true;
|
||||
paintEmission = true;
|
||||
// textureCoord is only meaningful for a MeshCollider; other collider shapes carry no UV,
|
||||
// so we fall back to the material's uniform scalar values for those.
|
||||
bool hasUv = col is MeshCollider;
|
||||
Vector2 uv = hasUv ? hit.textureCoord : Vector2.zero;
|
||||
|
||||
// Let listeners (the in-game HUD) refresh their widgets to the adopted values + flags.
|
||||
Picked?.Invoke();
|
||||
// --- Albedo: BaseMap (sRGB) * BaseColor ---
|
||||
Color baseCol = GetColorProp(mat, "_BaseColor", "_Color", Color.white);
|
||||
Texture baseTex = GetTexProp(mat, "_BaseMap", "_MainTex");
|
||||
Color albedo = baseCol;
|
||||
if (hasUv && baseTex)
|
||||
albedo = SampleTexel(baseTex, ApplyST(mat, "_BaseMap", "_MainTex", uv), true) * baseCol;
|
||||
brushColor = new Color(Mathf.Clamp01(albedo.r), Mathf.Clamp01(albedo.g), Mathf.Clamp01(albedo.b), 1f);
|
||||
|
||||
// --- Metallic / Smoothness: MetallicGloss map (linear) ---
|
||||
// URP/Lit: metallic = map.r ; smoothness = map.a * _Smoothness (or _Metallic/_Glossiness scalars).
|
||||
float metallicVal = GetFloatProp(mat, "_Metallic", null, 0f);
|
||||
float smoothVal = GetFloatProp(mat, "_Smoothness", "_Glossiness", 0.5f);
|
||||
Texture mgTex = GetTexProp(mat, "_MetallicGlossMap", null);
|
||||
if (hasUv && mgTex)
|
||||
{
|
||||
Color mg = SampleTexel(mgTex, ApplyST(mat, "_MetallicGlossMap", null, uv), false);
|
||||
metallicVal = mg.r;
|
||||
smoothVal = mg.a * smoothVal;
|
||||
}
|
||||
metallic = Mathf.Clamp01(metallicVal);
|
||||
smoothness = Mathf.Clamp01(smoothVal);
|
||||
|
||||
// --- Occlusion: OcclusionMap.g (linear), lerp(1, g, strength) ---
|
||||
float occStrength = GetFloatProp(mat, "_OcclusionStrength", null, 1f);
|
||||
float occ = 1f;
|
||||
Texture occTex = GetTexProp(mat, "_OcclusionMap", null);
|
||||
if (hasUv && occTex)
|
||||
occ = Mathf.Lerp(1f, SampleTexel(occTex, ApplyST(mat, "_OcclusionMap", null, uv), false).g, occStrength);
|
||||
occlusion = Mathf.Clamp01(occ);
|
||||
|
||||
// --- Emission: EmissionMap (sRGB) * EmissionColor ---
|
||||
Color emColor = GetColorProp(mat, "_EmissionColor", null, Color.black);
|
||||
Texture emTex = GetTexProp(mat, "_EmissionMap", null);
|
||||
Color emCol = emColor;
|
||||
if (hasUv && emTex)
|
||||
emCol = SampleTexel(emTex, ApplyST(mat, "_EmissionMap", null, uv), true) * emColor;
|
||||
emissionColor = new Color(Mathf.Clamp01(emCol.r), Mathf.Clamp01(emCol.g), Mathf.Clamp01(emCol.b), 1f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Material read helpers (name-tolerant: URP and legacy Standard) ---
|
||||
|
||||
private static Color GetColorProp(Material m, string nameA, string nameB, Color fallback)
|
||||
{
|
||||
if (m.HasProperty(nameA)) return m.GetColor(nameA);
|
||||
if (nameB != null && m.HasProperty(nameB)) return m.GetColor(nameB);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static float GetFloatProp(Material m, string nameA, string nameB, float fallback)
|
||||
{
|
||||
if (m.HasProperty(nameA)) return m.GetFloat(nameA);
|
||||
if (nameB != null && m.HasProperty(nameB)) return m.GetFloat(nameB);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static Texture GetTexProp(Material m, string nameA, string nameB)
|
||||
{
|
||||
if (m.HasProperty(nameA)) { Texture t = m.GetTexture(nameA); if (t) return t; }
|
||||
if (nameB != null && m.HasProperty(nameB)) { Texture t = m.GetTexture(nameB); if (t) return t; }
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Vector2 ApplyST(Material m, string nameA, string nameB, Vector2 uv)
|
||||
{
|
||||
string prop = m.HasProperty(nameA) ? nameA : (nameB != null && m.HasProperty(nameB) ? nameB : null);
|
||||
if (prop == null) return uv;
|
||||
Vector2 s = m.GetTextureScale(prop);
|
||||
Vector2 o = m.GetTextureOffset(prop);
|
||||
return new Vector2(uv.x * s.x + o.x, uv.y * s.y + o.y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Samples a single texel from a texture at a UV (texel-exact). Uses GetPixelBilinear when the
|
||||
/// texture is CPU-readable; otherwise blits it to a temporary RenderTexture and reads back the
|
||||
/// one texel, so it works regardless of the texture's "Read/Write" import flag. <paramref
|
||||
/// name="srgb"/> selects the colour space so the returned value matches the readable path
|
||||
/// (gamma for colour maps, linear for data maps).
|
||||
/// </summary>
|
||||
private static Color SampleTexel(Texture tex, Vector2 uv, bool srgb)
|
||||
{
|
||||
Texture2D t2d = tex as Texture2D;
|
||||
if (t2d != null && t2d.isReadable)
|
||||
return t2d.GetPixelBilinear(uv.x, uv.y);
|
||||
|
||||
int w = Mathf.Max(1, tex.width), h = Mathf.Max(1, tex.height);
|
||||
var rw = srgb ? RenderTextureReadWrite.sRGB : RenderTextureReadWrite.Linear;
|
||||
RenderTexture rt = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32, rw);
|
||||
RenderTexture prev = RenderTexture.active;
|
||||
Graphics.Blit(tex, rt);
|
||||
RenderTexture.active = rt;
|
||||
|
||||
var tmp = new Texture2D(1, 1, TextureFormat.RGBA32, false, !srgb);
|
||||
int px = Mathf.Clamp(Mathf.FloorToInt(Mathf.Repeat(uv.x, 1f) * w), 0, w - 1);
|
||||
int py = Mathf.Clamp(Mathf.FloorToInt(Mathf.Repeat(uv.y, 1f) * h), 0, h - 1);
|
||||
tmp.ReadPixels(new Rect(px, py, 1, 1), 0, 0, false);
|
||||
tmp.Apply(false);
|
||||
Color c = tmp.GetPixel(0, 0);
|
||||
|
||||
RenderTexture.active = prev;
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
if (Application.isPlaying) Destroy(tmp); else DestroyImmediate(tmp);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
@@ -735,6 +735,18 @@ public partial class MeshPainter : MonoBehaviour
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raycasts at a screen position and returns the nearest hit on ANY collider (not just the
|
||||
/// paint mesh). Used by the pipette, which can sample foreign objects' materials too.
|
||||
/// </summary>
|
||||
private bool TryRaycastAny(Vector2 screenPos, out RaycastHit hit)
|
||||
{
|
||||
hit = default;
|
||||
if (!paintCamera) return false;
|
||||
Ray ray = paintCamera.ScreenPointToRay(screenPos);
|
||||
return Physics.Raycast(ray, out hit, 1000f, ~0, QueryTriggerInteraction.Ignore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raycasts at a screen position against the paint mesh and computes the brush
|
||||
/// placement: hit point (local space), local 3D radius (constant visual size via UV
|
||||
|
||||
Reference in new issue
Block a user