unity用ComputeShader做模型流体喷涂喷绘工具

news2024/11/24 8:39:01

最近在研究喷涂喷绘项目,需要做大量纹理图形运算,因此更适合用GPU来处理,在unity中用ComputeShader完成像素运算,SurfaceShader完成纹理渲染。

实现思路:

1.用射线碰撞模型,得到碰撞纹理坐标brushX和brushY

2.ComputeShader拿到brush坐标,在纹理相应的位置做像素运算,并输出纹理ComputeTexture

3.通过SurfaceShader渲染纹理

管理代码:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.VersionControl;
using UnityEngine;
using UnityEngine.UI;

namespace Game.Patinter
{
    public class PatintManager : MonoBehaviour
    {
        //图片尺寸
        public static int textureSize = 1024;

        //渲染模型
        public GameObject paintSurfacePanel;
        
        //渲染模型
        public GameObject paintDataPanel;

        //运算shader
        private ComputeShader computeShader;
        
        //运算纹理
        private RenderTexture computeTexture;
        
        //输出纹理
        private Texture2D resultTexture;
        
        private int computeShaderKernel;
        
        // Start is called before the first frame update
        void Start()
        {
            //实例化shader
            computeShader = (ComputeShader) Resources.Load("Shader/PaintComputeShader", typeof(ComputeShader));
            computeShaderKernel = computeShader.FindKernel("PaintCompute");

            //创建纹理
            computeTexture = new RenderTexture(textureSize, textureSize, 24);
            computeTexture.enableRandomWrite = true;
            computeTexture.Create();

            //绑定纹理
            computeShader.SetTexture(computeShaderKernel, "paintTexture", computeTexture);
            computeShader.SetInt("textureSize", textureSize);
            
            //输出纹理
            resultTexture = new Texture2D(textureSize, textureSize, TextureFormat.ARGB32, false);
        }

        // Update is called once per frame
        void Update()
        {
            //鼠标左键按下开始喷绘
            if (Input.GetMouseButton(0))
            {
                var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit hit;
                Physics.Raycast(ray, out hit, 100);
                
                //检测到碰撞体
                if (hit.collider != null)
                {
                    var hitX = hit.textureCoord.x;
                    var hitY = hit.textureCoord.y;
                    
                    Render(hitX, hitY);
                    return;
                }
                
                //未检测到碰撞体
                Render(0, 0);
            }
            else
            {
                Render(0, 0);
            }
            
            //空格清空面板
            if (Input.GetKeyDown(KeyCode.Space))
            {
                computeTexture = new RenderTexture(textureSize, textureSize, 24);
                computeTexture.enableRandomWrite = true;
                computeTexture.Create();

                computeShader.SetTexture(computeShaderKernel, "paintTexture", computeTexture);

                Render(0, 0);
            }
        }

        void Render(float hitX, float hitY)
        {
            //传入绘制点
            computeShader.SetFloat("brushX", hitX * textureSize);
            computeShader.SetFloat("brushY", hitY * textureSize);
            
            //纹理运算
            computeShader.Dispatch(computeShaderKernel, textureSize / 8, textureSize / 8, 1);

            //拷贝纹理
            RenderTexture.active = computeTexture;
            resultTexture.ReadPixels(new Rect(0, 0, textureSize, textureSize), 0, 0);
            resultTexture.Apply();

            //渲染纹理
            paintDataPanel.GetComponent<MeshRenderer>().material.SetTexture("_MainTex", resultTexture);
            paintSurfacePanel.GetComponent<MeshRenderer>().material.SetTexture("_PaintDataTex", resultTexture);
        }
    }
}

代码很简单,就80行;在Start中初始化;Update中检测射线实时渲染;Render负责传入参数启动运算。

ComputeShader:

// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel PaintCompute

// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> paintTexture;

float brushX;
float brushY;

int textureSize;

[numthreads(8,8,1)]
void PaintCompute(uint3 id : SV_DispatchThreadID)
{
    //绘制点有效
    if (brushX != 0 && brushY != 0)
    {
        // TODO: insert actual code here!
        //和绘制点距离
        float dis = distance(id.xy, float2(brushX, brushY));

        //距离小于90个像素
        if (dis < 90)
        {
            float4 v = paintTexture[id.xy];

            //添加边缘模糊
            float rate = 1 - dis / 90;
            v.x += 0.04 * rate;
            
            paintTexture[id.xy] = v;
        }
    }

    //流体效果
    if (id.y > 0)
    {
        float4 v = paintTexture[id.xy];

        //大于0.9向下流动
        if (v.x > 0.9)
        {
            v.x -= 0.02f;
            paintTexture[id.xy] = v;
            
            float4 down = paintTexture[id.xy - float2(0, 1)];
            if (down.x < 0.8f)down.x = 0.8;
            down += float4(0.0178f, 0, 0, 0);
            
            paintTexture[id.xy - float2(0, 1)] = down;
        }
    }
}

