-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Asset mod helper for creating custom 3D objects * New sample mod which spawns rubber ducks
- Loading branch information
1 parent
24690b7
commit 8facd84
Showing
24 changed files
with
664 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using UnityEngine; | ||
|
||
namespace OWML.Assets | ||
{ | ||
public class Mod3DObject : MonoBehaviour | ||
{ | ||
private void Start() | ||
{ | ||
DontDestroyOnLoad(gameObject); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using System.Collections; | ||
using OWML.Common; | ||
using UnityEngine; | ||
|
||
namespace OWML.Assets | ||
{ | ||
public class ModAssets : IModAssets | ||
{ | ||
private readonly IModConsole _console; | ||
private readonly ObjImporter _objImporter; | ||
|
||
public ModAssets(IModConsole console) | ||
{ | ||
_console = console; | ||
_objImporter = new ObjImporter(); | ||
} | ||
|
||
public GameObject Create3DObject(ModBehaviour modBehaviour, string objectFilename, string imageFilename) | ||
{ | ||
var objectPath = modBehaviour.ModManifest.FolderPath + objectFilename; | ||
var imagePath = modBehaviour.ModManifest.FolderPath + imageFilename; | ||
|
||
_console.WriteLine("Creating object from " + objectPath); | ||
|
||
var go = new GameObject(); | ||
go.AddComponent<Mod3DObject>(); | ||
|
||
var loadObject = LoadObject(go, objectPath); | ||
modBehaviour.StartCoroutine(loadObject); | ||
|
||
var loadTexture = LoadTexture(go, imagePath); | ||
modBehaviour.StartCoroutine(loadTexture); | ||
|
||
return go; | ||
} | ||
|
||
private IEnumerator LoadObject(GameObject go, string objectPath) | ||
{ | ||
var mesh = _objImporter.ImportFile(objectPath); | ||
var meshFilter = go.AddComponent<MeshFilter>(); | ||
meshFilter.mesh = mesh; | ||
yield return null; | ||
} | ||
|
||
private IEnumerator LoadTexture(GameObject go, string imagePath) | ||
{ | ||
var texture = new Texture2D(4, 4, TextureFormat.DXT1, false); | ||
var url = "file://" + imagePath; | ||
using (var www = new WWW(url)) | ||
{ | ||
yield return www; | ||
www.LoadImageIntoTexture(texture); | ||
} | ||
var meshRenderer = go.AddComponent<MeshRenderer>(); | ||
meshRenderer.material.mainTexture = texture; | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{A62856BD-D06C-4F2C-86E8-91C6FDF8F8D5}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>OWML.Assets</RootNamespace> | ||
<AssemblyName>OWML.Assets</AssemblyName> | ||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
<Deterministic>true</Deterministic> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="Assembly-CSharp"> | ||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Outer Wilds\OuterWilds_Data\Managed\Assembly-CSharp.dll</HintPath> | ||
</Reference> | ||
<Reference Include="System.Core" /> | ||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL"> | ||
<SpecificVersion>False</SpecificVersion> | ||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Outer Wilds\OuterWilds_Data\Managed\UnityEngine.CoreModule.dll</HintPath> | ||
</Reference> | ||
<Reference Include="UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL"> | ||
<SpecificVersion>False</SpecificVersion> | ||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Outer Wilds\OuterWilds_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath> | ||
</Reference> | ||
<Reference Include="UnityEngine.UnityWebRequestWWWModule"> | ||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Outer Wilds\OuterWilds_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath> | ||
</Reference> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Compile Include="Mod3DObject.cs" /> | ||
<Compile Include="ModAssets.cs" /> | ||
<Compile Include="ObjImporter.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="..\OWML.Common\OWML.Common.csproj"> | ||
<Project>{3C00626F-B688-4F32-B493-5B7EC1C879A0}</Project> | ||
<Name>OWML.Common</Name> | ||
</ProjectReference> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
using UnityEngine; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
|
||
namespace OWML.Assets | ||
{ | ||
// Source: https://wiki.unity3d.com/index.php?title=ObjImporter&oldid=13033 | ||
|
||
/* This version of ObjImporter first reads through the entire file, getting a count of how large | ||
* the final arrays will be, and then uses standard arrays for everything (as opposed to ArrayLists | ||
* or any other fancy things). | ||
*/ | ||
|
||
public class ObjImporter | ||
{ | ||
|
||
private struct meshStruct | ||
{ | ||
public Vector3[] vertices; | ||
public Vector3[] normals; | ||
public Vector2[] uv; | ||
public Vector2[] uv1; | ||
public Vector2[] uv2; | ||
public int[] triangles; | ||
public int[] faceVerts; | ||
public int[] faceUVs; | ||
public Vector3[] faceData; | ||
public string name; | ||
public string fileName; | ||
} | ||
|
||
// Use this for initialization | ||
public Mesh ImportFile(string filePath) | ||
{ | ||
meshStruct newMesh = createMeshStruct(filePath); | ||
populateMeshStruct(ref newMesh); | ||
|
||
Vector3[] newVerts = new Vector3[newMesh.faceData.Length]; | ||
Vector2[] newUVs = new Vector2[newMesh.faceData.Length]; | ||
Vector3[] newNormals = new Vector3[newMesh.faceData.Length]; | ||
int i = 0; | ||
/* The following foreach loops through the facedata and assigns the appropriate vertex, uv, or normal | ||
* for the appropriate Unity mesh array. | ||
*/ | ||
foreach (Vector3 v in newMesh.faceData) | ||
{ | ||
newVerts[i] = newMesh.vertices[(int)v.x - 1]; | ||
if (v.y >= 1) | ||
newUVs[i] = newMesh.uv[(int)v.y - 1]; | ||
|
||
if (v.z >= 1) | ||
newNormals[i] = newMesh.normals[(int)v.z - 1]; | ||
i++; | ||
} | ||
|
||
Mesh mesh = new Mesh(); | ||
|
||
mesh.vertices = newVerts; | ||
mesh.uv = newUVs; | ||
mesh.normals = newNormals; | ||
mesh.triangles = newMesh.triangles; | ||
|
||
mesh.RecalculateBounds(); | ||
//mesh.Optimize(); | ||
|
||
return mesh; | ||
} | ||
|
||
private static meshStruct createMeshStruct(string filename) | ||
{ | ||
int triangles = 0; | ||
int vertices = 0; | ||
int vt = 0; | ||
int vn = 0; | ||
int face = 0; | ||
meshStruct mesh = new meshStruct(); | ||
mesh.fileName = filename; | ||
StreamReader stream = File.OpenText(filename); | ||
string entireText = stream.ReadToEnd(); | ||
stream.Close(); | ||
using (StringReader reader = new StringReader(entireText)) | ||
{ | ||
string currentText = reader.ReadLine(); | ||
char[] splitIdentifier = { ' ' }; | ||
string[] brokenString; | ||
while (currentText != null) | ||
{ | ||
if (!currentText.StartsWith("f ") && !currentText.StartsWith("v ") && !currentText.StartsWith("vt ") | ||
&& !currentText.StartsWith("vn ")) | ||
{ | ||
currentText = reader.ReadLine(); | ||
if (currentText != null) | ||
{ | ||
currentText = currentText.Replace(" ", " "); | ||
} | ||
} | ||
else | ||
{ | ||
currentText = currentText.Trim(); //Trim the current line | ||
brokenString = currentText.Split(splitIdentifier, 50); //Split the line into an array, separating the original line by blank spaces | ||
switch (brokenString[0]) | ||
{ | ||
case "v": | ||
vertices++; | ||
break; | ||
case "vt": | ||
vt++; | ||
break; | ||
case "vn": | ||
vn++; | ||
break; | ||
case "f": | ||
face = face + brokenString.Length - 1; | ||
triangles = triangles + 3 * (brokenString.Length - 2); /*brokenString.Length is 3 or greater since a face must have at least | ||
3 vertices. For each additional vertice, there is an additional | ||
triangle in the mesh (hence this formula).*/ | ||
break; | ||
} | ||
currentText = reader.ReadLine(); | ||
if (currentText != null) | ||
{ | ||
currentText = currentText.Replace(" ", " "); | ||
} | ||
} | ||
} | ||
} | ||
mesh.triangles = new int[triangles]; | ||
mesh.vertices = new Vector3[vertices]; | ||
mesh.uv = new Vector2[vt]; | ||
mesh.normals = new Vector3[vn]; | ||
mesh.faceData = new Vector3[face]; | ||
return mesh; | ||
} | ||
|
||
private static void populateMeshStruct(ref meshStruct mesh) | ||
{ | ||
StreamReader stream = File.OpenText(mesh.fileName); | ||
string entireText = stream.ReadToEnd(); | ||
stream.Close(); | ||
using (StringReader reader = new StringReader(entireText)) | ||
{ | ||
string currentText = reader.ReadLine(); | ||
|
||
char[] splitIdentifier = { ' ' }; | ||
char[] splitIdentifier2 = { '/' }; | ||
string[] brokenString; | ||
string[] brokenBrokenString; | ||
int f = 0; | ||
int f2 = 0; | ||
int v = 0; | ||
int vn = 0; | ||
int vt = 0; | ||
int vt1 = 0; | ||
int vt2 = 0; | ||
while (currentText != null) | ||
{ | ||
if (!currentText.StartsWith("f ") && !currentText.StartsWith("v ") && !currentText.StartsWith("vt ") && | ||
!currentText.StartsWith("vn ") && !currentText.StartsWith("g ") && !currentText.StartsWith("usemtl ") && | ||
!currentText.StartsWith("mtllib ") && !currentText.StartsWith("vt1 ") && !currentText.StartsWith("vt2 ") && | ||
!currentText.StartsWith("vc ") && !currentText.StartsWith("usemap ")) | ||
{ | ||
currentText = reader.ReadLine(); | ||
if (currentText != null) | ||
{ | ||
currentText = currentText.Replace(" ", " "); | ||
} | ||
} | ||
else | ||
{ | ||
currentText = currentText.Trim(); | ||
brokenString = currentText.Split(splitIdentifier, 50); | ||
switch (brokenString[0]) | ||
{ | ||
case "g": | ||
break; | ||
case "usemtl": | ||
break; | ||
case "usemap": | ||
break; | ||
case "mtllib": | ||
break; | ||
case "v": | ||
mesh.vertices[v] = new Vector3(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]), | ||
System.Convert.ToSingle(brokenString[3])); | ||
v++; | ||
break; | ||
case "vt": | ||
mesh.uv[vt] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2])); | ||
vt++; | ||
break; | ||
case "vt1": | ||
mesh.uv[vt1] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2])); | ||
vt1++; | ||
break; | ||
case "vt2": | ||
mesh.uv[vt2] = new Vector2(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2])); | ||
vt2++; | ||
break; | ||
case "vn": | ||
mesh.normals[vn] = new Vector3(System.Convert.ToSingle(brokenString[1]), System.Convert.ToSingle(brokenString[2]), | ||
System.Convert.ToSingle(brokenString[3])); | ||
vn++; | ||
break; | ||
case "vc": | ||
break; | ||
case "f": | ||
|
||
int j = 1; | ||
List<int> intArray = new List<int>(); | ||
while (j < brokenString.Length && ("" + brokenString[j]).Length > 0) | ||
{ | ||
Vector3 temp = new Vector3(); | ||
brokenBrokenString = brokenString[j].Split(splitIdentifier2, 3); //Separate the face into individual components (vert, uv, normal) | ||
temp.x = System.Convert.ToInt32(brokenBrokenString[0]); | ||
if (brokenBrokenString.Length > 1) //Some .obj files skip UV and normal | ||
{ | ||
if (brokenBrokenString[1] != "") //Some .obj files skip the uv and not the normal | ||
{ | ||
temp.y = System.Convert.ToInt32(brokenBrokenString[1]); | ||
} | ||
temp.z = System.Convert.ToInt32(brokenBrokenString[2]); | ||
} | ||
j++; | ||
|
||
mesh.faceData[f2] = temp; | ||
intArray.Add(f2); | ||
f2++; | ||
} | ||
j = 1; | ||
while (j + 2 < brokenString.Length) //Create triangles out of the face data. There will generally be more than 1 triangle per face. | ||
{ | ||
mesh.triangles[f] = intArray[0]; | ||
f++; | ||
mesh.triangles[f] = intArray[j]; | ||
f++; | ||
mesh.triangles[f] = intArray[j + 1]; | ||
f++; | ||
|
||
j++; | ||
} | ||
break; | ||
} | ||
currentText = reader.ReadLine(); | ||
if (currentText != null) | ||
{ | ||
currentText = currentText.Replace(" ", " "); //Some .obj files insert double spaces, this removes them. | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.