public vec3(vec2 xy, float z) { this.x = xy.x; this.y = xy.y; this.z = z; }
/// <summary> /// /// </summary> /// <param name="min"></param> /// <param name="max"></param> public BoundingBox2D(vec2 min, vec2 max) { this.MinPosition = min; this.MaxPosition = max; }
/// <summary> /// Reads mesh's vertexes, normals and faces. /// </summary> /// <param name="context"></param> public override void Parse(ObjVNFContext context) { var objVNF = new ObjVNFMesh(); var vertexes = new vec3[context.vertexCount]; var normals = new vec3[context.normalCount]; var texCoords = new vec2[context.texCoordCount]; var faces = new ObjVNFFace[context.faceCount]; string filename = context.ObjFilename; int vertexIndex = 0, normalIndex = 0, texCoordIndex = 0, faceIndex = 0; using (var reader = new System.IO.StreamReader(filename)) { while (!reader.EndOfStream) { string line = reader.ReadLine(); string[] parts = line.Split(separator, StringSplitOptions.RemoveEmptyEntries); if (parts.Length <= 0) { continue; } if (parts[0] == "v") { vertexes[vertexIndex++] = ParseVec3(parts); } else if (parts[0] == "vn") { normals[normalIndex++] = ParseVec3(parts); } else if (parts[0] == "vt") { texCoords[texCoordIndex++] = ParseVec2(parts); } else if (parts[0] == "f") { faces[faceIndex++] = ParseFace(parts); } } } objVNF.vertexes = vertexes; objVNF.normals = normals; objVNF.texCoords = texCoords; objVNF.faces = faces; context.Mesh = objVNF; if (vertexIndex != context.vertexCount) { throw new Exception(string.Format("v: [{0}] not equals to [{1}] in MeshParser!", vertexIndex, context.vertexCount)); } if (normalIndex != context.normalCount) { throw new Exception(string.Format("vn: [{0}] not equals to [{1}] in MeshParser!", normalIndex, context.normalCount)); } if (texCoordIndex != context.texCoordCount) { throw new Exception(string.Format("vt: [{0}] not equals to [{1}] in MeshParser!", texCoordIndex, context.texCoordCount)); } if (faceIndex != context.faceCount) { throw new Exception(string.Format("f: [{0}] not equals to [{1}] in MeshParser!", vertexIndex, context.vertexCount)); } if (faceIndex > 0) { Type type = faces[0].GetType(); for (int i = 1; i < faceIndex; i++) { if (faces[i].GetType() != type) { throw new Exception(string.Format("Different face types [{0}] vs [{1}]!", type, faces[i].GetType())); } } } }
public override void Parse(ObjVNFContext context) { ObjVNFMesh mesh = context.Mesh; vec3[] vertexes = mesh.vertexes;// positions vec2[] texCoords = mesh.texCoords; vec3[] normals = mesh.normals; if (vertexes == null || texCoords == null || normals == null) { return; } if (vertexes.Length != texCoords.Length || vertexes.Length != normals.Length) { return; } ObjVNFFace[] faces = mesh.faces; if (faces == null || faces.Length == 0) { return; } // if (not triangles) { return; } if (faces[0].VertexIndexes().Count() != 3) { return; } var tangents = new vec3[normals.Length]; for (int i = 0; i < faces.Length; i++) { var face = faces[i] as ObjVNFTriangle; if (face == null) { return; } // no dealing with quad. uint[] vertexIndexes = face.VertexIndexes(); vec3 p0 = vertexes[vertexIndexes[0]]; vec3 p1 = vertexes[vertexIndexes[1]]; vec3 p2 = vertexes[vertexIndexes[2]]; vec2 uv0 = texCoords[vertexIndexes[0]]; vec2 uv1 = texCoords[vertexIndexes[1]]; vec2 uv2 = texCoords[vertexIndexes[2]]; vec3 q0 = p1 - p0, q1 = p2 - p0; float u0 = uv0.x, v0 = uv0.y, u1 = uv1.x, v1 = uv1.y, u2 = uv2.x, v2 = uv2.y; float coefficient = 1.0f / ((u1 - u0) * (v2 - v0) - (v1 - v0) * (u2 - u0)); vec3 tangentFace; tangentFace.x = (v2 - v0) * q0.x + (v0 - v1) * q1.x; tangentFace.y = (v2 - v0) * q0.y + (v0 - v1) * q1.y; tangentFace.z = (v2 - v0) * q0.z + (v0 - v1) * q1.z; //vec3 binormalFace; //binormalFace.x = (u0 - u2) * q0.x + (u1 - u0) * q1.x; //binormalFace.y = (u0 - u2) * q0.y + (u1 - u0) * q1.y; //binormalFace.z = (u0 - u2) * q0.z + (u1 - u0) * q1.z; for (int t = 0; t < vertexIndexes.Length; t++) { vec3 n = normals[vertexIndexes[t]].normalize(); tangents[vertexIndexes[t]] = tangentFace - tangentFace.dot(n) * n; } } mesh.tangents = tangents; }
///// <summary> ///// Index of the the texture which this glyph belongs to in the 2D texture array. ///// 此字符所在的纹理,在二维纹理数组中的索引。 ///// </summary> //public readonly int textureIndex; /// <summary> /// Information of rendering a glyph. /// 绘制一个字符(串)所需要的信息。 /// </summary> /// <param name="characters">The glyph(a character or a string).此字符(串)。</param> /// <param name="leftTop">UV of left top.此字符的字形在纹理的横向偏移量(左上角uv)</param> /// <param name="rightBottom">UV of right bottom.此字符的字形在纹理的纵向偏移量(右下角uv)</param> /// <param name="textureIndex">Index of the the texture which this glyph belongs to in the 2D texture array.此字符所在的纹理,在二维纹理数组中的索引。</param> public GlyphInfo(string characters, vec2 leftTop, vec2 rightBottom, int textureIndex) { this.characters = characters; this.quad = new QuadSTRStruct(leftTop, rightBottom, textureIndex); }
/// <summary> /// start from (0, 0) to the right. /// </summary> /// <param name="text"></param> /// <param name="server"></param> /// <param name="totalWidth"></param> /// <param name="totalHeight"></param> unsafe private void PositionPass(string text, GlyphServer server, out float totalWidth, out float totalHeight) { int textureWidth = server.TextureWidth; int textureHeight = server.TextureHeight; VertexBuffer buffer = this.positionBuffer; var positionArray = (QuadPositionStruct *)buffer.MapBuffer(MapBufferAccess.ReadWrite); const float height = 2.0f; // let's say height is 2.0f. totalWidth = 0; totalHeight = height; int index = 0; foreach (var c in text) { if (index >= this.labelModel.Capacity) { break; } GlyphInfo glyphInfo; float wByH = 0; if (server.GetGlyphInfo(c, out glyphInfo)) { float w = (glyphInfo.quad.rightBottom.x - glyphInfo.quad.leftBottom.x) * textureWidth; float h = (glyphInfo.quad.rightBottom.y - glyphInfo.quad.rightTop.y) * textureHeight; wByH = height * w / h; } else { // put an empty glyph(square) here. wByH = height * 1.0f / 1.0f; } var leftTop = new vec2(totalWidth, height / 2); var leftBottom = new vec2(totalWidth, -height / 2); var rightBottom = new vec2(totalWidth + wByH, -height / 2); var rightTop = new vec2(totalWidth + wByH, height / 2); positionArray[index++] = new QuadPositionStruct(leftTop, leftBottom, rightBottom, rightTop); totalWidth += wByH; } // move to center. const float scale = 1f; for (int i = 0; i < text.Length; i++) { if (i >= this.labelModel.Capacity) { break; } QuadPositionStruct quad = positionArray[i]; var newPos = new QuadPositionStruct( // y is already in [-1, 1], so just shrink x to [-1, 1] new vec2(quad.leftTop.x / totalWidth * 2.0f - 1f, quad.leftTop.y) * scale, new vec2(quad.leftBottom.x / totalWidth * 2.0f - 1f, quad.leftBottom.y) * scale, new vec2(quad.rightBottom.x / totalWidth * 2.0f - 1f, quad.rightBottom.y) * scale, new vec2(quad.rightTop.x / totalWidth * 2.0f - 1f, quad.rightTop.y) * scale ); positionArray[i] = newPos; } buffer.UnmapBuffer(); }
// https://www.cnblogs.com/bitzhuwei/p/opengl-Computing-Tangent-Space-Basis-Vectors.html public override void Parse(ObjVNFContext context) { ObjVNFMesh mesh = context.Mesh; vec3[] vertexes = mesh.vertexes;// positions vec2[] texCoords = mesh.texCoords; vec3[] normals = mesh.normals; if (vertexes == null || texCoords == null || normals == null) { return; } if (vertexes.Length != texCoords.Length || vertexes.Length != normals.Length) { return; } ObjVNFFace[] faces = mesh.faces; if (faces == null || faces.Length == 0) { return; } // if (not triangles) { return; } if (faces[0].VertexIndexes().Count() != 3) { return; } var tangents = new vec3[normals.Length]; var biTangents = new vec3[normals.Length]; for (int i = 0; i < faces.Length; i++) { var face = faces[i] as ObjVNFTriangle; if (face == null) { return; } // no dealing with quad. uint[] vertexIndexes = face.VertexIndexes(); uint i0 = vertexIndexes[0]; uint i1 = vertexIndexes[1]; uint i2 = vertexIndexes[2]; vec3 p0 = vertexes[i0]; vec3 p1 = vertexes[i1]; vec3 p2 = vertexes[i2]; vec2 uv0 = texCoords[i0]; vec2 uv1 = texCoords[i1]; vec2 uv2 = texCoords[i2]; float x1 = p1.x - p0.x; float y1 = p1.y - p0.y; float z1 = p1.z - p0.z; float x2 = p2.x - p0.x; float y2 = p2.y - p0.y; float z2 = p2.z - p0.z; float s1 = uv1.x - uv0.x; float t1 = uv1.y - uv0.y; float s2 = uv2.x - uv0.x; float t2 = uv2.y - uv0.y; float r = 1.0F / (s1 * t2 - s2 * t1); var sdir = new vec3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); var tdir = new vec3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); //tangents[i0] += sdir; tangents[i0] = (float)i / (float)(i + 1) * tangents[i0] + sdir / (float)(i + 1); //tangents[i1] += sdir; tangents[i1] = (float)i / (float)(i + 1) * tangents[i1] + sdir / (float)(i + 1); //tangents[i2] += sdir; tangents[i2] = (float)i / (float)(i + 1) * tangents[i2] + sdir / (float)(i + 1); //biTangents[i0] += tdir; biTangents[i0] = (float)i / (float)(i + 1) * biTangents[i0] + sdir / (float)(i + 1); //biTangents[i1] += tdir; biTangents[i1] = (float)i / (float)(i + 1) * biTangents[i1] + sdir / (float)(i + 1); //biTangents[i2] += tdir; biTangents[i2] = (float)i / (float)(i + 1) * biTangents[i2] + sdir / (float)(i + 1); } var finalTangents = new vec4[normals.Length]; for (long a = 0; a < normals.Length; a++) { vec3 n = normals[a]; vec3 t = tangents[a]; // Calculate handedness float w = (n.cross(t).dot(biTangents[a]) < 0.0F) ? -1.0F : 1.0F; // Gram-Schmidt orthogonalize finalTangents[a] = new vec4((t - n * n.dot(t)).normalize(), w); } mesh.tangents = finalTangents; }
public static vec2 ToVec2(this float[] array, int startIndex = 0) { vec2 result = new vec2(array[startIndex], array[startIndex + 1]); return(result); }
public override void SetUniform(ShaderProgram program) { vec2 value = this.value; program.SetUniform(VarName, value.x, value.y); }