# 学习OpenGL ES之纹理投影效果

1. 基本几何体的渲染
2. 法线贴图
3. 纹理坐标
4. 投影矩阵

### 基本原理

3D物体的顶点经过投影仪的VP和自身的M变换后就会变成投影仪空间的坐标。因为所有经过投影变换的点如果在可视范围内，它的x，y都会落在-1和1之间，所以我们可以将投影仪空间的坐标当做UV来使用，UV的范围是01，-11的范围只要加1再乘以0.5就可以很方便的变换成0~1的范围。这样我们就可以根据顶点在投影仪空间的坐标来获取UV了。

``````// projectors
uniform mat4 projectorMatrix;
uniform sampler2D projectorMap;
uniform bool useProjector;
``````

`useProjector`主要用作开关投影效果。`projectorMatrix`由投影仪的投影矩阵和观察矩阵相乘而来。

``````vec4 positionInProjectorSpace = projectorMatrix * modelMatrix * vec4(fragPosition, 1.0);
positionInProjectorSpace /= positionInProjectorSpace.w;
vec2 projectorUV = (positionInProjectorSpace.xy + 1.0) * 0.5;
``````

`positionInProjectorSpace /= positionInProjectorSpace.w;`之所以要除以`w`，是因为如果你使用的是透视投影矩阵，那么有可能w不为1，这时候需要`xyzw`都除以`w`保证`xy`范围的正确性。

``````if (projectorUV.x >= 0.0 && projectorUV.x <=1.0 && projectorUV.y >= 0.0 && projectorUV.y <=1.0) {
projectorColor = texture2D(projectorMap, projectorUV);
gl_FragColor = vec4(finalColor * 0.4 + projectorColor.rgb * 0.6, 1.0);
} else {
gl_FragColor = vec4(finalColor, 1.0);
}
``````

### 生成并刷新投影仪的矩阵

``````@property (assign, nonatomic) GLKMatrix4 projectorMatrix;
...

// update projector matrix
GLKMatrix4 projectorProjectionMatrix = GLKMatrix4MakeOrtho(-2, 2, -2, 2, -100, 100);
GLKMatrix4 projectorCameraMatrix = GLKMatrix4MakeLookAt(0, 4, 0, 0, 0, 0, cos(self.elapsedTime), 0, sin(self.elapsedTime));
self.projectorMatrix = GLKMatrix4Multiply(projectorProjectionMatrix, projectorCameraMatrix);
``````

``````[obj.context setUniformMatrix4fv:@"projectorMatrix" value: self.projectorMatrix];
``````

### 投影纹理

``````UIImage *projectorImage = [UIImage imageNamed:@"squarepants.jpg"];
self.projectorMap = [GLKTextureLoader textureWithCGImage:projectorImage.CGImage options:nil error:nil];
...
[obj.context bindTexture:self.projectorMap to:GL_TEXTURE2 uniformName:@"projectorMap"];
``````

OpenGL ES