完整资源:
前情提要:
从0开始编写minecraft光影包(0)GLSL,坐标系,光影包结构介绍
从零开始编写minecraft光影包(4)泛光性能与品质优化
从零开始编写minecraft光影包(5)简单光照系统,曝光调节,色调映射与饱和度
前言
回到学习就不能摸鱼了🐎?还是来更新罢。。。
这次更新一些比较高级的水面特效的绘制,比如焦散,屏幕空间反射等等。。。
代码迁移
上一篇博客我们将水面绘制的代码写在了 gbuffers_water 着色器中,但是这么做有几个不好的地方:
- 需要重复计算天空颜色
- 在后续绘制天空漫反射的时候,因为天空是在 composite 着色器中绘制的,所以绘制针对天空的漫反射将会变得十分困难
- 在后续的编程中我们将绘制屏幕空间反射,这一步需要将反射的颜色和基色混合,同样因为水面的绘制在 gbuffers_water 着色器,这使得最后颜色的混合变得十分困难
好吧就是我当时写的时候没有考虑清楚,我菜,我爬爬爬 dbq 呜呜呜
话不多🔒开始动工,我们将水面的基础绘制,迁移到 composite 着色器中进行:
首先将 gbuffers_water 着色器改写。我们首先修改 gbuffers_water.vsh,我们不再计算天空颜色,而是只计算法线,并且计算水面凹凸,施加到顶点上:
#version 120
attribute vec2 mc_Entity;
uniform mat4 gbufferProjection;
uniform mat4 gbufferProjectionInverse;
uniform mat4 gbufferModelView;
uniform mat4 gbufferModelViewInverse;
uniform vec3 cameraPosition;
uniform int worldTime;
varying float id;
varying vec3 normal;
varying vec4 texcoord;
varying vec4 lightMapCoord;
varying vec4 color;
/*
* @function getBump : 水面凹凸计算
* @param positionInViewCoord : 眼坐标系中的坐标
* @return : 计算凹凸之后的眼坐标
*/
vec4 getBump(vec4 positionInViewCoord) {
vec4 positionInWorldCoord = gbufferModelViewInverse * positionInViewCoord; // “我的世界坐标”
positionInWorldCoord.xyz += cameraPosition; // 世界坐标(绝对坐标)
// 计算凹凸
positionInWorldCoord.y += sin(float(worldTime*0.3) + positionInWorldCoord.z * 2) * 0.05;
positionInWorldCoord.xyz -= cameraPosition; // 转回 “我的世界坐标”
return gbufferModelView * positionInWorldCoord; // 返回眼坐标
}
void main() {
vec4 positionInViewCoord = gl_ModelViewMatrix * gl_Vertex; // mv变换计算眼坐
if(mc_Entity.x == 10091) { // 如果是水则计算凹凸
gl_Position = gbufferProjection * getBump(positionInViewCoord); // p变换
} else { // 否则直接传递坐标
gl_Position = gbufferProjection * positionInViewCoord; // p变换
}
color = gl_Color; // 基色
id = mc_Entity.x; // 方块id
normal = gl_NormalMatrix * gl_Normal; // 眼坐标系中的法线
lightMapCoord = gl_TextureMatrix[1] * gl_MultiTexCoord1; // 光照纹理坐标
texcoord = gl_TextureMatrix[0] * gl_MultiTexCoord0; // 纹理坐标
}
然后在 gbuffers_water.fsh 中,我们也不计算水面的颜色,取而代之我们直接输出一个颜色即可。值得注意的是我们将眼坐标下的法线方向传递到四号缓冲区。
#version 120
uniform sampler2D texture;
uniform sampler2D lightmap;
uniform vec3 cameraPosition;
uniform int worldTime;
varying float id;
varying vec3 normal; // 法向量在眼坐标系下
varying vec4 texcoord;
varying vec4 color;
varying vec4 lightMapCoord;
/* DRAWBUFFERS: 04 */
void main() {
vec4 light = texture2D(lightmap, lightMapCoord.st); // 光照
if(id!=10091) {
gl_FragData[0] = color * texture2D(texture, texcoord.st) * light; // 不是水面则正常绘制纹理
gl_FragData[1] = vec4(normal*0.5+0.5, 0.5); // 法线
} else { // 是水面则输出 vec3(0.05, 0.2, 0.3)
gl_FragData[0] = vec4(vec3(0.05, 0.2, 0.3), 0.5)