/// <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); }
private static void ClampVectorComponents(ref Vector4 v) { v.X = MathF.Clamp01(v.X); v.Y = MathF.Clamp01(v.Y); v.Z = MathF.Clamp01(v.Z); v.W = MathF.Clamp01(v.W); }
[Test] public void Clamp01Checks() { Assert.AreEqual(MathF.Clamp01(-0.0f), 0.0f, Epsilon); Assert.AreEqual(MathF.Clamp01(0.0f), 0.0f, Epsilon); Assert.AreEqual(MathF.Clamp01(0.001f), 0.001f, Epsilon); Assert.AreEqual(MathF.Clamp01(1.0001f), 1.0f, Epsilon); Assert.AreEqual(MathF.Clamp01(1.0f), 1.0f, Epsilon); Assert.AreEqual(MathF.Clamp01(0.999f), 0.999f, Epsilon); Assert.AreEqual(MathF.Clamp01(0.567f), 0.567f, Epsilon); }
public override float GetAtten(Vector3 targetPosition) { // θ,片元指向光源的方向与聚光灯朝向的夹角(cos) float cosTheta = Vector3.Dot(-GetDirection(targetPosition).normlize, spotDir.normlize); // Epsilon是内外圆锥的余弦差值 float epsilon = cosInnerAngle - cosPhi; // 聚光灯强度 float intensity = MathF.Clamp01((cosTheta - cosPhi) / epsilon); return(intensity); }
public override void Draw(IDrawDevice device) { if (_sprites == null) { return; } float warpTime = MathF.Max(MinWarpTime, WarpTime); float chargeTime = MathF.Max(MinChargeTime, ChargeTime); if (ElapsedTime < chargeTime) { float alpha = MathF.Clamp01(ElapsedTime / chargeTime); foreach (var sprite in _sprites) { SpriteGlowEffect.RenderSpriteGlow(device, sprite, GlowType.Position | GlowType.Scale, 1.1f, 10f, Color.WithAlpha(alpha), DrawTechnique.Res, -100); } foreach (var geom in _geometries) { SpriteGlowEffect.RenderSpriteGlow(device, geom, GlowType.Position | GlowType.Scale, 1.1f, 10f, Color.WithAlpha(alpha), DrawTechnique.Res, -100); } } else if (ElapsedTime >= chargeTime && ElapsedTime <= chargeTime + warpTime) { foreach (var spr in _sprites) { spr.Active = false; } var vel = 100f; var vector = Ship.Transform.GetWorldVector(new Vector2(vel, 0)); var rb = Ship.GetComponent <RigidBody>(); rb.Active = false; //rb.ApplyLocalForce(vector * rb.Mass); Ship.Transform.Pos += new Vector3(vector, Ship.Transform.Pos.Z); float alpha = 1f - MathF.Clamp01((ElapsedTime - chargeTime) / warpTime); foreach (var sprite in _sprites) { SpriteGlowEffect.RenderSpriteGlow(device, sprite, GlowType.Position | GlowType.Scale, 1.1f, 10f, Color.WithAlpha(alpha), DrawTechnique.Res, -100); } foreach (var geom in _geometries) { SpriteGlowEffect.RenderSpriteGlow(device, geom, GlowType.Position | GlowType.Scale, 1.1f, 10f, Color.WithAlpha(alpha), DrawTechnique.Res, -100); } } else { _isWarpDone = true; } ElapsedTime += Time.DeltaTime; }
/// <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); }