public virtual void BeforeStroke(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { foreach (var p in pntr.plugins) { p.BeforeGPUStroke(pntr, br, st, this); } }
public static void Paint(Vector2 uv, BrushConfig br, RenderTexture rt) { if (TexMGMT.BigRT_pair == null) { TexMGMT.UpdateBuffersState(); } var id = rt.GetImgData(); var stroke = new StrokeVector(uv) { useTexcoord2 = false, firstStroke = false }; TexMGMT.ShaderPrepareStroke(br, br.speed * 0.05f, id, stroke, null); float width = br.StrokeWidth(id.width, false); Rtbrush.localScale = Vector3.one; BrushMesh = brushMeshGenerator.inst().GetLongMesh(0, width); Rtbrush.localRotation = Quaternion.Euler(new Vector3(0, 0, Vector2.Angle(Vector2.up, Vector2.zero))); Rtbrush.localPosition = StrokeVector.BrushWorldPositionFrom(uv); TexMGMT.Render(); AfterStroke(br); }
public override void AfterGPUStroke(PlaytimePainter p, BrushConfig br, StrokeVector st, BrushType type) { if (br.IsA3Dbrush(p) && p.IsAtlased()) { Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_ATLAS_SECTION_AND_ROWS, new Vector4(0, 0, 1, 0)); } }
public override void PrePaint(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { var v4 = new Vector4(st.unRepeatedUV.x, st.unRepeatedUV.y, Mathf.Floor(st.unRepeatedUV.x), Mathf.Floor(st.unRepeatedUV.y)); Shader.SetGlobalVector("_brushPointedUV_Untiled", v4); if (st.firstStroke) { if (method == (ColorSetMethod.MDownColor)) { if (pntr) { pntr.SampleTexture(st.uvTo); FromColor(br, st.unRepeatedUV); } } else if (method == (ColorSetMethod.MDownPosition)) { FromUV(st.uvTo); } Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_SAMPLING_DISPLACEMENT, new Vector4( ((float)currentPixel.x + 0.5f) / ((float)Cfg.samplingMaskSize.x), ((float)currentPixel.y + 0.5f) / ((float)Cfg.samplingMaskSize.y), Cfg.samplingMaskSize.x, Cfg.samplingMaskSize.y)); } }
public override bool PaintRenderTexture(StrokeVector stroke, ImageData image, BrushConfig bc, PlaytimePainter pntr) { var vt = pntr.GetVolumeTexture(); if (vt != null) { BrushTypeSphere.Inst.BeforeStroke(pntr, bc, stroke); Shader.SetGlobalVector(VOLUME_POSITION_N_SIZE + "_BRUSH", vt.PosNsize4Shader); Shader.SetGlobalVector(VOLUME_H_SLICES + "_BRUSH", vt.Slices4Shader); if (stroke.mouseDwn) { stroke.posFrom = stroke.posTo; } stroke.useTexcoord2 = false; TexMGMT.ShaderPrepareStroke(bc, bc.speed * 0.05f, image, stroke, pntr); stroke.SetWorldPosInShader(); TexMGMT.brushRendy.FullScreenQuad(); TexMGMT.Render(); BrushTypeSphere.Inst.AfterStroke(pntr, bc, stroke); return(true); } return(false); }
public virtual void PaintRenderTexture(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { BeforeStroke(pntr, br, st); if (st.CrossedASeam()) { st.uvFrom = st.uvTo; } ImageData id = pntr.ImgData; TexMGMT.ShaderPrepareStroke(br, br.speed * 0.05f, id, st, pntr); var rb = Rtbrush; rb.localScale = Vector3.one; Vector2 direction = st.Delta_uv; float length = direction.magnitude; BrushMesh = brushMeshGenerator.inst().GetLongMesh(length * 256, br.StrokeWidth(id.width, false)); rb.localRotation = Quaternion.Euler(new Vector3(0, 0, (direction.x > 0 ? -1 : 1) * Vector2.Angle(Vector2.up, direction))); rb.localPosition = StrokeVector.BrushWorldPositionFrom((st.uvFrom + st.uvTo) / 2); TexMGMT.Render(); AfterStroke(pntr, br, st); }
public override void BeforeGPUStroke(PlaytimePainter pntr, BrushConfig br, StrokeVector st, BrushType type) { if (br.IsA3Dbrush(pntr) && pntr.IsAtlased()) { var ats = GetAtlasedSection(); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_ATLAS_SECTION_AND_ROWS, new Vector4(ats.x, ats.y, atlasRows, 1)); } }
public void PrepareVolumeBlit(BrushConfig bc, ImageData id, float alpha, StrokeVector stroke, VolumeTexture volume) { PrepareBlit(bc, id, alpha, stroke); pos = (stroke.posFrom - volume.transform.position) / volume.size + 0.5f * Vector3.one; isVolumeBlit = true; slices = volume.h_slices; volHeight = volume.Height; texWidth = id.width; }
public override void AfterStroke(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { base.AfterStroke(pntr, br, st); if (br.decalRotationMethod == DecalRotationMethod.Random) { br.decalAngle = UnityEngine.Random.Range(-90f, 450f); TexMGMT.Shader_UpdateDecal(Cfg.brushConfig); //pntr.Dec//Update_Brush_Parameters_For_Preview_Shader(); } }
public static bool PaintTexture2D(StrokeVector stroke, float brushAlpha, ImageData image, BrushConfig bc, PlaytimePainter pntr) { var pl = pntr.GetPlugin <TileableAtlasingPainterPlugin>(); if (pl != null) { return(pl.PaintTexture2D(stroke, brushAlpha, image, bc, pntr)); } else { return(false); } }
// ******************* Brush Shader MGMT public static void Shader_PerFrame_Update(StrokeVector st, bool hidePreview, float size) { if ((hidePreview) && (previewAlpha == 0)) { return; } previewAlpha = Mathf.Lerp(previewAlpha, hidePreview ? 0 : 1, 0.1f); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_POINTED_UV, new Vector4(st.uvTo.x, st.uvTo.y, 0, previewAlpha)); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_WORLD_POS_FROM, new Vector4(prevPosPreview.x, prevPosPreview.y, prevPosPreview.z, size)); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_WORLD_POS_TO, new Vector4(st.posTo.x, st.posTo.y, st.posTo.z, (st.posTo - prevPosPreview).magnitude)); prevPosPreview = st.posTo; }
private void Update() { brush.Brush3D_Radius = transform.lossyScale.x * 0.7f; foreach (PaintingCollision col in paintingOn) { PlaytimePainter p = col.painter; if (brush.IsA3Dbrush(p)) { StrokeVector v = col.vector; v.posTo = transform.position; brush.Paint(v, p); } } }
public static bool Paint(StrokeVector stroke, float brushAlpha, ImageData image, BrushConfig bc, PlaytimePainter pntr) { Vector2 uvCoords = stroke.uvFrom; brAlpha = brushAlpha; bc.PrepareCPUBlit(); if (image == null || image.Pixels == null) { return(false); } int ihalf = (int)(half - 0.5f); bool smooth = bc.Type(true) != BrushTypePixel.Inst; if (smooth) { ihalf += 1; } MyIntVec2 tmp = image.UvToPixelNumber(uvCoords);//new myIntVec2 (pixIndex); int fromx = tmp.x - ihalf; tmp.y -= ihalf; var pixels = image.Pixels; for (y = -ihalf; y < ihalf + 1; y++) { tmp.x = fromx; for (x = -ihalf; x < ihalf + 1; x++) { if (_alphaMode()) { _blitMode(ref pixels[image.PixelNo(tmp)]); } tmp.x += 1; } tmp.y += 1; } return(true); }
void Paint() { RaycastHit hit; if (Physics.Raycast(new Ray(transform.position, transform.forward), out hit)) { var painter = hit.transform.GetComponentInParent <PlaytimePainter>(); if (painter != null) { if ((painter.skinnedMeshRendy != null) && (brush.IsA3Dbrush(painter) == false)) { painter.UpdateColliderForSkinnedMesh(); bool colliderDIsabled = !painter.meshCollider.enabled; if (colliderDIsabled) { painter.meshCollider.enabled = true; } if (!painter.meshCollider.Raycast(new Ray(transform.position, transform.forward), out hit, 99999)) { Debug.Log("Missed the Mesh Collider"); if (colliderDIsabled) { painter.meshCollider.enabled = false; } return; } if (colliderDIsabled) { painter.meshCollider.enabled = false; } } StrokeVector v = new StrokeVector(hit, false); brush.Paint(v, painter.SetTexTarget(brush)); } } }
public virtual void AfterStroke(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { pntr.AfterStroke(st); if (!br.IsSingleBufferBrush() && !br.IsA3Dbrush(pntr)) { TexMGMT.UpdateBufferSegment(); } if ((br.useMask) && (st.mouseUp) && (br.randomMaskOffset)) { br.maskOffset = new Vector2(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f)); } foreach (var p in pntr.plugins) { p.AfterGPUStroke(pntr, br, st, this); } }
public StrokeVector(StrokeVector other) { uvFrom = other.uvFrom; posFrom = other.posFrom; uvTo = other.uvTo; posTo = other.posTo; unRepeatedUV = other.unRepeatedUV; useTexcoord2 = other.useTexcoord2; previousDelta = other.previousDelta; avgBrushSpeed = other.avgBrushSpeed; mouseDwn = other.mouseDwn; firstStroke = other.firstStroke; // For cases like Lazy Brush, when painting doesn't start on the first frame. mouseUp = other.mouseDwn; Dwn(); }
public bool PaintTexture2D_NEW(StrokeVector stroke, float brushAlpha, ImageData image, BrushConfig bc, PlaytimePainter pntr) { var volume = image.texture2D.GetVolumeTextureData(); if (image.CanUsePixelsForJob()) { var blitJob = new BlitJobs(); blitJob.PrepareVolumeBlit(bc, image, brushAlpha, stroke, volume); image.jobHandle = blitJob.Schedule(); JobHandle.ScheduleBatchedJobs(); return(true); } return(false); }
static void PrepareSphereBrush(ImageData id, BrushConfig br, StrokeVector stroke, PlaytimePainter pntr) { if (TexMGMT.BigRT_pair == null) { TexMGMT.UpdateBuffersState(); } if (stroke.mouseDwn) { stroke.posFrom = stroke.posTo; } TexMGMT.ShaderPrepareStroke(br, br.speed * 0.05f, id, stroke, null); Vector2 offset = id.offset - stroke.unRepeatedUV.Floor(); stroke.SetWorldPosInShader(); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_EDITED_UV_OFFSET, new Vector4(id.tiling.x, id.tiling.y, offset.x, offset.y)); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_ATLAS_SECTION_AND_ROWS, new Vector4(0, 0, 1, 0)); }
void Paint(Collision collision, PaintingCollision pCont) { if (brush.IsA3Dbrush(pCont.painter)) { StrokeVector v = pCont.vector; v.posTo = transform.position; if (v.mouseDwn) { v.posFrom = v.posTo; } brush.Paint(v, pCont.painter); } else { if (collision.contacts.Length > 0) { var cp = collision.contacts[0]; RaycastHit hit; Ray ray = new Ray(cp.point + cp.normal * 0.1f, -cp.normal); if (collision.collider.Raycast(ray, out hit, 2f)) { StrokeVector v = pCont.vector; v.uvTo = hit.textureCoord; if (v.mouseDwn) { v.uvFrom = v.uvTo; } brush.Paint(pCont.vector, pCont.painter.SetTexTarget(brush)); } } } }
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 static void Paint(RenderTexture rt, GameObject go, Mesh mesh, BrushConfig br, StrokeVector st, List <int> submeshIndex) { br.BlitMode.PrePaint(null, br, st); PrepareSphereBrush(rt.GetImgData(), br, st, null); TexMGMT.brushRendy.UseMeshAsBrush(go, mesh, submeshIndex); TexMGMT.Render(); AfterStroke(br); }
public override void PaintRenderTexture(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { BeforeStroke(pntr, br, st); if (st.CrossedASeam()) { st.uvFrom = st.uvTo; } if (TexMGMT.BigRT_pair == null) { TexMGMT.UpdateBuffersState(); } ImageData id = pntr.ImgData; TexMGMT.ShaderPrepareStroke(br, br.speed * 0.05f, id, st, pntr); Rtbrush.localScale = Vector3.one * br.StrokeWidth(id.width, false); BrushMesh = brushMeshGenerator.inst().GetQuad(); Rtbrush.localRotation = Quaternion.identity; Rtbrush.localPosition = st.BrushWorldPosition; TexMGMT.Render(); AfterStroke(pntr, br, st); }
public virtual bool PaintRenderTexture(StrokeVector stroke, ImageData image, BrushConfig bc, PlaytimePainter pntr) { 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 PlaytimePainter Paint(StrokeVector stroke, PlaytimePainter pntr) { var id = pntr.ImgData; if (id == null) { pntr.InitIfNotInited(); id = pntr.ImgData; if (id == null) { return(pntr); } } var cpu = id.TargetIsTexture2D(); var t = Type(cpu); BlitMode.PrePaint(pntr, this, stroke); if (cpu) { pntr.RecordingMGMT(); t.PaintToTexture2D(pntr, this, stroke); } else { var md = pntr.MatDta; if (id.renderTexture == null && !TexMGMT.materialsUsingTendTex.Contains(md)) { TexMGMT.ChangeBufferTarget(id, md, pntr.MaterialTexturePropertyName, pntr); //materialsUsingTendTex.Add(md); pntr.SetTextureOnMaterial(id); //Debug.Log("Adding RT target"); } bool rendered = false; foreach (var pl in TexMGMT.Plugins) { if (pl.PaintRenderTexture(stroke, id, this, pntr)) { rendered = true; break; } } if ((pntr.terrain != null) && (!t.SupportedForTerrain_RT)) { return(pntr); } pntr.RecordingMGMT(); if (!rendered) { t.PaintRenderTexture(pntr, this, stroke); } } return(pntr); }
public static void PaintAtlased(RenderTexture rt, GameObject go, Mesh mesh, BrushConfig br, StrokeVector st, List <int> submeshIndex, int A_Textures_in_row) { br.BlitMode.PrePaint(null, br, st); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_ATLAS_SECTION_AND_ROWS, new Vector4(0, 0, A_Textures_in_row, 1)); PrepareSphereBrush(rt.GetImgData(), br, st, null); TexMGMT.brushRendy.UseMeshAsBrush(go, mesh, submeshIndex); TexMGMT.Render(); AfterStroke(br); Shader.SetGlobalVector(PainterDataAndConfig.BRUSH_ATLAS_SECTION_AND_ROWS, new Vector4(0, 0, 1, 0)); }
public override void PaintRenderTexture(PlaytimePainter pntr, BrushConfig br, StrokeVector st) { ImageData id = pntr.ImgData; BeforeStroke(pntr, br, st); PrepareSphereBrush(id, br, st, pntr); if (!st.mouseDwn) { TexMGMT.brushRendy.UseMeshAsBrush(pntr); TexMGMT.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 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 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); } }