Hi!

I would like to color a torus red on the left half and blue on the right half surely with a transition.

Best check my next post below as I made a mockup of what I want to accomplish.

↓↓↓

Hi!

I would like to color a torus red on the left half and blue on the right half surely with a transition.

Best check my next post below as I made a mockup of what I want to accomplish.

↓↓↓

The following may not be exactly what you had in mind but it does run in the p5.js WebEditor. The errors came from the shader.vert file, so I used new files from here: https://github.com/aferriss/p5jsShaderExamples/tree/gh-pages/6_3d/6-1_rectangle and they allowed it to run without error.

```
let redGreen;
function preload() {
redGreen = loadShader("shader.vert", "shader.frag");
}
function setup() {
createCanvas(800, 600, WEBGL);
noStroke();
}
function draw() {
background(0);
shader(redGreen);
rotateX(frameCount * 0.01);
rotateY(frameCount * 0.01);
rotateZ(PI/2);
torus(180, 40, 100, 12);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
```

shader.frag

```
precision mediump float;
varying vec2 vTexCoord;
void main() {
// draw the texcoords to the screen
gl_FragColor = vec4(vTexCoord.x, vTexCoord.y, 0.0 ,1.0);
}
```

shader.vert

```
// Get the position attribute of the geometry
attribute vec3 aPosition;
// Get the texture coordinate attribute from the geometry
attribute vec2 aTexCoord;
// When we use 3d geometry, we need to also use some builtin variables that p5 provides
// Most 3d engines will provide these variables for you. They are 4x4 matrices that define
// the camera position / rotation, and the geometry position / rotation / scale
// There are actually 3 matrices, but two of them have already been combined into a single one
// This pre combination is an optimization trick so that the vertex shader doesn't have to do as much work
// uProjectionMatrix is used to convert the 3d world coordinates into screen coordinates
uniform mat4 uProjectionMatrix;
// uModelViewMatrix is a combination of the model matrix and the view matrix
// The model matrix defines the object position / rotation / scale
// Multiplying uModelMatrix * vec4(aPosition, 1.0) would move the object into it's world position
// The view matrix defines attributes about the camera, such as focal length and camera position
// Multiplying uModelViewMatrix * vec4(aPosition, 1.0) would move the object into its world position in front of the camera
uniform mat4 uModelViewMatrix;
varying vec2 vTexCoord;
void main() {
// copy the position data into a vec4, using 1.0 as the w component
vec4 positionVec4 = vec4(aPosition, 1.0);
// Move our vertex positions into screen space
// The order of multiplication is always projection * view * model * position
// In this case model and view have been combined so we just do projection * modelView * position
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
// Send the texture coordinates to the fragment shader
vTexCoord = aTexCoord;
}
```

1 Like

@svan thank you!!

It seems I copy pasted something wrong. Yes, I had the shader from that gitthub page loaded too. The problem I still have is that with the torus the gradient transition has a sharp break at one side like if the torus had a start and a end position:

How it looks:

I am looking for a result like this from red to blue. I mocked it up in photoshop that is why the transition of the gradient looks not so smooth:

Just for reference the code:

**sketch:**

```
let redGreen;
function preload() {
redGreen = loadShader("shader.vert", "shader.frag");
}
function setup() {
createCanvas(400, 400, WEBGL);
noStroke();
}
function draw() {
background(0);
shader(redGreen);
//rotateX(frameCount * 0.01);
//rotateY(frameCount * 0.01);
//rotateZ(PI/2);
translate(200-width/2,200-height/2);
torus(50, 20, 100, 12);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
```

**shader.vert**

```
attribute vec3 aPosition;
attribute vec2 aTexCoord;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
varying vec2 vTexCoord;
void main() {
vec4 positionVec4 = vec4(aPosition, 1.0);
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
vTexCoord = aTexCoord;
}
```

**shader.frag**

```
precision mediump float;
varying vec2 vTexCoord;
void main() {
// draw the texcoords to the screen
gl_FragColor = vec4(vTexCoord.x, vTexCoord.y, 0.0 ,1.0);
}
```

help would be very much appreciated. Also for more online resources I could read up on. Thanks!

Anyone can help here?

Since this seems like a shader question and not everyone is familiar with glsl around here, I’d recommend asking on the shader zone discord server. Hope this helps

1 Like

Instead of passing a uv pair for the texture coordinates, you only need a single float value based on the vertex y-coordinate. In your fragment shader, just have

```
varying float high;
void main() {
gl_Fragcolor = vec4( high, 0., 1.-high, 1. );
}
```

Then in your vertex shader, you have to compute `high`

from your `aPosition.y`

. Scale and offset it so it ranges from `0`

to `1`

.

1 Like

I played around with this a bit. It looks like p5 defines the torus model coordinates to scale from -1 to 1 from the middle of the big ring with the smaller ring extending from there. So if you had a `torus( 100, 20 )`

as an example, in your vertex shader, your `aPosition.y`

would range from `-1.2`

to `1.2`

. For that case, I would have `high = aPosition.y / 2.4 + 0.5;`

in the vertex shader.

1 Like

thank you @scudly for playing around with this. yes there is something about how p5 calculates the torus that is not ideal for shaders it seems. But boy do I know nothing about shaders and 3d

I will try to test your ideas although I don´t know exactly know where to put the lines of your code. I will try to read the shader introduction again and hope it helps to understand your suggestions better. Thanks!

My vertex shader is

```
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
attribute vec3 aPosition;
varying float high;
void main() {
high = aPosition.y / 2.4 + 0.5;
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
}
```

where the 2.4 number depends on the scaling of torus you create. Specifically, the ratio of the two radii.

Thanks, when I paste the above in the vertex shader and the following int o the shader.frag:

```
precision mediump float;
varying float high;
void main() {
gl_Fragcolor = vec4( high, 0., 1.-high, 1. );
}
```

I get this error:

p5.js says: [sketch.js, line 19] An error with message “Failed to execute ‘useProgram’ on ‘WebGLRenderingContext’: parameter 1 is not of type ‘WebGLProgram’.” occurred inside the p5js library when torus was called. If not stated otherwise, it might be an issue with the arguments passed to torus. (reference | p5.js)

Do I need to change somethin in the stech file too?

Here’s my full code which runs without errors on my linux chrome:

```
let redGreen;
function setup() {
createCanvas(400, 400, WEBGL);
redGreen = createShader( vs, fs );
noStroke();
}
function draw() {
background(0);
shader(redGreen);
torus( 100, 20, 100, 12);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
let vs = `
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
attribute vec3 aPosition;
varying float high;
void main() {
vec4 positionVec4 = vec4(aPosition, 1.0);
gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
high = aPosition.y / 2.4 + 0.5;
}
`;
let fs = `
precision mediump float;
varying float high;
void main() {
gl_FragColor = vec4( high, 0., 1.-high, 1.0 );
}
`;
```

3 Likes

running here too! That´s awesome. Thank you! Will dig into this now and try to understand. The result is spot on!