static Material doMaterials(NIFFile nf, NiMesh mesh, GameObject go) { StringBuilder strB = new StringBuilder(20); if (standardShader == null) { standardShader = Shader.Find("Standard"); } bool IS_TERRAIN = (nf.getStringTable().Contains("terrainL1")); bool animated = false; bool presetMaterial = false; string materialName = null; Material mat = null; Material mat2 = null; if (mesh.materialNames.Count > 0) { strB.Length = 0; strB.Append("materials/"); strB.Append(mesh.materialNames[0]); mat2 = Resources.Load <Material>(strB.ToString()); if (mat2 != null) { mat = Material.Instantiate <Material>(mat2); } } else { Debug.LogWarning("No mesh materials found in mesh :" + mesh.name); } if (mat == null) { // do materials/textures if (IS_TERRAIN) { materialName = "terrainmat"; } if (mesh.materialNames.Contains("Ocean_Water_Shader") || mesh.materialNames.Contains("Flow_Water") || mesh.name.Contains("water_UP") || mesh.name.Contains("water_DOWN")) { materialName = "WaterMaterial"; } bool alpha = (mesh.materialNames.Contains("TwoSided_Alpha_Specular") || mesh.materialNames.Contains("Lava_Flow_Decal")); foreach (string n in mesh.materialNames) { if (n.ToLower().Contains("alpha")) { alpha = true; } } if (alpha) { materialName = "2sidedtransmat_fade"; } // handle some simple animated "scrolling" textures animated = (mesh.materialNames.Contains("Additive_UVScroll_Distort") || mesh.materialNames.Contains("Lava_Flow_Decal") || mesh.materialNames.Contains("Local_Cloud_Flat") || mesh.materialNames.Contains("Alpha_UVScroll_Overlay_Foggy_Waterfall") || mesh.materialNames.Contains("Fat_spike12_m") || mesh.materialNames.Contains("pPlane1_m")); if (animated) { materialName = "2sidedtransmat_fade"; } foreach (int eid in mesh.extraDataIDs) { NIFObject obj = nf.getObject(eid); if (obj is NiBooleanExtraData) { NiBooleanExtraData fExtra = (NiBooleanExtraData)obj; switch (fExtra.extraDataString) { case "doAlphaTest": if (fExtra.booleanData) { materialName = "2sidedtransmat"; } break; default: break; } } } if (materialName == null) { if (standardMaterial == null) { standardMaterial = new Material(standardShader); } mat = Material.Instantiate(standardMaterial); materialName = standardMaterial.name; } else { mat = Material.Instantiate(Resources.Load <Material>(materialName)); } //Debug.Log("Using guessed material[" + materialName + "] for " + mesh.name + " from list of materials: " + string.Join(",", mesh.materialNames.ToArray()), go); } else if (mat2 != null) { materialName = mat2.name; presetMaterial = true; //Debug.Log("Using actual material[" + materialName + "] for " + mesh.name + " from list of materials: " + string.Join(",", mesh.materialNames.ToArray()), go); } else { Debug.LogWarning("No material found!?"); } #if UNITY_EDITOR MeshOriginalMaterial mom = go.AddComponent <MeshOriginalMaterial>(); if (mesh.materialNames.Count > 0) { mom.materialName = mesh.materialNames[0]; } #endif if (presetMaterial) { foreach (int extraId in mesh.extraDataIDs) { NIFObject obj = nf.getObject(extraId); setMaterialProperty(mat, obj); } if (mat.HasProperty("doAlphaTest")) { if (mat.GetInt("doAlphaTest") == 0) { strB.Length = 0; strB.Append("materials/"); strB.Append(mat2.name); strB.Append("_shader_opaque"); string shaderName = strB.ToString(); //Debug.Log("loading opaque shader:" + shaderName, go); Shader shader = Resources.Load <Shader>(shaderName); if (shader != null) { mat.shader = shader; } } } } mat.enableInstancing = true; mat.EnableKeyword("_SPECULARHIGHLIGHTS_OFF"); if (animated) { NiFloatsExtraData extra = getFloatsExtraData(nf, mesh, "tex0ScrollRate"); if (extra != null) { UVScroll scroller = go.AddComponent <UVScroll>(); scroller.material = mat; scroller.xRate = extra.floatData[0]; scroller.yRate = extra.floatData[1]; } } foreach (int eid in mesh.extraDataIDs) { NIFObject obj = nf.getObject(eid); if (obj is NiFloatExtraData) { NiFloatExtraData fExtra = (NiFloatExtraData)obj; switch (fExtra.extraDataString) { case "scaleY": if (mat.HasProperty("_MainTex")) { mat.mainTextureScale = new Vector2(mat.mainTextureScale.x, fExtra.floatData); } else { if (mat.HasProperty("scaleY")) { mat.SetFloat("scaleY", fExtra.floatData); } else { Debug.LogWarning("While trying to set scaleY, material[" + mat.name + "][" + materialName + "] doesn't have an appropriate texture property"); } } break; case "scale": if (mat.HasProperty("_MainTex")) { mat.mainTextureScale = new Vector2(fExtra.floatData, mat.mainTextureScale.y); } else { if (mat.HasProperty("scale")) { mat.SetFloat("scale", fExtra.floatData); } else { Debug.LogWarning("While trying to set scale, material[" + mat.name + "][" + materialName + "] doesn't have an appropriate texture property"); } } break; default: break; } } } string[] textureNameIds = getTextureIds(nf, mesh); if (presetMaterial) { foreach (int extraId in mesh.extraDataIDs) { NIFObject obj = nf.getObject(extraId); setMaterialProperty(mat, obj); } } if (mat.HasProperty("alphaTestRef")) { mat.SetFloat("alphaTestRef", 1.0f - mat.GetFloat("alphaTestRef")); } List <int> propIDs = mesh.nodePropertyIDs; foreach (int propID in propIDs) { NIFObject obj = nf.getObject(propID); if (obj is NiTexturingProperty) { NiTexturingProperty propObj = (NiTexturingProperty)obj; foreach (NifTexMap tex in propObj.texList) { if (tex != null) { Debug.Log("\t" + tex.sourceTexLinkID); } } int i = 0; foreach (NifTexMap tex in propObj.shaderMapList) { string texName = ""; if (tex != null) { int sourceTexID = tex.sourceTexLinkID; if (sourceTexID != -1) { NiSourceTexture sourceTex = (NiSourceTexture)nf.getObject(sourceTexID); texName = sourceTex.texFilename; if (presetMaterial) { strB.Length = 0; if (IS_TERRAIN) { strB.Append("_terrain"); strB.Append(i); } else { strB.Append("_"); strB.Append(textureNameIds[i]); } // Debug.Log("attempt to set texture property :" + propertyName + " with texure:" + texName); enqueSetTexture(mat, strB.ToString(), nf, texName); //mat.SetTexture(propertyName, loadTexture(nf, texName)); } else if (IS_TERRAIN) { strB.Length = 0; strB.Append("_terrain"); strB.Append(i); string param = strB.ToString(); //"_terrain" + i; //Debug.Log("set " + param + " to " + texName + " mat:" + mat.name); enqueSetTexture(mat, param, nf, texName); //mat.SetTexture(param, loadTexture(nf, texName)); } else { //Debug.Log("texName[" + texName + "]: id:" + textureNameIds[i]); try { switch (textureNameIds[i]) { case "skyGradientTexture0": case "diffuseTexture": case "diffuseTextureXZ": enqueSetTexture(mat, "_MainTex", nf, texName); //mat.SetTexture("_MainTex", loadTexture(nf, texName)); break; case "decalNormalTexture": enqueSetTexture(mat, "_DetailNormalMap", nf, texName); //mat.SetTexture("_DetailNormalMap", loadTexture(nf, texName)); break; case "normalTexture": enqueSetTexture(mat, "_BumpMap", nf, texName); //mat.SetTexture("_BumpMap", loadTexture(nf, texName)); break; case "glowTexture": mat.EnableKeyword("_EMISSION"); if (mesh.materialNames.Contains("Lava_Flow_Decal")) { mat.SetColor("_EmissionColor", Color.red); } else { mat.SetColor("_EmissionColor", Color.white * 0.5f); } enqueSetTexture(mat, "_EmissionMap", nf, texName); //mat.SetTexture("_EmissionMap", loadTexture(nf, texName)); break; case "glossTexture": enqueSetTexture(mat, "_MetallicGlossMap", nf, texName); //mat.SetTexture("_MetallicGlossMap", loadTexture(nf, texName)); break; case "decalTexture": case "starMapTexture0": enqueSetTexture(mat, "_DetailAlbedoMap", nf, texName); //mat.SetTexture("_DetailAlbedoMap", loadTexture(nf, texName)); break; default: //Debug.LogWarning("No shader material property for " + textureNameIds[i]); break; } }catch (ArgumentOutOfRangeException ex) { Debug.LogWarning("Texture id[" + i + "] was out of range of the texture name ids: " + textureNameIds.ToList()); //mat.SetTexture("_MainTex", loadTexture(nf, texName)); enqueSetTexture(mat, "_MainTex", nf, texName); } } } } i++; } } } return(mat); }
/// <summary> /// This method needs to be called within an Update method from unity. As such, it should be pretty quick /// </summary> /// <param name="nf"></param> /// <param name="mesh"></param> /// <param name="meshData"></param> /// <param name="skinMesh"></param> /// <returns></returns> static GameObject processMesh(NIFFile nf, NiMesh mesh, NIFFile.MeshData meshData, bool skinMesh) { //Debug.Log("process mesh:" + mesh.name); GameObject go = new GameObject(); go.name = mesh.name; if (mesh.name.Length == 0) { go.name = "mesh"; } go.transform.localPosition = new Vector3(mesh.translation.x, mesh.translation.y, mesh.translation.z); Mesh newMesh = new Mesh(); MeshFilter mf = go.AddComponent <MeshFilter>(); Renderer r; if (!skinMesh) { r = go.AddComponent <MeshRenderer>(); } else { r = go.AddComponent <SkinnedMeshRenderer>(); // needed to force Unity to use 2 bones. RIFT exposes 3 bones, and if we let Unity choose, it'll try to use 4 // which will make models look wrong ((SkinnedMeshRenderer)r).quality = SkinQuality.Bone2; ((SkinnedMeshRenderer)r).sharedMesh = newMesh; } mf.mesh = newMesh; if (Assets.GameWorld.useColliders) { MeshCollider mc = go.AddComponent <MeshCollider>(); mc.sharedMesh = newMesh; } newMesh.subMeshCount = mesh.numSubMeshes; if (mesh.meshPrimType != 0) // Triangles { Debug.Log("unknown meshPrimType:" + mesh.meshPrimType); } else { bool IS_TERRAIN = (nf.getStringTable().Contains("terrainL1")); newMesh.SetVertices(meshData.verts); if (meshData.inNormals.Count > 0) { newMesh.SetNormals(meshData.inNormals); } if (meshData.uvs.Count > 0) { newMesh.SetUVs(0, meshData.uvs); } if (meshData.boneWeights.Count > 0 && !IS_TERRAIN && skinMesh) { newMesh.boneWeights = meshData.boneWeights.ToArray(); } // huge memory GC issue here.... newMesh.triangles = meshData.tristest; r.material = doMaterials(nf, mesh, go); } return(go); }