updated with enemy
8
Assets/Adobe.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a9976dfedf6d8b45b5bb3f03320094d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Adobe/Substance3DForUnity.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b663793eb4aeb35429a1791214f3a9f9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Adobe/Substance3DForUnity/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfe765b550e1b604682ed4d23a504e89
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Adobe.SubstanceEditor",
|
||||
"rootNamespace": "Adobe.SubstanceEditor",
|
||||
"references": [
|
||||
"GUID:0322a29457affe94ab4ade0a1555000f",
|
||||
"GUID:b78cd19d3dcc04e4a8eb1915990b2db1"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5520fe70c6e8e046b4383b7dd2c75c8
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Adobe/Substance3DForUnity/Editor/Assets.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c96dedd774b1103439d2b3517649cf88
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_128.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
108
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_128.png.meta
Normal file
@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30be34334090e2b478db7867a8d81934
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_16.png
Normal file
After Width: | Height: | Size: 464 B |
108
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_16.png.meta
Normal file
@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f582f763e5df3c241b43ca4f4eac7f4c
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_256.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
108
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_256.png.meta
Normal file
@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf4c0b432f60d4c42bcf5e564e5a356a
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_32.png
Normal file
After Width: | Height: | Size: 670 B |
108
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_32.png.meta
Normal file
@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0aa309be25f1381499253b908921e763
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_64.png
Normal file
After Width: | Height: | Size: 978 B |
108
Assets/Adobe/Substance3DForUnity/Editor/Assets/Logo_64.png.meta
Normal file
@ -0,0 +1,108 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 729db32ebfbf92e49aec2d8b254e28e7
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 6.0 KiB |
@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ee05e940668f9f4c9dd8e52aba9675f
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2aa042885e232cc44a033f24979e8def
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMasterTextureLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Adobe/Substance3DForUnity/Editor/Scripts.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dbef35dc04f100549aa054b79a370e9a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c561c4b0d14ef6e44bce6495d361246e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class PhysicalSizeExtension
|
||||
{
|
||||
public static bool IsSupported()
|
||||
{
|
||||
return PluginPipelines.IsHDRP();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 459462fea64803a4b8c2e0fe9979fba8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,186 @@
|
||||
using Adobe.Substance;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceGraphSOExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates SubstanceGraphSO related assets using the renderResult data.
|
||||
/// </summary>
|
||||
/// <param name="renderResult">Target render result.</param>
|
||||
/// <param name="substance">Owner substance.</param>
|
||||
/// <returns>Returns true if textures must be reassigned to the material.</returns>
|
||||
internal static bool UpdateAssociatedAssets(this SubstanceGraphSO graph, IntPtr renderResult, bool forceRebuild)
|
||||
{
|
||||
if (!forceRebuild && CheckIfTextureAssetsExist(graph))
|
||||
{
|
||||
ResizeExistingTexturesIfNeeded(renderResult, graph);
|
||||
graph.UpdateOutputTextures(renderResult);
|
||||
return false;
|
||||
}
|
||||
|
||||
graph.CreateAndUpdateOutputTextures(renderResult);
|
||||
|
||||
if (graph.IsRuntimeOnly)
|
||||
return true;
|
||||
|
||||
graph.SaveOutputsTGAFiles();
|
||||
AssetDatabase.Refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates TGA files using the currect values of the outputs Texture2D.
|
||||
/// </summary>
|
||||
/// <param name="graph"></param>
|
||||
private static void SaveOutputsTGAFiles(this SubstanceGraphSO graph)
|
||||
{
|
||||
foreach (var substanceOutput in graph.Output)
|
||||
{
|
||||
var texture = substanceOutput.OutputTexture;
|
||||
|
||||
if (texture == null)
|
||||
continue;
|
||||
|
||||
var textureOutput = graph.GetAssociatedAssetPath(substanceOutput.Description.Identifier, "tga");
|
||||
var bytes = texture.EncodeToTGA();
|
||||
File.WriteAllBytes(textureOutput, bytes);
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
graph.ConfigureTextureImporter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Properly configure TextureImporters settings based on output types.
|
||||
/// </summary>
|
||||
/// <param name="graph"></param>
|
||||
private static void ConfigureTextureImporter(this SubstanceGraphSO graph)
|
||||
{
|
||||
foreach (var substanceOutput in graph.Output)
|
||||
{
|
||||
var texture = substanceOutput.OutputTexture;
|
||||
|
||||
if (texture == null)
|
||||
continue;
|
||||
|
||||
var textureOutput = graph.GetAssociatedAssetPath(substanceOutput.Description.Identifier, "tga");
|
||||
substanceOutput.OutputTexture = AssetDatabase.LoadAssetAtPath<Texture2D>(textureOutput);
|
||||
ConfigureTextureImporter(substanceOutput);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes existing texture to match the expected values from renderResult.
|
||||
/// </summary>
|
||||
/// <param name="renderResult">Render result.</param>
|
||||
/// <param name="graph">Target graph.</param>
|
||||
private static void ResizeExistingTexturesIfNeeded(IntPtr renderResult, SubstanceGraphSO graph)
|
||||
{
|
||||
var renderResultsSizes = graph.GetResizedOutputs(renderResult);
|
||||
|
||||
//Resize existing output textures.
|
||||
if (renderResultsSizes.Count != 0)
|
||||
{
|
||||
foreach (var resultSize in renderResultsSizes)
|
||||
{
|
||||
var outputIndex = resultSize.Item1;
|
||||
var outputSize = resultSize.Item2;
|
||||
var targetOutput = graph.Output.FirstOrDefault(a => a.Index == outputIndex);
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
targetOutput.OutputTexture.Reinitialize(outputSize.x, outputSize.y);
|
||||
#else
|
||||
targetOutput.OutputTexture.Resize(outputSize.x, outputSize.y);
|
||||
#endif
|
||||
if (!graph.IsRuntimeOnly)
|
||||
{
|
||||
var bytes = targetOutput.OutputTexture.EncodeToTGA();
|
||||
var assetPath = AssetDatabase.GetAssetPath(targetOutput.OutputTexture);
|
||||
File.WriteAllBytes(assetPath, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get the texture2D instances for a give graph.
|
||||
/// </summary>
|
||||
/// <param name="graph">Target graph.</param>
|
||||
/// <param name="textures">Array of texture2D instances attached to each substance output.</param>
|
||||
/// <returns>True if all textures instances exists. If false they must be rebuild.</returns>
|
||||
private static bool CheckIfTextureAssetsExist(SubstanceGraphSO graph)
|
||||
{
|
||||
foreach (var output in graph.Output)
|
||||
{
|
||||
if (!output.IsStandardOutput(graph.OutputMaterial) && !graph.GenerateAllOutputs)
|
||||
{
|
||||
if (output.OutputTexture != null)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(output.OutputTexture);
|
||||
|
||||
if (!string.IsNullOrEmpty(assetPath))
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
|
||||
output.OutputTexture = null;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (output.OutputTexture == null)
|
||||
return false;
|
||||
|
||||
output.OutputTexture = TextureUtils.EnsureTextureCorrectness(output.OutputTexture, !output.IsNormalMap(), graph.GenerateAllMipmaps);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the texture importer settings to the associated texture output.
|
||||
/// </summary>
|
||||
/// <param name="textureOutput">Target output texture.</param>
|
||||
private static void ConfigureTextureImporter(SubstanceOutputTexture textureOutput)
|
||||
{
|
||||
var texturePath = AssetDatabase.GetAssetPath(textureOutput.OutputTexture);
|
||||
TextureImporter importer = AssetImporter.GetAtPath(texturePath) as TextureImporter;
|
||||
|
||||
if (importer == null)
|
||||
return;
|
||||
|
||||
importer.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
importer.isReadable = true;
|
||||
importer.maxTextureSize = 4096;
|
||||
importer.sRGBTexture = textureOutput.sRGB;
|
||||
|
||||
if (textureOutput.IsNormalMap())
|
||||
{
|
||||
importer.textureType = TextureImporterType.NormalMap;
|
||||
}
|
||||
else
|
||||
{
|
||||
var defaultSettings = importer.GetDefaultPlatformTextureSettings();
|
||||
|
||||
if (defaultSettings.format != TextureImporterFormat.RGBA32)
|
||||
{
|
||||
defaultSettings.format = TextureImporterFormat.RGBA32;
|
||||
importer.SetPlatformTextureSettings(defaultSettings);
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(importer);
|
||||
AssetDatabase.WriteImportSettingsIfDirty(texturePath);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36f38a90f11f0544a89dffe1f5752bae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82768c317d7769d4ba20e5a0daa7f62b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,33 @@
|
||||
using Adobe.Substance.Input.Description;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custome GUIContent class that provides extra information for drawing input parameters.
|
||||
/// </summary>
|
||||
internal class SubstanceInputGUIContent : GUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Description info for the input SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescription Description;
|
||||
|
||||
public SerializedProperty DataProp;
|
||||
|
||||
public SubstanceInputGUIContent(SubstanceInputDescription description, SerializedProperty dataProp) : base(description.Label, description.Identifier)
|
||||
{
|
||||
Description = description;
|
||||
DataProp = dataProp;
|
||||
}
|
||||
|
||||
public SubstanceInputGUIContent(SubstanceInputDescription description, SerializedProperty dataProp, string text) : base(text)
|
||||
{
|
||||
Description = description;
|
||||
DataProp = dataProp;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4796d6b0fe84aa64d9385f2fe71bb4bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,173 @@
|
||||
using Adobe.Substance;
|
||||
using Adobe.Substance.Input.Description;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal class SubstanceInt4GUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalInt4 NumericalDescription;
|
||||
|
||||
public SubstanceInt4GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt4 numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceInt4GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt4 numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceInt3GUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalInt3 NumericalDescription;
|
||||
|
||||
public SubstanceInt3GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt3 numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceInt3GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt3 numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceInt2GUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalInt2 NumericalDescription;
|
||||
|
||||
public SubstanceInt2GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt2 numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceInt2GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt2 numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceIntGUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalInt NumericalDescription;
|
||||
|
||||
public SubstanceIntGUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceIntGUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalInt numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceFloat4GUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalFloat4 NumericalDescription;
|
||||
|
||||
public SubstanceFloat4GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat4 numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceFloat4GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat4 numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceFloat3GUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalFloat3 NumericalDescription;
|
||||
|
||||
public SubstanceFloat3GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat3 numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceFloat3GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat3 numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceFloat2GUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalFloat2 NumericalDescription;
|
||||
|
||||
public SubstanceFloat2GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat2 numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceFloat2GUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat2 numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceFloatGUIContent : SubstanceInputGUIContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Numerical input description for the target SerializedProperty.
|
||||
/// </summary>
|
||||
public SubstanceInputDescNumericalFloat NumericalDescription;
|
||||
|
||||
public SubstanceFloatGUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat numDescription) : base(description, dataProp)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
|
||||
public SubstanceFloatGUIContent(SubstanceInputDescription description, SerializedProperty dataProp, SubstanceInputDescNumericalFloat numDescription, string text) : base(description, dataProp, text)
|
||||
{
|
||||
NumericalDescription = numDescription;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceIntComboBoxGUIContent : SubstanceIntGUIContent
|
||||
{
|
||||
public GUIContent[] EnumValuesGUI { get; }
|
||||
|
||||
public int[] EnumValues { get; }
|
||||
|
||||
public SubstanceIntComboBoxGUIContent(SubstanceInputDescription description, SubstanceInputDescNumericalInt intDescription, SerializedProperty dataProp) : base(description, dataProp, intDescription)
|
||||
{
|
||||
var enumValues = intDescription.EnumValues;
|
||||
|
||||
EnumValuesGUI = new GUIContent[enumValues.Length];
|
||||
EnumValues = new int[enumValues.Length];
|
||||
|
||||
for (int i = 0; i < EnumValuesGUI.Length; i++)
|
||||
{
|
||||
var enumElement = enumValues[i];
|
||||
EnumValuesGUI[i] = new GUIContent(enumElement.Label);
|
||||
EnumValues[i] = enumElement.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ee2316ba345eed46837d35e55cfa832
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88b3a286e79783948aac3ed8572e25f1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,200 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Threading.Tasks;
|
||||
using Adobe.Substance;
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
|
||||
using UnityEditor.AssetImporters;
|
||||
|
||||
#else
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
#endif
|
||||
|
||||
namespace Adobe.SubstanceEditor.Importer
|
||||
{
|
||||
internal class SubstanceAssetModificationProcessor : UnityEditor.AssetModificationProcessor
|
||||
{
|
||||
public static AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions rao)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetPath))
|
||||
return AssetDeleteResult.DidNotDelete;
|
||||
|
||||
if (AssetDatabase.IsValidFolder(assetPath))
|
||||
return CanDeleteFolder(assetPath, rao) ? AssetDeleteResult.DidNotDelete : AssetDeleteResult.FailedDelete;
|
||||
|
||||
var substanceInstance = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(assetPath);
|
||||
|
||||
if (substanceInstance != null)
|
||||
{
|
||||
if (substanceInstance.FlagedForDelete || !File.Exists(substanceInstance.AssetPath))
|
||||
{
|
||||
return AssetDeleteResult.DidNotDelete;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"The target file cannot be manually deleted because it is associated with {substanceInstance.AssetPath}. In order to delete it, first the .sbsar file must be deleted.");
|
||||
return AssetDeleteResult.FailedDelete;
|
||||
}
|
||||
}
|
||||
|
||||
if (Path.GetExtension(assetPath.ToLower()) != ".sbsar")
|
||||
return AssetDeleteResult.DidNotDelete;
|
||||
|
||||
SubstanceImporter importer = AssetImporter.GetAtPath(assetPath) as SubstanceImporter;
|
||||
|
||||
if (importer != null)
|
||||
{
|
||||
foreach (var materialInstance in importer._fileAsset.GetGraphs())
|
||||
{
|
||||
if (materialInstance == null)
|
||||
continue;
|
||||
|
||||
SubstanceEditorEngine.instance.ReleaseInstance(materialInstance);
|
||||
materialInstance.FlagedForDelete = true;
|
||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(materialInstance));
|
||||
}
|
||||
}
|
||||
|
||||
return AssetDeleteResult.DidNotDelete;
|
||||
}
|
||||
|
||||
public static AssetMoveResult OnWillMoveAsset(string from, string to)
|
||||
{
|
||||
if (string.IsNullOrEmpty(from))
|
||||
return AssetMoveResult.DidNotMove;
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
if (Path.GetExtension(from.ToLower()) == ".asset")
|
||||
{
|
||||
var substanceInstance = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(from);
|
||||
|
||||
if (substanceInstance != null)
|
||||
{
|
||||
substanceInstance.Move(to);
|
||||
}
|
||||
else
|
||||
{
|
||||
SubstanceEditorEngine.instance.PushMoveOperation(from, to);
|
||||
}
|
||||
|
||||
return AssetMoveResult.DidNotMove;
|
||||
}
|
||||
|
||||
if (Path.GetExtension(from.ToLower()) != ".sbsar")
|
||||
return AssetMoveResult.DidNotMove;
|
||||
|
||||
var importer = AssetImporter.GetAtPath(from) as SubstanceImporter;
|
||||
|
||||
if (importer != null)
|
||||
{
|
||||
var so = new SerializedObject(importer);
|
||||
var prop = so.FindProperty("_assetPath");
|
||||
|
||||
if (prop != null && !string.IsNullOrEmpty(prop.stringValue))
|
||||
{
|
||||
prop.stringValue = to;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh(ImportAssetOptions.Default);
|
||||
|
||||
var fileObject = AssetDatabase.LoadAssetAtPath<SubstanceFileSO>(from);
|
||||
|
||||
foreach (var materialInstance in fileObject.GetGraphs())
|
||||
materialInstance.AssetPath = to;
|
||||
|
||||
return AssetMoveResult.DidNotMove;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the target folder has sbsar file generated assets that can be deleted or not.
|
||||
/// </summary>
|
||||
/// <param name="assetPath">Path to the target folder.</param>
|
||||
/// <param name="rao">Remove asset options.</param>
|
||||
/// <returns>True if the folder can be deleted.</returns>
|
||||
private static bool CanDeleteFolder(string assetPath, RemoveAssetOptions rao)
|
||||
{
|
||||
var assetsGUIDs = AssetDatabase.FindAssets($"t:{nameof(SubstanceGraphSO)}", new[] { assetPath });
|
||||
|
||||
foreach (var guid in assetsGUIDs)
|
||||
{
|
||||
var targetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
|
||||
var substanceInstance = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(targetPath);
|
||||
|
||||
if (substanceInstance != null)
|
||||
{
|
||||
if (!substanceInstance.FlagedForDelete && File.Exists(substanceInstance.AssetPath))
|
||||
{
|
||||
Debug.LogWarning($"The target folder cannot be deleted manually because it has assets associated with {substanceInstance.AssetPath}. In order to delete it, first the .sbsar file must be deleted.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Importer for Substance Material Assets using the .sbsar extension .
|
||||
/// </summary>
|
||||
[ScriptedImporter(Adobe.Substance.Version.ImporterVersion, "sbsar")]
|
||||
public sealed class SubstanceImporter : ScriptedImporter
|
||||
{
|
||||
[SerializeField]
|
||||
public SubstanceFileSO _fileAsset;
|
||||
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
{
|
||||
var rawData = ScriptableObject.CreateInstance<SubstanceFileRawData>();
|
||||
rawData.FileContent = File.ReadAllBytes(ctx.assetPath);
|
||||
rawData.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
|
||||
ctx.AddObjectToAsset("Substance Data", rawData);
|
||||
|
||||
_fileAsset = ScriptableObject.CreateInstance<SubstanceFileSO>();
|
||||
|
||||
CreateSubstanceFile(ctx, rawData);
|
||||
|
||||
ctx.AddObjectToAsset("Substance File", _fileAsset);
|
||||
ctx.SetMainObject(_fileAsset);
|
||||
}
|
||||
|
||||
public SubstanceGraphSO GetDefaultGraph()
|
||||
{
|
||||
var graphs = _fileAsset.GetGraphs();
|
||||
|
||||
if (graphs == null || graphs.Count == 0)
|
||||
return null;
|
||||
|
||||
return graphs[0];
|
||||
}
|
||||
|
||||
private void CreateSubstanceFile(AssetImportContext ctx, SubstanceFileRawData rawData)
|
||||
{
|
||||
var graphCount = Engine.GetFileGraphCount(rawData.FileContent);
|
||||
|
||||
var initInfos = new List<EditorTools.SubstanceInstanceInfo>();
|
||||
|
||||
for (int i = 0; i < graphCount; i++)
|
||||
{
|
||||
var guid = System.Guid.NewGuid().ToString();
|
||||
|
||||
initInfos.Add(new EditorTools.SubstanceInstanceInfo()
|
||||
{
|
||||
GUID = guid,
|
||||
Index = i,
|
||||
IsRoot = true,
|
||||
Name = $"graph_{i}"
|
||||
});
|
||||
}
|
||||
|
||||
EditorTools.CreateSubstanceInstanceAsync(ctx.assetPath, rawData, initInfos);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dda12f74ff9116a42b23482252b2c482
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,643 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Text.RegularExpressions;
|
||||
using Adobe.Substance;
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
|
||||
using UnityEditor.AssetImporters;
|
||||
|
||||
#else
|
||||
using UnityEditor.Experimental.AssetImporters;
|
||||
#endif
|
||||
|
||||
namespace Adobe.SubstanceEditor.Importer
|
||||
{
|
||||
[CustomEditor(typeof(SubstanceImporter)), CanEditMultipleObjects]
|
||||
internal class SubstanceImporterEditor : ScriptedImporterEditor
|
||||
{
|
||||
protected override bool needsApplyRevert => false;
|
||||
|
||||
public override bool showImportedObject => false;
|
||||
|
||||
private int _selectedInstance = 0;
|
||||
|
||||
//Size of the preview thumbnail for instances in the list.
|
||||
private const int _instanceListPreviewSize = 64;
|
||||
|
||||
private const int _isntanceListElementSpacing = 0;
|
||||
|
||||
private Vector2 _scrollPosition = Vector2.zero;
|
||||
|
||||
public SubstanceImporter _importer;
|
||||
|
||||
public List<SubstanceGraphSO> _graphs;
|
||||
|
||||
public string _tempLabelName;
|
||||
|
||||
private Dictionary<SubstanceGraphSO, SubstanceGraphSOEditor> _elementsEditors;
|
||||
|
||||
private Dictionary<SubstanceGraphSO, MaterialEditor> _previewEditors;
|
||||
|
||||
private SubstanceGraphSOEditor _currentEditor;
|
||||
|
||||
private Texture2D _backgroundImage = default;
|
||||
|
||||
private Texture2D _textHightlightBackground = default;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_elementsEditors = new Dictionary<SubstanceGraphSO, SubstanceGraphSOEditor>();
|
||||
_previewEditors = new Dictionary<SubstanceGraphSO, MaterialEditor>();
|
||||
_importer = target as SubstanceImporter;
|
||||
_graphs = _importer._fileAsset.GetGraphs();
|
||||
|
||||
EditorApplication.projectWindowItemOnGUI += OnHierarchyWindowItemOnGUI;
|
||||
Undo.undoRedoPerformed += UndoCallback;
|
||||
EnsureRefreshedMaterials();
|
||||
EnsureRequiredTextures();
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
EditorApplication.projectWindowItemOnGUI -= OnHierarchyWindowItemOnGUI;
|
||||
Undo.undoRedoPerformed -= UndoCallback;
|
||||
SaveCurrentInsatance();
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
private void SaveCurrentInsatance()
|
||||
{
|
||||
if (_currentEditor != null)
|
||||
{
|
||||
_currentEditor.SaveEditorChanges();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_graphs == null || _graphs.Count <= _selectedInstance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var currentInstance = _graphs[_selectedInstance];
|
||||
|
||||
if (_elementsEditors.TryGetValue(currentInstance, out SubstanceGraphSOEditor editor))
|
||||
editor.SaveEditorChanges();
|
||||
}
|
||||
|
||||
private void UndoCallback()
|
||||
{
|
||||
if (Selection.activeObject is SubstanceFileSO)
|
||||
{
|
||||
var target = Selection.activeObject as SubstanceFileSO;
|
||||
|
||||
if (_importer._fileAsset == target)
|
||||
{
|
||||
var targetGraph = _graphs[_selectedInstance];
|
||||
targetGraph.RenderTextures = true;
|
||||
SubstanceEditorEngine.instance.PushAllInputsToUpdate();
|
||||
EditorUtility.SetDirty(targetGraph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static void OnHierarchyWindowItemOnGUI(string guid, Rect rt)
|
||||
{
|
||||
var currentEvent = Event.current;
|
||||
|
||||
if ("Duplicate" == currentEvent.commandName && currentEvent.type == EventType.ExecuteCommand)
|
||||
{
|
||||
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
|
||||
if (Path.GetExtension(assetPath) == ".sbsar")
|
||||
{
|
||||
Debug.LogWarning("Substance graph can not be manually duplicated.");
|
||||
currentEvent.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Draw Body
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawMainUI();
|
||||
}
|
||||
|
||||
private void DrawMainUI()
|
||||
{
|
||||
if (_graphs.Count == 0)
|
||||
return;
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
{
|
||||
//Draw instances list.
|
||||
EditorGUILayout.BeginVertical();
|
||||
DrawInstancesListSection();
|
||||
EditorGUILayout.EndVertical();
|
||||
DrawUILine();
|
||||
|
||||
//Draw shader UI.
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
DrawShaderSelectionSection();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
DrawUILine();
|
||||
|
||||
//Draw selected instance properties.
|
||||
EditorGUILayout.BeginVertical();
|
||||
DrawSelectedInstanceProperties(_graphs[_selectedInstance]);
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void DrawInstancesListSection()
|
||||
{
|
||||
int numGraphs = _graphs.Count;
|
||||
|
||||
if (numGraphs == 0)
|
||||
return;
|
||||
|
||||
//Instance UI width = preview texture size + padding.
|
||||
float entryWidth = _instanceListPreviewSize + 16;
|
||||
|
||||
//Instance UI height = preview texture size + name text.
|
||||
float entryHeight = _instanceListPreviewSize + EditorGUIUtility.singleLineHeight;
|
||||
|
||||
EditorGUILayout.LabelField("Substance Graphs");
|
||||
EditorGUILayout.Space();
|
||||
|
||||
using (var scrollViewScope = new EditorGUILayout.ScrollViewScope(_scrollPosition, false, false))
|
||||
{
|
||||
scrollViewScope.handleScrollWheel = false;
|
||||
_scrollPosition = scrollViewScope.scrollPosition;
|
||||
|
||||
var listStyle = new GUIStyle();
|
||||
listStyle.padding = new RectOffset(15, 15, 15, 15);
|
||||
|
||||
var rect = EditorGUILayout.BeginHorizontal(listStyle);
|
||||
{
|
||||
//Gray area
|
||||
var targetRect = new Rect(rect.x + 5, rect.y, rect.width - 10, rect.height);
|
||||
DrawGrayRectangle(targetRect);
|
||||
|
||||
//Text styles
|
||||
var normalTextStyle = new GUIStyle();
|
||||
normalTextStyle.wordWrap = true;
|
||||
normalTextStyle.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
normalTextStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f, 1);
|
||||
|
||||
var highlightTextStyle = new GUIStyle();
|
||||
highlightTextStyle.alignment = TextAnchor.MiddleCenter;
|
||||
highlightTextStyle.normal.textColor = Color.white;
|
||||
highlightTextStyle.normal.background = _textHightlightBackground;
|
||||
highlightTextStyle.wordWrap = true;
|
||||
|
||||
for (int instanceIndex = 0; instanceIndex < numGraphs; instanceIndex++)
|
||||
{
|
||||
if (TryGetInstanceByIndex(instanceIndex, out SubstanceGraphSO instance))
|
||||
{
|
||||
EditorGUILayout.BeginVertical(GUILayout.Width(entryWidth), GUILayout.Height(entryHeight));
|
||||
{
|
||||
DrawListElement(instance, instanceIndex, entryWidth - 12, normalTextStyle, highlightTextStyle);
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
GUILayout.Space(_isntanceListElementSpacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
DrawAddAndRemove();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawGrayRectangle(Rect rect)
|
||||
{
|
||||
var style = new GUIStyle();
|
||||
style.normal.background = _backgroundImage;
|
||||
GUI.Box(rect, GUIContent.none, style);
|
||||
}
|
||||
|
||||
private void DrawListElement(SubstanceGraphSO instance, int instanceIndex, float entryWidth, GUIStyle normalStyle, GUIStyle highlightStyle)
|
||||
{
|
||||
Material graphMaterial = instance.OutputMaterial;
|
||||
|
||||
if (graphMaterial == null)
|
||||
return;
|
||||
|
||||
Texture2D miniThumbnail = AssetPreview.GetAssetPreview(graphMaterial);
|
||||
|
||||
if (GUILayout.Button(miniThumbnail, GUILayout.Width(_instanceListPreviewSize),
|
||||
GUILayout.Height(_instanceListPreviewSize)))
|
||||
{
|
||||
OnInstanceSelected(instanceIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (instanceIndex != _selectedInstance)
|
||||
{
|
||||
GUILayout.Label(instance.Name, normalStyle, GUILayout.Width(entryWidth));
|
||||
return;
|
||||
}
|
||||
|
||||
var label = _tempLabelName ?? instance.Name;
|
||||
_tempLabelName = GUILayout.TextField(label, highlightStyle, GUILayout.Width(entryWidth));
|
||||
|
||||
if (!_tempLabelName.Equals(instance.Name, StringComparison.Ordinal))
|
||||
{
|
||||
Event e = Event.current;
|
||||
if (e.keyCode == KeyCode.Return)
|
||||
{
|
||||
if (e.type == EventType.KeyUp)
|
||||
{
|
||||
if (!TryRenameInstance(instance, _tempLabelName))
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error", "The provided name can't be assigned to a substance instance.", "Ok");
|
||||
_tempLabelName = instance.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAddAndRemove()
|
||||
{
|
||||
if (GUILayout.Button("Copy graph"))
|
||||
{
|
||||
CreateNewInstance();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Delete graph"))
|
||||
{
|
||||
if (TryGetSelectedInstance(out SubstanceGraphSO instanceSO))
|
||||
{
|
||||
DeleteInstance(instanceSO);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawShaderSelectionSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("Shader", GUILayout.Width(55));
|
||||
|
||||
if (!TryGetCurrentGraph(out SubstanceGraphSO graph))
|
||||
return;
|
||||
|
||||
if (graph.OutputMaterial == null || graph.OutputMaterial.shader == null)
|
||||
return;
|
||||
|
||||
var currentShader = graph.OutputMaterial.shader;
|
||||
|
||||
var shaderNames = ShaderUtil.GetAllShaderInfo().Select((a) => a.name).Where(b => !b.StartsWith("Hidden") && !b.StartsWith("GUI")).ToArray();
|
||||
var selectedElement = shaderNames.FirstOrDefault(a => a == currentShader.name);
|
||||
var selectedIndex = Array.IndexOf(shaderNames, selectedElement);
|
||||
|
||||
var newSelected = EditorGUILayout.Popup(selectedIndex, shaderNames, GUILayout.MaxWidth(320));
|
||||
|
||||
if (newSelected != selectedIndex)
|
||||
{
|
||||
var newSelectedElement = shaderNames[newSelected];
|
||||
_graphs[_selectedInstance].OutputMaterial.shader = Shader.Find(newSelectedElement);
|
||||
EditorUtility.SetDirty(_graphs[_selectedInstance].OutputMaterial);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Edit", GUILayout.MaxWidth(60)))
|
||||
{
|
||||
EditorUtility.FocusProjectWindow();
|
||||
Selection.activeObject = currentShader;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSelectedInstanceProperties(SubstanceGraphSO currentInstance)
|
||||
{
|
||||
if (!_elementsEditors.TryGetValue(currentInstance, out SubstanceGraphSOEditor editor))
|
||||
{
|
||||
editor = SubstanceGraphSOEditor.CreateEditor(currentInstance) as SubstanceGraphSOEditor;
|
||||
_elementsEditors.Add(currentInstance, editor);
|
||||
}
|
||||
|
||||
if (_currentEditor != null && _currentEditor != editor)
|
||||
{
|
||||
_currentEditor.SaveEditorChanges();
|
||||
}
|
||||
|
||||
_currentEditor = editor;
|
||||
editor.OnInspectorGUI();
|
||||
}
|
||||
|
||||
#endregion Draw Body
|
||||
|
||||
#region Static Preview
|
||||
|
||||
public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height)
|
||||
{
|
||||
if (_importer == null)
|
||||
return null;
|
||||
|
||||
if (_graphs[0] == null)
|
||||
return null;
|
||||
|
||||
if (_graphs[0].HasThumbnail)
|
||||
{
|
||||
return _graphs[0].GetThumbnailTexture();
|
||||
}
|
||||
else
|
||||
{
|
||||
var icon = UnityPackageInfo.GetSubstanceIcon(width, height);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
Texture2D tex = new Texture2D(width, height);
|
||||
EditorUtility.CopySerialized(icon, tex);
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
||||
return base.RenderStaticPreview(assetPath, subAssets, width, height);
|
||||
}
|
||||
|
||||
#endregion Static Preview
|
||||
|
||||
#region Preview
|
||||
|
||||
public override bool HasPreviewGUI()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override GUIContent GetPreviewTitle()
|
||||
{
|
||||
if (!TryGetCurrentGraph(out SubstanceGraphSO graph))
|
||||
return new GUIContent("Material", null, "");
|
||||
|
||||
if (graph.OutputMaterial == null)
|
||||
return new GUIContent("Material", null, "");
|
||||
|
||||
if (string.IsNullOrEmpty(graph.OutputMaterial.name))
|
||||
return new GUIContent("Material", null, "");
|
||||
|
||||
return new GUIContent(graph.OutputMaterial.name, null, "");
|
||||
}
|
||||
|
||||
public override void OnPreviewSettings()
|
||||
{
|
||||
if (_graphs == null || _graphs.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("No graphs found. Please make sure to not rename folders with that are managed by the Substance Plugin.");
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedInstance = _graphs[_selectedInstance];
|
||||
|
||||
if (selectedInstance == null)
|
||||
return;
|
||||
|
||||
if (!_previewEditors.TryGetValue(selectedInstance, out MaterialEditor editor))
|
||||
{
|
||||
var material = selectedInstance?.OutputMaterial;
|
||||
|
||||
if (material != null)
|
||||
{
|
||||
editor = MaterialEditor.CreateEditor(material) as MaterialEditor;
|
||||
_previewEditors.Add(selectedInstance, editor);
|
||||
}
|
||||
}
|
||||
|
||||
if (editor != null)
|
||||
editor.OnPreviewSettings();
|
||||
}
|
||||
|
||||
public override void OnPreviewGUI(Rect r, GUIStyle background)
|
||||
{
|
||||
if (_graphs == null || _graphs.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("No graphs found. Please make sure to not rename folders with that are managed by the Substance Plugin.");
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedInstance = _graphs[_selectedInstance];
|
||||
|
||||
if (selectedInstance == null)
|
||||
return;
|
||||
|
||||
if (!_previewEditors.TryGetValue(selectedInstance, out MaterialEditor editor))
|
||||
{
|
||||
var material = selectedInstance?.OutputMaterial;
|
||||
|
||||
if (material != null)
|
||||
{
|
||||
editor = MaterialEditor.CreateEditor(material) as MaterialEditor;
|
||||
_previewEditors.Add(selectedInstance, editor);
|
||||
}
|
||||
}
|
||||
|
||||
if (editor != null)
|
||||
editor.OnPreviewGUI(r, background);
|
||||
}
|
||||
|
||||
public override void DrawPreview(Rect previewArea)
|
||||
{
|
||||
OnPreviewGUI(previewArea, new GUIStyle());
|
||||
}
|
||||
|
||||
#endregion Preview
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a SubstanceGraphSO with a copy of the values from the current selected instance.
|
||||
/// </summary>
|
||||
/// <param name="name">Name for the new instance.</param>
|
||||
/// <param name="currentInstance">Current selected instance.</param>
|
||||
private void CreateNewInstance()
|
||||
{
|
||||
if (!TryGetSelectedInstance(out SubstanceGraphSO rootInstance))
|
||||
{
|
||||
if (!TryGetInstanceByIndex(0, out rootInstance))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var newInstanceName = GenerateNewInstanceName(rootInstance);
|
||||
|
||||
var instanceAsset = EditorTools.CreateSubstanceInstance(_importer.assetPath, rootInstance.RawData, newInstanceName, rootInstance.GetNativeID(), System.Guid.NewGuid().ToString(), copy: rootInstance);
|
||||
SubstanceEditorEngine.instance.RenderInstanceAsync(instanceAsset);
|
||||
|
||||
_graphs.Add(instanceAsset);
|
||||
EditorUtility.SetDirty(_importer);
|
||||
AssetDatabase.Refresh();
|
||||
_selectedInstance = _graphs.Count - 1;
|
||||
ResetTempName();
|
||||
}
|
||||
|
||||
private void DeleteInstance(SubstanceGraphSO instance)
|
||||
{
|
||||
if (instance.IsRoot)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Invalid operation", "Can't delete root instance.", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
_graphs.Remove(instance);
|
||||
EditorUtility.SetDirty(_importer);
|
||||
|
||||
SubstanceEditorEngine.instance.ReleaseInstance(instance);
|
||||
instance.FlagedForDelete = true;
|
||||
EditorUtility.SetDirty(instance);
|
||||
|
||||
var assetPath = AssetDatabase.GetAssetPath(instance);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
AssetDatabase.Refresh();
|
||||
_selectedInstance = 0;
|
||||
ResetTempName();
|
||||
}
|
||||
|
||||
private void OnInstanceSelected(int instanceIndex)
|
||||
{
|
||||
_selectedInstance = instanceIndex;
|
||||
|
||||
if (TryGetSelectedInstance(out SubstanceGraphSO target))
|
||||
EditorGUIUtility.PingObject(target);
|
||||
|
||||
ResetTempName();
|
||||
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
private bool TryRenameInstance(SubstanceGraphSO instanceSO, string name)
|
||||
{
|
||||
if (!IsValidAndNoConflict(name))
|
||||
return false;
|
||||
|
||||
instanceSO.Rename(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Utilities
|
||||
|
||||
private string GenerateNewInstanceName(SubstanceGraphSO currentInstance)
|
||||
{
|
||||
var index = _graphs.Count;
|
||||
var newName = currentInstance.Name + $"_copy";
|
||||
|
||||
while (!IsValidAndNoConflict(newName))
|
||||
newName = currentInstance.Name + $"__copy{index++}";
|
||||
|
||||
return newName;
|
||||
}
|
||||
|
||||
private bool IsValidAndNoConflict(string name)
|
||||
{
|
||||
if (!IsValidName(name))
|
||||
return false;
|
||||
|
||||
if (_graphs.Where(a => a != null).FirstOrDefault(a => a.Name == name) != null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsValidName(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name) || string.IsNullOrWhiteSpace(name))
|
||||
return false;
|
||||
|
||||
Regex containsABadCharacter = new Regex("[" + Regex.Escape(new string(Path.GetInvalidFileNameChars())) + "]");
|
||||
|
||||
if (containsABadCharacter.IsMatch(name))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetCurrentGraph(out SubstanceGraphSO graph)
|
||||
{
|
||||
graph = null;
|
||||
|
||||
if (!TryGetSelectedInstance(out graph))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetInstanceByIndex(int index, out SubstanceGraphSO instance)
|
||||
{
|
||||
instance = null;
|
||||
|
||||
if (_importer == null || _graphs == null || _graphs.Count == 0)
|
||||
return false;
|
||||
|
||||
if (_graphs.Count <= index)
|
||||
return false;
|
||||
|
||||
instance = _graphs[index];
|
||||
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
private bool TryGetSelectedInstance(out SubstanceGraphSO instance)
|
||||
{
|
||||
return TryGetInstanceByIndex(_selectedInstance, out instance);
|
||||
}
|
||||
|
||||
private static void DrawUILine()
|
||||
{
|
||||
var rect = EditorGUILayout.BeginVertical();
|
||||
{
|
||||
Handles.color = Color.black;
|
||||
EditorGUILayout.Space(15);
|
||||
Handles.DrawLine(new Vector2(rect.x - 40, rect.y + (rect.height / 2)), new Vector2(rect.width + 20, rect.y + (rect.height / 2)));
|
||||
EditorGUILayout.Space(15);
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void ResetTempName()
|
||||
{
|
||||
if (TryGetSelectedInstance(out SubstanceGraphSO material))
|
||||
_tempLabelName = material.Name;
|
||||
}
|
||||
|
||||
private void EnsureRequiredTextures()
|
||||
{
|
||||
float c = (EditorGUIUtility.isProSkin) ? 0.35f : 0.65f;
|
||||
_backgroundImage = Globals.CreateColoredTexture(64, 64, new Color(c, c, c, 1));
|
||||
_textHightlightBackground = Globals.CreateColoredTexture(_instanceListPreviewSize, _instanceListPreviewSize, Color.gray);
|
||||
}
|
||||
|
||||
private void EnsureRefreshedMaterials()
|
||||
{
|
||||
foreach (var instance in _graphs)
|
||||
{
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
var material = instance.OutputMaterial;
|
||||
|
||||
if (material == null)
|
||||
continue;
|
||||
|
||||
EditorUtility.SetDirty(material);
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
#endregion Utilities
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87dac30333bc79345bec7a3b39edcc45
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c179733d89e9d09458a2e90cf842d409
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,115 @@
|
||||
using Adobe.Substance;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class UnityPackageInfo
|
||||
{
|
||||
public const string PackageName = "com.adobe.substanceforunity";
|
||||
|
||||
private static UnityEditor.PackageManager.PackageInfo _cachedPackageInfo = null;
|
||||
|
||||
private static string IconPath_256 => $"{PathUtils.SubstanceRootPath}/Editor/Assets/Logo_256.png";
|
||||
private static string IconPath_128 => $"{PathUtils.SubstanceRootPath}/Editor/Assets/Logo_128.png";
|
||||
private static string IconPath_64 = $"{PathUtils.SubstanceRootPath}/Editor/Assets/Logo_64.png";
|
||||
private static string IconPath_32 = $"{PathUtils.SubstanceRootPath}/Editor/Assets/Logo_32.png";
|
||||
|
||||
private static Texture2D _cachedIcon256 = null;
|
||||
private static Texture2D _cachedIcon128 = null;
|
||||
private static Texture2D _cachedIcon64 = null;
|
||||
private static Texture2D _cachedIcon32 = null;
|
||||
|
||||
public static UnityEditor.PackageManager.PackageInfo GetPackageInfo()
|
||||
{
|
||||
#pragma warning disable 162
|
||||
if (!PathUtils.UsingPackageManager)
|
||||
return null;
|
||||
#pragma warning restore 162
|
||||
|
||||
if (_cachedPackageInfo != null)
|
||||
return _cachedPackageInfo;
|
||||
|
||||
var packageInfoRequest = UnityEditor.PackageManager.Client.List(true);
|
||||
|
||||
while (packageInfoRequest.Status == UnityEditor.PackageManager.StatusCode.InProgress)
|
||||
continue;
|
||||
|
||||
var packages = packageInfoRequest.Result?.FirstOrDefault(a => a.name == PackageName);
|
||||
|
||||
if (packages != null)
|
||||
_cachedPackageInfo = packages;
|
||||
|
||||
return _cachedPackageInfo;
|
||||
}
|
||||
|
||||
public static Texture2D GetSubstanceIcon(int width, int height)
|
||||
{
|
||||
if (width != height)
|
||||
return GetSubstanceIconResized(width, height);
|
||||
|
||||
switch (width)
|
||||
{
|
||||
case 256:
|
||||
return GetSubstanceIcon256();
|
||||
|
||||
case 128:
|
||||
return GetSubstanceIcon128();
|
||||
|
||||
case 64:
|
||||
return GetSubstanceIcon64();
|
||||
|
||||
case 32:
|
||||
return GetSubstanceIcon32();
|
||||
|
||||
default:
|
||||
return GetSubstanceIconResized(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture2D GetSubstanceIconResized(int width, int height)
|
||||
{
|
||||
var icon = GetSubstanceIcon256();
|
||||
Texture2D tex = new Texture2D(width, height);
|
||||
EditorUtility.CopySerialized(icon, tex);
|
||||
return tex;
|
||||
}
|
||||
|
||||
public static Texture2D GetSubstanceIcon256()
|
||||
{
|
||||
if (_cachedIcon256 != null)
|
||||
return _cachedIcon256;
|
||||
|
||||
_cachedIcon256 = AssetDatabase.LoadAssetAtPath<Texture2D>(IconPath_256);
|
||||
return _cachedIcon256;
|
||||
}
|
||||
|
||||
public static Texture2D GetSubstanceIcon128()
|
||||
{
|
||||
if (_cachedIcon128 != null)
|
||||
return _cachedIcon128;
|
||||
|
||||
_cachedIcon128 = AssetDatabase.LoadAssetAtPath<Texture2D>(IconPath_128);
|
||||
return _cachedIcon128;
|
||||
}
|
||||
|
||||
public static Texture2D GetSubstanceIcon64()
|
||||
{
|
||||
if (_cachedIcon64 != null)
|
||||
return _cachedIcon64;
|
||||
|
||||
_cachedIcon64 = AssetDatabase.LoadAssetAtPath<Texture2D>(IconPath_64);
|
||||
return _cachedIcon64;
|
||||
}
|
||||
|
||||
public static Texture2D GetSubstanceIcon32()
|
||||
{
|
||||
if (_cachedIcon32 != null)
|
||||
return _cachedIcon32;
|
||||
|
||||
_cachedIcon32 = AssetDatabase.LoadAssetAtPath<Texture2D>(IconPath_32);
|
||||
return _cachedIcon32;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72cba7e39e029164f841301c6320fd30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 741dbc64474bb4d4683c75c99534538a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,29 @@
|
||||
using Adobe.Substance;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor.ProjectSettings
|
||||
{
|
||||
internal static class Extensions
|
||||
{
|
||||
public static void DrawAboutWindow()
|
||||
{
|
||||
string aboutMessage = "Plugin Info:\n";
|
||||
aboutMessage += "Package Name: Substance 3D for Unity" + "\n";
|
||||
aboutMessage += "Package Version: " + Version.PluginVersion + "\n";
|
||||
aboutMessage += "Engine Version: " + Version.EngineVersion + "\n";
|
||||
|
||||
bool state = EditorUtility.DisplayDialog("About Substance 3D", aboutMessage, "Copy to clipboard", "Close");
|
||||
|
||||
if (state == true)
|
||||
{
|
||||
// Copy to clipboard:
|
||||
TextEditor _textEditor = new TextEditor();
|
||||
_textEditor.text = aboutMessage;
|
||||
_textEditor.OnFocus();
|
||||
_textEditor.Copy();
|
||||
DrawAboutWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd5f8823e57c3e04fbc09267e76055db
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,191 @@
|
||||
using Adobe.Substance;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Adobe.SubstanceEditor.ProjectSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Settings provider for the Adobe Substance tab in the Unity project settings UI.
|
||||
/// </summary>
|
||||
internal class SubstanceEditorSettingsProvider : SettingsProvider
|
||||
{
|
||||
private const string substanceURL = "https://substance3d.adobe.com/assets/";
|
||||
|
||||
private SerializedObject _editorSettings;
|
||||
|
||||
private SerializedProperty _generateAllTextureProp;
|
||||
|
||||
private SerializedProperty _targetResolutionProp;
|
||||
|
||||
private static string SubstanceAssetLogoPath => $"{PathUtils.SubstanceRootPath}/Editor/Assets/S_3DHeart_18_N_nudged.png";
|
||||
private static string SubstanceCommunityAssetLogoPath => $"{PathUtils.SubstanceRootPath}/Editor/Assets/S_3DCummunityAssets_18_N.png";
|
||||
|
||||
private const string SubstanceCommunityURL = "https://substance3d.adobe.com/community-assets";
|
||||
|
||||
private const string SubstanceAssetURL = "https://substance3d.adobe.com/assets";
|
||||
|
||||
private class Contents
|
||||
{
|
||||
public static readonly GUIContent GenerateAllTexturesText = new GUIContent("Generate all outputs", "Generate all output textures for the substance graphs.");
|
||||
public static readonly GUIContent TextureResoltuionText = new GUIContent("Texture resolution", "Texture resolution for all graphs outputs.");
|
||||
public static readonly GUIContent SubstanceAssetsIcon = new GUIContent();
|
||||
public static readonly GUIContent SubstanceCommunityIcon = new GUIContent();
|
||||
}
|
||||
|
||||
private class Styles
|
||||
{
|
||||
public static GUIStyle AssetButtonsStyle;
|
||||
public static readonly GUIStyle SubstanceAssetButtonsPanelStyle = new GUIStyle();
|
||||
public static readonly GUIStyle RichTextStyle = new GUIStyle() { richText = true };
|
||||
}
|
||||
|
||||
public SubstanceEditorSettingsProvider(string path, SettingsScope scope = SettingsScope.User) : base(path, scope)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnActivate(string searchContext, VisualElement rootElement)
|
||||
{
|
||||
_editorSettings = SubstanceEditorSettingsSO.GetSerializedSettings();
|
||||
_generateAllTextureProp = _editorSettings.FindProperty("_generateAllTexture");
|
||||
_targetResolutionProp = _editorSettings.FindProperty("_targetResolution");
|
||||
|
||||
Contents.SubstanceAssetsIcon.image = AssetDatabase.LoadAssetAtPath<Texture2D>(SubstanceAssetLogoPath);
|
||||
Contents.SubstanceAssetsIcon.tooltip = SubstanceAssetURL;
|
||||
|
||||
Contents.SubstanceCommunityIcon.image = AssetDatabase.LoadAssetAtPath<Texture2D>(SubstanceCommunityAssetLogoPath);
|
||||
Contents.SubstanceCommunityIcon.tooltip = SubstanceCommunityURL;
|
||||
}
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
_editorSettings.Update();
|
||||
|
||||
if (Styles.AssetButtonsStyle == null)
|
||||
{
|
||||
Styles.AssetButtonsStyle = new GUIStyle(GUI.skin.label);
|
||||
Styles.AssetButtonsStyle.fixedHeight = 24;
|
||||
Styles.AssetButtonsStyle.fixedWidth = 24;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
{
|
||||
if (_generateAllTextureProp != null)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(_generateAllTextureProp, Contents.GenerateAllTexturesText, GUILayout.Width(100));
|
||||
}
|
||||
|
||||
if (_targetResolutionProp != null)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorDrawUtilities.DrawResolutionSelection(_targetResolutionProp, Contents.TextureResoltuionText);
|
||||
}
|
||||
|
||||
DrawEngineInfo();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
DrawTextLinksAndAbout();
|
||||
//DrawAboutText();
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
_editorSettings.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void DrawEngineInfo()
|
||||
{
|
||||
string label = PlatformUtils.IsCPU() ? "CPU" : "GPU";
|
||||
var content = new GUIContent($"Computing textures with {label}", "Engine used for rendering textures");
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(content);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a hyperlink label that should redirect the user to a URL.
|
||||
/// </summary>
|
||||
/// <param name="text">Label text.</param>
|
||||
/// <param name="url">Redirect URL.</param>
|
||||
private void DrawClickableText(string text, GUIStyle style, Action callback)
|
||||
{
|
||||
var labelRect = EditorGUILayout.GetControlRect();
|
||||
|
||||
if (Event.current.type == EventType.MouseUp && labelRect.Contains(Event.current.mousePosition))
|
||||
callback();
|
||||
|
||||
GUI.Label(labelRect, text, style);
|
||||
}
|
||||
|
||||
private void DrawTextLinksAndAbout()
|
||||
{
|
||||
var textStyle = new GUIStyle();
|
||||
textStyle.normal.textColor = new Color(75f / 255f, 122f / 255f, 243f / 255f);
|
||||
textStyle.alignment = TextAnchor.LowerLeft;
|
||||
textStyle.fixedWidth = 150;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.Space(10, false);
|
||||
|
||||
if (GUILayout.Button(Contents.SubstanceAssetsIcon, Styles.AssetButtonsStyle))
|
||||
Application.OpenURL(SubstanceAssetURL);
|
||||
|
||||
DrawClickableText("Substance 3D assets", textStyle, () => Application.OpenURL(SubstanceAssetURL));
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.Space(10, false);
|
||||
|
||||
if (GUILayout.Button(Contents.SubstanceCommunityIcon, Styles.AssetButtonsStyle))
|
||||
Application.OpenURL(SubstanceCommunityURL);
|
||||
|
||||
DrawClickableText("Substance 3D community assets", textStyle, () => Application.OpenURL(SubstanceCommunityURL));
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.Space(40, false);
|
||||
DrawClickableText("About", textStyle, () => Extensions.DrawAboutWindow());
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
#region Registration
|
||||
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreateSubstanceSettingsProvider()
|
||||
{
|
||||
if (SubstanceEditorSettingsSO.IsSettingsAvailable())
|
||||
{
|
||||
return new SubstanceEditorSettingsProvider("Project/Adobe Substance 3D", SettingsScope.Project)
|
||||
{
|
||||
label = "Adobe Substance 3D",
|
||||
keywords = GetSearchKeywordsFromGUIContentProperties<Contents>()
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion Registration
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e36266595fde1a47b3add3f8a295cfe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,59 @@
|
||||
using Adobe.Substance;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor.ProjectSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Global editor settings scriptable object
|
||||
/// </summary>
|
||||
internal class SubstanceEditorSettingsSO : ScriptableObject
|
||||
{
|
||||
private static string _editorSettingsAsset => $"{PathUtils.SubstanceRootPath}/Editor/Settings/SubstanceEditorSettings.asset";
|
||||
|
||||
[SerializeField]
|
||||
private bool _generateAllTexture;
|
||||
|
||||
[SerializeField]
|
||||
private Vector2Int _targetResolution;
|
||||
|
||||
internal static SubstanceEditorSettingsSO GetOrCreateSettings()
|
||||
{
|
||||
var settings = AssetDatabase.LoadAssetAtPath<SubstanceEditorSettingsSO>(_editorSettingsAsset);
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
settings = ScriptableObject.CreateInstance<SubstanceEditorSettingsSO>();
|
||||
settings._generateAllTexture = false;
|
||||
settings._targetResolution = new Vector2Int(9, 9);
|
||||
AssetDatabase.CreateAsset(settings, _editorSettingsAsset);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static Vector2Int TextureOutputResultion()
|
||||
{
|
||||
var settigns = GetOrCreateSettings();
|
||||
return settigns._targetResolution;
|
||||
}
|
||||
|
||||
public static bool GenerateAllTextures()
|
||||
{
|
||||
var settigns = GetOrCreateSettings();
|
||||
return settigns._generateAllTexture;
|
||||
}
|
||||
|
||||
public static bool IsSettingsAvailable()
|
||||
{
|
||||
return File.Exists(_editorSettingsAsset);
|
||||
}
|
||||
|
||||
internal static SerializedObject GetSerializedSettings()
|
||||
{
|
||||
return new SerializedObject(GetOrCreateSettings());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 715e7c131b0ebdd48b77c2b2741d1dae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 846e54def7465614e9af6ed817c28f6a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,61 @@
|
||||
using Adobe.Substance;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawer
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty property, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
switch (content.Description.Type)
|
||||
{
|
||||
case SubstanceValueType.Float:
|
||||
return SubstanceInputDrawerFloat.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.Float2:
|
||||
return SubstanceInputDrawerFloat2.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.Float3:
|
||||
return SubstanceInputDrawerFloat3.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.Float4:
|
||||
return SubstanceInputDrawerFloat4.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.Int:
|
||||
return SubstanceInputDrawerInt.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.Int2:
|
||||
return SubstanceInputDrawerInt2.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.Int3:
|
||||
return SubstanceInputDrawerInt3.DrawInput(content.DataProp, content, handler, inputID); ;
|
||||
|
||||
case SubstanceValueType.Int4:
|
||||
return SubstanceInputDrawerInt4.DrawInput(property, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.Image:
|
||||
return SubstanceInputDrawerTexture.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
case SubstanceValueType.String:
|
||||
return SubstanceInputDrawerString.DrawInput(content.DataProp, content, handler, inputID);
|
||||
|
||||
default:
|
||||
return DrawDefault(property, content);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content)
|
||||
{
|
||||
if (content.Description.WidgetType == SubstanceWidgetType.NoWidget)
|
||||
{
|
||||
EditorGUILayout.LabelField($"Hidden property.");
|
||||
return false;
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.LabelField($"Not supported. Value with widget {content.Description.WidgetType}");
|
||||
EditorGUI.indentLevel--;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 291115c592a8ea648812908d840ceb8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,67 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance.Input.Description;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerFloat
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
float newValue;
|
||||
bool changed = false;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
case SubstanceWidgetType.Slider:
|
||||
changed = DrawSlider(valueProperty, content as SubstanceFloatGUIContent, out newValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content, out newValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputFloat(inputID, newValue);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static bool DrawSlider(SerializedProperty valueProperty, SubstanceFloatGUIContent content, out float newValue)
|
||||
{
|
||||
var floatInputDesc = content.NumericalDescription;
|
||||
|
||||
var maxValue = floatInputDesc.MaxValue;
|
||||
var minValue = floatInputDesc.MinValue;
|
||||
var sliderClamp = maxValue != minValue;
|
||||
|
||||
var oldValue = valueProperty.floatValue;
|
||||
|
||||
newValue = EditorGUILayout.Slider(content, oldValue, sliderClamp ? minValue : 0, sliderClamp ? maxValue : 50);
|
||||
|
||||
if (oldValue != newValue)
|
||||
{
|
||||
valueProperty.floatValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out float newValue)
|
||||
{
|
||||
var oldValue = valueProperty.floatValue;
|
||||
newValue = EditorGUILayout.FloatField(content, oldValue);
|
||||
|
||||
if (oldValue != newValue)
|
||||
{
|
||||
valueProperty.floatValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 033dbc14304ac024da91e3803dfab82f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,43 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerFloat2
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
Vector2 newValue;
|
||||
bool changed;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content, out newValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputFloat2(inputID, newValue);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector2 newValue)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
var previewValue = valueProperty.vector2Value;
|
||||
newValue = EditorGUILayout.Vector2Field(content, previewValue);
|
||||
|
||||
if (newValue != previewValue)
|
||||
{
|
||||
valueProperty.vector2Value = newValue;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a184eff873fa9f04a9cb3c6e7a45656c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,70 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerFloat3
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
Vector3 newValue;
|
||||
bool changed;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
case SubstanceWidgetType.Color:
|
||||
changed = DrawColorPicker(valueProperty, content, out newValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content, out newValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputFloat3(inputID, newValue);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders custome GUI for input float3 as color.
|
||||
/// </summary>
|
||||
/// <param name="position">GUI position rect.</param>
|
||||
/// <param name="valueProperty">Value property.</param>
|
||||
/// <param name="content">GUI content.</param>
|
||||
/// <param name="description">Description for the target input.</param>
|
||||
private static bool DrawColorPicker(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector3 newValue)
|
||||
{
|
||||
var previewValue = valueProperty.vector3Value;
|
||||
|
||||
var color = new Color(previewValue.x, previewValue.y, previewValue.z, 1);
|
||||
var newColor = EditorGUILayout.ColorField(content, color, false, false, false);
|
||||
newValue = new Vector3();
|
||||
|
||||
if (color != newColor)
|
||||
{
|
||||
newValue = new Vector4(newColor.r, newColor.g, newColor.b, newColor.a);
|
||||
valueProperty.vector3Value = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector3 newValue)
|
||||
{
|
||||
var previewValue = valueProperty.vector3Value;
|
||||
newValue = EditorGUILayout.Vector3Field(content, previewValue);
|
||||
|
||||
if (newValue != previewValue)
|
||||
{
|
||||
valueProperty.vector3Value = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd7292cd00c740040b07a24e3f49ac8f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,68 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerFloat4
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
Vector4 newValyue;
|
||||
bool changed;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
case SubstanceWidgetType.Color:
|
||||
changed = DrawColorPicker(valueProperty, content, out newValyue);
|
||||
break;
|
||||
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content, out newValyue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputFloat4(inputID, newValyue);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders custome GUI for input float4 as color.
|
||||
/// </summary>
|
||||
/// <param name="position">GUI position rect.</param>
|
||||
/// <param name="valueProperty">Value property.</param>
|
||||
/// <param name="content">GUI content.</param>
|
||||
/// <param name="description">Description for the target input.</param>
|
||||
private static bool DrawColorPicker(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector4 newValue)
|
||||
{
|
||||
var previewValue = valueProperty.vector4Value;
|
||||
|
||||
var color = new Vector4(previewValue.x, previewValue.y, previewValue.z, previewValue.w);
|
||||
newValue = EditorGUILayout.ColorField(content, color);
|
||||
|
||||
if (color != newValue)
|
||||
{
|
||||
valueProperty.vector4Value = new Vector4(newValue.x, newValue.y, newValue.z, newValue.w);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector4 newValue)
|
||||
{
|
||||
var oldValue = valueProperty.vector4Value;
|
||||
newValue = EditorGUILayout.Vector4Field(content, oldValue);
|
||||
|
||||
if (oldValue != newValue)
|
||||
{
|
||||
valueProperty.vector4Value = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b864e9955ea52c1439bd7a5e691c3e75
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,194 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance.Input.Description;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Drawer helper for int substance inputs.
|
||||
/// </summary>
|
||||
internal static class SubstanceInputDrawerInt
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws int input.
|
||||
/// </summary>
|
||||
/// <param name="valueProperty"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <returns>True if value changed.</returns>
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
int value;
|
||||
bool changed;
|
||||
|
||||
if (content.Description.Label == "$randomseed")
|
||||
{
|
||||
changed = DrawRandomSeedButton(valueProperty, content, out value);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
case SubstanceWidgetType.ToggleButton:
|
||||
changed = DrawToggleButton(valueProperty, content as SubstanceIntGUIContent, out value);
|
||||
break;
|
||||
|
||||
case SubstanceWidgetType.Slider:
|
||||
changed = DrawSlider(valueProperty, content as SubstanceIntGUIContent, out value);
|
||||
break;
|
||||
|
||||
case SubstanceWidgetType.ComboBox:
|
||||
changed = DrawComboBox(valueProperty, content as SubstanceIntGUIContent, out value);
|
||||
break;
|
||||
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content, out value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputInt(inputID, value);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the int input as a toggle button.
|
||||
/// </summary>
|
||||
/// <param name="valueProperty">Value property.</param>
|
||||
/// <param name="content">GUI content.</param>
|
||||
/// <returns>True if value changed.</returns>
|
||||
private static bool DrawToggleButton(SerializedProperty valueProperty, SubstanceIntGUIContent content, out int newValue)
|
||||
{
|
||||
newValue = 0;
|
||||
var oldValue = valueProperty.intValue != 0;
|
||||
var newValueToggle = EditorGUILayout.Toggle(content, oldValue);
|
||||
|
||||
if (oldValue != newValueToggle)
|
||||
{
|
||||
newValue = newValueToggle ? 1 : 0;
|
||||
valueProperty.intValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the int input as a slider.
|
||||
/// </summary>
|
||||
/// <param name="valueProperty">Value property.</param>
|
||||
/// <param name="content">GUI content.</param>
|
||||
/// <returns>True if value changed.</returns>
|
||||
private static bool DrawSlider(SerializedProperty valueProperty, SubstanceIntGUIContent content, out int newValue)
|
||||
{
|
||||
var numDescription = content.NumericalDescription;
|
||||
|
||||
var maxValue = numDescription.MaxValue;
|
||||
var minValue = numDescription.MinValue;
|
||||
|
||||
var oldValue = valueProperty.intValue;
|
||||
newValue = EditorGUILayout.IntSlider(content, oldValue, minValue, maxValue);
|
||||
|
||||
if (oldValue != newValue)
|
||||
{
|
||||
valueProperty.intValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the int input as combo box.
|
||||
/// </summary>
|
||||
/// <param name="valueProperty">Value property.</param>
|
||||
/// <param name="content">GUI content.</param>
|
||||
/// <returns>True if value changed.</returns>
|
||||
private static bool DrawComboBox(SerializedProperty valueProperty, SubstanceIntGUIContent content, out int newValue)
|
||||
{
|
||||
var specializedContent = content as SubstanceIntComboBoxGUIContent;
|
||||
|
||||
var oldValue = valueProperty.intValue;
|
||||
newValue = EditorGUILayout.IntPopup(content, oldValue, specializedContent.EnumValuesGUI, specializedContent.EnumValues);
|
||||
|
||||
if (oldValue != newValue)
|
||||
{
|
||||
valueProperty.intValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default input render.
|
||||
/// </summary>
|
||||
/// <param name="valueProperty">Value property.</param>
|
||||
/// <param name="content">GUI content.</param>
|
||||
/// <returns>True if value changed.</returns>
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out int newValue)
|
||||
{
|
||||
var oldValue = valueProperty.intValue;
|
||||
newValue = EditorGUILayout.IntField(content, oldValue);
|
||||
|
||||
if (oldValue != newValue)
|
||||
{
|
||||
valueProperty.intValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the random seed button.
|
||||
/// </summary>
|
||||
/// <param name="valueProperty">Value property.</param>
|
||||
/// <param name="content">GUI content.</param>
|
||||
/// <returns>True if value changed.</returns>
|
||||
private static bool DrawRandomSeedButton(SerializedProperty valueProperty, SubstanceInputGUIContent content, out int newValue)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
newValue = valueProperty.intValue;
|
||||
int minimum = 0;
|
||||
int maximum = 10000;
|
||||
|
||||
int labelWidth = (int)EditorGUIUtility.labelWidth - 15;
|
||||
int fieldWidth = 50;
|
||||
|
||||
content.text = "Random Seed";
|
||||
content.tooltip = "$randomseed: the overall random aspect of the texture";
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
{
|
||||
int buttonWidth = (int)EditorGUIUtility.currentViewWidth - labelWidth - fieldWidth - 60;
|
||||
|
||||
EditorGUILayout.LabelField(content, GUILayout.Width(labelWidth), GUILayout.ExpandWidth(true));
|
||||
|
||||
if (GUILayout.Button("Randomize", GUILayout.Width(buttonWidth)))
|
||||
{
|
||||
newValue = UnityEngine.Random.Range(minimum, maximum);
|
||||
valueProperty.intValue = newValue;
|
||||
result = true;
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
newValue = EditorGUILayout.IntField(newValue, GUILayout.Width(fieldWidth));
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
newValue = (newValue < minimum) ? minimum : (newValue > maximum) ? maximum : newValue;
|
||||
valueProperty.intValue = newValue;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91b2fc4c484fa3f48804e6352c3d51d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,95 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerInt2
|
||||
{
|
||||
private static readonly string[] _resulutions = { "256", "512", "1024", "2048", "4096" };
|
||||
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
Vector2Int newValue;
|
||||
bool changed;
|
||||
|
||||
if (IsSizeAttribute(content))
|
||||
{
|
||||
changed = DrawResolutionSelection(valueProperty, content, out newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
changed = DrawDefault(valueProperty, content, out newValue);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputInt2(inputID, newValue);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static bool DrawResolutionSelection(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector2Int newValue)
|
||||
{
|
||||
Vector2Int oldValue = valueProperty.vector2IntValue;
|
||||
var currentIndex = GetEnumIndex(oldValue);
|
||||
int newIndex = EditorGUILayout.Popup("Output Resolution", currentIndex, _resulutions);
|
||||
|
||||
if (currentIndex != newIndex)
|
||||
{
|
||||
newValue = GetValueFromIndex(newIndex);
|
||||
valueProperty.vector2IntValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
newValue = new Vector2Int();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector2Int newValue)
|
||||
{
|
||||
Vector2Int oldValue = valueProperty.vector2IntValue;
|
||||
newValue = EditorGUILayout.Vector2IntField(content, oldValue);
|
||||
|
||||
if (newValue != oldValue)
|
||||
{
|
||||
valueProperty.vector2IntValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsSizeAttribute(GUIContent content)
|
||||
{
|
||||
return content.text == "$outputsize";
|
||||
}
|
||||
|
||||
private static int GetEnumIndex(Vector2Int data)
|
||||
{
|
||||
switch (data.x)
|
||||
{
|
||||
case 8: return 0;
|
||||
case 9: return 1;
|
||||
case 10: return 2;
|
||||
case 11: return 3;
|
||||
case 12: return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector2Int GetValueFromIndex(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return new Vector2Int(8, 8);
|
||||
case 1: return new Vector2Int(9, 9);
|
||||
case 2: return new Vector2Int(10, 10);
|
||||
case 3: return new Vector2Int(11, 11);
|
||||
case 4: return new Vector2Int(12, 12);
|
||||
default:
|
||||
return new Vector2Int(8, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17a55141ccae8494f8ea0e29affd3a9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,41 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerInt3
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
Vector3Int newValue;
|
||||
bool changed;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content, out newValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputInt3(inputID, newValue);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Vector3Int newValue)
|
||||
{
|
||||
var previewValue = valueProperty.vector3IntValue;
|
||||
newValue = EditorGUILayout.Vector3IntField(content, previewValue);
|
||||
|
||||
if (newValue != previewValue)
|
||||
{
|
||||
valueProperty.vector3IntValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c99f44dae8ff5f4097e558c6f881451
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,211 @@
|
||||
using UnityEditor;
|
||||
using Adobe.Substance;
|
||||
using UnityEngine;
|
||||
using Adobe.Substance.Input.Description;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerInt4
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
int value0;
|
||||
int value1;
|
||||
int value2;
|
||||
int value3;
|
||||
bool changed;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
case SubstanceWidgetType.Slider:
|
||||
changed = DrawSliderWidget(valueProperty, content as SubstanceInt4GUIContent, out value0, out value1, out value2, out value3);
|
||||
break;
|
||||
|
||||
case SubstanceWidgetType.Color:
|
||||
changed = DrawColorWidget(valueProperty, content as SubstanceInt4GUIContent, out value0, out value1, out value2, out value3);
|
||||
break;
|
||||
//TODO: Add edge cases here.
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content as SubstanceInt4GUIContent, out value0, out value1, out value2, out value3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
handler.SetInputInt4(inputID, value0, value1, value2, value3);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInt4GUIContent content, out int newValue0, out int newValue1, out int newValue2, out int newValue3)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
var value0 = valueProperty?.FindPropertyRelative("Data0");
|
||||
var value1 = valueProperty?.FindPropertyRelative("Data1");
|
||||
var value2 = valueProperty?.FindPropertyRelative("Data2");
|
||||
var value3 = valueProperty?.FindPropertyRelative("Data3");
|
||||
|
||||
var previewValue0 = value0.intValue;
|
||||
var previewValue1 = value1.intValue;
|
||||
var previewValue2 = value2.intValue;
|
||||
var previewValue3 = value3.intValue;
|
||||
|
||||
newValue0 = EditorGUILayout.IntField(content, previewValue0);
|
||||
newValue1 = EditorGUILayout.IntField(content, previewValue1);
|
||||
newValue2 = EditorGUILayout.IntField(content, previewValue2);
|
||||
newValue3 = EditorGUILayout.IntField(content, previewValue3);
|
||||
|
||||
if (newValue0 != previewValue0)
|
||||
{
|
||||
value0.intValue = newValue0;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue1 != previewValue1)
|
||||
{
|
||||
value1.intValue = newValue1;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue2 != previewValue2)
|
||||
{
|
||||
value2.intValue = newValue2;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue3 != previewValue3)
|
||||
{
|
||||
value3.intValue = newValue3;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool DrawSliderWidget(SerializedProperty valueProperty, SubstanceInt4GUIContent content, out int newValue0, out int newValue1, out int newValue2, out int newValue3)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
int rightValue0 = 100;
|
||||
int rightValue1 = 100;
|
||||
int rightValue2 = 100;
|
||||
int rightValue3 = 100;
|
||||
|
||||
int leftValue0 = 0;
|
||||
int leftValue1 = 0;
|
||||
int leftValue2 = 0;
|
||||
int leftValue3 = 0;
|
||||
|
||||
var int4NumbericalDescription = content.NumericalDescription;
|
||||
|
||||
if (int4NumbericalDescription != null)
|
||||
{
|
||||
leftValue0 = int4NumbericalDescription.MinValue0;
|
||||
leftValue1 = int4NumbericalDescription.MinValue1;
|
||||
leftValue2 = int4NumbericalDescription.MinValue2;
|
||||
leftValue3 = int4NumbericalDescription.MinValue3;
|
||||
|
||||
rightValue0 = int4NumbericalDescription.MaxValue0;
|
||||
rightValue1 = int4NumbericalDescription.MaxValue1;
|
||||
rightValue2 = int4NumbericalDescription.MaxValue2;
|
||||
rightValue3 = int4NumbericalDescription.MaxValue3;
|
||||
}
|
||||
|
||||
var value0 = valueProperty?.FindPropertyRelative("Data0");
|
||||
var value1 = valueProperty?.FindPropertyRelative("Data1");
|
||||
var value2 = valueProperty?.FindPropertyRelative("Data2");
|
||||
var value3 = valueProperty?.FindPropertyRelative("Data3");
|
||||
|
||||
var previewValue0 = value0.intValue;
|
||||
var previewValue1 = value1.intValue;
|
||||
var previewValue2 = value2.intValue;
|
||||
var previewValue3 = value3.intValue;
|
||||
|
||||
newValue0 = EditorGUILayout.IntSlider(content, previewValue0, leftValue0, rightValue0);
|
||||
newValue1 = EditorGUILayout.IntSlider(content, previewValue1, leftValue1, rightValue1);
|
||||
newValue2 = EditorGUILayout.IntSlider(content, previewValue2, leftValue2, rightValue2);
|
||||
newValue3 = EditorGUILayout.IntSlider(content, previewValue3, leftValue3, rightValue3);
|
||||
|
||||
if (newValue0 != previewValue0)
|
||||
{
|
||||
value0.intValue = newValue0;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue1 != previewValue1)
|
||||
{
|
||||
value1.intValue = newValue1;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue2 != previewValue2)
|
||||
{
|
||||
value2.intValue = newValue2;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue3 != previewValue3)
|
||||
{
|
||||
value3.intValue = newValue3;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool DrawColorWidget(SerializedProperty valueProperty, SubstanceInt4GUIContent content, out int newValue0, out int newValue1, out int newValue2, out int newValue3)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
var value0 = valueProperty?.FindPropertyRelative("Data0");
|
||||
var value1 = valueProperty?.FindPropertyRelative("Data1");
|
||||
var value2 = valueProperty?.FindPropertyRelative("Data2");
|
||||
var value3 = valueProperty?.FindPropertyRelative("Data3");
|
||||
|
||||
var previewValue0 = value0.intValue;
|
||||
var previewValue1 = value1.intValue;
|
||||
var previewValue2 = value2.intValue;
|
||||
var previewValue3 = value3.intValue;
|
||||
|
||||
var floatValue0 = ((float)previewValue0) / 255f;
|
||||
var floatValue1 = ((float)previewValue1) / 255f;
|
||||
var floatValue2 = ((float)previewValue2) / 255f;
|
||||
var floatValue3 = ((float)previewValue3) / 255f;
|
||||
|
||||
Color color = new Color(floatValue0, floatValue1, floatValue2, floatValue3);
|
||||
|
||||
var newColor = EditorGUILayout.ColorField(content, color);
|
||||
|
||||
newValue0 = (int)newColor.r * 255;
|
||||
newValue1 = (int)newColor.g * 255;
|
||||
newValue2 = (int)newColor.b * 255;
|
||||
newValue3 = (int)newColor.a * 255;
|
||||
|
||||
if (newValue0 != previewValue0)
|
||||
{
|
||||
value0.intValue = newValue0;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue1 != previewValue1)
|
||||
{
|
||||
value1.intValue = newValue1;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue2 != previewValue2)
|
||||
{
|
||||
value2.intValue = newValue2;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (newValue3 != previewValue3)
|
||||
{
|
||||
value3.intValue = newValue3;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6083c230932064544b0beca8c8228f62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,35 @@
|
||||
using UnityEditor;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerString
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
bool changed;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
var stringValue = valueProperty.stringValue;
|
||||
handler.SetInputString(inputID, stringValue);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(valueProperty, content);
|
||||
return EditorGUI.EndChangeCheck();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ac347008a541b247a481fafa2196b14
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,61 @@
|
||||
using Adobe.Substance;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceInputDrawerTexture
|
||||
{
|
||||
public static bool DrawInput(SerializedProperty valueProperty, SubstanceInputGUIContent content, SubstanceNativeGraph handler, int inputID)
|
||||
{
|
||||
Texture2D newValue;
|
||||
bool changed;
|
||||
|
||||
switch (content.Description.WidgetType)
|
||||
{
|
||||
default:
|
||||
changed = DrawDefault(valueProperty, content, out newValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
if (newValue != null)
|
||||
{
|
||||
var pixels = newValue.GetPixels32();
|
||||
handler.SetInputTexture2D(inputID, pixels, newValue.width, newValue.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SetInputTexture2DNull(inputID);
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static bool DrawDefault(SerializedProperty valueProperty, SubstanceInputGUIContent content, out Texture2D newValue)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.ObjectField(valueProperty, content);
|
||||
var changed = EditorGUI.EndChangeCheck();
|
||||
newValue = null;
|
||||
|
||||
if (changed)
|
||||
{
|
||||
if (valueProperty.objectReferenceValue != null)
|
||||
{
|
||||
newValue = valueProperty.objectReferenceValue as Texture2D;
|
||||
|
||||
if (newValue != null)
|
||||
{
|
||||
if (!newValue.isReadable)
|
||||
TextureUtils.SetReadableFlag(newValue, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07aca6dfe5b18924ba359d2f53a2ac34
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,824 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Adobe.Substance.Input;
|
||||
using Adobe.SubstanceEditor.Importer;
|
||||
using Adobe.SubstanceEditor.ProjectSettings;
|
||||
using Adobe.Substance;
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Editor Singleton to manage interactions with the Substance engine.
|
||||
/// </summary>
|
||||
internal sealed class SubstanceEditorEngine : ScriptableSingleton<SubstanceEditorEngine>
|
||||
{
|
||||
/// <summary>
|
||||
/// Substance files currently loaded in the engine.
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, SubstanceNativeGraph> _activeSubstanceDictionary = new Dictionary<string, SubstanceNativeGraph>();
|
||||
|
||||
/// <summary>
|
||||
/// Currently active instances.
|
||||
/// </summary>
|
||||
private readonly List<SubstanceGraphSO> _managedInstances = new List<SubstanceGraphSO>();
|
||||
|
||||
private readonly Queue<string> _delayiedInitilization = new Queue<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Render results generated by the substance engine in a background thread.
|
||||
/// </summary>
|
||||
private readonly ConcurrentQueue<RenderResult> _renderResultsQueue = new ConcurrentQueue<RenderResult>();
|
||||
|
||||
private readonly List<SubstanceGraphSO> _playmodeObjects = new List<SubstanceGraphSO>();
|
||||
|
||||
private readonly Queue<DelayAssetCreationInfo> _creationQueue = new Queue<DelayAssetCreationInfo>();
|
||||
|
||||
private class DelayAssetCreationInfo
|
||||
{
|
||||
public SubstanceGraphSO InstanceAsset;
|
||||
public string InstancePath;
|
||||
|
||||
public DelayAssetCreationInfo(SubstanceGraphSO instanceAsset, string instancePath)
|
||||
{
|
||||
InstanceAsset = instanceAsset;
|
||||
InstancePath = instancePath;
|
||||
}
|
||||
}
|
||||
|
||||
internal void DelayAssetCreation(SubstanceGraphSO instanceAsset, string instancePath)
|
||||
{
|
||||
_creationQueue.Enqueue(new DelayAssetCreationInfo(instanceAsset, instancePath));
|
||||
}
|
||||
|
||||
private bool _resetAllInputs = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializer to ensure SubstanceEditorEngine is
|
||||
/// started consistently on editor load and assembly reload.
|
||||
///</summary>
|
||||
[InitializeOnLoad]
|
||||
private sealed class SubstanceEditorEngineInitializer
|
||||
{
|
||||
static SubstanceEditorEngineInitializer()
|
||||
{
|
||||
AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
|
||||
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
|
||||
}
|
||||
|
||||
private static void OnBeforeAssemblyReload()
|
||||
{
|
||||
SubstanceEditorEngine.instance.TearDown();
|
||||
}
|
||||
|
||||
private static void OnAfterAssemblyReload()
|
||||
{
|
||||
SubstanceEditorEngine.instance.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
private static Queue<Tuple<string, string>> _delayMoveOperation = new Queue<Tuple<string, string>>();
|
||||
|
||||
internal void PushMoveOperation(string from, string to)
|
||||
{
|
||||
_delayMoveOperation.Enqueue(new Tuple<string, string>(from, to));
|
||||
}
|
||||
|
||||
private bool _isLoaded;
|
||||
|
||||
public bool IsInitialized => _isLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Initalize substance engine.
|
||||
/// </summary>
|
||||
private void Setup()
|
||||
{
|
||||
_isLoaded = false;
|
||||
PluginPipelines.GetCurrentPipelineInUse();
|
||||
var enginePath = PlatformUtils.GetEnginePath();
|
||||
var pluginPath = PlatformUtils.GetPluginPath();
|
||||
Engine.Initialize(pluginPath, enginePath);
|
||||
EditorApplication.update += Update;
|
||||
EditorApplication.quitting += OnQuit;
|
||||
Undo.undoRedoPerformed += UndoCallback;
|
||||
}
|
||||
|
||||
private void UndoCallback()
|
||||
{
|
||||
if (Selection.activeObject is SubstanceGraphSO)
|
||||
{
|
||||
var target = Selection.activeObject as SubstanceGraphSO;
|
||||
|
||||
var managedInstance = _managedInstances.FirstOrDefault((a) => a.GUID == target.GUID);
|
||||
|
||||
if (managedInstance != null)
|
||||
{
|
||||
managedInstance.RenderTextures = true;
|
||||
PushAllInputsToUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shutdown substance engine.
|
||||
/// </summary>
|
||||
private void TearDown()
|
||||
{
|
||||
_isLoaded = false;
|
||||
EditorApplication.update -= Update;
|
||||
EditorApplication.quitting -= OnQuit;
|
||||
Undo.undoRedoPerformed -= UndoCallback;
|
||||
Engine.Shutdown();
|
||||
}
|
||||
|
||||
private void OnQuit()
|
||||
{
|
||||
//Check if there are pending updates. If there is, we need to do them synchronously.
|
||||
foreach (var graph in _managedInstances)
|
||||
{
|
||||
if (graph == null)
|
||||
continue;
|
||||
|
||||
if (!TryGetHandlerFromInstance(graph, out SubstanceNativeGraph substanceHandler))
|
||||
continue;
|
||||
|
||||
if (substanceHandler.InRenderWork)
|
||||
continue;
|
||||
|
||||
if (graph.RenderTextures)
|
||||
{
|
||||
var renderResult = substanceHandler.Render();
|
||||
graph.UpdateAssociatedAssets(renderResult, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Update
|
||||
|
||||
/// <summary>
|
||||
/// Editor update.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (!_isLoaded)
|
||||
{
|
||||
LoadAllSbsarFiles();
|
||||
_isLoaded = true;
|
||||
}
|
||||
|
||||
_managedInstances.RemoveAll(item => item == null);
|
||||
|
||||
CheckDelayedMove();
|
||||
HandleAssetCreation();
|
||||
HandleDelayedInitialization();
|
||||
HandlePlaymode();
|
||||
CheckUIUpdate();
|
||||
CheckRenderResultsUpdates();
|
||||
}
|
||||
|
||||
private void CheckDelayedMove()
|
||||
{
|
||||
while (_delayMoveOperation.Count != 0)
|
||||
{
|
||||
var newMove = _delayMoveOperation.Dequeue();
|
||||
|
||||
var substanceInstance = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(newMove.Item2);
|
||||
|
||||
if (substanceInstance != null)
|
||||
{
|
||||
substanceInstance.Move(newMove.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAssetCreation()
|
||||
{
|
||||
while (_creationQueue.Count != 0)
|
||||
{
|
||||
var creationData = _creationQueue.Dequeue();
|
||||
|
||||
if (creationData == null)
|
||||
continue;
|
||||
|
||||
if (creationData.InstanceAsset == null)
|
||||
continue;
|
||||
|
||||
var oldAsset = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(creationData.InstancePath);
|
||||
|
||||
AssetDatabase.CreateAsset(creationData.InstanceAsset, creationData.InstancePath);
|
||||
|
||||
var createAsset = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(creationData.InstancePath);
|
||||
var importer = AssetImporter.GetAtPath(createAsset.AssetPath) as SubstanceImporter;
|
||||
EditorUtility.SetDirty(importer);
|
||||
AssetDatabase.Refresh();
|
||||
SubmitAsyncRenderWorkBatch(new List<SubstanceGraphSO> { creationData.InstanceAsset });
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDelayedInitialization()
|
||||
{
|
||||
while (_delayiedInitilization.Count != 0)
|
||||
{
|
||||
var instancePath = _delayiedInitilization.Dequeue();
|
||||
var materialInstance = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(instancePath);
|
||||
_managedInstances.Add(materialInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _onPlaymodeEnterHandled = false;
|
||||
|
||||
private void HandlePlaymode()
|
||||
{
|
||||
if (EditorApplication.isPlaying && !_onPlaymodeEnterHandled)
|
||||
{
|
||||
var runtiemMaterials = GameObject.FindObjectsOfType<Substance.Runtime.SubstanceRuntimeGraph>();
|
||||
|
||||
foreach (var graph in _managedInstances)
|
||||
{
|
||||
bool isAssigned = runtiemMaterials.FirstOrDefault(a => a.GraphSO == graph) != null;
|
||||
|
||||
if (Application.IsPlaying(graph) && (isAssigned || graph.IsRuntimeOnly))
|
||||
{
|
||||
if (!_playmodeObjects.Contains(graph))
|
||||
_playmodeObjects.Add(graph);
|
||||
}
|
||||
}
|
||||
|
||||
_onPlaymodeEnterHandled = true;
|
||||
}
|
||||
|
||||
if (!EditorApplication.isPlaying && _onPlaymodeEnterHandled)
|
||||
{
|
||||
var objectsToRemove = new List<SubstanceGraphSO>();
|
||||
|
||||
foreach (var playmodeObject in _playmodeObjects)
|
||||
{
|
||||
if (!Application.IsPlaying(playmodeObject))
|
||||
{
|
||||
playmodeObject.RenderTextures = true;
|
||||
objectsToRemove.Add(playmodeObject);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in objectsToRemove)
|
||||
_playmodeObjects.Remove(item);
|
||||
|
||||
_onPlaymodeEnterHandled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updated the state of the SubstanceFileHandlers based on changes made in the graph objects.
|
||||
/// </summary>
|
||||
private void CheckUIUpdate()
|
||||
{
|
||||
foreach (var graph in _managedInstances)
|
||||
{
|
||||
if (graph == null)
|
||||
continue;
|
||||
|
||||
if (graph.RawData == null)
|
||||
{
|
||||
var assets = AssetDatabase.LoadAllAssetsAtPath(graph.AssetPath);
|
||||
|
||||
if (assets == null)
|
||||
continue;
|
||||
|
||||
var dataObject = assets.FirstOrDefault(a => a is SubstanceFileRawData) as SubstanceFileRawData;
|
||||
|
||||
graph.RawData = dataObject;
|
||||
EditorUtility.SetDirty(graph);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
if (!TryGetHandlerFromInstance(graph, out SubstanceNativeGraph substanceHandler))
|
||||
continue;
|
||||
|
||||
if (substanceHandler.InRenderWork)
|
||||
continue;
|
||||
|
||||
if (graph.IsRuntimeOnly && graph.OutputMaterial != null)
|
||||
if (graph.OutputMaterial.GetTexture("_MainTex") == null)
|
||||
MaterialUtils.AssignOutputTexturesToMaterial(graph);
|
||||
|
||||
if (HasMaterialShaderChanged(graph))
|
||||
{
|
||||
SubmitAsyncRenderWork(substanceHandler, graph, true);
|
||||
graph.RenderTextures = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (graph.OutputRemaped)
|
||||
{
|
||||
graph.OutputRemaped = false;
|
||||
|
||||
if (graph.IsRuntimeOnly)
|
||||
{
|
||||
DeleteGeneratedTextures(graph);
|
||||
}
|
||||
|
||||
RenderingUtils.UpdateAlphaChannelsAssignment(substanceHandler, graph);
|
||||
SubmitAsyncRenderWork(substanceHandler, graph, true);
|
||||
graph.RenderTextures = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (graph.RenderTextures)
|
||||
{
|
||||
graph.RenderTextures = false;
|
||||
|
||||
if (_resetAllInputs)
|
||||
{
|
||||
_resetAllInputs = true;
|
||||
|
||||
foreach (var input in graph.Input)
|
||||
{
|
||||
input.UpdateNativeHandle(substanceHandler);
|
||||
}
|
||||
}
|
||||
|
||||
SubmitAsyncRenderWork(substanceHandler, graph);
|
||||
|
||||
EditorUtility.SetDirty(graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updated the render results that are finished by the substance engine
|
||||
/// </summary>
|
||||
private void CheckRenderResultsUpdates()
|
||||
{
|
||||
if (_renderResultsQueue.TryDequeue(out RenderResult renderResult))
|
||||
{
|
||||
SubstanceGraphSO graph = _managedInstances.FirstOrDefault(a => a.GUID == renderResult.GUID);
|
||||
|
||||
if (graph == null)
|
||||
return;
|
||||
|
||||
if (!TryGetHandlerFromInstance(graph, out SubstanceNativeGraph handler))
|
||||
return;
|
||||
|
||||
var textureReassigned = graph.UpdateAssociatedAssets(renderResult.Result, renderResult.ForceRebuild);
|
||||
|
||||
if (textureReassigned)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(graph.AssetPath))
|
||||
{
|
||||
AssetCreationUtils.CreateMaterialOrUpdateMaterial(graph, graph.Name);
|
||||
EditorUtility.SetDirty(graph);
|
||||
EditorUtility.SetDirty(graph.OutputMaterial);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (graph.OutputMaterial == null)
|
||||
{
|
||||
AssetCreationUtils.CreateMaterialOrUpdateMaterial(graph, graph.Name);
|
||||
EditorUtility.SetDirty(graph);
|
||||
EditorUtility.SetDirty(graph.OutputMaterial);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.SetDirty(graph.OutputMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
handler.InRenderWork = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the shaders assigned to the substance graph generated material has changed. If so, we have to change the default outputs.
|
||||
/// </summary>
|
||||
private bool HasMaterialShaderChanged(SubstanceGraphSO graph)
|
||||
{
|
||||
if (graph.OutputMaterial == null || string.IsNullOrEmpty(graph.MaterialShader))
|
||||
return false;
|
||||
|
||||
if (graph.OutputMaterial.shader.name == graph.MaterialShader)
|
||||
return false;
|
||||
|
||||
AssetCreationUtils.UpdateMeterialAssignment(graph);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Update
|
||||
|
||||
#region Public methods
|
||||
|
||||
#region Instance Management
|
||||
|
||||
/// <summary>
|
||||
/// Loads a sbsar file into the engine. The engine will keep track of this file internally.
|
||||
/// </summary>
|
||||
/// <param name="assetPath">Path to a sbsar file.</param>
|
||||
public void InitializeInstance(SubstanceGraphSO substanceInstance, string instancePath, out SubstanceGraphSO matchingInstance)
|
||||
{
|
||||
matchingInstance = null;
|
||||
|
||||
if (substanceInstance == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(substanceInstance.AssetPath))
|
||||
Debug.LogError("Unable to instantiate substance material with null assetPath.");
|
||||
|
||||
matchingInstance = _managedInstances.FirstOrDefault(a => a.OutputPath.Equals(substanceInstance.OutputPath, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!_activeSubstanceDictionary.TryGetValue(substanceInstance.GUID, out SubstanceNativeGraph _))
|
||||
{
|
||||
var substanceArchive = Engine.OpenFile(substanceInstance.RawData.FileContent, substanceInstance.GetNativeID());
|
||||
_activeSubstanceDictionary.Add(substanceInstance.GUID, substanceArchive);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(instancePath))
|
||||
_delayiedInitilization.Enqueue(instancePath);
|
||||
else
|
||||
{
|
||||
_managedInstances.Add(substanceInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads the target substance from th e substance engine.
|
||||
/// </summary>
|
||||
/// <param name="assetPath">Path to a sbsar file.</param>
|
||||
public void ReleaseInstance(SubstanceGraphSO substanceInstance)
|
||||
{
|
||||
if (TryGetHandlerFromInstance(substanceInstance, out SubstanceNativeGraph substanceArchive))
|
||||
{
|
||||
_activeSubstanceDictionary.Remove(substanceInstance.GUID);
|
||||
substanceArchive.Dispose();
|
||||
|
||||
var managedInstance = _managedInstances.FirstOrDefault((a) => a.GUID == substanceInstance.GUID);
|
||||
|
||||
if (managedInstance != null)
|
||||
_managedInstances.Remove(managedInstance);
|
||||
}
|
||||
}
|
||||
|
||||
public string SerializeCurrentState(SubstanceGraphSO substanceInstance)
|
||||
{
|
||||
if (TryGetHandlerFromInstance(substanceInstance, out SubstanceNativeGraph substanceArchive))
|
||||
return substanceArchive.CreatePresetFromCurrentState();
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public void SetStateFromSerializedData(SubstanceGraphSO substanceInstance, string data)
|
||||
{
|
||||
if (TryGetHandlerFromInstance(substanceInstance, out SubstanceNativeGraph substanceArchive))
|
||||
substanceArchive.ApplyPreset(data);
|
||||
}
|
||||
|
||||
#endregion Instance Management
|
||||
|
||||
public void PushAllInputsToUpdate()
|
||||
{
|
||||
_resetAllInputs = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the list of substance graphs from a substance file.
|
||||
/// </summary>
|
||||
/// <param name="assetPath">Path to the target substance file.</param>
|
||||
/// <returns>List of substance graph objects.</returns>
|
||||
public void CreateGraphObject(SubstanceGraphSO instance, SubstanceGraphSO copy = null)
|
||||
{
|
||||
if (!TryGetHandlerFromInstance(instance, out SubstanceNativeGraph substanceHandle))
|
||||
return;
|
||||
|
||||
if (copy != null)
|
||||
{
|
||||
if (TryGetHandlerFromInstance(copy, out SubstanceNativeGraph copyHandle))
|
||||
{
|
||||
var copyPreset = copyHandle.CreatePresetFromCurrentState();
|
||||
substanceHandle.ApplyPreset(copyPreset); ;
|
||||
}
|
||||
}
|
||||
|
||||
instance.Input = GetGraphInputs(substanceHandle);
|
||||
instance.Output = GetGraphOutputs(substanceHandle);
|
||||
instance.PhysicalSize = substanceHandle.GetPhysicalSize();
|
||||
instance.HasPhysicalSize = instance.PhysicalSize != Vector3.zero;
|
||||
|
||||
RenderingUtils.ConfigureOutputTextures(substanceHandle, instance);
|
||||
|
||||
instance.GenerateAllOutputs = SubstanceEditorSettingsSO.GenerateAllTextures();
|
||||
SetOutputTextureSize(instance, substanceHandle);
|
||||
|
||||
instance.DefaultPreset = substanceHandle.CreatePresetFromCurrentState();
|
||||
|
||||
var thumbnailData = substanceHandle.GetThumbnail();
|
||||
|
||||
if (thumbnailData != null)
|
||||
{
|
||||
instance.Thumbnail = thumbnailData;
|
||||
instance.HasThumbnail = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a substance file using the substance engine.
|
||||
/// </summary>
|
||||
/// <param name="assetPath">Path to a sbsar file.</param>
|
||||
/// <param name="graphID">Target graph index.</param>
|
||||
/// <returns>Task that will be finished once the rendering is finished.</returns>
|
||||
public void RenderInstanceAsync(SubstanceGraphSO instances)
|
||||
{
|
||||
if (TryGetHandlerFromInstance(instances, out SubstanceNativeGraph substanceArchive))
|
||||
SubmitAsyncRenderWork(substanceArchive, instances);
|
||||
}
|
||||
|
||||
public void RenderInstanceAsync(IReadOnlyList<SubstanceGraphSO> instances)
|
||||
{
|
||||
foreach (var graph in instances)
|
||||
RenderInstanceAsync(graph);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns the substance graph objects inputs to the substance file Handlers associated with them.
|
||||
/// </summary>
|
||||
/// <param name="assetPath">Path to the sbsar object.</param>
|
||||
/// <param name="graphCopy">List of graph objects.</param>
|
||||
internal void SetSubstanceInput(SubstanceGraphSO instance)
|
||||
{
|
||||
if (TryGetHandlerFromInstance(instance, out SubstanceNativeGraph substanceArchive))
|
||||
{
|
||||
foreach (var input in instance.Input)
|
||||
input.UpdateNativeHandle(substanceArchive);
|
||||
}
|
||||
}
|
||||
|
||||
#region Preset
|
||||
|
||||
/// <summary>
|
||||
/// Get the preset XML document for the current state of the a managed substance object.
|
||||
/// </summary>
|
||||
/// <param name="assetPath">Path to the target sbsar file.</param>
|
||||
/// <param name="graphID">Target graph id. </param>
|
||||
/// <returns>XML document with the current input states as a preset. </returns>
|
||||
public string ExportGraphPresetXML(SubstanceGraphSO instance)
|
||||
{
|
||||
if (!TryGetHandlerFromInstance(instance, out SubstanceNativeGraph substanceArchive))
|
||||
return null;
|
||||
|
||||
return substanceArchive.CreatePresetFromCurrentState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the inputs from a preset XML document into the target graph of a managed substance file.
|
||||
/// </summary>
|
||||
/// <param name="substanceInstancePath">Path to the target sbsar file.</param>
|
||||
/// <param name="graphID">Target graph id.</param>
|
||||
/// <param name="presetXML">Preset XML document.</param>
|
||||
public void LoadPresetsToGraph(SubstanceGraphSO instance, string presetXML)
|
||||
{
|
||||
if (TryGetHandlerFromInstance(instance, out SubstanceNativeGraph substanceHandler))
|
||||
{
|
||||
substanceHandler.ApplyPreset(presetXML);
|
||||
|
||||
instance.Input = GetGraphInputs(substanceHandler);
|
||||
instance.RenderTextures = true;
|
||||
EditorUtility.SetDirty(instance);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Preset
|
||||
|
||||
#endregion Public methods
|
||||
|
||||
public bool TryGetHandlerFromInstance(SubstanceGraphSO substanceInstance, out SubstanceNativeGraph substanceHandler)
|
||||
{
|
||||
substanceHandler = null;
|
||||
|
||||
if (substanceInstance == null)
|
||||
return false;
|
||||
|
||||
if (!_activeSubstanceDictionary.TryGetValue(substanceInstance.GUID, out substanceHandler))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetHandlerFromGUI(string guid, out SubstanceNativeGraph substanceHandler)
|
||||
{
|
||||
if (!_activeSubstanceDictionary.TryGetValue(guid, out substanceHandler))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads all sbsar files currently in the project.
|
||||
/// </summary>
|
||||
private void LoadAllSbsarFiles()
|
||||
{
|
||||
string[] files = Directory.GetFiles(Application.dataPath, "*.sbsar", SearchOption.AllDirectories);
|
||||
|
||||
foreach (string filePath in files)
|
||||
{
|
||||
if (filePath.StartsWith(Application.dataPath))
|
||||
{
|
||||
var assetPath = "Assets" + filePath.Substring(Application.dataPath.Length);
|
||||
assetPath = assetPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
|
||||
if (!File.Exists(assetPath))
|
||||
continue;
|
||||
|
||||
SubstanceImporter importer = AssetImporter.GetAtPath(assetPath) as SubstanceImporter;
|
||||
|
||||
if (importer == null)
|
||||
continue;
|
||||
|
||||
foreach (var substanceInstance in importer._fileAsset.GetGraphs())
|
||||
{
|
||||
if (!substanceInstance.IsRuntimeOnly)
|
||||
return;
|
||||
|
||||
InitializeInstance(substanceInstance, AssetDatabase.GetAssetPath(substanceInstance), out SubstanceGraphSO _);
|
||||
|
||||
if (TryGetHandlerFromInstance(substanceInstance, out SubstanceNativeGraph fileHandler))
|
||||
{
|
||||
if (substanceInstance == null)
|
||||
continue;
|
||||
|
||||
substanceInstance.RuntimeInitialize(fileHandler, substanceInstance.IsRuntimeOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshActiveInstances()
|
||||
{
|
||||
foreach (var substanceInstance in _managedInstances)
|
||||
{
|
||||
substanceInstance.RenderTextures = true;
|
||||
}
|
||||
}
|
||||
|
||||
private List<ISubstanceInput> GetGraphInputs(SubstanceNativeGraph substanceFileHandler)
|
||||
{
|
||||
var inputs = new List<ISubstanceInput>();
|
||||
|
||||
var graphInputCount = substanceFileHandler.GetInputCount();
|
||||
|
||||
for (int j = 0; j < graphInputCount; j++)
|
||||
{
|
||||
SubstanceInputBase graphInput = substanceFileHandler.GetInputObject(j);
|
||||
inputs.Add(graphInput);
|
||||
}
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
private List<SubstanceOutputTexture> GetGraphOutputs(SubstanceNativeGraph substanceFileHandler)
|
||||
{
|
||||
var outputs = new List<SubstanceOutputTexture>();
|
||||
|
||||
var graphOutputCount = substanceFileHandler.GetOutputCount();
|
||||
|
||||
for (int j = 0; j < graphOutputCount; j++)
|
||||
{
|
||||
var outputDescription = substanceFileHandler.GetOutputDescription(j);
|
||||
var unityTextureName = MaterialUtils.GetUnityTextureName(outputDescription);
|
||||
SubstanceOutputTexture graphData = new SubstanceOutputTexture(outputDescription, unityTextureName);
|
||||
|
||||
if (graphData.IsBaseColor() ||
|
||||
graphData.IsDiffuse() ||
|
||||
graphData.IsSpecular() ||
|
||||
graphData.IsHightMap() ||
|
||||
graphData.IsEmissive())
|
||||
{
|
||||
graphData.sRGB = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
graphData.sRGB = false;
|
||||
}
|
||||
|
||||
outputs.Add(graphData);
|
||||
}
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
private void SetOutputTextureSize(SubstanceGraphSO graph, SubstanceNativeGraph substanceFileHandler)
|
||||
{
|
||||
var outputSize = graph.Input.FirstOrDefault(a => a.Description.Label == "$outputsize");
|
||||
|
||||
if (outputSize == null)
|
||||
return;
|
||||
|
||||
if (outputSize is SubstanceInputInt2 outputSizeInput)
|
||||
{
|
||||
outputSizeInput.Data = SubstanceEditorSettingsSO.TextureOutputResultion();
|
||||
outputSizeInput.UpdateNativeHandle(substanceFileHandler);
|
||||
}
|
||||
}
|
||||
|
||||
#region Rendering
|
||||
|
||||
public void SubmitAsyncRenderWork(SubstanceNativeGraph substanceArchive, SubstanceGraphSO instanceKey, bool forceRebuild = false)
|
||||
{
|
||||
if (substanceArchive.InRenderWork)
|
||||
return;
|
||||
|
||||
substanceArchive.InRenderWork = true;
|
||||
|
||||
var renderResut = new RenderResult()
|
||||
{
|
||||
SubstanceArchive = substanceArchive,
|
||||
ForceRebuild = forceRebuild,
|
||||
GUID = instanceKey.GUID
|
||||
};
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
renderResut.Result = substanceArchive.Render();
|
||||
_renderResultsQueue.Enqueue(renderResut);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
substanceArchive.InRenderWork = false;
|
||||
Debug.LogException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void SubmitAsyncRenderWorkBatch(IReadOnlyList<SubstanceGraphSO> instanceKey)
|
||||
{
|
||||
var guildList = instanceKey.Select(a => a.GUID).ToArray();
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
foreach (var guid in guildList)
|
||||
{
|
||||
if (!TryGetHandlerFromGUI(guid, out SubstanceNativeGraph substanceArchive))
|
||||
continue;
|
||||
|
||||
if (substanceArchive.InRenderWork)
|
||||
continue;
|
||||
|
||||
substanceArchive.InRenderWork = true;
|
||||
|
||||
var renderResut = new RenderResult()
|
||||
{
|
||||
SubstanceArchive = substanceArchive,
|
||||
ForceRebuild = false,
|
||||
GUID = guid
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
renderResut.Result = substanceArchive.Render();
|
||||
_renderResultsQueue.Enqueue(renderResut);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
substanceArchive.InRenderWork = false;
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteGeneratedTextures(SubstanceGraphSO graph)
|
||||
{
|
||||
foreach (var output in graph.Output)
|
||||
{
|
||||
if (output.OutputTexture != null)
|
||||
{
|
||||
var texturePath = AssetDatabase.GetAssetPath(output.OutputTexture);
|
||||
|
||||
if (!string.IsNullOrEmpty(texturePath))
|
||||
AssetDatabase.DeleteAsset(texturePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct RenderResult
|
||||
{
|
||||
public SubstanceNativeGraph SubstanceArchive;
|
||||
public IntPtr Result;
|
||||
public bool ForceRebuild;
|
||||
public string GUID;
|
||||
}
|
||||
|
||||
#endregion Rendering
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83f5cf3931946de4da5f6a2138701f02
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,142 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
using Adobe.Substance;
|
||||
using Adobe.SubstanceEditor.Importer;
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
[CustomEditor(typeof(SubstanceFileSO))]
|
||||
[CanEditMultipleObjects]
|
||||
public class SubstanceFileEditor : UnityEditor.Editor
|
||||
{
|
||||
private SubstanceFileSO _target;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
_target = serializedObject.targetObject as SubstanceFileSO;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback for GUI events to block substance files from been duplicated.
|
||||
/// </summary>
|
||||
/// <param name="guid">Asset guid.</param>
|
||||
/// <param name="rt">GUI rect.</param>
|
||||
protected static void OnHierarchyWindowItemOnGUI(string guid, Rect rt)
|
||||
{
|
||||
var currentEvent = Event.current;
|
||||
|
||||
if ("Duplicate" == currentEvent.commandName && currentEvent.type == EventType.ExecuteCommand)
|
||||
{
|
||||
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
|
||||
if (Path.GetExtension(assetPath) == ".sbsar")
|
||||
{
|
||||
Debug.LogWarning("Substance graph can not be manually duplicated.");
|
||||
currentEvent.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height)
|
||||
{
|
||||
if (_target == null)
|
||||
return null;
|
||||
|
||||
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(_target)) as SubstanceImporter;
|
||||
|
||||
if (importer == null)
|
||||
return null;
|
||||
|
||||
var defaultGraph = importer.GetDefaultGraph();
|
||||
|
||||
if (defaultGraph == null)
|
||||
return null;
|
||||
|
||||
if (defaultGraph.HasThumbnail)
|
||||
{
|
||||
var thumbnailTexture = defaultGraph.GetThumbnailTexture();
|
||||
return thumbnailTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
var icon = UnityPackageInfo.GetSubstanceIcon(width, height);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
Texture2D tex = new Texture2D(width, height);
|
||||
EditorUtility.CopySerialized(icon, tex);
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
||||
return base.RenderStaticPreview(assetPath, subAssets, width, height);
|
||||
}
|
||||
|
||||
#region Scene Drag
|
||||
|
||||
public void OnSceneDrag(SceneView sceneView, int index)
|
||||
{
|
||||
Event evt = Event.current;
|
||||
|
||||
if (evt.type == EventType.Repaint)
|
||||
return;
|
||||
|
||||
var materialIndex = -1;
|
||||
var go = HandleUtility.PickGameObject(evt.mousePosition, out materialIndex);
|
||||
|
||||
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(_target)) as SubstanceImporter;
|
||||
|
||||
if (importer != null)
|
||||
{
|
||||
var defaultGraph = importer.GetDefaultGraph();
|
||||
|
||||
if (defaultGraph != null && defaultGraph.OutputMaterial != null)
|
||||
{
|
||||
if (go && go.GetComponent<Renderer>())
|
||||
{
|
||||
HandleRenderer(go.GetComponent<Renderer>(), materialIndex, defaultGraph.OutputMaterial, evt.type, evt.alt);
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void HandleRenderer(Renderer r, int materialIndex, Material dragMaterial, EventType eventType, bool alt)
|
||||
{
|
||||
var applyMaterial = false;
|
||||
switch (eventType)
|
||||
{
|
||||
case EventType.DragUpdated:
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
|
||||
applyMaterial = true;
|
||||
break;
|
||||
|
||||
case EventType.DragPerform:
|
||||
DragAndDrop.AcceptDrag();
|
||||
applyMaterial = true;
|
||||
break;
|
||||
}
|
||||
if (applyMaterial)
|
||||
{
|
||||
var materials = r.sharedMaterials;
|
||||
|
||||
bool isValidMaterialIndex = (materialIndex >= 0 && materialIndex < r.sharedMaterials.Length);
|
||||
if (!alt && isValidMaterialIndex)
|
||||
{
|
||||
materials[materialIndex] = dragMaterial;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int q = 0; q < materials.Length; ++q)
|
||||
materials[q] = dragMaterial;
|
||||
}
|
||||
|
||||
r.sharedMaterials = materials;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Scene Drag
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 812ebf7eca2a66e4c989c54c5e8b9e8f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,967 @@
|
||||
using Adobe.Substance;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
[CustomEditor(typeof(SubstanceGraphSO))]
|
||||
public class SubstanceGraphSOEditor : UnityEditor.Editor
|
||||
{
|
||||
private GraphInputsGroupingHelper _inputGroupingHelper;
|
||||
|
||||
private GraphOutputAlphaChannelsHelper _outputChannelsHelper;
|
||||
|
||||
private bool _propertiesChanged = false;
|
||||
|
||||
private bool _showOutput = true;
|
||||
|
||||
private bool _showExportPresentationHandler = false;
|
||||
|
||||
private bool _showPhysicalSize = false;
|
||||
|
||||
private SubstanceGraphSO _target = null;
|
||||
|
||||
private SubstanceNativeGraph _nativeGraph = null;
|
||||
|
||||
// Scrollview handling:
|
||||
private Rect lastRect;
|
||||
|
||||
private Texture2D _backgroundImage;
|
||||
|
||||
private MaterialEditor _materialPreviewEditor;
|
||||
|
||||
private Vector2 _textureOutputScrollView;
|
||||
|
||||
private SerializedProperty _generateAllOutputsProperty;
|
||||
private SerializedProperty _generateAllMipmapsProperty;
|
||||
private SerializedProperty _runtimeOnlyProperty;
|
||||
private SerializedProperty _outputRemapedProperty;
|
||||
private SerializedProperty _graphOutputs;
|
||||
private SerializedProperty _presetProperty;
|
||||
private SerializedProperty _physicalSizelProperty;
|
||||
private SerializedProperty _hasPhysicalSizeProperty;
|
||||
private SerializedProperty _enablePhysicalSizeProperty;
|
||||
|
||||
private IReadOnlyList<SerializedProperty> _outputProperties;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
if (!IsSerializedObjectReady())
|
||||
return;
|
||||
|
||||
_target = serializedObject.targetObject as SubstanceGraphSO;
|
||||
_textureOutputScrollView = Vector2.zero;
|
||||
_propertiesChanged = false;
|
||||
|
||||
if (_inputGroupingHelper == null)
|
||||
_inputGroupingHelper = new GraphInputsGroupingHelper(_target, serializedObject);
|
||||
|
||||
if (_outputChannelsHelper == null)
|
||||
_outputChannelsHelper = new GraphOutputAlphaChannelsHelper(_target);
|
||||
|
||||
float c = (EditorGUIUtility.isProSkin) ? 0.35f : 0.65f;
|
||||
|
||||
if (_backgroundImage == null)
|
||||
_backgroundImage = Globals.CreateColoredTexture(16, 16, new Color(c, c, c, 1));
|
||||
|
||||
EditorApplication.projectWindowItemOnGUI += OnHierarchyWindowItemOnGUI;
|
||||
_generateAllOutputsProperty = serializedObject.FindProperty("GenerateAllOutputs");
|
||||
_generateAllMipmapsProperty = serializedObject.FindProperty("GenerateAllMipmaps");
|
||||
_runtimeOnlyProperty = serializedObject.FindProperty("IsRuntimeOnly");
|
||||
_outputRemapedProperty = serializedObject.FindProperty("OutputRemaped");
|
||||
_graphOutputs = serializedObject.FindProperty("Output");
|
||||
_presetProperty = serializedObject.FindProperty("CurrentStatePreset");
|
||||
_physicalSizelProperty = serializedObject.FindProperty("PhysicalSize");
|
||||
_hasPhysicalSizeProperty = serializedObject.FindProperty("HasPhysicalSize");
|
||||
_enablePhysicalSizeProperty = serializedObject.FindProperty("EnablePhysicalSize");
|
||||
|
||||
if (!SubstanceEditorEngine.instance.TryGetHandlerFromInstance(_target, out _nativeGraph))
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.IsInitialized)
|
||||
return;
|
||||
|
||||
SubstanceEditorEngine.instance.InitializeInstance(_target, null, out SubstanceGraphSO _);
|
||||
|
||||
if (SubstanceEditorEngine.instance.TryGetHandlerFromInstance(_target, out _nativeGraph))
|
||||
_target.RuntimeInitialize(_nativeGraph, _target.IsRuntimeOnly);
|
||||
}
|
||||
|
||||
var outputList = serializedObject.FindProperty("Output");
|
||||
var list = new List<SerializedProperty>();
|
||||
|
||||
for (int i = 0; i < outputList.arraySize; i++)
|
||||
{
|
||||
var output = outputList.GetArrayElementAtIndex(i);
|
||||
var textureTarget = output.FindPropertyRelative("MaterialTextureTarget");
|
||||
list.Add(textureTarget);
|
||||
}
|
||||
|
||||
_outputProperties = list;
|
||||
}
|
||||
|
||||
private void GetShaderInputTextures(Shader shader)
|
||||
{
|
||||
_shaderInputTextures.Add("none");
|
||||
|
||||
for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); i++)
|
||||
{
|
||||
if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
|
||||
{
|
||||
_shaderInputTextures.Add(ShaderUtil.GetPropertyName(shader, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
if (_materialPreviewEditor != null)
|
||||
{
|
||||
_materialPreviewEditor.OnDisable();
|
||||
_materialPreviewEditor = null;
|
||||
}
|
||||
|
||||
SaveEditorChanges();
|
||||
EditorApplication.projectWindowItemOnGUI -= OnHierarchyWindowItemOnGUI;
|
||||
}
|
||||
|
||||
public void SaveEditorChanges()
|
||||
{
|
||||
if (_propertiesChanged)
|
||||
{
|
||||
SaveTGAFiles();
|
||||
UpdateGraphMaterialLabel();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
_propertiesChanged = false;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (serializedObject.targetObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_nativeGraph == null)
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.TryGetHandlerFromInstance(_target, out _nativeGraph))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_materialPreviewEditor == null)
|
||||
{
|
||||
var material = _target.OutputMaterial;
|
||||
|
||||
if (material != null)
|
||||
_materialPreviewEditor = MaterialEditor.CreateEditor(material) as MaterialEditor;
|
||||
}
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
if (DrawGraph())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
_propertiesChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback for GUI events to block substance files from been duplicated.
|
||||
/// </summary>
|
||||
/// <param name="guid">Asset guid.</param>
|
||||
/// <param name="rt">GUI rect.</param>
|
||||
protected static void OnHierarchyWindowItemOnGUI(string guid, Rect rt)
|
||||
{
|
||||
var currentEvent = Event.current;
|
||||
|
||||
if ("Duplicate" == currentEvent.commandName && currentEvent.type == EventType.ExecuteCommand)
|
||||
{
|
||||
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var instanceObject = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(assetPath);
|
||||
|
||||
if (instanceObject != null)
|
||||
{
|
||||
Debug.LogWarning("Substance graph can not be manually duplicated.");
|
||||
currentEvent.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Material Preview
|
||||
|
||||
public override bool HasPreviewGUI()
|
||||
{
|
||||
return _materialPreviewEditor != null;
|
||||
}
|
||||
|
||||
public override GUIContent GetPreviewTitle()
|
||||
{
|
||||
return new GUIContent("Material", null, "");
|
||||
}
|
||||
|
||||
public override void OnPreviewSettings()
|
||||
{
|
||||
if (_materialPreviewEditor)
|
||||
_materialPreviewEditor.OnPreviewSettings();
|
||||
}
|
||||
|
||||
public override void OnPreviewGUI(Rect r, GUIStyle background)
|
||||
{
|
||||
if (_materialPreviewEditor)
|
||||
_materialPreviewEditor.OnPreviewGUI(r, background);
|
||||
}
|
||||
|
||||
#endregion Material Preview
|
||||
|
||||
#region Draw
|
||||
|
||||
private bool DrawGraph()
|
||||
{
|
||||
bool valuesChanged = false;
|
||||
|
||||
if (DrawTextureGenerationSettings(_generateAllOutputsProperty, _generateAllMipmapsProperty, _runtimeOnlyProperty))
|
||||
{
|
||||
_outputRemapedProperty.boolValue = true;
|
||||
valuesChanged = true;
|
||||
}
|
||||
|
||||
GUILayout.Space(8);
|
||||
|
||||
DrawInputs(out bool serializedObject, out bool renderGraph);
|
||||
|
||||
if (renderGraph)
|
||||
{
|
||||
var newPreset = _nativeGraph.CreatePresetFromCurrentState();
|
||||
_presetProperty.stringValue = newPreset;
|
||||
SubstanceEditorEngine.instance.SubmitAsyncRenderWork(_nativeGraph, _target);
|
||||
valuesChanged = true;
|
||||
}
|
||||
|
||||
if (serializedObject)
|
||||
valuesChanged = true;
|
||||
|
||||
DrawPresentExport(_target);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
_showOutput = EditorGUILayout.Foldout(_showOutput, "Generated textures");
|
||||
|
||||
if (_showOutput)
|
||||
{
|
||||
if (DrawAdvanceSettings())
|
||||
{
|
||||
MaterialUtils.EnableEmissionIfAssigned(_target.OutputMaterial);
|
||||
_outputRemapedProperty.boolValue = true;
|
||||
valuesChanged = true;
|
||||
}
|
||||
|
||||
if (DrawGeneratedTextures(_graphOutputs, _generateAllOutputsProperty.boolValue))
|
||||
{
|
||||
_outputRemapedProperty.boolValue = true;
|
||||
valuesChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
return valuesChanged;
|
||||
}
|
||||
|
||||
#region Texture Generation Settings
|
||||
|
||||
private bool DrawTextureGenerationSettings(SerializedProperty generateAllOutputsProperty, SerializedProperty generateAllMipmapsProperty, SerializedProperty runtimeOnlyProperty)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
GUILayout.Space(4);
|
||||
|
||||
var boxWidth = EditorGUIUtility.currentViewWidth;
|
||||
var boxHeight = (3 * EditorGUIUtility.singleLineHeight) + 16;
|
||||
var padding = 16;
|
||||
|
||||
DrawHighlightBox(boxWidth, boxHeight, padding);
|
||||
|
||||
if (DrawGenerateAllOutputs(generateAllOutputsProperty) ||
|
||||
DrawGenerateAllMipmaps(generateAllMipmapsProperty) ||
|
||||
DrawRuntimeOnlyToggle(runtimeOnlyProperty))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static readonly GUIContent _GenerateAllOutputsGUI = new GUIContent("Generate All Outputs", "Force the generation of all Substance outputs");
|
||||
|
||||
private bool DrawGenerateAllOutputs(SerializedProperty generateAllOutputsProperty)
|
||||
{
|
||||
var oldValue = generateAllOutputsProperty.boolValue;
|
||||
generateAllOutputsProperty.boolValue = EditorGUILayout.Toggle(_GenerateAllOutputsGUI, generateAllOutputsProperty.boolValue);
|
||||
return oldValue != generateAllOutputsProperty.boolValue;
|
||||
}
|
||||
|
||||
private static readonly GUIContent _GenerateAllMipMapsGUI = new GUIContent("Generate Mip Maps", "Enable MipMaps when generating textures");
|
||||
|
||||
private bool DrawGenerateAllMipmaps(SerializedProperty generateAllMipmapsProperty)
|
||||
{
|
||||
var oldValue = generateAllMipmapsProperty.boolValue;
|
||||
generateAllMipmapsProperty.boolValue = EditorGUILayout.Toggle(_GenerateAllMipMapsGUI, generateAllMipmapsProperty.boolValue);
|
||||
return oldValue != generateAllMipmapsProperty.boolValue;
|
||||
}
|
||||
|
||||
private static readonly GUIContent _RuntimeOnlyGUI = new GUIContent("Runtime only", "If checked this instance will not generate TGA texture files");
|
||||
|
||||
private bool DrawRuntimeOnlyToggle(SerializedProperty runtimeOnlyProperty)
|
||||
{
|
||||
var oldValue = runtimeOnlyProperty.boolValue;
|
||||
runtimeOnlyProperty.boolValue = EditorGUILayout.Toggle(_RuntimeOnlyGUI, runtimeOnlyProperty.boolValue);
|
||||
return oldValue != runtimeOnlyProperty.boolValue;
|
||||
}
|
||||
|
||||
#endregion Texture Generation Settings
|
||||
|
||||
#region Physical size
|
||||
|
||||
private bool DrawPhysicalSize()
|
||||
{
|
||||
if (!_hasPhysicalSizeProperty.boolValue)
|
||||
return false;
|
||||
|
||||
_showPhysicalSize = EditorGUILayout.Foldout(_showPhysicalSize, "Physical Size");
|
||||
bool valueChanged = false;
|
||||
|
||||
if (_showPhysicalSize)
|
||||
{
|
||||
var currentValue = _physicalSizelProperty.vector3Value;
|
||||
var enablePhysicaSize = _enablePhysicalSizeProperty.boolValue;
|
||||
|
||||
if (EditorGUILayout.Toggle("Use Physical Size", enablePhysicaSize) != enablePhysicaSize)
|
||||
{
|
||||
_enablePhysicalSizeProperty.boolValue = !enablePhysicaSize;
|
||||
valueChanged = true;
|
||||
}
|
||||
|
||||
var newValue = new Vector3();
|
||||
|
||||
newValue.x = EditorGUILayout.FloatField("X:", currentValue.x);
|
||||
newValue.y = EditorGUILayout.FloatField("Y:", currentValue.y);
|
||||
newValue.z = EditorGUILayout.FloatField("Z:", currentValue.z);
|
||||
|
||||
if ((newValue - currentValue).sqrMagnitude >= 0.01f)
|
||||
{
|
||||
_physicalSizelProperty.vector3Value = newValue;
|
||||
valueChanged = true;
|
||||
}
|
||||
|
||||
if (_target.OutputMaterial != null)
|
||||
{
|
||||
DrawPhysicalSizeOffsets(_target.OutputMaterial);
|
||||
}
|
||||
}
|
||||
return valueChanged;
|
||||
}
|
||||
|
||||
private static bool _showPhysicalSizePositionOffset = false;
|
||||
|
||||
private void DrawPhysicalSizeOffsets(Material material)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
_showPhysicalSizePositionOffset = EditorGUILayout.Foldout(_showPhysicalSizePositionOffset, "Position Offset (In %)");
|
||||
|
||||
if (_showPhysicalSizePositionOffset)
|
||||
{
|
||||
Vector2 offset = MaterialUtils.GetPhysicalSizePositionOffset(material);
|
||||
Vector2 newOffset = offset;
|
||||
newOffset.x = EditorGUILayout.FloatField("X:", offset.x * 100.0f) / 100.0f;
|
||||
newOffset.y = EditorGUILayout.FloatField("Y:", offset.y * 100.0f) / 100.0f;
|
||||
|
||||
if ((newOffset - offset).sqrMagnitude >= 0.0000001f)
|
||||
{
|
||||
MaterialUtils.SetPhysicalSizePositionOffset(material, newOffset);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
#endregion Physical size
|
||||
|
||||
#region Input draw
|
||||
|
||||
/// <summary>
|
||||
/// Draws substance file inputs.
|
||||
/// </summary>
|
||||
/// <param name="serializeObject">True if object properties have changed.</param>
|
||||
/// <param name="renderGraph">True if substance graph must be re rendered.</param>
|
||||
private void DrawInputs(out bool serializeObject, out bool renderGraph)
|
||||
{
|
||||
renderGraph = false;
|
||||
serializeObject = false;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (DrawGrouplessInputs(_inputGroupingHelper.GrouplessInputs))
|
||||
{
|
||||
renderGraph = true;
|
||||
serializeObject = true;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (PhysicalSizeExtension.IsSupported())
|
||||
{
|
||||
if (DrawPhysicalSize())
|
||||
{
|
||||
renderGraph = true;
|
||||
serializeObject = true;
|
||||
MaterialUtils.ApplyPhysicalSize(_target.OutputMaterial, _physicalSizelProperty.vector3Value, _enablePhysicalSizeProperty.boolValue);
|
||||
UpdateGraphMaterialLabel();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
foreach (var groupInfo in _inputGroupingHelper.InputGroups)
|
||||
{
|
||||
if (DrawInputGroup(groupInfo))
|
||||
{
|
||||
renderGraph = true;
|
||||
serializeObject = true;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inputs that are not part of any input group.
|
||||
/// </summary>
|
||||
/// <param name="inputsInfo">Inputs info</param>
|
||||
/// <returns>True if any input has changed.</returns>
|
||||
private bool DrawGrouplessInputs(SubstanceInputGroupCachedInfo inputsInfo)
|
||||
{
|
||||
var indexArray = inputsInfo.Inputs;
|
||||
|
||||
bool changed = false;
|
||||
|
||||
for (int i = 0; i < indexArray.Count; i++)
|
||||
{
|
||||
var property = indexArray[i].InputProperty;
|
||||
var guiContent = indexArray[i].GUIContent;
|
||||
var index = indexArray[i].Index;
|
||||
|
||||
if (_nativeGraph.IsInputVisible(index))
|
||||
{
|
||||
if (SubstanceInputDrawer.DrawInput(property, guiContent, _nativeGraph, index))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws inputs from a input group.
|
||||
/// </summary>
|
||||
/// <param name="groupInfo"></param>
|
||||
/// <returns></returns>
|
||||
private bool DrawInputGroup(SubstanceInputGroupCachedInfo groupInfo)
|
||||
{
|
||||
var groupName = groupInfo.Name;
|
||||
var indexArray = groupInfo.Inputs;
|
||||
|
||||
groupInfo.ShowGroup = EditorGUILayout.Foldout(groupInfo.ShowGroup, groupName);
|
||||
|
||||
if (!groupInfo.ShowGroup)
|
||||
return false;
|
||||
|
||||
bool changed = false;
|
||||
|
||||
for (int i = 0; i < indexArray.Count; i++)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
var property = indexArray[i].InputProperty;
|
||||
var guiContent = indexArray[i].GUIContent;
|
||||
var index = indexArray[i].Index;
|
||||
|
||||
if (_nativeGraph.IsInputVisible(index))
|
||||
{
|
||||
if (SubstanceInputDrawer.DrawInput(property, guiContent, _nativeGraph, index))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
#endregion Input draw
|
||||
|
||||
#region Output draw
|
||||
|
||||
private static readonly GUIContent _GeneratedTextureGUI = new GUIContent();
|
||||
|
||||
private bool DrawGeneratedTextures(SerializedProperty outputList, bool generateAllTextures)
|
||||
{
|
||||
bool valueChanged = false;
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
using (var scrollViewScope = new EditorGUILayout.ScrollViewScope(_textureOutputScrollView, false, false))
|
||||
{
|
||||
scrollViewScope.handleScrollWheel = false;
|
||||
_textureOutputScrollView = scrollViewScope.scrollPosition;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
var outputsCount = outputList.arraySize;
|
||||
|
||||
for (int i = 0; i < outputsCount; i++)
|
||||
{
|
||||
var outputProperty = outputList.GetArrayElementAtIndex(i);
|
||||
var outputTexture = _target.Output[i];
|
||||
|
||||
if (generateAllTextures || outputTexture.IsStandardOutput(_target.OutputMaterial))
|
||||
valueChanged |= DrawOutputTexture(outputProperty, _GeneratedTextureGUI, outputTexture);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
return valueChanged;
|
||||
}
|
||||
|
||||
private bool DrawOutputTexture(SerializedProperty output, GUIContent content, SubstanceOutputTexture substanceOutput)
|
||||
{
|
||||
var valueChanged = false;
|
||||
|
||||
EditorGUILayout.BeginVertical(GUILayout.Width(120));
|
||||
{
|
||||
var texture = output.FindPropertyRelative("OutputTexture").objectReferenceValue as Texture2D;
|
||||
var label = output.FindPropertyRelative("Description.Channel").stringValue;
|
||||
var sRGB = output.FindPropertyRelative("sRGB");
|
||||
var alpha = output.FindPropertyRelative("AlphaChannel");
|
||||
var inverAlpha = output.FindPropertyRelative("InvertAssignedAlpha");
|
||||
var isAlphaAssignable = output.FindPropertyRelative("IsAlphaAssignable").boolValue;
|
||||
|
||||
//Draw texture preview.
|
||||
if (texture != null)
|
||||
{
|
||||
if (texture != null)
|
||||
{
|
||||
content.text = null;
|
||||
|
||||
var thumbnail = EditorUtility.IsDirty(texture) ? AssetPreview.GetMiniThumbnail(texture) : AssetPreview.GetAssetPreview(texture);
|
||||
|
||||
if (thumbnail == null)
|
||||
thumbnail = AssetPreview.GetAssetPreview(texture);
|
||||
|
||||
content.image = thumbnail;
|
||||
content.tooltip = texture.name;
|
||||
|
||||
if (GUILayout.Button(content, //style,
|
||||
GUILayout.Width(70),
|
||||
GUILayout.Height(70)))
|
||||
{
|
||||
// Highlight object in project browser:
|
||||
EditorGUIUtility.PingObject(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label(label);
|
||||
|
||||
if (substanceOutput.IsBaseColor() || substanceOutput.IsDiffuse() || substanceOutput.IsEmissive())
|
||||
{
|
||||
var oldsRGB = sRGB.boolValue;
|
||||
var newsRGB = GUILayout.Toggle(oldsRGB, "sRGB");
|
||||
|
||||
if (newsRGB != oldsRGB)
|
||||
{
|
||||
sRGB.boolValue = newsRGB;
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Draw alpha remapping.
|
||||
EditorGUILayout.BeginHorizontal(GUILayout.Width(80), GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
||||
{
|
||||
if (isAlphaAssignable)
|
||||
{
|
||||
var option = _outputChannelsHelper.GetAlphaChannels(label);
|
||||
var index = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(alpha.stringValue))
|
||||
index = Array.IndexOf(option, alpha.stringValue);
|
||||
|
||||
EditorGUILayout.LabelField("A", GUILayout.Width(10));
|
||||
|
||||
var newIndex = EditorGUILayout.Popup(index, option, GUILayout.Width(70));
|
||||
|
||||
if (newIndex != index)
|
||||
{
|
||||
alpha.stringValue = newIndex != 0 ? option[newIndex] : string.Empty;
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
//Draw inver alpha.
|
||||
EditorGUILayout.BeginHorizontal(GUILayout.Width(80), GUILayout.Height(EditorGUIUtility.singleLineHeight));
|
||||
{
|
||||
if (!string.IsNullOrEmpty(alpha.stringValue))
|
||||
{
|
||||
var oldValue = inverAlpha.boolValue;
|
||||
var newValue = GUILayout.Toggle(oldValue, "Invert alpha");
|
||||
|
||||
if (newValue != oldValue)
|
||||
{
|
||||
inverAlpha.boolValue = newValue;
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
return valueChanged;
|
||||
}
|
||||
|
||||
private static bool _showAdvanceSettings = false;
|
||||
|
||||
private readonly List<string> _shaderInputTextures = new List<string>();
|
||||
private string _shaderName = string.Empty;
|
||||
|
||||
private bool DrawAdvanceSettings()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
_showAdvanceSettings = EditorGUILayout.Foldout(_showAdvanceSettings, "Output Textures Mapping");
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (_showAdvanceSettings)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
if (_target.OutputMaterial != null)
|
||||
{
|
||||
if (!_shaderName.Equals(_target.OutputMaterial.shader.name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_shaderInputTextures.Clear();
|
||||
GetShaderInputTextures(_target.OutputMaterial.shader);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _outputProperties.Count; i++)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.TextField(_target.Output[i].Description.Channel, GUILayout.Width(200));
|
||||
|
||||
var oldstring = _outputProperties[i].stringValue;
|
||||
var oldSelected = _shaderInputTextures.FindIndex(0, _shaderInputTextures.Count, (value) => { return oldstring.Equals(value, StringComparison.OrdinalIgnoreCase); });
|
||||
|
||||
if (oldSelected == -1)
|
||||
oldSelected = 0;
|
||||
|
||||
var newSelectedIndex = EditorGUILayout.Popup("", oldSelected, _shaderInputTextures.ToArray());
|
||||
|
||||
if (newSelectedIndex != oldSelected)
|
||||
{
|
||||
result = true;
|
||||
var updateString = newSelectedIndex == 0 ? string.Empty : _shaderInputTextures[newSelectedIndex];
|
||||
_outputProperties[i].stringValue = updateString;
|
||||
MaterialUtils.UpdateTextureTarget(_target.OutputMaterial, _target.Output[i].OutputTexture, oldstring, updateString);
|
||||
|
||||
//Clean other outputs that have the same assignment.
|
||||
for (int j = 0; j < _outputProperties.Count; j++)
|
||||
{
|
||||
if (string.Equals(_outputProperties[j].stringValue, updateString) && i != j)
|
||||
{
|
||||
_outputProperties[j].stringValue = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion Output draw
|
||||
|
||||
#region Presets draw
|
||||
|
||||
private static readonly GUIContent _PresetExportGUIContent = new GUIContent("Export Preset...", "Save Preset");
|
||||
private static readonly GUIContent _PresetImportGUIContent = new GUIContent("Import Preset...", "Fetch Preset");
|
||||
private static readonly GUIContent _PresetResetGUIContent = new GUIContent("Reset Preset to Default", "Restore input defaults");
|
||||
|
||||
private void DrawPresentExport(SubstanceGraphSO graph)
|
||||
{
|
||||
int labelWidth = (int)EditorGUIUtility.labelWidth - 15;
|
||||
|
||||
_showExportPresentationHandler = EditorGUILayout.Foldout(_showExportPresentationHandler, "Preset Handling", true);
|
||||
|
||||
if (_showExportPresentationHandler)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.LabelField(" ", GUILayout.Width(labelWidth)); // Used to position the next button
|
||||
|
||||
if (GUILayout.Button(_PresetExportGUIContent))
|
||||
HandleExportPresets(graph);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.LabelField(" ", GUILayout.Width(labelWidth)); // Used to position the next button
|
||||
|
||||
if (GUILayout.Button(_PresetImportGUIContent))
|
||||
HandleImportPresets(graph);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(6);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
EditorGUILayout.LabelField(" ", GUILayout.Width(labelWidth)); // Used to position the next button
|
||||
|
||||
if (GUILayout.Button(_PresetResetGUIContent))
|
||||
HandleResetPresets(graph);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleExportPresets(SubstanceGraphSO graph)
|
||||
{
|
||||
string savePath = EditorUtility.SaveFilePanel("Save Preset as...", graph.AssetPath, graph.GetAssetFileName(), "sbsprs");
|
||||
|
||||
if (savePath != "")
|
||||
{
|
||||
string savePreset = "<sbspresets count=\"1\" formatversion=\"1.1\">\n "; //formatting line needed by other integrations
|
||||
savePreset += SubstanceEditorEngine.instance.ExportGraphPresetXML(graph);
|
||||
savePreset += "</sbspresets>";
|
||||
File.WriteAllText(savePath, savePreset);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleImportPresets(SubstanceGraphSO graph)
|
||||
{
|
||||
string loadPath = EditorUtility.OpenFilePanel("Select Preset", graph.AssetPath, "sbsprs");
|
||||
|
||||
if (loadPath != "")
|
||||
{
|
||||
string presetFile = System.IO.File.ReadAllText(loadPath);
|
||||
|
||||
int startIndex = presetFile.IndexOf("<sbspreset ");
|
||||
int endIndex = presetFile.IndexOf("sbspreset>") + 10;
|
||||
var presetXML = presetFile.Substring(startIndex, endIndex - startIndex);
|
||||
|
||||
SubstanceEditorEngine.instance.LoadPresetsToGraph(graph, presetXML);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleResetPresets(SubstanceGraphSO graph)
|
||||
{
|
||||
SubstanceEditorEngine.instance.LoadPresetsToGraph(graph, graph.DefaultPreset);
|
||||
}
|
||||
|
||||
#endregion Presets draw
|
||||
|
||||
#region Thumbnail preview
|
||||
|
||||
public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height)
|
||||
{
|
||||
if (_target.HasThumbnail)
|
||||
return _target.GetThumbnailTexture();
|
||||
|
||||
var icon = UnityPackageInfo.GetSubstanceIcon(width, height);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
Texture2D tex = new Texture2D(width, height);
|
||||
EditorUtility.CopySerialized(icon, tex);
|
||||
return tex;
|
||||
}
|
||||
|
||||
return base.RenderStaticPreview(assetPath, subAssets, width, height);
|
||||
}
|
||||
|
||||
#endregion Thumbnail preview
|
||||
|
||||
#endregion Draw
|
||||
|
||||
#region Scene Drag
|
||||
|
||||
public void OnSceneDrag(SceneView sceneView, int index)
|
||||
{
|
||||
Event evt = Event.current;
|
||||
|
||||
if (evt.type == EventType.Repaint)
|
||||
return;
|
||||
|
||||
var materialIndex = -1;
|
||||
var go = HandleUtility.PickGameObject(evt.mousePosition, out materialIndex);
|
||||
|
||||
if (_target.OutputMaterial != null)
|
||||
{
|
||||
if (go && go.GetComponent<Renderer>())
|
||||
{
|
||||
HandleRenderer(go.GetComponent<Renderer>(), materialIndex, _target.OutputMaterial, evt.type, evt.alt);
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
|
||||
if (_target.IsRuntimeOnly)
|
||||
{
|
||||
var runtimeComponent = go.GetComponent<Adobe.Substance.Runtime.SubstanceRuntimeGraph>();
|
||||
|
||||
if (runtimeComponent == null)
|
||||
runtimeComponent = go.AddComponent<Adobe.Substance.Runtime.SubstanceRuntimeGraph>();
|
||||
|
||||
runtimeComponent.AttachGraph(_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void HandleRenderer(Renderer r, int materialIndex, Material dragMaterial, EventType eventType, bool alt)
|
||||
{
|
||||
var applyMaterial = false;
|
||||
switch (eventType)
|
||||
{
|
||||
case EventType.DragUpdated:
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
|
||||
applyMaterial = true;
|
||||
break;
|
||||
|
||||
case EventType.DragPerform:
|
||||
DragAndDrop.AcceptDrag();
|
||||
applyMaterial = true;
|
||||
break;
|
||||
}
|
||||
if (applyMaterial)
|
||||
{
|
||||
var materials = r.sharedMaterials;
|
||||
|
||||
bool isValidMaterialIndex = (materialIndex >= 0 && materialIndex < r.sharedMaterials.Length);
|
||||
if (!alt && isValidMaterialIndex)
|
||||
{
|
||||
materials[materialIndex] = dragMaterial;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int q = 0; q < materials.Length; ++q)
|
||||
materials[q] = dragMaterial;
|
||||
}
|
||||
|
||||
r.sharedMaterials = materials;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Scene Drag
|
||||
|
||||
#region Utilities
|
||||
|
||||
private void SaveTGAFiles()
|
||||
{
|
||||
if (_target == null)
|
||||
return;
|
||||
|
||||
if (_target.IsRuntimeOnly)
|
||||
return;
|
||||
|
||||
_target.OutputRemaped = true;
|
||||
_target.RenderTextures = true;
|
||||
EditorUtility.SetDirty(_target);
|
||||
}
|
||||
|
||||
private Rect DrawHighlightBox(float width, float height, float xPadding)
|
||||
{
|
||||
float bx, by, bw, bh;
|
||||
|
||||
bx = xPadding;
|
||||
by = GetPosition();
|
||||
bw = width - xPadding;
|
||||
bh = height;
|
||||
|
||||
var boxRect = new Rect(bx, by, bw, bh);
|
||||
|
||||
var backgroundStyle = new GUIStyle();
|
||||
backgroundStyle.normal.background = _backgroundImage;
|
||||
GUI.Box(boxRect, GUIContent.none, backgroundStyle);
|
||||
return boxRect;
|
||||
}
|
||||
|
||||
private int GetPosition()
|
||||
{
|
||||
Rect rect = GUILayoutUtility.GetLastRect();
|
||||
|
||||
if ((rect.x != 0) || (rect.y != 0))
|
||||
lastRect = rect;
|
||||
|
||||
return (int)lastRect.y;
|
||||
}
|
||||
|
||||
/// This is a workaround a bug in the Unity asset database for generating materials previews.
|
||||
/// It basically generated a previews image whenever a property changes in the material, but it is now considering changes in the
|
||||
/// textures assign to the material itself. By adding a random label we ensure that the asset preview image will be updated.
|
||||
private void UpdateGraphMaterialLabel()
|
||||
{
|
||||
if (_target == null)
|
||||
return;
|
||||
|
||||
const string tagPrefix = "sb_";
|
||||
|
||||
var material = _target.OutputMaterial;
|
||||
|
||||
if (material != null)
|
||||
{
|
||||
var labels = AssetDatabase.GetLabels(material);
|
||||
var newLabels = labels.Where(a => !a.Contains(tagPrefix)).ToList();
|
||||
newLabels.Add($"{tagPrefix}{Guid.NewGuid().ToString("N")}");
|
||||
AssetDatabase.SetLabels(material, newLabels.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Utilities
|
||||
|
||||
/// Work around Unity SerializedObjectNotCreatableException during script compilation.
|
||||
private bool IsSerializedObjectReady()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (serializedObject.targetObject == null)
|
||||
return false;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94692ae502378e0469eba20cb87193c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09746064b4df14847928695cb7c68c07
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,66 @@
|
||||
using Adobe.Substance;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// General utilites for material creating and output texture assignment.
|
||||
/// </summary>
|
||||
internal static class AssetCreationUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a Unity material and set its textures according to the currently in use Unity render pipeline.//
|
||||
/// </summary>
|
||||
/// <param name="graph"></param>
|
||||
/// <returns></returns>
|
||||
public static void CreateMaterialOrUpdateMaterial(SubstanceGraphSO graph, string instanceName)
|
||||
{
|
||||
var materialOutput = graph.GetAssociatedAssetPath($"{instanceName}_material", "mat");
|
||||
var oldMaterial = AssetDatabase.LoadAssetAtPath<Material>(materialOutput);
|
||||
|
||||
if (oldMaterial != null)
|
||||
{
|
||||
graph.OutputMaterial = oldMaterial;
|
||||
}
|
||||
|
||||
bool createMaterial = graph.OutputMaterial == null;
|
||||
|
||||
if (createMaterial)
|
||||
{
|
||||
graph.OutputMaterial = new Material(MaterialUtils.GetStandardShader())
|
||||
{
|
||||
name = Path.GetFileNameWithoutExtension(materialOutput)
|
||||
};
|
||||
}
|
||||
|
||||
MaterialUtils.AssignOutputTexturesToMaterial(graph);
|
||||
|
||||
if (createMaterial)
|
||||
AssetDatabase.CreateAsset(graph.OutputMaterial, materialOutput);
|
||||
else
|
||||
EditorUtility.SetDirty(graph.OutputMaterial);
|
||||
|
||||
graph.MaterialShader = graph.OutputMaterial.shader.name;
|
||||
}
|
||||
|
||||
public static void UpdateMeterialAssignment(SubstanceGraphSO graph)
|
||||
{
|
||||
graph.MaterialShader = graph.OutputMaterial.shader.name;
|
||||
|
||||
foreach (var output in graph.Output)
|
||||
{
|
||||
if (!output.IsStandardOutput(graph.OutputMaterial) && (!graph.GenerateAllOutputs))
|
||||
{
|
||||
var texturePath = AssetDatabase.GetAssetPath(output.OutputTexture);
|
||||
|
||||
if (File.Exists(texturePath))
|
||||
AssetDatabase.DeleteAsset(texturePath);
|
||||
|
||||
output.OutputTexture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc9df0d9c52231245aa194e418a9c115
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,67 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class with utility methods commonly used to draw substance properties and UI.
|
||||
/// </summary>
|
||||
internal static class EditorDrawUtilities
|
||||
{
|
||||
private static readonly string[] _resolutions = { "256", "512", "1024", "2048", "4096" };
|
||||
|
||||
public static void DrawResolutionSelection(SerializedProperty property, GUIContent content, params GUILayoutOption[] options)
|
||||
{
|
||||
Vector2Int oldValue = property.vector2IntValue;
|
||||
var currentIndex = GetEnumIndex(oldValue);
|
||||
int newIndex = EditorGUILayout.Popup(content, currentIndex, _resolutions, options);
|
||||
|
||||
if (currentIndex != newIndex)
|
||||
{
|
||||
Vector2Int newValue = GetValueFromIndex(newIndex);
|
||||
property.vector2IntValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetEnumIndex(Vector2Int data)
|
||||
{
|
||||
switch (data.x)
|
||||
{
|
||||
case 8:
|
||||
return 0;
|
||||
|
||||
case 9:
|
||||
return 1;
|
||||
|
||||
case 10:
|
||||
return 2;
|
||||
|
||||
case 11:
|
||||
return 3;
|
||||
|
||||
case 12:
|
||||
return 4;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector2Int GetValueFromIndex(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return new Vector2Int(8, 8);
|
||||
case 1: return new Vector2Int(9, 9);
|
||||
case 2: return new Vector2Int(10, 10);
|
||||
case 3: return new Vector2Int(11, 11);
|
||||
case 4: return new Vector2Int(12, 12);
|
||||
|
||||
default:
|
||||
return new Vector2Int(8, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fb287e26604e6d4493b8ad922d4b790
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,353 @@
|
||||
using Adobe.Substance;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class EditorTools
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes an object editable. (Usefull for object managed by Importers)
|
||||
/// </summary>
|
||||
/// <param name="pObject"></param>
|
||||
public static void OverrideReadOnlyFlag(UnityEngine.Object unityObject)
|
||||
{
|
||||
unityObject.hideFlags &= ~HideFlags.NotEditable;
|
||||
}
|
||||
|
||||
public static SubstanceGraphSO CreateSubstanceInstance(string assetPath, SubstanceFileRawData fileData, string name, int index, string guid, bool isRoot = false, SubstanceGraphSO copy = null)
|
||||
{
|
||||
var instanceAsset = ScriptableObject.CreateInstance<SubstanceGraphSO>();
|
||||
instanceAsset.AssetPath = assetPath;
|
||||
instanceAsset.RawData = fileData;
|
||||
instanceAsset.Name = name;
|
||||
instanceAsset.IsRoot = isRoot;
|
||||
instanceAsset.GUID = guid;
|
||||
instanceAsset.OutputPath = CreateGraphFolder(assetPath, name);
|
||||
instanceAsset.SetNativeID(index);
|
||||
instanceAsset.GenerateAllMipmaps = true;
|
||||
var instancePath = MakeRootGraphAssetPath(instanceAsset);
|
||||
SubstanceEditorEngine.instance.InitializeInstance(instanceAsset, instancePath, out SubstanceGraphSO _);
|
||||
SubstanceEditorEngine.instance.CreateGraphObject(instanceAsset, copy);
|
||||
AssetDatabase.CreateAsset(instanceAsset, instancePath);
|
||||
return instanceAsset;
|
||||
}
|
||||
|
||||
public static void UpdateSubstanceInstance(SubstanceGraphSO instanceAsset, SubstanceFileRawData newFileData)
|
||||
{
|
||||
instanceAsset.RawData = newFileData;
|
||||
var inputState = SubstanceEditorEngine.instance.SerializeCurrentState(instanceAsset);
|
||||
SubstanceEditorEngine.instance.ReleaseInstance(instanceAsset);
|
||||
SubstanceEditorEngine.instance.InitializeInstance(instanceAsset, null, out SubstanceGraphSO _);
|
||||
SubstanceEditorEngine.instance.SetStateFromSerializedData(instanceAsset, inputState);
|
||||
SubstanceEditorEngine.instance.CreateGraphObject(instanceAsset, null);
|
||||
}
|
||||
|
||||
public class SubstanceInstanceInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Index { get; set; }
|
||||
public string GUID { get; set; }
|
||||
public bool IsRoot { get; set; }
|
||||
|
||||
public SubstanceInstanceInfo()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateSubstanceInstanceAsync(string assetPath, SubstanceFileRawData fileData, IEnumerable<SubstanceInstanceInfo> infos)
|
||||
{
|
||||
var instances = new List<Tuple<SubstanceGraphSO, string>>();
|
||||
|
||||
foreach (var item in infos)
|
||||
{
|
||||
var instanceAsset = ScriptableObject.CreateInstance<SubstanceGraphSO>();
|
||||
instanceAsset.AssetPath = assetPath;
|
||||
instanceAsset.RawData = fileData;
|
||||
instanceAsset.Name = item.Name;
|
||||
instanceAsset.IsRoot = item.IsRoot;
|
||||
instanceAsset.GUID = item.GUID;
|
||||
instanceAsset.OutputPath = CreateGraphFolder(assetPath, item.Name);
|
||||
instanceAsset.SetNativeID(item.Index);
|
||||
instanceAsset.GenerateAllMipmaps = true;
|
||||
var instancePath = MakeRootGraphAssetPath(instanceAsset);
|
||||
SubstanceEditorEngine.instance.InitializeInstance(instanceAsset, instancePath, out SubstanceGraphSO matchingInstance);
|
||||
|
||||
SubstanceEditorEngine.instance.CreateGraphObject(instanceAsset, matchingInstance);
|
||||
instances.Add(new Tuple<SubstanceGraphSO, string>(instanceAsset, instancePath));
|
||||
}
|
||||
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
SubstanceEditorEngine.instance.DelayAssetCreation(instance.Item1, instance.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Rename(this SubstanceGraphSO substanceMaterial, string name)
|
||||
{
|
||||
var oldFolder = substanceMaterial.OutputPath;
|
||||
|
||||
if (substanceMaterial.Name == name)
|
||||
return;
|
||||
|
||||
substanceMaterial.Name = name;
|
||||
|
||||
var dir = Path.GetDirectoryName(substanceMaterial.AssetPath);
|
||||
var assetName = Path.GetFileNameWithoutExtension(substanceMaterial.AssetPath);
|
||||
var newFolder = Path.Combine(dir, $"{assetName}_{name}");
|
||||
substanceMaterial.OutputPath = newFolder;
|
||||
|
||||
FileUtil.MoveFileOrDirectory(oldFolder, substanceMaterial.OutputPath);
|
||||
File.Delete($"{oldFolder}.meta");
|
||||
|
||||
EditorUtility.SetDirty(substanceMaterial);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
var oldPath = AssetDatabase.GetAssetPath(substanceMaterial);
|
||||
var error = AssetDatabase.RenameAsset(oldPath, $"{name}.asset");
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
Debug.LogError(error);
|
||||
|
||||
var materialOldName = AssetDatabase.GetAssetPath(substanceMaterial.OutputMaterial);
|
||||
var materialNewName = Path.GetFileName(substanceMaterial.GetAssociatedAssetPath($"{name}_material", "mat"));
|
||||
error = AssetDatabase.RenameAsset(materialOldName, materialNewName);
|
||||
EditorUtility.SetDirty(substanceMaterial.OutputMaterial);
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
Debug.LogError(error);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
public static void Move(this SubstanceGraphSO substanceMaterial, string to)
|
||||
{
|
||||
substanceMaterial.OutputPath = Path.GetDirectoryName(to);
|
||||
|
||||
var oldMaterialPath = AssetDatabase.GetAssetPath(substanceMaterial.OutputMaterial);
|
||||
AssetDatabase.MoveAsset(oldMaterialPath, Path.Combine(substanceMaterial.OutputPath, Path.GetFileName(oldMaterialPath)));
|
||||
|
||||
foreach (var output in substanceMaterial.Output)
|
||||
{
|
||||
var textureAssetPath = AssetDatabase.GetAssetPath(output.OutputTexture);
|
||||
var textureFileName = Path.GetFileName(textureAssetPath);
|
||||
var newTexturePath = Path.Combine(substanceMaterial.OutputPath, textureFileName);
|
||||
AssetDatabase.MoveAsset(textureAssetPath, newTexturePath);
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(substanceMaterial);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private static string CreateGraphFolder(string assetPath, string graphName)
|
||||
{
|
||||
var dir = Path.GetDirectoryName(assetPath);
|
||||
var assetName = Path.GetFileNameWithoutExtension(assetPath);
|
||||
|
||||
var newFolder = Path.Combine(dir, $"{assetName}_{graphName}");
|
||||
|
||||
if (Directory.Exists(newFolder))
|
||||
return newFolder;
|
||||
|
||||
string guid = AssetDatabase.CreateFolder(dir, $"{assetName}_{graphName}");
|
||||
return AssetDatabase.GUIDToAssetPath(guid);
|
||||
}
|
||||
|
||||
private static string MakeRootGraphAssetPath(SubstanceGraphSO substanceMaterial)
|
||||
{
|
||||
return Path.Combine(substanceMaterial.OutputPath, $"{substanceMaterial.Name}.asset");
|
||||
}
|
||||
}
|
||||
|
||||
public static class SubstanceEditorTools
|
||||
{
|
||||
public static void SetGraphFloatInput(SubstanceGraphSO graph, int inputId, float value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.floatValue = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphFloat2Input(SubstanceGraphSO graph, int inputId, Vector2 value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.vector2Value = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphFloat3Input(SubstanceGraphSO graph, int inputId, Vector3 value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.vector3Value = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphFloat4Input(SubstanceGraphSO graph, int inputId, Vector3 value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.vector4Value = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphIntInput(SubstanceGraphSO graph, int inputId, int value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.intValue = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphInt2Input(SubstanceGraphSO graph, int inputId, Vector2Int value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.vector2IntValue = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphInt3Input(SubstanceGraphSO graph, int inputId, Vector3Int value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.vector3IntValue = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphInt4Input(SubstanceGraphSO graph, int inputId, int value0, int value1, int value2, int value3)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp0 = graphInput.FindPropertyRelative("Data0");
|
||||
var dataProp1 = graphInput.FindPropertyRelative("Data1");
|
||||
var dataProp2 = graphInput.FindPropertyRelative("Data2");
|
||||
var dataProp3 = graphInput.FindPropertyRelative("Data3");
|
||||
dataProp0.intValue = value0;
|
||||
dataProp1.intValue = value1;
|
||||
dataProp2.intValue = value2;
|
||||
dataProp3.intValue = value3;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphInputString(SubstanceGraphSO graph, int inputId, string value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.stringValue = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
public static void SetGraphInputTexture(SubstanceGraphSO graph, int inputId, Texture2D value)
|
||||
{
|
||||
var so = new SerializedObject(graph);
|
||||
var graphInputs = so.FindProperty("Input");
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(inputId);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
dataProp.objectReferenceValue = value;
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
UpdateNativeInput(graph, inputId);
|
||||
}
|
||||
|
||||
private static void UpdateNativeInput(SubstanceGraphSO graph, int inputId)
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.TryGetHandlerFromInstance(graph, out SubstanceNativeGraph _nativeGraph))
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.IsInitialized)
|
||||
return;
|
||||
|
||||
SubstanceEditorEngine.instance.InitializeInstance(graph, null, out SubstanceGraphSO _);
|
||||
}
|
||||
|
||||
if (SubstanceEditorEngine.instance.TryGetHandlerFromInstance(graph, out _nativeGraph))
|
||||
graph.RuntimeInitialize(_nativeGraph, graph.IsRuntimeOnly);
|
||||
|
||||
graph.Input[inputId].UpdateNativeHandle(_nativeGraph);
|
||||
}
|
||||
|
||||
public static void RenderGraph(SubstanceGraphSO graph)
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.TryGetHandlerFromInstance(graph, out SubstanceNativeGraph _nativeGraph))
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.IsInitialized)
|
||||
return;
|
||||
|
||||
SubstanceEditorEngine.instance.InitializeInstance(graph, null, out SubstanceGraphSO _);
|
||||
}
|
||||
|
||||
if (SubstanceEditorEngine.instance.TryGetHandlerFromInstance(graph, out _nativeGraph))
|
||||
{
|
||||
SubstanceEditorEngine.instance.SubmitAsyncRenderWork(_nativeGraph, graph);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CreatePresetFromCurrentState(SubstanceGraphSO graph)
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.TryGetHandlerFromInstance(graph, out SubstanceNativeGraph _nativeGraph))
|
||||
{
|
||||
if (!SubstanceEditorEngine.instance.IsInitialized)
|
||||
return string.Empty;
|
||||
|
||||
SubstanceEditorEngine.instance.InitializeInstance(graph, null, out SubstanceGraphSO _);
|
||||
}
|
||||
|
||||
if (SubstanceEditorEngine.instance.TryGetHandlerFromInstance(graph, out _nativeGraph))
|
||||
graph.RuntimeInitialize(_nativeGraph, graph.IsRuntimeOnly);
|
||||
|
||||
return _nativeGraph.CreatePresetFromCurrentState();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9501269c4defb994083f07343a9de616
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,165 @@
|
||||
using Adobe.Substance;
|
||||
using Adobe.Substance.Input.Description;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Cached info for a substance input. Allow drawing UI without having to query description values from the SerializedProperty object.
|
||||
/// </summary>
|
||||
internal class SubstanceInputCachedInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Input serialized property.
|
||||
/// </summary>
|
||||
public SerializedProperty InputProperty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// GUIContent for the drawing the input.
|
||||
/// </summary>
|
||||
public SubstanceInputGUIContent GUIContent { get; }
|
||||
|
||||
public int Index { get; }
|
||||
|
||||
public SubstanceInputCachedInfo(SerializedProperty inputProperty, SubstanceInputGUIContent GUIContent, int index)
|
||||
{
|
||||
this.InputProperty = inputProperty;
|
||||
this.GUIContent = GUIContent;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubstanceInputGroupCachedInfo
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public List<SubstanceInputCachedInfo> Inputs { get; }
|
||||
|
||||
public bool ShowGroup { get; set; }
|
||||
|
||||
public SubstanceInputGroupCachedInfo(string groupName)
|
||||
{
|
||||
Name = groupName;
|
||||
Inputs = new List<SubstanceInputCachedInfo>();
|
||||
ShowGroup = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for caching grouping information for inputs so we don't have to query them every UI draw.
|
||||
/// </summary>
|
||||
internal class GraphInputsGroupingHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Readonly list with all input groups and their elements info.
|
||||
/// </summary>
|
||||
public IReadOnlyList<SubstanceInputGroupCachedInfo> InputGroups { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Groups with inputs that don't have grouping information.
|
||||
/// </summary>
|
||||
public SubstanceInputGroupCachedInfo GrouplessInputs { get; }
|
||||
|
||||
public GraphInputsGroupingHelper(SubstanceGraphSO graph, SerializedObject targetObject)
|
||||
{
|
||||
var GUIgroups = new List<SubstanceInputGroupCachedInfo>();
|
||||
var graphInputs = targetObject.FindProperty("Input");
|
||||
var groups = graph.Input.Select(a => a.Description.GuiGroup).Distinct();
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var groupInfo = new SubstanceInputGroupCachedInfo(group);
|
||||
|
||||
for (int i = 0; i < graph.Input.Count; i++)
|
||||
{
|
||||
var target = graph.Input[i];
|
||||
|
||||
if (target.Description.GuiGroup == group)
|
||||
{
|
||||
SubstanceInputGUIContent guiContent;
|
||||
|
||||
var graphInput = graphInputs.GetArrayElementAtIndex(i);
|
||||
var dataProp = graphInput.FindPropertyRelative("Data");
|
||||
|
||||
target.TryGetNumericalDescription(out ISubstanceInputDescNumerical descNumerical);
|
||||
|
||||
switch (target.Description.Type)
|
||||
{
|
||||
case SubstanceValueType.Float:
|
||||
guiContent = new SubstanceFloatGUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalFloat);
|
||||
break;
|
||||
|
||||
case SubstanceValueType.Float2:
|
||||
guiContent = new SubstanceFloat2GUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalFloat2);
|
||||
break;
|
||||
|
||||
case SubstanceValueType.Float3:
|
||||
guiContent = new SubstanceFloat3GUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalFloat3);
|
||||
break;
|
||||
|
||||
case SubstanceValueType.Float4:
|
||||
guiContent = new SubstanceFloat4GUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalFloat4);
|
||||
break;
|
||||
|
||||
case SubstanceValueType.Int:
|
||||
guiContent = (target.Description.WidgetType == SubstanceWidgetType.ComboBox) ? new SubstanceIntComboBoxGUIContent(target.Description, descNumerical as SubstanceInputDescNumericalInt, dataProp) : new SubstanceIntGUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalInt);
|
||||
break;
|
||||
|
||||
case SubstanceValueType.Int2:
|
||||
guiContent = new SubstanceInt2GUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalInt2);
|
||||
break;
|
||||
|
||||
case SubstanceValueType.Int3:
|
||||
guiContent = new SubstanceInt3GUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalInt3);
|
||||
break;
|
||||
|
||||
case SubstanceValueType.Int4:
|
||||
guiContent = new SubstanceInt4GUIContent(target.Description, dataProp, descNumerical as SubstanceInputDescNumericalInt4);
|
||||
break;
|
||||
|
||||
default:
|
||||
guiContent = new SubstanceInputGUIContent(target.Description, dataProp);
|
||||
break;
|
||||
}
|
||||
|
||||
groupInfo.Inputs.Add(new SubstanceInputCachedInfo(graphInput, guiContent, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(groupInfo.Name))
|
||||
{
|
||||
if (GrouplessInputs == null)
|
||||
GrouplessInputs = groupInfo;
|
||||
else
|
||||
GrouplessInputs.Inputs.AddRange(groupInfo.Inputs);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIgroups.Add(groupInfo);
|
||||
}
|
||||
}
|
||||
|
||||
InputGroups = GUIgroups;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GraphOutputAlphaChannelsHelper
|
||||
{
|
||||
private readonly List<string> _channels;
|
||||
|
||||
public GraphOutputAlphaChannelsHelper(SubstanceGraphSO graph)
|
||||
{
|
||||
_channels = new List<string> { "source" };
|
||||
|
||||
foreach (var item in graph.Output.Where(a => a.IsAlphaAssignable).Select(b => b.Description.Label))
|
||||
_channels.Add(item);
|
||||
}
|
||||
|
||||
public string[] GetAlphaChannels(string label)
|
||||
{
|
||||
return _channels.Where(a => a != label).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 613ef46be9575f44fbcb243ab26b4db4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,19 @@
|
||||
using Adobe.Substance;
|
||||
using System.IO;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
public static class NamingExtensions
|
||||
{
|
||||
public static string GetAssociatedAssetPath(this SubstanceGraphSO graph, string name, string extension)
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(graph.AssetPath);
|
||||
return Path.Combine(graph.OutputPath, $"{fileName}_{name}.{extension}");
|
||||
}
|
||||
|
||||
public static string GetAssetFileName(this SubstanceGraphSO graph)
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(graph.AssetPath);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5bf22d7a02c9e744483e24b116112bb8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,68 @@
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using System.IO;
|
||||
using Adobe.Substance;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
public class SubstanceBuildUtils
|
||||
{
|
||||
[PostProcessBuildAttribute(1)]
|
||||
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
|
||||
{
|
||||
if (target == BuildTarget.StandaloneLinux64)
|
||||
OnPostprocessBuildLinux(pathToBuiltProject);
|
||||
else if (target == BuildTarget.StandaloneOSX)
|
||||
OnPostprocessBuildMac(pathToBuiltProject);
|
||||
|
||||
SubstanceEditorEngine.instance.RefreshActiveInstances();
|
||||
}
|
||||
|
||||
private static void OnPostprocessBuildLinux(string pathToBuiltProject)
|
||||
{
|
||||
var dataPath = pathToBuiltProject.Replace(".x86_64", "_Data");
|
||||
var pluginsPath = Path.Combine(dataPath, "Plugins");
|
||||
|
||||
if (!Directory.Exists(pluginsPath))
|
||||
Directory.CreateDirectory(pluginsPath);
|
||||
|
||||
var enginePath = Path.GetDirectoryName(PlatformUtils.GetEnginePath());
|
||||
string[] files = Directory.GetFiles(enginePath);
|
||||
|
||||
foreach (string s in files)
|
||||
{
|
||||
var extension = Path.GetExtension(s);
|
||||
|
||||
if (string.Equals(extension, ".so") || string.Equals(extension, ".1"))
|
||||
{
|
||||
var fileName = Path.GetFileName(s);
|
||||
var testination = Path.Combine(pluginsPath, fileName);
|
||||
File.Copy(s, testination, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnPostprocessBuildMac(string pathToBuiltProject)
|
||||
{
|
||||
var pluginsPath = Path.Combine(Path.Combine(pathToBuiltProject, "Contents"), "PlugIns");
|
||||
|
||||
if (!Directory.Exists(pluginsPath))
|
||||
Directory.CreateDirectory(pluginsPath);
|
||||
|
||||
var enginePath = Path.GetDirectoryName(PlatformUtils.GetEnginePath());
|
||||
string[] files = Directory.GetFiles(enginePath);
|
||||
|
||||
foreach (string s in files)
|
||||
{
|
||||
var extension = Path.GetExtension(s);
|
||||
|
||||
if (string.Equals(extension, ".dylib") || string.Equals(extension, ".1"))
|
||||
{
|
||||
var fileName = Path.GetFileName(s);
|
||||
var testination = Path.Combine(pluginsPath, fileName);
|
||||
File.Copy(s, testination, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18d63636c53acdc4680dd008426e63f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,39 @@
|
||||
using Adobe.Substance;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class SubstanceFileExtensions
|
||||
{
|
||||
internal static List<SubstanceGraphSO> GetGraphs(this SubstanceFileSO fileSO)
|
||||
{
|
||||
var result = new List<SubstanceGraphSO>();
|
||||
|
||||
var path = AssetDatabase.GetAssetPath(fileSO);
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(SubstanceGraphSO)));
|
||||
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
SubstanceGraphSO graph = AssetDatabase.LoadAssetAtPath<SubstanceGraphSO>(assetPath);
|
||||
|
||||
if (graph != null)
|
||||
{
|
||||
var filePath = AssetDatabase.GetAssetPath(graph.RawData);
|
||||
|
||||
if (filePath.Equals(path, System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Add(graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d88a151702771984bb824b8639661be1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,121 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Adobe.SubstanceEditor
|
||||
{
|
||||
internal static class TextureUtils
|
||||
{
|
||||
public static bool IsCompressed(this TextureFormat unityFormat)
|
||||
{
|
||||
switch (unityFormat)
|
||||
{
|
||||
case TextureFormat.RGBA32:
|
||||
case TextureFormat.RGBA64:
|
||||
case TextureFormat.RGB24:
|
||||
case TextureFormat.BGRA32:
|
||||
case TextureFormat.R8:
|
||||
case TextureFormat.R16:
|
||||
case TextureFormat.RFloat:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture2D SetReadableFlag(Texture2D pTexture, bool pReadable)
|
||||
{
|
||||
Texture2D texture = pTexture;
|
||||
|
||||
if (pTexture == null)
|
||||
return null;
|
||||
|
||||
string assetPath = AssetDatabase.GetAssetPath(pTexture);
|
||||
|
||||
var textureImporter = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
||||
if (textureImporter != null)
|
||||
{
|
||||
if (textureImporter.isReadable == pReadable)
|
||||
return pTexture;
|
||||
|
||||
textureImporter.isReadable = pReadable;
|
||||
Debug.LogWarning(string.Format("Setting {0}'s 'Read/Write Enabled' flag to {1}",
|
||||
pTexture.name, (pReadable ? "true" : "false")));
|
||||
|
||||
EditorUtility.SetDirty(textureImporter);
|
||||
AssetDatabase.ImportAsset(assetPath);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
texture = AssetDatabase.LoadMainAssetAtPath(assetPath) as Texture2D;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
public static Texture2D EnsureTextureCorrectness(Texture2D pTexture, bool ensureRGBA, bool enableMipMaps)
|
||||
{
|
||||
Texture2D texture = pTexture;
|
||||
|
||||
if (pTexture == null)
|
||||
return null;
|
||||
|
||||
string assetPath = AssetDatabase.GetAssetPath(pTexture);
|
||||
|
||||
var textureImporter = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
||||
|
||||
if (textureImporter != null)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if (textureImporter.textureCompression != TextureImporterCompression.Uncompressed)
|
||||
{
|
||||
textureImporter.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
Debug.LogWarning(string.Format("Setting {0}'s 'Compression' flag to Uncompressed", pTexture.name));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (textureImporter.isReadable != true)
|
||||
{
|
||||
textureImporter.isReadable = true;
|
||||
Debug.LogWarning(string.Format("Setting {0}'s 'Read/Write Enabled' flag to {1}",
|
||||
pTexture.name, (true ? "true" : "false")));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (textureImporter.maxTextureSize < 4096)
|
||||
{
|
||||
textureImporter.maxTextureSize = 4096;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (enableMipMaps != textureImporter.mipmapEnabled)
|
||||
{
|
||||
textureImporter.mipmapEnabled = enableMipMaps;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (ensureRGBA)
|
||||
{
|
||||
var defaultSettings = textureImporter.GetDefaultPlatformTextureSettings();
|
||||
|
||||
if (defaultSettings.format != TextureImporterFormat.RGBA32)
|
||||
{
|
||||
defaultSettings.format = TextureImporterFormat.RGBA32;
|
||||
textureImporter.SetPlatformTextureSettings(defaultSettings);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
AssetDatabase.ImportAsset(assetPath);
|
||||
texture = AssetDatabase.LoadMainAssetAtPath(assetPath) as Texture2D;
|
||||
}
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f50142101ff97a409b03240bd12d0b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Adobe/Substance3DForUnity/Editor/Settings.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78d21cfe470a7ec4b9caa5d8b89c89b4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,17 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
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: 715e7c131b0ebdd48b77c2b2741d1dae, type: 3}
|
||||
m_Name: SubstanceEditorSettings
|
||||
m_EditorClassIdentifier:
|
||||
_generateAllTexture: 0
|
||||
_targetResolution: {x: 10, y: 10}
|
||||
_targetTextureEngine: 0
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e686586dac7adb5429a0ca6dd01af373
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Adobe/Substance3DForUnity/HOWTO.pdf
Normal file
7
Assets/Adobe/Substance3DForUnity/HOWTO.pdf.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30801c657a078c941a2391ec38ae57c4
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
14
Assets/Adobe/Substance3DForUnity/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
Adobe Substance 3D for Unity
|
||||
=====
|
||||
The Substance 3D plugin enables you to load, apply, and tweak Substance parametric materials directly in Unity. <br /><br />
|
||||
Whether you are working on games, architectural visualization, virtual reality and or deploying across mobile, desktop or XR, Substance 3D delivers a unique experience with optimized features for enhanced productivity. <br/><br/>
|
||||
|
||||
**Work faster, be more productive**: Substance 3D parameters allow for real-time texture updates in editor or at runtime. <br/><br/>
|
||||
Substance 3D for Unity contains the plugin for the **Substance Engine** <br/><br/>
|
||||
Import and customize physically-based Substance materials created in Substance Designer with support for Unity Standard/Standard (specular) shader and HDRP. <br /><br />
|
||||
Please refer to the HOWTO guide to get started using Substance 3D for Unity. More detailed information will be available soon on our official documentation. <br /><br />
|
||||
Support or Questions? Email us at contact@substance3d.com. <br/><br/>
|
||||
Known Issues:
|
||||
- Height map does not render correctly when using scanned Substance data with fixed output size
|
||||
- The documentation on https://substance3d.adobe.com/documentation/integrations/unity-170459323.html is outdated
|
||||
- Currently there is no option to toggle between CPU and GPU
|
7
Assets/Adobe/Substance3DForUnity/README.md.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f965ac7ac1ee7d4da311dd8525582d2
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Adobe/Substance3DForUnity/Runtime.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7d6d85ed61bf2a4f8f6fd772abefb65
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|