using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System; using Godot; namespace Rokojori.Reallusion { public class CCMaterialInfo:CCImportFileBase { public string name; public CCJSONProperty materialType = new CCJSONProperty( "Material Type" ); public CCJSONProperty multiUVIndex = new CCJSONProperty( "MultiUV Index" ); public CCJSONProperty nodeType = new CCJSONProperty( "Node Type" ); public CCJSONProperty twoSide = new CCJSONProperty( "Two Side" ); public CCJSONProperty> diffuseColor = new CCJSONProperty>( "Diffuse Color" ); public CCJSONProperty> ambientColor = new CCJSONProperty>( "Ambient Color" ); public CCJSONProperty> specularColor = new CCJSONProperty>( "Specular Color" ); public CCJSONProperty opacity = new CCJSONProperty( "Opacity" ); public CCJSONProperty selfIllumination = new CCJSONProperty( "Self Illumination" ); public CCJSONProperty specular = new CCJSONProperty( "Specular" ); public CCJSONProperty glossiness = new CCJSONProperty( "Glossiness" ); public CCJSONProperty> textures = new CCJSONProperty>( "Textures" ); public CCJSONProperty customShader = new CCJSONProperty( "Custom Shader" ); public CCJSONProperty subsurfaceScatter = new CCJSONProperty( "Subsurface Scatter" ); public CCMaterialInfo( CCImportFile ccImportFile, string name ):base( ccImportFile ) { this.name = name; textures.SetReader( ( data ) => { var list = new List(); var obj = data.AsObject(); Info( "Reading textures:", obj.keys ); obj.keys.ForEach( k => { var ti = CCTextureInfo.Create( importFile, k, obj.Get( k ) ); Info( "Adding texture for material", name, ti.name, ti.texturePath.value ); list.Add( ti ); } ); return list; } ); customShader.SetReader( ( data ) => { var shaderName = data.AsObject().Get( "Shader Name" ).stringValue; var cs = new CCCustomShader( importFile, shaderName ); Info( "Found Shader", shaderName ); cs.ReadFrom( data.AsObject() ); return cs; } ); subsurfaceScatter.SetReader( ( data ) => { var ss = new CCSubsurfaceScatter( importFile ); ss.ReadFrom( data.AsObject() ); return ss; } ); } public void ReadFrom( JSONObject root ) { materialType.Read( root ); multiUVIndex.Read( root ); nodeType.Read( root ); twoSide.Read( root ); diffuseColor.Read( root ); ambientColor.Read( root ); specularColor.Read( root ); opacity.Read( root ); selfIllumination.Read( root ); textures.Read( root ); customShader.Read( root ); subsurfaceScatter.Read( root ); } public bool IsCustomShader( string shaderName ) { return customShader.exists && customShader.value.name == shaderName; } public Material CreateMaterial( CCMaterialSettings settings ) { RJLog.Log( "Custom Shader", customShader.exists ? customShader.value.name : "none" ); if ( settings.materialType.shaderType == CCMaterialType.CCShaderType.RLHair ) { return CreateHairMaterial( settings ); } if ( settings.materialType.shaderType == CCMaterialType.CCShaderType.RLEyeOcclusion ) { return CreateEyeOcclusionMaterial( settings ); } if ( settings.materialType.shaderType == CCMaterialType.CCShaderType.RLEye ) { return CreateEyeMaterial( settings ); } if ( settings.materialType.shaderType == CCMaterialType.CCShaderType.RLSkin || settings.materialType.shaderType == CCMaterialType.CCShaderType.RLHead ) { return CreateSkinMaterial( settings ); } if ( HasOpacityTexture() ) { return CreateOpacityMaterial( settings ); } return CreatePBRMaterial( settings ); } public Color GetAlbedoColor( float gamma ) { var a = opacity.GetOr( 1.0f ); var color = ColorX.From( diffuseColor.GetOr( new List{ 255, 255, 255, 255 } ), 255 ); color.A *= a; color = color.Gamma( gamma ); return color; } public bool HasOpacityTexture() { if ( textures.exists ) { var opacityTexture = textures.value.Find( t => t.name == CCTextureInfo.Opacity ); return opacityTexture != null; } return false; } public bool IsTransparent() { return HasOpacityTexture() || GetAlbedoColor( 1.0f ).A < 1.0f; } public CCMaterialType GetMaterialType() { var materialType = new CCMaterialType(); materialType.shaderType = CCMaterialType.CCShaderType.PBR; if ( customShader.exists ) { materialType.shaderType = ReflectionHelper.StringToEnum( customShader.value.name, CCMaterialType.CCShaderType.Unknown ); } return materialType; } public StandardMaterial3D CreatePBRMaterial( CCMaterialSettings settings, bool skin = false ) { var material = new StandardMaterial3D(); material.CullMode = twoSide.GetOr( false ) ? BaseMaterial3D.CullModeEnum.Disabled : BaseMaterial3D.CullModeEnum.Back; material.Metallic = 1.0f; material.AlbedoColor = GetAlbedoColor( settings.configuration.gammaForAlbedoColor ); material.Transparency = IsTransparent() ? BaseMaterial3D.TransparencyEnum.Alpha : BaseMaterial3D.TransparencyEnum.Disabled; material.MetallicSpecular = skin ? 0.0f : 0.5f; if ( skin && subsurfaceScatter.exists) { material.SubsurfScatterEnabled = true; material.SubsurfScatterStrength = subsurfaceScatter.value.radius.value / 3.0f; material.SubsurfScatterSkinMode = true; } if ( ! textures.exists ) { return material; } textures.value.ForEach( ( t ) => { if ( t.isBaseColor ) { material.AlbedoTexture = t.GetTexture(); var uv1Scale = t.tiling.GetOr( new List(){ 1, 1 } ); var uv1Offset = t.offset.GetOr( new List(){ 0, 0 } ); material.Uv1Scale = new Vector3( uv1Scale[ 0 ], uv1Scale[ 1 ], 1 ); material.Uv1Offset = new Vector3( uv1Offset[ 0 ], uv1Offset[ 1 ], 1 ); } else if ( t.isNormal ) { material.NormalTexture = t.GetTexture(); material.NormalEnabled = true; } else if ( t.isRoughness ) { material.RoughnessTexture = t.GetTexture(); material.RoughnessTextureChannel = BaseMaterial3D.TextureChannel.Red; } else if ( t.isMetallic ) { material.MetallicTexture = t.GetTexture(); material.MetallicTextureChannel = BaseMaterial3D.TextureChannel.Red; } else if ( t.isGlow ) { material.EmissionEnabled = true; material.EmissionTexture = t.GetTexture(); } else if ( t.isAO ) { material.AOEnabled = true; material.AOTexture = t.GetTexture(); material.AOTextureChannel = BaseMaterial3D.TextureChannel.Red; } } ); return material; } public ShaderMaterial CreateEyeOcclusionMaterial( CCMaterialSettings settings ) { var eyeOcclusionMaterial = new CCEyeOcclusionMaterial(); eyeOcclusionMaterial.shadowTopColor.Set( ColorX.From( customShader.value.shadowTopColor.value, 255.0f ) ); eyeOcclusionMaterial.shadowBottomColor.Set( ColorX.From( customShader.value.shadowBottomColor.value, 255.0f ) ); return eyeOcclusionMaterial; } public ShaderMaterial CreateEyeMaterial( CCMaterialSettings settings ) { var eyeMaterial = new CCEyeMaterial(); textures.value.ForEach( ( t ) => { if ( t.isBaseColor ) { eyeMaterial.textureAlbedo.Set( t.GetTexture() ); } } ); eyeMaterial.textureNormal.Set( customShader.value.GetIrisNormal() ); return eyeMaterial; } public ShaderMaterial CreateSkinMaterial( CCMaterialSettings settings ) { var skinMaterial = new CCSkinMaterial(); CustomMaterial outputMaterial = skinMaterial; if ( settings.configuration.transmissiveSkin ) { outputMaterial = new CCSkinTransmissiveMaterial(); } if ( settings.configuration.applyAlbedoNoise ) { var skinScale = 2.0f; if ( name.EndsWith( "Head" ) ) { skinScale = 1.0f; } else if ( name.EndsWith( "Body" ) ) { skinScale = 5.0f; } skinMaterial.albedoNoiseUvScale.AssignFor( outputMaterial, skinScale ); skinMaterial.albedoNoiseOffset.AssignFor( outputMaterial, settings.configuration.albedoNoiseBrightness ); skinMaterial.albedoNoise.AssignFor( outputMaterial, settings.configuration.albedoNoiseAmount ); skinMaterial.textureAlbedoNoise.AssignFor( outputMaterial, settings.configuration.skinAlbedoNoise ); } skinMaterial.albedo.AssignFor( outputMaterial, GetAlbedoColor( settings.configuration.gammaForAlbedoColor ) ); skinMaterial.specular.AssignFor( outputMaterial, 0.5f ); var tiling = customShader.value.GetFloatVariable( "MicroNormal Tiling", 20f ); skinMaterial.uv1Scale.AssignFor( outputMaterial, Vector3.One ); skinMaterial.uv2Scale.AssignFor( outputMaterial, Vector3.One * tiling ); skinMaterial.microNormalTexture.AssignFor( outputMaterial, customShader.value.GetMicroNormal() ); skinMaterial.microNormalMaskTexture.AssignFor( outputMaterial, customShader.value.GetMicroNormalMask() ); skinMaterial.microNormalScale.AssignFor( outputMaterial, customShader.value.GetFloatVariable( "MicroNormal Strength", 0.5f ) ); if ( outputMaterial is CCSkinTransmissiveMaterial st ) { st.textureSubsurfaceTransmittance.Set( customShader.value.GetTransmisionMap() ); } // skinMaterial.textureSubsurfaceTransmittance.Set( customShader.value.GetTransmisionMap() ); skinMaterial.textureSpecular.AssignFor( outputMaterial, customShader.value.GetSpecularMask() ); skinMaterial.textureSubsurfaceScattering.AssignFor( outputMaterial, customShader.value.GetSSSMap() ); textures.value.ForEach( ( t ) => { if ( t.isBaseColor ) { skinMaterial.textureAlbedo.AssignFor( outputMaterial, t.GetTexture() ); var uv1Scale = t.tiling.GetOr( new List(){ 1, 1 } ); var uv1Offset = t.offset.GetOr( new List(){ 0, 0 } ); skinMaterial.uv1Scale.AssignFor( outputMaterial, new Vector3( uv1Scale[ 0 ], uv1Scale[ 1 ], 1 ) ); skinMaterial.uv1Offset.AssignFor( outputMaterial, new Vector3( uv1Offset[ 0 ], uv1Offset[ 1 ], 1 ) ); } else if ( t.isNormal ) { skinMaterial.textureNormal.AssignFor( outputMaterial, t.GetTexture() ); } else if ( t.isRoughness ) { skinMaterial.textureRoughness.AssignFor( outputMaterial, t.GetTexture() ); } else if ( t.isAO ) { skinMaterial.textureAmbientOcclusion.AssignFor( outputMaterial, t.GetTexture() ); } } ); return outputMaterial; } public ShaderMaterial CreateOpacityMaterial( CCMaterialSettings settings ) { var opacityMaterial = new CCPBROpacityMaterial(); opacityMaterial.albedo.Set( GetAlbedoColor( settings.configuration.gammaForAlbedoColor ) ); opacityMaterial.specular.Set( 0.0f ); opacityMaterial.opacity.Set( opacity.GetOr( 1 ) ); opacityMaterial.uv1Scale.Set( Vector3.One ); opacityMaterial.uv2Scale.Set( Vector3.One ); textures.value.ForEach( ( t ) => { if ( t.isBaseColor ) { opacityMaterial.textureAlbedo.Set( t.GetTexture() ); var uv1Scale = t.tiling.GetOr( new List(){ 1, 1 } ); var uv1Offset = t.offset.GetOr( new List(){ 0, 0 } ); opacityMaterial.uv1Scale.Set( new Vector3( uv1Scale[ 0 ], uv1Scale[ 1 ], 1 ) ); opacityMaterial.uv1Offset.Set( new Vector3( uv1Offset[ 0 ], uv1Offset[ 1 ], 1 ) ); } if ( t.isOpacity ) { opacityMaterial.textureOpacity.Set( t.GetTexture() ); } else if ( t.isNormal ) { opacityMaterial.textureNormal.Set( t.GetTexture() ); } else if ( t.isRoughness ) { opacityMaterial.textureRoughness.Set( t.GetTexture() ); } else if ( t.isMetallic ) { opacityMaterial.textureMetallic.Set( t.GetTexture() ); opacityMaterial.metallicTextureChannel.Set( new Vector4( 1, 0, 0, 0 ) ); } else if ( t.isAO ) { opacityMaterial.textureAmbientOcclusion.Set( t.GetTexture() ); opacityMaterial.aoTextureChannel.Set( new Vector4( 1, 0, 0, 0 ) ); } } ); return opacityMaterial; } public ShaderMaterial CreateHairMaterial( CCMaterialSettings settings ) { var scissorMaterial = new CCHairScissorMaterial(); var alphaMaterial = new CCHairAlphaMaterial(); var alphaBackMaterial = new CCHairAlphaBackMaterial(); scissorMaterial.NextPass = alphaBackMaterial; alphaBackMaterial.NextPass = alphaMaterial; alphaBackMaterial.RenderPriority = settings.materialRenderPriorityIndexBack; alphaMaterial.RenderPriority = settings.materialRenderPriorityIndexFront; var m = new List(){ scissorMaterial, alphaMaterial, alphaBackMaterial }; var mat = scissorMaterial; CustomMaterial outputMaterial = scissorMaterial; var opacityScale = 1.0f; if ( CCImportConfiguration.HairShaderMode.Alpha_Only == settings.configuration.hairShaderMode ) { var hairMaterial = new CCHairMaterial(); hairMaterial.RenderPriority = settings.materialRenderPriorityIndexBack; outputMaterial = hairMaterial; m = new List(){ hairMaterial }; opacityScale = 1.5f; } else if ( CCImportConfiguration.HairShaderMode.Shadow_Scissor_AlphaBack_AlphaFront == settings.configuration.hairShaderMode ) { scissorMaterial.NextPass = null; var shadowMaterial = new CCHairShadowMaterial(); shadowMaterial.RenderPriority = -2; var hairMaterial = new CCHairScissorMaterial(); outputMaterial = shadowMaterial; shadowMaterial.NextPass = hairMaterial; hairMaterial.NextPass = alphaBackMaterial; m = new List(){ shadowMaterial, hairMaterial, alphaMaterial, alphaBackMaterial }; opacityScale = 1f; } mat.naturalColors.AssignFor( m, settings.configuration.naturalColors ); mat.maximumHighlightAmount.AssignFor( m, settings.configuration.maximumHighlightAmount ); mat.opacityGamma.AssignFor( m, settings.configuration.GetHairOpacityGamma( settings.meshName, settings.materialIndex ) ); mat.flowMap.AssignFor( m, customShader.value.GetHairFlowMap() ); mat.rootMap.AssignFor( m, customShader.value.GetHairRootMap() ); mat.idMap.AssignFor( m, customShader.value.GetHairIDMap() ); mat.anisotropyRatio.AssignFor( m, settings.configuration.anisotropicRatio ); mat.vertexGreyToColor.AssignFor( m, customShader.value.GetColorVariable( "VertexGrayToColor", 255f, false ) ); mat.vertexColorStrength.AssignFor( m, customShader.value.GetFloatVariable( "VertexColorStrength" ) ); mat.diffuseStrength.AssignFor( m, customShader.value.GetFloatVariable( "Diffuse Strength" ) ); mat.baseColorMapStrength.AssignFor( m, customShader.value.GetFloatVariable( "BaseColorMapStrength" ) ); mat.strandRootColor.AssignFor( m, customShader.value.GetColorVariable( "RootColor", 255f, false ) ); mat.strandRootStrength.AssignFor( m, customShader.value.GetFloatVariable( "RootColorStrength" ) ); mat.strandEndColor.AssignFor( m, customShader.value.GetColorVariable( "TipColor", 255f, false ) ); mat.strandEndStrength.AssignFor( m, customShader.value.GetFloatVariable( "TipColorStrength" ) ); mat.highlightAColor.AssignFor( m, customShader.value.GetColorVariable( "_1st Dye Color", 255, false ) ); mat.highlightAStrength.AssignFor( m, customShader.value.GetFloatVariable( "_1st Dye Strength" ) ); mat.highlightARange.AssignFor( m, customShader.value.GetColorVariable( "_1st Dye Distribution from Grayscale", 255, false ).ToVector3() ); mat.highlightAOverlapEnd.AssignFor( m, customShader.value.GetFloatVariable( "Mask 1st Dye by RootMap" ) ); mat.highlightAInvert.AssignFor( m, customShader.value.GetFloatVariable( "Invert 1st Dye RootMap Mask" ) ); mat.highlightBColor.AssignFor( m, customShader.value.GetColorVariable( "_2nd Dye Color", 255, false ) ); mat.highlightBStrength.AssignFor( m, customShader.value.GetFloatVariable( "_2nd Dye Strength" ) ); mat.highlightBRange.AssignFor( m, customShader.value.GetColorVariable( "_2nd Dye Distribution from Grayscale", 255, false ).ToVector3() ); mat.highlightBOverlapEnd.AssignFor( m, customShader.value.GetFloatVariable( "Mask 2nd Dye by RootMap" ) ); mat.highlightBInvert.AssignFor( m, customShader.value.GetFloatVariable( "Invert 2nd Dye RootMap Mask" ) ); mat.albedo.AssignFor( m, GetAlbedoColor( settings.configuration.gammaForAlbedoColor ) ); // mat.specular.AssignFor( m, 0.5f ); mat.opacity.AssignFor( m, opacity.GetOr( 1 ) * opacityScale ); mat.blendAmount.AssignFor( m, 0f ); mat.roughnessOffset.AssignFor( m, settings.configuration.roughnessOffset ); mat.metallicOffset.AssignFor( m, settings.configuration.metallicOffset ); textures.value.ForEach( ( t ) => { if ( t.isBaseColor ) { mat.textureAlbedo.AssignFor( m, t.GetTexture() ); } if ( t.isOpacity ) { mat.textureOpacity.AssignFor( m, t.GetTexture() ); } else if ( t.isRoughness ) { mat.textureRoughness.AssignFor( m, t.GetTexture() ); } else if ( t.isMetallic ) { mat.textureMetallic.AssignFor( m, t.GetTexture() ); } else if ( t.isAO ) { mat.textureAmbientOcclusion.AssignFor( m, t.GetTexture() ); } else if ( t.isBlend ) { mat.textureBlend.AssignFor( m, t.GetTexture() ); mat.blendAmount.AssignFor( m, t.strength.GetOr( 0f ) / 100f ) ; } } ); return outputMaterial; } } }