当前位置:网站首页>Introduction to graphics: graphic painting (I)
Introduction to graphics: graphic painting (I)
2022-07-04 01:47:00 【Yangyang 2035】
Recently, I want to realize a series of painting functions , I think it's very useful .
The first is ordinary color rendering , Use material texture to paint , as follows :
Suppose there is a texture on it uv, Our mouse rays hit muv, according to radius Calculate the drawn circumscribed rectangle rect, Then judge the circle coloring according to the distance from the arc to the center of the circle . The only thing to pay attention to here is the boundary of texture pixels , Don't cross the line , as follows :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestColorSpray : MonoBehaviour
{
public Color color; // Color
[Range(0, 1)]
public float alpha; // transparency
public int radius; // Radius pixels
private Camera cam;
private bool isStart = false;
private Material mat;
private Texture2D tex;
private int texWidth;
private int texHeight;
void Start()
{
cam = Camera.main;
}
void FixedUpdate()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
StartSpray(hit.transform);
}
}
if (Input.GetMouseButton(0))
{
if (isStart)
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
#if UNITY_EDITOR
Debug.DrawLine(cam.transform.position, hit.point, Color.black);
#endif
// Mouse Center
Vector2 muv = new Vector2(hit.textureCoord.x * texWidth, hit.textureCoord.y * texHeight);
int mx = Mathf.Clamp((int)muv.x, 0, texWidth - 1);
int my = Mathf.Clamp((int)muv.y, 0, texHeight - 1);
// Outside rectangle ( Irregular )
int left = Mathf.Clamp(mx - radius, 0, texWidth - 1);
int right = Mathf.Clamp(mx + radius, 0, texWidth - 1);
int bottom = Mathf.Clamp(my - radius, 0, texHeight - 1);
int top = Mathf.Clamp(my + radius, 0, texHeight - 1);
int rectwid = right - left;
int recthei = top - bottom;
// draw
Color[] ogcols = tex.GetPixels(left, bottom, rectwid, recthei);
// progressive scanning
for (int y = 0; y < recthei; y++)
{
for (int x = 0; x < rectwid; x++)
{
int index = y * rectwid + x;
int px = x + left - mx;
int py = y + bottom - my;
float alphainten;
if (CheckInCircle(radius, px, py, out alphainten))
{
Color ocol = ogcols[index];
Color scol = color;
float inten = alphainten * alpha;
ogcols[index] = BlendColor(ocol, scol, inten);
}
}
}
tex.SetPixels(left, bottom, rectwid, recthei, ogcols);
tex.Apply();
}
}
}
if (Input.GetMouseButtonUp(0))
{
StopSpray();
}
}
private void StartSpray(Transform obj)
{
isStart = true;
mat = obj.GetComponent<MeshRenderer>().sharedMaterial;
tex = (Texture2D)mat.GetTexture("_MainTex");
texWidth = tex.width;
texHeight = tex.height;
}
private void StopSpray()
{
isStart = false;
}
/// <summary>
/// testing xy stay rad Circular middle
/// Relative coordinates , center of a circle (0,0)
/// </summary>
/// <param name="rad"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="inten"></param>
/// <returns></returns>
private bool CheckInCircle(int rad, int x, int y, out float inten)
{
float rad2 = rad * rad;
float len2 = x * x + y * y;
inten = 1f - len2 / rad2;
return len2 <= rad2;
}
/// <summary>
/// Mix colors
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
private Color BlendColor(Color a, Color b, float k)
{
Color c = Color.Lerp(a, b, k);
return c;
}
}
Test it ,material Of maintex Set to readwrite/rgba32, as follows :
But there's a small problem , It is suggested to make a copy of the material picture , Otherwise Apply Covering the original data , as follows :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SprayObject : MonoBehaviour
{
void Start()
{
MeshRenderer render = gameObject.GetComponent<MeshRenderer>();
Material mat = render.material;
Texture2D tex = (Texture2D)mat.GetTexture("_MainTex");
Texture2D copytex = new Texture2D(tex.width, tex.height, tex.format, false);
copytex.SetPixels(tex.GetPixels());
copytex.Apply();
mat.SetTexture("_MainTex", copytex);
}
}
In this way, the objects we spray on first clone A material and map .
At the same time, there is a big problem in this scheme , That's it uv Joints cannot be treated , as follows :
Because of the uv Is discontinuous and random ( According to the artists uvmapping) Of , Therefore, the continuity of spraying cannot be handled , If it's true , We have to think of another spraying scheme .
Of course, the current plan also has a certain place to play , For example, brush the terrain 、 Brush objects , I use this .
There are also brush patterns and textures , as follows :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestGraphSpray : MonoBehaviour
{
public Texture2D graphTex; // pattern
[Range(0, 1)]
public float alpha; // transparency
private Camera cam;
private bool isStart = false;
private Material mat;
private Texture2D tex;
private int texWidth;
private int texHeight;
private int gWid; // The pattern is wide
private int gHei; // The pattern is high
private int ghWid; // Pattern half width
private int ghHei; // The pattern is half height
void Start()
{
cam = Camera.main;
gWid = graphTex.width;
gHei = graphTex.height;
ghWid = (int)(gWid * 0.5f);
ghHei = (int)(graphTex.height * 0.5f);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
StartSpray(hit.transform);
}
}
if (Input.GetMouseButton(0))
{
if (isStart)
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
#if UNITY_EDITOR
Debug.DrawLine(cam.transform.position, hit.point, Color.black);
#endif
// Mouse Center
Vector2 muv = new Vector2(hit.textureCoord.x * texWidth, hit.textureCoord.y * texHeight);
int mx = Mathf.Clamp((int)muv.x, 0, texWidth - 1);
int my = Mathf.Clamp((int)muv.y, 0, texHeight - 1);
// Outside rectangle ( Irregular )
int left = Mathf.Clamp(mx - ghWid, 0, texWidth - 1);
int right = Mathf.Clamp(mx + ghWid, 0, texWidth - 1);
int bottom = Mathf.Clamp(my - ghHei, 0, texHeight - 1);
int top = Mathf.Clamp(my + ghHei, 0, texHeight - 1);
int rectwid = right - left;
int recthei = top - bottom;
// draw
Color[] ocols = tex.GetPixels(left, bottom, rectwid, recthei);
// According to whether the rectangle is out of bounds , Judge graphTex Starting point of sampling
int gx = mx > ghWid ? 0 : ghWid - mx;
int gy = my > ghHei ? 0 : ghHei - my;
Color[] gcols = graphTex.GetPixels(gx, gy, rectwid, recthei);
// progressive scanning
for (int y = 0; y < recthei; y++)
{
for (int x = 0; x < rectwid; x++)
{
int index = y * rectwid + x;
Color ocol = ocols[index];
Color gcol = gcols[index];
float k = alpha * gcol.a;
ocols[index] = BlendColor(ocol, gcol, k);
}
}
tex.SetPixels(left, bottom, rectwid, recthei, ocols);
tex.Apply();
}
}
}
if (Input.GetMouseButtonUp(0))
{
StopSpray();
}
}
private void StartSpray(Transform obj)
{
isStart = true;
mat = obj.GetComponent<MeshRenderer>().sharedMaterial;
tex = (Texture2D)mat.GetTexture("_MainTex");
texWidth = tex.width;
texHeight = tex.height;
}
private void StopSpray()
{
isStart = false;
}
private Color BlendColor(Color a, Color b, float k)
{
Color c = Color.Lerp(a, b, k);
return c;
}
}
The core is based on drawing rect Just mix the sampling pattern with the background color array , The effect is as follows :
Pay special attention to rectangles “ breakthrough ” The problem of pattern sampling coordinates in the case of boundary .
Of course, there are still many problems that need to be solved , such as :
1. Model UV joint 、 How to deal with the joint spraying between models ?
2. spraying + Grid computing works together , similar zbrush operation ?
3. Can we handle it? 3d Texture matching model coloring ?
Later, there is time to slowly realize .
by the way , By the way , This kind of drawing operation is not suitable for use ComputeShader, I wrote a test , although ComputeShader In the calculation of color matrix CPU fast , But on the data bus bus The exchange is too time-consuming , Not suitable for this spraying operation .
边栏推荐
- SQL statement
- Fundamentals of machine learning: feature selection with lasso
- Solution of cursor thickening
- Small program graduation design is based on wechat order takeout small program graduation design opening report function reference
- Feign implements dynamic URL
- 2020-12-02 SSM advanced integration Shang Silicon Valley
- QML add gradient animation during state transition
- The force deduction method summarizes the single elements in the 540 ordered array
- How can enterprises optimize the best cost of cloud computing?
- Why can't it run (unresolved)
猜你喜欢

Magical usage of edge browser (highly recommended by program ape and student party)

Write the first CUDA program

TP5 automatic registration hook mechanism hook extension, with a complete case

In the process of seeking human intelligent AI, meta bet on self supervised learning

Since the "epidemic", we have adhered to the "no closing" of data middle office services

HackTheBox-baby breaking grad
![Jerry's watch listens to the message notification of the target third-party software and pushes the message to the device [article]](/img/8b/ff062f34d36e1caa9909c8ab431daf.jpg)
Jerry's watch listens to the message notification of the target third-party software and pushes the message to the device [article]

Maximum entropy model

MPLS③

String hash, find the string hash value after deleting any character, double hash
随机推荐
Make drop-down menu
Feign implements dynamic URL
be based on. NETCORE development blog project starblog - (14) realize theme switching function
Rearrangement of tag number of cadence OrCAD components and sequence number of schematic page
51 MCU external interrupt
Do you know the eight signs of a team becoming agile?
CLP information - how does the digital transformation of credit business change from star to finger?
Why can't it run (unresolved)
ThinkPHP uses redis to update database tables
Jerry's watch listens to the message notification of the target third-party software and pushes the message to the device [article]
Solution to the problem that jsp language cannot be recognized in idea
Méthode de calcul de la connexion MSSQL de la carte esp32c3
Lightweight Pyramid Networks for Image Deraining
Difference between value and placeholder
Setting function of Jerry's watch management device [chapter]
In the process of seeking human intelligent AI, meta bet on self supervised learning
Stringutils and collectionutils
Infiltration learning diary day19
Typescript basic knowledge sorting
A little understanding of GSLB (global server load balance) technology