顶点shader主要对顶点坐标变换,将顶点坐标从local->world->view->clip 空间变换
local空间:模型物体坐标系
world空间:世界空间坐标系
view空间: 相机空间
clip空间: 裁剪空间
local->world空间简化后其实就是这么一行代码:
vec4 posW = dModelMatrix * vec4(localPos, 1.0);
dModelMatrix就是将顶点local坐标系转换到了世界坐标系下。
dModelMatrix是通过getModelMatrix()方法获取
mat4 getModelMatrix() { #ifdef DYNAMICBATCH return getBoneMatrix(vertex_boneIndices); #elif defined(SKIN) return matrix_model * (getBoneMatrix(vertex_boneIndices.x) * vertex_boneWeights.x + getBoneMatrix(vertex_boneIndices.y) * vertex_boneWeights.y+ getBoneMatrix(vertex_boneIndices.z) * vertex_boneWeights.z + getBoneMatrix(vertex_boneIndices.w) * vertex_boneWeights.w); #elif defined(INSTANCING) return mat4(instance_line1, instance_line2, instance_line3, instance_line4); #else return matrix_model; #endif }
从代码可以看出这里有不同分支代码,通过不一样的方式得到modelMatrix,如果没有蒙皮动画就是简单的通过外部传进来的全局modelMatrix给返回即可
如果有蒙皮动画会将返回modelMatrix * boneMatrix,意思就是顶点local坐标先会进行一次骨骼变化(通过骨骼矩阵),然后再通过modelMatrix转到世界空间,
boneMatrix的计算方式会通过顶点权重以及对应的骨骼的骨骼矩阵进行加和。
world->clip空间简化后:
screenPos = matrix_viewProjection * posW;
其实就是将之前得到的顶点世界坐标通过matrix_viewprojection矩阵变换到裁剪空间,这里虽然写的是screenPos其实这里坐标还不是屏幕坐标,它只是未归一化的clip空间,然后到fragment shader时候会除以w然后裁剪后xyz归一到[-1,1]的NDC空间
vertex shader只需要输出clip空间的坐标即可也就是getPosition()返回给gl_Position出去。
gl_Position = getPosition();
void main(void) { gl_Position = getPosition(); vPositionW = getWorldPosition(); vNormalW = dNormalW = getNormal(); vec2 uv0 = getUv0(); vUv0 = uv0; vVertexColor = vertex_color; }
后面几行代码getWorldPosition(),getNormal(),getUv0(),计算输出顶点的世界坐标以及世界空间法线方向和uv坐标给fragment shader用来光照着色使用!
#version 300 es
#define attribute in #define varying out #define texture2D texture #define GL2 #define VERTEXSHADER varying vec4 vVertexColor; varying vec3 vPositionW; varying vec3 vNormalW; varying vec2 vUv0; attribute vec3 vertex_position; attribute vec3 vertex_normal; attribute vec4 vertex_tangent; attribute vec2 vertex_texCoord0; attribute vec2 vertex_texCoord1; attribute vec4 vertex_color; uniform mat4 matrix_viewProjection; uniform mat4 matrix_model; uniform mat3 matrix_normal; vec3 dPositionW; mat4 dModelMatrix; mat3 dNormalMatrix; vec3 dLightPosW; vec3 dLightDirNormW; vec3 dNormalW; #ifdef NINESLICED vec2 getUv0() { vec2 uv = vertex_position.xz; // offset inner vertices inside // (original vertices must be in [-1;1] range) vec2 positiveUnitOffset = clamp(vertex_position.xz, vec2(0.0), vec2(1.0)); vec2 negativeUnitOffset = clamp(-vertex_position.xz, vec2(0.0), vec2(1.0)); uv += (-positiveUnitOffset * innerOffset.xy + negativeUnitOffset * innerOffset.zw) * vertex_texCoord0.xy; uv = uv * -0.5 + 0.5; uv = uv * atlasRect.zw + atlasRect.xy; vMask = vertex_texCoord0.xy; return uv; } #else vec2 getUv0() { return vertex_texCoord0; } #endif attribute vec4 vertex_boneWeights; attribute vec4 vertex_boneIndices; uniform sampler2D texture_poseMap; uniform vec2 texture_poseMapSize; mat4 getBoneMatrix(const in float i) { float j = i * 4.0; float x = mod(j, float(texture_poseMapSize.x)); float y = floor(j / float(texture_poseMapSize.x)); float dx = 1.0 / float(texture_poseMapSize.x); float dy = 1.0 / float(texture_poseMapSize.y); y = dy * (y + 0.5); vec4 v1 = texture2D(texture_poseMap, vec2(dx * (x + 0.5), y)); vec4 v2 = texture2D(texture_poseMap, vec2(dx * (x + 1.5), y)); vec4 v3 = texture2D(texture_poseMap, vec2(dx * (x + 2.5), y)); vec4 v4 = texture2D(texture_poseMap, vec2(dx * (x + 3.5), y)); mat4 bone = mat4(v1, v2, v3, v4); return bone; } #define SKIN #ifdef PIXELSNAP uniform vec4 uScreenSize; #endif mat4 getModelMatrix() { #ifdefDYNAMICBATCH return getBoneMatrix(vertex_boneIndices); #elifdefined(SKIN) return matrix_model * (getBoneMatrix(vertex_boneIndices.x) * vertex_boneWeights.x + getBoneMatrix(vertex_boneIndices.y) * vertex_boneWeights.y+ getBoneMatrix(vertex_boneIndices.z) * vertex_boneWeights.z + getBoneMatrix(vertex_boneIndices.w) * vertex_boneWeights.w); #elifdefined(INSTANCING) return mat4(instance_line1, instance_line2, instance_line3, instance_line4); #else return matrix_model; #endif } vec4 getPosition() { dModelMatrix = getModelMatrix(); vec3 localPos = vertex_position; #ifdefNINESLICED // outer and inner vertices are at the same position, scale both localPos.xz *= outerScale; // offset inner vertices inside // (original vertices must be in [-1;1] range) vec2 positiveUnitOffset = clamp(vertex_position.xz, vec2(0.0), vec2(1.0)); vec2 negativeUnitOffset = clamp(-vertex_position.xz, vec2(0.0), vec2(1.0)); localPos.xz += (-positiveUnitOffset * innerOffset.xy + negativeUnitOffset * innerOffset.zw) * vertex_texCoord0.xy; vTiledUv = (localPos.xz - outerScale + innerOffset.xy) * -0.5 + 1.0; // uv = local pos - inner corner localPos.xz *= -0.5; // move from -1;1 to -0.5;0.5 localPos = localPos.xzy; #endif vec4 posW = dModelMatrix * vec4(localPos, 1.0); #ifdefSCREENSPACE posW.zw = vec2(0.0, 1.0); #endif dPositionW = posW.xyz; vec4 screenPos; #ifdefUV1LAYOUT screenPos = vec4(vertex_texCoord1.xy * 2.0 - 1.0, 0.5, 1); #else #ifdefSCREENSPACE screenPos = posW; #else screenPos = matrix_viewProjection * posW; #endif #ifdefPIXELSNAP // snap vertex to a pixel boundary screenPos.xy = (screenPos.xy * 0.5) + 0.5; screenPos.xy *= uScreenSize.xy; screenPos.xy = floor(screenPos.xy); screenPos.xy *= uScreenSize.zw; screenPos.xy = (screenPos.xy * 2.0) - 1.0; #endif #endif return screenPos; } vec3 getWorldPosition() { return dPositionW; } vec3 getNormal() { #ifdefSKIN dNormalMatrix = mat3(dModelMatrix[0].xyz, dModelMatrix[1].xyz, dModelMatrix[2].xyz); #elifdefined(INSTANCING) dNormalMatrix = mat3(instance_line1.xyz, instance_line2.xyz, instance_line3.xyz); #else dNormalMatrix = matrix_normal; #endif return normalize(dNormalMatrix * vertex_normal); } void main(void) { gl_Position = getPosition(); vPositionW = getWorldPosition(); vNormalW = dNormalW = getNormal(); vec2 uv0 = getUv0(); vUv0 = uv0; vVertexColor = vertex_color; } #version 300 es
#define attribute in #define varying out #define texture2D texture #define GL2 #define VERTEXSHADER varying vec4 vVertexColor; varying vec3 vPositionW; varying vec3 vNormalW; varying vec2 vUv0; attribute vec3 vertex_position; attribute vec3 vertex_normal; attribute vec4 vertex_tangent; attribute vec2 vertex_texCoord0; attribute vec2 vertex_texCoord1; attribute vec4 vertex_color; uniform mat4 matrix_viewProjection; uniform mat4 matrix_model; uniform mat3 matrix_normal; vec3 dPositionW; mat4 dModelMatrix; mat3 dNormalMatrix; vec3 dLightPosW; vec3 dLightDirNormW; vec3 dNormalW; #ifdef NINESLICED vec2 getUv0() { vec2 uv = vertex_position.xz; // offset inner vertices inside // (original vertices must be in [-1;1] range) vec2 positiveUnitOffset = clamp(vertex_position.xz, vec2(0.0), vec2(1.0)); vec2 negativeUnitOffset = clamp(-vertex_position.xz, vec2(0.0), vec2(1.0)); uv += (-positiveUnitOffset * innerOffset.xy + negativeUnitOffset * innerOffset.zw) * vertex_texCoord0.xy; uv = uv * -0.5 + 0.5; uv = uv * atlasRect.zw + atlasRect.xy; vMask = vertex_texCoord0.xy; return uv; } #else vec2 getUv0() { return vertex_texCoord0; } #endif attribute vec4 vertex_boneWeights; attribute vec4 vertex_boneIndices; uniform sampler2D texture_poseMap; uniform vec2 texture_poseMapSize; mat4 getBoneMatrix(const in float i) { float j = i * 4.0; float x = mod(j, float(texture_poseMapSize.x)); float y = floor(j / float(texture_poseMapSize.x)); float dx = 1.0 / float(texture_poseMapSize.x); float dy = 1.0 / float(texture_poseMapSize.y); y = dy * (y + 0.5); vec4 v1 = texture2D(texture_poseMap, vec2(dx * (x + 0.5), y)); vec4 v2 = texture2D(texture_poseMap, vec2(dx * (x + 1.5), y)); vec4 v3 = texture2D(texture_poseMap, vec2(dx * (x + 2.5), y)); vec4 v4 = texture2D(texture_poseMap, vec2(dx * (x + 3.5), y)); mat4 bone = mat4(v1, v2, v3, v4); return bone; } #define SKIN #ifdef PIXELSNAP uniform vec4 uScreenSize; #endif mat4 getModelMatrix() { #ifdefDYNAMICBATCH return getBoneMatrix(vertex_boneIndices); #elifdefined(SKIN) return matrix_model * (getBoneMatrix(vertex_boneIndices.x) * vertex_boneWeights.x + getBoneMatrix(vertex_boneIndices.y) * vertex_boneWeights.y+ getBoneMatrix(vertex_boneIndices.z) * vertex_boneWeights.z + getBoneMatrix(vertex_boneIndices.w) * vertex_boneWeights.w); #elifdefined(INSTANCING) return mat4(instance_line1, instance_line2, instance_line3, instance_line4); #else return matrix_model; #endif } vec4 getPosition() { dModelMatrix = getModelMatrix(); vec3 localPos = vertex_position; #ifdefNINESLICED // outer and inner vertices are at the same position, scale both localPos.xz *= outerScale; // offset inner vertices inside // (original vertices must be in [-1;1] range) vec2 positiveUnitOffset = clamp(vertex_position.xz, vec2(0.0), vec2(1.0)); vec2 negativeUnitOffset = clamp(-vertex_position.xz, vec2(0.0), vec2(1.0)); localPos.xz += (-positiveUnitOffset * innerOffset.xy + negativeUnitOffset * innerOffset.zw) * vertex_texCoord0.xy; vTiledUv = (localPos.xz - outerScale + innerOffset.xy) * -0.5 + 1.0; // uv = local pos - inner corner localPos.xz *= -0.5; // move from -1;1 to -0.5;0.5 localPos = localPos.xzy; #endif vec4 posW = dModelMatrix * vec4(localPos, 1.0); #ifdefSCREENSPACE posW.zw = vec2(0.0, 1.0); #endif dPositionW = posW.xyz; vec4 screenPos; #ifdefUV1LAYOUT screenPos = vec4(vertex_texCoord1.xy * 2.0 - 1.0, 0.5, 1); #else #ifdefSCREENSPACE screenPos = posW; #else screenPos = matrix_viewProjection * posW; #endif #ifdefPIXELSNAP // snap vertex to a pixel boundary screenPos.xy = (screenPos.xy * 0.5) + 0.5; screenPos.xy *= uScreenSize.xy; screenPos.xy = floor(screenPos.xy); screenPos.xy *= uScreenSize.zw; screenPos.xy = (screenPos.xy * 2.0) - 1.0; #endif #endif return screenPos; } vec3 getWorldPosition() { return dPositionW; } vec3 getNormal() { #ifdefSKIN dNormalMatrix = mat3(dModelMatrix[0].xyz, dModelMatrix[1].xyz, dModelMatrix[2].xyz); #elifdefined(INSTANCING) dNormalMatrix = mat3(instance_line1.xyz, instance_line2.xyz, instance_line3.xyz); #else dNormalMatrix = matrix_normal; #endif return normalize(dNormalMatrix * vertex_normal); } void main(void) { gl_Position = getPosition(); vPositionW = getWorldPosition(); vNormalW = dNormalW = getNormal(); vec2 uv0 = getUv0(); vUv0 = uv0; vVertexColor = vertex_color; }