当前位置: 首页 > news >正文

天猫网站建设目的网站没有备案会怎么样

天猫网站建设目的,网站没有备案会怎么样,最好的韩国服务器,整站优化费用目录 一 引入 二 TBN矩阵 三 代码实现 3.1手工计算切线和副切线 3.2 像素着色器 3.3 切线空间的两种使用方法 3.4 渲染效果 四 复杂的物体 本章节源码点击此处 继上篇法线贴图 来熟悉切线空间是再好不过的。对于法线贴图来说,我们知道它就是一个2D的颜色纹理,根据rgb… 目录 一 引入 二 TBN矩阵 三 代码实现 3.1手工计算切线和副切线 3.2 像素着色器 3.3 切线空间的两种使用方法 3.4 渲染效果 四 复杂的物体 本章节源码点击此处 继上篇法线贴图  来熟悉切线空间是再好不过的。对于法线贴图来说,我们知道它就是一个2D的颜色纹理,根据rgb来映射法线对应的xyz,从而达到在同一个平面上有多个不同方向法线的效果这样就能根据光照的计算结果不同从而得到凹凸不平(或者说更加细节)的平面。 一 引入 我们可以尝试看下面这张图由于我们的法线贴图中的rgb是固定的,也就是比如原来大多数是指向正z轴方向的法线对于一个面向正z轴的平面来说是没有问题的但是如果我们现在要在一个面向正y轴方向的屏幕也采用这个纹理贴图呢还能够使用这个原有的法线贴图吗?光照看起来完全不对发生这种情况是平面的表面法线现在指向了y而采样得到的法线仍然指向的是z。结果就是光照仍然认为表面法线和之前朝向正z方向时一样这样光照就不对了。 有一种方案是要想正确的实现光照效果(也就是正确的法线),那么无非就是为每个单独的平面制作一个单独的法线贴图。如果是一个立方体的话我们就需要6个法线贴图但是如果模型上有无数的朝向不同方向的表面这就会变得极其复杂并且繁琐,无论是纹理制作者和使用者可能都容易出错。另一种方案就是我们在计算光照时不在原有的世界坐标来计算而是对于这个单独的平面的空间来计算也就是我们想办法让坐标都变换到这个表平面的空间中。这个坐标空间你也可以理解为纹理空间,我们把纹理空间对应的UV(也就是xy)映射到这个坐标空间里然后在这个空间中取出每个像素点的颜色值这样法线贴图向量总是指向这个坐标空间的正z方向所有的光照向量都相对与这个正z方向进行变换。我们就能始终使用同样的法线贴图不管朝向问题。这个坐标空间叫做切线空间。 二 TBN矩阵 法线贴图中的法线向量并不都指向切线空间的正Z方向。实际上法线贴图中的每个像素代表的是该点在切线空间中的一个法线向量这个向量可以指向任意方向用来表示模型表面在那个点上的微小凸起或凹陷方向。我们需要使用一个特定的矩阵将世界坐标切换到切线空间坐标中同时也可以使用这个矩阵的逆矩阵将切线空间坐标切换回世界坐标中。这种矩阵叫做TBN矩阵这三个字母分别代表tangent、bitangent和normal向量。TBN矩阵主要用于将不同的向量如光照方向、视线方向等从一个空间通常是世界空间或模型空间转换到切线空间。或者相互转换。这样做的目的是使光照计算能够在与法线贴图中存储的法线相匹配的坐标系中进行因为法线贴图中的法线是在切线空间中定义的。我们需要三个相互垂直的向量它们沿一个表面的法线贴图对齐于上、右、前 简单来说:TBN矩阵可以实现切线空间与模型空间/世界坐标相互转换。这取决于你生成TBN矩阵时所用的坐标系。T切向量 TangentB副切向量 BitangentN法向量 Normal P1,P2,P3纹理中的UV坐标(也就是纹理坐标),而E1和E2就是两个顶点之间的位置坐标注意图中边E2与纹理坐标的差ΔU2、Δ2构成一个三角形。Δ2与切线向量T方向相同而ΔV2与副切线向量B方向相同。这也就是说所以我们可以将三角形的边E1与E2写成切线向量T和副切线向量B的线性组合 具体的推导就需要线性代数的知识了,而实际最终我们的开发并不会自己计算,而是利用接口最终计算的TBN矩阵的推导公式如下。 当我们知道TBN矩阵的任意两个坐标轴时另一个都可以通过叉乘得到。 三 代码实现 我们使用的场景是一个简单的2D平面,但能实现其原理。 3.1手工计算切线和副切线 我们仍然使用之前的法线贴图,但是此时我们把顶点的坐标改变也就是说让这个面面向y轴, 首先生成4个顶点也就是组成两个三角形,以及对应的纹理坐标和法线值至于为什么要传入顶点的法线值是因为对于这个平面来说,由于我们是在顶点着色器中计算使用的TBN矩阵,所以这个法线是相对准确的。 // 首先准备4个顶点, 其实是两个三角形(两个面)QVector3D pos1(-1.0f, 0.0f, -1.0f);QVector3D pos2(-1.0f, 0.0f, 1.0f);QVector3D pos3( 1.0f, 0.0f, 1.0f);QVector3D pos4( 1.0f, 0.0f, -1.0f);// 准备对应的纹理坐标QVector2D uv1(0.0f, 1.0f);QVector2D uv2(0.0f, 0.0f);QVector2D uv3(1.0f, 0.0f);QVector2D uv4(1.0f, 1.0f);// 法线 这个法线是因为我们是在顶点着色器里面使用的TBN矩阵 所以这个法线应该是准确的QVector3D nm(0.0f, 1.0f, 0.0f); 接下来就是按照上面的公式来生成TB向量了 // 先准备两个平面的TB向量,需要分开计算QVector3D tangent1, bitangent1;QVector3D tangent2, bitangent2;// 第一个三角形QVector3D edge1 pos2 - pos1;QVector3D edge2 pos3 - pos1;QVector2D deltaUV1 uv2 - uv1;QVector2D deltaUV2 uv3 - uv1;// 先计算矩阵前面的系数float f 1.0f / (deltaUV1.x() * deltaUV2.y() - deltaUV2.x() * deltaUV1.y());// 生成TB向量tangent1.setX(f * (deltaUV2.y() * edge1.x() - deltaUV1.y() * edge2.x()));tangent1.setY(f * (deltaUV2.y() * edge1.y() - deltaUV1.y() * edge2.y()));tangent1.setZ(f * (deltaUV2.y() * edge1.z() - deltaUV1.y() * edge2.z()));bitangent1.setX(f * (-deltaUV2.x() * edge1.x() deltaUV1.x() * edge2.x()));bitangent1.setY(f * (-deltaUV2.x() * edge1.y() deltaUV1.x() * edge2.y()));bitangent1.setZ(f * (-deltaUV2.x() * edge1.z() deltaUV1.x() * edge2.z()));// 第二个三角形计算方法同上edge1 pos3 - pos1;edge2 pos4 - pos1;deltaUV1 uv3 - uv1;deltaUV2 uv4 - uv1;f 1.0f / (deltaUV1.x() * deltaUV2.y() - deltaUV2.x() * deltaUV1.y());tangent2.setX(f * (deltaUV2.y() * edge1.x() - deltaUV1.y() * edge2.x()));tangent2.setY(f * (deltaUV2.y() * edge1.y() - deltaUV1.y() * edge2.y()));tangent2.setZ(f * (deltaUV2.y() * edge1.z() - deltaUV1.y() * edge2.z()));bitangent2.setX(f * (-deltaUV2.x() * edge1.x() deltaUV1.x() * edge2.x()));bitangent2.setY(f * (-deltaUV2.x() * edge1.y() deltaUV1.x() * edge2.y()));bitangent2.setZ(f * (-deltaUV2.x() * edge1.z() deltaUV1.x() * edge2.z()));// 这些顶点和法线我们都通过VAO传递进去,由于我们用的是一个2D的平面测试程序所以法线是同一个这并不影响。float quadVertices[] {// positions // normal // texcoords // tangent // bitangentpos1.x(), pos1.y(), pos1.z(), nm.x(), nm.y(), nm.z(), uv1.x(), uv1.y(), tangent1.x(), tangent1.y(), tangent1.z(), bitangent1.x(), bitangent1.y(), bitangent1.z(),pos2.x(), pos2.y(), pos2.z(), nm.x(), nm.y(), nm.z(), uv2.x(), uv2.y(), tangent1.x(), tangent1.y(), tangent1.z(), bitangent1.x(), bitangent1.y(), bitangent1.z(),pos3.x(), pos3.y(), pos3.z(), nm.x(), nm.y(), nm.z(), uv3.x(), uv3.y(), tangent1.x(), tangent1.y(), tangent1.z(), bitangent1.x(), bitangent1.y(), bitangent1.z(),pos1.x(), pos1.y(), pos1.z(), nm.x(), nm.y(), nm.z(), uv1.x(), uv1.y(), tangent2.x(), tangent2.y(), tangent2.z(), bitangent2.x(), bitangent2.y(), bitangent2.z(),pos3.x(), pos3.y(), pos3.z(), nm.x(), nm.y(), nm.z(), uv3.x(), uv3.y(), tangent2.x(), tangent2.y(), tangent2.z(), bitangent2.x(), bitangent2.y(), bitangent2.z(),pos4.x(), pos4.y(), pos4.z(), nm.x(), nm.y(), nm.z(), uv4.x(), uv4.y(), tangent2.x(), tangent2.y(), tangent2.z(), bitangent2.x(), bitangent2.y(), bitangent2.z()};// 配置顶点缓冲glGenVertexArrays(1,quadVAO);glGenBuffers(1,quadVBO);glBindVertexArray(quadVAO);glBindBuffer(GL_ARRAY_BUFFER,quadVBO);glBufferData(GL_ARRAY_BUFFER,sizeof(quadVertices),quadVertices, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,14 * sizeof(float),0);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(2);glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(6 * sizeof(float)));glEnableVertexAttribArray(3);glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(8 * sizeof(float)));glEnableVertexAttribArray(4);glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void*)(11 * sizeof(float)));glBindVertexArray(quadVAO);glDrawArrays(GL_TRIANGLES, 0, 6);glBindVertexArray(0); 3.2 像素着色器 顶点着色器 在定点着色器中,我们并没有使用传进来的B向量,因为在顶点着色器中传入的法线向量是准确的我们只需要将这个法线N和主切线T进行点积就能得到一个正交坐标系。但需要注意的是在某些情况下法线N与切线T可能不会垂直,我们需要额外处理一下。(试想一下我们计算切线T的时候如果同一个顶点被多个平面共用那么这里的纹理坐标可能就会被综合多个平面的效果导致T切线计算后代结果稍微有偏差。)格拉姆-施密特正交化过程Gram-Schmidt process的数学技巧我们可以对TBN向量进行重正交化这样每个向量就又会重新垂直了。当然我们也可以直接使用传入的B切线生成这样都是可以的。 #version 330 core layout (location 0) in vec3 aPos; layout (location 1) in vec3 aNormal; layout (location 2) in vec2 aTexCoords; // T 向量 layout (location 3) in vec3 aTangent; // B 向量 layout (location 4) in vec3 aBitangent;out VS_OUT {vec3 FragPos;vec2 TexCoords;vec3 TangentLightPos;vec3 TangentViewPos;vec3 TangentFragPos; } vs_out;uniform mat4 projection; uniform mat4 view; uniform mat4 model;uniform vec3 lightPos; uniform vec3 viewPos;uniform bool blin; void main() {// 顶点坐标传出的还是世界坐标vs_out.FragPos vec3(model * vec4(aPos, 1.0));vs_out.TexCoords aTexCoords;mat3 normalMatrix transpose(inverse(mat3(model)));vec3 T normalize(normalMatrix * aTangent);vec3 N normalize(normalMatrix * aNormal);// 为了防止法向量和T向量不垂直T normalize(T - dot(T, N) * N);// B向量我们采用N和T的点积计算得到Bvec3 B cross(N, T);mat3 TBN transpose(mat3(T, B, N));if(blin true){vs_out.TangentLightPos TBN * lightPos;vs_out.TangentViewPos TBN * viewPos;vs_out.TangentFragPos TBN * vs_out.FragPos;}else{vs_out.TangentLightPos lightPos;vs_out.TangentViewPos viewPos;vs_out.TangentFragPos vs_out.FragPos;}gl_Position projection * view * model * vec4(aPos, 1.0); }片段着色器: 在顶点着色器中我们已经将光源,视线以及顶点坐标转换到切线空间了这时候我们只需要正常计算光照即可 #version 330 core out vec4 FragColor;in VS_OUT {vec3 FragPos;vec2 TexCoords;vec3 TangentLightPos;vec3 TangentViewPos;vec3 TangentFragPos; } fs_in;uniform sampler2D diffuseMap; uniform sampler2D normalMap;uniform vec3 lightPos; uniform vec3 viewPos;void main() {// 从法线贴图中获取法线值vec3 normal texture(normalMap, fs_in.TexCoords).rgb;// 将法线坐标标准化normal normalize(normal * 2.0 - 1.0);// 获取漫反射的颜色值vec3 color texture(diffuseMap, fs_in.TexCoords).rgb;// ambientvec3 ambient 0.1 * color;// diffusevec3 lightDir normalize(fs_in.TangentLightPos - fs_in.TangentFragPos);float diff max(dot(lightDir, normal), 0.0);vec3 diffuse diff * color;// specularvec3 viewDir normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);vec3 reflectDir reflect(-lightDir, normal);vec3 halfwayDir normalize(lightDir viewDir);float spec pow(max(dot(normal, halfwayDir), 0.0), 32.0);vec3 specular vec3(0.2) * spec;FragColor vec4(ambient diffuse specular, 1.0); }3.3 切线空间的两种使用方法 第一种方法也就是我们上面使用的方法: 在顶点着色器中将光源,视线,顶点所有相关向量在顶点着色器中转换到切线空间不用在像素着色器中做这件事不是把TBN矩阵的逆矩阵发送给像素着色器而是将切线空间的光源位置观察位置以及顶点位置发送给像素着色器。这样我们就不用在像素着色器里进行矩阵乘法了。这是一个极佳的优化因为顶点着色器通常比像素着色器运行的少。第二种方法就是我们只需要在顶点着色器中将TBN传递给片段着色器,然后再片段着色器中将法线贴图的纹理使用TBN矩阵转换到世界坐标即可这样看起来更简单但片段着色器运行的次数更多相对来说消耗更大。 3.4 渲染效果 在渲染时我们加上开关也就是可以控制是否使用切线空间来优化错误的法线贴图看看他们不同的效果。因为片段着色器没有什么不同,也就是在顶点着色器中加上一个控制变量这个变量用于控制是否使用切线空间。 if(blin true){vs_out.TangentLightPos TBN * lightPos;vs_out.TangentViewPos TBN * viewPos;vs_out.TangentFragPos TBN * vs_out.FragPos;}else{vs_out.TangentLightPos lightPos;vs_out.TangentViewPos viewPos;vs_out.TangentFragPos vs_out.FragPos;}四 复杂的物体 对于复杂的物体也就是平面(或者说网格很多的物体,像Assimp这种模型加载库是会提供的我们只需要利用其提供的API接口生成TBN矩阵即可在着色器中的使用方法是一样的。
http://www.w-s-a.com/news/353116/

