From 686f263b0d9a5d95b4b3b055c7eda373bc2ba8da Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 May 2014 13:45:58 -0430 Subject: [PATCH] Added support for gpu skinning. Added animation system. --- .../nxtar/components/AnimationComponent.java | 44 +++++ .../shaders/SingleLightPerPixelShader.java | 162 ++++++++++++------ .../ciens/ccg/nxtar/states/InGameState.java | 6 + .../ccg/nxtar/systems/AnimationSystem.java | 15 +- 4 files changed, 176 insertions(+), 51 deletions(-) create mode 100644 src/ve/ucv/ciens/ccg/nxtar/components/AnimationComponent.java diff --git a/src/ve/ucv/ciens/ccg/nxtar/components/AnimationComponent.java b/src/ve/ucv/ciens/ccg/nxtar/components/AnimationComponent.java new file mode 100644 index 0000000..5c5131b --- /dev/null +++ b/src/ve/ucv/ciens/ccg/nxtar/components/AnimationComponent.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014 Miguel Angel Astor Romero + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ve.ucv.ciens.ccg.nxtar.components; + +import java.util.LinkedList; +import java.util.List; + +import com.artemis.Component; +import com.badlogic.gdx.graphics.g3d.ModelInstance; +import com.badlogic.gdx.graphics.g3d.utils.AnimationController; + +public class AnimationComponent extends Component { + public AnimationController controller; + public List animationsIds; + public int current; + public int next; + + public AnimationComponent(ModelInstance instance) throws IllegalArgumentException{ + if(instance == null) + throw new IllegalArgumentException("Instance is null."); + + controller = new AnimationController(instance); + animationsIds = new LinkedList(); + current = -1; + next = -1; + + for(int i = 0; i < instance.animations.size; i++){ + animationsIds.add(instance.animations.get(i).id); + } + } +} diff --git a/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPerPixelShader.java b/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPerPixelShader.java index f10fb1c..b123837 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPerPixelShader.java +++ b/src/ve/ucv/ciens/ccg/nxtar/graphics/shaders/SingleLightPerPixelShader.java @@ -19,6 +19,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Camera; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.VertexAttributes; import com.badlogic.gdx.graphics.g3d.Renderable; import com.badlogic.gdx.graphics.g3d.Shader; import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute; @@ -30,59 +31,100 @@ import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.utils.GdxRuntimeException; public class SingleLightPerPixelShader implements Shader{ - private static final String VERTEX_SHADER_PATH = "shaders/directionalPerPixelSingleLight/directionalPerPixel_vert.glsl"; - private static final String FRAGMENT_SHADER_PATH = "shaders/directionalPerPixelSingleLight/directionalPerPixel_frag.glsl"; + private static final int MAX_NUM_BONES = 4; + private static final Matrix4 IDENTITY = new Matrix4(); + private static final String VERTEX_SHADER_PATH = "shaders/directionalPerPixelSingleLight/directionalPerPixel_vert.glsl"; + private static final String FRAGMENT_SHADER_PATH = "shaders/directionalPerPixelSingleLight/directionalPerPixel_frag.glsl"; + private static final String INCLUDE_SKINNING = "#define SKINNING\n"; - private ShaderProgram program; + private ShaderProgram skinningProgram; + private ShaderProgram baseProgram; private Camera camera; private RenderContext context; private Matrix4 normalMatrix; // Uniform locations. - private int u_geomTrans; - private int u_projTrans; - private int u_lightPos; - private int u_lightDiffuse; - private int u_specular; - private int u_ambient; - private int u_shiny; - private int u_cameraPos; - private int u_materialDiffuse; - private int u_normalMatrix; + private int[] u_geomTrans; + private int[] u_projTrans; + private int[] u_lightPos; + private int[] u_lightDiffuse; + private int[] u_specular; + private int[] u_ambient; + private int[] u_shiny; + private int[] u_cameraPos; + private int[] u_materialDiffuse; + private int[] u_normalMatrix; + private int[] u_bones; public SingleLightPerPixelShader(){ - program = null; - camera = null; - context = null; + skinningProgram = null; + baseProgram = null; + camera = null; + context = null; } @Override public void init() throws GdxRuntimeException{ normalMatrix = new Matrix4().idt(); + u_bones = new int[MAX_NUM_BONES]; // Compile the shader. - program = new ShaderProgram(Gdx.files.internal(VERTEX_SHADER_PATH), Gdx.files.internal(FRAGMENT_SHADER_PATH)); + String vertexCode = Gdx.files.internal(VERTEX_SHADER_PATH).readString(); + String fragmentCode = Gdx.files.internal(FRAGMENT_SHADER_PATH).readString(); - if(!program.isCompiled()) - throw new GdxRuntimeException(program.getLog()); + skinningProgram = new ShaderProgram(INCLUDE_SKINNING + vertexCode, fragmentCode); + baseProgram = new ShaderProgram(vertexCode, fragmentCode); + + if(!skinningProgram.isCompiled()) + throw new GdxRuntimeException(skinningProgram.getLog()); + + if(!baseProgram.isCompiled()) + throw new GdxRuntimeException(skinningProgram.getLog()); + + // Create uniform locations. + u_projTrans = new int[2]; + u_geomTrans = new int[2]; + u_lightPos = new int[2]; + u_lightDiffuse = new int[2]; + u_specular = new int[2]; + u_ambient = new int[2]; + u_shiny = new int[2]; + u_cameraPos = new int[2]; + u_materialDiffuse = new int[2]; + u_normalMatrix = new int[2]; // Cache uniform locations. - u_projTrans = program.getUniformLocation("u_projTrans"); - u_geomTrans = program.getUniformLocation("u_geomTrans"); - u_lightPos = program.getUniformLocation("u_lightPos"); - u_lightDiffuse = program.getUniformLocation("u_lightDiffuse"); - u_specular = program.getUniformLocation("u_specular"); - u_ambient = program.getUniformLocation("u_ambient"); - u_shiny = program.getUniformLocation("u_shiny"); - u_cameraPos = program.getUniformLocation("u_cameraPos"); - u_materialDiffuse = program.getUniformLocation("u_materialDiffuse"); - u_normalMatrix = program.getUniformLocation("u_normalMatrix"); + u_projTrans [0] = skinningProgram.getUniformLocation("u_projTrans"); + u_geomTrans [0] = skinningProgram.getUniformLocation("u_geomTrans"); + u_lightPos [0] = skinningProgram.getUniformLocation("u_lightPos"); + u_lightDiffuse [0] = skinningProgram.getUniformLocation("u_lightDiffuse"); + u_specular [0] = skinningProgram.getUniformLocation("u_specular"); + u_ambient [0] = skinningProgram.getUniformLocation("u_ambient"); + u_shiny [0] = skinningProgram.getUniformLocation("u_shiny"); + u_cameraPos [0] = skinningProgram.getUniformLocation("u_cameraPos"); + u_materialDiffuse [0] = skinningProgram.getUniformLocation("u_materialDiffuse"); + u_normalMatrix [0] = skinningProgram.getUniformLocation("u_normalMatrix"); + + u_projTrans [1] = baseProgram.getUniformLocation("u_projTrans"); + u_geomTrans [1] = baseProgram.getUniformLocation("u_geomTrans"); + u_lightPos [1] = baseProgram.getUniformLocation("u_lightPos"); + u_lightDiffuse [1] = baseProgram.getUniformLocation("u_lightDiffuse"); + u_specular [1] = baseProgram.getUniformLocation("u_specular"); + u_ambient [1] = baseProgram.getUniformLocation("u_ambient"); + u_shiny [1] = baseProgram.getUniformLocation("u_shiny"); + u_cameraPos [1] = baseProgram.getUniformLocation("u_cameraPos"); + u_materialDiffuse [1] = baseProgram.getUniformLocation("u_materialDiffuse"); + u_normalMatrix [1] = baseProgram.getUniformLocation("u_normalMatrix"); + + for(int i = 0; i < MAX_NUM_BONES; i++){ + u_bones[i] = skinningProgram.getUniformLocation("u_bone" + Integer.toString(i)); + } } @Override public void dispose(){ - if(program != null) - program.dispose(); + if(skinningProgram != null) skinningProgram.dispose(); + if(baseProgram != null) baseProgram.dispose(); } @Override @@ -118,11 +160,6 @@ public class SingleLightPerPixelShader implements Shader{ this.camera = camera; this.context = context; - program.begin(); - - // Set camera dependant uniforms. - program.setUniformMatrix(u_projTrans, this.camera.combined); - program.setUniformf(u_cameraPos, this.camera.position); // Set render context. this.context.setDepthTest(GL20.GL_LEQUAL); @@ -131,6 +168,10 @@ public class SingleLightPerPixelShader implements Shader{ @Override public void render(Renderable renderable){ + ShaderProgram program; + int index; + boolean bonesEnabled; + // Get material colors. Vector3 lightPosition = renderable.environment.directionalLights.get(0).direction; Color diffuseLightColor = renderable.environment.directionalLights.get(0).color; @@ -139,24 +180,49 @@ public class SingleLightPerPixelShader implements Shader{ Color ambientColor = ((ColorAttribute)renderable.environment.get(ColorAttribute.AmbientLight)).color; float shininess = ((FloatAttribute)renderable.material.get(FloatAttribute.Shininess)).value; - // Set model dependant uniforms. - program.setUniformMatrix(u_geomTrans, renderable.worldTransform); - program.setUniformMatrix(u_normalMatrix, normalMatrix.idt().mul(renderable.worldTransform).inv().tra()); - program.setUniformf(u_lightPos, lightPosition); - program.setUniformf(u_lightDiffuse, diffuseLightColor); - program.setUniformf(u_materialDiffuse, diffuseColor); - program.setUniformf(u_specular, specularColor); - program.setUniformf(u_ambient, ambientColor); - program.setUniformf(u_shiny, shininess); + if(renderable.mesh.getVertexAttribute(VertexAttributes.Usage.BoneWeight) != null){ + program = skinningProgram; + index = 0; + bonesEnabled = true; + }else{ + program = baseProgram; + index = 1; + bonesEnabled = false; + } + + program.begin(); + + // Set camera dependant uniforms. + program.setUniformMatrix(u_projTrans[index], this.camera.combined); + program.setUniformf(u_cameraPos[index], this.camera.position); + + // Set model dependant uniforms. + program.setUniformMatrix(u_geomTrans[index], renderable.worldTransform); + program.setUniformMatrix(u_normalMatrix[index], normalMatrix.idt().mul(renderable.worldTransform).inv().tra()); + program.setUniformf(u_lightPos[index], lightPosition); + program.setUniformf(u_lightDiffuse[index], diffuseLightColor); + program.setUniformf(u_materialDiffuse[index], diffuseColor); + program.setUniformf(u_specular[index], specularColor); + program.setUniformf(u_ambient[index], ambientColor); + program.setUniformf(u_shiny[index], shininess); + + // Set the bones uniforms. + if(bonesEnabled){ + for(int i = 0; i < MAX_NUM_BONES; i++){ + if(renderable.bones != null && i < renderable.bones.length && renderable.bones[i] != null) + skinningProgram.setUniformMatrix(u_bones[i], renderable.bones[i]); + else + skinningProgram.setUniformMatrix(u_bones[i], IDENTITY); + } + } - // Render. renderable.mesh.render(program, renderable.primitiveType, renderable.meshPartOffset, renderable.meshPartSize); + + program.end(); } @Override public void end(){ - program.end(); - this.camera = null; this.context = null; } diff --git a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java index ad4c163..1c55957 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java +++ b/src/ve/ucv/ciens/ccg/nxtar/states/InGameState.java @@ -27,6 +27,7 @@ import ve.ucv.ciens.ccg.nxtar.graphics.RenderParameters; import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData; import ve.ucv.ciens.ccg.nxtar.network.monitors.MotorEventQueue; import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor; +import ve.ucv.ciens.ccg.nxtar.systems.AnimationSystem; import ve.ucv.ciens.ccg.nxtar.systems.MarkerPositioningSystem; import ve.ucv.ciens.ccg.nxtar.systems.MarkerRenderingSystem; import ve.ucv.ciens.ccg.nxtar.systems.ObjectRenderingSystem; @@ -191,14 +192,19 @@ public class InGameState extends BaseState{ // Set up the game world. gameWorld = new World(); + entityCreator = new MarkerTestEntityCreator(); entityCreator.setWorld(gameWorld); entityCreator.createAllEntities(); + gameWorld.setSystem(new MarkerPositioningSystem()); + gameWorld.setSystem(new AnimationSystem()); + markerRenderingSystem = new MarkerRenderingSystem(modelBatch); objectRenderingSystem = new ObjectRenderingSystem(modelBatch); gameWorld.setSystem(markerRenderingSystem, true); gameWorld.setSystem(objectRenderingSystem, true); + gameWorld.initialize(); } diff --git a/src/ve/ucv/ciens/ccg/nxtar/systems/AnimationSystem.java b/src/ve/ucv/ciens/ccg/nxtar/systems/AnimationSystem.java index 445d0e6..9a08e5d 100644 --- a/src/ve/ucv/ciens/ccg/nxtar/systems/AnimationSystem.java +++ b/src/ve/ucv/ciens/ccg/nxtar/systems/AnimationSystem.java @@ -15,23 +15,32 @@ */ package ve.ucv.ciens.ccg.nxtar.systems; -import ve.ucv.ciens.ccg.nxtar.components.ModelComponent; +import ve.ucv.ciens.ccg.nxtar.components.AnimationComponent; import com.artemis.Aspect; +import com.artemis.ComponentMapper; import com.artemis.Entity; +import com.artemis.annotations.Mapper; import com.artemis.systems.EntityProcessingSystem; +import com.badlogic.gdx.Gdx; public class AnimationSystem extends EntityProcessingSystem { + @Mapper ComponentMapper animationMapper; @SuppressWarnings("unchecked") public AnimationSystem(){ - super(Aspect.getAspectForAll(ModelComponent.class)); + super(Aspect.getAspectForAll(AnimationComponent.class)); } @Override protected void process(Entity e) { - // TODO Auto-generated method stub + AnimationComponent animation = animationMapper.get(e); + if(animation.current != animation.next){ + animation.controller.setAnimation(animation.animationsIds.get(animation.next)); + } + + animation.controller.update(Gdx.graphics.getDeltaTime()); } }