-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
p5Shader - Is there a way to specify custom attributes? #5120
Comments
I believe you are looking for this: |
@JalokimFreelance Thanks for the link! I'm looking for the ability to define custom attributes. The examples in the linked articles use the predefined ones. |
The key thing I'm hoping for is a
If a
The default attributes ( _ _ _. |
I don't believe such a function exists currently, although I think it could make a good addition to the webgl api. Binding attributes is typically a bit more complex than uniforms and most of the time people rely on the ones provided by the library. You might be able to pack your data into another buffer that you're not using, for instance if you don't need normals you could put your data in there. I'd also look around https://github.com/processing/p5.js/blob/main/src/webgl/p5.RenderBuffer.js as I think that's where the attribute binding functions are. If you'd like to take a crack at adding a setAttribute function to the api, you'll also need to make a case for why it increases accessibility. I think there may be a case to make in that it lowers the barrier of entry for beginners in webgl / graphics programming wanting to use attribute buffers, and expands the usefulness of the library on par with some others. Hope that helps! |
@aferriss Thank you for the detailed reply!
I'm still learning many of these concepts, but I'll try to give it a shot. If anyone more experienced wants to give it a go, please feel free to do so.
How would one do this? It seems that the various geometry constructors fill the attributes with values. How would one then overwrite these values? (ex one, two) |
Well, I think with the default shapes (rect, box, ellipse, etc) you won't be able to because there's no way to hold a reference to the shapes (I could be wrong about this but this is how I remember). This is actually something that could be nice to have too, so that you could loop over the shape's vertices, uvs, normals, etc. It's kind of outside of the processing / p5 paradigm of declaratively drawing shapes and maybe more similar to something like three.js. However, if you use a mesh with This is definitely an area where the webGL api needs some work. I think there were some tasks related to allowing per vertex colors floating around at some point. Searching through the closed issues might bring them up. |
Sorry for the late reply! |
Hi @aferriss It doesn't look like it is possible to render a model using a custom shader. I copied the loadModel example and created the following shaders: v.vert attribute vec3 aPosition;
attribute vec4 aVertexColor;
varying vec3 vVertexColor;
void main ()
{
// vVertexColor = aVertexColor.rgb;
vVertexColor = vec3( 1.0, 0.0, 0.0 ); // red
vec4 positionVec4 = vec4( aPosition, 1.0 );
positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
gl_Position = positionVec4;
} f.frag varying vec3 vVertexColor;
void main ()
{
gl_FragColor = vec4( vVertexColor, 1.0 );
} The main program looks like this, let octahedron;
let shader1;
function preload ()
{
octahedron = loadModel( 'octahedron.obj' );
shader1 = loadShader( "v.vert", "f.frag" );
}
function setup ()
{
createCanvas( 100, 100, WEBGL );
// Disable line shader ??
// noStroke();
// Disable fill shader ??
// noFill();
}
function draw ()
{
shader( shader1 );
clear();
rotateX( frameCount * 0.01 );
rotateY( frameCount * 0.01 );
model( octahedron );
// rect( 0, 0, 0, 0 );
// ellipse( 0, 0, 0, 0 );
// triangle( 0, 0, 0, 0, 0, 0 );
} Expected result, the octahedron is red. However, the model seems to be rendered by the default shaders (for material and lines). Setting When the It seems there's no clean way to hack the existing interface to use custom attributes. |
I spoke too soon. v.vert attribute vec3 aPosition;
attribute vec4 aVertexColor;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
varying vec3 vVertexColor;
void main ()
{
// vVertexColor = aVertexColor.rgb;
vVertexColor = vec3( 1.0, 0.0, 0.0 ); // red
vec4 positionVec4 = vec4( aPosition, 1.0 );
// positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
// gl_Position = positionVec4;
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
} |
It might not be appearing because you aren't using any of the matrices for projection. Without looking more closely I can't say for certain, but a typical vertex shader for a 3d object looks like:
You can see a couple more of the shaders here: https://github.com/processing/p5.js/tree/c1640a7cb11c25145e9b9dd561ba27f7b49fcde4/src/webgl/shaders You might also need to look into the obj loader to ensure that it is properly reading color from the mesh as well. I'm afraid you're nudging up against the boundaries of what has been implemented in p5. You might try checking out three.js if p5 isn't able to get you where you're trying to go. It's much more fully featured when dealing with 3d and webGL. |
Ah, I see. For posterity, here's a link to the final working code I put together. There are three variants:
|
@JetStarBlues These are great examples! Thanks for taking the time to share them. It seems like you were able to get pretty close to what you were aiming for. It's great to see the variety of approaches, and I think definitely helps illuminate areas in the webGL api that could use more work. One area where help is always welcome is documentation, so if you see anything that you think should be updated, or was never documented in the first place, I think those would be very welcome PR's. I've never seen anyone directly with the p5.Geometry class like that either so contributing those examples could be very valuable for other newcomers to the 3d api. |
Oh! Happy to hear =D! (Thanks for taking the time to reply to these sporadic posts!)
Noted. Will give it a try. |
@aferriss Came up with one more implementation idea. 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 );
} |
It will always create buffers of type |
This is great! I really didn't know that you could use p5 to make procedural geometry in this way. I definitely think we should consider documenting this workflow. @stalgiag what do you think about this? I moved some of your examples to the editor and simplified them as well: Simple Triangle The last example of custom particles, I was able to render 100,000 particles on my macbook at 60fps! |
Cool examples! |
This is really great. I know it isn't very in line with the rest of the API but I often find myself wishing that |
I think one other thing to consider for this approach, is making the way that values are specified consistent. For the default buffers, |
@JetStarBlues Completely agree. I actually got briefly stumped by this when I was making my examples. @stalgiag agreed! It feels like all the major pieces are already there and it would just take a little push to make it friendlier. |
Here is an example illustrating how access to the uv values can be used for uv mapping. |
@aferriss It occurred to me that a similar technique could be used to "use a shader as a texture". The current example in the documentation uses |
An update. Found out how to update the buffer values "on the fly".
It looks like function draw() {
// modify vertices
...
// mark vertices as dirty
m.dirtyFlags.vertices = true
// draw the model. Internal call to _prepareBuffer() will update buffers
model(m);
} Here is a simple live version of this in action. An additional hack is required to propogate the vertex updates to the default stroke shader. Here is another demo. This one is based on Coding Challenge: 3D Supershapes. In (I find it surprising that the immediate mode version can handle more vertices (via |
Hi! This might be unrelated to this issue, but is there a way using this method to also define the primitive rendering mode like |
If this open, can I take this? |
This is open, but needs a bit of discussion about how it should be solved before we get to the implementation. Do you have an idea of how you want to approach the problem, like what the API would look like for users? |
Adding WebGL custom attributes contributor @lukeplowden @davepagurek in this discussion. |
Closing this now that #7276 is merged in! This will be coming in p5 2.0 🙂 |
How would this new feature help increase access to p5.js?
Potential to expand capability of p5's WebGL mode.
Most appropriate sub-area of p5.js?
Feature enhancement details:
Is there a way to specify custom attributes when working with shaders?
From what I've gathered from this contributor_doc, these are the available attributes (let me know if this assumption is incorrect):
attribute vec3 aPosition
attribute vec3 aNormal
attribute vec2 aTexCoord
attribute vec4 aDirection
attribute vec4 aVertexColor
Suppose I want to pass some custom attributes to a shader. (For example, I want to specify a cube (or other custom geometry such as a 3D model or something generated dynamically) by passing in some vertices as one attribute, and some vertex colors as another attribute). How can I go about this? Is there a
setAttribute
equivalent tosetUniform
? If not, is there a way to do this using private p5 methods?Sidenote:
It would be great if the shader documentation on p5js.org/reference was a bit more fleshed out. For example:
beginShape
andendShape
to specify custom geometry (aPostion
), and vertex colors (aVertexColor
) (as seen here Enabling lights() in WEBGL breaks vertex colors. #4274))Related issues:
The text was updated successfully, but these errors were encountered: