private void MeshControl_Paint(object sender, PaintEventArgs e) { if (!Loaded) { return; } var deltaTime = GetElapsedTime(); // Tick camera ActiveCamera.Tick(deltaTime); // Update labels cameraLabel.Text = $"{ActiveCamera.Location.X}, {ActiveCamera.Location.Y}, {ActiveCamera.Location.Z}\n(yaw: {ActiveCamera.Yaw} pitch: {ActiveCamera.Pitch})"; fpsLabel.Text = $"FPS: {Math.Round(1f / deltaTime)}"; //Animate light position var lightPos = ActiveCamera.Location; var cameraLeft = new Vector3((float)Math.Cos(ActiveCamera.Yaw + MathHelper.PiOver2), (float)Math.Sin(ActiveCamera.Yaw + MathHelper.PiOver2), 0); lightPos += cameraLeft * 200 * (float)Math.Sin(PreciseTimer.Elapsed.TotalSeconds * 2); // Get animation matrices var animationMatrices = new float[Skeleton.Bones.Length * 16]; for (var i = 0; i < Skeleton.Bones.Length; i++) { // Default to identity matrices animationMatrices[i * 16] = 1.0f; animationMatrices[(i * 16) + 5] = 1.0f; animationMatrices[(i * 16) + 10] = 1.0f; animationMatrices[(i * 16) + 15] = 1.0f; } if (Animations.Count > 0) { animationMatrices = ActiveAnimation.GetAnimationMatricesAsArray((float)PreciseTimer.Elapsed.TotalSeconds, Skeleton); //Update animation texture GL.BindTexture(TextureTarget.Texture2D, AnimationTexture); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba32f, 4, Skeleton.Bones.Length, 0, PixelFormat.Rgba, PixelType.Float, animationMatrices); GL.BindTexture(TextureTarget.Texture2D, 0); } GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); var prevShader = -1; var prevMaterial = string.Empty; //var sw = System.Diagnostics.Stopwatch.StartNew(); foreach (var obj in MeshesToRender) { var objChanged = true; foreach (var call in obj.DrawCalls) { int uniformLocation; if (call.Shader.Program != prevShader) { objChanged = true; prevShader = call.Shader.Program; GL.UseProgram(call.Shader.Program); uniformLocation = call.Shader.GetUniformLocation("vLightPosition"); GL.Uniform3(uniformLocation, lightPos); uniformLocation = call.Shader.GetUniformLocation("vEyePosition"); GL.Uniform3(uniformLocation, ActiveCamera.Location); uniformLocation = call.Shader.GetUniformLocation("projection"); var matrix = ActiveCamera.ProjectionMatrix; GL.UniformMatrix4(uniformLocation, false, ref matrix); uniformLocation = call.Shader.GetUniformLocation("modelview"); matrix = ActiveCamera.CameraViewMatrix; GL.UniformMatrix4(uniformLocation, false, ref matrix); uniformLocation = call.Shader.GetUniformLocation("bAnimated"); if (uniformLocation != -1) { GL.Uniform1(uniformLocation, Animations.Count == 0 ? 0.0f : 1.0f); } //Push animation texture to the shader (if it supports it) if (Animations.Count > 0) { uniformLocation = call.Shader.GetUniformLocation("animationTexture"); if (uniformLocation != -1) { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, AnimationTexture); GL.Uniform1(uniformLocation, 0); } uniformLocation = call.Shader.GetUniformLocation("fNumBones"); if (uniformLocation != -1) { var v = (float)Math.Max(1, Skeleton.Bones.Length - 1); GL.Uniform1(uniformLocation, v); } } } // Stupidly hacky if (objChanged) { objChanged = false; prevMaterial = string.Empty; var transform = obj.Transform; uniformLocation = call.Shader.GetUniformLocation("transform"); GL.UniformMatrix4(uniformLocation, false, ref transform); uniformLocation = call.Shader.GetUniformLocation("m_vTintColorSceneObject"); if (uniformLocation > -1) { GL.Uniform4(uniformLocation, obj.TintColor); } } GL.BindVertexArray(call.VertexArrayObject); uniformLocation = call.Shader.GetUniformLocation("m_vTintColorDrawCall"); if (uniformLocation > -1) { GL.Uniform3(uniformLocation, call.TintColor); } if (call.Material.Parameters.Name != prevMaterial) { prevMaterial = call.Material.Parameters.Name; //Start at 1, texture unit 0 is reserved for the animation texture var textureUnit = 1; foreach (var texture in call.Material.Textures) { uniformLocation = call.Shader.GetUniformLocation(texture.Key); if (uniformLocation > -1) { GL.ActiveTexture(TextureUnit.Texture0 + textureUnit); GL.BindTexture(TextureTarget.Texture2D, texture.Value); GL.Uniform1(uniformLocation, textureUnit); textureUnit++; } } foreach (var param in call.Material.Parameters.FloatParams) { uniformLocation = call.Shader.GetUniformLocation(param.Key); if (uniformLocation > -1) { GL.Uniform1(uniformLocation, param.Value); } } foreach (var param in call.Material.Parameters.VectorParams) { uniformLocation = call.Shader.GetUniformLocation(param.Key); if (uniformLocation > -1) { GL.Uniform4(uniformLocation, new Vector4(param.Value.X, param.Value.Y, param.Value.Z, param.Value.W)); } } var alpha = 0f; if (call.Material.Parameters.IntParams.ContainsKey("F_ALPHA_TEST") && call.Material.Parameters.IntParams["F_ALPHA_TEST"] == 1 && call.Material.Parameters.FloatParams.ContainsKey("g_flAlphaTestReference")) { alpha = call.Material.Parameters.FloatParams["g_flAlphaTestReference"]; } var alphaReference = call.Shader.GetUniformLocation("g_flAlphaTestReference"); GL.Uniform1(alphaReference, alpha); /* * if (call.Material.IntParams.ContainsKey("F_TRANSLUCENT") && call.Material.IntParams["F_TRANSLUCENT"] == 1) * { * GL.Enable(EnableCap.Blend); * GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); * } * else * { * GL.Disable(EnableCap.Blend); * } */ } GL.DrawElements(call.PrimitiveType, call.IndexCount, call.IndiceType, (IntPtr)call.StartIndex); } } //sw.Stop(); Console.WriteLine("{0} {1}", sw.Elapsed, sw.ElapsedTicks); // Only needed when debugging if something doesnt work, causes high CPU /* * var error = GL.GetError(); * * if (error != ErrorCode.NoError) * { * Console.WriteLine(error); * } */ #if DEBUG Debug.Reset(); //DebugDrawSkeleton(); Debug.Draw(ActiveCamera, false); #endif meshControl.SwapBuffers(); meshControl.Invalidate(); }
private void MeshControl_Paint(object sender, PaintEventArgs e) { if (!Loaded) { return; } ActiveCamera.Tick(); //Animate light position var lightPos = ActiveCamera.Location; var cameraLeft = new Vector3((float)Math.Cos(ActiveCamera.Yaw + MathHelper.PiOver2), (float)Math.Sin(ActiveCamera.Yaw + MathHelper.PiOver2), 0); lightPos += cameraLeft * 200 * (float)Math.Sin(Environment.TickCount / 500.0); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); foreach (var call in drawCalls) { //Bind shader GL.UseProgram(call.Shader); //Set shader uniforms var transformLoc = GL.GetUniformLocation(call.Shader, "projection"); GL.UniformMatrix4(transformLoc, false, ref ActiveCamera.ProjectionMatrix); var modelviewLoc = GL.GetUniformLocation(call.Shader, "modelview"); GL.UniformMatrix4(modelviewLoc, false, ref ActiveCamera.CameraViewMatrix); var lightPosAttrib = GL.GetUniformLocation(call.Shader, "vLightPosition"); GL.Uniform3(lightPosAttrib, lightPos); var eyePosAttrib = GL.GetUniformLocation(call.Shader, "vEyePosition"); GL.Uniform3(eyePosAttrib, ActiveCamera.Location); //Bind VAO GL.BindVertexArray(call.VertexArrayObject); //Set shader texture samplers //Color texture TryToBindTexture(call.Shader, 0, "colorTexture", call.MaterialID); if (call.Material.TextureIDs.ContainsKey("g_tNormal")) { //Bind normal texture TryToBindTexture(call.Shader, 1, "normalTexture", call.Material.TextureIDs["g_tNormal"]); } if (call.Material.TextureIDs.ContainsKey("g_tMasks1")) { //Bind mask 1 texture TryToBindTexture(call.Shader, 2, "mask1Texture", call.Material.TextureIDs["g_tMasks1"]); } if (call.Material.TextureIDs.ContainsKey("g_tMasks2")) { //Bind mask 2 texture TryToBindTexture(call.Shader, 3, "mask2Texture", call.Material.TextureIDs["g_tMasks2"]); } if (call.Material.TextureIDs.ContainsKey("g_tDiffuseWarp")) { //Bind diffuse warp texture TryToBindTexture(call.Shader, 4, "diffuseWarpTexture", call.Material.TextureIDs["g_tDiffuseWarp"]); } GL.DrawElements(call.PrimitiveType, (int)call.IndexCount, call.IndiceType, IntPtr.Zero); } // Only needed when debugging if something doesnt work, causes high CPU /* * var error = GL.GetError(); * * if (error != ErrorCode.NoError) * { * Console.WriteLine(error); * } */ meshControl.SwapBuffers(); meshControl.Invalidate(); }