public static void PrepareCpuBlit(this BrushConfig bc, ImageMeta id) { half = (bc.Size(false)) / 2; var smooth = bc.GetBrushType(true) != BrushTypePixel.Inst; if (smooth) { alphaMode = CircleAlpha; } else { alphaMode = NoAlpha; } blitMode = bc.GetBlitMode(true).BlitFunctionTex2D(id); alpha = 1; var m = bc.mask; r = m.HasFlag(BrushMask.R); g = m.HasFlag(BrushMask.G); b = m.HasFlag(BrushMask.B); a = m.HasFlag(BrushMask.A); cSrc = bc.Color; }
public static void PrepareCpuBlit(this BrushConfig bc, TextureMeta id) { half = (bc.Size(false)) / 2; var smooth = bc.GetBrushType(true) != BrushTypes.Pixel.Inst; if (smooth) { alphaMode = CircleAlpha; } else { alphaMode = NoAlpha; } blitMode = bc.GetBlitMode(true).BlitFunctionTex2D(id); alpha = 1; Set(bc.mask); cSrc = bc.Color; }
public void PaintPixelsInRam(StrokeVector stroke, float brushAlpha, ImageMeta image, BrushConfig bc, PlaytimePainter painter) { var volume = image.texture2D.GetVolumeTextureData(); if (!volume) { return; } if (volume.VolumeJobIsRunning) { return; } bc.brush3DRadius = Mathf.Min(BrushScaleMaxForCpu(volume), bc.brush3DRadius); var volumeScale = volume.size; var pos = (stroke.posFrom - volume.transform.position) / volumeScale + 0.5f * Vector3.one; var height = volume.Height; var texWidth = image.width; BlitFunctions.brAlpha = brushAlpha; bc.PrepareCpuBlit(image); BlitFunctions.half = bc.Size(true) / volumeScale; var pixels = image.Pixels; var iHalf = (int)(BlitFunctions.half - 0.5f); var smooth = bc.GetBrushType(true) != BrushTypePixel.Inst; if (smooth) { iHalf += 1; } BlitFunctions.alphaMode = BlitFunctions.SphereAlpha; var sliceWidth = texWidth / volume.hSlices; var hw = sliceWidth / 2; var y = (int)pos.y; var z = (int)(pos.z + hw); var x = (int)(pos.x + hw); for (BlitFunctions.y = -iHalf; BlitFunctions.y < iHalf + 1; BlitFunctions.y++) { var h = y + BlitFunctions.y; if (h >= height) { return; } if (h < 0) { continue; } var hy = h / volume.hSlices; var hx = h % volume.hSlices; var hTexIndex = (hy * texWidth + hx) * sliceWidth; for (BlitFunctions.z = -iHalf; BlitFunctions.z < iHalf + 1; BlitFunctions.z++) { var trueZ = z + BlitFunctions.z; if (trueZ < 0 || trueZ >= sliceWidth) { continue; } var yTexIndex = hTexIndex + trueZ * texWidth; for (BlitFunctions.x = -iHalf; BlitFunctions.x < iHalf + 1; BlitFunctions.x++) { if (!BlitFunctions.alphaMode()) { continue; } var trueX = x + BlitFunctions.x; if (trueX < 0 || trueX >= sliceWidth) { continue; } var texIndex = yTexIndex + trueX; BlitFunctions.blitMode(ref pixels[texIndex]); } } } }
public override void PaintRenderTexture(PlaytimePainter painter, BrushConfig br, StrokeVector st) { BeforeStroke(br, st, painter); var deltaUv = st.DeltaUv; //uv - st.uvFrom;//.Previous_uv; var magnitude = deltaUv.magnitude; var id = painter.TexMeta; 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 StrokeVector(st) { firstStroke = false }; r.SHADER_STROKE_SEGMENT_UPDATE(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; } r.SHADER_STROKE_SEGMENT_UPDATE(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_Painter(painter, br, st, alphaBuffer, id); }
public override void PaintRenderTexture(PlaytimePainter painter, BrushConfig br, StrokeVector st) { BeforeStroke(br, st, painter); var id = painter.TexMeta; 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; } bool alphaBuffer; TexMGMT.SHADER_STROKE_SEGMENT_UPDATE(br, 1, id, st, out alphaBuffer, 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 = StrokeVector.BrushWorldPositionFrom(uv); TexMGMT.Render(); AfterStroke_Painter(painter, br, st, alphaBuffer, id); } else { painter.AfterStroke(st); } }
public virtual void PaintToTexture2D(PlaytimePainter painter, BrushConfig br, StrokeVector st) { 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.Speed * (Application.isPlaying ? Time.deltaTime : 0.1f)); var worldSpace = painter.NeedsGrid(); var id = painter.TexMeta; 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, worldSpace ? worldDist : uvDist); deltaUv /= steps; deltaPos /= steps; st.uvFrom += deltaUv; st.posFrom += deltaPos; } BlitFunctions.PaintTexture2DMethod blitMethod = null; foreach (var p in CameraModuleBase.BrushPlugins) { if (p.IsEnabledFor(painter, id, br)) { p.PaintPixelsInRam(st, alpha, id, br, painter); blitMethod = p.PaintPixelsInRam; break; } } if (blitMethod == null) { blitMethod = BlitFunctions.Paint; blitMethod(st, alpha, id, br, painter); } for (float i = 1; i < steps; i++) { st.uvFrom += deltaUv; st.posFrom += deltaPos; blitMethod(st, alpha, id, br, painter); } painter.AfterStroke(st); }
public static float StrokeWidth(this BrushConfig br, float pixWidth, bool world) => br.Size(world) / (pixWidth) * 2 * PainterCamera.OrthographicSize;
public bool PaintTexture2D(StrokeVector stroke, float brushAlpha, TextureMeta image, BrushConfig bc, PlaytimePainter painter) { if (!painter.IsAtlased()) { return(false); } var uvCoords = stroke.uvFrom; var atlasedSection = GetAtlasedSection(); sectorSize = image.width / atlasRows; atlasSector.From(atlasedSection * sectorSize); BlitFunctions.brAlpha = brushAlpha; BlitFunctions.half = (bc.Size(false)) / 2; var iHalf = Mathf.FloorToInt(BlitFunctions.half - 0.5f); var smooth = bc.GetBrushType(true) != BrushTypes.Pixel.Inst; if (smooth) { BlitFunctions.alphaMode = BlitFunctions.CircleAlpha; } else { BlitFunctions.alphaMode = BlitFunctions.NoAlpha; } BlitFunctions.blitMode = bc.GetBlitMode(true).BlitFunctionTex2D(image); if (smooth) { iHalf += 1; } BlitFunctions.alpha = 1; BlitFunctions.Set(bc.mask); BlitFunctions.cSrc = bc.Color; var tmp = image.UvToPixelNumber(uvCoords); var fromX = tmp.x - iHalf; tmp.y -= iHalf; var pixels = image.Pixels; for (BlitFunctions.y = -iHalf; BlitFunctions.y < iHalf + 1; BlitFunctions.y++) { tmp.x = fromX; for (BlitFunctions.x = -iHalf; BlitFunctions.x < iHalf + 1; BlitFunctions.x++) { if (BlitFunctions.alphaMode()) { var sx = tmp.x - atlasSector.x; var sy = tmp.y - atlasSector.y; sx %= sectorSize; if (sx < 0) { sx += sectorSize; } sy %= sectorSize; if (sy < 0) { sy += sectorSize; } BlitFunctions.blitMode(ref pixels[((atlasSector.y + sy)) * image.width + (atlasSector.x + sx)]); } tmp.x += 1; } tmp.y += 1; } return(true); }
public void SHADER_BRUSH_UPDATE(BrushConfig brush = null, float brushAlpha = 1, TextureMeta id = null, PlaytimePainter painter = null) { if (brush == null) { brush = GlobalBrush; } if (id == null && painter) { id = painter.TexMeta; } brush.previewDirty = false; if (id == null) { return; } float textureWidth = id.width; var rendTex = id.TargetIsRenderTexture(); var brushType = brush.GetBrushType(!rendTex); var blitMode = brush.GetBlitMode(!rendTex); var is3DBrush = brush.IsA3DBrush(painter); var useAlphaBuffer = (brush.useAlphaBuffer && blitMode.SupportsAlphaBufferPainting && rendTex); PainterShaderVariables.BrushColorProperty.GlobalValue = brush.Color; PainterShaderVariables.BrushMaskProperty.GlobalValue = brush.mask.ToVector4(); float useTransparentLayerBackground = 0; PainterShaderVariables.OriginalTextureTexelSize.GlobalValue = new Vector4( 1f / id.width, 1f / id.height, id.width, id.height ); if (id.isATransparentLayer) { 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; } } 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(); PainterShaderVariables.BrushFormProperty.GlobalValue = new Vector4( brushAlpha, // x - transparency brush.Size(is3DBrush), // y - scale for sphere brush.Size(is3DBrush) / textureWidth, // z - scale for uv space brush.blurAmount); // w - blur amount 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 ); } }
public void SHADER_BRUSH_UPDATE(BrushConfig brush = null, float brushAlpha = 1, ImageMeta id = null, PlaytimePainter painter = null) { if (brush == null) { brush = GlobalBrush; } if (!painter) { painter = PlaytimePainter.selectedInPlaytime; } if (id == null && painter) { id = painter.ImgMeta; } brush.previewDirty = false; if (id == null) { return; } float textureWidth = id.width; var rendTex = id.TargetIsRenderTexture(); var brushType = brush.GetBrushType(!rendTex); var blitMode = brush.GetBlitMode(!rendTex); var is3DBrush = brush.IsA3DBrush(painter); //var isDecal = rendTex && brushType.IsUsingDecals; var useAlphaBuffer = (brush.useAlphaBuffer && blitMode.SupportsAlphaBufferPainting && rendTex); BrushColorProperty.GlobalValue = brush.Color; BrushMaskProperty.GlobalValue = new Vector4( BrushExtensions.HasFlag(brush.mask, BrushMask.R) ? 1 : 0, BrushExtensions.HasFlag(brush.mask, BrushMask.G) ? 1 : 0, BrushExtensions.HasFlag(brush.mask, BrushMask.B) ? 1 : 0, BrushExtensions.HasFlag(brush.mask, BrushMask.A) ? 1 : 0); float useTransparentLayerBackground = 0; if (id.isATransparentLayer) { var md = painter.MatDta; if (md != null && md.usePreviewShader && md.material) { var mt = md.material.mainTexture; TransparentLayerUnderProperty.GlobalValue = mt; useTransparentLayerBackground = (mt && (id != mt.GetImgDataIfExists())) ? 1 : 0; } } brushType.OnShaderBrushUpdate(brush); //if (isDecal) // SHADER_DECAL_UPDATE(brush); if (rendTex) { SourceMaskProperty.GlobalValue = brush.useMask ? Data.masks.TryGet(brush.selectedSourceMask) : null; } 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), (brush.maskFromGreyscale && brush.useMask) ? 1 : 0); MaskOffsetProperty.GlobalValue = brush.maskOffset.ToVector4(); BrushFormProperty.GlobalValue = new Vector4( brushAlpha, // x - transparency brush.Size(is3DBrush), // y - scale for sphere brush.Size(is3DBrush) / textureWidth, // z - scale for uv space brush.blurAmount); // w - blur amount AlphaBufferConfigProperty.GlobalValue = new Vector4( brush.alphaLimitForAlphaBuffer, brush.worldSpaceBrushPixelJitter ? 1 : 0, useAlphaBuffer ? 1 : 0, 0); AlphaPaintingBuffer.GlobalValue = AlphaBuffer; brushType.SetKeyword(id.useTexCoord2); UnityUtils.SetShaderKeyword(PainterDataAndConfig.BRUSH_TEXCOORD_2, id.useTexCoord2); if (blitMode.SupportsTransparentLayer) { UnityUtils.SetShaderKeyword(PainterDataAndConfig.TARGET_TRANSPARENT_LAYER, id.isATransparentLayer); } blitMode.SetKeyword(id).SetGlobalShaderParameters(); if (rendTex && blitMode.UsingSourceTexture) { SourceTextureProperty.GlobalValue = Data.sourceTextures.TryGet(brush.selectedSourceTexture); TextureSourceParameters.GlobalValue = new Vector4( (float)brush.srcColorUsage, brush.clampSourceTexture ? 1f : 0f, useTransparentLayerBackground, brush.ignoreSrcTextureTransparency ? 1f : 0f ); } }