I want to draw the following picture.
The language is typescript.
The Code:
Code is distributed in multiple files. The scenegraph file contains a function to visit a group node, which ultimately performs a DFS, as follows:
visitGroupNode(node: GroupNode, lvl: number = 0) {
if (lvl == 0) {
this.iStack = [];
this.mStack = []; // empty array
this.obj = [];
let rootMatrix = Matrix.identity();
let rootInverse = Matrix.identity();
this.mStack.push(rootMatrix);
this.iStack.push(rootInverse);
}
// get children
let currentNode = node as any;
//console.log("--->");
if (currentNode) {}
else return;
//console.log("executing level : " + lvl);
let c = currentNode.childNodes;
// Insert thematrices
let prevM = this.mStack[this.mStack.length - 1];
let prevI = this.iStack[this.iStack.length - 1];
if (prevM) this.mStack.push(prevM.mul(currentNode.transform.matrix));
else this.mStack.push(currentNode.transform.matrix);
if (prevI) this.iStack.push(prevI.mul(currentNode.transform.inverse));
else this.iStack.push(currentNode.transform.inverse);
//console.log("node type is : " + currentNode.constructor.name);
//console.log(currentNode);
//console.log("current one");
//currentNode.transform.matrix.print();
//console.log("previous one");
//prevM.print();
//console.log("total");
//prevM.mul(currentNode.transform.matrix).print();
this.obj.push(currentNode);
for ( var i = 0; i < c.length; i++) {
let currChild = c[i];
if(currChild.constructor.name == "GroupNode") this.visitGroupNode(currChild, lvl + 1);
if(currChild.constructor.name == "SphereNode") {
//console.log("End of chain");
this.visitSphereNode(currChild);
}
if(currChild.constructor.name == "BoxNode") {
this.visitBoxNode(currChild);
}
}
}
The important part is the visitBoxNode
, resp. visitSphereNode
function.
For the sphere, the visitSphereNode function calls a render function, which is defined in file Sphere.ts as follows.
render(shader: Shader) { // overload target
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
const positionLocation = shader.getAttributeLocation("a_position");
this.gl.enableVertexAttribArray(positionLocation);
this.gl.vertexAttribPointer(positionLocation, 3, this.gl.FLOAT, false, 0, 0);
// TODO: bind color buffer
const colorLocation = shader.getAttributeLocation( "a_vertexColor");
this.gl.vertexAttribPointer(colorLocation, //buffer
3, // count
this.gl.FLOAT, //type
false, // normalize
4, // wie viel überspringen pro schritt (stride)
0 // wie viele am anfang vernachlässigen (offset)
);
this.gl.enableVertexAttribArray(colorLocation);
console.log("colorLocation is : "); console.log(colorLocation);
//shader.getUniformVec3("scolor").set(new Vector(0.2,0.4,0.0));
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
this.gl.drawElements(this.gl.TRIANGLES, this.elements, this.gl.UNSIGNED_SHORT, 0);
// this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// this.gl.drawElements(this.gl.TRIANGLES, this.elements, this.gl.UNSIGNED_SHORT, 0);
//
// this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// this.gl.drawElements(this.gl.TRIANGLES, this.elements, this.gl.UNSIGNED_SHORT, 0);
//this.gl.disableVertexAttribArray(positionLocation);
//this.gl.disableVertexAttribArray(colorLocation);
}
Full code in pastebin: HERE
The shader file in pastebin: HERE
The shader file calls the vertex shader and the fragement shader.
The vertex shader is like this:
attribute vec3 a_position;
attribute vec3 a_vertexColor;
// TODO: declare variable
uniform mat4 M;
varying lowp vec4 v_color;
//uniform vec4 scolor; // NOTICE if i set this active, firefox complains : variable not linkable between shaders.
void main() {
gl_Position = M*vec4(a_position, 1.0);
// TODO: set variable for fragement shader
v_color = vec4(a_vertexColor, 1.0);
}
The fragment shader is:
precision mediump float;
//TODO: declare variable
varying lowp vec4 v_color;
//uniform vec4 scolor;
void main(void) {
gl_FragColor = vec4(0.0, 0.0, 0.5, 1.0); // old value
//TODO: set color
gl_FragColor = v_color;
}
The box code is similarly added in pastebin: HERE.
Problem: The colors are all over the place.
Question
Clearly, the sphere needs to use an Uniform color, and the box a varying color.
How can I make them both appear on the same canvas using the shader glsl file(s)?
The default values of attributes and uniforms are 0 for the RGB channels and 1 for the alpha channel. This is also the case when a vertex attribute is not specified or disabled. The uniform variable can of course be explicitly set to 0. You can combine the color from the vertex attributes and a color from a uniform variable. Add a uniform variable for the color, add the RGB channels and multiply the alpha channels. If the mesh is uniform colored, then you disable the attribute for the color with 'disableVertexAttribArray'. If the mesh has a color attribute, set the uniform variable to (0, 0, 0, 1).
precision mediump float;
varying lowp vec4 v_color;
uniform vec4 u_color;
void main(void) {
gl_FragColor = vec4(v_color.rgb + u_color.rgb, v_color.a * u_color.a);
}
Another option is to mix
the color depending on the alpha channel of the uniform color:
precision mediump float;
varying lowp vec4 v_color;
uniform vec4 u_color;
void main(void) {
gl_FragColor = vec4(mix(v_color.rgb, u_color.rgb, u_color.a), 1.0);
}