Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <canvas id="test"></canvas>
<script type="shader-source" id="vertex">
  precision mediump float; // 中等精度
  attribute vec3 a_Pos; // 点坐标
  attribute vec3 a_Normal; // 法向量
  attribute vec4 a_Color; // 点对应的颜色
  varying vec4 v_Color; // 传递至片元着色器的颜色值
  varying vec3 v_Normal; // 法向量插值
  varying vec3 v_Pos; // 坐标插值
  uniform mat4 u_Matrix;
  uniform mat4 u_ModelMatrix; // 模型矩阵
  void main() {
    gl_Position = u_Matrix * vec4(a_Pos, 1); // 点坐标
    v_Color = a_Color;
    v_Normal = mat3(u_ModelMatrix) * a_Normal; // 法向量跟随变换
    v_Pos = mat3(u_ModelMatrix) * a_Pos;
  }
</script>
<script type="shader-source" id="fragment">
  precision mediump float; // 中等精度
  varying vec4 v_Color; // 接收顶点着色器传过来的颜色值
  varying vec3 v_Normal;
  varying vec3 v_Pos; // 坐标插值
  uniform vec3 u_LightColor; // 光源颜色
  uniform vec3 u_LightPos; // 平行光方向(入射方向)
  uniform float u_AmbientFactor; // 环境光因子
  uniform vec3 u_Eye; // 眼睛位置
  uniform float u_Shininess; // 反光度(一般为2的n次幂);目前webgl还不支持int类型的属性?
  void main() {
    vec3 lightDirection = normalize(u_LightPos - v_Pos); // 光线方向(指向光源位置)
    float diffuseFactor = dot(normalize(lightDirection), normalize(v_Normal)); // 由光线方向和法向量计算漫反射因子(即漫反射强度)
    diffuseFactor = max(diffuseFactor, 0.0);
    // vec3 reflectDirection = reflect(normalize(-lightDirection), normalize(v_Normal)); // 光线反射方向
    // reflectDirection = normalize(reflectDirection);
    vec3 viewDirection = normalize(u_Eye - v_Pos); // 人眼观察方向(指向眼睛)
    vec3 halfVector = normalize(lightDirection + viewDirection); // 半程向量(入射光方向与观察方向中间方向)
    float specularFactor = 0.0;
    if (diffuseFactor > 0.0) { // 判断是否有反射光
      specularFactor = dot(halfVector, normalize(v_Normal)); // 计算镜面反射因子
      specularFactor = max(specularFactor, 0.0);
      specularFactor = pow(specularFactor, u_Shininess); // 加入反光度
    }
    vec3 diffuseColor = u_LightColor * diffuseFactor; // 漫反射光
    vec3 ambientColor = vec3(1.0, 1.0, 1.0) * u_AmbientFactor; // 环境光
    vec3 specularColor = u_LightColor * specularFactor; // 镜面高光
    gl_FragColor = vec4(diffuseColor + ambientColor + specularColor, 1.0) * v_Color; // 片元颜色
  }
</script>
              
            
!

CSS

              
                html,
body {
  margin: 0;
  padding: 0
}
canvas {
  display: block;
}
              
            
!

JS

              
                const test = document.getElementById('test')
test.width = window.innerWidth
test.height = window.innerHeight
const aspect = test.width / test.height // 屏幕宽高比
const gl = test.getContext('webgl') || test.getContext("experimental-webgl") // 创建webgl
const vertexSource = document.getElementById('vertex').innerHTML // 获取着色器源码
const fragSource = document.getElementById('fragment').innerHTML
let projection = mat4.create()
mat4.ortho(projection, -8 * aspect, 8 * aspect, -8, 8, 30, -30)
let objects = []
const objectNum = 50
let guiInfo = {
  light: [255, 255, 255],
  factor: 0.2,
  shininess: 32,
  lightX: 0,
  lightY: 0,
  lightZ: 5,
  eyeX: 0,
  eyeY: 0,
  eyeZ: 10
}
let gui = new dat.GUI()
gui
  .addColor(guiInfo, 'light')
  .name('光源颜色')
  .onFinishChange(() => {
    let color = toColor(guiInfo.light) // 转化颜色值
    box.updateUniform('u_LightColor', color)
  })
