public override void PaintRenderTextureUvSpace(PaintCommand.UV command) { Brush br = command.Brush; Stroke st = command.Stroke; TextureMeta id = command.TextureData; BeforeStroke(command); if (st.CrossedASeam()) { st.uvFrom = st.uvTo; } command.strokeAlphaPortion = Mathf.Clamp01(br.Flow * 0.05f); TexMGMT.SHADER_STROKE_SEGMENT_UPDATE(command);// br, br.Speed * 0.05f, id, st, out alphaBuffer, painter); RtBrush.localScale = Vector3.one * br.StrokeWidth(id.width, false); BrushMesh = PainterCamera.BrushMeshGenerator.GetQuad(); RtBrush.localRotation = Quaternion.identity; RtBrush.localPosition = st.BrushWorldPosition; TexMGMT.Render(); AfterStroke(command);//painter, br, st, alphaBuffer, id); }
public static void Paint(Vector2 uv, Brush br, RenderTexture rt) { var command = new PaintCommand.UV(new Stroke(uv) { firstStroke = false }, rt.GetTextureMeta(), br) { strokeAlphaPortion = Mathf.Clamp01(br.Flow * 0.05f) }; TexMGMT.SHADER_STROKE_SEGMENT_UPDATE(command); // br, br.Speed * 0.05f, id, stroke, out alphaBuffer); float width = br.StrokeWidth(command.TextureData.width, false); RtBrush.localScale = Vector3.one; BrushMesh = PainterCamera.BrushMeshGenerator.GetLongMesh(0, width); RtBrush.localRotation = Quaternion.Euler(new Vector3(0, 0, Vector2.Angle(Vector2.up, Vector2.zero))); RtBrush.localPosition = Stroke.BrushWorldPositionFrom(command.Stroke.uvTo); TexMGMT.Render(); br.GetBrushType(false).AfterStroke(command); }
public virtual void PaintRenderTextureUvSpace(PaintCommand.UV command) { TextureMeta textureMeta = command.TextureData; Brush br = command.Brush; Stroke st = command.Stroke; BeforeStroke(command); if (st.CrossedASeam()) { st.uvFrom = st.uvTo; } command.strokeAlphaPortion = Mathf.Clamp01(br.Flow * 0.05f); TexMGMT.SHADER_STROKE_SEGMENT_UPDATE(command); var rb = RtBrush; rb.localScale = Vector3.one; var direction = st.DeltaUv; var length = direction.magnitude; BrushMesh = PainterCamera.BrushMeshGenerator.GetLongMesh(length * 256, br.StrokeWidth(textureMeta.width, false)); rb.localRotation = Quaternion.Euler(new Vector3(0, 0, (direction.x > 0 ? -1 : 1) * Vector2.Angle(Vector2.up, direction))); rb.localPosition = Stroke.BrushWorldPositionFrom((st.uvFrom + st.uvTo) * 0.5f); TexMGMT.Render(); AfterStroke(command); }
public static void Paint(Vector2 uvCoords, float brushAlpha, Texture2D texture, Vector2 offset, Vector2 tiling, Brush bc) { var id = texture.GetTextureMeta(); id.offset = offset; id.tiling = tiling; var cmd = new PaintCommand.UV(new Stroke(uvCoords), texture.GetTextureMeta(), bc); cmd.strokeAlphaPortion = brushAlpha; Paint(cmd); }
public override void AfterStroke(PaintCommand.UV command) { Brush br = command.Brush; Stroke st = command.Stroke; base.AfterStroke(command); if (br.rotationMethod != RotationMethod.Random) { return; } br.decalAngle = Random.Range(-90f, 450f); OnShaderBrushUpdate(Cfg.Brush); }
public override void PrePaint(PaintCommand.UV paintCommand) //Brush br, Stroke st, PlaytimePainter painter = null) { Stroke st = paintCommand.Stroke; var v4 = new Vector4(st.unRepeatedUv.x, st.unRepeatedUv.y, Mathf.Floor(st.unRepeatedUv.x), Mathf.Floor(st.unRepeatedUv.y)); _pointedUvUnTiledProperty.GlobalValue = v4; if (!st.firstStroke) { return; } if (method == (ColorSetMethod.MDownColor)) { var painter = paintCommand.TryGetPainter(); if (painter) { painter.SampleTexture(st.uvTo); } else { paintCommand.Brush.Color = paintCommand.TextureData.SampleAt(st.uvTo); } FromColor(paintCommand.Brush, st.unRepeatedUv); } else if (method == (ColorSetMethod.MDownPosition)) { FromUv(st.uvTo); } BRUSH_SAMPLING_DISPLACEMENT.GlobalValue = new Vector4( (currentPixel.x + 0.5f) / Cfg.samplingMaskSize.x, (currentPixel.y + 0.5f) / Cfg.samplingMaskSize.y, Cfg.samplingMaskSize.x, Cfg.samplingMaskSize.y); }
public virtual void AfterStroke(PaintCommand.UV command) { PaintCommand.ForPainterComponent painterCommand = command as PaintCommand.ForPainterComponent; Brush br = command.Brush; Stroke st = command.Stroke; TextureMeta id = command.TextureData; command.OnStrokeComplete(); if (br.useMask && st.MouseUpEvent && br.randomMaskOffset) { br.maskOffset = new Vector2(Random.Range(0f, 1f), Random.Range(0f, 1f)); } if (command.usedAlphaBuffer) { var sh = br.GetBlitMode(false).ShaderForAlphaBufferBlit; if (painterCommand == null || painterCommand.painter.NotUsingPreview) { TexMGMT.UpdateFromAlphaBuffer(id.CurrentRenderTexture(), sh); } else { TexMGMT.AlphaBufferSetDirtyBeforeRender(id, sh); } } else if (!br.IsSingleBufferBrush() && !command.Is3DBrush) { TexMGMT.UpdateBufferSegment(); } if (painterCommand != null) { foreach (var p in painterCommand.painter.Modules) { p.AfterGpuStroke(painterCommand); } } }
public void BeforeStroke(PaintCommand.UV command)//Brush br, Stroke st, PlaytimePainter painter = null) { Brush br = command.Brush; Stroke st = command.Stroke; PaintCommand.ForPainterComponent painterCommand = command as PaintCommand.ForPainterComponent; var cam = TexMGMT; if (!RenderTextureBuffersManager.secondBufferUpdated) { RenderTextureBuffersManager.UpdateBufferTwo(); } if (painterCommand != null) { foreach (var p in painterCommand.painter.Modules) { p.BeforeGpuStroke(painterCommand);//br, st, this); } } }
public void Paint(PaintCommand.UV command) { var imgData = command.TextureData; var cpu = command.TextureData.TargetIsTexture2D(); var brushType = GetBrushType(cpu); var blitMode = GetBlitMode(cpu); var isWorldSpace = command.Is3DBrush; var painterCommand = command as PaintCommand.ForPainterComponent; PlaytimePainter painter = painterCommand?.painter; blitMode.PrePaint(command); if (cpu) { if (painter) { foreach (var module in imgData.Modules) { module.OnPainting(painter); } } brushType.PaintPixelsInRam(command); } else { if (painter) { var materialData = painter.MatDta; if (!imgData.renderTexture && !TexMGMT.materialsUsingRenderTexture.Contains(materialData)) { TexMGMT.ChangeBufferTarget(imgData, materialData, painter.GetMaterialTextureProperty(), painter); painter.SetTextureOnMaterial(imgData); } var rendered = false; foreach (var pl in CameraModuleBase.BrushPlugins) { if (pl.IsEnabledFor(painter, imgData, this)) { pl.PaintRenderTextureUvSpace(command); rendered = true; break; } } if (!painter.terrain || brushType.SupportedForTerrainRt) { foreach (var module in imgData.Modules) { module.OnPainting(painter); } if (!rendered) { if (isWorldSpace) { brushType.PaintRenderTextureInWorldSpace(command as PaintCommand.WorldSpace); } else { brushType.PaintRenderTextureUvSpace(command); } } } } else { if (isWorldSpace) { brushType.PaintRenderTextureInWorldSpace(command as PaintCommand.WorldSpace); } else { brushType.PaintRenderTextureUvSpace(command); } } } }
public static void Paint(PaintCommand.UV command) { TextureMeta image = command.TextureData; if (image.Pixels == null) { return; } Brush bc = command.Brush; var uvCoords = command.Stroke.uvFrom; brAlpha = command.strokeAlphaPortion; bc.PrepareCpuBlit(image); var iHalf = (int)(half); Vector2 offset; var tmp = image.UvToPixelNumber(uvCoords, out offset); var smooth = bc.GetBrushType(true) != BrushTypes.Pixel.Inst; if (smooth) { iHalf += 1; offset = Vector2.zero; } var hf = half - 0.5f; var halfFromX = Mathf.RoundToInt(-hf + offset.x); var halfFromY = Mathf.RoundToInt(-hf + offset.y); var halfToX = Mathf.RoundToInt(hf + offset.x); var halfToY = Mathf.RoundToInt(hf + offset.y); var fromX = tmp.x + halfFromX; tmp.y += halfFromY; var pixels = image.Pixels; for (y = halfFromY; y <= halfToY; y++) { tmp.x = fromX; for (x = halfFromX; x <= halfToX; x++) { if (alphaMode()) { blitMode(ref pixels[image.PixelNo(tmp)]); } tmp.x += 1; } tmp.y += 1; } }
public virtual void PrePaint(PaintCommand.UV paintCommand) //Brush br, Stroke st, PlaytimePainter painter = null) { }
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 void SHADER_STROKE_SEGMENT_UPDATE(PaintCommand.UV command) { Brush bc = command.Brush; TextureMeta id = command.TextureData; Stroke stroke = command.Stroke; 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; }
public void SHADER_BRUSH_UPDATE(PaintCommand.UV command) { Brush brush = command.Brush; var id = command.TextureData; var rendTex = id.TargetIsRenderTexture(); var brushType = brush.GetBrushType(!rendTex); var is3DBrush = command.Is3DBrush; #region Brush brush.previewDirty = false; PainterShaderVariables.BrushColorProperty.GlobalValue = brush.Color; PainterShaderVariables.BrushMaskProperty.GlobalValue = brush.mask.ToVector4(); brushType.OnShaderBrushUpdate(brush); if (rendTex) { PainterShaderVariables.SourceMaskProperty.GlobalValue = brush.useMask ? Data.masks.TryGet(brush.selectedSourceMask) : null; } PainterShaderVariables.MaskDynamicsProperty.GlobalValue = new Vector4( brush.maskTiling, rendTex ? brush.hardness * brush.hardness : 0, // y - Hardness is 0 to do correct preview for Texture2D brush ((brush.flipMaskAlpha && brush.useMask) ? 0 : 1), // z - flip mask if any (brush.maskFromGreyscale && brush.useMask) ? 1 : 0); PainterShaderVariables.MaskOffsetProperty.GlobalValue = brush.maskOffset.ToVector4(); float brushSizeUvSpace = brush.Size(is3DBrush) / (id == null ? 256 : Mathf.Min(id.width, id.height)); PainterShaderVariables.BrushFormProperty.GlobalValue = new Vector4( command.strokeAlphaPortion, // x - transparency brush.Size(is3DBrush), // y - scale for sphere brushSizeUvSpace, // z - scale for uv space brush.blurAmount); // w - blur amount #endregion if (id == null) { return; } var blitMode = brush.GetBlitMode(!rendTex); var useAlphaBuffer = (brush.useAlphaBuffer && blitMode.SupportsAlphaBufferPainting && rendTex); float useTransparentLayerBackground = 0; PainterShaderVariables.OriginalTextureTexelSize.GlobalValue = new Vector4( 1f / id.width, 1f / id.height, id.width, id.height ); var painter = command.TryGetPainter(); if (id.isATransparentLayer && painter) { var md = painter.MatDta; var mat = md.material; if (md != null && md.usePreviewShader && mat) { var mt = mat.mainTexture; PainterShaderVariables.TransparentLayerUnderProperty.GlobalValue = mt; useTransparentLayerBackground = (mt && (id != mt.GetImgDataIfExists())) ? 1 : 0; } } PainterShaderVariables.AlphaBufferConfigProperty.GlobalValue = new Vector4( brush.alphaLimitForAlphaBuffer, brush.worldSpaceBrushPixelJitter ? 1 : 0, useAlphaBuffer ? 1 : 0, 0); PainterShaderVariables.AlphaPaintingBuffer.GlobalValue = AlphaBuffer; brushType.SetKeyword(id.useTexCoord2); QcUnity.SetShaderKeyword(PainterShaderVariables.BRUSH_TEXCOORD_2, id.useTexCoord2); //if (blitMode.SupportsTransparentLayer) QcUnity.SetShaderKeyword(PainterShaderVariables.TARGET_TRANSPARENT_LAYER, id.isATransparentLayer); blitMode.SetKeyword(id).SetGlobalShaderParameters(); if (rendTex && blitMode.UsingSourceTexture) { PainterShaderVariables.SourceTextureProperty.GlobalValue = Data.sourceTextures.TryGet(brush.selectedSourceTexture); PainterShaderVariables.TextureSourceParameters.GlobalValue = new Vector4( (float)brush.srcColorUsage, brush.clampSourceTexture ? 1f : 0f, useTransparentLayerBackground, brush.ignoreSrcTextureTransparency ? 1f : 0f ); } }