public static void PrepareCPUBlit(this BrushConfig bc) { half = (bc.Size(false)) / 2; bool smooth = bc.Type(true) != BrushTypePixel.Inst; if (smooth) { _alphaMode = circleAlpha; } else { _alphaMode = noAlpha; } _blitMode = bc.BlitMode.BlitFunctionTex2D;//bliTMode_Texture2D.blitFunction(); alpha = 1; r = bc.mask.GetFlag(BrushMask.R); g = bc.mask.GetFlag(BrushMask.G); b = bc.mask.GetFlag(BrushMask.B); a = bc.mask.GetFlag(BrushMask.A); csrc = bc.colorLinear.ToGamma(); }
public void PrepareBlit(BrushConfig bc, ImageData id, float brushAlpha, StrokeVector stroke) { values = id.pixelsForJob; pixelNumber = id.UvToPixelNumber(stroke.uvFrom); width = id.width; height = id.height; brAlpha = brushAlpha; half = (bc.Size(false)) / 2; smooth = bc.Type(true) != BrushTypePixel.Inst; blitJobBlitMode = bc.BlitMode.BlitJobFunction(); alpha = 1; r = bc.mask.GetFlag(BrushMask.R); g = bc.mask.GetFlag(BrushMask.G); b = bc.mask.GetFlag(BrushMask.B); a = bc.mask.GetFlag(BrushMask.A); csrc = bc.colorLinear.ToGamma(); }
public bool PaintTexture2D(StrokeVector stroke, float brushAlpha, ImageData image, BrushConfig bc, PlaytimePainter pntr) { if (pntr.IsAtlased()) { Vector2 uvCoords = stroke.uvFrom; Vector2 AtlasedSection = GetAtlasedSection(); sectorSize = image.width / atlasRows; atlasSector.From(AtlasedSection * sectorSize); Blit_Functions.brAlpha = brushAlpha; Blit_Functions.half = (bc.Size(false)) / 2; int ihalf = Mathf.FloorToInt(Blit_Functions.half - 0.5f); bool smooth = bc.Type(true) != BrushTypePixel.Inst; if (smooth) { Blit_Functions._alphaMode = Blit_Functions.circleAlpha; } else { Blit_Functions._alphaMode = Blit_Functions.noAlpha; } Blit_Functions._blitMode = bc.BlitMode.BlitFunctionTex2D; if (smooth) { ihalf += 1; } Blit_Functions.alpha = 1; Blit_Functions.r = bc.mask.GetFlag(BrushMask.R); Blit_Functions.g = bc.mask.GetFlag(BrushMask.G); Blit_Functions.b = bc.mask.GetFlag(BrushMask.B); Blit_Functions.a = bc.mask.GetFlag(BrushMask.A); Blit_Functions.csrc = bc.colorLinear.ToGamma(); MyIntVec2 tmp = image.UvToPixelNumber(uvCoords);//new myIntVec2 (pixIndex); int fromx = tmp.x - ihalf; tmp.y -= ihalf; var pixels = image.Pixels; for (Blit_Functions.y = -ihalf; Blit_Functions.y < ihalf + 1; Blit_Functions.y++) { tmp.x = fromx; for (Blit_Functions.x = -ihalf; Blit_Functions.x < ihalf + 1; Blit_Functions.x++) { if (Blit_Functions._alphaMode()) { int sx = tmp.x - atlasSector.x; int sy = tmp.y - atlasSector.y; sx %= sectorSize; if (sx < 0) { sx += sectorSize; } sy %= sectorSize; if (sy < 0) { sy += sectorSize; } Blit_Functions._blitMode(ref pixels[((atlasSector.y + sy)) * image.width + (atlasSector.x + sx)]); } tmp.x += 1; } tmp.y += 1; } return(true); } return(false); }
public bool PaintTexture2D(StrokeVector stroke, float brushAlpha, ImageData image, BrushConfig bc, PlaytimePainter pntr) { var volume = image.texture2D.GetVolumeTextureData(); if (volume != null) { if (volume.VolumeJobIsRunning) { return(false); } float volumeScale = volume.size; Vector3 pos = (stroke.posFrom - volume.transform.position) / volumeScale + 0.5f * Vector3.one; int height = volume.Height; int texWidth = image.width; Blit_Functions.brAlpha = brushAlpha; bc.PrepareCPUBlit(); Blit_Functions.half = bc.Size(true) / volumeScale; var pixels = image.Pixels; int ihalf = (int)(Blit_Functions.half - 0.5f); bool smooth = bc.Type(true) != BrushTypePixel.Inst; if (smooth) { ihalf += 1; } Blit_Functions._alphaMode = Blit_Functions.SphereAlpha; int sliceWidth = texWidth / volume.h_slices; int hw = sliceWidth / 2; int y = (int)pos.y; int z = (int)(pos.z + hw); int x = (int)(pos.x + hw); for (Blit_Functions.y = -ihalf; Blit_Functions.y < ihalf + 1; Blit_Functions.y++) { int h = y + Blit_Functions.y; if (h >= height) { return(true); } if (h >= 0) { int hy = h / volume.h_slices; int hx = h % volume.h_slices; int hTex_index = (hy * texWidth + hx) * sliceWidth; for (Blit_Functions.z = -ihalf; Blit_Functions.z < ihalf + 1; Blit_Functions.z++) { int trueZ = z + Blit_Functions.z; if (trueZ >= 0 && trueZ < sliceWidth) { int yTex_index = hTex_index + trueZ * texWidth; for (Blit_Functions.x = -ihalf; Blit_Functions.x < ihalf + 1; Blit_Functions.x++) { if (Blit_Functions._alphaMode()) { int trueX = x + Blit_Functions.x; if (trueX >= 0 && trueX < sliceWidth) { int texIndex = yTex_index + trueX; Blit_Functions._blitMode(ref pixels[texIndex]); } } } } } } } return(true); } return(false); }
public override void PaintRenderTexture(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { BeforeStroke(pntr, br, st); // Vector2 outb = new Vector2(Mathf.Floor(st.uvTo.x), Mathf.Floor(st.uvTo.y)); // st.uvTo -= outb; // st.uvFrom -= outb; Vector2 delta_uv = st.Delta_uv;//uv - st.uvFrom;//.Previous_uv; float magn = delta_uv.magnitude; var id = pntr.ImgData; float width = br.Size(false) / ((float)id.width) * 4; //const float followPortion = 0.5f; //float follow = width; float trackPortion = (delta_uv.magnitude - width * 0.5f) * 0.25f; if ((trackPortion > 0) || (st.mouseUp)) { if (st.firstStroke) { previousDirectionLazy = st.previousDelta = delta_uv; LazySpeedDynamic = delta_uv.magnitude; LazyAngleSmoothed = 0; // Debug.Log("First stroke"); } float angle = Mathf.Deg2Rad * Vector2.Angle(st.previousDelta, delta_uv); bool smooth = angle < Mathf.PI * 0.5f; if ((st.CrossedASeam()) && (magn > previousDirectionLazy.magnitude * 8)) { // Debug.Log("Crossed a seam"); st.mouseUp = true; st.uvTo = st.uvFrom;// painter.Previous_uv; delta_uv = Vector2.zero; smooth = false; } previousDirectionLazy = delta_uv; if (!st.mouseUp) { if (smooth) { float clockwise = Vector3.Cross(st.previousDelta, delta_uv).z > 0 ? 1 : -1; float sin = Mathf.Sin(angle) * clockwise; float maxSinus = 8; if (Mathf.Abs(LazyAngleSmoothed) > Mathf.Abs(sin)) { LazyAngleSmoothed = sin; } else { LazyAngleSmoothed = Mathf.Lerp(LazyAngleSmoothed, sin, 0.2f); } sin = LazyAngleSmoothed; if ((sin * sin > maxSinus * maxSinus) || ((sin > 0) != (maxSinus > 0))) { float absSin = Mathf.Abs(sin); float absNSin = Mathf.Abs(maxSinus); if (absSin < absNSin) { maxSinus = maxSinus * absSin / absNSin; } st.uvTo = st.uvFrom + st.previousDelta.normalized.Rotate(maxSinus * clockwise) * trackPortion; LazySpeedDynamic = trackPortion; } else { LazySpeedDynamic = Mathf.Min(delta_uv.magnitude * 0.5f, Mathf.Lerp(LazySpeedDynamic, delta_uv.magnitude * 0.5f, 0.001f)); LazySpeedDynamic = Mathf.Max(trackPortion, LazySpeedDynamic); st.uvTo = st.uvFrom + st.previousDelta.normalized.Rotate(sin) * LazySpeedDynamic; } } else { LazySpeedDynamic = delta_uv.magnitude; LazyAngleSmoothed = 0; st.uvTo = st.uvFrom + delta_uv.normalized * trackPortion; } } PainterCamera r = TexMGMT; //RenderTexturePainter.inst.RenderLazyBrush(painter.Previous_uv, uv, brush.speed * 0.05f, painter.curImgData, brush, painter.LmouseUP, smooth ); if (TexMGMT.BigRT_pair == null) { TexMGMT.UpdateBuffersState(); } float meshWidth = br.StrokeWidth(id.width, false); //.Size(false) / ((float)id.width) * 2 * rtp.orthoSize; Transform tf = Rtbrush; Vector2 direction = st.Delta_uv; //uvTo - uvFrom; bool isTail = st.firstStroke; //(!previousTo.Equals(uvFrom)); if ((!isTail) && (!smooth)) { var st2 = new StrokeVector(st) { firstStroke = false }; r.ShaderPrepareStroke(br, br.speed * 0.05f, id, st2, pntr); Vector3 junkPoint = st.uvFrom + st.previousDelta * 0.01f; BrushMesh = brushMeshGenerator.inst().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();//Render_UpdateSecondBufferIfUsing(id); st.uvFrom = junkPoint; isTail = true; } r.ShaderPrepareStroke(br, br.speed * 0.05f, id, st, pntr); BrushMesh = brushMeshGenerator.inst().GetStreak(UvToPosition(st.uvFrom), UvToPosition(st.uvTo), meshWidth, st.mouseUp, isTail); tf.localScale = Vector3.one; tf.localRotation = Quaternion.identity; tf.localPosition = new Vector3(0, 0, 10); st.previousDelta = direction; r.Render(); AfterStroke(pntr, br, st); } }
public override void PaintRenderTexture(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { BeforeStroke(pntr, br, st); ImageData id = pntr.ImgData; if ((st.firstStroke) || (br.decalContinious)) { if (br.decalRotationMethod == DecalRotationMethod.StrokeDirection) { Vector2 delta = st.uvTo - previousUV; // if ((st.firstStroke) || (delta.magnitude*id.width > br.Size(false)*0.25f)) { float portion = Mathf.Clamp01(delta.magnitude * id.width * 4 / br.Size(false)); float newAngle = Vector2.SignedAngle(Vector2.up, delta) + br.decalAngleModifier; br.decalAngle = Mathf.LerpAngle(br.decalAngle, newAngle, portion); previousUV = st.uvTo; //} } if (TexMGMT.BigRT_pair == null) { TexMGMT.UpdateBuffersState(); } TexMGMT.ShaderPrepareStroke(br, 1, id, st, pntr); Transform tf = Rtbrush; tf.localScale = Vector3.one * br.Size(false); tf.localRotation = Quaternion.Euler(new Vector3(0, 0, br.decalAngle)); BrushMesh = brushMeshGenerator.inst().GetQuad(); st.uvTo = st.uvTo.To01Space(); Vector2 deltauv = st.Delta_uv; /* * * int strokes = Mathf.Max(1, (br.decalContinious && (!st.firstStroke)) ? (int)(deltauv.magnitude*id.width/br.Size(false)) : 1); * * deltauv /= strokes; * * for (int i = 0; i < strokes; i++) { * st.uvFrom += deltauv;*/ Vector2 uv = st.uvTo; if ((br.decalRotationMethod == DecalRotationMethod.StrokeDirection) && (!st.firstStroke)) { float length = Mathf.Max(deltauv.magnitude * 2 * id.width / br.Size(false), 1); Vector3 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(pntr, br, st); } else { pntr.AfterStroke(st); } }
public virtual void PaintToTexture2D(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { Vector2 delta_uv = st.uvTo - st.uvFrom; if (delta_uv.magnitude > (0.2f + st.avgBrushSpeed * 3)) { delta_uv = Vector2.zero; // This is made to avoid glitch strokes on seams } else { st.avgBrushSpeed = (st.avgBrushSpeed + delta_uv.magnitude) / 2; } float alpha = Mathf.Clamp01(br.speed * (Application.isPlaying ? Time.deltaTime : 0.1f)); bool worldSpace = pntr.NeedsGrid(); var id = pntr.ImgData; float uvDist = (delta_uv.magnitude * id.width * 8 / br.Size(false)); float worldDist = st.Delta_WorldPos.magnitude; float steps = (int)Mathf.Max(1, worldSpace ? worldDist : uvDist); delta_uv /= steps; Vector3 deltaPos = st.Delta_WorldPos / steps; st.uvFrom += delta_uv; st.posFrom += deltaPos; Blit_Functions.PaintTexture2DMethod pluginBlit = null; if (pluginBlit == null && tex2DPaintPlugins != null) { foreach (Blit_Functions.PaintTexture2DMethod p in tex2DPaintPlugins.GetInvocationList()) { if (p(st, alpha, id, br, pntr)) { pluginBlit = p; break; } } } if (pluginBlit == null) { pluginBlit = Blit_Functions.Paint; pluginBlit(st, alpha, id, br, pntr); } for (float i = 1; i < steps; i++) { st.uvFrom += delta_uv; st.posFrom += deltaPos; pluginBlit(st, alpha, id, br, pntr); } pntr.AfterStroke(st); }
public void Shader_BrushCFG_Update(BrushConfig brush, float brushAlpha, float textureWidth, bool RendTex, bool texcoord2, PlaytimePainter pntr) { var brushType = brush.Type(!RendTex); bool is3Dbrush = brush.IsA3Dbrush(pntr); bool isDecal = (RendTex) && (brushType.IsUsingDecals); Color c = brush.colorLinear.ToGamma(); #if UNITY_EDITOR // if (isLinearColorSpace) c = c.linear; #endif Shader.SetGlobalVector("_brushColor", c); Shader.SetGlobalVector("_brushMask", new Vector4( brush.mask.GetFlag(BrushMask.R) ? 1 : 0, brush.mask.GetFlag(BrushMask.G) ? 1 : 0, brush.mask.GetFlag(BrushMask.B) ? 1 : 0, brush.mask.GetFlag(BrushMask.A) ? 1 : 0)); if (isDecal) { Shader_UpdateDecal(brush); } if (brush.useMask && RendTex) { Shader.SetGlobalTexture("_SourceMask", Data.masks.TryGet(brush.selectedSourceMask)); } Shader.SetGlobalVector("_maskDynamics", new Vector4( brush.maskTiling, RendTex ? brush.Hardness : 0, // y - Hardness is 0 to do correct preview for Texture2D brush (brush.flipMaskAlpha ? 0 : 1) , 0)); Shader.SetGlobalVector("_maskOffset", new Vector4( brush.maskOffset.x, brush.maskOffset.y, 0, 0)); Shader.SetGlobalVector("_brushForm", 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 brushType.SetKeyword(texcoord2); if (texcoord2) { Shader.EnableKeyword(PainterDataAndConfig.BRUSH_TEXCOORD_2); } else { Shader.DisableKeyword(PainterDataAndConfig.BRUSH_TEXCOORD_2); } brush.BlitMode.SetKeyword().SetGlobalShaderParameters(); if (brush.BlitMode.GetType() == typeof(BlitModeSamplingOffset)) { Shader.EnableKeyword("PREVIEW_SAMPLING_DISPLACEMENT"); Shader.DisableKeyword("PREVIEW_ALPHA"); Shader.DisableKeyword("PREVIEW_RGB"); } else { Shader.DisableKeyword("PREVIEW_SAMPLING_DISPLACEMENT"); BlitModeExtensions.SetShaderToggle(TexMGMTdata.previewAlphaChanel, "PREVIEW_ALPHA", "PREVIEW_RGB"); } if ((RendTex) && (brush.BlitMode.UsingSourceTexture)) { Shader.SetGlobalTexture("_SourceTexture", Data.sourceTextures.TryGet(brush.selectedSourceTexture)); } }
public static float StrokeWidth(this BrushConfig br, float pixWidth, bool world) => br.Size(world) / (pixWidth) * 2 * PainterCamera.orthoSize;