Unity中获取地形的法线

news2024/9/25 2:31:21

之前,生成了地形图:(42条消息) 从灰度图到地形图_averagePerson的博客-CSDN博客

那末,地形的法线贴图怎么获取?

大概分为两个部分吧,先拿到法线数据,再画到纹理中去。

关于法线

计算

Unity - Scripting API: Mesh.RecalculateNormals (unity3d.com)

这个链接讲的是法线的计算,它是什么空间下的?无所谓了……

这里也不对地形搞什么几何变换,而且它是方向,模型空间世界空间是一个结果。

获取

Unity - Scripting API: Mesh.normals (unity3d.com)

直接一个等于号,然后这个法线是对顶点不是对三角形面片。

就这两点,没了。

存到纹理中

构造

Unity - Scripting API: Texture2D (unity3d.com)

这个变量,好像在unity shader里也经常出现嘞

要把法线数据存到Texture2D里,首先得构造一下对象啊,构造函数是什么?

Unity - Scripting API: Texture2D.Texture2D (unity3d.com)

RGBA32,构造RenderTexture的时候也有你。

怎么赋值?

赋值

Unity - Scripting API: Texture2D.SetPixels (unity3d.com)

  1. 直接传数组

  1. 数组要展平【mesh.normals其实就是一维的,那就可以直接用了】

  1. 最后需要Apply

  1. 从左到右从下到上【地形顶点正好也是这个顺序的】

官方示例代码:

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    void Start()
    {
        Renderer rend = GetComponent<Renderer>();

        // duplicate the original texture and assign to the material
        Texture2D texture = Instantiate(rend.material.mainTexture) as Texture2D;
        rend.material.mainTexture = texture;

        // colors used to tint the first 3 mip levels
        Color[] colors = new Color[3];
        colors[0] = Color.red;
        colors[1] = Color.green;
        colors[2] = Color.blue;
        int mipCount = Mathf.Min(3, texture.mipmapCount);

        // tint each mip level
        for (int mip = 0; mip < mipCount; ++mip)
        {
            Color[] cols = texture.GetPixels(mip);
            for (int i = 0; i < cols.Length; ++i)
            {
                cols[i] = Color.Lerp(cols[i], colors[mip], 0.33f);
            }
            texture.SetPixels(cols, mip);
        }
        // actually apply all SetPixels, don't recalculate mip levels
        texture.Apply(false);
    }
}

试一试

根据文档,调api就行了。

代码

计算法线的

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Terrian : MonoBehaviour
{
    public int N = 10;
    public Texture2D texture2dHeightMap;
    [Range(1,100)]
    public float heightRatio = 30.0f;//一个系数,控制地形总体的高度的

    public Texture2D normalTex;

    MeshRenderer meshRenderer;
    MeshFilter meshFilter;

    // 用来存放顶点数据
    List<Vector3> verts;
    List<int> indices;
    Vector3[] normals;

    private void Awake()
    {
    }

    private void Start()
    {
        verts = new List<Vector3>();
        indices = new List<int>();

        meshRenderer = GetComponent<MeshRenderer>();
        meshFilter = GetComponent<MeshFilter>();

        //normalTex = new Texture2D(texture2dHeightMap.width, texture2dHeightMap.height, TextureFormat.RGB24,-1,false);
        normalTex = new Texture2D(N,N, TextureFormat.RGB24, -1, false);//2.5D的地形,顶点的法线,法线贴图规模不是灰度图规模
    }

    private void Update()
    {
        Generate();

        normals = new Vector3[N * N];
        normals = meshFilter.mesh.normals;
        for(int i = 0; i < 10; ++i)
        {
            print(normals[i]);
        }

        Color[] colors = new Color[N * N];
        for(int i = 0; i < N * N; ++i)
        {
            colors[i] = new Color(normals[i].x, normals[i].y, normals[i].z);
        }

        normalTex.SetPixels(colors);
        normalTex.Apply(false);
    }

    public void Generate()
    {
        ClearMeshData();

        // 把数据填写好
        AddMeshData();

        // 把数据传递给Mesh,生成真正的网格
        Mesh mesh = new Mesh();
        mesh.vertices = verts.ToArray();
        mesh.triangles = indices.ToArray();

        mesh.RecalculateNormals();
        mesh.RecalculateBounds();

        meshFilter.mesh = mesh;
    }

    void ClearMeshData()
    {
        verts.Clear();
        indices.Clear();
    }

    void AddMeshData()
    {

        //01填充顶点数据
        for (int z = 0; z < N; ++z)//按先x后z的顶点排列顺序,所以先循环的是z
        {
            for(int x = 0; x < N; ++x)
            {
                int u = Mathf.FloorToInt(1.0f * x / N * texture2dHeightMap.width);
                int v = Mathf.FloorToInt(1.0f * z / N * texture2dHeightMap.height);
                float grayValue = texture2dHeightMap.GetPixel(u,v).grayscale;

                float height = grayValue*heightRatio;
                Vector3 temp = new Vector3(x, height, z);
                verts.Add(temp);
            }
        }
        //02填充索引数据
        for(int z = 0; z < N - 1; ++z)
        {
            for(int x = 0; x < N - 1; ++x)
            {
                int index_lb = z * N + x;//index of the left bottom vertex. lb = left bottom
                int index_lt = (z + 1) * N + x;
                int index_rt = (z + 1) * N + x + 1;
                int index_rb = z * N + x + 1;

                indices.Add(index_lb);indices.Add(index_lt);indices.Add(index_rt);
                indices.Add(index_rt);indices.Add(index_rb);indices.Add(index_lb);
            }
        }
    }


    
}