为了更像喷绘的效果,需要加上边缘模糊和流体效果

模型shader:

Shader "Custom/PaintSurfaceShader"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _PaintDataTex ("PaintDataTex (RGB)", 2D) = "black" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _PaintDataTex;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldRefl;
            INTERNAL_DATA
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
        // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf(Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
            fixed4 p = tex2D(_PaintDataTex, IN.uv_MainTex);

            o.Albedo = c.rgb * (1 - p.r) + _Color * p.r;

            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

将模型本身的纹理和喷涂上色混合

热力图Shader:

Shader "Custom/PaintDataShader"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "black" {}
        _ColorMapTex ("ColorMap (RGB)", 2D) = "black" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _ColorMapTex;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldPos;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
        // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf(Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
            fixed4 m = tex2D(_ColorMapTex, float2((1 - c.r)*0.9 + 0.09, 0.1));
            o.Albedo = m.rgb;

            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

此功能是为了反映喷涂渲染状况

效果:

 左边是热力图,右边效果图

源码:https://download.csdn.net/download/u014261855/87777737

后记:流体没有+法线,还有优化空间,有兴趣的朋友可以优化讨论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/518832.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PMP课堂模拟题目及解析(第8期)

71. 项目经理负责管理一个处于执行阶段的项目&#xff0c;并希望审查项目范围以进行成本结算&#xff0c;项目经理发现在工作分解结构&#xff08;WBS &#xff09;中遗漏了一项可交付成果。项目经理下一步应该怎么做&#xff1f; A. 询问干系人是否需要添加这些遗漏的可交付…

【18】SCI易中期刊推荐——计算机科学(中科院2区)

💖💖>>>加勒比海带,QQ2479200884<<<💖💖 🍀🍀>>>【YOLO魔法搭配&论文投稿咨询】<<<🍀🍀 ✨✨>>>学习交流 | 温澜潮生 | 合作共赢 | 共同进步<<<✨✨ 📚📚>>>人工智能 | 计算机视觉…

【LeetCode】209.长度最小的子数组

209. 长度最小的子数组 思路一&#xff1a;暴力解法 通过两个for循环&#xff0c;从头开始找符合条件的子序列。暴力解法无法通过本题&#xff0c;超出时间限制&#xff0c;所以仅供参考。 代码如下&#xff1a; 暴力解法1&#xff1a;下面的代码是通过申请一个新的数组&#x…

人脸检测和人体检测4:C++实现人脸检测和人体检测(含源码,可实时检测)

人脸检测和人体检测4&#xff1a;C实现人脸检测和人体检测(含源码&#xff0c;可实时检测) 目录 人脸检测和人体检测4&#xff1a;C实现人脸检测和人体检测(含源码&#xff0c;可实时检测) 1. 前言 2. 人脸检测和人体检测检测模型&#xff08;YOLOv5&#xff09; &#xf…

AI教父Geoffrey Hinton:AGI革命堪比车轮的发明

作者 | Yana Khare 译者 | 平川 来源 | AI前线 ID | ai-front AI 教父&#xff1a;Geoffrey Hinton Geoffrey Hinton 通常被认为是“人工智能教父”&#xff0c;他在机器学习广泛流行之前就一直是这个领域的开拓者。Hinton 对人工神经网络和机器学习算法的发展做出了重大的贡…

单链表OJ题:LeetCode--234.回文链表

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;今天给大家带来的是LeetCode中203题&#xff1a;移除链表元素 数据结构 &#xff1a;数据结构专栏 作 者 &#xff1a;stackY、 LeetCode&#xff1a;LeetCode刷题训练营 LeetCode--234.回文链表&#xff1a;https:…

【利用AI让知识体系化】3万多字让你我快速入门数据结构与算法

文章目录 第一章&#xff1a;介绍数据结构与算法1.1 数据结构的概念1.2 算法的概念1.3 数据结构与算法的关系1.4 为什么需要学习数据结构与算法 第二章&#xff1a;时间与空间复杂度2.1 什么是时间复杂度2.2 时间复杂度的算法分析2.3 什么是空间复杂度2.4 空间复杂度的算法分析…

Lombok工具 : 常用注解介绍 (全)

文章目录 介绍引入Maven依赖常用的注解 NoArgsConstructor/AllArgsConstructorRequiredArgsConstructorGetter/SetterToString/EqualsAndHashCodeDataBuilderAccessors 其他注解 SneakyThrowsValueCleanupNotNullSynchronizedLog、Log4j、Slf4j、Log4j2、CommonsLog、XSlf4j等…

无需繁琐手工操作,如何利用Web自动化测试元素定位做到快速高效的测试?

1、什么是Web自动化测试元素定位&#xff1f; 在Web自动化测试中&#xff0c;元素定位是非常重要的环节。因为我们需要找到需要进行操作的页面元素&#xff0c;例如按钮、输入框、下拉菜单等等。元素定位可以帮助我们在自动化测试中对这些元素进行操作&#xff0c;如点击、输入…

