@Override public void simpleUpdate(float tpf) { Vector3f camDir = cam.getDirection().clone().multLocal(0.6f); Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f); walkDirection.set(0, 0, 0); if (left) walkDirection.addLocal(camLeft); if (right) walkDirection.addLocal(camLeft.negate()); if (up) walkDirection.addLocal(camDir); if (down) walkDirection.addLocal(camDir.negate()); player.setWalkDirection(walkDirection); cam.setLocation(player.getPhysicsLocation()); }
@Override protected void initialize(Application app) { ed = getState(EntityDataState.class).getEntityData(); entities = ed.getEntities(Position.class, ModelType.class); // Calculate how big min/max needs to be to incorporate // the full view + margin at z = 0 Camera cam = app.getCamera(); float z = cam.getViewToProjectionZ(cam.getLocation().z); Vector3f worldMin = cam.getWorldCoordinates(new Vector2f(0, 0), z); Vector3f worldMax = cam.getWorldCoordinates(new Vector2f(cam.getWidth(), cam.getHeight()), z); min = worldMin.addLocal(-margin, -margin, 0); max = worldMax.addLocal(margin, margin, 0); }
private void refreshFont() { Camera cam = IsoCamera.getInstance().getCam(); Vector3f start = from.getPlanet().getPosition(); Vector3f end = to.getPlanet().getPosition(); float width = label.getLineWidth(); Random r = new Random(); // float height = r.nextFloat() * end.subtract(start).z; Vector3f position = new Vector3f(width / 2, .15f, 0); Vector3f fontPos = start.add(end.subtract(start).mult(0.4f + 0.75f * r.nextFloat())); position.addLocal(fontPos); Vector3f up = cam.getUp().clone(); Vector3f dir = cam.getDirection().clone().negateLocal().normalizeLocal(); Vector3f left = cam.getLeft().clone().normalizeLocal().negateLocal(); Quaternion look = new Quaternion(); look.fromAxes(left, up, dir); label.setLocalTransform(new Transform(position, look)); // Vector3f camPos = IsoCamera.getInstance().getCam().getLocation(); // Vector3f fontPos = to.getPlanet().getPosition(). // subtract(from.getPlanet().getPosition()); // Vector3f up = IsoCamera.getInstance().getCam().getUp().clone(); // Vector3f dir = camPos.subtract(fontPos); //// Vector3f dir = Vector3f.UNIT_Y.clone().subtract(fontPos); // // Vector3f left = IsoCamera.getInstance().getCam().getLeft().clone(); // dir.normalizeLocal(); // left.negateLocal(); // left.normalizeLocal(); // up.normalizeLocal(); //// dir.negateLocal(); // // Quaternion look = new Quaternion(); // look.fromAxes(left, up, dir); // // Vector3f newPos = to.getPlanet().getPosition(). // subtract(from.getPlanet().getPosition()); // // newPos.x -= label.getLineWidth() / 2; // // Transform t = new Transform(newPos, look); // // label.setLocalTransform(t); }
@Override public void simpleUpdate(float lastTimePerFrame) { float playerMoveSpeed = ((cubesSettings.getBlockSize() * 6.5f) * lastTimePerFrame); Vector3f camDir = cam.getDirection().mult(playerMoveSpeed); Vector3f camLeft = cam.getLeft().mult(playerMoveSpeed); walkDirection.set(0, 0, 0); if (arrowKeys[0]) { walkDirection.addLocal(camDir); } if (arrowKeys[1]) { walkDirection.addLocal(camLeft.negate()); } if (arrowKeys[2]) { walkDirection.addLocal(camDir.negate()); } if (arrowKeys[3]) { walkDirection.addLocal(camLeft); } walkDirection.setY(0); walkDirection.normalize(); walkDirection.multLocal(lastTimePerFrame * 10); playerControl.setWalkDirection(walkDirection); cam.setLocation(playerControl.getPhysicsLocation()); }
public void postQueue(RenderQueue rq) { GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); if (occluders.size() == 0) { noOccluders = true; return; } else { noOccluders = false; } GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive); // update frustum points based on current camera Camera viewCam = viewPort.getCamera(); ShadowUtil.updateFrustumPoints( viewCam, viewCam.getFrustumNear(), viewCam.getFrustumFar(), 1.0f, points); Vector3f frustaCenter = new Vector3f(); for (Vector3f point : points) { frustaCenter.addLocal(point); } frustaCenter.multLocal(1f / 8f); // update light direction shadowCam.setProjectionMatrix(null); shadowCam.setParallelProjection(true); // shadowCam.setFrustumPerspective(45, 1, 1, 20); shadowCam.lookAtDirection(direction, Vector3f.UNIT_Y); shadowCam.update(); shadowCam.setLocation(frustaCenter); shadowCam.update(); shadowCam.updateViewProjection(); // render shadow casters to shadow map ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points); Renderer r = renderManager.getRenderer(); renderManager.setCamera(shadowCam, false); renderManager.setForcedMaterial(preshadowMat); r.setFrameBuffer(shadowFB); r.clearBuffers(false, true, false); viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, true); r.setFrameBuffer(viewPort.getOutputFrameBuffer()); renderManager.setForcedMaterial(null); renderManager.setCamera(viewCam, false); }
public Vector3f onMove(Vector3f moveVec) { if (moveVec.equals(Vector3f.ZERO)) { return currentPos3d; } Vector3f newPos2d = new Vector3f(currentPos3d); newPos2d.addLocal(moveVec); newPos2d.setY(0); Vector3f currentPos2d = new Vector3f(currentPos3d); currentPos2d.setY(0); // Cell nextCell = navMesh.resolveMotionOnMesh(currentPos2d, currentCell, newPos2d, newPos2d); // currentCell = nextCell; newPos2d.setY(currentPos3d.getY()); return newPos2d; }
public static Mesh genNormalLines(Mesh mesh, float scale) { FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData(); ColorRGBA originColor = ColorRGBA.White; ColorRGBA normalColor = ColorRGBA.Blue; Mesh lineMesh = new Mesh(); lineMesh.setMode(Mesh.Mode.Lines); Vector3f origin = new Vector3f(); Vector3f point = new Vector3f(); FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.limit() * 2); FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.limit() / 3 * 4 * 2); for (int i = 0; i < vertexBuffer.limit() / 3; i++) { populateFromBuffer(origin, vertexBuffer, i); populateFromBuffer(point, normalBuffer, i); int index = i * 2; setInBuffer(origin, lineVertex, index); setInBuffer(originColor, lineColor, index); point.multLocal(scale); point.addLocal(origin); setInBuffer(point, lineVertex, index + 1); setInBuffer(normalColor, lineColor, index + 1); } lineMesh.setBuffer(Type.Position, 3, lineVertex); lineMesh.setBuffer(Type.Color, 4, lineColor); lineMesh.setStatic(); // lineMesh.setInterleaved(); return lineMesh; }
private static Transform convertPositions(FloatBuffer input, BoundingBox bbox, Buffer output) { if (output.capacity() < input.capacity()) throw new RuntimeException("Output must be at least as large as input!"); Vector3f offset = bbox.getCenter().negate(); Vector3f size = new Vector3f(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent()); size.multLocal(2); ShortBuffer sb = null; ByteBuffer bb = null; float dataTypeSize; float dataTypeOffset; if (output instanceof ShortBuffer) { sb = (ShortBuffer) output; dataTypeOffset = shortOff; dataTypeSize = shortSize; } else { bb = (ByteBuffer) output; dataTypeOffset = byteOff; dataTypeSize = byteSize; } Vector3f scale = new Vector3f(); scale.set(dataTypeSize, dataTypeSize, dataTypeSize).divideLocal(size); Vector3f invScale = new Vector3f(); invScale.set(size).divideLocal(dataTypeSize); offset.multLocal(scale); offset.addLocal(dataTypeOffset, dataTypeOffset, dataTypeOffset); // offset = (-modelOffset * shortSize)/modelSize + shortOff // scale = shortSize / modelSize input.clear(); output.clear(); Vector3f temp = new Vector3f(); int vertexCount = input.capacity() / 3; for (int i = 0; i < vertexCount; i++) { BufferUtils.populateFromBuffer(temp, input, i); // offset and scale vector into -32768 ... 32767 // or into -128 ... 127 if using bytes temp.multLocal(scale); temp.addLocal(offset); // quantize and store if (sb != null) { short v1 = (short) temp.getX(); short v2 = (short) temp.getY(); short v3 = (short) temp.getZ(); sb.put(v1).put(v2).put(v3); } else { byte v1 = (byte) temp.getX(); byte v2 = (byte) temp.getY(); byte v3 = (byte) temp.getZ(); bb.put(v1).put(v2).put(v3); } } Transform transform = new Transform(); transform.setTranslation(offset.negate().multLocal(invScale)); transform.setScale(invScale); return transform; }
@Override public void updateParticleData(ParticleData[] particles, Camera cam, Matrix3f inverseRotation) { for (int i = 0; i < particles.length; i++) { ParticleData p = particles[i]; int offset = templateVerts.capacity() * i; int colorOffset = templateColors.capacity() * i; if (p.life == 0 || !p.active) { for (int x = 0; x < templateVerts.capacity(); x += 3) { finVerts.put(offset + x, 0); finVerts.put(offset + x + 1, 0); finVerts.put(offset + x + 2, 0); } continue; } for (int x = 0; x < templateVerts.capacity(); x += 3) { switch (emitter.getBillboardMode()) { case Velocity: if (p.velocity.x != Vector3f.UNIT_Y.x && p.velocity.y != Vector3f.UNIT_Y.y && p.velocity.z != Vector3f.UNIT_Y.z) up.set(p.velocity).crossLocal(Vector3f.UNIT_Y).normalizeLocal(); else up.set(p.velocity).crossLocal(lock).normalizeLocal(); left.set(p.velocity).crossLocal(up).normalizeLocal(); dir.set(p.velocity); break; case Velocity_Z_Up: if (p.velocity.x != Vector3f.UNIT_Y.x && p.velocity.y != Vector3f.UNIT_Y.y && p.velocity.z != Vector3f.UNIT_Y.z) up.set(p.velocity).crossLocal(Vector3f.UNIT_Y).normalizeLocal(); else up.set(p.velocity).crossLocal(lock).normalizeLocal(); left.set(p.velocity).crossLocal(up).normalizeLocal(); dir.set(p.velocity); rotStore = tempQ.fromAngleAxis(-90 * FastMath.DEG_TO_RAD, left); left = rotStore.mult(left); up = rotStore.mult(up); break; case Velocity_Z_Up_Y_Left: up.set(p.velocity).crossLocal(Vector3f.UNIT_Y).normalizeLocal(); left.set(p.velocity).crossLocal(up).normalizeLocal(); dir.set(p.velocity); tempV3.set(left).crossLocal(up).normalizeLocal(); rotStore = tempQ.fromAngleAxis(90 * FastMath.DEG_TO_RAD, p.velocity); left = rotStore.mult(left); up = rotStore.mult(up); rotStore = tempQ.fromAngleAxis(-90 * FastMath.DEG_TO_RAD, left); up = rotStore.mult(up); break; case Normal: emitter.getShape().setNext(p.triangleIndex); tempV3.set(emitter.getShape().getNormal()); if (tempV3 == Vector3f.UNIT_Y) tempV3.set(p.velocity); up.set(tempV3).crossLocal(Vector3f.UNIT_Y).normalizeLocal(); left.set(tempV3).crossLocal(up).normalizeLocal(); dir.set(tempV3); break; case Normal_Y_Up: emitter.getShape().setNext(p.triangleIndex); tempV3.set(p.velocity); if (tempV3 == Vector3f.UNIT_Y) tempV3.set(Vector3f.UNIT_X); up.set(Vector3f.UNIT_Y); left.set(tempV3).crossLocal(up).normalizeLocal(); dir.set(tempV3); break; case Camera: up.set(cam.getUp()); left.set(cam.getLeft()); dir.set(cam.getDirection()); break; case UNIT_X: up.set(Vector3f.UNIT_Y); left.set(Vector3f.UNIT_Z); dir.set(Vector3f.UNIT_X); break; case UNIT_Y: up.set(Vector3f.UNIT_Z); left.set(Vector3f.UNIT_X); dir.set(Vector3f.UNIT_Y); break; case UNIT_Z: up.set(Vector3f.UNIT_X); left.set(Vector3f.UNIT_Y); dir.set(Vector3f.UNIT_Z); break; } tempV3.set(templateVerts.get(x), templateVerts.get(x + 1), templateVerts.get(x + 2)); tempV3 = rotStore.mult(tempV3); tempV3.multLocal(p.size); rotStore.fromAngles(p.angles.x, p.angles.y, p.angles.z); tempV3 = rotStore.mult(tempV3); tempV3.addLocal(p.position); if (!emitter.getParticlesFollowEmitter()) { tempV3.subtractLocal( emitter .getEmitterNode() .getWorldTranslation() .subtract(p.initialPosition)); // .divide(8f)); } finVerts.put(offset + x, tempV3.getX()); finVerts.put(offset + x + 1, tempV3.getY()); finVerts.put(offset + x + 2, tempV3.getZ()); } if (p.emitter.getApplyLightingTransform()) { for (int v = 0; v < templateNormals.capacity(); v += 3) { tempV3.set( templateNormals.get(v), templateNormals.get(v + 1), templateNormals.get(v + 2)); rotStore.fromAngles(p.angles.x, p.angles.y, p.angles.z); mat3.set(rotStore.toRotationMatrix()); float vx = tempV3.x, vy = tempV3.y, vz = tempV3.z; tempV3.x = mat3.get(0, 0) * vx + mat3.get(0, 1) * vy + mat3.get(0, 2) * vz; tempV3.y = mat3.get(1, 0) * vx + mat3.get(1, 1) * vy + mat3.get(1, 2) * vz; tempV3.z = mat3.get(2, 0) * vx + mat3.get(2, 1) * vy + mat3.get(2, 2) * vz; finNormals.put(offset + v, tempV3.getX()); finNormals.put(offset + v + 1, tempV3.getY()); finNormals.put(offset + v + 2, tempV3.getZ()); } } for (int v = 0; v < templateColors.capacity(); v += 4) { finColors .put(colorOffset + v, p.color.r) .put(colorOffset + v + 1, p.color.g) .put(colorOffset + v + 2, p.color.b) .put(colorOffset + v + 3, p.color.a * p.alpha); } } this.setBuffer(VertexBuffer.Type.Position, 3, finVerts); if (particles[0].emitter.getApplyLightingTransform()) this.setBuffer(VertexBuffer.Type.Normal, 3, finNormals); this.setBuffer(VertexBuffer.Type.Color, 4, finColors); updateBound(); }
public Hallway(Vector3f start, float xi, float zi) { float x = start.getX() + xi; float z = start.getZ() + zi; float rng, dist; int len = 0; int spread = 0; int lenMax = FastMath.nextRandomInt(HALL_LENGTH_MIN, HALL_LENGTH_MAX); boolean b = false; // Make sure both xi and zi have an absolute value of 1: xi = A.sign(xi); zi = A.sign(zi); // Assign the first 2 corners: corners[0] = new Vector3f( (zi * (HALL_WIDTH - 1)) + x, start.getY(), (xi * (HALL_WIDTH - 1)) + z); // Bottom Left corners[1] = new Vector3f( (-zi * (HALL_WIDTH - 1)) + x, start.getY(), (-xi * (HALL_WIDTH - 1)) + z); // Bottom Right Vector3f left = corners[0].clone(); Vector3f right = corners[1].clone(); ArrayList<HallData> newHalls = new ArrayList(1); while (len <= lenMax) { if (world.get(left) != null && world.get(left).contains("h")) { b = true; } if (world.get(right) != null && world.get(right).contains("h")) { b = true; } // Check each of the spaces in this step for hallway: if (b) { right.addLocal(-xi, 0, -zi); left.addLocal(-xi, 0, -zi); break; } world.put(left.clone(), "h"); world.put(right.add(zi, 0, xi), "h"); world.put(right.clone(), "h"); // Check distance & random to see if more hallways should be created: dist = left.distance(Vector3f.ZERO); rng = FastMath.nextRandomFloat(); if (dist < HALL_MAX_RADIUS && spread > HALL_SPREAD && len < lenMax) { if (rng < 0.13f) { newHalls.add(new HallData(left.clone(), zi, xi)); spread = 0; } else if (rng < 0.26f) { newHalls.add(new HallData(right.clone(), -zi, -xi)); spread = 0; } else if (rng < 0.33f) { newHalls.add(new HallData(left.clone(), zi, xi)); newHalls.add(new HallData(right.clone(), -zi, -xi)); spread = 0; } } x += xi; z += zi; spread++; len++; left.addLocal(xi, 0, zi); right.addLocal(xi, 0, zi); } corners[2] = right.clone(); // Top Right corners[3] = left.clone(); // Top Left // Generate hallways: int j = 0; while (j < newHalls.size()) { hallways.add(new Hallway(newHalls.get(j).start, newHalls.get(j).xi, newHalls.get(j).zi)); j++; } // Return if there's no hallway to generate (0 in size): float xs = FastMath.abs(corners[1].getX() - corners[3].getX()) + 1; float zs = FastMath.abs(corners[1].getZ() - corners[3].getZ()) + 1; if (Math.min(FastMath.abs(xs), FastMath.abs(zs)) < 1) { return; } // Generate the front wall: walls.add(new Wall(left.add(xi, 0, zi), -zi, -xi, HALL_WIDTH * 2 - 1)); walls.add(new Wall(left.add(zi, 0, xi), -xi, -zi, len + 1)); walls.add(new Wall(right.add(-zi, 0, -xi), -xi, -zi, len + 1)); // Generate the actual floor: float xloc = (corners[3].getX() + corners[1].getX()) * 0.5f; float zloc = (corners[3].getZ() + corners[1].getZ()) * 0.5f; NPCManager.addNew("grunt", new Vector3f(xloc, start.getY(), zloc).mult(ZS).add(0, 5, 0)); center = new Vector3f(xloc, start.getY() - 0.5f, zloc); floor = geoFloor(center, xs, zs, T.getMaterialPath("BC_Tex"), new Vector2f(zs, xs), true); map.add(floor); }
/** * Updates the points array to contain the frustum corners of the given camera. The nearOverride * and farOverride variables can be used to override the camera's near/far values with own values. * * <p>TODO: Reduce creation of new vectors * * @param viewCam * @param nearOverride * @param farOverride */ public static void updateFrustumPoints( Camera viewCam, float nearOverride, float farOverride, float scale, Vector3f[] points) { Vector3f pos = viewCam.getLocation(); Vector3f dir = viewCam.getDirection(); Vector3f up = viewCam.getUp(); float depthHeightRatio = viewCam.getFrustumTop() / viewCam.getFrustumNear(); float near = nearOverride; float far = farOverride; float ftop = viewCam.getFrustumTop(); float fright = viewCam.getFrustumRight(); float ratio = fright / ftop; float near_height; float near_width; float far_height; float far_width; if (viewCam.isParallelProjection()) { near_height = ftop; near_width = near_height * ratio; far_height = ftop; far_width = far_height * ratio; } else { near_height = depthHeightRatio * near; near_width = near_height * ratio; far_height = depthHeightRatio * far; far_width = far_height * ratio; } Vector3f right = dir.cross(up).normalizeLocal(); Vector3f temp = new Vector3f(); temp.set(dir).multLocal(far).addLocal(pos); Vector3f farCenter = temp.clone(); temp.set(dir).multLocal(near).addLocal(pos); Vector3f nearCenter = temp.clone(); Vector3f nearUp = temp.set(up).multLocal(near_height).clone(); Vector3f farUp = temp.set(up).multLocal(far_height).clone(); Vector3f nearRight = temp.set(right).multLocal(near_width).clone(); Vector3f farRight = temp.set(right).multLocal(far_width).clone(); points[0].set(nearCenter).subtractLocal(nearUp).subtractLocal(nearRight); points[1].set(nearCenter).addLocal(nearUp).subtractLocal(nearRight); points[2].set(nearCenter).addLocal(nearUp).addLocal(nearRight); points[3].set(nearCenter).subtractLocal(nearUp).addLocal(nearRight); points[4].set(farCenter).subtractLocal(farUp).subtractLocal(farRight); points[5].set(farCenter).addLocal(farUp).subtractLocal(farRight); points[6].set(farCenter).addLocal(farUp).addLocal(farRight); points[7].set(farCenter).subtractLocal(farUp).addLocal(farRight); if (scale != 1.0f) { // find center of frustum Vector3f center = new Vector3f(); for (int i = 0; i < 8; i++) { center.addLocal(points[i]); } center.divideLocal(8f); Vector3f cDir = new Vector3f(); for (int i = 0; i < 8; i++) { cDir.set(points[i]).subtractLocal(center); cDir.multLocal(scale - 1.0f); points[i].addLocal(cDir); } } }
@Override public void simpleUpdate(float tpf) { for (Planet planet : planets) { planet.getGeom().rotate(0, 0, planet.getRotationSpeed() * tpf); planet.getPivot().rotate(0, planet.getTranslationSpeed() * tpf, 0); } for (Spatial spatial : explosions.getChildren()) { ParticleEmitter explosion = (ParticleEmitter) spatial; if (explosion.getNumVisibleParticles() < 1) { explosion.removeFromParent(); } } Vector3f rotation = new Vector3f(0, 0, 0); if (left) { rotation.addLocal(0, 1, 0); } if (right) { rotation.addLocal(0, -1, 0); } if (up) { rotation.addLocal(1, 0, 0); } if (down) { rotation.addLocal(-1, 0, 0); } if (leftSide) { rotation.addLocal(0, 0, 1); } if (rightSide) { rotation.addLocal(0, 0, -1); } Vector3f transformed = new Vector3f(0, 0, 0); spaceship.getLocalRotation().mult(rotation, transformed); spaceship.getControl().setAngularVelocity(transformed); Vector3f movement = new Vector3f(0, 0, 0); if (moving) { spaceship.getWorldRotation().mult(new Vector3f(0, 0, -6), movement); } spaceship.getControl().setLinearVelocity(movement); bloom.setBloomIntensity(bloom.getBloomIntensity() + (bloomDirection * tpf / 8)); if (bloom.getBloomIntensity() > 4) { bloomDirection = -1; } if (bloom.getBloomIntensity() < 2) { bloomDirection = 1; } Vector3f direction = spaceship.getRear().getWorldTranslation().subtract(cam.getLocation()); float magnitude = direction.length(); if (magnitude > 0) { cam.setLocation( cam.getLocation().add(direction.normalize().mult(tpf * magnitude * magnitude / 2))); } cam.lookAt(spaceship.getFront().getWorldTranslation(), Vector3f.UNIT_Y); for (Spatial spatial : asteroids.getChildren()) { if (spatial.getWorldTranslation().subtract(Vector3f.ZERO).length() > 200) { spatial.removeFromParent(); } } if (Math.random() < 0.01 && asteroids.getChildren().size() < MAX_ASTEROIDS) { generateRandomAsteroid(); } for (Spatial spatial : lasers.getChildren()) { Laser laser = (Laser) spatial; if (laser.getWorldTranslation().subtract(Vector3f.ZERO).length() > 200) { bap.getPhysicsSpace().remove(laser.getControl()); laser.removeFromParent(); continue; } laser.move(laser.getDirection().mult(laser.getSpeed())); } scoreText.setText("Score: " + score); }
private static BoneWorldGrid makeBoneWorldGrid( ByteArray3d boneMeshGrid, float worldScale, MyBone bone) { Transform transform = BoneTransformUtils.boneTransform2(bone); // bounding box needed for boneMeshGrid in world grid: float bs = 1.0f; Vector3f c1 = transform.transformVector(new Vector3f(-bs, -bs, -bs), null).multLocal(worldScale); Vector3f c2 = transform.transformVector(new Vector3f(+bs, -bs, -bs), null).multLocal(worldScale); Vector3f c3 = transform.transformVector(new Vector3f(-bs, +bs, -bs), null).multLocal(worldScale); Vector3f c4 = transform.transformVector(new Vector3f(-bs, -bs, +bs), null).multLocal(worldScale); Vector3f c5 = transform.transformVector(new Vector3f(+bs, +bs, -bs), null).multLocal(worldScale); Vector3f c6 = transform.transformVector(new Vector3f(-bs, +bs, +bs), null).multLocal(worldScale); Vector3f c7 = transform.transformVector(new Vector3f(+bs, -bs, +bs), null).multLocal(worldScale); Vector3f c8 = transform.transformVector(new Vector3f(+bs, +bs, +bs), null).multLocal(worldScale); Vector3f cmin = c1.clone(); cmin.minLocal(c2); cmin.minLocal(c3); cmin.minLocal(c4); cmin.minLocal(c5); cmin.minLocal(c6); cmin.minLocal(c7); cmin.minLocal(c8); Vector3f cmax = c1.clone(); cmax.maxLocal(c2); cmax.maxLocal(c3); cmax.maxLocal(c4); cmax.maxLocal(c5); cmax.maxLocal(c6); cmax.maxLocal(c7); cmax.maxLocal(c8); int xsize = (int) FastMath.ceil(cmax.x - cmin.x); int ysize = (int) FastMath.ceil(cmax.y - cmin.y); int zsize = (int) FastMath.ceil(cmax.z - cmin.z); ByteArray3d grid = new ByteArray3d(xsize, ysize, zsize); int w = grid.getWidth(); int h = grid.getHeight(); int d = grid.getDepth(); Vector3f v = new Vector3f(); Vector3f inv = new Vector3f(); Vector3f inv2 = new Vector3f(); // we want to calculate transform: (inv - (-bs)) * (sz / (bs - (-bs))) // se let's precalculate it to (inv + shift) * scale Vector3f scale = new Vector3f(boneMeshGrid.getWidth(), boneMeshGrid.getHeight(), boneMeshGrid.getDepth()) .divideLocal(bs * 2); Vector3f shift = Vector3f.UNIT_XYZ.mult(bs); for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { // calculate inverse transform at (x,y,0) and (x,y,1), the rest of the transforms in inner // loop // can be calculated by adding (inv2-inv1) because the transforms are linear v.set(x, y, 0).addLocal(cmin).divideLocal(worldScale); transform.transformInverseVector(v, inv); inv.addLocal(shift).multLocal(scale); v.set(x, y, 1).addLocal(cmin).divideLocal(worldScale); transform.transformInverseVector(v, inv2); inv2.addLocal(shift).multLocal(scale); Vector3f add = inv2.subtractLocal(inv); for (int z = 0; z < d; z++) { inv.addLocal(add); if (inv.x >= 0 && inv.x < boneMeshGrid.getWidth() && inv.y >= 0 && inv.y < boneMeshGrid.getHeight() && inv.z >= 0 && inv.z < boneMeshGrid.getDepth()) { grid.set(x, y, z, boneMeshGrid.get((int) inv.x, (int) inv.y, (int) inv.z)); } } } } // Once the boneMeshGrid has been transformed into world grid, it may suffer from // downsampling and upsampling artifacts (because the sampling is very simple nearest-neighbor). // Blurring the grid helps with both issues (blur=fake antialias). It has the added benefit // that each BoneWorldGrid will have some "smoothing buffer" around the actual shape, so that // the shape blends better with other bones' shapes. blurGrid(grid); BoneWorldGrid bwg2 = new BoneWorldGrid(); bwg2.grid = grid; bwg2.location = new Vector3i(Math.round(cmin.x), Math.round(cmin.y), Math.round(cmin.z)); return bwg2; }
private static Mesh genTangentLines(Mesh mesh, float scale) { FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData(); FloatBuffer tangentBuffer = (FloatBuffer) mesh.getBuffer(Type.Tangent).getData(); FloatBuffer binormalBuffer = null; if (mesh.getBuffer(Type.Binormal) != null) { binormalBuffer = (FloatBuffer) mesh.getBuffer(Type.Binormal).getData(); } ColorRGBA originColor = ColorRGBA.White; ColorRGBA tangentColor = ColorRGBA.Red; ColorRGBA binormalColor = ColorRGBA.Green; ColorRGBA normalColor = ColorRGBA.Blue; Mesh lineMesh = new Mesh(); lineMesh.setMode(Mesh.Mode.Lines); Vector3f origin = new Vector3f(); Vector3f point = new Vector3f(); Vector3f tangent = new Vector3f(); Vector3f normal = new Vector3f(); IntBuffer lineIndex = BufferUtils.createIntBuffer(vertexBuffer.limit() / 3 * 6); FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.limit() * 4); FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.limit() / 3 * 4 * 4); boolean hasParity = mesh.getBuffer(Type.Tangent).getNumComponents() == 4; float tangentW = 1; for (int i = 0; i < vertexBuffer.limit() / 3; i++) { populateFromBuffer(origin, vertexBuffer, i); populateFromBuffer(normal, normalBuffer, i); if (hasParity) { tangent.x = tangentBuffer.get(i * 4); tangent.y = tangentBuffer.get(i * 4 + 1); tangent.z = tangentBuffer.get(i * 4 + 2); tangentW = tangentBuffer.get(i * 4 + 3); } else { populateFromBuffer(tangent, tangentBuffer, i); } int index = i * 4; int id = i * 6; lineIndex.put(id, index); lineIndex.put(id + 1, index + 1); lineIndex.put(id + 2, index); lineIndex.put(id + 3, index + 2); lineIndex.put(id + 4, index); lineIndex.put(id + 5, index + 3); setInBuffer(origin, lineVertex, index); setInBuffer(originColor, lineColor, index); point.set(tangent); point.multLocal(scale); point.addLocal(origin); setInBuffer(point, lineVertex, index + 1); setInBuffer(tangentColor, lineColor, index + 1); // wvBinormal = cross(wvNormal, wvTangent) * -inTangent.w if (binormalBuffer == null) { normal.cross(tangent, point); point.multLocal(-tangentW); point.normalizeLocal(); } else { populateFromBuffer(point, binormalBuffer, i); } point.multLocal(scale); point.addLocal(origin); setInBuffer(point, lineVertex, index + 2); setInBuffer(binormalColor, lineColor, index + 2); point.set(normal); point.multLocal(scale); point.addLocal(origin); setInBuffer(point, lineVertex, index + 3); setInBuffer(normalColor, lineColor, index + 3); } lineMesh.setBuffer(Type.Index, 1, lineIndex); lineMesh.setBuffer(Type.Position, 3, lineVertex); lineMesh.setBuffer(Type.Color, 4, lineColor); lineMesh.setStatic(); // lineMesh.setInterleaved(); return lineMesh; }
private static void processTriangleData( Mesh mesh, List<VertexData> vertices, boolean approxTangent, boolean splitMirrored) { ArrayList<VertexInfo> vertexMap = linkVertices(mesh, splitMirrored); FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.size() * 4); ColorRGBA[] cols = null; if (debug) { cols = new ColorRGBA[vertices.size()]; } Vector3f tangent = new Vector3f(); Vector3f binormal = new Vector3f(); // Vector3f normal = new Vector3f(); Vector3f givenNormal = new Vector3f(); Vector3f tangentUnit = new Vector3f(); Vector3f binormalUnit = new Vector3f(); for (int k = 0; k < vertexMap.size(); k++) { float wCoord = -1; VertexInfo vertexInfo = vertexMap.get(k); givenNormal.set(vertexInfo.normal); givenNormal.normalizeLocal(); TriangleData firstTriangle = vertices.get(vertexInfo.indices.get(0)).triangles.get(0); // check tangent and binormal consistency tangent.set(firstTriangle.tangent); tangent.normalizeLocal(); binormal.set(firstTriangle.binormal); binormal.normalizeLocal(); for (int i : vertexInfo.indices) { ArrayList<TriangleData> triangles = vertices.get(i).triangles; for (int j = 0; j < triangles.size(); j++) { TriangleData triangleData = triangles.get(j); tangentUnit.set(triangleData.tangent); tangentUnit.normalizeLocal(); if (tangent.dot(tangentUnit) < toleranceDot) { // log.log(Level.WARNING, // "Angle between tangents exceeds tolerance " // + "for vertex {0}.", i); break; } if (!approxTangent) { binormalUnit.set(triangleData.binormal); binormalUnit.normalizeLocal(); if (binormal.dot(binormalUnit) < toleranceDot) { // log.log(Level.WARNING, // "Angle between binormals exceeds tolerance " // + "for vertex {0}.", i); break; } } } } // find average tangent tangent.set(0, 0, 0); binormal.set(0, 0, 0); int triangleCount = 0; for (int i : vertexInfo.indices) { ArrayList<TriangleData> triangles = vertices.get(i).triangles; triangleCount += triangles.size(); if (debug) { cols[i] = ColorRGBA.White; } for (int j = 0; j < triangles.size(); j++) { TriangleData triangleData = triangles.get(j); tangent.addLocal(triangleData.tangent); binormal.addLocal(triangleData.binormal); } } int blameVertex = vertexInfo.indices.get(0); if (tangent.length() < ZERO_TOLERANCE) { log.log(Level.WARNING, "Shared tangent is zero for vertex {0}.", blameVertex); // attempt to fix from binormal if (binormal.length() >= ZERO_TOLERANCE) { binormal.cross(givenNormal, tangent); tangent.normalizeLocal(); } // if all fails use the tangent from the first triangle else { tangent.set(firstTriangle.tangent); } } else { tangent.divideLocal(triangleCount); } tangentUnit.set(tangent); tangentUnit.normalizeLocal(); if (Math.abs(Math.abs(tangentUnit.dot(givenNormal)) - 1) < ZERO_TOLERANCE) { log.log(Level.WARNING, "Normal and tangent are parallel for vertex {0}.", blameVertex); } if (!approxTangent) { if (binormal.length() < ZERO_TOLERANCE) { log.log(Level.WARNING, "Shared binormal is zero for vertex {0}.", blameVertex); // attempt to fix from tangent if (tangent.length() >= ZERO_TOLERANCE) { givenNormal.cross(tangent, binormal); binormal.normalizeLocal(); } // if all fails use the binormal from the first triangle else { binormal.set(firstTriangle.binormal); } } else { binormal.divideLocal(triangleCount); } binormalUnit.set(binormal); binormalUnit.normalizeLocal(); if (Math.abs(Math.abs(binormalUnit.dot(givenNormal)) - 1) < ZERO_TOLERANCE) { log.log(Level.WARNING, "Normal and binormal are parallel for vertex {0}.", blameVertex); } if (Math.abs(Math.abs(binormalUnit.dot(tangentUnit)) - 1) < ZERO_TOLERANCE) { log.log(Level.WARNING, "Tangent and binormal are parallel for vertex {0}.", blameVertex); } } Vector3f finalTangent = new Vector3f(); Vector3f tmp = new Vector3f(); for (int i : vertexInfo.indices) { if (approxTangent) { // Gram-Schmidt orthogonalize finalTangent .set(tangent) .subtractLocal(tmp.set(givenNormal).multLocal(givenNormal.dot(tangent))); finalTangent.normalizeLocal(); wCoord = tmp.set(givenNormal).crossLocal(tangent).dot(binormal) < 0f ? -1f : 1f; tangents.put((i * 4), finalTangent.x); tangents.put((i * 4) + 1, finalTangent.y); tangents.put((i * 4) + 2, finalTangent.z); tangents.put((i * 4) + 3, wCoord); } else { tangents.put((i * 4), tangent.x); tangents.put((i * 4) + 1, tangent.y); tangents.put((i * 4) + 2, tangent.z); tangents.put((i * 4) + 3, wCoord); // setInBuffer(binormal, binormals, i); } } } tangents.limit(tangents.capacity()); // If the model already had a tangent buffer, replace it with the regenerated one mesh.clearBuffer(Type.Tangent); mesh.setBuffer(Type.Tangent, 4, tangents); if (mesh.isAnimated()) { mesh.clearBuffer(Type.BindPoseNormal); mesh.clearBuffer(Type.BindPosePosition); mesh.clearBuffer(Type.BindPoseTangent); mesh.generateBindPose(true); } if (debug) { writeColorBuffer(vertices, cols, mesh); } mesh.updateBound(); mesh.updateCounts(); }