完成部分:
- 环境和框架搭建
- bllin-phong光照模型
优化部分:
- 从文件加载shader
遇到的问题:
- 模型偶尔加载不出来
- shader参数设置不正确
环境和框架搭建
根据文档搭建好环境后,运行后会执行默认材质,效果如下:
由于默认材质直接使用贴图颜色,没有执行任何光照计算,所以模型不会随光源位置发生任何改变。在此过程中会遇到模型偶尔加载不出来的问题,参见bug部分。
Bllin-Phong光照模型
1.添加shader
该部分可以直接以字符串形式加入到InternalShader.js中,也可以从文件中加载,参加优化部分
2.修改index.html,在material.js后面添加phongmaterial.js
<script src="src/materials/PhongMaterial.js" defer></script>
3.将loadOBJ.js中的材质定义部分(第40~56行)换成phongmaterial
let myMaterial = new PhongMaterial(mat.color.toArray(), colorMap, mat.specular.toArray(), renderer.lights[0].entity.mat.intensity);
4.增加PhongMaterial
class PhongMaterial extends Material {
/**
* Creates an instance of PhongMaterial.
* @param {vec3f} color The material color
* @param {Texture} colorMap The texture object of the material
* @param {vec3f} specular The material specular coefficient
* @param {float} intensity The light intensity
* @memberof PhongMaterial
*/
constructor(color, colorMap, specular, intensity) {
let textureSample = 0;
if (colorMap != null) {
textureSample = 1;
super({
'uTextureSample': { type:'1i', value:textureSample },
'uSampler': { type: 'texture', value: colorMap },
'uKd': { type:'3fv', value:color },
'uKs': { type:'3fv', value:specular },
'uLightIntensity': { type: '1f', value: intensity }
}, [], PhongVertexShader, PhongFragmentShader);
} else {
// console.log(color);
super({
'uTextureSample': { type:'1i', value:textureSample },
'uKd': { type:'3fv', value:color },
'uKs': { type:'3fv', value:specular },
'uLightIntensity': { type:'1f', value:intensity }
}, [], PhongVertexShader, PhongFragmentShader);
}
}
}
最终可以达到的效果如下:
从文件加载Shader
因为Shader需要在渲染之前完成加载和绑定,并且PhongShader本身并不大,故而使用同步实现。首先,在loadShader.js中增加以下函数用于同步读取Shader文件:
function loadShaderFromFile(filePath) {
var xhr = new XMLHttpRequest();
xhr.open('GET', filePath, false); // 使用同步请求
xhr.send(null);
if (xhr.status === 200) {
return xhr.responseText;
} else {
console.error('无法加载着色器文件:', filePath);
return null;
}
}
其次,在PhongMaterial的构造函数中增加以下四行代码用于从文件中读取Shader:
const phongVertexPath = 'src/shaders/phongShader/vertex.glsl';
const phongFragmentPath = 'src/shaders/phongShader/fragment.glsl';
var PhongVertexShader = loadShaderFromFile(phongVertexPath);
var PhongFragmentShader = loadShaderFromFile(phongFragmentPath);
如果不出问题,效果与采用静态字符串形式的无二。
一些bug
1.模型加载不出来
有两个可能的原因,可以通过刷新几次进行甄别。
如果偶尔能显示,应该是材质加载的问题,在loadOBJ.js中,有这样一个语句materials.preload();这个语句会进行资源的异步加载,但随便将该materials进行了传参,此时materials可能还没加载完成,导致在渲染模型的时候无法正确应用材质。解决方法是在Index.html中加入以下代码声明材质的预加载:
<link rel="preload" href="/assets/mary/MC003_Kozakura_Mari.png" as="image" type="image/png" crossorigin/>
还有可能是shader不对,Material.js中可以发现如下语句:
this.#flatten_uniforms = ['uModelViewMatrix', 'uProjectionMatrix', 'uCameraPos', 'uLightPos'];
在给shader传参时,使用的是modelview矩阵,也就是把模型矩阵和视图矩阵的乘积传入,shader里也应该是如此。
2.shader参数设置不正确
在完成所有工作后,发现渲染出来的模型是灰色,这个问题很脑残,原因是在复制pdf中的PhongMaterial.js多一些空格,,,导致参数映射不正确。