老域名查询工具- 在线域名批量查询工具

域名批量查询工具 域名批量查询工具是一种帮助用户快速查询多个域名信息的工具&#xff0c;通常能够自动扫描一组域名的WHOIS信息、DNS、IP地址、服务器等各种信息&#xff0c;并提供快速的结果反馈。 以下是域名批量查询工具主要的优点&#xff1a; 提高工作效率&#xff1a…

培训出来包装三年经验拿21K,入职8天就被裁了....

最近翻了一些网站的招聘信息&#xff0c;把一线大厂和大型互联网公司看了个遍&#xff0c;发现市场还是挺火热的&#xff0c;虽说铜三铁四&#xff0c;但是软件测试岗位并没有削减多少&#xff0c;建议大家有空还是多关注和多投简历&#xff0c;不要闭门造车&#xff0c;错过好…

腾讯云面试题-重复的字符串+设计测试用例

原题出自&#xff1a;https://leetcode.cn/problems/repeated-substring-pattern/ 题目&#xff1a; 题解&#xff1a; 1、字符串长度为空&#xff0c;则返回false。 2、字符串长度为1&#xff0c;则为true&#xff0c;是由子串构成的。 3、字符串长度为2&#xff0c;判断首…

c++模板 理解(图、文、代码)

嗯&#xff0c;又是发个重点&#xff0c;拿出来单独做笔记 本文有参考以下博文&#xff1a; 1、C template \ auto_c template auto_rainbow_lucky0106的博客-CSDN博客 2、C 中的 const & &#xff08;常引用&#xff09;参数 - 知乎 3、C template \ auto_c template …

一文读懂国内首本《牛客2023金融科技校园招聘白皮书》

金融科技人才作为金融数字化转型的关键支撑&#xff0c;但当下金融科技人才培养体系尚未形成&#xff0c;优秀的金融科技人才供不应求&#xff0c;目前存在严重的人才供给问题。 据调研数据统计&#xff0c;96.8%的金融机构存在金融科技人才缺口&#xff0c;54.8%的机构认为新…

PDU配电单元推荐——同为科技(TOWE)自接线工程安全机柜PDU

随着信息化、数字化互联网技术在各行各业的迅速发展&#xff0c;符合现代化需求的机房建设尤为重要&#xff0c;其背后蕴藏着广阔的经济效益与市场前景。现代机房具备先进性、实用性、合理性、拓展性、精细化等特点&#xff0c;除了核心的计算机系统要实现安全可靠的平稳运行外…

UNIX中的文件属性和打开目录函数 lstat、opendir、readdir 5.13

文件属性获取与修改相关的操作函数 stat()fstat()/Istat() 文件类型 设置用户ID和设置组ID 文件存取许可权 新文件和目录的所有权 文件长度 文件截短. 文件的时间 打开目录 读取目录项 以下三个函数可以获取文件/目录的属性信息: #include <unistd.h> #include <sy…

小黑子—多媒体技术与运用基础知识四:计算机动画与视频处理技术

多媒体技术与运用4.0 多媒体系列第四章1. 计算机动态视觉媒体1.1 动态视觉媒体产生原理1.2 动态视频文件特点1.3 技术参数1.4 动画与视频的异同 2. 计算机动画的基础2.1 计算机动画的类型2.1.1 从动画生成机制划分2.1.2 从画面透视效果划分2.1.3 从画面形成规则和制作方法划分2…

PaLM 2全面反超反超GPT-4,谷歌官宣AI重构搜索,朝着ChatGPT微软开炮

来源 | 量子位 | 公众号 QbitAI 万众瞩目&#xff0c;谷歌的反击来了。 现在&#xff0c;谷歌搜索终于要加入AI对话功能了&#xff0c;排队通道已经开放。 当然这还只是第一步。 大的还在后面&#xff1a; 全新大语言模型PaLM 2正式亮相&#xff0c;谷歌声称它在部分任务超…

IT行业项目管理软件,你知道多少?

IT行业项目管理软件&#xff0c;主要得看用来管理的是软件研发还是做IT运维。如果是做软件研发&#xff0c;那还得看项目经理是用什么思路&#xff0c;是传统的瀑布式方法还是敏捷的方法或者是混合的方法。 如果用来管理的是IT运维工作&#xff0c;那么很多通用型的项目管理软件…

微服架构基础设施环境平台搭建 -(三)Docker+Kubernetes集群搭建

微服架构基础设施环境平台搭建 -&#xff08;三&#xff09;DockerKubernetes集群搭建 通过采用微服相关架构构建一套以KubernetesDocker为自动化运维基础平台&#xff0c;以微服务为服务中心&#xff0c;在此基础之上构建业务中台&#xff0c;并通过Jekins自动构建、编译、测试…