public override void PaintRenderTextureUvSpace(PaintCommand.UV command)//PlaytimePainter painter, Brush br, Stroke st) { Brush br = command.Brush; Stroke st = command.Stroke; var id = command.TextureData; BeforeStroke(command); var deltaUv = st.DeltaUv; //uv - st.uvFrom;//.Previous_uv; var magnitude = deltaUv.magnitude; var width = br.Size(false) / id.width * 4; var trackPortion = (deltaUv.magnitude - width * 0.5f) * 0.25f; if (!(trackPortion > 0) && !st.MouseUpEvent) { return; } if (st.firstStroke) { previousDirectionLazy = st.previousDelta = deltaUv; _lazySpeedDynamic = deltaUv.magnitude; _lazyAngleSmoothed = 0; // Debug.Log("First stroke"); } var angle = Mathf.Deg2Rad * Vector2.Angle(st.previousDelta, deltaUv); var smooth = angle < Mathf.PI * 0.5f; if (st.CrossedASeam() && (magnitude > previousDirectionLazy.magnitude * 8)) { // Debug.Log("Crossed a seam"); st.MouseUpEvent = true; st.uvTo = st.uvFrom; // painter.Previous_uv; deltaUv = Vector2.zero; smooth = false; } previousDirectionLazy = deltaUv; if (!st.MouseUpEvent) { if (smooth) { var clockwise = Vector3.Cross(st.previousDelta, deltaUv).z > 0 ? 1f : -1f; var sin = Mathf.Sin(angle) * clockwise; float maxSinus = 8; _lazyAngleSmoothed = Mathf.Abs(_lazyAngleSmoothed) > Mathf.Abs(sin) ? sin : Mathf.Lerp(_lazyAngleSmoothed, sin, 0.2f); sin = _lazyAngleSmoothed; if ((sin * sin > maxSinus * maxSinus) || ((sin > 0) != (maxSinus > 0))) { var absSin = Mathf.Abs(sin); var absNSin = Mathf.Abs(maxSinus); if (absSin < absNSin) { maxSinus = maxSinus * absSin / absNSin; } st.uvTo = st.uvFrom + st.previousDelta.normalized.Rotate_Radians(maxSinus * clockwise) * trackPortion; _lazySpeedDynamic = trackPortion; } else { _lazySpeedDynamic = Mathf.Min(deltaUv.magnitude * 0.5f, Mathf.Lerp(_lazySpeedDynamic, deltaUv.magnitude * 0.5f, 0.001f)); _lazySpeedDynamic = Mathf.Max(trackPortion, _lazySpeedDynamic); st.uvTo = st.uvFrom + st.previousDelta.normalized.Rotate_Radians(sin) * _lazySpeedDynamic; } } else { _lazySpeedDynamic = deltaUv.magnitude; _lazyAngleSmoothed = 0; st.uvTo = st.uvFrom + deltaUv.normalized * trackPortion; } } var r = TexMGMT; var meshWidth = br.StrokeWidth(id.width, false); var tf = RtBrush; var direction = st.DeltaUv; var isTail = st.firstStroke; // bool alphaBuffer; if (!isTail && !smooth) { var st2 = new Stroke(st) { firstStroke = false }; r.SHADER_STROKE_SEGMENT_UPDATE(command);//br, br.Speed * 0.05f, id, st2, out alphaBuffer, painter); Vector3 junkPoint = st.uvFrom + st.previousDelta * 0.01f; BrushMesh = PainterCamera.BrushMeshGenerator.GetStreak(UvToPosition(st.uvFrom), UvToPosition(junkPoint), meshWidth, true, false); tf.localScale = Vector3.one; tf.localRotation = Quaternion.identity; tf.localPosition = new Vector3(0, 0, 10); r.Render(); st.uvFrom = junkPoint; isTail = true; } command.strokeAlphaPortion = Mathf.Clamp01(br.Flow * 0.05f); r.SHADER_STROKE_SEGMENT_UPDATE(command);//br, br.Speed * 0.05f, id, st, out alphaBuffer, painter); BrushMesh = PainterCamera.BrushMeshGenerator.GetStreak(UvToPosition(st.uvFrom), UvToPosition(st.uvTo), meshWidth, st.MouseUpEvent, isTail); tf.localScale = Vector3.one; tf.localRotation = Quaternion.identity; tf.localPosition = new Vector3(0, 0, 10); st.previousDelta = direction; r.Render(); AfterStroke(command); //painter, br, st, alphaBuffer, id); }
public override void PaintRenderTextureUvSpace(PaintCommand.UV command) //PlaytimePainter painter, Brush br, Stroke st) { Brush br = command.Brush; Stroke st = command.Stroke; BeforeStroke(command); var id = command.TextureData; if (st.firstStroke || br.decalContentious) { if (br.rotationMethod == RotationMethod.FaceStrokeDirection) { var delta = st.uvTo - _previousUv; var portion = Mathf.Clamp01(delta.magnitude * id.width * 4 / br.Size(false)); var newAngle = Vector2.SignedAngle(Vector2.up, delta) + br.decalAngleModifier; br.decalAngle = Mathf.LerpAngle(br.decalAngle, newAngle, portion); _previousUv = st.uvTo; } command.strokeAlphaPortion = 1; TexMGMT.SHADER_STROKE_SEGMENT_UPDATE(command); // br, 1, id, st, out alphaBuffer, command.painter); var tf = RtBrush; tf.localScale = Vector3.one * br.Size(false); tf.localRotation = Quaternion.Euler(new Vector3(0, 0, br.decalAngle)); BrushMesh = PainterCamera.BrushMeshGenerator.GetQuad(); st.uvTo = st.uvTo.To01Space(); var deltaUv = st.DeltaUv; var uv = st.uvTo; if (br.rotationMethod == RotationMethod.FaceStrokeDirection && !st.firstStroke) { var length = Mathf.Max(deltaUv.magnitude * 2 * id.width / br.Size(false), 1); var scale = tf.localScale; if ((Mathf.Abs(Mathf.Abs(br.decalAngleModifier) - 90)) < 40) { scale.x *= length; } else { scale.y *= length; } tf.localScale = scale; uv -= deltaUv * ((length - 1) * 0.5f / length); } tf.localPosition = Stroke.BrushWorldPositionFrom(uv); TexMGMT.Render(); AfterStroke(command); } else { command.OnStrokeComplete(); //painter.AfterStroke(st); } }
public virtual void PaintPixelsInRam(PaintCommand.UV command) { Brush br = command.Brush; Stroke st = command.Stroke; var deltaUv = st.uvTo - st.uvFrom; if (deltaUv.magnitude > (0.2f + st.avgBrushSpeed * 3)) { deltaUv = Vector2.zero; // This is made to avoid glitch strokes on seams } else { st.avgBrushSpeed = (st.avgBrushSpeed + deltaUv.magnitude) / 2; } var alpha = Mathf.Clamp01(br.Flow * (Application.isPlaying ? Time.deltaTime : 0.1f)); var id = command.TextureData; var deltaPos = st.DeltaWorldPos; float steps = 1; if (id.disableContiniousLine) { st.uvFrom = st.uvTo; st.posFrom = st.posTo; } else { var uvDist = (deltaUv.magnitude * id.width * 8 / br.Size(false)); var worldDist = st.DeltaWorldPos.magnitude; steps = (int)Mathf.Max(1, IsAWorldSpaceBrush ? worldDist : uvDist); deltaUv /= steps; deltaPos /= steps; st.uvFrom += deltaUv; st.posFrom += deltaPos; } Action <PaintCommand.UV> blitMethod = null; command.strokeAlphaPortion = alpha; var painter = command.TryGetPainter(); foreach (var p in CameraModuleBase.BrushPlugins) { if (p.IsEnabledFor(painter, id, br)) { p.PaintPixelsInRam(command);//st, alpha, id, br, painter); blitMethod = p.PaintPixelsInRam; break; } } if (blitMethod == null) { blitMethod = BlitFunctions.Paint; blitMethod(command); } for (float i = 1; i < steps; i++) { st.uvFrom += deltaUv; st.posFrom += deltaPos; blitMethod(command); } command.OnStrokeComplete();//.AfterStroke(st); }
public static void Paint(RenderTexture renderTexture, Brush br, Stroke st) => _inst.PaintRenderTextureUvSpace(new PaintCommand.UV(st, renderTexture, br));
public void SHADER_STROKE_SEGMENT_UPDATE(PaintCommand.UV command) { Brush bc = command.Brush; TextureMeta id = command.TextureData; Stroke stroke = command.Stroke; CheckPaintingBuffers(); var isDoubleBuffer = !id.renderTexture; var useSingle = !isDoubleBuffer || bc.IsSingleBufferBrush(); var blitMode = bc.GetBlitMode(false); command.usedAlphaBuffer = !useSingle && bc.useAlphaBuffer && bc.GetBrushType(false).SupportsAlphaBufferPainting&& blitMode.SupportsAlphaBufferPainting; var painter = command.TryGetPainter(); Shader shd = null; if (painter) { foreach (var pl in CameraModuleBase.BrushPlugins) { var bs = useSingle ? pl.GetBrushShaderSingleBuffer(painter) : pl.GetBrushShaderDoubleBuffer(painter); if (!bs) { continue; } shd = bs; break; } } if (!shd) { if (command.usedAlphaBuffer) { shd = blitMode.ShaderForAlphaOutput; AlphaBufferSetDirtyBeforeRender(id, blitMode.ShaderForAlphaBufferBlit); } else { shd = useSingle ? blitMode.ShaderForSingleBuffer : blitMode.ShaderForDoubleBuffer; } } if (!useSingle && !RenderTextureBuffersManager.secondBufferUpdated) { RenderTextureBuffersManager.UpdateBufferTwo(); } SHADER_BRUSH_UPDATE(command); TargetTexture = command.usedAlphaBuffer ? AlphaBuffer : id.CurrentRenderTexture(); if (isDoubleBuffer) { PainterShaderVariables.DESTINATION_BUFFER.GlobalValue = BackBuffer; } CurrentShader = shd; }