Skip to content

Instantly share code, notes, and snippets.

@JetStarBlues
Last active February 8, 2024 16:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JetStarBlues/44ef51264c7c042829ac6accd3893199 to your computer and use it in GitHub Desktop.
Save JetStarBlues/44ef51264c7c042829ac6accd3893199 to your computer and use it in GitHub Desktop.
Custom attributes (ish) in p5
varying vec3 vVertexColor;
void main ()
{
gl_FragColor = vec4( vVertexColor, 1.0 );
}

Some rough sketches demonstrating ways to place custom values in p5.Geometry buffers (as discussed here).

  • sketch.js
    • uses loadModel (which indirectly creates an instance of p5.Geometry)
  • sketch2.js
    • directly creates a new instance of p5.Geometry
  • sketch4.js
    • like sketch2.js, directly creates a new instance of p5.Geometry. However, instead of overriding existing buffers, creates new buffers

Alternatively, gl commands can be used directly, bypassing the need for a p5.Geometry instance.

let renderer = createCanvas( 400, 400, WEBGL );
let gl = renderer.GL;
  • sketch3.js
    • uses gl commands
v 0.000000E+00 0.000000E+00 40.0000
v 22.5000 22.5000 0.000000E+00
v 22.5000 -22.5000 0.000000E+00
v -22.5000 -22.5000 0.000000E+00
v -22.5000 22.5000 0.000000E+00
v 0.000000E+00 0.000000E+00 -40.0000
f 1 2 3
f 1 3 4
f 1 4 5
f 1 5 2
f 6 5 4
f 6 4 3
f 6 3 2
f 6 2 5
let octahedron;
let shader1;
function preload ()
{
shader1 = loadShader( "vert.glsl", "frag.glsl" );
octahedron = loadModel( 'octahedron.obj' );
// Try setting custom vertex colors
/* METHOD 1 - Using the vertexColors buffer.
Format seems to be flat array,
https://github.com/processing/p5.js/blob/374acfb44588bfd565c54d61264df197d798d121/src/webgl/p5.RendererGL.Immediate.js#L70
https://github.com/processing/p5.js/blob/374acfb44588bfd565c54d61264df197d798d121/src/webgl/p5.RendererGL.js#L151
*/
octahedron.vertexColors = [
1, 0, 0, 1,
0, 1, 0, 1,
0, 1, 0, 1,
0, 1, 0, 1,
0, 1, 0, 1,
1, 0, 0, 1,
];
/* METHOD 2 - Using the vertexNormals buffer.
Format seems to be p5.Vector
*/
octahedron.vertexNormals = [
new p5.Vector( 1, 0, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 1, 0, 0 ),
];
}
function setup ()
{
createCanvas( 400, 400, WEBGL );
}
function draw ()
{
shader( shader1 );
clear();
rotateX( frameCount * 0.01 );
rotateY( frameCount * 0.01 );
model( octahedron );
}
let m1;
let m2;
let shader1;
/* Follow steps taken by loadShader
https://github.com/processing/p5.js/blob/e9110a6a09574acfee3fed445c887e5b0f5467a2/src/webgl/loading.js#L104
And use buffers available for a p5.Geometry as inferred from p5.rendererGL.retainedMode
https://github.com/processing/p5.js/blob/374acfb44588bfd565c54d61264df197d798d121/src/webgl/p5.RendererGL.js#L151
buffer source | attribute name | buffer format
---------------|---------------------|---------------------------------------------------
lineVertices | vec3 aPosition | [ [ x, y, z ], [ x, y, z ] ... ]
lineNormals | vec4 aDirection | [ [ x, y, z, w ], [ x, y, z, w ] ... ]
vertices | vec3 aPostion | [ p5.Vector( x, y, z ), p5.Vector( x, y, z )... ]
vertexNormals | vec3 aNormal | [ p5.Vector( x, y, z ), p5.Vector( x, y, z )... ]
vertexColors | vec4 aMaterialColor | [ r, g, b, a, r, g, b, a ... ]
uvs | vec2 aTexCoord | [ [ x, y ], [ x, y ] ... ]
new p5.RenderBuffer( 3, 'lineVertices', 'lineVertexBuffer', 'aPosition', this, this._flatten )
new p5.RenderBuffer( 4, 'lineNormals', 'lineNormalBuffer', 'aDirection', this, this._flatten )
new p5.RenderBuffer( 3, 'vertices', 'vertexBuffer', 'aPosition', this, this._vToNArray )
new p5.RenderBuffer( 3, 'vertexNormals', 'normalBuffer', 'aNormal', this, this._vToNArray )
new p5.RenderBuffer( 4, 'vertexColors', 'colorBuffer', 'aMaterialColor', this )
new p5.RenderBuffer( 2, 'uvs', 'uvBuffer', 'aTexCoord', this, this._flatten )
The buffer format can be simplified if the p5.rendererGL constructor is modified
to expect flat arrays, instead of doing the flattening in-situ on a per-case basis.
*/
function preload ()
{
shader1 = loadShader( "vert.glsl", "frag.glsl" );
}
function setup ()
{
createCanvas( 400, 400, WEBGL );
/*
If p5.Geometry.faces.length != 0, then gl.drawElements is used.
Otherwise, gl.drawArrays is used.
p5.model
-> p5.RendererGL.createBuffers
-> p5.RendererGL.prototype.drawBuffers
-> p5.RendererGL.prototype._drawElements
*/
// gl.drawElements
m1 = new p5.Geometry();
m1.gid = "placeholderName1";
m1.vertices = [
new p5.Vector( 0, 0, 40 ),
new p5.Vector( 22.5, 22.5, 0 ),
new p5.Vector( 22.5, - 22.5, 0 ),
new p5.Vector( - 22.5, - 22.5, 0 ),
new p5.Vector( - 22.5, 22.5, 0 ),
new p5.Vector( 0, 0, - 40 ),
];
m1.faces = [ // if defined, gl.drawElements is used, otherwise gl.drawArrays
[ 0, 1, 2 ],
[ 0, 2, 3 ],
[ 0, 3, 4 ],
[ 0, 4, 1 ],
[ 5, 4, 3 ],
[ 5, 3, 2 ],
[ 5, 2, 1 ],
[ 5, 1, 4 ]
];
m1.vertexNormals = [ // shove vertex colors here...
new p5.Vector( 1, 0, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 0, 1, 0 ),
new p5.Vector( 1, 0, 0 ),
];
// gl.drawArrays
m2 = new p5.Geometry();
m2.gid = "placeholderName2";
for ( let face of m1.faces )
{
for ( let i = 0; i < 3; i += 1 )
{
m2.vertices.push( m1.vertices[ face[ i ] ].copy() );
m2.vertexNormals.push( m1.vertexNormals[ face[ i ] ].copy() );
}
}
}
function draw ()
{
shader( shader1 );
clear();
rotateX( frameCount * 0.01 );
rotateY( frameCount * 0.01 );
// Edit attributes on the "fly"...
m1.vertexNormals[ 0 ] = new p5.Vector( 0, 0, 1 );
m1.vertexNormals[ 5 ] = new p5.Vector( 0, 0, 1 );
m1.vertices[ 0 ] = new p5.Vector( 0, 0, 80 );
model( m1 );
translate( 100, 0, 0 );
model( m2 );
}
/* gl code based on,
https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL
*/
let shaderProgram1;
let m3;
let indexBuffer;
let vertexBuffer;
let vertexColorBuffer;
let renderer;
let gl;
function preload ()
{
shaderProgram1 = loadShader( "vert2.glsl", "frag.glsl" );
}
function setup ()
{
renderer = createCanvas( 400, 400, WEBGL );
gl = renderer.GL;
//
m3 = {};
m3.vertices = [
0, 0, 40,
22.5, 22.5, 0,
22.5, - 22.5, 0,
- 22.5, - 22.5, 0,
- 22.5, 22.5, 0,
0, 0, - 40,
];
m3.faces = [
0, 1, 2,
0, 2, 3,
0, 3, 4,
0, 4, 1,
5, 4, 3,
5, 3, 2,
5, 2, 1,
5, 1, 4,
];
m3.vertexColors = [
1, 0, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
1, 0, 0,
];
indexBuffer = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( m3.faces ), gl.STATIC_DRAW );
vertexBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( m3.vertices ), gl.STATIC_DRAW );
vertexColorBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vertexColorBuffer );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( m3.vertexColors ), gl.STATIC_DRAW );
}
function draw ()
{
shader( shaderProgram1 );
clear();
rotateX( frameCount * 0.01 );
rotateY( frameCount * 0.01 );
//
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, indexBuffer );
{
const nComponents = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
gl.vertexAttribPointer(
gl.getAttribLocation( shaderProgram1._glProgram, 'aVertexPosition' ),
nComponents, type, normalize, stride, offset
);
gl.enableVertexAttribArray(
gl.getAttribLocation( shaderProgram1._glProgram, 'aVertexPosition' )
)
}
{
const nComponents = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer( gl.ARRAY_BUFFER, vertexColorBuffer );
gl.vertexAttribPointer(
gl.getAttribLocation( shaderProgram1._glProgram, 'aVertexColor' ),
nComponents, type, normalize, stride, offset
);
gl.enableVertexAttribArray(
gl.getAttribLocation( shaderProgram1._glProgram, 'aVertexColor' )
)
}
//
shaderProgram1.bindShader();
{
const vertexCount = m3.faces.length;
const type = gl.UNSIGNED_SHORT;
const offset = 0;
gl.drawElements( gl.TRIANGLES, vertexCount, type, offset );
}
shaderProgram1.unbindShader();
// Confirm that default shaders still work
resetShader();
fill( 255, 0, 0 );
translate( 100, 0, 0 );
box( 40 );
}
let m1;
let shader1;
let renderer;
function preload ()
{
shader1 = loadShader( "vert3.glsl", "frag.glsl" );
}
function setup ()
{
renderer = createCanvas( 400, 400, WEBGL );
m1 = new p5.Geometry();
m1.gid = "uniqueName1";
m1.vertices = [
new p5.Vector( 0, 0, 40 ),
new p5.Vector( 22.5, 22.5, 0 ),
new p5.Vector( 22.5, - 22.5, 0 ),
new p5.Vector( - 22.5, - 22.5, 0 ),
new p5.Vector( - 22.5, 22.5, 0 ),
new p5.Vector( 0, 0, - 40 ),
];
m1.faces = [
[ 0, 1, 2 ],
[ 0, 2, 3 ],
[ 0, 3, 4 ],
[ 0, 4, 1 ],
[ 5, 4, 3 ],
[ 5, 3, 2 ],
[ 5, 2, 1 ],
[ 5, 1, 4 ]
];
// Custom attributes
m1.custom_vertexColors = [
1, 0, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
1, 0, 0,
];
// https://github.com/processing/p5.js/blob/374acfb44588bfd565c54d61264df197d798d121/src/webgl/p5.RendererGL.js#L151
renderer.retainedMode.buffers.fill.push(
new p5.RenderBuffer(
3, // number of components per vertex
'custom_vertexColors', // src
'custom_vertexColorsBuffer', // dst
'aCustomVertexColor', // attribute name
renderer // renderer
)
);
}
function draw ()
{
shader( shader1 );
clear();
rotateX( frameCount * 0.01 );
rotateY( frameCount * 0.01 );
model( m1 );
}
attribute vec3 aPosition;
attribute vec4 aVertexColor;
attribute vec4 aMaterialColor;
attribute vec3 aNormal;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
uniform mat3 uNormalMatrix;
varying vec3 vVertexColor;
void main ()
{
// vVertexColor = vec3( 1.0, 0.0, 0.0 ); // red
// METHOD 1
/* Pass colors by using the vertexColors buffer
Cryptically 😕, values from this buffer are assigned
the name `aMaterialColor` instead of `aVertexColor`
https://github.com/processing/p5.js/blob/374acfb44588bfd565c54d61264df197d798d121/src/webgl/p5.RendererGL.js#L154
*/
// vVertexColor = aVertexColor.rgb;
vVertexColor = aMaterialColor.rgb;
// METHOD 2
/* Pass colors by overwriting normal buffer
*/
vVertexColor = aNormal;
vec4 positionVec4 = vec4( aPosition, 1.0 );
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
}
attribute vec3 aVertexPosition;
attribute vec3 aVertexColor;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
uniform mat3 uNormalMatrix;
varying vec3 vVertexColor;
void main ()
{
vVertexColor = aVertexColor;
vec4 positionVec4 = vec4( aVertexPosition, 1.0 );
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
}
attribute vec3 aPosition;
attribute vec3 aCustomVertexColor;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
uniform mat3 uNormalMatrix;
varying vec3 vVertexColor;
void main ()
{
vVertexColor = aCustomVertexColor;
vec4 positionVec4 = vec4( aPosition, 1.0 );
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment