Skip to content

Commit

Permalink
Support WebGL custom vertex attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
davepagurek committed Dec 5, 2024
1 parent 1eb56fe commit 7fd2eb2
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 36 deletions.
57 changes: 49 additions & 8 deletions preview/global/sketch.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,55 @@
console.log(p5);
const vertSrc = `#version 300 es
precision mediump float;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
in vec3 aPosition;
in vec2 aOffset;
void main(){
vec4 positionVec4 = vec4(aPosition.xyz, 1.0);
positionVec4.xy += aOffset;
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
}
`;

const fragSrc = `#version 300 es
precision mediump float;
out vec4 outColor;
void main(){
outColor = vec4(0.0, 1.0, 1.0, 1.0);
}
`;

let myShader;
function setup(){
createCanvas(200, 200);
createCanvas(100, 100, WEBGL);

// Create and use the custom shader.
myShader = createShader(vertSrc, fragSrc);

describe('A wobbly, cyan circle on a gray background.');
}

async function draw(){
background(0, 50, 50);
circle(100, 100, 50);
function draw(){
// Set the styles
background(125);
noStroke();
shader(myShader);

// Draw the circle.
beginShape();
for (let i = 0; i < 30; i++){
const x = 40 * cos(i/30 * TWO_PI);
const y = 40 * sin(i/30 * TWO_PI);

// Apply some noise to the coordinates.
const xOff = 10 * noise(x + millis()/1000) - 5;
const yOff = 10 * noise(y + millis()/1000) - 5;

fill('white');
textSize(30);
text('hello', 10, 30);
// Apply these noise values to the following vertex.
vertexProperty('aOffset', [xOff, yOff]);
vertex(x, y);
}
endShape(CLOSE);
}
17 changes: 17 additions & 0 deletions src/shape/custom_shapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ class Shape {
kind = null;
contours = [];
_splineEnds = constants.SHOW;
userVertexProperties = null;

constructor(
vertexProperties,
Expand Down Expand Up @@ -626,6 +627,22 @@ class Shape {
this.#vertexProperties = { ...this.#initialVertexProperties };
this.kind = null;
this.contours = [];
this.userVertexProperties = null;
}

vertexProperty(name, data) {
this.userVertexProperties = this.userVertexProperties || {};
const key = this.vertexPropertyKey(name);
if (!this.userVertexProperties[key]) {
this.userVertexProperties[key] = data.length ? data.length : 1;
}
this.#vertexProperties[key] = data;
}
vertexPropertyName(key) {
return key.replace(/Src$/, '');
}
vertexPropertyKey(name) {
return name + 'Src';
}

/*
Expand Down
2 changes: 1 addition & 1 deletion src/shape/vertex.js
Original file line number Diff line number Diff line change
Expand Up @@ -2398,7 +2398,7 @@ function vertex(p5, fn){
* fill(j/rows*255, j/cols*255, 255);
*
* // Calculate the distance from the corner of each cell to the mouse.
* let distance = dist(x1,y1, mouseX, mouseY);
* let distance = dist(x, y, mouseX, mouseY);
*
* // Send the distance to the shader.
* vertexProperty('aDistance', min(distance, 100));
Expand Down
60 changes: 36 additions & 24 deletions src/webgl/ShapeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,57 @@ export class ShapeBuilder {
}

constructFromContours(shape, contours) {
if (this._useUserVertexProperties === true){
if (this._useUserVertexProperties){
this._resetUserVertexProperties();
}
this.geometry.reset();
this.contourIndices = [];
this.shapeMode = constants.TESS;
const shouldProcessEdges = !!this.renderer.states.strokeColor;

const userVertexPropertyHelpers = {};
if (shape.userVertexProperties) {
this._useUserVertexProperties = true;
for (const key in shape.userVertexProperties) {
const name = shape.vertexPropertyName(key);
const prop = this.geometry._userVertexPropertyHelper(name, [], shape.userVertexProperties[key]);
userVertexPropertyHelpers[key] = prop;
this.tessyVertexSize += prop.getDataSize();
this.bufferStrides[prop.getSrcName()] = prop.getDataSize();
this.renderer.buffers.user.push(
new RenderBuffer(prop.getDataSize(), prop.getSrcName(), prop.getDstName(), name, this.renderer)
);
}
} else {
this._useUserVertexProperties = false;
}

let idx = -1;
for (const contour of contours) {
this.contourIndices.push(this.geometry.vertices.length);
let prevIdx = -1;
for (const vertex of contour) {
idx++
this.geometry.vertices.push(vertex.position);
this.geometry.vertexNormals.push(vertex.normal);
this.geometry.vertexNormals.push(vertex.normal || new Vector(0, 0, 0));
this.geometry.uvs.push(vertex.textureCoordinates.x, vertex.textureCoordinates.y);
this.geometry.vertexColors.push(...vertex.fill.array());
this.geometry.vertexStrokeColors.push(...vertex.stroke.array());
if (this.renderer.states.fillColor) {
this.geometry.vertexColors.push(...vertex.fill.array());
} else {
this.geometry.vertexColors.push(0, 0, 0, 0);
}
if (this.renderer.states.strokeColor) {
this.geometry.vertexStrokeColors.push(...vertex.stroke.array());
} else {
this.geometry.vertexColors.push(0, 0, 0, 0);
}
for (const key in userVertexPropertyHelpers) {
const prop = userVertexPropertyHelpers[key];
if (key in vertex) {
prop.setCurrentData(vertex[key]);
}
prop.pushCurrentData();
}
if (shouldProcessEdges && prevIdx >= 0) {
// TODO: handle other shape modes
this.geometry.edges.push([prevIdx, idx]);
Expand Down Expand Up @@ -259,26 +291,6 @@ export class ShapeBuilder {
return this;
}

vertexProperty(propertyName, data) {
if (!this._useUserVertexProperties) {
this._useUserVertexProperties = true;
this.geometry.userVertexProperties = {};
}
const propertyExists = this.geometry.userVertexProperties[propertyName];
let prop;
if (propertyExists){
prop = this.geometry.userVertexProperties[propertyName];
} else {
prop = this.geometry._userVertexPropertyHelper(propertyName, data);
this.tessyVertexSize += prop.getDataSize();
this.bufferStrides[prop.getSrcName()] = prop.getDataSize();
this.renderer.buffers.user.push(
new RenderBuffer(prop.getDataSize(), prop.getSrcName(), prop.getDstName(), propertyName, this.renderer)
);
}
prop.setCurrentData(data);
}

_resetUserVertexProperties() {
const properties = this.geometry.userVertexProperties;
for (const propName in properties){
Expand Down
5 changes: 3 additions & 2 deletions src/webgl/material.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as constants from '../core/constants';
import { RendererGL } from './p5.RendererGL';
import { Shader } from './p5.Shader';
import { request } from '../io/files';
import { Color } from '../color/p5.Color';

function material(p5, fn){
/**
Expand Down Expand Up @@ -3625,7 +3626,7 @@ function material(p5, fn){
this.states.drawMode = constants.TEXTURE;
this.states._useNormalMaterial = false;
this.states._tex = tex;
this.states.fillColor = true;
this.states.fillColor = new Color(255);
};

RendererGL.prototype.normalMaterial = function(...args) {
Expand All @@ -3634,7 +3635,7 @@ function material(p5, fn){
this.states._useEmissiveMaterial = false;
this.states._useNormalMaterial = true;
this.states.curFillColor = [1, 1, 1, 1];
this.states.fillColor = true;
this.states.fillColor = new Color(255);
this.states.strokeColor = null;
}

Expand Down
3 changes: 3 additions & 0 deletions src/webgl/p5.Geometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,9 @@ class Geometry {
return this.name;
},
getCurrentData(){
if (this.currentData === undefined) {
this.currentData = new Array(this.getDataSize()).fill(0);
}
return this.currentData;
},
getDataSize() {
Expand Down
2 changes: 1 addition & 1 deletion src/webgl/p5.RendererGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ class RendererGL extends Renderer {
}

vertexProperty(...args) {
this.shapeBuilder.vertexProperty(...args);
this.currentShape.vertexProperty(...args);
}

normal(xorv, y, z) {
Expand Down

0 comments on commit 7fd2eb2

Please sign in to comment.