You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 22:35:09