当前位置:网站首页>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 .
边栏推荐
- Will the memory of ParticleSystem be affected by maxparticles
- Special copy UML notes
- Pesticide synergist - current market situation and future development trend
- 2022 R2 mobile pressure vessel filling certificate examination and R2 mobile pressure vessel filling simulation examination questions
- Douban scoring applet Part-3
- Which insurance products can the elderly buy?
- Bacteriostatic circle scanning correction template
- Query efficiency increased by 10 times! Three optimization schemes to help you solve the deep paging problem of MySQL
- AI helps make new breakthroughs in art design plagiarism retrieval! Professor Liu Fang's team paper was employed by ACM mm, a multimedia top-level conference
- C import Xls data method summary I (upload files and create Workbooks)
猜你喜欢
Basic editing specifications and variables of shell script
How can enterprises optimize the best cost of cloud computing?
JVM performance tuning and practical basic theory - medium
Openbionics exoskeleton project introduction | bciduino community finishing
Make drop-down menu
Introduction to Tianchi news recommendation: 4 Characteristic Engineering
In the process of seeking human intelligent AI, meta bet on self supervised learning
Force buckle day32
Applet graduation project is based on wechat classroom laboratory reservation applet graduation project opening report function reference
Do you know the eight signs of a team becoming agile?
随机推荐
MySQL deadly serial question 2 -- are you familiar with MySQL index?
Sequence sorting of basic exercises of test questions
Gee: create a new feature and set corresponding attributes
Huawei cloud micro certification Huawei cloud computing service practice has been stable
Magical usage of edge browser (highly recommended by program ape and student party)
Applet graduation design is based on wechat course appointment registration. Applet graduation design opening report function reference
Logical operator, displacement operator
Example 073 square sum value judgment programming requires the input of a and B, if a ²+ b ² If the result of is greater than 100, a is output ²+ b ² Value, otherwise output the result of a + B.
When the watch system of Jerry's is abnormal, it is used to restore the system [chapter]
Feign implements dynamic URL
Pratique technique | analyse et solution des défaillances en ligne (Partie 1)
Pyrethroid pesticide intermediates - market status and future development trend
In the process of seeking human intelligent AI, meta bet on self supervised learning
51 MCU external interrupt
Prose article appreciation - the rain in the warm country has never changed into cold, hard and brilliant flowers. Knowledgeable people think he is monotonous, and he thinks he is unlucky, doesn't he?
Day05 table
A little understanding of GSLB (global server load balance) technology
Neo4j learning notes
Jerry's update contact [article]
Maximum likelihood method, likelihood function and log likelihood function