显示法线贴图的。这个是在摄像机上的——屏幕后处理嘛!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShowTexture2D : MonoBehaviour
{
    public Terrian terrian;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(terrian.normalTex, destination);
    }


}

结果

看着……走势差不多吧。而且,绿色的,表示向上,符合的。

对不对?在这种情况下,没法看出来。只能接着往下做,然后拔出萝卜带出泥巴。

纯平面是纯绿色

高度系数越大,颜色越深

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

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

相关文章

第4讲 cameraserver.rc详解(下)

本讲是Android Camera Native Framework专题的第4讲&#xff0c;我们介绍cameraserver.rc详解&#xff08;下&#xff09;&#xff0c;包括如下内容&#xff1a;Android init语言简介cameraserver.rc详解serviceuser选项group选项ioprio选项task_profiles选项rlimit选项更多&am…

领域自适应 DA Domain Adaptation

领域自适应是与机器学习和转移学习相关的领域。 当我们的目标是从源数据分布中学习在不同&#xff08;但相关&#xff09;的目标数据分布上的良好性能模型时&#xff0c;就会出现这种情况。 例如&#xff0c;常见垃圾邮件过滤问题的任务之一在于使模型从一个用户&#xff08;源…

2023年金三银四必备软件测试常见面试题1500问!!!【测试思维篇】

五、测试思维5.1 打电话功能怎么去测&#xff1f;我们会从几个方面去测试&#xff1a;界面、功能、兼容性、易用性、安全、性能、异常。1&#xff09;界面我们会测试下是否跟界面原型图一致&#xff0c;考虑浏览器不同显示比例&#xff0c;屏幕分辨率。2&#xff09;功能&#…

SpringBoot:SpringBoot配置文件application.properties、application.yml 和 application.ymal(2)

SpringBoot配置文件1. 配置文件格式1.1 application.properties配置文件1.2 application.yml配置文件1.3 application.yaml配置文件1.4 三种配置文件优先级和区别2. yaml格式2.1 语法规则2.2 yaml书写2.2.1 字面量&#xff1a;单个的、不可拆分的值2.2.2 数组&#xff1a;一组按…

《分布式技术原理与算法解析》学习笔记Day24

分布式缓存 在计算机领域&#xff0c;缓存是一个非常重要的、用来提升性能的技术。 什么是分布式缓存&#xff1f; 缓存技术是指用一个更快的存储设备存储一些经常用到的数据&#xff0c;供用户快速访问。 分布式缓存是指在分布式环境或者系统下&#xff0c;把一些热门数据…

全面零信任?Dell搞了个“大动作”

1860年&#xff0c;清朝僧格林沁带领数万骑兵&#xff0c;朝着数千英法联军发起猛烈冲锋&#xff0c;企图依靠清朝凶狠的骑兵突击战术击溃对方。然而&#xff0c;面对已经完成了近代化的西方军队&#xff0c;原来无往不利的八旗骑兵被打的土崩瓦解&#xff0c;再无任何抵抗的能…

Editor工具开发基础四:窗口EditorWindow

目录 1.设置窗口位置和大小 2.设置窗口最大和最小 3.设置窗口标题 4.设置窗中窗 BeginWindows和EndWindows 5.添加窗中窗可拖动 GUI.DragWindow() 完整代码&#xff1a; public class EditorToolWindow : EditorWindow {public static EditorToolWindow ins;[MenuItem(&q…

Elasticsearch:保护你的 Elasticsearch 实例 - 如何使用带有内置证书的 Docker 镜像

使用 docker 来构建 Elasticsearch 集群为开发者们带来了极大的方便。在我之前的文章中&#xff1a; Elasticsearch&#xff1a;使用 Docker compose 来一键部署 Elastic Stack 8.x Elasticsearch&#xff1a;如何在 Docker 上运行 Elasticsearch 8.x 进行本地开发 Elastic&am…

JavaSE-线程池(5)- ThreadPoolExecutor常用方法

