//Calculation taken from: https://learnopengl.com/Advanced-Lighting/Normal-Mapping TangentSpaceData GetTangentSpaceData(List <Vector3> positions, List <Vector2> uvs) { if (positions.Count != uvs.Count) { throw new Exception("Position Data does not match the amount of uv data"); } Vector3[] tangents = new Vector3[positions.Count]; Vector3[] biTangents = new Vector3[positions.Count]; for (int i = 0; i < positions.Count - 2; i += 2) { int idx1 = i; int idx2 = i + 1; int idx3 = i + 2; Vector3 pos1 = positions[idx1]; Vector3 pos2 = positions[idx2]; Vector3 pos3 = positions[idx3]; Vector3 edge1 = pos2 - pos1; Vector3 edge2 = pos3 - pos1; Vector2 uv1 = uvs[idx1]; Vector2 uv2 = uvs[idx2]; Vector2 uv3 = uvs[idx3]; Vector2 deltaUV1 = uv2 - uv1; Vector2 deltaUV2 = uv3 - uv1; float f = 1.0f / (deltaUV1.Y * deltaUV2.X - deltaUV1.X * deltaUV2.Y); Vector3 tangent; tangent.X = f * (deltaUV2.Y * edge1.X - deltaUV1.Y * edge2.X); tangent.Y = f * (deltaUV2.Y * edge1.Y - deltaUV1.Y * edge2.Y); tangent.Z = f * (deltaUV2.Y * edge1.Z + deltaUV1.Y * edge2.Z); tangent = Vector3.Normalize(tangent); Vector3 biTangent; biTangent.X = f * (-deltaUV2.X * edge1.X + deltaUV1.X * edge2.X); biTangent.Y = f * (-deltaUV2.X * edge1.Y + deltaUV1.X * edge2.Y); biTangent.Z = f * (-deltaUV2.X * edge1.Z + deltaUV1.X * edge2.Z); biTangent = Vector3.Normalize(biTangent); tangents[idx1] = tangent; biTangents[idx1] = biTangent; tangents[idx2] = tangent; biTangents[idx2] = biTangent; tangents[idx3] = tangent; biTangents[idx3] = biTangent; } TangentSpaceData result = new TangentSpaceData(); result.tangent = tangents; result.biTangent = biTangents; return(result); }
List <GameObject> GetSphereSampleScene() { List <GameObject> goList = new List <GameObject>(); DefaultMesh plane = Meshes.CreatePlane(10, 10, 10, 10).Transform(Transformation.Translation(new Vector3(0, -1f, 0))); VAO planeMesh = VAOLoader.FromMesh(plane, renderer.GetPBRShader()); GameObject planeGO = new GameObject(); PBRMaterial planemat = new PBRMaterial(); planemat.albedoColor = new Vector3(1); planemat.roughness = 1; planemat.metal = 0; planeGO.mesh = planeMesh; planeGO.material = planemat; //goList.Add(planeGO); //return goList; int gridSize = 7; float sphereSize = 0.1f; float spacing = sphereSize + sphereSize * 2f; float startX = gridSize / 2 * spacing; Vector3 startVector = new Vector3(startX, startX, 0); float paramSteps = 1.0f / gridSize; string texPrefix = "rustediron2_"; ITexture2D albedoText = contentLoader.Load <ITexture2D>(texPrefix + "basecolor.png"); ITexture2D metallicText = contentLoader.Load <ITexture2D>(texPrefix + "metallic.png"); ITexture2D normalText = contentLoader.Load <ITexture2D>(texPrefix + "normal.png"); ITexture2D roughnessText = contentLoader.Load <ITexture2D>(texPrefix + "roughness.png"); DefaultMesh mesh = contentLoader.Load <DefaultMesh>("uvSphere").Transform(Transformation.Scale(0.1f)); //DefaultMesh mesh = Meshes.CreateSphere(sphereSize, 2); VAO geom = VAOLoader.FromMesh(mesh, renderer.GetPBRShader()); TangentSpaceData tangentData = GetTangentSpaceData(mesh.Position, mesh.TexCoord); int tangentLocation = renderer.GetPBRShader().GetResourceLocation(ShaderResourceType.Attribute, "tangent"); int biTangentLocation = GL.GetAttribLocation(renderer.GetPBRShader().ProgramID, "biTangent"); geom.SetAttribute(tangentLocation, tangentData.tangent); geom.SetAttribute(biTangentLocation, tangentData.biTangent); for (int i = 0; i < gridSize; i++) { Vector3 tmpStart = startVector; for (int j = 0; j < gridSize; j++) { GameObject go = new GameObject(); go.transform.position = tmpStart; go.material.metal = i * paramSteps; go.material.roughness = j * paramSteps; go.material.albedoColor = new Vector3(1, 0, 0); go.mesh = geom; /* * go.material.albedoMap = albedoText; * go.material.metallicMap = metallicText; * go.material.normalMap = normalText; * go.material.roughnessMap = roughnessText; */ goList.Add(go); tmpStart.X -= spacing; } startVector.Y -= spacing; } return(goList); }