相关文章:

  • 开封网站建设培训郑州高端网站建设哪家好
  • 东莞哪家做网站很有名的公司即墨专业医院网站制作公司
  • 做面食网站china cd wordpress
  • 门户网站 营销优秀建筑模型案例作品
  • 训做网站的心得体会范文中山市 有限公司网站建设
  • 服装电子商务网站建设过程与实现两学一做学习教育网站
  • 住房和城建设网站怎么用源码建站
  • 监理工程师证查询网站百度关键词优化软件网站
  • 关于建筑建设的网站asp网站建设报告书
  • 服务二级公司网站建设平台销售模式有哪些
  • 南昌县建设局网站微信分销小程序开发
  • 网站设计师需要什么知识与技能wordpress个性
  • 做茶叶网站的目的和规划有什么做照片书的网站
  • 开福区城乡建设局门户网站关键词挖掘查询工具爱站网
  • 网站建设全国排名沈阳seo按天计费
  • 成都公司网站设计无锡seo网站推广费用
  • 建网站平台要多少钱购物网站界面设计策划
  • 学完js了可以做哪些网站长沙建站官网
  • 怎么样做问卷网站多少钱英语
  • 房产网站建设方案建筑公司是干什么的
  • wordpress建的大型网站柳州市网站建设
  • 石家庄做网站的公司有哪些微信自媒体网站建设
  • 池州哪里有做网站注册公司有哪些风险
  • 做古代风格头像的网站对网站政务建设的建议
  • 网站搜索栏怎么做设计个网站要多少钱
  • 阿里巴巴网站建设目标wamp wordpress
  • 自己做的网站怎么挂网上金蝶erp
  • 网站的页面由什么组成淘宝网网站建设的需求分析
  • 软文网站推广法dede5.7内核qq个性门户网站源码
  • 个人备案网站名称校园网站建设特色