首页 > 其他分享 >从0开始做一个软渲染器 —— 法线变换

从0开始做一个软渲染器 —— 法线变换

时间:2024-03-05 16:11:05浏览次数:24  
标签:法线 Square 渲染器 Mat ModelMatrix 变换 vec normalMatrix

从0开始做一个软渲染器 —— 法线变换

1. 为什么要进行法线变换

如果只对模型的位置进行变换,例如旋转和缩放(位移不会改变法线),而不考虑法线进行相应变换,那么模型的光照就一整个乱掉。

2. 怎么进行法线变换

如果模型只是旋转或者XYZ等比例的缩放,那么法线直接乘以ModelMatrix不会有什么问题,但是如果不是等比例的缩放就会出现问题,参考文章图形学 | Shader |用一篇文章理解法线变换、切线空间、法线贴图 - 知乎 (zhihu.com)

假设光线是垂直向-Z方向,光照强度 = \(normal * -light.dir\)正常光照效果如图:

normal_corr.png

如果缩放比例\(XYZ = 1, 1, 5\),那么按理来说脸上法线正确情况会向两侧扩,也就是的光照强度变弱,脸会变暗。但是直接把法线乘以ModelMatrix的效果如下:

normal_err.png

脸明显变白了,显然法线出现错误。

如何进行正确的法线变换参考下面文章:

正确的normal transform matrix

\[(M^{-1})^T \]

求逆操作是一个消耗很大的过程,但是由于Scale Matrix, Rotate Matrix 和 Traslate Matrix的特殊性可以直接避免普通矩阵的求逆操作,参考下面两篇文章:

按照公式(不考虑T变换)

\[M=\left( \begin{matrix} \vec{X} & 0 \\ \vec{Y} & 0 \\ \vec{Z} & 0 \\ \vec{T} & 1 \\ \end{matrix} \right), M^{-1}=\left( \begin{matrix} \frac{1}{{\left|\vec{X}\right|}^{2}}\vec{X} & \frac{1}{{\left|\vec{Y}\right|}^{2}}\vec{Y} & \frac{1}{{\left|\vec{Z}\right|}^{2}}\vec{Z} & \vec{0} \\ -\vec{T}\cdot\frac{1}{{\left|\vec{X}\right|}^{2}}\vec{X} & -\vec{T}\cdot\frac{1}{{\left|\vec{Y}\right|}^{2}}\vec{Y} & -\vec{T}\cdot\frac{1}{{\left|\vec{Z}\right|}^{2}}\vec{Z} & 1 \\ \end{matrix} \right) \]

代码如下:

V2F BasicShader::VertexShader(const Vertex& v)
{
    V2F v2f;
    v2f.m_WorldPos	= v.m_Position * m_ModelMatrix;
    v2f.m_ScreenPos = v.m_Position * m_ModelMatrix * m_VPMatrix;

    //法线变换, 求变换矩阵
    float MagX_Square =	m_ModelMatrix.m_Mat[0][0] * m_ModelMatrix.m_Mat[0][0] +
                        m_ModelMatrix.m_Mat[0][1] * m_ModelMatrix.m_Mat[0][1] +
                        m_ModelMatrix.m_Mat[0][2] * m_ModelMatrix.m_Mat[0][2];

    float MagY_Square = m_ModelMatrix.m_Mat[1][0] * m_ModelMatrix.m_Mat[1][0] +
                        m_ModelMatrix.m_Mat[1][1] * m_ModelMatrix.m_Mat[1][1] +
                        m_ModelMatrix.m_Mat[1][2] * m_ModelMatrix.m_Mat[1][2];

    float MagZ_Square = m_ModelMatrix.m_Mat[2][0] * m_ModelMatrix.m_Mat[2][0] +
                        m_ModelMatrix.m_Mat[2][1] * m_ModelMatrix.m_Mat[2][1] +
                        m_ModelMatrix.m_Mat[2][2] * m_ModelMatrix.m_Mat[2][2];


    Matrix4 normalMatrix = m_ModelMatrix;

    normalMatrix.m_Mat[3][0] = 0;
    normalMatrix.m_Mat[3][1] = 0;
    normalMatrix.m_Mat[3][2] = 0;

    normalMatrix.m_Mat[0][0] /= MagX_Square;
    normalMatrix.m_Mat[0][1] /= MagX_Square;
    normalMatrix.m_Mat[0][2] /= MagX_Square;
    normalMatrix.m_Mat[1][0] /= MagY_Square;
    normalMatrix.m_Mat[1][1] /= MagY_Square;
    normalMatrix.m_Mat[1][2] /= MagY_Square;
    normalMatrix.m_Mat[2][0] /= MagZ_Square;
    normalMatrix.m_Mat[2][1] /= MagZ_Square;
    normalMatrix.m_Mat[2][2] /= MagZ_Square;


    v2f.m_Normal	= v.m_Normal * normalMatrix;
    v2f.m_Texcoord	= v.m_TexCoord;
    v2f.m_Color		= v.m_Color;


    return v2f;
}

