基于Phong光照的方向光材质反射参数配置问题
为场景添加材质反射参数的解决方案
我写了一个给场景应用方向光的简单演示程序,当前效果如下:
现在遇到的问题是无法设置物体的材质反射参数(环境光ambient、漫反射diffuse、镜面反射specular、高光指数shininess、自发光emission)。以下是修改后的完整实现:
修改后的顶点着色器
attribute vec4 a_position; attribute vec3 a_normal; uniform mat4 u_worldViewProjectionMatrix; uniform mat4 u_worldInverseTransposeMatrix; uniform mat4 u_worldMatrix; // 新增:计算世界空间顶点位置 varying vec3 v_normal; varying vec3 v_worldPosition; // 新增:传递世界空间位置到片元着色器 void main() { gl_Position = u_worldViewProjectionMatrix * a_position; v_normal = mat3(u_worldInverseTransposeMatrix) * a_normal; v_worldPosition = (u_worldMatrix * a_position).xyz; // 计算并传递世界空间位置 }
修改后的片元着色器
precision mediump float; varying vec3 v_normal; varying vec3 v_worldPosition; // 光源参数 uniform vec3 u_reverseLightDirection; uniform vec3 u_lightColor; // 新增:光源颜色 // 材质参数(核心新增部分) uniform vec3 u_materialAmbient; uniform vec3 u_materialDiffuse; uniform vec3 u_materialSpecular; uniform float u_materialShininess; uniform vec3 u_materialEmission; // 相机位置 uniform vec3 u_cameraPosition; void main() { vec3 normal = normalize(v_normal); vec3 lightDir = normalize(u_reverseLightDirection); // 环境光分量 vec3 ambient = u_materialAmbient * u_lightColor; // 漫反射分量 float diffuseFactor = max(dot(normal, lightDir), 0.0); vec3 diffuse = u_materialDiffuse * u_lightColor * diffuseFactor; // 镜面反射分量 vec3 viewDir = normalize(u_cameraPosition - v_worldPosition); vec3 reflectDir = reflect(-lightDir, normal); float specularFactor = pow(max(dot(viewDir, reflectDir), 0.0), u_materialShininess); vec3 specular = u_materialSpecular * u_lightColor * specularFactor; // 自发光分量 vec3 emission = u_materialEmission; // 最终颜色合成 gl_FragColor = vec4(ambient + diffuse + specular + emission, 1.0); }
更新后的场景渲染函数
function draw() { gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.enable(gl.CULL_FACE); gl.cullFace(gl.BACK); gl.enable(gl.DEPTH_TEST); gl.useProgram(shaderProgram); addCubeToScene(); } function addCubeToScene() { // 位置属性设置(原有逻辑不变) gl.enableVertexAttribArray(positionAttr.loc); gl.bindBuffer(gl.ARRAY_BUFFER, shaderProgram.positionBuffer); setCubeGeometry(gl); gl.vertexAttribPointer( positionAttr.loc, positionAttr.size - 1, gl.FLOAT, false, 0, 0 ); // 法线属性设置(原有逻辑不变) gl.enableVertexAttribArray(normalAttr.loc); gl.bindBuffer(gl.ARRAY_BUFFER, shaderProgram.normalBuffer); setNormals(gl); gl.vertexAttribPointer( normalAttr.loc, normalAttr.size, gl.FLOAT, false, 0, 0 ); // 矩阵计算(原有逻辑不变) const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; const zNear = 1; const zFar = 2000; const projectionMatrix = m4.perspective(fieldOfViewRadians, aspect, zNear, zFar); const camera = [0, 0, 300]; const target = [0, 0, 0]; const up = [0, 1, 0]; const cameraMatrix = m4.lookAt(camera, target, up); const viewMatrix = m4.inverse(cameraMatrix); const viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix); let worldMatrix = m4.xRotation(rotation[0]); worldMatrix = m4.yRotate(worldMatrix, rotation[1]); worldMatrix = m4.zRotate(worldMatrix, rotation[2]); worldMatrix = m4.translate(worldMatrix, translation[0], translation[1], translation[2]); worldMatrix = m4.scale(worldMatrix, scale[0], scale[1], scale[2]); const worldViewProjectionMatrix = m4.multiply(viewProjectionMatrix, worldMatrix); const worldInverseMatrix = m4.inverse(worldMatrix); const worldInverseTransposeMatrix = m4.transpose(worldInverseMatrix); // 设置原有矩阵uniform(不变) gl.uniformMatrix4fv(worldViewProjectionMatrixUniform.loc, false, worldViewProjectionMatrix); gl.uniformMatrix4fv(worldInverseTransposeMatrixUniform.loc, false, worldInverseTransposeMatrix); // 新增:设置世界矩阵uniform gl.uniformMatrix4fv(worldMatrixUniform.loc, false, worldMatrix); // 新增:设置光源参数 gl.uniform3fv(lightColorUniform.loc, [1.0, 1.0, 1.0]); // 白色光源 gl.uniform3fv(reverseLightDirectionUniform.loc, m4.normalize([0, 0, 1])); // 新增:设置材质参数(可根据需求调整) gl.uniform3fv(materialAmbientUniform.loc, [0.1, 0.1, 0.1]); // 环境光反射强度 gl.uniform3fv(materialDiffuseUniform.loc, [0.3, 0.5, 1.0]); // 漫反射颜色(替代原u_color) gl.uniform3fv(materialSpecularUniform.loc, [1.0, 1.0, 1.0]); // 镜面反射颜色 gl.uniform1f(materialShininessUniform.loc, 32.0); // 高光指数(值越大高光越集中) gl.uniform3fv(materialEmissionUniform.loc, [0.0, 0.0, 0.0]); // 自发光颜色(默认关闭) // 新增:设置相机位置 gl.uniform3fv(cameraPositionUniform.loc, camera); // 绘制几何体(原有逻辑不变) gl.drawArrays(gl.TRIANGLES, 0, 6 * 2 * 3); }
补充说明
在初始化着色器程序时,需要新增获取以下uniform变量的位置:
// 新增的uniform位置定义 const worldMatrixUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_worldMatrix') }; const lightColorUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_lightColor') }; const materialAmbientUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_materialAmbient') }; const materialDiffuseUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_materialDiffuse') }; const materialSpecularUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_materialSpecular') }; const materialShininessUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_materialShininess') }; const materialEmissionUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_materialEmission') }; const cameraPositionUniform = { loc: gl.getUniformLocation(shaderProgram, 'u_cameraPosition') };
内容的提问来源于stack exchange,提问作者Temax
相关产品推荐
相关产品推荐

