OBJLoader enhancement: named groups support
This commit is contained in:
parent
6ade1a027e
commit
0f06c14c28
@ -17,6 +17,10 @@ sourceSets {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile project(':jme3-testdata')
|
||||
}
|
||||
|
||||
task updateVersionPropertiesFile {
|
||||
def versionFile = file('src/main/resources/com/jme3/system/version.properties')
|
||||
def versionFileText = "# THIS IS AN AUTO-GENERATED FILE..\n" +
|
||||
|
@ -152,6 +152,7 @@ public class MTLLoader implements AssetLoader {
|
||||
material.setFloat("AlphaDiscardThreshold", 0.01f);
|
||||
}
|
||||
|
||||
material.setName(matName);
|
||||
matList.put(matName, material);
|
||||
}
|
||||
|
||||
|
@ -66,10 +66,9 @@ public final class OBJLoader implements AssetLoader {
|
||||
protected final ArrayList<Vector3f> verts = new ArrayList<Vector3f>();
|
||||
protected final ArrayList<Vector2f> texCoords = new ArrayList<Vector2f>();
|
||||
protected final ArrayList<Vector3f> norms = new ArrayList<Vector3f>();
|
||||
|
||||
protected final ArrayList<Face> faces = new ArrayList<Face>();
|
||||
protected final HashMap<String, ArrayList<Face>> matFaces = new HashMap<String, ArrayList<Face>>();
|
||||
|
||||
|
||||
private final ArrayList<Group> groups = new ArrayList<Group>();
|
||||
|
||||
protected String currentMatName;
|
||||
protected String currentObjectName;
|
||||
|
||||
@ -87,6 +86,16 @@ public final class OBJLoader implements AssetLoader {
|
||||
protected String objName;
|
||||
protected Node objNode;
|
||||
|
||||
private static class Group {
|
||||
private String name;
|
||||
private final ArrayList<Face> faces = new ArrayList<Face>();
|
||||
private final HashMap<String, ArrayList<Face>> matFaces = new HashMap<String, ArrayList<Face>>();
|
||||
|
||||
public Group(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class Vertex {
|
||||
|
||||
Vector3f v;
|
||||
@ -164,8 +173,7 @@ public final class OBJLoader implements AssetLoader {
|
||||
verts.clear();
|
||||
texCoords.clear();
|
||||
norms.clear();
|
||||
faces.clear();
|
||||
matFaces.clear();
|
||||
groups.clear();
|
||||
|
||||
vertIndexMap.clear();
|
||||
indexVertMap.clear();
|
||||
@ -289,10 +297,17 @@ public final class OBJLoader implements AssetLoader {
|
||||
f.verticies[i] = vertList.get(i);
|
||||
}
|
||||
|
||||
if (matList != null && matFaces.containsKey(currentMatName)){
|
||||
matFaces.get(currentMatName).add(f);
|
||||
Group group = groups.get(groups.size() - 1);
|
||||
|
||||
if (currentMatName != null && matList != null && matList.containsKey(currentMatName)){
|
||||
ArrayList<Face> matFaces = group.matFaces.get(currentMatName);
|
||||
if (matFaces == null) {
|
||||
matFaces = new ArrayList<Face>();
|
||||
group.matFaces.put(currentMatName, matFaces);
|
||||
}
|
||||
matFaces.add(f);
|
||||
}else{
|
||||
faces.add(f); // faces that belong to the default material
|
||||
group.faces.add(f); // faces that belong to the default material
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,13 +352,6 @@ public final class OBJLoader implements AssetLoader {
|
||||
} catch (AssetNotFoundException ex){
|
||||
logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{name, key});
|
||||
}
|
||||
|
||||
if (matList != null){
|
||||
// create face lists for every material
|
||||
for (String matName : matList.keySet()){
|
||||
matFaces.put(matName, new ArrayList<Face>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean nextStatement(){
|
||||
@ -387,8 +395,14 @@ public final class OBJLoader implements AssetLoader {
|
||||
// specify MTL lib to use for this OBJ file
|
||||
String mtllib = scan.nextLine().trim();
|
||||
loadMtlLib(mtllib);
|
||||
}else if (cmd.equals("s") || cmd.equals("g")){
|
||||
}else if (cmd.equals("s")) {
|
||||
logger.log(Level.WARNING, "smoothing groups are not supported, statement ignored: {0}", cmd);
|
||||
return nextStatement();
|
||||
}else if (cmd.equals("mg")) {
|
||||
logger.log(Level.WARNING, "merge groups are not supported, statement ignored: {0}", cmd);
|
||||
return nextStatement();
|
||||
}else if (cmd.equals("g")) {
|
||||
groups.add(new Group(scan.nextLine().trim()));
|
||||
}else{
|
||||
// skip entire command until next line
|
||||
logger.log(Level.WARNING, "Unknown statement in OBJ! {0}", cmd);
|
||||
@ -565,11 +579,14 @@ public final class OBJLoader implements AssetLoader {
|
||||
}
|
||||
|
||||
objNode = new Node(objName + "-objnode");
|
||||
|
||||
Group defaultGroupStub = new Group(null);
|
||||
groups.add(defaultGroupStub);
|
||||
|
||||
if (!(info.getKey() instanceof ModelKey))
|
||||
throw new IllegalArgumentException("Model assets must be loaded using a ModelKey");
|
||||
|
||||
InputStream in = null;
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = info.openStream();
|
||||
|
||||
@ -583,25 +600,43 @@ public final class OBJLoader implements AssetLoader {
|
||||
}
|
||||
}
|
||||
|
||||
if (matFaces.size() > 0){
|
||||
for (Entry<String, ArrayList<Face>> entry : matFaces.entrySet()){
|
||||
ArrayList<Face> materialFaces = entry.getValue();
|
||||
if (materialFaces.size() > 0){
|
||||
Geometry geom = createGeometry(materialFaces, entry.getKey());
|
||||
for (Group group : groups) {
|
||||
if (group == defaultGroupStub) {
|
||||
materializeGroup(group, objNode);
|
||||
} else {
|
||||
Node groupNode = new Node(group.name);
|
||||
materializeGroup(group, groupNode);
|
||||
if (groupNode.getQuantity() == 1) {
|
||||
Spatial geom = groupNode.getChild(0);
|
||||
geom.setName(groupNode.getName());
|
||||
objNode.attachChild(geom);
|
||||
} else if (groupNode.getQuantity() > 1) {
|
||||
objNode.attachChild(groupNode);
|
||||
}
|
||||
}
|
||||
}else if (faces.size() > 0){
|
||||
// generate final geometry
|
||||
Geometry geom = createGeometry(faces, null);
|
||||
objNode.attachChild(geom);
|
||||
}
|
||||
|
||||
if (objNode.getQuantity() == 1)
|
||||
// only 1 geometry, so no need to send node
|
||||
return objNode.getChild(0);
|
||||
return objNode.getChild(0);
|
||||
else
|
||||
return objNode;
|
||||
}
|
||||
|
||||
|
||||
private void materializeGroup(Group group, Node container) throws IOException {
|
||||
if (group.matFaces.size() > 0) {
|
||||
for (Entry<String, ArrayList<Face>> entry : group.matFaces.entrySet()){
|
||||
ArrayList<Face> materialFaces = entry.getValue();
|
||||
if (materialFaces.size() > 0){
|
||||
Geometry geom = createGeometry(materialFaces, entry.getKey());
|
||||
container.attachChild(geom);
|
||||
}
|
||||
}
|
||||
} else if (group.faces.size() > 0) {
|
||||
// generate final geometry
|
||||
Geometry geom = createGeometry(group.faces, null);
|
||||
container.attachChild(geom);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2020 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.scene.plugins;
|
||||
|
||||
import com.jme3.asset.AssetInfo;
|
||||
import com.jme3.asset.AssetLoader;
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.asset.ModelKey;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.system.TestUtil;
|
||||
import com.jme3.texture.Image;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class OBJLoaderTest {
|
||||
private AssetManager assetManager;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
assetManager = TestUtil.createAssetManager();
|
||||
// texture loaders are outside of core, so creating stub
|
||||
assetManager.registerLoader(PngLoaderStub.class, "png");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHappyPath() {
|
||||
Node scene = (Node) assetManager.loadModel(new ModelKey("OBJLoaderTest/TwoChairs.obj"));
|
||||
String sceneAsString = toDiffFriendlyString("", scene);
|
||||
System.out.println(sceneAsString);
|
||||
String expectedText = "" +
|
||||
// generated root name (as before named groups support)
|
||||
"TwoChairs-objnode\n" +
|
||||
// unnamed geometry with generated name (as before named groups support).
|
||||
// actually it's partially smoothed, but this fact is ignored.
|
||||
" TwoChairs-geom-0 (material: dot_purple)\n" +
|
||||
// named group as Geometry
|
||||
" Chair 2 (material: dot_purple)\n" +
|
||||
// named group as Geometry
|
||||
" Pillow 2 (material: dot_red)\n" +
|
||||
// named group as node with two dufferent Geometry instances,
|
||||
// because two materials are used (as before named groups support)
|
||||
" Podium\n" +
|
||||
" TwoChairs-geom-3 (material: dot_red)\n" +
|
||||
" TwoChairs-geom-4 (material: dot_blue)\n" +
|
||||
// named group as Geometry
|
||||
" Pillow 1 (material: dot_green)";
|
||||
assertEquals(expectedText, sceneAsString.trim());
|
||||
}
|
||||
|
||||
private static String toDiffFriendlyString(String indent, Spatial spatial) {
|
||||
if (spatial instanceof Geometry) {
|
||||
return indent + spatial.getName() + " (material: "+((Geometry) spatial).getMaterial().getName()+")\n";
|
||||
}
|
||||
if (spatial instanceof Node) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(indent).append(spatial.getName()).append("\n");
|
||||
Node node = (Node) spatial;
|
||||
for (final Spatial child : node.getChildren()) {
|
||||
s.append(toDiffFriendlyString(indent + " ", child));
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
return indent + spatial + "\n";
|
||||
}
|
||||
|
||||
public static class PngLoaderStub implements AssetLoader {
|
||||
@Override
|
||||
public Object load(final AssetInfo assetInfo) {
|
||||
return new Image();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2020 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jme3test.model;
|
||||
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.asset.ModelKey;
|
||||
import com.jme3.collision.CollisionResult;
|
||||
import com.jme3.collision.CollisionResults;
|
||||
import com.jme3.font.BitmapFont;
|
||||
import com.jme3.font.BitmapText;
|
||||
import com.jme3.font.Rectangle;
|
||||
import com.jme3.light.AmbientLight;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Ray;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Spatial;
|
||||
|
||||
public class TestObjGroupsLoading extends SimpleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestObjGroupsLoading app = new TestObjGroupsLoading();
|
||||
app.start();
|
||||
}
|
||||
|
||||
private BitmapText pointerDisplay;
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
|
||||
// load scene with following structure:
|
||||
// Chair 1 (just mesh without name) and named groups: Chair 2, Pillow 2, Podium
|
||||
Spatial scene = assetManager.loadModel(new ModelKey("OBJLoaderTest/TwoChairs.obj"));
|
||||
// add light to make it visible
|
||||
scene.addLight(new AmbientLight(ColorRGBA.White));
|
||||
// attach scene to the root
|
||||
rootNode.attachChild(scene);
|
||||
|
||||
// configure camera for best scene viewing
|
||||
cam.setLocation(new Vector3f(-3, 4, 3));
|
||||
cam.lookAtDirection(new Vector3f(0, -0.5f, -1), Vector3f.UNIT_Y);
|
||||
flyCam.setMoveSpeed(10);
|
||||
|
||||
// create display to indicate pointed geometry name
|
||||
pointerDisplay = new BitmapText(guiFont);
|
||||
pointerDisplay.setBox(new Rectangle(0, settings.getHeight(), settings.getWidth(), settings.getHeight()/2));
|
||||
pointerDisplay.setAlignment(BitmapFont.Align.Center);
|
||||
pointerDisplay.setVerticalAlignment(BitmapFont.VAlign.Center);
|
||||
guiNode.attachChild(pointerDisplay);
|
||||
|
||||
initCrossHairs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleUpdate(final float tpf) {
|
||||
|
||||
// ray to the center of the screen from the camera
|
||||
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
|
||||
|
||||
// find object at the center of the screen
|
||||
|
||||
final CollisionResults results = new CollisionResults();
|
||||
rootNode.collideWith(ray, results);
|
||||
|
||||
CollisionResult result = results.getClosestCollision();
|
||||
if (result == null) {
|
||||
pointerDisplay.setText("");
|
||||
} else {
|
||||
// display pointed geometry and it's parents names
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Spatial node = result.getGeometry(); node != null; node = node.getParent()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(" < ");
|
||||
}
|
||||
sb.append(node.getName());
|
||||
}
|
||||
pointerDisplay.setText(sb);
|
||||
}
|
||||
}
|
||||
|
||||
private void initCrossHairs() {
|
||||
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
|
||||
BitmapText ch = new BitmapText(guiFont, false);
|
||||
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
|
||||
ch.setText("+"); // crosshairs
|
||||
ch.setLocalTranslation( // center
|
||||
settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
|
||||
settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
|
||||
guiNode.attachChild(ch);
|
||||
}
|
||||
}
|
20
jme3-testdata/src/main/resources/OBJLoaderTest/TwoChairs.mtl
Normal file
20
jme3-testdata/src/main/resources/OBJLoaderTest/TwoChairs.mtl
Normal file
@ -0,0 +1,20 @@
|
||||
newmtl dot_purple
|
||||
map_Kd -o 0 0 -s 1 1 dot_purple.png
|
||||
Kd 1 1 1
|
||||
d 1
|
||||
|
||||
newmtl dot_red
|
||||
map_Kd -o 0 0 -s 1 1 dot_red.png
|
||||
Kd 1 1 1
|
||||
d 1
|
||||
|
||||
newmtl dot_blue
|
||||
map_Kd -o 0 0 -s 1 1 dot_blue.png
|
||||
Kd 1 1 1
|
||||
d 1
|
||||
|
||||
newmtl dot_green
|
||||
map_Kd -o 0 0 -s 1 1 dot_green.png
|
||||
Kd 1 1 1
|
||||
d 1
|
||||
|
219
jme3-testdata/src/main/resources/OBJLoaderTest/TwoChairs.obj
Normal file
219
jme3-testdata/src/main/resources/OBJLoaderTest/TwoChairs.obj
Normal file
@ -0,0 +1,219 @@
|
||||
# ProBuilder 4.2.3
|
||||
# https://unity3d.com/unity/features/worldbuilding/probuilder
|
||||
# 5/10/2020 4:30:31 PM
|
||||
|
||||
mtllib ./TwoChairs.mtl
|
||||
o TwoChairs
|
||||
|
||||
v -4 1 0
|
||||
v -5 1 0
|
||||
v -4 2 0
|
||||
v -5 2 0
|
||||
v -5 1 -1
|
||||
v -5 2 -1
|
||||
v -5 1 -1.25
|
||||
v -4 1 -1.25
|
||||
|
||||
s 1
|
||||
v -5 2 -1.25
|
||||
v -4 2 -1.25
|
||||
v -4 1 -1
|
||||
v -4 2 -1
|
||||
v -4 3 -1
|
||||
v -5 3 -1
|
||||
v -4 3 -1.25
|
||||
v -5 3 -1.25
|
||||
s off
|
||||
|
||||
vt 0 0
|
||||
vt -1 0
|
||||
vt 0 1
|
||||
vt -1 1
|
||||
vt 1 0
|
||||
vt 1 1
|
||||
vt -1 -1
|
||||
vt 0 -1
|
||||
vt -1 -1.25
|
||||
vt 0 -1.25
|
||||
vt -1.25 1
|
||||
vt -1.25 0
|
||||
vt 1.25 0
|
||||
vt 1.25 1
|
||||
vt 1 -1
|
||||
vt 1 -1.25
|
||||
vt 0 2
|
||||
vt -1 2
|
||||
vt 1.25 2
|
||||
vt 1 2
|
||||
vt -1.25 2
|
||||
|
||||
vn 0 0 1
|
||||
vn -1 0 0
|
||||
vn 0 0 -1
|
||||
vn 1 0 0
|
||||
vn 0 -1 0
|
||||
vn 0 1 0
|
||||
|
||||
usemtl dot_purple
|
||||
f 3/3/1 4/4/1 2/2/1 1/1/1
|
||||
f 4/3/2 6/4/2 5/2/2 2/1/2
|
||||
f 9/6/3 10/3/3 8/1/3 7/5/3
|
||||
f 12/6/4 3/3/4 1/1/4 11/5/4
|
||||
f 7/9/5 8/10/5 11/8/5 5/7/5
|
||||
f 9/11/2 7/12/2 5/2/2 6/4/2
|
||||
f 8/13/4 10/14/4 12/6/4 11/5/4
|
||||
f 15/10/6 16/16/6 14/15/6 13/8/6
|
||||
f 13/17/1 14/18/1 6/4/1 12/3/1
|
||||
f 15/19/4 13/20/4 12/6/4 10/14/4
|
||||
f 14/18/2 16/21/2 9/11/2 6/4/2
|
||||
f 16/20/3 15/17/3 10/3/3 9/6/3
|
||||
|
||||
g Chair 2
|
||||
v -2 1 0
|
||||
v -3 1 0
|
||||
v -2 2 0
|
||||
v -3 2 0
|
||||
v -3 1 -1
|
||||
v -3 2 -1
|
||||
v -3 1 -1.25
|
||||
v -2 1 -1.25
|
||||
v -3 2 -1.25
|
||||
v -2 2 -1.25
|
||||
v -2 1 -1
|
||||
v -2 2 -1
|
||||
v -2 3 -1
|
||||
v -3 3 -1
|
||||
v -2 3 -1.25
|
||||
v -3 3 -1.25
|
||||
|
||||
vt 0 0
|
||||
vt -1 0
|
||||
vt 0 1
|
||||
vt -1 1
|
||||
vt 1 0
|
||||
vt 1 1
|
||||
vt -1 -1
|
||||
vt 0 -1
|
||||
vt -1 -1.25
|
||||
vt 0 -1.25
|
||||
vt -1.25 1
|
||||
vt -1.25 0
|
||||
vt 1.25 0
|
||||
vt 1.25 1
|
||||
vt 1 -1
|
||||
vt 1 -1.25
|
||||
vt 0 2
|
||||
vt -1 2
|
||||
vt 1.25 2
|
||||
vt 1 2
|
||||
vt -1.25 2
|
||||
|
||||
vn 0 0 1
|
||||
vn -1 0 0
|
||||
vn 0 0 -1
|
||||
vn 1 0 0
|
||||
vn 0 -1 0
|
||||
vn 0 1 0
|
||||
|
||||
usemtl dot_purple
|
||||
f 19/24/7 20/25/7 18/23/7 17/22/7
|
||||
f 20/24/8 22/25/8 21/23/8 18/22/8
|
||||
f 25/27/9 26/24/9 24/22/9 23/26/9
|
||||
f 28/27/10 19/24/10 17/22/10 27/26/10
|
||||
f 23/30/11 24/31/11 27/29/11 21/28/11
|
||||
f 25/32/8 23/33/8 21/23/8 22/25/8
|
||||
f 24/34/10 26/35/10 28/27/10 27/26/10
|
||||
f 31/31/12 32/37/12 30/36/12 29/29/12
|
||||
f 29/38/7 30/39/7 22/25/7 28/24/7
|
||||
f 31/40/10 29/41/10 28/27/10 26/35/10
|
||||
f 30/39/8 32/42/8 25/32/8 22/25/8
|
||||
f 32/41/9 31/38/9 26/24/9 25/27/9
|
||||
|
||||
g Pillow 2
|
||||
v -2 2 0
|
||||
v -3 2 0
|
||||
v -2 2 -1
|
||||
v -3 2 -1
|
||||
|
||||
vt 0 0
|
||||
vt 1 0
|
||||
vt 0 -1
|
||||
vt 1 -1
|
||||
|
||||
vn 0 1 0
|
||||
|
||||
usemtl dot_red
|
||||
f 35/45/13 36/46/13 34/44/13 33/43/13
|
||||
|
||||
g Podium
|
||||
v -1 0 1.5
|
||||
v -6 0 1.5
|
||||
v -1 1 1.5
|
||||
v -6 1 1.5
|
||||
v -6 0 -2
|
||||
v -6 1 -2
|
||||
v -1 0 -2
|
||||
v -1 1 -2
|
||||
|
||||
vt -1 0
|
||||
vt -6 0
|
||||
vt -1 1
|
||||
vt -6 1
|
||||
vt 1.5 0
|
||||
vt -2 0
|
||||
vt 1.5 1
|
||||
vt -2 1
|
||||
vt 6 0
|
||||
vt 1 0
|
||||
vt 6 1
|
||||
vt 1 1
|
||||
|
||||
s 1
|
||||
vt 2 0
|
||||
vt -1.5 0
|
||||
vt 2 1
|
||||
vt -1.5 1
|
||||
vt 1 1.5
|
||||
vt 6 1.5
|
||||
vt 1 -2
|
||||
vt 6 -2
|
||||
vt -1 -2
|
||||
vt -6 -2
|
||||
vt -1 1.5
|
||||
vt -6 1.5
|
||||
s off
|
||||
|
||||
vn 0 0 1
|
||||
vn 0 0.7071068 0.7071068
|
||||
vn -1 0 0
|
||||
vn 0 0 -1
|
||||
vn 1 0 0
|
||||
vn 0 1 0
|
||||
vn 0 -1 0
|
||||
|
||||
usemtl dot_red
|
||||
f 39/49/15 40/50/15 38/48/14 37/47/14
|
||||
f 40/53/16 42/54/16 41/52/16 38/51/16
|
||||
f 42/57/17 44/58/17 43/56/17 41/55/17
|
||||
f 44/61/18 39/62/18 37/60/18 43/59/18
|
||||
f 37/69/20 38/70/20 41/68/20 43/67/20
|
||||
|
||||
usemtl dot_blue
|
||||
f 44/65/19 42/66/19 40/64/15 39/63/15
|
||||
|
||||
g Pillow 1
|
||||
v -4 2 0
|
||||
v -5 2 0
|
||||
v -4 2 -1
|
||||
v -5 2 -1
|
||||
|
||||
vt 0 0
|
||||
vt 1 0
|
||||
vt 0 -1
|
||||
vt 1 -1
|
||||
|
||||
vn 0 1 0
|
||||
|
||||
usemtl dot_green
|
||||
f 47/73/21 48/74/21 46/72/21 45/71/21
|
||||
|
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_blue.png
Normal file
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_blue.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 143 B |
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_green.png
Normal file
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 142 B |
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_purple.png
Normal file
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_purple.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 143 B |
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_red.png
Normal file
BIN
jme3-testdata/src/main/resources/OBJLoaderTest/dot_red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 142 B |
Loading…
x
Reference in New Issue
Block a user