JavaSE-线程池&#xff08;5&#xff09;- ThreadPoolExecutor常用方法 invokeAll ExecutorService 接口中定义的方法&#xff0c;给定一组任务&#xff0c;在所有任务执行完成时返回一个 Futures 列表&#xff0c;其中包含它们的状态和结果。 /*** Executes the given task…

Java基础:常见API(Math,System,Runtime,Object,BigInteger,BigDecima)

1.常见API 1.1 Math类 向上取整是向着数轴右边走的意思, 负数也是. 也可以叫进一法, 不论正数负数都会往右走一. 向下取整是向着数轴左边走. 也可以叫去尾法, 不论正负数都会将小数点后的数字去掉. 1.1.2 练习 // 判断有多少水仙花数int count 0;for (int i 100; i < 1…

代码随想录算法训练营九期第十三天 | 239. 滑动窗口最大值、347.前 K 个高频元素、总结

打卡第十三天&#xff0c;昨天休息&#xff0c;今天继续栈和队列&#xff0c;重新复习了单调队列&#xff0c;上次看ACwing的视频学了单调队列&#xff0c;没有完全学明白&#xff0c;重学之后比之前清晰多了 今日任务 滑动窗口最大值 347.前 K 个高频元素总结 239. 滑动窗口最…

【Ap AutoSAR入门与实战开发02】-【Ap_s2s模块01】: s2s的背景

总目录链接==>> AutoSAR入门和实战系列总目录 文章目录 1 s2s的背景?2 AUTOSAR 方法应支持车辆的无缝开发2.1 面向服务的ECU的解读2.2 面向信号的ECU的解读2.3 通过网关ECU实现转换1 s2s的背景? Cp AutoSAR基于传统的can,lin,flexray总线的通信,一般是面向信号设…

汽车网络安全需求分析方法综述

引言&#xff1a; 近年来&#xff0c;汽车的网络安全问题逐渐被重视&#xff0c;在汽车产品的全生命周期中&#xff0c;需要进行网络安全风险管理&#xff0c;其主要活动包括网络安全需求分析、安全策略设计与实施、运营阶段安全监控与应急响应等。 安全需求分析工作作为系统安…

信息安全概论之《密码编码学与网络安全----原理与实践(第八版)》

前言&#xff1a;在信息安全概论课程的学习中&#xff0c;参考了《密码编码学与网络安全----原理与实践&#xff08;第八版&#xff09;》一书。以下内容为以课件为主要参考&#xff0c;课本内容与网络资源为辅助参考&#xff0c;学习该课程后作出的总结。 一、信息安全概述 1…

【蓝桥杯集训9】单调栈、单调队列(模拟栈、模拟队列)专题(3 / 3)

目录 单调栈模板 1、模拟栈 单调队列模板 1、模拟队列 2、双端队列 135. 最大子序和 - 前缀和滑动窗口单调队列 单调栈模板 什么时候用单调栈&#xff1f; 求序列中每一个数左边或右边第一个比它大或小的数 1、单调递增栈 在保持栈内元素单调递增前提下&#xff08;如果…

Redis 主从库如何实现数据一致?

目录 1、主从库间如何进行第一次同步&#xff1f; 2、主从级联模式分担全量复制时的主库压力 3、主从库间网络断了怎么办&#xff1f; 总结 // 好的文章&#xff0c;值得反复去读 Redis 具有高可靠性&#xff0c;这里有两层含义&#xff1a;一是数据尽量少丢失&#xff0c;…

2023JAVA面试题全集超全面超系统超实用!早做准备早上岸

2022年我凭借一份《Java面试核心知识点》成功拿下了阿里、字节、小米等大厂的offer&#xff0c;两年的时间&#xff0c;为了完成我给自己立的flag&#xff08;拿下一线互联网企业offer大满贯&#xff09;&#xff0c;即使在职也一直在不断的学习与备战面试中&#xff01;——或…

【Spark分布式内存计算框架——Spark Streaming】6. DStream(下)流式应用状态 Kafka

3.3 流式应用状态 使用SparkStreaming处理实际实时应用业务时&#xff0c;针对不同业务需求&#xff0c;需要使用不同的函数。SparkStreaming流式计算框架&#xff0c;针对具体业务主要分为三类&#xff0c;使用不同函数进行处理&#xff1a; 业务一&#xff1a;无状态Statel…

【数电基础】——数制和码制

目录 1.概述 1.信号&#xff08;电路&#xff09;的功能 2.信号的分类&#xff1a; 3.数字信号的输入和输出的逻辑关系表示方法 2.数制 1.十进制&#xff08;D/d&#xff09; 2.二进制(B/b) 3.八进制&#xff08;O/o&#xff09; 4.十六进制&#xff08;H/h&#xff09;…

使用huggingface微调预训练模型

官方教程&#xff1a;https://huggingface.co/docs/transformers/training 准备数据集&#xff08;基于datasets库&#xff09; train.json 数据格式&#xff1a; {"source":"你是谁&#xff1f;", "target":"我是恁爹"} {"so…