Thank you for theses information
I tried the whole day to make it work, but unsuccessfully :bang:
There is some things I still do not understand:
atlasTexture = atlas.getRegions().first().getTexture();
Is used (NormalMapTest.java) as the diffuse texture :nerd:
How is the atlas handled with the pixel Shader texCoords ?
I'm currently stuck there, as far as I understand, Mesh.ts .bind() method seems to handle the shader's attributes, but i'm stuck with the error : "Error: Couldn't find location for attribute a_texCoords"
Here is my code:
var transitionsDemo = function(canvas, loadingComplete, bgColor) {
var OUTLINE_COLOR = new spine.Color(0, 0.8, 0, 1);
var canvas, gl, renderer, input, assetManager;
var skeleton, skeletonNoMix, state, stateNoMix, bounds;
var timeSlider, timeSliderLabel;
var timeKeeper;
var DEMO_NAME = "TransitionsDemo";
if (!bgColor) bgColor = new spine.Color(235 / 255, 239 / 255, 244 / 255, 1);
var ambiantColor = [1, 1, 1];
var lightColor = [1, 0, 1];
var lightPos = [100, 0, 0];
var nm_texture = null;
var df_texture = null;
var ShaderProgram = null;
var uniformSetters;
var attribSetters;
function init () {
timeSlider = $("#transitions-timeslider").data("slider");
timeSlider.set(0.5);
timeSliderLabel = $("#transitions-timeslider-label")[0];
canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight;
gl = canvas.ctx.gl;
renderer = new spine.webgl.SceneRenderer(canvas, gl);
shaderProgram = createShader();
renderer.batcherShader = shaderProgram;
assetManager = spineDemos.assetManager;
var textureLoader = function(img) { return new spine.webgl.GLTexture(gl, img); };
assetManager.loadTexture(DEMO_NAME, textureLoader, "atlas1.png");
assetManager.loadTexture(DEMO_NAME, textureLoader, "atlas1_NORM.png");
assetManager.loadText(DEMO_NAME, "atlas1.atlas");
assetManager.loadJson(DEMO_NAME, "demos.json");
input = new spine.webgl.Input(canvas);
timeKeeper = new spine.TimeKeeper();
}
function loadingComplete () {
skeleton = loadSkeleton("spineboy");
skeletonNoMix = new spine.Skeleton(skeleton.data);
state = createState(0.25);
state.multipleMixing = true;
setAnimations(state, 0, 0);
stateNoMix = createState(0);
setAnimations(stateNoMix, -0.25, 0);
state.apply(skeleton);
skeleton.updateWorldTransform();
bounds = { offset: new spine.Vector2(), size: new spine.Vector2() };
skeleton.getBounds(bounds.offset, bounds.size, []);
setupInput();
$("#transitions-overlay").removeClass("overlay-hide");
$("#transitions-overlay").addClass("overlay");
}
function setupInput() {
$("#transitions-die").click(function () {
var entry = state.setAnimation(0, "death", false);
setAnimations(state, 0, true, 0);
entry.next.mixDuration = 0.1;
var entry = stateNoMix.setAnimation(0, "death", false);
setAnimations(stateNoMix, -0.25, -0.25 + -0.1);
});
}
function createState (mix) {
var stateData = new spine.AnimationStateData(skeleton.data);
stateData.defaultMix = mix;
var state = new spine.AnimationState(stateData);
return state;
}
function setAnimations (state, delay, first) {
state.addAnimation(0, "idle", true, first);
state.addAnimation(0, "walk", true, 0.6);
state.addAnimation(0, "jump", false, 1);
state.addAnimation(0, "run", true, delay);
state.addAnimation(0, "walk", true, 1.2);
state.addAnimation(0, "run", true, 0.5);
state.addAnimation(0, "jump", false, 1);
state.addAnimation(0, "run", true, delay);
state.addAnimation(0, "jump", true, 0.5);
state.addAnimation(0, "walk", true, delay).listener = {
start: function (trackIndex) {
setAnimations(state, delay, 0.6);
}
};
}
function loadSkeleton(name) {
var atlas = new spine.TextureAtlas(assetManager.get(DEMO_NAME, "atlas1.atlas"), function(path) {
return assetManager.get(DEMO_NAME, path);
});
df_texture = assetManager.get(DEMO_NAME, "atlas1.png");
nm_texture = assetManager.get(DEMO_NAME, "atlas1_NORM.png");
var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
var skeletonJson = new spine.SkeletonJson(atlasLoader);
var skeletonData = skeletonJson.readSkeletonData(assetManager.get(DEMO_NAME, "demos.json")[name]);
var skeleton = new spine.Skeleton(skeletonData);
skeleton.setSkinByName("default");
return skeleton;
}
function render () {
timeKeeper.update();
var delta = timeKeeper.delta * timeSlider.get();
if (timeSliderLabel) {
var oldValue = timeSliderLabel.textContent;
var newValue = Math.round(timeSlider.get() * 100) + "%";
if (oldValue !== newValue) timeSliderLabel.textContent = newValue;
}
var offset = bounds.offset;
var size = bounds.size;
renderer.camera.position.x = offset.x + size.x - 50;
renderer.camera.position.y = offset.y + size.y / 2 - 40;
renderer.camera.viewportWidth = size.x * 2;
renderer.camera.viewportHeight = size.y * 2;
renderer.resize(spine.webgl.ResizeMode.Fit);
gl.clearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a);
gl.clear(gl.COLOR_BUFFER_BIT);
renderer.begin();
shaderProgram.bind();
shaderProgram.setUniformi("u_texture", df_texture.texture);
shaderProgram.setUniformi("u_normals", nm_texture.texture);
shaderProgram.setUniform2f("resolution", size.x*2, size.y*2);
shaderProgram.setUniform3f("ambientColor", ambiantColor[0], ambiantColor[1], ambiantColor[2]);
shaderProgram.setUniform3f("light", lightPos[0], lightPos[1], lightPos[2]);
shaderProgram.setUniform3f("lightColor", lightColor[0], lightColor[1], lightColor[2]);
state.update(delta);
state.apply(skeleton);
skeleton.updateWorldTransform();
skeleton.x = -200;
skeleton.y = -100;
renderer.drawSkeleton(skeleton, true);
renderer.end();
}
function createShader () {
var vert = "attribute vec4 a_position;\n" //
+ "attribute vec4 a_color;\n" //
+ "attribute vec2 a_texCoord0;\n" //
+ "uniform mat4 u_proj;\n" //
+ "uniform mat4 u_trans;\n" //
+ "uniform mat4 u_projTrans;\n" //
+ "varying vec4 v_color;\n" //
+ "varying vec2 v_texCoords;\n" //
+ "\n" //
+ "void main()\n" //
+ "{\n" //
+ " v_color = a_color;\n" //
+ " v_texCoords = a_texCoord0;\n" //
+ " gl_Position = u_projTrans * a_position;\n" //
+ "}\n" //
+ "";
var frag = "#ifdef GL_ES\n" //
+ "precision mediump float;\n" //
+ "#endif\n" //
+ "varying vec4 v_color;\n" //
+ "varying vec2 v_texCoords;\n" //
+ "uniform sampler2D u_texture;\n" //
+ "uniform sampler2D u_normals;\n" //
+ "uniform vec3 light;\n" //
+ "uniform vec3 ambientColor;\n" //
+ "float ambientIntensity = 1.0; \n" //
+ "uniform vec2 resolution;\n" //
+ "uniform vec3 lightColor;\n" //
+ "bool useNormals = true;\n" //
+ "bool useShadow = false;\n" //
+ "vec3 attenuation = vec3(0.5, 0.5, 0.5);\n" //
+ "float strength = 1.0;\n" //
+ "bool yInvert = false;\n" //
+ "\n" //
+ "void main() {\n" //
+ " // sample color & normals from our textures\n" //
+ " vec4 color = texture2D(u_texture, v_texCoords.st);\n" //
+ " vec3 nColor = texture2D(u_normals, v_texCoords.st).rgb;\n" //
+ "\n" //
+ " // some bump map programs will need the Y value flipped..\n" //
+ " nColor.g = yInvert ? 1.0 - nColor.g : nColor.g;\n" //
+ "\n" //
+ " // this is for debugging purposes, allowing us to lower the intensity of our bump map\n" //
+ " vec3 nBase = vec3(0.5, 0.5, 1.0);\n" //
+ " nColor = mix(nBase, nColor, strength);\n" //
+ "\n" //
+ " // normals need to be converted to [-1.0, 1.0] range and normalized\n" //
+ " vec3 normal = normalize(nColor * 2.0 - 1.0);\n" //
+ "\n" //
+ " // here we do a simple distance calculation\n" //
+ " vec3 deltaPos = vec3( (light.xy - gl_FragCoord.xy) / resolution.xy, light.z );\n" //
+ "\n" //
+ " vec3 lightDir = normalize(deltaPos);\n" //
+ " float lambert = useNormals ? clamp(dot(normal, lightDir), 0.0, 1.0) : 1.0;\n" //
+ " \n" //
+ " // now let's get a nice little falloff\n" //
+ " float d = sqrt(dot(deltaPos, deltaPos)); \n" //
+ " float att = useShadow ? 1.0 / ( attenuation.x + (attenuation.y*d) + (attenuation.z[i]d[/i]d) ) : 1.0;\n" //
+ " \n" //
+ " vec3 result = (ambientColor * ambientIntensity) + (lightColor.rgb * lambert) * att;\n" //
+ " result *= color.rgb;\n" //
+ " \n" //
+ " gl_FragColor = v_color * vec4(result, color.a);\n" //
+ "}";
// CREATING COMMON WAY
/*
var program = gl.createProgram();
// Lier les shaders préexistants
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vert);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, frag);
gl.compileShader(fragShader);
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);
gl.linkProgram(program);
if ( !gl.getProgramParameter( program, gl.LINK_STATUS) ) {
var info = gl.getProgramInfoLog(program);
throw 'Impossible de compiler le program WebGL.\n\n' + info;
}
uniformSetters = webglUtils.createUniformSetters(gl, program);
attribSetters = webglUtils.createAttributeSetters(gl, program);
*/
var program = new spine.webgl.Shader(gl, vert, frag);
return program;
}
transitionsDemo.loadingComplete = loadingComplete;
transitionsDemo.render = render;
transitionsDemo.DEMO_NAME = DEMO_NAME;
init();
};
And here is the result with the firefox canvas tool analysis :
I would be glad if you could take the time to take a look at this code