结果如下图所示,符合预期:

normal_corr2.png

标签:法线,Square,渲染器,Mat,ModelMatrix,变换,vec,normalMatrix
From: https://www.cnblogs.com/dogwealth/p/18054287

相关文章

  • 从零开始做一个软渲染器——视锥剔除、齐次裁剪和背面剔除
    从零开始做一个软渲染器——视锥剔除、齐次裁剪和背面剔除项目地址:https://github.com/DogWealth/PIRenderer1.视锥剔除最简单的视锥剔除只需要在齐次空间(也就是透视投影变换之后,透视除法之前)中对三角形的顶点判断是否满足如下条件\[-w\lex\lew\\-w\ley\lew\\-w\le......
  • 拉普拉斯变换的积分上下限,或者说积分路径,是复数域的,但是w是单变量,一个单变量,怎么能在
       这个的积分上下限,或者说积分路径,是复数域的,但是w是单变量,一个单变量,怎么能在复空间上面积分呢? 做变换后,由一个维度变成两个维度。 ......
  • Unity3D Shader事项法线贴图功能详解
    Unity3D它提供了丰富的功能和工具,使开发人员能够轻松创建出色的游戏和应用程序。其中Shader是Unity3D中非常重要的一部分,它可以帮助开发人员实现各种视觉效果,包括法线贴图功能。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技......
  • 从0开始做一个软渲染器——透视投影和投影矫正
    从0开始做一个软渲染器——透视投影和投影矫正已经做了一段时间了,一直都没记录。最近实现了一个透视投影的相机,从这一部分记录。项目地址:https://github.com/DogWealth/PIRenderer需要注意的是:以下代码的运算都将向量考虑成行向量,进行从左往右的乘法运算。相比列向量,对应的相......
  • 基于FPGA的9/7整数小波变换和逆变换verilog实现,包含testbench
    1.算法运行效果图预览 将测试结果导入到matlab显示   2.算法运行软件版本vivado2019.2,matlab2022a 3.算法理论概述      小波变换是一种在信号处理中广泛应用的数学工具,它能够提供信号在不同尺度和位置上的信息。在图像处理、数据压缩、噪声消除等领域,小......
  • AWT仿射变换:java.awt.geom.AffineTransform的使用
    使用AffineTransform的包有哪些?java.awt包:包含用于创建用户界面和绘制图形图像的所有类。java.awt.font包:提供与字体相关的类和接口。java.awt.geom包:提供用于在与二维几何形状相关的对象上定义和执行操作的Java2D类。java.awt.image包:提供创建和修改图像的各种类。ja......
  • Unity3D 光照计算方向与法线贴图详解
    在Unity3D中,光照计算方向与法线贴图是实现高质量光照效果的重要技术之一。本文将详细介绍光照计算方向与法线贴图的原理和实现方法,并给出相应的代码示例。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学......
  • 快速傅立叶变换
    快速傅立叶变换1引入现在有两个多项式$f(x)$,$g(x)$:$$f(x)=5x^2+3x+7\g(x)=7x^2+2x+1$$我们要求出两者相乘的结果,按照多项式相乘的运算法则,把每一项相乘,总复杂度为$O(n^2)$。这是传统算法能到达的最好复杂度。能不能进行优化呢?使用快速傅立叶变换,我们可以实现$O(n\log......
  • 紧束缚方法中基于原胞坐标和原子坐标两种傅里叶变换法
    见https://www.guanjihuan.com/archives/16199和https://zhuanlan.zhihu.com/p/92538964其中提到在计算陈数时,这两种变换方法会有区别,在上面这个知乎中提到:SSH模型中的这两种变换方法:在严谨的经验紧束缚法中,其实是基于原子坐标的傅里叶变换法:布洛赫和:类似地:哈密顿量和哈......
  • 基于FPGA的图像Robert变换实现,包括tb测试文件和MATLAB辅助验证
    1.算法运行效果图预览 fpga的结果导入到matlab显示: 2.算法运行软件版本vivado2019.2 matlab2022a 3.算法理论概述       随着数字图像处理技术的不断发展,边缘检测作为图像处理的基本操作,其在机器视觉、自动驾驶、医学影像分析等领域的应用日益广泛。Rober......