/// <summary> /// 法线映射 /// </summary> /// <param name="vertex"></param> /// <returns></returns> public Color01 NormalMappingWithLambert(Vertex vertex, Mesh mesh, Light light) { // 从法线贴图中取出法线(切线空间下的) Color01 UndecryptedNormal = Texture.Tex2D(normalTexture, vertex.u, vertex.v); // 把法线从[0,1]区间变回到[-1,1]区间 Vector3 normal = new Vector3( UndecryptedNormal.R * 2 - 1, UndecryptedNormal.G * 2 - 1, UndecryptedNormal.B * 2 - 1 ); // 获得世界坐标下的法线 Vector3 worldNormal = mesh.mMatrix * vertex.normal; worldNormal.Normlize(); // 获得世界坐标下的切线 Vector3 worldTangent = mesh.mMatrix * vertex.tangent; worldTangent.Normlize(); // 获得世界坐标下的副切线 Vector3 worldBinormal = Vector3.Cross(worldNormal, worldTangent) * vertex.tangent.W; worldBinormal.Normlize(); // 构建 切线-世界 变换矩阵 Matrix4x4 TtoW = new Matrix4x4(); TtoW.Identity(); TtoW.value[0, 0] = worldTangent.X; TtoW.value[1, 0] = worldTangent.Y; TtoW.value[2, 0] = worldTangent.Z; TtoW.value[0, 1] = worldBinormal.X; TtoW.value[1, 1] = worldBinormal.Y; TtoW.value[2, 1] = worldBinormal.Z; TtoW.value[0, 2] = worldNormal.X; TtoW.value[1, 2] = worldNormal.Y; TtoW.value[2, 2] = worldNormal.Z; // 将切线空间的法线变为世界坐标 normal = TtoW * normal; normal.Normlize(); // 增大凹凸比例 normal.X *= 3; normal.Y *= 3; normal.Z *= MathF.Sqrt(1 - MathF.Clamp01(normal.X * normal.X + normal.Y * normal.Y)); Color01 albedo = Texture.Tex2D(texture2D, vertex.u, vertex.v) * vertex.color; Vector3 worldPos = mesh.mMatrix * vertex.modelSpacePos; float radiance = Vector3.Dot(normal, light.GetDirection(worldPos)) * 0.5f + 0.5f; Color01 diffuse = albedo * radiance; return(diffuse); }
static private Color01 _grad2(Color01 col1, Color01 col2, double x) { return(new Color01( (col2.R - col1.R) * x + col1.R, (col2.G - col1.G) * x + col1.G, (col2.B - col1.B) * x + col1.B )); }
/// <summary> /// 基于半兰伯特光照模型的光照 /// </summary> /// <param name="vertex"></param> /// <returns></returns> public Color01 LightingWithLambert(Vertex vertex, Mesh mesh, Light light) { // 将顶点的法线变换到世界空间下,对于一个只包含旋转变换的变换矩阵,他是正交矩阵 // 使用m矩阵变换法线(仅适用于只发生旋转的物体) Vector3 worldNormal = mesh.mMatrix * vertex.normal; worldNormal.Normlize(); // 获得顶点当前所在世界坐标 Vector3 worldPos = mesh.mMatrix * vertex.modelSpacePos; // 根据平行光方向及当前法线方向, // 计算当前像素的辐照度 Vector3 lightDirection = light.GetDirection(worldPos); // 使用半兰伯特表达式计算辐照度 float radiance = Vector3.Dot(worldNormal, lightDirection) * 0.5f + 0.5f; // 获得贴图颜色 //Color01 albedo = Texture.Tex2D(texture2D, vertex.u, vertex.v); Color01 albedo = Color01.White; // 使用Blinn-Phong模型计算高光反射 // 获得世界坐标下的视角方向 Vector3 worldViewDir = camera.position - worldPos; // 计算half向量 Vector3 h = (worldViewDir + lightDirection); h.Normlize(); // 光泽度 float gloss = 32f; float spec = Math.Max(0, Vector3.Dot(h, worldNormal)); // 计算高光反射 Color01 specular = lightColor * (float)Math.Pow(spec, gloss); // 计算漫反射光照 Color01 diffuse = albedo * radiance * light.lightColor; Color01 finalColor = diffuse + specular; // 计算光源衰减 finalColor *= light.GetAtten(worldPos); finalColor.A = 1; return(finalColor); }
public SpotLight(float outerAngle, float innerAngle, Vector3 spotDir, Color01 lightColor, Vector3 position) { this.outerAngle = outerAngle; this.cosPhi = (float)Math.Cos(outerAngle * MathF.Deg2Rad); this.spotDir = spotDir; this.innerAngle = innerAngle; this.cosInnerAngle = (float)Math.Cos(innerAngle * MathF.Deg2Rad); this.lightColor = lightColor; this.position = position; }
/// <summary> /// 基于半兰伯特光照模型的光照 /// </summary> /// <param name="vertex"></param> /// <returns></returns> public Color01 LightingWithLambert(Vertex vertex) { // 将顶点的法线变换到世界空间下,对于一个只包含旋转变换的变换矩阵,他是正交矩阵 // 使用m矩阵变换法线(仅适用于只发生旋转的物体) Vector3 worldNormal = vertex.mMatrix * vertex.normal; worldNormal.Normlize(); // 根据平行光方向及当前法线方向, // 计算当前像素的辐照度 //float radiance = Math.Max(0,Vector3.Dot(worldNormal, DirectionLight)); // 使用半兰伯特表达式计算辐照度 float radiance = Vector3.Dot(worldNormal, DirectionLight) * 0.5f + 0.5f; // 获得贴图颜色 Color01 albedo = Texture.Tex2D(texture2D, vertex.u, vertex.v); // 使用Blinn-Phong模型计算高光反射 // 获得顶点当前所在世界坐标 Vector3 worldPos = vertex.mMatrix * vertex.modelSpacePos; // 获得世界坐标下的视角方向 Vector3 worldViewDir = cameraPostion - worldPos; // 计算half向量 Vector3 h = (worldViewDir + DirectionLight); h.Normlize(); // 光泽度 float gloss = 20f; // 计算高光反射 Color01 specular = lightColor * (float)Math.Pow(Math.Max(0, Vector3.Dot(h, worldNormal)), gloss); // 计算漫反射光照 Color01 diffuse = albedo * radiance * lightColor; Color01 finalColor = lightColor * radiance; finalColor.A = 1; return(finalColor); }
private bool GetColorForLog(LogData log, out Color01 color) { switch (log.type) { default: case LogType.VeryVerbose: case LogType.Verbose: case LogType.Info: color = new Color01(0.3f, 0.3f, 0.3f, 0.7f); return(true); case LogType.Warning: color = new Color01(0.3f, 0.3f, 0f, 0.7f); return(true); case LogType.Error: color = new Color01(0.3f, 0f, 0f, 0.7f); return(true); } }
/// <summary> /// 对应任意一种情况的光栅化线段的方法, /// 是Bresenham朴素算法的优化版,不出现浮点运算 /// </summary> /// <param name="x1"></param> /// <param name="y1"></param> /// <param name="x2"></param> /// <param name="y2"></param> /// <param name="color"></param> private void DrawLine(Vertex v1, Vertex v2) { int x1 = (int)v1.pos.X; int y1 = (int)v1.pos.Y; int x2 = (int)v2.pos.X; int y2 = (int)v2.pos.Y; // 线段起点与终点在x轴上的距离(可能为负) int dx = x2 - x1; // 线段起点和终点在y轴上的距离(可能为负) int dy = y2 - y1; // 计算从x1到x2的方向是正方向还是负方向 // 1<<1 = 2; 0<<1 = 0 int stepX = ((dx > 0 ? 1 : 0) << 1) - 1; // 计算从y1到y2的方向是正方向还是负方向 int stepY = ((dy > 0 ? 1 : 0) << 1) - 1; dx = Math.Abs(dx); dy = Math.Abs(dy); // 误差 int eps = 0; if (dx > dy) { int y = y1; // 当x轴距离差更大时,将x作为自增变量 for (int x = x1; x != x2; x += stepX) { float t = (float)(x - x1) / (float)(x2 - x1); // 当前顶点 Vertex vertex = Vertex.LerpVertexData(v1, v2, t); vertex.pos.X = x; vertex.pos.Y = y; float z = vertex.pos.Z; // 对当前像素进行深度测试 if (IsZTest) { if (!ZTest(x, y, z)) { continue; } } // 透视插值矫正 float realZ = 1.0f / z; vertex.u *= realZ; // 变回原来的u vertex.v *= realZ; // 变回原来的v float u = vertex.u; float v = vertex.v; // 对顶点颜色进行插值 Color01 color = Color01.LerpColor(v1.color, v2.color, t); // 对纹理贴图进行采样 Color01 textureColor = Texture.Tex2D(texture2D, u, v); Color01 finalColor = textureColor * color; if (drawingSkyBox) { finalColor = CubeMap.TexCube(skyBox, vertex.modelSpacePos); DrawPixel(x, y, finalColor); } else if (fragmentShaderOn) { // 对所有光源进行着色器计算,然后将所有光源的结果叠加起来 // 即该片元的颜色由所有光源决定 finalColor = Color01.Black; foreach (var light in lights) { finalColor += FragmentShader(vertex, light); } DrawPixel(x, y, finalColor); } else { DrawPixel(x, y, finalColor); } // 增量误差 eps += dy; // 误差大于0.5,那么y++ if ((eps << 1) >= dx) { y += stepY; eps -= dx; } } } else { int x = x1; // 当y轴距离差更大时,将y作为自增变量 for (int y = y1; y != y2; y += stepY) { float t = (float)(y - y1) / (float)(y2 - y1); Color01 color = Color01.LerpColor(v1.color, v2.color, t); DrawPixel(x, y, color); // 增量误差 eps += dx; if ((eps << 1) >= dy) { x += stepX; eps -= dy; } } } }
/// <summary> /// 在后备缓冲区中,对点(x,y)画上一个color的颜色 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="color"></param> private void DrawPixel(int x, int y, Color01 color) { screenBuffer.SetPixel(x, y, color.ToColor()); }
public static void _draw() { var panel = _form.panel; _form.tickLabel.Text = MyStrategy.Universe.World.TickIndex + ""; var drawArea = new Bitmap(panel.Size.Width, panel.Size.Height); panel.Image = drawArea; _graphics = Graphics.FromImage(drawArea); var lookAtSquadId = MyStrategy.SquadCalculator.SquadList.FirstOrDefault(s => s.Id.ToString() == _form.lookAtTextBox.Text.Trim()); if (lookAtSquadId != null) { var centralUnit = lookAtSquadId.CentralUnit; if (centralUnit != null) { LookAt(new Point(centralUnit)); } } #region WarFog // туман войны FillRect(Color.AntiqueWhite, 0, 0, MyStrategy.Universe.World.Width, MyStrategy.Universe.World.Height); foreach (var unit in MyStrategy.Universe.MyUnits.GetEnumeration()) { FillCircle(Color.White, unit.X, unit.Y, unit.VisionRange); } #endregion #region BonusMap var squadData = MyStrategy.BonusCalculator.BonusMapList.FirstOrDefault(s => s.Key.ToString() == _form.lookAtTextBox.Text.Trim()).Value; var bonusMapId = 0; var squadId = 0; int.TryParse(_form.mapIdTextBox.Text.Trim(), out bonusMapId); int.TryParse(_form.lookAtTextBox.Text.Trim(), out squadId); if (squadData != null && bonusMapId < squadData.Count) { if (lookAtSquadId != null) { var tileList = squadData[bonusMapId].GetTileList(); foreach (var tile in tileList) { if (Math.Abs(tile.Value) > Double.Epsilon) { var color01 = new Color01(1, 1 - tile.Value, 1 - tile.Value); FillRect(color01.ToColor(), tile.CenterPosition.X, tile.CenterPosition.Y, tile.Size * 1, tile.Size * 1); if (tile.Value > 0.9999) { FillRect(Color.YellowGreen, tile.CenterPosition.X, tile.CenterPosition.Y, tile.Size * 1, tile.Size * 1); } if (Math.Abs(tile.RealValue) > Double.Epsilon) { DrawText($"{tile.RealValue:f2}", 3, Brushes.Black, tile.CenterPosition.X, tile.CenterPosition.Y); } } } } } if (squadData != null) { foreach (var rays in MyStrategy.BonusCalculator.PossibleRays) { if (rays.Key == squadId) { var maxRay = rays.Value.OrderByDescending(r => r.Value).FirstOrDefault(); foreach (var ray in rays.Value) { var color01 = new Color01(1, 1 - ray.Value, 1 - ray.Value); if (ray.Key == maxRay.Key) { FillCircle(Color.Green, ray.Key.X, ray.Key.Y, 3); } FillCircle(color01.ToColor(), ray.Key.X, ray.Key.Y, 1); } } } } foreach (var squad in MyStrategy.SquadCalculator.SquadList.Where(s => s.IsScout)) { var scoutCenter = squad.SquadCenter; if (scoutCenter != null) { DrawCircle(Color.DeepSkyBlue, scoutCenter.X, scoutCenter.Y, MyStrategy.Universe.Game.FighterVisionRange); } } #endregion #region Facilities foreach (var facility in MyStrategy.Universe.World.Facilities) { Color color = Color.Gray; if (facility.OwnerPlayerId == MyStrategy.Universe.Player.Id) { color = Color.ForestGreen; } if (facility.OwnerPlayerId == MyStrategy.Universe.World.GetOpponentPlayer().Id) { color = Color.OrangeRed; } var size = MyStrategy.Universe.Game.FacilityWidth; FillRect(color, facility.Left + size / 2, facility.Top + size / 2, size / 4, size / 4); DrawText($"{facility.CapturePoints:f0}", 7, Brushes.DarkSlateBlue, facility.Left + size / 2, facility.Top + size / 2); } #endregion #region UnitsDraw foreach (var unit in MyStrategy.Universe.MyUnits.GetEnumeration()) { switch (unit.Type) { case VehicleType.Fighter: DrawUnit(Color.Blue, unit, "F"); break; case VehicleType.Helicopter: DrawUnit(Color.Brown, unit, "H"); break; case VehicleType.Tank: DrawUnit(Color.Red, unit, "T"); break; case VehicleType.Arrv: DrawUnit(Color.Green, unit, "A"); break; case VehicleType.Ifv: DrawUnit(Color.Gray, unit, "I"); break; } } foreach (var unit in MyStrategy.Universe.OppUnits.GetEnumeration()) { switch (unit.Type) { case VehicleType.Fighter: DrawUnit(Color.DodgerBlue, unit, "F"); break; case VehicleType.Helicopter: DrawUnit(Color.SandyBrown, unit, "H"); break; case VehicleType.Tank: DrawUnit(Color.LightPink, unit, "T"); break; case VehicleType.Arrv: DrawUnit(Color.LightGreen, unit, "A"); break; case VehicleType.Ifv: DrawUnit(Color.LightGray, unit, "I"); break; } } #endregion #region Predictions var allRealUnits = MyStrategy.Universe.OppUnits.GetCombinedList(MyStrategy.Universe.MyUnits); foreach (var currectUnit in allRealUnits) { var expectedTickForNextUpdate = MyStrategy.Universe.World.TickIndex; if (currectUnit.PlayerId == MyStrategy.Universe.Player.Id) { var correspondingSquad = MyStrategy.SquadCalculator.SquadList.GetSquadByUnit(currectUnit); if (correspondingSquad == null) { continue; } expectedTickForNextUpdate = MyStrategy.Universe.World.TickIndex + correspondingSquad.ExpectedTicksToNextUpdate; } else { // nearestMyUnit = MyStrategy.Universe.MyUnits. // var correspondingSquad = MyStrategy.SquadCalculator.SquadList.GetSquadByUnit(nearestMyUnit); // expectedTickForNextUpdate = MyStrategy.Universe.World.TickIndex + correspondingSquad.ExpectedTicksToNextUpdate; expectedTickForNextUpdate = MyStrategy.Universe.World.TickIndex + 60; } var predictedState = MyStrategy.Predictor.GetStateOnTick(expectedTickForNextUpdate); var allPredictedUnits = predictedState.OppUnits.GetCombinedList(predictedState.MyUnits); foreach (var predictedUnit in allPredictedUnits) { if (predictedUnit.Id == currectUnit.Id) { var vectorLength = currectUnit.GetDistanceTo(predictedUnit); if (vectorLength > 2) { DrawLine(Color.Gray, currectUnit.X, currectUnit.Y, predictedUnit.X, predictedUnit.Y, 1); } } } } #endregion #region MoveOrders foreach (var order in SquadCalculator.MoveOrders.OrderList) { var unit = MyStrategy.Universe.MyUnits.FirstOrDefault(u => u.Id.Equals(order.Key)); //if (unit.GetDistanceTo(order.Value) > 200) // MyStrategy.Universe.Print("Wrong move order in visual"); if (unit != null) { DrawLine(Color.LightGreen, unit.X, unit.Y, order.Value.X, order.Value.Y, 2); } } #endregion #region NukeStrike foreach (var player in MyStrategy.Universe.World.Players) { var isNukeRequested = player.NextNuclearStrikeTickIndex > 0; var isMe = player.IsMe; var radius = MyStrategy.Universe.Game.TacticalNuclearStrikeRadius; var scout = MyStrategy.Universe.MyUnits.FirstOrDefault(u => u.Id == MyStrategy.SquadCalculator.NukeStrikeScoutId); foreach (var squad in MyStrategy.SquadCalculator.SquadList) { if (squad.NukeMarkerCounter > 0) { DrawCircle(Color.DarkOliveGreen, MyStrategy.SquadCalculator.NukeStrikePosition.X, MyStrategy.SquadCalculator.NukeStrikePosition.Y, radius - 2, 2); DrawCircle(Color.DarkOliveGreen, scout.X, scout.Y, 10, 2); } } if (isNukeRequested) { DrawCircle(isMe? Color.GreenYellow : Color.DeepPink, player.NextNuclearStrikeX, player.NextNuclearStrikeY, radius, 3); } var coolDownValue = player.RemainingNuclearStrikeCooldownTicks; DrawText($"{coolDownValue}", 8, Brushes.Black, isMe ? 500 : 600, 25); } #region Damage if (MyStrategy.Universe.World.TickIndex != 0) { var thisStepUnits = MyStrategy.Predictor.WorldStateList[MyStrategy.Universe.World.TickIndex].MyUnits; var previousStepUnits = MyStrategy.Predictor.WorldStateList[MyStrategy.Universe.World.TickIndex - 1].MyUnits; foreach (var thisStepUnit in thisStepUnits) { foreach (var previousStepUnit in previousStepUnits) { if (thisStepUnit.Durability + Double.Epsilon < previousStepUnit.Durability) { DrawCircle(Color.Yellow, thisStepUnit.X, thisStepUnit.Y, 2.5, 2); } } } thisStepUnits = MyStrategy.Predictor.WorldStateList[MyStrategy.Universe.World.TickIndex].OppUnits; previousStepUnits = MyStrategy.Predictor.WorldStateList[MyStrategy.Universe.World.TickIndex - 1].OppUnits; foreach (var thisStepUnit in thisStepUnits) { foreach (var previousStepUnit in previousStepUnits) { if (thisStepUnit.Durability + Double.Epsilon < previousStepUnit.Durability) { DrawCircle(Color.LightYellow, thisStepUnit.X, thisStepUnit.Y, 2.5, 2); } } } } #endregion #endregion #region SquadSelection var selectedSquad = MyStrategy.SquadCalculator.SquadList.FirstOrDefault(s => s.Id.ToString() == _form.lookAtTextBox.Text.Trim()); if (selectedSquad != null && selectedSquad.Units.Count > 0) { var xMax = selectedSquad.Units.OrderByDescending(u => u.X).FirstOrDefault().X + 5; var xMin = selectedSquad.Units.OrderBy(u => u.X).FirstOrDefault().X - 5; var yMax = selectedSquad.Units.OrderByDescending(u => u.Y).FirstOrDefault().Y + 5; var yMin = selectedSquad.Units.OrderBy(u => u.Y).FirstOrDefault().Y - 5; DrawLine(Color.Aquamarine, xMin, yMin, xMax, yMin, 2); DrawLine(Color.Aquamarine, xMin, yMin, xMin, yMax, 2); DrawLine(Color.Aquamarine, xMax, yMax, xMax, yMin, 2); DrawLine(Color.Aquamarine, xMax, yMax, xMin, yMax, 2); } #endregion #region WorldSelection foreach (var selectedUnit in MyStrategy.Universe.GetSelectedUnits()) { DrawCircle(Color.White, selectedUnit.X, selectedUnit.Y, 2.5); } #endregion //// #region Something // foreach (var seg in RoadsHelper.Roads) // DrawLine(Color.Khaki, seg.A.X, seg.A.Y, seg.B.X, seg.B.Y); // if (_form.gradCheckBox.Checked) // { // var maxDanger = DangerPoints.Max(x => x.Item2); // var minDanger = DangerPoints.Min(x => x.Item2); // // if (maxDanger > Const.Eps) // { // foreach (var t in DangerPoints) // { // var pt = t.Item1; // var danger = t.Item2; // var color = // (danger >= 0 ? _grad(BadColors, 1 - danger/maxDanger) : _grad(GoodColors, danger/minDanger)) // .ToColor(); // FillCircle(color, pt.X, pt.Y, 4); // } // } // } // if (_form.renderCheckBox.Checked) // { // for (var i = 0; i <= MyStrategy.Universe.GridSize; i++) // for (var j = 0; j <= MyStrategy.Universe.GridSize; j++) // FillCircle(Color.Red, MyStrategy.Universe._points[i, j].X, MyStrategy.Universe._points[i, j].Y, 3); // } #endregion #region Statuses // statuses // foreach (var unit in MyStrategy.Universe.MyUnits) // { // if (unit.RemainingFrozen > 0) // FillCircle(Color.SkyBlue, unit.X, unit.Y, unit.Radius - 3); // if (unit.IsBurning) // FillCircle(Color.Orange, unit.X, unit.Y, unit.Radius - 3); // } #endregion #region Wizards // wizards // foreach (var wizard in MyStrategy.Universe.Wizards) // { // var w = MyStrategy.Universe.World.Wizards.FirstOrDefault(x => x.Id == wizard.Id); // var color = w.IsMe ? Color.Red : (wizard.Faction == MyStrategy.Universe.Self.Faction ? Color.Blue : Color.Gold); // // DrawCircle(color, w.X, w.Y, wizard.Radius); // // var d = 7; // for (var i = 0; i < d; i++) // if (wizard.RemainingStaffCooldownTicks >= MyStrategy.Universe.Game.StaffCooldownTicks - d) // DrawCircle(color, w.X, w.Y, wizard.Radius - (d - i)); // // DrawText(w.Life + "", 15, Brushes.Red, wizard.X - 20, wizard.Y - 35); // DrawText(w.Mana + "", 15, Brushes.Blue, wizard.X - 20, wizard.Y - 15); // DrawText(w.Xp + "", 15, Brushes.Green, wizard.X - 20, wizard.Y + 5); // // DrawPie(color, wizard.X, wizard.Y, MyStrategy.Universe.Game.StaffRange, -MyStrategy.Universe.Game.StaffSector / 2.0 + wizard.Angle, MyStrategy.Universe.Game.StaffSector / 2.0 + wizard.Angle); // DrawPie(color, wizard.X, wizard.Y, wizard.CastRange, -MyStrategy.Universe.Game.StaffSector / 2.0 + wizard.Angle, MyStrategy.Universe.Game.StaffSector / 2.0 + wizard.Angle); // // // var statusesStr = ""; // if (wizard.RemainingHastened > 0) // statusesStr += "H"; // if (wizard.RemainingEmpowered > 0) // statusesStr += "E"; // if (wizard.RemainingShielded > 0) // statusesStr += "S"; // // var skillsStr = ""; // for (var i = 0; i < 5; i++) // skillsStr += wizard.SkillsLearnedArr[i]; // // var skillsStr2 = ""; // for (var i = 0; i < 5; i++) // skillsStr2 += wizard.SkillsFactorsArr[i] + wizard.AurasFactorsArr[i]; // // DrawText(statusesStr, 20, Brushes.Coral, wizard.X + 30, wizard.Y - 40); // DrawText(skillsStr, 15, Brushes.Black, wizard.X + 30, wizard.Y - 15); // DrawText(skillsStr2, 15, Brushes.DeepSkyBlue, wizard.X + 30, wizard.Y + 5); // } #endregion #region Minions // minions // foreach (var minion in MyStrategy.Universe.Minions) // { // var color = minion.IsTeammate ? Color.Blue : (minion.Faction == Faction.Neutral ? Color.Fuchsia : Color.DarkOrange); // // DrawCircle(color, minion.X, minion.Y, minion.Radius); // // var to = Point.ByAngle(minion.Angle) * minion.Radius + minion; // DrawLine(color, minion.X, minion.Y, to.X, to.Y, 2); // // if (minion is AOrc) // { // DrawCircle(Color.Black, minion.X, minion.Y, MyStrategy.Universe.Game.OrcWoodcutterAttackRange); // } // // DrawText(minion.Life + "", 15, Brushes.Red, minion.X - 10, minion.Y - 30); // } #endregion #region Trees // trees // foreach (var tree in TreesObserver.Trees) // { // FillCircle(Color.Chartreuse, tree.X, tree.Y, tree.Radius); // } #endregion #region Buildings // buildings // foreach (var building in BuildingsObserver.Buildings) // { // FillCircle(building.IsTeammate ? Color.Blue : Color.DarkOrange, building.X, building.Y, building.Radius); // DrawText(building.Life + "", 15, Brushes.Red, building.X - 10, building.Y - 30); // if (building.IsBesieded) // DrawText("rush", 13, Brushes.Black, building.X - 10, building.Y); // if (building.IsOpponent) // DrawCircle(Color.Red, building.X, building.Y, building.CastRange); // } #endregion #region Bonuses // bonuses // foreach (var bonus in BonusesObserver.Bonuses) // { // var color = bonus.Type == BonusType.Empower // ? Color.Blue // : bonus.Type == BonusType.Haste // ? Color.Aquamarine // : Color.MidnightBlue; // if (bonus.Exists) // FillCircle(color, bonus.X, bonus.Y, bonus.Radius); // else // DrawCircle(color, bonus.X, bonus.Y, bonus.Radius); // } // if (MyStrategy.Universe.NextBonusWaypoint != null) // FillCircle(Color.Red, MyStrategy.Universe.NextBonusWaypoint.X, MyStrategy.Universe.NextBonusWaypoint.Y, 10); #endregion #region MapRanges // map ranges DrawLine(Color.Black, 1, 1, 1, MyStrategy.Universe.World.Height - 1); DrawLine(Color.Black, 1, MyStrategy.Universe.World.Height - 1, MyStrategy.Universe.World.Height - 1, MyStrategy.Universe.World.Height - 1); DrawLine(Color.Black, MyStrategy.Universe.World.Height - 1, 1, MyStrategy.Universe.World.Height - 1, MyStrategy.Universe.World.Height - 1); DrawLine(Color.Black, MyStrategy.Universe.World.Height - 1, 1, 1, 1); #endregion #region MinionSpaws // minions spawns // foreach (var pt in MagicConst.MinionAppearencePoints) // { // FillCircle(Color.Khaki, pt.X, pt.Y, 20); // FillCircle(Color.Khaki, MyStrategy.Universe.World.Height - pt.X, MyStrategy.Universe.World.Height - pt.Y, 20); // } #endregion #region ProjectTiles // projectiles // foreach (var projectile in MyStrategy.Universe.World.Projectiles) // { // var color = projectile.Type == ProjectileType.MagicMissile // ? Color.Blue // : projectile.Type == ProjectileType.Dart // ? Color.Black // : projectile.Type == ProjectileType.FrostBolt // ? Color.SkyBlue // : Color.Gold; // // FillCircle(color, projectile.X, projectile.Y, projectile.Radius); // if (Projectiles.ContainsKey(projectile.Id)) // { // var pts = Projectiles[projectile.Id]; // DrawLine(Color.BlueViolet, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, 3); // } // } #endregion foreach (var seg in SegmentsDrawQueue) { var points = seg[0] as List <Point>; var pen = seg[1] as Pen; float width = seg.Length > 2 ? Convert.ToSingle(seg[2]) : 0F; for (var i = 1; i < points.Count; i++) { DrawLine(pen.Color, points[i].X, points[i].Y, points[i - 1].X, points[i - 1].Y, width); } } }
public PointLight(Vector3 position, float range, Color01 lightColor) { this.position = position; this.range = range; this.lightColor = lightColor; }
public DirectionalLight(Vector3 direction, Color01 color) { this.direction = direction; lightColor = color; }
/// <summary> /// 山寨版片元着色器, /// 根据一个顶点的各属性,计算当前顶点(屏幕空间下)的像素的颜色 /// </summary> /// <param name="vertex"></param> /// <returns></returns> public Color01 FragmentShader(Vertex vertex) { // 基于半兰伯特光照模型的光照 //return LightingWithLambert(vertex); // 从法线贴图中取出法线(切线空间下的) Color01 UndecryptedNormal = Texture.Tex2D(normalTexture, vertex.u, vertex.v); // 把法线从[0,1]区间变回到[-1,1]区间 Vector3 normal = new Vector3( UndecryptedNormal.R * 2 - 1, UndecryptedNormal.G * 2 - 1, UndecryptedNormal.B * 2 - 1 ); // 获得世界坐标下的法线 Vector3 worldNormal = vertex.mMatrix * vertex.normal; worldNormal.Normlize(); // 获得世界坐标下的切线 Vector3 worldTangent = vertex.mMatrix * vertex.tangent; worldTangent.Normlize(); // 获得世界坐标下的副切线 Vector3 worldBinormal = Vector3.Cross(worldNormal, worldTangent) * vertex.tangent.W; worldBinormal.Normlize(); // 构建 切线-世界 变换矩阵 Matrix4x4 TtoW = new Matrix4x4(); TtoW.Identity(); TtoW.value[0, 0] = worldTangent.X; TtoW.value[1, 0] = worldTangent.Y; TtoW.value[2, 0] = worldTangent.Z; TtoW.value[0, 1] = worldBinormal.X; TtoW.value[1, 1] = worldBinormal.Y; TtoW.value[2, 1] = worldBinormal.Z; TtoW.value[0, 2] = worldNormal.X; TtoW.value[1, 2] = worldNormal.Y; TtoW.value[2, 2] = worldNormal.Z; // 将切线空间的法线变为世界坐标 normal = TtoW * normal; normal.Normlize(); // 增大凹凸比例 normal.X *= 3; normal.Y *= 3; normal.Z *= MathF.Sqrt(1 - MathF.Clamp01(normal.X * normal.X + normal.Y * normal.Y)); Color01 albedo = Texture.Tex2D(texture2D, vertex.u, vertex.v); float radiance = Vector3.Dot(normal, DirectionLight) * 0.5f + 0.5f; Color01 diffuse = albedo * radiance; return(diffuse); }