package pl.vorg.mowa.core.graphics; import com.framsticks.net.client3D.Log; /** * A set of helper metods useful with 3d objects. * * @author vorg */ public class GeometryUtils { public static void generateNormals(Geometry geometry) { VertexStream vertexStream = geometry.getVertexStream(); if (vertexStream == null) { Log.getInstance() .log("err", "GeometryUtils.generateNormals err: vertex stream not found"); return; } if (vertexStream.getAttribByName("normal") == null) { FloatVertexAttrib normalAttrib = new FloatVertexAttrib("normal"); vertexStream.addAttrib(normalAttrib); float[] normals = new float[((FloatVertexAttrib) vertexStream .getAttribByName("pos")).getBuffer().length]; normalAttrib.setBuffer(normals); } if (geometry.getPrimitiveType() == PrimitiveType.Triangles) { genSmoothTriangleNormals(geometry.getVertexStream()); } if (geometry.getPrimitiveType() == PrimitiveType.Quads) { genSmoothQuadNormals(geometry.getVertexStream()); } } private static void genSmoothTriangleNormals(VertexStream vertexStream) { IndexBuffer indexBuffer = vertexStream.getIndexBuffer(); int[] indices = indexBuffer.getBuffer(); FloatVertexAttrib posAttrib = (FloatVertexAttrib) vertexStream .getAttribByName("pos"); float[] positions = posAttrib.getBuffer(); FloatVertexAttrib normalAttrib = (FloatVertexAttrib) vertexStream .getAttribByName("normal"); float[] normals = normalAttrib.getBuffer(); normalAttrib.setBuffer(normals); Vec3[] faceNormalList = new Vec3[indices.length / 3]; for (int i = 0; i < indices.length; i += 3) { Vec3 a = new Vec3(positions[indices[i] * 3], positions[indices[i] * 3 + 1], positions[indices[i] * 3 + 2]); Vec3 b = new Vec3(positions[indices[i + 1] * 3], positions[indices[i + 1] * 3 + 1], positions[indices[i + 1] * 3 + 2]); Vec3 c = new Vec3(positions[indices[i + 2] * 3], positions[indices[i + 2] * 3 + 1], positions[indices[i + 2] * 3 + 2]); Vec3 bsa = Vec3.sub(b, a); Vec3 bsc = Vec3.sub(b, c); Vec3 n = Vec3.cross(bsc, bsa); n.normalize(); faceNormalList[i / 3] = n; } // For each vertice. for (int i = 0; i < positions.length; i += 3) { // Search faces containg the vertice and add a normal vector to it. float x = positions[i]; float y = positions[i + 1]; float z = positions[i + 2]; Vec3 vertNormal = new Vec3(); for (int j = 0; j < indices.length; j++) { if ((x == positions[indices[j] * 3]) && (y == positions[indices[j] * 3 + 1]) && (z == positions[indices[j] * 3 + 2])) { vertNormal.add(faceNormalList[j / 3]); } } vertNormal.normalize(); normals[i] = vertNormal.getX(); normals[i + 1] = vertNormal.getY(); normals[i + 2] = vertNormal.getZ(); } } private static void genSmoothQuadNormals(VertexStream vertexStream) { IndexBuffer indexBuffer = vertexStream.getIndexBuffer(); int[] indices = indexBuffer.getBuffer(); FloatVertexAttrib posAttrib = (FloatVertexAttrib) vertexStream .getAttribByName("pos"); float[] positions = posAttrib.getBuffer(); FloatVertexAttrib normalAttrib = (FloatVertexAttrib) vertexStream .getAttribByName("normal"); float[] normals = new float[positions.length]; normalAttrib.setBuffer(normals); Vec3[] faceNormalList = new Vec3[indices.length / 4]; for (int i = 0; i < indices.length; i += 4) { Vec3 a = new Vec3(positions[indices[i] * 3], positions[indices[i] * 3 + 1], positions[indices[i] * 3 + 2]); Vec3 b = new Vec3(positions[indices[i + 1] * 3], positions[indices[i + 1] * 3 + 1], positions[indices[i + 1] * 3 + 2]); Vec3 c = new Vec3(positions[indices[i + 2] * 3], positions[indices[i + 2] * 3 + 1], positions[indices[i + 2] * 3 + 2]); Vec3 bsa = Vec3.sub(b, a); Vec3 bsc = Vec3.sub(b, c); Vec3 n = Vec3.cross(bsc, bsa); n.normalize(); faceNormalList[i / 4] = n; } // For each vertice. for (int i = 0; i < positions.length; i += 3) { // Search faces containg the vertice and add a normal vector to it. float x = positions[i]; float y = positions[i + 1]; float z = positions[i + 2]; Vec3 vertNormal = new Vec3(); for (int j = 0; j < indices.length; j++) { if ((x == positions[indices[j] * 3]) && (y == positions[indices[j] * 3 + 1]) && (z == positions[indices[j] * 3 + 2])) { vertNormal.add(faceNormalList[j / 4]); } } vertNormal.normalize(); normals[i] = vertNormal.getX(); normals[i + 1] = vertNormal.getY(); normals[i + 2] = vertNormal.getZ(); } } // Isn't tested well. public static void generateTangents(Geometry geometry) { VertexStream vertexStream = geometry.getVertexStream(); if (vertexStream == null) { Log.getInstance() .log("err", "GeometryUtils.generateTangents err: vertex stream not found"); return; } if (vertexStream.getAttribByName("tangent") == null) { FloatVertexAttrib tangentAttrib = new FloatVertexAttrib("tangent"); vertexStream.addAttrib(tangentAttrib); float[] tangents = new float[((FloatVertexAttrib) vertexStream .getAttribByName("pos")).getBuffer().length]; tangentAttrib.setBuffer(tangents); } if (vertexStream.getAttribByName("normal") == null) { FloatVertexAttrib normalAttrib = new FloatVertexAttrib("normal"); vertexStream.addAttrib(normalAttrib); float[] normals = new float[((FloatVertexAttrib) vertexStream .getAttribByName("pos")).getBuffer().length]; normalAttrib.setBuffer(normals); } if (geometry.getPrimitiveType() == PrimitiveType.Triangles) { genTriangleTangents(geometry.getVertexStream()); } } private static void genTriangleTangents(VertexStream vertexStream) { IndexBuffer indexBuffer = vertexStream.getIndexBuffer(); int[] indices = indexBuffer.getBuffer(); FloatVertexAttrib posAttrib = (FloatVertexAttrib) vertexStream .getAttribByName("pos"); float[] positions = posAttrib.getBuffer(); FloatVertexAttrib texCoord0Attrib = (FloatVertexAttrib) vertexStream .getAttribByName("texCoord0"); float[] texCoords0 = texCoord0Attrib.getBuffer(); FloatVertexAttrib tangentAttrib = (FloatVertexAttrib) vertexStream .getAttribByName("tangent"); float[] tangents = tangentAttrib.getBuffer(); for (int i = 0; i < indices.length; i += 3) { int i1 = indices[i]; int i2 = indices[i + 1]; int i3 = indices[i + 2]; Vec3 pos1 = new Vec3(positions[i1] * 3, positions[i1 * 3 + 1], positions[i1 * 3 + 2]); Vec3 pos2 = new Vec3(positions[i2] * 3, positions[i2 * 3 + 1], positions[i2 * 3 + 2]); Vec3 pos3 = new Vec3(positions[i3] * 3, positions[i3 * 3 + 1], positions[i3 * 3 + 2]); Vec2 coord1 = new Vec2(texCoords0[i1 * 2], texCoords0[i1 * 2 + 1]); Vec2 coord2 = new Vec2(texCoords0[i2 * 2], texCoords0[i2 * 2 + 1]); Vec2 coord3 = new Vec2(texCoords0[i3 * 2], texCoords0[i3 * 2 + 1]); Vec3 v0 = Vec3.sub(pos1, pos2); Vec3 v1 = Vec3.sub(pos3, pos1); Vec3 normal = Vec3.normalized(Vec3.cross(v0, v1)); float dt0 = coord1.getT() - coord2.getT(); float dt1 = coord3.getT() - coord1.getT(); Vec3 tangent = Vec3.normalized(Vec3.sub(Vec3.mul(dt1, v0), Vec3.mul(dt0, v1))); float ds0 = coord1.getS() - coord2.getS(); float ds1 = coord3.getS() - coord1.getS(); Vec3 binormal = Vec3.normalized(Vec3.sub(Vec3.mul(ds1, v0), Vec3.mul(ds0, v1))); Vec3 tangentCross = Vec3.cross(tangent, binormal); if (Vec3.dot(tangentCross, normal) < 0.0f) { tangent = Vec3.neg(tangent); binormal = Vec3.neg(binormal); } tangents[i1 * 3] = tangents[i1 * 3] + tangent.getX(); tangents[i1 * 3 + 1] = tangents[i1 * 3 + 1] + tangent.getY(); tangents[i1 * 3 + 2] = tangents[i1 * 3 + 2] + tangent.getZ(); tangents[i2 * 3] = tangents[i2 * 3] + tangent.getX(); tangents[i2 * 3 + 1] = tangents[i2 * 3 + 1] + tangent.getY(); tangents[i2 * 3 + 2] = tangents[i2 * 3 + 2] + tangent.getZ(); tangents[i3 * 3] = tangents[i3 * 3] + tangent.getX(); tangents[i3 * 3 + 1] = tangents[i3 * 3 + 1] + tangent.getY(); tangents[i3 * 3 + 2] = tangents[i3 * 3 + 2] + tangent.getZ(); } for (int j = 0; j < tangents.length; j += 3) { Vec3 tangent = new Vec3(tangents[j], tangents[j + 1], tangents[j + 2]); tangent.normalize(); tangents[j] = tangent.getX(); tangents[j + 1] = tangent.getY(); tangents[j + 2] = tangent.getZ(); } } }