/** * <code>rotateUpTo</code> is a utility function that alters the local rotation to point the Y * axis in the direction given by newUp. * * @param newUp the up vector to use - assumed to be a unit vector. */ public void rotateUpTo(Vector3f newUp) { TempVars vars = TempVars.get(); Vector3f compVecA = vars.vect1; Quaternion q = vars.quat1; // First figure out the current up vector. Vector3f upY = compVecA.set(Vector3f.UNIT_Y); Quaternion rot = localTransform.getRotation(); rot.multLocal(upY); // get angle between vectors float angle = upY.angleBetween(newUp); // figure out rotation axis by taking cross product Vector3f rotAxis = upY.crossLocal(newUp).normalizeLocal(); // Build a rotation quat and apply current local rotation. q.fromAngleNormalAxis(angle, rotAxis); q.mult(rot, rot); vars.release(); setTransformRefresh(); }
public Vector3f reflect(Vector3f point, Vector3f store) { if (store == null) store = new Vector3f(); float d = pseudoDistance(point); store.set(normal).negateLocal().multLocal(d * 2f); store.addLocal(point); return store; }
/** * Centers the spatial in the origin of the world bound. * * @return The spatial on which this method is called, e.g <code>this</code>. */ public Spatial center() { Vector3f worldTrans = getWorldTranslation(); Vector3f worldCenter = getWorldBound().getCenter(); Vector3f absTrans = worldTrans.subtract(worldCenter); setLocalTranslation(absTrans); return this; }
@Override public Transform clone() { try { Transform tq = (Transform) super.clone(); tq.rot = rot.clone(); tq.scale = scale.clone(); tq.translation = translation.clone(); return tq; } catch (CloneNotSupportedException e) { throw new AssertionError(); } }
public Vector3f transformInverseVector(final Vector3f in, Vector3f store) { if (store == null) store = new Vector3f(); // The author of this code should look above and take the inverse of that // But for some reason, they didnt .. // in.subtract(translation, store).divideLocal(scale); // rot.inverse().mult(store, store); in.subtract(translation, store); rot.inverse().mult(store, store); store.divideLocal(scale); return store; }
public Vector3f transformVector(final Vector3f in, Vector3f store) { if (store == null) store = new Vector3f(); // multiply with scale first, then rotate, finally translate (cf. // Eberly) return rot.mult(store.set(in).multLocal(scale), store).addLocal(translation); }
/** * Changes the values of this matrix acording to it's parent. Very similar to the concept of * Node/Spatial transforms. * * @param parent The parent matrix. * @return This matrix, after combining. */ public Transform combineWithParent(Transform parent) { scale.multLocal(parent.scale); // rot.multLocal(parent.rot); parent.rot.mult(rot, rot); // This here, is evil code // parent // .rot // .multLocal(translation) // .multLocal(parent.scale) // .addLocal(parent.translation); translation.multLocal(parent.scale); parent.rot.multLocal(translation).addLocal(parent.translation); return this; }
/** * <code>lookAt</code> is a convenience method for auto-setting the local rotation based on a * position in world space and an up vector. It computes the rotation to transform the z-axis to * point onto 'position' and the y-axis to 'up'. Unlike {@link * Quaternion#lookAt(com.jme3.math.Vector3f, com.jme3.math.Vector3f) } this method takes a world * position to look at and not a relative direction. * * <p>Note : 28/01/2013 this method has been fixed as it was not taking into account the parent * rotation. This was resulting in improper rotation when the spatial had rotated parent nodes. * This method is intended to work in world space, so no matter what parent graph the spatial has, * it will look at the given position in world space. * * @param position where to look at in terms of world coordinates * @param upVector a vector indicating the (local) up direction. (typically {0, 1, 0} in jME.) */ public void lookAt(Vector3f position, Vector3f upVector) { Vector3f worldTranslation = getWorldTranslation(); TempVars vars = TempVars.get(); Vector3f compVecA = vars.vect4; compVecA.set(position).subtractLocal(worldTranslation); getLocalRotation().lookAt(compVecA, upVector); if (getParent() != null) { Quaternion rot = vars.quat1; rot = rot.set(parent.getWorldRotation()).inverseLocal().multLocal(getLocalRotation()); rot.normalizeLocal(); setLocalRotation(rot); } vars.release(); setTransformRefresh(); }
@Override public Plane clone() { try { Plane p = (Plane) super.clone(); p.normal = normal.clone(); return p; } catch (CloneNotSupportedException e) { throw new AssertionError(); } }
/** * Uploads the lights in the light list as two uniform arrays.<br> * <br> * * * * <p><code>uniform vec4 g_LightColor[numLights];</code><br> * // g_LightColor.rgb is the diffuse/specular color of the light.<br> * // g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point, <br> * // 2 = Spot. <br> * <br> * <code>uniform vec4 g_LightPosition[numLights];</code><br> * // g_LightPosition.xyz is the position of the light (for point lights)<br> * // or the direction of the light (for directional lights).<br> * // g_LightPosition.w is the inverse radius (1/r) of the light (for attenuation) <br> */ protected void updateLightListUniforms(Shader shader, Geometry g, int numLights) { if (numLights == 0) { // this shader does not do lighting, ignore. return; } LightList lightList = g.getWorldLightList(); Uniform lightColor = shader.getUniform("g_LightColor"); Uniform lightPos = shader.getUniform("g_LightPosition"); Uniform lightDir = shader.getUniform("g_LightDirection"); lightColor.setVector4Length(numLights); lightPos.setVector4Length(numLights); lightDir.setVector4Length(numLights); Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); int lightIndex = 0; for (int i = 0; i < numLights; i++) { if (lightList.size() <= i) { lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); lightPos.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); } else { Light l = lightList.get(i); ColorRGBA color = l.getColor(); lightColor.setVector4InArray( color.getRed(), color.getGreen(), color.getBlue(), l.getType().getId(), i); switch (l.getType()) { case Directional: DirectionalLight dl = (DirectionalLight) l; Vector3f dir = dl.getDirection(); lightPos.setVector4InArray(dir.getX(), dir.getY(), dir.getZ(), -1, lightIndex); break; case Point: PointLight pl = (PointLight) l; Vector3f pos = pl.getPosition(); float invRadius = pl.getInvRadius(); lightPos.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightIndex); break; case Spot: SpotLight sl = (SpotLight) l; Vector3f pos2 = sl.getPosition(); Vector3f dir2 = sl.getDirection(); float invRange = sl.getInvSpotRange(); float spotAngleCos = sl.getPackedAngleCos(); lightPos.setVector4InArray(pos2.getX(), pos2.getY(), pos2.getZ(), invRange, lightIndex); lightDir.setVector4InArray( dir2.getX(), dir2.getY(), dir2.getZ(), spotAngleCos, lightIndex); break; case Ambient: // skip this light. Does not increase lightIndex continue; default: throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); } } lightIndex++; } while (lightIndex < numLights) { lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); lightPos.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); lightIndex++; } }
public Vector3f getClosestPoint(Vector3f point, Vector3f store) { // float t = constant - normal.dot(point); // return store.set(normal).multLocal(t).addLocal(point); float t = (constant - normal.dot(point)) / normal.dot(normal); return store.set(normal).multLocal(t).addLocal(point); }
/** Loads the identity. Equal to translation=0,0,0 scale=1,1,1 rot=0,0,0,1. */ public void loadIdentity() { translation.set(0, 0, 0); scale.set(1, 1, 1); rot.set(0, 0, 0, 1); }
/** * Sets this matrix's scale to the given x,y,z values. * * @param x This matrix's new x scale. * @param y This matrix's new y scale. * @param z This matrix's new z scale. * @return this */ public Transform setScale(float x, float y, float z) { scale.set(x, y, z); return this; }
/** * <code>pseudoDistance</code> calculates the distance from this plane to a provided point. If the * point is on the negative side of the plane the distance returned is negative, otherwise it is * positive. If the point is on the plane, it is zero. * * @param point the point to check. * @return the signed distance from the plane to a point. */ public float pseudoDistance(Vector3f point) { return normal.dot(point) - constant; }
/** * Sets this matrix's translation to the given x,y,z values. * * @param x This matrix's new x translation. * @param y This matrix's new y translation. * @param z This matrix's new z translation. * @return this */ public Transform setTranslation(float x, float y, float z) { translation.set(x, y, z); return this; }
/** * Initialize the Plane using the given 3 points as coplanar. * * @param v1 the first point * @param v2 the second point * @param v3 the third point */ public void setPlanePoints(Vector3f v1, Vector3f v2, Vector3f v3) { normal.set(v2).subtractLocal(v1); normal.crossLocal(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z).normalizeLocal(); constant = normal.dot(v1); }
/** * Stores this scale value into the given vector3f. If scale is null, a new vector3f is created to * hold the value. The value, once stored, is returned. * * @param scale The store location for this matrix's scale. * @return The value of this matrix's scale. */ public Vector3f getScale(Vector3f scale) { if (scale == null) scale = new Vector3f(); scale.set(this.scale); return scale; }
/** * Stores this translation value into the given vector3f. If trans is null, a new vector3f is * created to hold the value. The value, once stored, is returned. * * @param trans The store location for this matrix's translation. * @return The value of this matrix's translation. */ public Vector3f getTranslation(Vector3f trans) { if (trans == null) trans = new Vector3f(); trans.set(this.translation); return trans; }
protected void renderMultipassLighting(Shader shader, Geometry g, RenderManager rm) { Renderer r = rm.getRenderer(); LightList lightList = g.getWorldLightList(); Uniform lightDir = shader.getUniform("g_LightDirection"); Uniform lightColor = shader.getUniform("g_LightColor"); Uniform lightPos = shader.getUniform("g_LightPosition"); Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); boolean isFirstLight = true; boolean isSecondLight = false; for (int i = 0; i < lightList.size(); i++) { Light l = lightList.get(i); if (l instanceof AmbientLight) { continue; } if (isFirstLight) { // set ambient color for first light only ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); isFirstLight = false; isSecondLight = true; } else if (isSecondLight) { ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); // apply additive blending for 2nd and future lights r.applyRenderState(additiveLight); isSecondLight = false; } TempVars vars = TempVars.get(); Quaternion tmpLightDirection = vars.quat1; Quaternion tmpLightPosition = vars.quat2; ColorRGBA tmpLightColor = vars.color; Vector4f tmpVec = vars.vect4f; ColorRGBA color = l.getColor(); tmpLightColor.set(color); tmpLightColor.a = l.getType().getId(); lightColor.setValue(VarType.Vector4, tmpLightColor); switch (l.getType()) { case Directional: DirectionalLight dl = (DirectionalLight) l; Vector3f dir = dl.getDirection(); tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1); lightPos.setValue(VarType.Vector4, tmpLightPosition); tmpLightDirection.set(0, 0, 0, 0); lightDir.setValue(VarType.Vector4, tmpLightDirection); break; case Point: PointLight pl = (PointLight) l; Vector3f pos = pl.getPosition(); float invRadius = pl.getInvRadius(); tmpLightPosition.set(pos.getX(), pos.getY(), pos.getZ(), invRadius); lightPos.setValue(VarType.Vector4, tmpLightPosition); tmpLightDirection.set(0, 0, 0, 0); lightDir.setValue(VarType.Vector4, tmpLightDirection); break; case Spot: SpotLight sl = (SpotLight) l; Vector3f pos2 = sl.getPosition(); Vector3f dir2 = sl.getDirection(); float invRange = sl.getInvSpotRange(); float spotAngleCos = sl.getPackedAngleCos(); tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange); lightPos.setValue(VarType.Vector4, tmpLightPosition); // We transform the spot directoin in view space here to save 5 varying later in the // lighting shader // one vec4 less and a vec4 that becomes a vec3 // the downside is that spotAngleCos decoding happen now in the frag shader. tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos); lightDir.setValue(VarType.Vector4, tmpLightDirection); break; default: throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); } vars.release(); r.setShader(shader); r.renderMesh(g.getMesh(), g.getLodLevel(), 1); } if (isFirstLight && lightList.size() > 0) { // There are only ambient lights in the scene. Render // a dummy "normal light" so we can see the ambient ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha); lightPos.setValue(VarType.Vector4, nullDirLight); r.setShader(shader); r.renderMesh(g.getMesh(), g.getLodLevel(), 1); } }