Hello
I’m doing a wall painting mechanic in my game. Besides painting, I need to specify how much I painted the wall. How can I do that.
The project I used for the painting mechanics:
Hello
I’m doing a wall painting mechanic in my game. Besides painting, I need to specify how much I painted the wall. How can I do that.
The project I used for the painting mechanics:
Do you mean a “quantity” of paint, in addition to paint color?
Isn’t this just an additional texture channel?
In the video, he paints to just one channel of the texture. You can use RGB for color, and A for quantity, for instance. If you’ve already set up the system shown in the video this should be trivial to do, but without no info about what’s currently stopping you we can’t help much.
Or, maybe you want a “percentage of wall covered in paint” value? This can be done in a variety of ways, first thing that comes to mind is downscaling your texture to a single texel, then checking the intensity value of that texel (kind of like finding average luminance).
I need to express proportionally how much I paint the wall.
For example:
If half of the wall is painted, it’s like 50% painted. This is how I need to calculate proportionality.(in real time)
Then it’s my second guess, correct?
This is basically calculating an histogram of the texture: counting how many white pixels there are in the texture channel.
one cheap (not entirely correct) way to do this in the GPU is to downscale your texture to half its size multiple times, averaging the value 4 texels each time, until you just have one texel. The value of that texel can be interpreted as a percentage from 0 to 100%.
Sorry, I didn’t understand what you mean. The texel size of the texture is (0.0, 0.0).
The mask texture in Paintable Wall material follows our painting information. If I can find the amount of painting done on the mask texture, I can calculate how much the wall has been painted.
https://www.youtube.com/watch?v=oTHVMSlfCzA
using UnityEngine;
using UnityEngine.Rendering;
public class PaintManager : Singleton<PaintManager>
{
public Shader texturePaint;
public Shader extendIslands;
int prepareUVID = Shader.PropertyToID("_PrepareUV");
int positionID = Shader.PropertyToID("_PainterPosition");
int hardnessID = Shader.PropertyToID("_Hardness");
int strengthID = Shader.PropertyToID("_Strength");
int radiusID = Shader.PropertyToID("_Radius");
int blendOpID = Shader.PropertyToID("_BlendOp");
int colorID = Shader.PropertyToID("_PainterColor");
int textureID = Shader.PropertyToID("_MainTex");
int uvOffsetID = Shader.PropertyToID("_OffsetUV");
int uvIslandsID = Shader.PropertyToID("_UVIslands");
Material paintMaterial;
Material extendMaterial;
CommandBuffer command;
public override void Awake()
{
base.Awake();
paintMaterial = new Material(texturePaint);
extendMaterial = new Material(extendIslands);
command = new CommandBuffer();
command.name = "CommmandBuffer - " + gameObject.name;
}
public void initTextures(Paintable paintable)
{
RenderTexture mask = paintable.getMask();
RenderTexture uvIslands = paintable.getUVIslands();
RenderTexture extend = paintable.getExtend();
RenderTexture support = paintable.getSupport();
Renderer rend = paintable.getRenderer();
command.SetRenderTarget(mask);
command.SetRenderTarget(extend);
command.SetRenderTarget(support);
paintMaterial.SetFloat(prepareUVID, 1);
command.SetRenderTarget(uvIslands);
command.DrawRenderer(rend, paintMaterial, 0);
Graphics.ExecuteCommandBuffer(command);
command.Clear();
}
public void paint(Paintable paintable, Vector3 pos, float radius = 1f, float hardness = .5f, float strength = .5f, Color? color = null)
{
RenderTexture mask = paintable.getMask();
RenderTexture uvIslands = paintable.getUVIslands();
RenderTexture extend = paintable.getExtend();
RenderTexture support = paintable.getSupport();
Renderer rend = paintable.getRenderer();
paintMaterial.SetFloat(prepareUVID, 0);
paintMaterial.SetVector(positionID, pos);
paintMaterial.SetFloat(hardnessID, hardness);
paintMaterial.SetFloat(strengthID, strength);
paintMaterial.SetFloat(radiusID, radius);
paintMaterial.SetTexture(textureID, support);
paintMaterial.SetColor(colorID, color ?? Color.red);
extendMaterial.SetFloat(uvOffsetID, paintable.extendsIslandOffset);
extendMaterial.SetTexture(uvIslandsID, uvIslands);
command.SetRenderTarget(mask);
command.DrawRenderer(rend, paintMaterial, 0);
command.SetRenderTarget(support);
command.Blit(mask, support);
command.SetRenderTarget(extend);
command.Blit(mask, extend, extendMaterial);
Graphics.ExecuteCommandBuffer(command);
command.Clear();
}
}
using UnityEngine;
public class MousePainter : MonoBehaviour{
public Camera cam;
[Space]
public bool mouseSingleClick;
[Space]
public Color paintColor;
public float radius = 1;
public float strength = 1;
public float hardness = 1;
void Update(){
bool click;
click = mouseSingleClick ? Input.GetMouseButtonDown(0) : Input.GetMouseButton(0);
if (click){
Vector3 position = Input.mousePosition;
Ray ray = cam.ScreenPointToRay(position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f)){
Debug.DrawRay(ray.origin, hit.point - ray.origin, Color.red);
transform.position = hit.point;
Paintable p = hit.collider.GetComponent<Paintable>();
if(p != null){
PaintManager.instance.paint(p, hit.point, radius, hardness, strength, paintColor);
}
}
}
}
}
using UnityEngine;
public class Paintable : MonoBehaviour {
const int TEXTURE_SIZE = 1024;
public float extendsIslandOffset = 1;
RenderTexture extendIslandsRenderTexture;
RenderTexture uvIslandsRenderTexture;
RenderTexture maskRenderTexture;
RenderTexture supportTexture;
Renderer rend;
int maskTextureID = Shader.PropertyToID("_MaskTexture");
public RenderTexture getMask() => maskRenderTexture;
public RenderTexture getUVIslands() => uvIslandsRenderTexture;
public RenderTexture getExtend() => extendIslandsRenderTexture;
public RenderTexture getSupport() => supportTexture;
public Renderer getRenderer() => rend;
void Start() {
maskRenderTexture = new RenderTexture(TEXTURE_SIZE, TEXTURE_SIZE, 0);
maskRenderTexture.filterMode = FilterMode.Bilinear;
extendIslandsRenderTexture = new RenderTexture(TEXTURE_SIZE, TEXTURE_SIZE, 0);
extendIslandsRenderTexture.filterMode = FilterMode.Bilinear;
uvIslandsRenderTexture = new RenderTexture(TEXTURE_SIZE, TEXTURE_SIZE, 0);
uvIslandsRenderTexture.filterMode = FilterMode.Bilinear;
supportTexture = new RenderTexture(TEXTURE_SIZE, TEXTURE_SIZE, 0);
supportTexture.filterMode = FilterMode.Bilinear;
rend = GetComponent<Renderer>();
rend.material.SetTexture(maskTextureID, extendIslandsRenderTexture);
PaintManager.instance.initTextures(this);
}
void OnDisable(){
maskRenderTexture.Release();
uvIslandsRenderTexture.Release();
extendIslandsRenderTexture.Release();
supportTexture.Release();
}
}
The texel size cannot be 0,0, that would mean the size of the texture is 0 as well.
What I mean is that you can use an algorithm similar to the one used to calculate average luminance for tonemapping:
get your mask texture, and draw it to another texture that’s half its size using a shader that, for each texel in the half-size texture, averages 4 texels of the original one.
repeat the first step (halving the target texture resolution each time) until you get a texture of size 1x1.
the value of that texture’s only texel is your paint percentage.