source: trunk/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/AnimationDemoExample.java @ 1787

Revision 1787, 10.6 KB checked in by ardorlabs, 4 months ago (diff)

minor cleanup to fix shader use

Line 
1/**
2 * Copyright (c) 2008-2011 Ardor Labs, Inc.
3 *
4 * This file is part of Ardor3D.
5 *
6 * Ardor3D is free software: you can redistribute it and/or modify it
7 * under the terms of its license which may be found in the accompanying
8 * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
9 */
10
11package com.ardor3d.example.pipeline;
12
13import java.io.IOException;
14import java.util.List;
15import java.util.Map;
16
17import com.ardor3d.example.ExampleBase;
18import com.ardor3d.example.Purpose;
19import com.ardor3d.extension.animation.skeletal.AnimationManager;
20import com.ardor3d.extension.animation.skeletal.SkeletonPose;
21import com.ardor3d.extension.animation.skeletal.SkinnedMesh;
22import com.ardor3d.extension.animation.skeletal.SkinnedMeshCombineLogic;
23import com.ardor3d.extension.animation.skeletal.blendtree.SimpleAnimationApplier;
24import com.ardor3d.extension.animation.skeletal.clip.AnimationClip;
25import com.ardor3d.extension.animation.skeletal.state.loader.InputStore;
26import com.ardor3d.extension.animation.skeletal.state.loader.JSLayerImporter;
27import com.ardor3d.extension.animation.skeletal.util.MissingCallback;
28import com.ardor3d.extension.model.collada.jdom.ColladaImporter;
29import com.ardor3d.extension.model.collada.jdom.data.ColladaStorage;
30import com.ardor3d.extension.model.util.nvtristrip.NvTriangleStripper;
31import com.ardor3d.framework.NativeCanvas;
32import com.ardor3d.light.DirectionalLight;
33import com.ardor3d.math.ColorRGBA;
34import com.ardor3d.math.Vector3;
35import com.ardor3d.renderer.Camera;
36import com.ardor3d.renderer.state.CullState;
37import com.ardor3d.renderer.state.CullState.Face;
38import com.ardor3d.renderer.state.GLSLShaderObjectsState;
39import com.ardor3d.scenegraph.Node;
40import com.ardor3d.scenegraph.Spatial;
41import com.ardor3d.scenegraph.hint.DataMode;
42import com.ardor3d.scenegraph.visitor.Visitor;
43import com.ardor3d.util.ReadOnlyTimer;
44import com.ardor3d.util.geom.MeshCombiner;
45import com.ardor3d.util.resource.ResourceLocatorTool;
46import com.ardor3d.util.resource.ResourceSource;
47import com.ardor3d.util.resource.URLResourceSource;
48import com.google.common.collect.Lists;
49import com.google.common.collect.Maps;
50
51/**
52 * Illustrates loading several animations from Collada and arranging them in an animation state machine.
53 */
54@Purpose(htmlDescriptionKey = "com.ardor3d.example.pipeline.AnimationDemoExample", //
55thumbnailPath = "com/ardor3d/example/media/thumbnails/pipeline_AnimationDemoExample.jpg", //
56maxHeapMemory = 64)
57public class AnimationDemoExample extends ExampleBase {
58
59    private static final long MIN_STATE_TIME = 5000;
60
61    static AnimationDemoExample instance;
62
63    private final List<AnimationManager> managers = Lists.newArrayList();
64    private final List<AnimationInfo> animInfo = Lists.newArrayList();
65    private final Map<SkeletonPose, SkinnedMesh> poseToMesh = Maps.newIdentityHashMap();
66
67    public static void main(final String[] args) {
68        ExampleBase.start(AnimationDemoExample.class);
69    }
70
71    public AnimationDemoExample() {
72        instance = this;
73    }
74
75    @Override
76    protected void initExample() {
77        _canvas.setTitle("Ardor3D - Animation Demo Example - Skeletons Patrol!");
78        _canvas.getCanvasRenderer().getRenderer().setBackgroundColor(ColorRGBA.GRAY);
79
80        // set camera
81        final Camera cam = _canvas.getCanvasRenderer().getCamera();
82        cam.setLocation(197, 113, -126);
83        cam.lookAt(new Vector3(157, 91, -174), Vector3.UNIT_Y);
84        cam.setFrustumPerspective(45.0, cam.getWidth() / (double) cam.getHeight(), .25, 900);
85        cam.update();
86
87        // speed up wasd control a little
88        _controlHandle.setMoveSpeed(200);
89
90        _lightState.detachAll();
91        final DirectionalLight light = new DirectionalLight();
92        light.setDiffuse(new ColorRGBA(0.75f, 0.75f, 0.75f, 0.75f));
93        light.setAmbient(new ColorRGBA(0.25f, 0.25f, 0.25f, 1.0f));
94        light.setDirection(new Vector3(-1, -1, -1).normalizeLocal());
95        light.setEnabled(true);
96        _lightState.attach(light);
97
98        final SkinnedMesh skeleton = loadMainSkeleton();
99
100        // Load collada model
101        for (int i = 0; i < 10; i++) {
102            final SkinnedMesh copy = skeleton.makeCopy(true);
103            copy.setCurrentPose(skeleton.getCurrentPose().makeCopy());
104            copy.setTranslation(((i % 5) - 2) * 60, 0, ((i / 5) * 40) - 320);
105            _root.attachChild(copy);
106            final AnimationManager manager = createAnimationManager(copy.getCurrentPose());
107            managers.add(manager);
108            animInfo.add(new AnimationInfo());
109            poseToMesh.put(copy.getCurrentPose(), copy);
110        }
111    }
112
113    private SkinnedMesh loadMainSkeleton() {
114        SkinnedMesh skeleton = null;
115        try {
116            final long time = System.currentTimeMillis();
117            final ColladaImporter colladaImporter = new ColladaImporter();
118
119            // OPTIMIZATION: run GeometryTool on collada meshes to reduce redundant vertices...
120            colladaImporter.setOptimizeMeshes(true);
121
122            // Load the collada scene
123            final String mainFile = "collada/skeleton/skeleton.walk.dae";
124            final ColladaStorage storage = colladaImporter.load(mainFile);
125            final Node colladaNode = storage.getScene();
126
127            System.out.println("Importing: " + mainFile);
128            System.out.println("Took " + (System.currentTimeMillis() - time) + " ms");
129
130            final GLSLShaderObjectsState gpuShader = new GLSLShaderObjectsState();
131            gpuShader.setEnabled(true);
132            try {
133                gpuShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(AnimationDemoExample.class,
134                        "com/ardor3d/extension/animation/skeletal/skinning_gpu_texture.vert"));
135                gpuShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
136                        AnimationDemoExample.class,
137                        "com/ardor3d/extension/animation/skeletal/skinning_gpu_texture.frag"));
138
139                gpuShader.setUniform("texture", 0);
140                gpuShader.setUniform("lightDirection", new Vector3(1, 1, 1).normalizeLocal());
141            } catch (final IOException ioe) {
142                ioe.printStackTrace();
143            }
144
145            // OPTIMIZATION: SkinnedMesh combining... Useful in our case because the skeleton model is composed of 2
146            // separate meshes.
147            skeleton = (SkinnedMesh) MeshCombiner.combine(colladaNode, new SkinnedMeshCombineLogic());
148            // Non-combined:
149            // primeModel = colladaNode;
150
151            // OPTIMIZATION: turn on the buffers in our skeleton so they can be shared. (reuse ids)
152            skeleton.acceptVisitor(new Visitor() {
153                @Override
154                public void visit(final Spatial spatial) {
155                    if (spatial instanceof SkinnedMesh) {
156                        final SkinnedMesh skinnedSpatial = (SkinnedMesh) spatial;
157                        skinnedSpatial.recreateWeightAttributeBuffer();
158                        skinnedSpatial.recreateJointAttributeBuffer();
159                    }
160                }
161            }, true);
162
163            // OPTIMIZATION: run nv strippifyier on model...
164            final NvTriangleStripper stripper = new NvTriangleStripper();
165            stripper.setReorderVertices(true);
166            skeleton.acceptVisitor(stripper, true);
167
168            // OPTIMIZATION: don't draw surfaces that face away from the camera...
169            final CullState cullState = new CullState();
170            cullState.setCullFace(Face.Back);
171            skeleton.setRenderState(cullState);
172
173            skeleton.getSceneHints().setDataMode(DataMode.VBO);
174            gpuShader.setUseAttributeVBO(true);
175            skeleton.setGPUShader(gpuShader);
176            skeleton.setUseGPU(true);
177
178        } catch (final Exception ex) {
179            ex.printStackTrace();
180        }
181        return skeleton;
182    }
183
184    private final Map<String, AnimationClip> animationStore = Maps.newHashMap();
185
186    private AnimationManager createAnimationManager(final SkeletonPose pose) {
187        // Make our manager
188        final AnimationManager manager = new AnimationManager(_timer, pose);
189
190        // Add our "applier logic".
191        final SimpleAnimationApplier applier = new SimpleAnimationApplier();
192        manager.setApplier(applier);
193
194        // Add a call back to load clips.
195        final InputStore input = new InputStore();
196        input.getClips().setMissCallback(new MissingCallback<String, AnimationClip>() {
197            public AnimationClip getValue(final String key) {
198                if (!animationStore.containsKey(key)) {
199                    try {
200                        final ColladaStorage storage1 = new ColladaImporter().load("collada/skeleton/" + key + ".dae");
201                        animationStore.put(key, storage1.extractChannelsAsClip(key));
202                    } catch (final IOException e) {
203                        e.printStackTrace();
204                        animationStore.put(key, null);
205                    }
206                }
207                return animationStore.get(key);
208            }
209        });
210
211        // Load our layer and states from script
212        try {
213            final ResourceSource layersFile = new URLResourceSource(ResourceLocatorTool.getClassPathResource(
214                    AnimationDemoExample.class, "com/ardor3d/example/pipeline/AnimationDemoExample.js"));
215            JSLayerImporter.addLayers(layersFile, manager, input);
216        } catch (final Exception e) {
217            e.printStackTrace();
218        }
219
220        // kick things off by setting our starting state
221        manager.getBaseAnimationLayer().setCurrentState("walk_anim", true);
222
223        return manager;
224    }
225
226    @Override
227    protected void updateExample(final ReadOnlyTimer timer) {
228        for (int i = 0, max = managers.size(); i < max; i++) {
229            final AnimationManager manager = managers.get(i);
230            final AnimationInfo info = animInfo.get(i);
231            if (System.currentTimeMillis() - info.lastStateChange > MIN_STATE_TIME) {
232                if (Math.random() < 0.001) {
233                    manager.getBaseAnimationLayer().doTransition(info.running ? "walk" : "run");
234                    info.running = !info.running;
235                    info.lastStateChange = System.currentTimeMillis();
236                    manager.findAnimationLayer("punch").setCurrentState("punch_right", true);
237                }
238            }
239            manager.update();
240        }
241    }
242
243    public NativeCanvas getCanvas() {
244        return _canvas;
245    }
246
247    public Node getRoot() {
248        return _root;
249    }
250
251    class AnimationInfo {
252        boolean running = false;
253        long lastStateChange = 0;
254    }
255
256    public SkinnedMesh getMeshForPose(final SkeletonPose applyToPose) {
257        return poseToMesh.get(applyToPose);
258    }
259}
Note: See TracBrowser for help on using the repository browser.