public static void AddFaceToVao(WorldServer world, Vector3i blockPos, int x, int y, int z, Block block, BlockFace face, BlockModel.FaceData data, VertexArrayObject vao, Matrix4 transform) { var faceId = (int)face - 1; var indicesOffset = vao.VertexCount; //var transform = Matrix4.CreateScale()//Matrix4.Identity;//block.GetTransform(world, blockPos, face); var texture = data.LoadedTexture; //block.GetTexture(world, blockPos, face); //var overlayTexture = block.GetOverlayTexture(world, blockPos, face); var texCoords = data.GetTexCoords(); //block.GetTexCoords(world, blockPos, face) ?? FaceTexCoords; //var overlayTexCoords = block.GetOverlayTexCoords(world, blockPos, face) ?? FaceTexCoords; var color = data.TintIndex == -1 ? new Vector4(1) : block.GetTintColor(world, blockPos, data.TintIndex).ToVector4(); var normal = face.GetNormal(); if (texCoords.Length != 4) { throw new Exception($"\"{block}\" invalid texture coords array length!"); } var vPositions = new Vector3[4]; var vTexCoords = new Vector4[4]; var vOverlayTexCoords = new Vector4[4]; //TODO: Remove var vBrightness = new Vector3[4]; for (var j = 0; j < 4; j++) { var vertexPosition = FacePositions[faceId * 4 + j]; var position = (new Vector4(vertexPosition, 1) * transform).Xyz + new Vector3(x, y, z); //tex coords are -1 if texture is null var texCoord = texture == null ? new Vector4(-1) : new Vector4(texCoords[j]) { //texCoord z = texId, w = textureArrayId Z = texture.TextureId, W = texture.ArrayId }; //per vertex light value interpolation (smooth lighting + free ambient occlusion) var brightness = CalculateBrightness(world, block, blockPos, face, vertexPosition); //TODO: transform normals vPositions[j] = position; vTexCoords[j] = texCoord; vOverlayTexCoords[j] = new Vector4(-1); vBrightness[j] = brightness; } //Flip faces to fix ambient occlusion anisotrophy //https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/ for (var j = 0; j < 4; j++) { vao.Add(vPositions[j], vTexCoords[j], new Vector4(normal), color.Xyz, vBrightness[j]); } var newIndices = new uint[FaceIndices.Length]; if ((vBrightness[0] + vBrightness[3]).LengthSquared > (vBrightness[1] + vBrightness[2]).LengthSquared) { for (var j = 0; j < newIndices.Length; j++) { newIndices[j] = (uint)(FlippedFaceIndices[j] + indicesOffset); } } else { for (var j = 0; j < newIndices.Length; j++) { newIndices[j] = (uint)(FaceIndices[j] + indicesOffset); } } //Calculate face middle for transparency sorting var faceMiddle = Vector3.Zero; if (vao is SortedVertexArrayObject) { faceMiddle = vPositions.Aggregate(faceMiddle, (current, pos) => current + pos); faceMiddle = faceMiddle / vPositions.Length + blockPos.ToVector3() - new Vector3(x, y, z); } vao.AddFace(newIndices, faceMiddle); }