public static MatrixMultiply ( float lhs, float rhs ) : float[] | ||
lhs | float | |
rhs | float | |
Résultat | float[] |
public float[] TransformationMatrix(uint limb, uint frame) { if (frame >= Frames) { throw new ArgumentOutOfRangeException("frame", "Only {0} frames exist.".F(Frames)); } if (limb >= Limbs) { throw new ArgumentOutOfRangeException("limb", "Only {1} limbs exist.".F(Limbs)); } var l = limbData[limb]; var t = new float[16]; Array.Copy(transforms, 16 * (Limbs * frame + limb), t, 0, 16); // Fix limb position t[12] *= l.Scale * (l.Bounds[3] - l.Bounds[0]) / l.Size[0]; t[13] *= l.Scale * (l.Bounds[4] - l.Bounds[1]) / l.Size[1]; t[14] *= l.Scale * (l.Bounds[5] - l.Bounds[2]) / l.Size[2]; // Center, flip and scale t = Util.MatrixMultiply(t, Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2])); t = Util.MatrixMultiply(Util.ScaleMatrix(l.Scale, -l.Scale, l.Scale), t); return(t); }
public void RenderDebugGeometry(WorldRenderer wr) { var pxOrigin = wr.ScreenPosition(pos); var groundZ = 0.5f * (pxOrigin.Y - wr.ScreenZPosition(pos, 0)); var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1)); // Draw sprite rect var offset = pxOrigin + renderProxy.Sprite.offset - 0.5f * renderProxy.Sprite.size; Game.Renderer.WorldLineRenderer.DrawRect(offset, offset + renderProxy.Sprite.size, Color.Red); // Draw transformed shadow sprite rect var c = Color.Purple; var psb = renderProxy.ProjectedShadowBounds; Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[1], shadowOrigin + psb[3], c, c); Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[3], shadowOrigin + psb[0], c, c); Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[0], shadowOrigin + psb[2], c, c); Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[2], shadowOrigin + psb[1], c, c); // Draw voxel bounding box var draw = voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); var scaleTransform = Util.ScaleMatrix(scale, scale, scale); var cameraTransform = Util.MakeFloatMatrix(camera.AsMatrix()); foreach (var v in draw) { var bounds = v.Voxel.Bounds(v.FrameFunc()); var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, (x, y) => Util.MatrixMultiply(x, Util.MakeFloatMatrix(y.AsMatrix()))); var pxOffset = wr.ScreenVector(v.OffsetFunc()); var pxPos = pxOrigin + new float2(pxOffset[0], pxOffset[1]); var screenTransform = Util.MatrixMultiply(cameraTransform, worldTransform); DrawBoundsBox(pxPos, screenTransform, bounds, Color.Yellow); } }
public ModelRenderProxy RenderAsync( WorldRenderer wr, IEnumerable <ModelAnimation> models, WRot camera, float scale, float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadowPalette) { if (!isInFrame) { throw new InvalidOperationException("BeginFrame has not been called. You cannot render until a frame has been started."); } // Correct for inverted y-axis var scaleTransform = Util.ScaleMatrix(scale, scale, scale); // Correct for bogus light source definition var lightYaw = Util.MakeFloatMatrix(new WRot(WAngle.Zero, WAngle.Zero, -lightSource.Yaw).AsMatrix()); var lightPitch = Util.MakeFloatMatrix(new WRot(WAngle.Zero, -lightSource.Pitch, WAngle.Zero).AsMatrix()); var shadowTransform = Util.MatrixMultiply(lightPitch, lightYaw); var invShadowTransform = Util.MatrixInverse(shadowTransform); var cameraTransform = Util.MakeFloatMatrix(camera.AsMatrix()); var invCameraTransform = Util.MatrixInverse(cameraTransform); if (invCameraTransform == null) { throw new InvalidOperationException("Failed to invert the cameraTransform matrix during RenderAsync."); } // Sprite rectangle var tl = new float2(float.MaxValue, float.MaxValue); var br = new float2(float.MinValue, float.MinValue); // Shadow sprite rectangle var stl = new float2(float.MaxValue, float.MaxValue); var sbr = new float2(float.MinValue, float.MinValue); foreach (var m in models) { // Convert screen offset back to world coords var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var worldTransform = m.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); var bounds = m.Model.Bounds(m.FrameFunc()); var worldBounds = Util.MatrixAABBMultiply(worldTransform, bounds); var screenBounds = Util.MatrixAABBMultiply(cameraTransform, worldBounds); var shadowBounds = Util.MatrixAABBMultiply(shadowTransform, worldBounds); // Aggregate bounds rects tl = float2.Min(tl, new float2(screenBounds[0], screenBounds[1])); br = float2.Max(br, new float2(screenBounds[3], screenBounds[4])); stl = float2.Min(stl, new float2(shadowBounds[0], shadowBounds[1])); sbr = float2.Max(sbr, new float2(shadowBounds[3], shadowBounds[4])); } // Inflate rects to ensure rendering is within bounds tl -= SpritePadding; br += SpritePadding; stl -= SpritePadding; sbr += SpritePadding; // Corners of the shadow quad, in shadow-space var corners = new float[][] { new[] { stl.X, stl.Y, 0, 1 }, new[] { sbr.X, sbr.Y, 0, 1 }, new[] { sbr.X, stl.Y, 0, 1 }, new[] { stl.X, sbr.Y, 0, 1 } }; var shadowScreenTransform = Util.MatrixMultiply(cameraTransform, invShadowTransform); var shadowGroundNormal = Util.MatrixVectorMultiply(shadowTransform, groundNormal); var screenCorners = new float3[4]; for (var j = 0; j < 4; j++) { // Project to ground plane corners[j][2] = -(corners[j][1] * shadowGroundNormal[1] / shadowGroundNormal[2] + corners[j][0] * shadowGroundNormal[0] / shadowGroundNormal[2]); // Rotate to camera-space corners[j] = Util.MatrixVectorMultiply(shadowScreenTransform, corners[j]); screenCorners[j] = new float3(corners[j][0], corners[j][1], 0); } // Shadows are rendered at twice the resolution to reduce artifacts Size spriteSize, shadowSpriteSize; int2 spriteOffset, shadowSpriteOffset; CalculateSpriteGeometry(tl, br, 1, out spriteSize, out spriteOffset); CalculateSpriteGeometry(stl, sbr, 2, out shadowSpriteSize, out shadowSpriteOffset); if (sheetBuilderForFrame == null) { sheetBuilderForFrame = new SheetBuilder(SheetType.BGRA, AllocateSheet); } var sprite = sheetBuilderForFrame.Allocate(spriteSize, 0, spriteOffset); var shadowSprite = sheetBuilderForFrame.Allocate(shadowSpriteSize, 0, shadowSpriteOffset); var sb = sprite.Bounds; var ssb = shadowSprite.Bounds; var spriteCenter = new float2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2); var shadowCenter = new float2(ssb.Left + ssb.Width / 2, ssb.Top + ssb.Height / 2); var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0); var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0); var correctionTransform = Util.MatrixMultiply(translateMtx, FlipMtx); var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx); doRender.Add(Pair.New <Sheet, Action>(sprite.Sheet, () => { foreach (var m in models) { // Convert screen offset to world offset var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var rotations = m.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); var worldTransform = Util.MatrixMultiply(scaleTransform, rotations); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); var transform = Util.MatrixMultiply(cameraTransform, worldTransform); transform = Util.MatrixMultiply(correctionTransform, transform); var shadow = Util.MatrixMultiply(shadowTransform, worldTransform); shadow = Util.MatrixMultiply(shadowCorrectionTransform, shadow); var lightTransform = Util.MatrixMultiply(Util.MatrixInverse(rotations), invShadowTransform); var frame = m.FrameFunc(); for (uint i = 0; i < m.Model.Sections; i++) { var rd = m.Model.RenderData(i); var t = m.Model.TransformationMatrix(i, frame); var it = Util.MatrixInverse(t); if (it == null) { throw new InvalidOperationException("Failed to invert the transformed matrix of frame {0} during RenderAsync.".F(i)); } // Transform light vector from shadow -> world -> limb coords var lightDirection = ExtractRotationVector(Util.MatrixMultiply(it, lightTransform)); Render(rd, wr.World.ModelCache, Util.MatrixMultiply(transform, t), lightDirection, lightAmbientColor, lightDiffuseColor, color.TextureMidIndex, normals.TextureMidIndex); // Disable shadow normals by forcing zero diffuse and identity ambient light if (m.ShowShadow) { Render(rd, wr.World.ModelCache, Util.MatrixMultiply(shadow, t), lightDirection, ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex); } } } })); var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, ZVector); screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector); return(new ModelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1])); }
public VoxelRenderProxy RenderAsync(WorldRenderer wr, IEnumerable <VoxelAnimation> voxels, WRot camera, float scale, float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadowPalette) { // Correct for inverted y-axis var scaleTransform = Util.ScaleMatrix(scale, scale, scale); // Correct for bogus light source definition var lightYaw = Util.MakeFloatMatrix(new WRot(WAngle.Zero, WAngle.Zero, -lightSource.Yaw).AsMatrix()); var lightPitch = Util.MakeFloatMatrix(new WRot(WAngle.Zero, -lightSource.Pitch, WAngle.Zero).AsMatrix()); var shadowTransform = Util.MatrixMultiply(lightPitch, lightYaw); var invShadowTransform = Util.MatrixInverse(shadowTransform); var cameraTransform = Util.MakeFloatMatrix(camera.AsMatrix()); var invCameraTransform = Util.MatrixInverse(cameraTransform); // Sprite rectangle var tl = new float2(float.MaxValue, float.MaxValue); var br = new float2(float.MinValue, float.MinValue); // Shadow sprite rectangle var stl = new float2(float.MaxValue, float.MaxValue); var sbr = new float2(float.MinValue, float.MinValue); foreach (var v in voxels) { // Convert screen offset back to world coords var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(v.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var worldTransform = v.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); var bounds = v.Voxel.Bounds(v.FrameFunc()); var worldBounds = Util.MatrixAABBMultiply(worldTransform, bounds); var screenBounds = Util.MatrixAABBMultiply(cameraTransform, worldBounds); var shadowBounds = Util.MatrixAABBMultiply(shadowTransform, worldBounds); // Aggregate bounds rects tl = float2.Min(tl, new float2(screenBounds[0], screenBounds[1])); br = float2.Max(br, new float2(screenBounds[3], screenBounds[4])); stl = float2.Min(stl, new float2(shadowBounds[0], shadowBounds[1])); sbr = float2.Max(sbr, new float2(shadowBounds[3], shadowBounds[4])); } // Inflate rects to ensure rendering is within bounds tl -= spritePadding; br += spritePadding; stl -= spritePadding; sbr += spritePadding; // Corners of the shadow quad, in shadow-space var corners = new float[][] { new float[] { stl.X, stl.Y, 0, 1 }, new float[] { sbr.X, sbr.Y, 0, 1 }, new float[] { sbr.X, stl.Y, 0, 1 }, new float[] { stl.X, sbr.Y, 0, 1 } }; var shadowScreenTransform = Util.MatrixMultiply(cameraTransform, invShadowTransform); var shadowGroundNormal = Util.MatrixVectorMultiply(shadowTransform, groundNormal); var screenCorners = new float2[4]; for (var j = 0; j < 4; j++) { // Project to ground plane corners[j][2] = -(corners[j][1] * shadowGroundNormal[1] / shadowGroundNormal[2] + corners[j][0] * shadowGroundNormal[0] / shadowGroundNormal[2]); // Rotate to camera-space corners[j] = Util.MatrixVectorMultiply(shadowScreenTransform, corners[j]); screenCorners[j] = new float2(corners[j][0], corners[j][1]); } // Shadows are rendered at twice the resolution to reduce artefacts Size spriteSize, shadowSpriteSize; int2 spriteOffset, shadowSpriteOffset; CalculateSpriteGeometry(tl, br, 1, out spriteSize, out spriteOffset); CalculateSpriteGeometry(stl, sbr, 2, out shadowSpriteSize, out shadowSpriteOffset); var sprite = sheetBuilder.Allocate(spriteSize, spriteOffset); var shadowSprite = sheetBuilder.Allocate(shadowSpriteSize, shadowSpriteOffset); var sb = sprite.bounds; var ssb = shadowSprite.bounds; var spriteCenter = new float2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2); var shadowCenter = new float2(ssb.Left + ssb.Width / 2, ssb.Top + ssb.Height / 2); var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, Renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0); var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, Renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0); var correctionTransform = Util.MatrixMultiply(translateMtx, flipMtx); var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, shadowScaleFlipMtx); doRender.Add(Pair.New <Sheet, Action>(sprite.sheet, () => { foreach (var v in voxels) { // Convert screen offset to world offset var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(v.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var rotations = v.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); var worldTransform = Util.MatrixMultiply(scaleTransform, rotations); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); var transform = Util.MatrixMultiply(cameraTransform, worldTransform); transform = Util.MatrixMultiply(correctionTransform, transform); var shadow = Util.MatrixMultiply(shadowTransform, worldTransform); shadow = Util.MatrixMultiply(shadowCorrectionTransform, shadow); var lightTransform = Util.MatrixMultiply(Util.MatrixInverse(rotations), invShadowTransform); var frame = v.FrameFunc(); for (uint i = 0; i < v.Voxel.Limbs; i++) { var rd = v.Voxel.RenderData(i); var t = v.Voxel.TransformationMatrix(i, frame); // Transform light vector from shadow -> world -> limb coords var lightDirection = ExtractRotationVector(Util.MatrixMultiply(Util.MatrixInverse(t), lightTransform)); Render(rd, Util.MatrixMultiply(transform, t), lightDirection, lightAmbientColor, lightDiffuseColor, color.Index, normals.Index); // Disable shadow normals by forcing zero diffuse and identity ambient light Render(rd, Util.MatrixMultiply(shadow, t), lightDirection, shadowAmbient, shadowDiffuse, shadowPalette.Index, normals.Index); } } })); var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, zVector); screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector); return(new VoxelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1])); }