gui
  .add(guiInfo, 'lightX', -100, 100, 1)
  .name('点光源坐标X')
  .onFinishChange(() => {
    updatePos()
  })
gui
  .add(guiInfo, 'lightY', -100, 100, 1)
  .name('点光源坐标Y')
  .onFinishChange(() => {
    updateEye()
  })
gui
  .add(guiInfo, 'lightZ', -100, 100, 1)
  .name('点光源坐标Z')
  .onFinishChange(() => {
    updateEye()
  })
gui
  .add(guiInfo, 'eyeX', -100, 100, 1)
  .name('眼睛坐标X')
  .onFinishChange(() => {
    updateEye()
  })
gui
  .add(guiInfo, 'eyeY', -100, 100, 1)
  .name('眼睛坐标Y')
  .onFinishChange(() => {
    updatePos()
  })
gui
  .add(guiInfo, 'eyeZ', -100, 100, 1)
  .name('眼睛坐标Z')
  .onFinishChange(() => {
    updatePos()
  })
gui
  .add(guiInfo, 'shininess', 1, 256, 1)
  .name('反光度')
  .onFinishChange(() => {
    box.updateUniform('u_Shininess', guiInfo.shininess)
  })
gui
  .add(guiInfo, 'factor', 0, 1, 0.01)
  .name('环境光因子')
  .onFinishChange(() => {
    box.updateUniform('u_AmbientFactor', guiInfo.factor)
  })

let box = new Cube(gl, {
  projection: projection,
  vertexSource: vertexSource,
  fragSource: fragSource,
  origin: [0, 0, 0],
  length: 4,
  uniform: {
    'u_Matrix': {
      type: 'm4fv'
    },
    'u_ModelMatrix': {
      type: 'm4fv'
    },
    'u_LightColor': {
      type: '3fv',
      value: toColor(guiInfo.light)
    },
    'u_AmbientFactor': {
      type: '1f',
      value: guiInfo.factor
    },
    'u_Shininess': {
      type: '1f',
      value: guiInfo.shininess
    },
    'u_LightPos': {
      type: '3fv',
      value: new Float32Array([
        guiInfo.lightX,
        guiInfo.lightY,
        guiInfo.lightZ
      ])
    },
    'u_Eye': {
      type: '3fv',
      value: new Float32Array([
        guiInfo.eyeX,
        guiInfo.eyeY,
        guiInfo.eyeZ
      ])
    }
  }
})

gl.enable(gl.CULL_FACE) // 隐藏背面
gl.clearColor(0.0, 0.0, 0.0, 1.0) // 设置画布清除颜色

function loop () {
  gl.clear(gl.COLOR_BUFFER_BIT) // 清除画布
  box.rotate(1, 1, 1)
  box.updateMatrix()
  box.updateModel()
  box.draw()
  requestAnimationFrame(loop)
}

// 转化为0-1之间的颜色值
function toColor (arr) {
  return new Float32Array([
    arr[0] / 255,
    arr[1] / 255,
    arr[2] / 255
  ])
}

// 更新光源位置
function updatePos () {
  let direction = new Float32Array([
    guiInfo.lightX,
    guiInfo.lightY,
    guiInfo.lightZ
  ])
  box.updateUniform('u_LightPos', direction)
}

// 更新眼睛位置
function updateEye () {
  let eye = new Float32Array([
    guiInfo.eyeX,
    guiInfo.eyeY,
    guiInfo.eyeZ
  ])
  box.updateUniform('u_Eye', eye)
}

loop()
              
            
!
999px

Console