protected override IRenderableMaterial CreateMaterial(object key) { switch (key) { case uint id: return(base.CreateMaterial(new Kn5MaterialDescription(_kn5.GetMaterial(id)))); case Tuple <object, uint> special: return(base.CreateMaterial(new Kn5MaterialDescription(special.Item1, _kn5.GetMaterial(special.Item2)))); default: return(base.CreateMaterial(key)); } }
Tuple <IRenderableTexture, float> IAlphaTexturesProvider.GetTexture(IDeviceContextHolder contextHolder, uint materialId) { if (!_cache.TryGetValue(materialId, out var result)) { if (_texturesProvider == null) { _texturesProvider = new Kn5TexturesProvider(_kn5, false); } result = new Tuple <IRenderableTexture, float>[] { null }; var material = _kn5.GetMaterial(materialId); if (material != null && (material.BlendMode != Kn5MaterialBlendMode.Opaque || material.AlphaTested)) { var shader = material.ShaderName; var normalsAlpha = shader == "ksPerPixelNM" || shader == "ksPerPixelNM_UV2" || shader.Contains("_AT") || shader == "ksSkinnedMesh"; if (normalsAlpha || !shader.Contains("MultiMap") && shader != "ksTyres" && shader != "ksBrakeDisc") { var textureName = material.GetMappingByName(normalsAlpha ? "txNormal" : "txDiffuse")?.Texture; var alphaRef = material.GetPropertyValueAByName("ksAlphaRef"); if (textureName != null && !shader.Contains("damage")) { result = new[] { Tuple.Create(_texturesProvider.GetTexture(contextHolder, textureName), alphaRef) }; } } } _cache[materialId] = result; } return(result[0]); }
Tuple <IRenderableTexture, float> INormalsNormalTexturesProvider.GetTexture(IDeviceContextHolder contextHolder, uint materialId) { if (!_cache.TryGetValue(materialId, out var result)) { if (_texturesProvider == null) { _texturesProvider = new Kn5TexturesProvider(_kn5, false); } var material = _kn5.GetMaterial(materialId); var textureName = material?.GetMappingByName("txNormal")?.Texture; if (textureName != null && !material.ShaderName.Contains("damage")) { var texture = _texturesProvider.GetTexture(contextHolder, textureName); result = new[] { Tuple.Create(texture, material.GetPropertyValueAByName("normalMult") + 1f) }; } else { result = new Tuple <IRenderableTexture, float>[] { null }; } _cache[materialId] = result; } return(result[0]); }
public int GroupOrder(IKn5 kn5, IEnumerable <Tuple <Kn5Node, double, Mat4x4> > node, Dictionary <Kn5Node, int> nodeIndices) { var isTransparent = false; var isBlending = false; var maxIndex = 0; foreach (var n in node) { isTransparent |= n.Item1.IsTransparent; isBlending = kn5.GetMaterial(n.Item1.MaterialId)?.BlendMode == Kn5MaterialBlendMode.AlphaBlend; maxIndex = Math.Max(maxIndex, nodeIndices[n.Item1]); } return((isTransparent ? 1 << 31 : 0) | (isBlending ? 1 << 30 : 0) | maxIndex); }
private static IEnumerable <Kn5Node> FilterNodes(IKn5 kn5, IFilter <string> filter, Kn5Node node) { if (node.NodeClass == Kn5NodeClass.Base) { return(node.Children.SelectMany(x => FilterNodes(kn5, filter, x))); } if (!filter.Test(node.Name) || kn5.GetMaterial(node.MaterialId)?.TextureMappings.Any(x => x.Name == "txNormal" || x.Name == "txNormalDetail") != false) { return(new Kn5Node[0]); } return(new[] { node }); }
public IRenderableMaterial CreateMaterial(object key) { if (key is uint id) { return new Kn5MaterialToBake(_kn5.GetMaterial(id)); } if (key is Kn5MaterialDescription description) { return new Kn5MaterialToBake(description.Material); } if (key is Kn5AmbientShadowMaterialDescription) { return new Kn5MaterialToBake(null); } throw new NotSupportedException("Type: " + key?.GetType()); }
public Kn5MaterialDialog([CanBeNull] BaseRenderer renderer, [CanBeNull] CarObject car, [CanBeNull] CarSkinObject activeSkin, [NotNull] IKn5 kn5, uint materialId) { ValuesStorage.Remove("__userpresets_p_" + PresetableKey); ValuesStorage.Remove("__userpresets_c_" + PresetableKey); var material = kn5.GetMaterial(materialId); if (material != null && renderer != null) { var properties = material.ShaderProperties.Select(x => x.Clone()).ToArray(); var depthMode = material.DepthMode; var alphaTested = material.AlphaTested; var blendMode = material.BlendMode; _dispose = new ActionAsDisposable(() => { foreach (var property in material.ShaderProperties) { property.CopyFrom(properties.FirstOrDefault(x => x.Name == property.Name)); } material.DepthMode = depthMode; material.AlphaTested = alphaTested; material.BlendMode = blendMode; (renderer as IKn5ObjectRenderer)?.RefreshMaterial(kn5, materialId); }); } DataContext = new ViewModel(renderer, kn5, activeSkin, materialId) { Close = Close }; InitializeComponent(); Buttons = new[] { kn5.IsEditable?CreateExtraDialogButton(AppStrings.Toolbar_Save, new AsyncCommand(async() => { var d = _dispose; try { _dispose = null; await Model.UpdateKn5AndClose(false); } catch (Exception e) { _dispose = d; NonfatalError.Notify("Can’t save material", e); } }, () => Model.IsChanged).ListenOn(Model, nameof(Model.IsChanged)), true) : null, CancelButton }; }
protected static IEnumerable <IKn5RenderableObject> Flatten(IKn5 kn5, IEnumerable <IRenderableObject> root, [CanBeNull] string textureName, [CanBeNull] string objectPath) { var split = Lazier.Create(() => objectPath?.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries)); bool TestObjectPath(IKn5RenderableObject obj) { var s = split.Value; if (s == null || s.Length < 1) { return(true); } if (s[s.Length - 1] != obj.OriginalNode.Name) { return(false); } return(kn5.GetObjectPath(obj.OriginalNode) == objectPath); } return(Flatten(root, x => { if (!(x is IKn5RenderableObject k)) { return true; } if (!TestObjectPath(k)) { return false; } if (textureName == null) { return true; } var material = kn5.GetMaterial(k.OriginalNode.MaterialId); return material != null && material.TextureMappings.Where(y => y.Name != "txDetail" && y.Name != "txNormalDetail") .Any(m => m.Texture == textureName); }));
private static async Task PrepareForGenerationAsync(Kn5NodeFilterContext filterContext, IKn5 kn5, CarLodGeneratorStageParams stage, bool printNodes) { var mergeRules = new CarLodGeneratorMergeRules(filterContext, stage); var toMerge = new Dictionary <Kn5Node, List <Tuple <Kn5Node, double, Mat4x4> > >(); var nodeIndices = new Dictionary <Kn5Node, int>(); MergeNode(kn5.RootNode, kn5.RootNode, 1d); foreach (var pair in toMerge) { var mergeData = pair.Value.GroupBy(x => mergeRules.MergeGroup(x.Item1, x.Item2)) .OrderBy(v => mergeRules.GroupOrder(kn5, v, nodeIndices)).Select(v => v.ToList()).ToList(); await Task.Run(() => { foreach (var group in mergeData) { MergeMeshes(pair.Key, group, mergeRules, stage); } }); } foreach (var node in kn5.Nodes.Where(x => x.Children?.Count > 1).ToList()) { var meshesList = node.Children .Where(x => x.NodeClass != Kn5NodeClass.Base) .Select((x, i) => new { x, i = OrderIndex(x, i) }) .OrderBy(x => x.i) .Select(x => x.x).ToList(); if (meshesList.Count > 0) { if (node.Children.Any(x => x.NodeClass == Kn5NodeClass.Base)) { node.Children = node.Children.Where(x => x.NodeClass == Kn5NodeClass.Base) .Prepend(Kn5Node.CreateBaseNode($"__{meshesList[0].Name}_wrap_", meshesList, true)) .Select((x, i) => new { x, i = OrderIndex(x, i) }) .OrderBy(x => x.i) .Select(x => x.x).ToList(); } else { node.Children = meshesList; } } } if (printNodes) { PrintNode(kn5.RootNode, 0, 0); } mergeRules.FinalizeKn5(kn5); var duplicateNames = kn5.Nodes.GroupBy(x => $"{x.NodeClass}/{x.Name}") .Select(x => x.ToList()).Where(x => x.Count > 1).ToList(); foreach (var group in duplicateNames) { AcToolsLogging.Write($"Duplicate name: {group[0].Name} ({group[0].NodeClass})"); foreach (var toRename in group.Skip(1).Select((x, i) => new { x, i })) { toRename.x.Name = $"{toRename.x.Name}___$unique:{toRename.i}"; } } int OrderIndex(Kn5Node node, int index) { return(index + (AnyTransparent(node) ? 1 << 10 : 0)); } void PrintNode(Kn5Node node, int level, int index) { var postfix = node.NodeClass == Kn5NodeClass.Base ? "" : $"{(node.IsTransparent ? ", transparent" : "")}, material: {kn5.GetMaterial(node.MaterialId)?.Name}"; AcToolsLogging.Write( $"{new string('\t', level)}{node.Name} [{node.NodeClass}{postfix}, index: {OrderIndex(node, index)}, aabb: {filterContext.GetAabb3(node)}]"); if (node.NodeClass == Kn5NodeClass.Base) { for (var i = 0; i < node.Children.Count; i++) { PrintNode(node.Children[i], level + 1, i); } } } bool AnyTransparent(Kn5Node node) { return(node.NodeClass == Kn5NodeClass.Base ? node.Children.Any(AnyTransparent) : node.IsTransparent || kn5.GetMaterial(node.MaterialId)?.BlendMode == Kn5MaterialBlendMode.AlphaBlend); } void ApplyPriority(Kn5Node mesh, double priority) { var offset = MoveAsideDistance(priority, stage); for (var i = 0; i < mesh.Vertices.Length; i++) { Apply(ref mesh.Vertices[i]); } mesh.Tag = priority; void Apply(ref Kn5Node.Vertex v) { v.Position[0] = v.Position[0] * (float)priority + offset.X; v.Position[1] = v.Position[1] * (float)priority + offset.Y; v.Position[2] = v.Position[2] * (float)priority + offset.Z; } } bool MergeNode(Kn5Node node, Kn5Node mergeRoot, double priority) { nodeIndices[node] = nodeIndices.Count; if (node != mergeRoot) { if (mergeRules.CanSkipNode(node)) { if (node.NodeClass == Kn5NodeClass.Base && !mergeRules.HasParentWithSameName(node) && !mergeRules.CanRemoveEmptyNode(node)) { node.Children.Clear(); return(true); } return(false); } var priorityAdjustment = mergeRules.CalculateReductionPriority(node); if (priorityAdjustment != 1d && (priorityAdjustment < priority || priority == 1d || node.NodeClass == Kn5NodeClass.Mesh)) { priority = priorityAdjustment; } if (node.NodeClass == Kn5NodeClass.Mesh) { if (mergeRoot != null && mergeRules.CanMerge(node)) { if (!toMerge.ContainsKey(mergeRoot)) { toMerge[mergeRoot] = new List <Tuple <Kn5Node, double, Mat4x4> >(); } toMerge[mergeRoot].Add(Tuple.Create(node, priority, node.CalculateTransformRelativeToParent(mergeRoot))); return(false); } if (priority != 1d) { ApplyPriority(node, priority); } return(true); } if (node.NodeClass == Kn5NodeClass.SkinnedMesh) { return(true); } if (mergeRoot != null) { if (!mergeRules.CanMerge(node)) { mergeRoot = null; } else if (node.Name != mergeRoot.Name && mergeRules.IsNodeMergeRoot(node)) { mergeRoot = node; } } } for (var i = 0; i < node.Children.Count; ++i) { if (!MergeNode(node.Children[i], mergeRoot, priority)) { node.Children.RemoveAt(i); --i; } } return(node.Children.Count > 0 || mergeRoot == node || !mergeRules.CanRemoveEmptyNode(node)); } }