双面渲染美翻了!零基础也能学会,源码直接带走…

2023-11-07 20:10

本文主要是介绍双面渲染美翻了!零基础也能学会,源码直接带走…,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

你是否也曾好奇?

如果要渲染一片树叶,但树叶的两个面的外观通常是不同的,如何做到正反面效果不一样呢?

4364ef21985054ab2e61715feccedbf8.png

图片来自网络

如果要渲染像下图中某个对象的一部分,又当如何做呢?

f95f3705649a2b451eead20ba22be1e0.png

细节指引: 图中,处于虚空连接口背后的龙是看得见的,从虚空连接口钻出来的龙只能看到一部分身体。

3D图形管线在进行背面裁剪的时候,是如何判断一个三角形是正对摄像机还是背对摄像机的呢?如下图所示:

c2129925ca63e6fc6792109392eb2495.png

图片来自网络

麒麟小贴士: 背面裁剪是图形管线在 vs 之后和 fs 之前做的一次预剔除处理。
通过背面裁剪,图形管线可以在渲染模型的时候,剔除背对着我们的面,(比如一个正对着我们的人物模型,他的背面),以提升渲染性能。

看完本文后,你将掌握以下知识点:

  • 点法式平面表示法

  • 正背面判定

  • 双面材质

  • 自定义裁剪面

三维空间平面表示法

46181809c739a4c68273fa92067d61ca.png

图片来自网络

在 3D 游戏编程相关的数学书里,我们可以很容易找到上图中的内容。

它用代数的方式解释了为什么可以用 Ax + By + Cz + D = 0 来表示平面。

A,B,C 是平面的单位化法向量的 XYZ 值,它决定了平面的正方向,D 为坐标原点到平面的距离的相反数

将一个点从原点朝向量(A,B,C)正方向移动 -D 的距离,可以得到平面上的一个点,因此这个表示法被称为:点法式

麒麟小贴士: 许多教材中,对矩阵运算和相关公式都是做的代数推导,晦涩难懂。但数学是对事物规律的体现,代数推导不是唯一解。


对于 3D 图形学中的诸多运算,可以使用空间几何来推导。空间几何可以使我们理解起来更加简单直观。


像反射公式、镜像矩阵、坐标系转换、投影矩阵等与平面相关的原理,大家不妨试试用几何原理理解一次。

接下来,我们尝试着用空间几何的方式理解一次平面公式(可能需要一些空间想象力):

b695f281772b7bdccace4580928b2db2.png

采用WPS Presentation绘制

1、在原点处,向任意方向(A,B,C)发射出一条射线,则这条射线的起点为记P0(0,0,0),方向记为 Direction(A,B,C)

2、我们发现,这条射线可以确定一个唯一的面:经过原点且垂直于条射线方向。那么 Direction(A,B,C) 恰好就是这个面的法向量。

3、将这个射线的起点沿 Direction(A,B,C) 正向或者负向移动,可以调节它在空间中的位置。假设我们移动到了点 P0(x0,y0,z0),由投影原理可知,此时射线起点到原点的距离 d 的计算方式为:

  • d = dot(Direction,P0)

  • => d = A * x0 + B * y0 + C * z0

此种情况下,我们依然可以得到一个 经过点 P0 且与 Direction 垂直的唯一面。

4、由于Direction是空间中任意方向,P0 是射线上的任意点,我们可以得到一个结论: 一个向量和一个距离坐标系原点的值可以用来表示三维空间中的任意平面。

5、如果一个点 P(x,y,z) 在平面上,可知:

  • Ax + By + Cz = d

  • => Ax + By + Cz - d = 0

6、不难看出 Ax + By + Cz 刚好是 Direction 与 P 的点乘,而在 3D 空间运算中,在参与矩阵运算时,点的表示法为 P(x,y,z,1)。因此, 若将平面记作四维向量 Plane(A,B,C,D) 其中 (D = -d),则恰好满足点乘运算规则,也完全符合代数推导结果:Ax + By + Cz + D = 0

7、每个平面,都会将空间一分为二,我们将法线方向的空间视为平面的正面,法线反方向的空间视为平面的背面

正背面的判定

86b85913810dbf82e864a4e4ab67dfe6.png

图片来自网络

3D 模型中,每一个面,都可以用一个法线来表示朝向。如上图所示,紫色的圆锥指向的方向即为法线方向。

由于点乘的规律(夹角小于90度时为正,大于90度时为负)刚好符合判断机制,所以我们通常采用点乘进行一些正负向的判断。

由点乘规则可知:

  • dot(Plane,P) > 0 时,点在平面正面;

  • dot(Plane,P) = 0 时,点在平面上;

  • dot(Plane,P) < 0 时,点在平面背面。

双面材质

有了上面的关于平面的基础知识,双面材质的实现就非常易于理解了。

实现双面材质需要注意三点:

1、设置材质的 CullModeNone,如下图所示:

04192404f32e5bab4c0acdd55b0caccd.png

2、根据朝向判断采用正面还是背面的贴图和颜色

7c567685aa107514877159601fc4f55f.png

3、当为背面时,翻转法线,才能确保光照正确,如下图所示:

fc0c3dd314cea27dc4cc7dbac50fd3c5.png

最终实现的效果如下:

be6dfe22efdcc1287f51edb59af92869.gif

应用场景

双面材质可以应用在一些需要双面显示且双面材质不同的地方,包括但不限于:

  • 人物衣服、裙子、飘带里外

  • 单向透光玻璃

  • 阔叶植被(如芭蕉树、椰子树等)

  • 布料、纸张等特殊展示场合

自定义裁剪面可以应用在一些需要剔除部分物体的地方,包括但不限于:

  • 实时水面、镜面渲染

  • 模型特效

  • 因功能导致的特殊渲染需求

自定义裁剪面

自定义裁剪面算是平面最基础的应用,它的思路与背面剔除很接近:

1、在Shader自定义一个平面

在Shader中定义平面非常简单,只需两步:

  • 在 properties 中添加一个 clipPlane 属性

  • 在 uniform block 中声明一个 vec4 clipPlane。

2、剔除平面背后的内容

使用 dot 函数进行平面判定,若位置处于平面背后,则使用 discard 指令进行剔除,如下图所示:

225a7b47e315e16ff67b34ec29dfd82d.png

为了更好地展示裁剪效果,麒麟子写了一个虚空飞龙入侵世界的 DEMO。

天空中出现了另一个时空与这个世界的连接口,龙群从虚空连接口陆续飞出并在连接口盘旋,效果如下所示:

Shader编写入门科普:Shader到底能做些什么效果?

这篇关于双面渲染美翻了!零基础也能学会,源码直接带走…的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/365999

相关文章

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显