Unable to move a shape in processing - processing

I am attempting to create a movable entity who can move left and right on a map. I have a map that sets the initial location of the entity but once the 'a' or 'd' keys are pushed, the character moves only slightly then resets to its initial location once the key is released. I have a Boolean variable "playerIsSpawned" to ensure that the character's location is only set in that location once, however this didn't seem to fix anything. What is causing this and how can I fix it?
var start_map = [
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 9, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1]
];
var playerX;
var playerY;
function drawPlayer() {
fill(0);
rect(playerX, playerY, 50, 50);
}
function drawMap(map) {
// The x and y do not represent the x and y axis
// Keep in mind a 2d array is an array of an array
noStroke();
var playerIsSpawned = false;
for (var x = 0; x < map.length; x++) {
for (var y = 0; y < map.length; y++) {
// Background
if (map[y][x] == 0) {
fill(184, 236, 255);
rect((10 + 50*x), (10 + 50*y), 50, 50);
}
// Ground
else if (map[y][x] == 1) {
fill(51, 153, 51);
rect((10 + 50*x), (10 + 50*y), 50, 50);
}
// Player
else if (map[y][x] == 9) {
if (playerIsSpawned == false) {
playerX = (10 + 50*x);
playerY = (10 + 50*y);
playerIsSpawned = true;
}
fill(184, 236, 255);
rect((10 + 50*x), (10 + 50*y), 50, 50);
}
}
}
drawPlayer();
function keyPressed() {
if (key == "d") {
playerX += 5;
}
else if (key == "a") {
playerX -= 5;
}
}
keyPressed();
}
function setup() {
background(0);
createCanvas(800, 800);
}
function draw() {
drawMap(start_map);
}

You declared playerIsSpawned inside drawMap. That'll get reset to false every time through there.
Also, consider defining the keyPressed() at the top level (same as draw and setup, and getting rid of that call to keyPressed() inside your draw loop.

Related

How can I make the background transparent in P5.js, but still keep the same effect?

I have a P5.js art, but when I remove the background, the effect changes. I'd like to remove the background but keep the effect the same. The reason for this is because I plan to overlay this on top of another canvas.
The line I'd like to remove is this: background(30); However, when I remove it, the effect becomes different.
The full code can be found here: https://editor.p5js.org/timexer/sketches/Rbbo72xVi
class Particle {
constructor(){
this.pos = createVector(width/2,height/2)
this.vel = createVector(0,0)
this.acc = p5.Vector.random2D().normalize()
this.r = map(this.pos.x, 0, width, 255, 0)
this.g = map(this.pos.y, 0, height, 0, 255)
this.b = map(dist(width / 2, height / 2, this.pos.x, this.pos.y), 0, width/2, 0, 255)
this.alpha = 255
}
update(){
var m = map(sin(frameCount), -1, 1, 0.3, 0.6)
this.acc.mult(m)
this.vel.add(this.acc)
this.pos.add(this.vel)
this.r = map(this.pos.x, 0, width, 255, 0)
this.g = map(this.pos.y, 0, height, 0, 255)
this.b = map(dist(width / 2, height / 2, this.pos.x, this.pos.y), 0, width, 0, 255)
if ( dist(width / 2, height / 2, this.pos.x, this.pos.y) > 80){
this.alpha -= 5
}
}
show(){
noStroke()
fill(this.r, this.g, this.b, this.alpha)
ellipse(this.pos.x, this.pos.y, 2)
}
}
var particles = []
function setup() {
createCanvas(800, 800);
angleMode(DEGREES)
}
function draw() {
background(30);
for(var i = 0; i <10; i++){
p = new Particle()
particles.push(p)
}
for(var i = 0; i < particles.length ; i++){
if(particles[i].alpha > 0){
particles[i].update()
particles[i].show()
}else{
particles.splice(i,1)
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
Instead of calling background(30) call clear()
var particles = []
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES)
}
function draw() {
clear();
for (var i = 0; i < 10; i++) {
const p = new Particle()
particles.push(p)
}
for (var i = 0; i < particles.length; i++) {
if (particles[i].alpha > 0) {
particles[i].update()
particles[i].show()
} else {
particles.splice(i, 1)
}
}
}
class Particle {
constructor() {
this.pos = createVector(width / 2, height / 2)
this.vel = createVector(0, 0)
this.acc = p5.Vector.random2D().normalize()
this.r = map(this.pos.x, 0, width, 255, 0)
this.g = map(this.pos.y, 0, height, 0, 255)
this.b = map(dist(width / 2, height / 2, this.pos.x, this.pos.y), 0, width / 2, 0, 255)
this.alpha = 255
}
update() {
var m = map(sin(frameCount), -1, 1, 0.3, 0.6)
this.acc.mult(m)
this.vel.add(this.acc)
this.pos.add(this.vel)
this.r = map(this.pos.x, 0, width, 255, 0)
this.g = map(this.pos.y, 0, height, 0, 255)
this.b = map(dist(width / 2, height / 2, this.pos.x, this.pos.y), 0, width, 0, 255)
if (dist(width / 2, height / 2, this.pos.x, this.pos.y) > 80) {
this.alpha -= 5
}
}
show() {
noStroke()
fill(this.r, this.g, this.b, this.alpha)
ellipse(this.pos.x, this.pos.y, 2)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

p5js, need help using get() to detect the color of a pixel as a RGBA array to see if the mouse is hovering over it

Currently learning and working on a project, for this particular case I'm trying to simulate a collision detection by obtaining the color of a pixel with get().
In the console log, I can see the color array of the pixel the mouse is hovering on corresponds to my color in the colors array but then I can't seem to compare them. Seems like I'm unable to see through some basic principle, I've been trying for some hours to find a solution to no avail.
function setup() {
createCanvas(400, 400);
colors = [[255, 165, 0, 255], [61, 145, 64, 255], [204, 0, 0, 255], [31, 117, 254, 255],
[160, 32, 240, 255], [0, 128, 128, 255], [244, 0, 161, 255]];
}
function draw() {
background(220);
for(var i = 0; i < colors.length; i++){
fill(colors[i]);
ellipse(120, 40 + 45 * i, 40);
let c = get(mouseX, mouseY);
// console.log(c);
if(c == colors[i]){
console.log(colors[i]);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
You can use the function I added at the bottom.
function setup() {
createCanvas(400, 400);
colors = [[255, 165, 0, 255], [61, 145, 64, 255], [204, 0, 0, 255], [31, 117, 254, 255],
[160, 32, 240, 255], [0, 128, 128, 255], [244, 0, 161, 255]];
}
function draw() {
background(220);
for(i = 0; i < colors.length; i++){
fill(colors[i]);
ellipse(120, 40 + 45 * i, 40);
}
for(i = 0; i < colors.length; i++){
let c = get(mouseX, mouseY);
if(arrayEquals(c,colors[i])){
console.log(colors[i]);
}
}
}
function arrayEquals(a, b) { //define a function with arguments a,b
return Array.isArray(a) && //true if 'a' is an array, '&&' checks if all arguments are true to return true otherswise false
Array.isArray(b) && //true if 'b' is an array
a.length === b.length && //true if 'a' is the same length as 'b'
a.every((val, index) => val === b[index]); //true if 'a' value is the same as the 'b' value at the same position for all positions
}

Change edges/triangulation of plane geometry

I am trying to edit the edges/triangulation of a planebuffer geometry in three js.
Example of problem
I want to change the corners in red to be triangulated like the corner in green.
Is this possible via editing a plane, or do I have to start building my own custom mesh buffer.
Here is a fiddle for an example of the kind of manipulation I am doing on the plane. (can click and drag to rotate it)
var camera, scene, renderer;
var geometry, material, mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 5;
scene = new THREE.Scene();
geometry = new THREE.PlaneBufferGeometry( 10, 10, 10, 10 );
const pointLight = new THREE.PointLight(0xFFFFFF, 1);
const ambientLight = new THREE.AmbientLight(0xFFFFFF, 0.1);
pointLight.position.y += 2;
pointLight.position.x = -1;
scene.add(pointLight);
scene.add(ambientLight);
const grid = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
const planePos = geometry.attributes.position;
for (let x = 0; x < grid.length; x++) {
const row = grid[x];
for (let y = 0; y < row.length; y++) {
const h = row[y];
const i = (x * row.length) + y;
planePos.setZ(i, h * 0.5);
}
}
//
material = new THREE.MeshPhongMaterial({flatShading:true});
mesh = new THREE.Mesh( geometry, material );
mesh.rotateX(Math.PI * -0.5);
mesh.translateZ(-1);
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
}
function animate(t) {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0;
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Ok, as #prisoner849 commented, buffergeometryies index property was the answer.
I redid the triangulation of the mesh by looping over the "squares" of my mesh, getting their corners and then changing the indexes for each squares triangles to one of a pre calculated set, based on which corner had a unique height. It also seems that you want the indexes to go in a specific order to control which side is "up", it seems to be that counter clockwise or so.
const size = 10;
const vertMap = [0, 3, 1, 3, 2, 1];
const triSets = [
[0, 3, 2, 0, 2, 1],
[1, 3, 2, 1, 0, 3],
[0, 3, 2, 0, 2, 1],
[1, 3, 2, 1, 0, 3],
];
const getSquareVerts = (x, y) => {
const i = (y * size) + x + y;
return [i, i + 1, i + (size + 2), i + (size + 1)];
}
const getUniqueHeightPoint = (verts) => {
let unique = -1;
const set = verts.reduce((p, n) => {
const c = p[n.toString()] || 0;
p[n.toString()] = c + 1;
return p;
}, {});
const keys = Object.keys(set);
if (keys.length == 2 && (set[keys[0]] == 1 || set[keys[0]] == 3)) {
for (const key of keys) {
if (set[key] == 1) {
unique = verts.findIndex((v) => v == parseFloat(key));
break;
}
}
}
return unique;
}
const reworkTris = (plane) => {
let indexOffset = 0;
const planeIdx = plane.geometry.index;
for (let y = 0; y < this.size; y++) {
for (let x = 0; x < this.size; x++) {
const verts = this.getSquareVerts(x, y);
const heights = verts.map((v) => this.planePos.getZ(v));
const uniqueHeight = this.getUniqueHeightPoint(heights);
let tris = vertMap.map((i) => verts[i]);
if (uniqueHeight >= 0) {
tris = triSets[uniqueHeight].map((i) => verts[i]);
}
planeIdx.set(tris, indexOffset);
indexOffset += 6;
}
}
planeIdx.needsUpdate = true;
}
const plane = new THREE.Mesh(new THREE.PlaneBufferGeometry());
reqorkTris(plane);

How to interpolate a cube using fromRotationTranslationScaleOrigin in gl-matrix?

Code: https://plnkr.co/edit/QNA31hMYnIJwotwbaDhT?p=preview
Question: How can I interpolate all properties of fromRotationTranslationScaleOrigin from gl-matrixin draw function of this cube?
Let's interpolate over 3 seconds:
from:
q = quat.create(),
translate =[-3, 0, -10],
scale = [1,1,1],
pivot = [0,0,0]
to:
q = quat.create(),
translate =[0, 0, -8],
scale = [3,3,3],
pivot = [1,1,1]
Program:
var gl,
shaderProgram,
vertices,
matrix = mat4.create(),
vertexCount,
indexCount,
q = quat.create(),
translate =[-3, 0, -10],
scale = [1,1,1],
pivot = [0,0,0];
initGL();
createShaders();
createVertices();
createIndices();
draw();
function initGL() {
var canvas = document.getElementById("canvas");
gl = canvas.getContext("webgl");
gl.enable(gl.DEPTH_TEST);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1, 1, 1, 1);
}
function createShaders() {
var vertexShader = getShader(gl, "shader-vs");
var fragmentShader = getShader(gl, "shader-fs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function createVertices() {
vertices = [
-1, -1, -1, 1, 0, 0, 1, // 0
1, -1, -1, 1, 1, 0, 1, // 1
-1, 1, -1, 0, 1, 1, 1, // 2
1, 1, -1, 0, 0, 1, 1, // 3
-1, 1, 1, 1, 0.5, 0, 1, // 4
1, 1, 1, 0.5, 1, 1, 1, // 5
-1, -1, 1, 1, 0, 0.5, 1, // 6
1, -1, 1, 0.5, 0, 1, 1, // 7
];
vertexCount = vertices.length / 7;
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var coords = gl.getAttribLocation(shaderProgram, "coords");
gl.vertexAttribPointer(coords, 3, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 7, 0);
gl.enableVertexAttribArray(coords);
var colorsLocation = gl.getAttribLocation(shaderProgram, "colors");
gl.vertexAttribPointer(colorsLocation, 4, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 7, Float32Array.BYTES_PER_ELEMENT * 3);
gl.enableVertexAttribArray(colorsLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var pointSize = gl.getAttribLocation(shaderProgram, "pointSize");
gl.vertexAttrib1f(pointSize, 20);
// var color = gl.getUniformLocation(shaderProgram, "color");
// gl.uniform4f(color, 0, 0, 0, 1);
var perspectiveMatrix = mat4.create();
mat4.perspective(perspectiveMatrix, 1, canvas.width / canvas.height, 0.1, 11);
var perspectiveLoc = gl.getUniformLocation(shaderProgram, "perspectiveMatrix");
gl.uniformMatrix4fv(perspectiveLoc, false, perspectiveMatrix);
}
function createIndices() {
var indices = [
0, 1, 2, 1, 2, 3,
2, 3, 4, 3, 4, 5,
4, 5, 6, 5, 6, 7,
6, 7, 0, 7, 0, 1,
0, 2, 6, 2, 6, 4,
1, 3, 7, 3, 7, 5
];
indexCount = indices.length;
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
}
function draw() {
mat4.fromRotationTranslationScaleOrigin(
matrix,
q,
translate,
scale,
pivot
);
var transformMatrix = gl.getUniformLocation(shaderProgram, "transformMatrix");
gl.uniformMatrix4fv(transformMatrix, false, matrix);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_BYTE, 0);
requestAnimationFrame(draw);
}
/*
* https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context
*/
function getShader(gl, id) {
var shaderScript, theSource, currentChild, shader;
shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
theSource = "";
currentChild = shaderScript.firstChild;
while (currentChild) {
if (currentChild.nodeType == currentChild.TEXT_NODE) {
theSource += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
}
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
// Unknown shader type
return null;
}
gl.shaderSource(shader, theSource);
// Compile the shader program
gl.compileShader(shader);
// See if it compiled successfully
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
<canvas id="canvas" width="600" height="600"></canvas>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec4 coords;
attribute float pointSize;
uniform mat4 transformMatrix;
attribute vec4 colors;
varying vec4 varyingColors;
uniform mat4 perspectiveMatrix;
void main(void) {
gl_Position = perspectiveMatrix * transformMatrix * coords;
gl_PointSize = pointSize;
varyingColors = colors;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 color;
varying vec4 varyingColors;
void main(void) {
gl_FragColor = varyingColors;
}
</script>
To the call back function of requestAnimationFrame is passe one single argument, which is a time value.
This time can be used to calculate a matrix by a function of time.
function draw(timeMs) {
requestAnimationFrame(draw);
let interval = timeMs / 3000; // 3000 ms are 3 seconds
let t = interval - Math.floor(interval);
// [...]
}
Use vec3.lerp to interpolate the translation, pivot and scale, dependent on the time interval t:
function draw(timeMs) {
// [...]
let trans_t = vec3.lerp([], translate, translate2, t);
let scale_t = vec3.lerp([], scale, scale2, t);
let pivot_t = vec3.lerp([], pivot, pivot2, t);
mat4.fromRotationTranslationScaleOrigin(matrix, q, trans_t, scale_t, pivot_t);
// [...]
}
See the example, where I applied the suggestions to the code of the question:
var gl,
shaderProgram,
vertices,
matrix = mat4.create(),
vertexCount,
indexCount,
q = quat.create(),
translate =[-3, 0, -10],
scale = [1,1,1],
pivot = [0,0,0];
translate2 = [0, 0, -8],
scale2 = [3,3,3],
pivot2 = [1,1,1]
initGL();
createShaders();
createVertices();
createIndices();
draw();
function initGL() {
var canvas = document.getElementById("canvas");
gl = canvas.getContext("webgl");
gl.enable(gl.DEPTH_TEST);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1, 1, 1, 1);
}
function createShaders() {
var vertexShader = getShader(gl, "shader-vs");
var fragmentShader = getShader(gl, "shader-fs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
}
function createVertices() {
vertices = [
-1, -1, -1, 1, 0, 0, 1, // 0
1, -1, -1, 1, 1, 0, 1, // 1
-1, 1, -1, 0, 1, 1, 1, // 2
1, 1, -1, 0, 0, 1, 1, // 3
-1, 1, 1, 1, 0.5, 0, 1, // 4
1, 1, 1, 0.5, 1, 1, 1, // 5
-1, -1, 1, 1, 0, 0.5, 1, // 6
1, -1, 1, 0.5, 0, 1, 1, // 7
];
vertexCount = vertices.length / 7;
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var coords = gl.getAttribLocation(shaderProgram, "coords");
gl.vertexAttribPointer(coords, 3, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 7, 0);
gl.enableVertexAttribArray(coords);
var colorsLocation = gl.getAttribLocation(shaderProgram, "colors");
gl.vertexAttribPointer(colorsLocation, 4, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 7, Float32Array.BYTES_PER_ELEMENT * 3);
gl.enableVertexAttribArray(colorsLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var pointSize = gl.getAttribLocation(shaderProgram, "pointSize");
gl.vertexAttrib1f(pointSize, 20);
// var color = gl.getUniformLocation(shaderProgram, "color");
// gl.uniform4f(color, 0, 0, 0, 1);
var perspectiveMatrix = mat4.create();
mat4.perspective(perspectiveMatrix, 1, canvas.width / canvas.height, 0.1, 11);
var perspectiveLoc = gl.getUniformLocation(shaderProgram, "perspectiveMatrix");
gl.uniformMatrix4fv(perspectiveLoc, false, perspectiveMatrix);
}
function createIndices() {
var indices = [
0, 1, 2, 1, 2, 3,
2, 3, 4, 3, 4, 5,
4, 5, 6, 5, 6, 7,
6, 7, 0, 7, 0, 1,
0, 2, 6, 2, 6, 4,
1, 3, 7, 3, 7, 5
];
indexCount = indices.length;
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
}
function draw(timeMs) {
requestAnimationFrame(draw);
let interval = timeMs / 3000
let t = interval - Math.floor(interval);
let trans_t = vec3.lerp([], translate, translate2, t);
let scale_t = vec3.lerp([], scale, scale2, t);
let pivot_t = vec3.lerp([], pivot, pivot2, t);
mat4.fromRotationTranslationScaleOrigin(matrix, q, trans_t, scale_t, pivot_t);
var transformMatrix = gl.getUniformLocation(shaderProgram, "transformMatrix");
gl.uniformMatrix4fv(transformMatrix, false, matrix);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_BYTE, 0);
}
/*
* https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context
*/
function getShader(gl, id) {
var shaderScript, theSource, currentChild, shader;
shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
theSource = "";
currentChild = shaderScript.firstChild;
while (currentChild) {
if (currentChild.nodeType == currentChild.TEXT_NODE) {
theSource += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
}
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
// Unknown shader type
return null;
}
gl.shaderSource(shader, theSource);
// Compile the shader program
gl.compileShader(shader);
// See if it compiled successfully
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec4 coords;
attribute float pointSize;
uniform mat4 transformMatrix;
attribute vec4 colors;
varying vec4 varyingColors;
uniform mat4 perspectiveMatrix;
void main(void) {
gl_Position = perspectiveMatrix * transformMatrix * coords;
gl_PointSize = pointSize;
varyingColors = colors;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 color;
varying vec4 varyingColors;
void main(void) {
gl_FragColor = varyingColors;
}
</script>
<canvas id="canvas" width="600" height="600"></canvas>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>

Groups & THREE.MultiMaterial

As part of prototyping some debugger objects and methods, I created a simple cube with a different color on each side. Rather than creating multiple meshes, I decided to use draw groups and THREE.Multimaterial. Unfortunately, it's only half-working, and I don't understand why.
What IS working is the first two sides (4 triangles). What's NOT working is any of the other sides. None of the other sides are visible. I've added debug code to draw the (index-based) vertex normals, the (index-based, manually calculated) face normals, and the wireframe (THREE.WireframeHelper).
If I increase the count for the second group to 9, nothing happens. If I change the groups to reference different start/count values within the first 8 vertices, those changes work as expected. Doing anything above 8th vertex has no effect.
I've also checked that the drawRange is set to draw from 0 to Infinity. I've also ruled out typos in my data, because otherwise the normals and wireframe wouldn't work. Is there anything else I'm missing? Thanks!
(I found the issue in r76. Code below referenced r79 at the time of writing.)
jsfiddle: http://jsfiddle.net/TheJim01/gumftkm4/
HTML:
<script src="http://threejs.org/build/three.js"></script>
<script src="http://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script src="http://threejs.org/examples/js/libs/stats.min.js"></script>
<div id="host"></div>
<script>
// INITIALIZE
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
document.getElementById('host').appendChild(renderer.domElement);
var stats= new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0';
document.body.appendChild(stats.domElement);
var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 250;
var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
trackballControl.rotateSpeed = 5.0; // need to speed it up a little
var scene = new THREE.Scene();
var light = new THREE.PointLight(0xffffff, 1, Infinity);
light.position.copy(camera.position);
scene.add(light);
function draw(){
light.position.copy(camera.position);
renderer.render(scene, camera);
stats.update();
}
trackballControl.addEventListener('change', draw);
function navStartHandler(e) {
renderer.domElement.addEventListener('mousemove', navMoveHandler);
renderer.domElement.addEventListener('mouseup', navEndHandler);
}
function navMoveHandler(e) {
trackballControl.update();
}
function navEndHandler(e) {
renderer.domElement.removeEventListener('mousemove', navMoveHandler);
renderer.domElement.removeEventListener('mouseup', navEndHandler);
}
renderer.domElement.addEventListener('mousedown', navStartHandler);
renderer.domElement.addEventListener('mousewheel', navMoveHandler);
</script>
CSS:
html *{
padding: 0;
margin: 0;
width: 100%;
overflow: hidden;
}
#host {
width: 100%;
height: 100%;
}
JavaScript:
// New Color Cube
(function () {
var pos = new Float32Array([
// front
-1, 1, 1,
-1, -1, 1,
1, 1, 1,
1, -1, 1,
// right
1, 1, 1,
1, -1, 1,
1, 1, -1,
1, -1, -1,
// back
1, 1, -1,
1, -1, -1,
-1, 1, -1,
-1, -1, -1,
// left
-1, 1, -1,
-1, -1, -1,
-1, 1, 1,
-1, -1, 1,
// top
-1, 1, -1,
-1, 1, 1,
1, 1, -1,
1, 1, 1,
// bottom
-1, -1, 1,
-1, -1, -1,
1, -1, 1,
1, -1, -1
]),
nor = new Float32Array([
// front
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
// right
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
// back
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,
// left
-1, 0, 0,
-1, 0, 0,
-1, 0, 0,
-1, 0, 0,
// top
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
// bottom
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0
]),
idx = new Uint32Array([
// front
0, 1, 2,
3, 2, 1,
// right
4, 5, 6,
7, 6, 5,
// back
8, 9, 10,
11, 10, 9,
// left
12, 13, 14,
15, 14, 13,
// top
16, 17, 18,
19, 18, 17,
// bottom
20, 21, 22,
23, 22, 21
]);
var sideColors = new THREE.MultiMaterial([
new THREE.MeshLambertMaterial({ color: 'red' }), // front
new THREE.MeshLambertMaterial({ color: 'green' }), // right
new THREE.MeshLambertMaterial({ color: 'orange' }), // back
new THREE.MeshLambertMaterial({ color: 'blue' }), // left
new THREE.MeshLambertMaterial({ color: 'white' }), // top
new THREE.MeshLambertMaterial({ color: 'yellow' }) // bottom
]);
var cubeGeometry = new THREE.BufferGeometry();
cubeGeometry.addAttribute("position", new THREE.BufferAttribute(pos, 3));
cubeGeometry.addAttribute("normal", new THREE.BufferAttribute(nor, 3));
cubeGeometry.setIndex(new THREE.BufferAttribute(idx, 3));
cubeGeometry.clearGroups();
cubeGeometry.addGroup(0, 6, 0);
cubeGeometry.addGroup(6, 6, 1);
cubeGeometry.addGroup(12, 6, 2);
cubeGeometry.addGroup(18, 6, 3);
cubeGeometry.addGroup(24, 6, 4);
cubeGeometry.addGroup(30, 6, 5);
THREE.ColorCube = function (scaleX, scaleY, scaleZ) {
THREE.Mesh.call(this, cubeGeometry, sideColors);
var scaler = new THREE.Matrix4().makeScale(scaleX, scaleY, scaleZ);
this.applyMatrix(scaler);
};
THREE.ColorCube.prototype = Object.create(THREE.Mesh.prototype);
THREE.ColorCube.prototype.constructor = THREE.ColorCube;
THREE.ColorCube.prototype.clearVertexNormals = function () {
if (this.vNormals === undefined) {
this.vNormals = [];
}
for (var i = 0, len = this.vNormals.length; i < len; ++i) {
this.parent.remove(this.vNormals[i]);
}
this.vNormals.length = 0;
}
THREE.ColorCube.prototype.drawVertexNormals = function (scale, color) {
this.clearVertexNormals();
scale = (scale === undefined) ? 1 : scale;
color = (color === undefined) ? 0xff : color;
var origin = new THREE.Vector3(),
normalArrow = null,
vert = null,
norm = null,
index = null,
vertexArray = this.geometry.attributes.position.array,
normalArray = this.geometry.attributes.normal.array,
indexArray = this.geometry.index.array;
for (var i = 0, len = indexArray.length; i < len; ++i) {
index = indexArray[i];
vert = new THREE.Vector3(...vertexArray.slice((index * 3), (index * 3) + 3)).applyMatrix4(this.matrix);
norm = new THREE.Vector3(...normalArray.slice((index * 3), (index * 3) + 3));
normalArrow = new THREE.ArrowHelper(
norm,
origin,
1 * scale,
color,
0.2 * scale,
0.1 * scale
);
normalArrow.position.copy(vert);
this.vNormals.push(normalArrow);
this.parent.add(normalArrow);
}
};
THREE.ColorCube.prototype.clearFaceNormals = function () {
if (this.fNormals === undefined) {
this.fNormals = [];
}
for (var i = 0, len = this.fNormals.length; i < len; ++i) {
this.parent.remove(this.fNormals[i]);
}
this.fNormals.length = 0;
}
THREE.ColorCube.prototype.drawFaceNormals = function (scale, color) {
this.clearFaceNormals();
scale = (scale === undefined) ? 1 : scale;
color = (color === undefined) ? 0xffaa00 : color;
var origin = new THREE.Vector3(),
normalArrow = null,
vertices = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
normals = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
indices = [0, 0, 0],
centroid = new THREE.Vector3(),
faceNormal = new THREE.Vector3(),
vertexArray = this.geometry.attributes.position.array,
normalArray = this.geometry.attributes.normal.array,
indexArray = this.geometry.index.array;
for (var i = 0, len = indexArray.length; i < len; i += 3) {
indices = indexArray.slice(i, i + 3);
vertices[0].set(...vertexArray.slice((indices[0] * 3), (indices[0] * 3) + 3)).applyMatrix4(this.matrix);
vertices[1].set(...vertexArray.slice((indices[1] * 3), (indices[1] * 3) + 3)).applyMatrix4(this.matrix);
vertices[2].set(...vertexArray.slice((indices[2] * 3), (indices[2] * 3) + 3)).applyMatrix4(this.matrix);
normals[0].set(...normalArray.slice((indices[0] * 3), (indices[0] * 3) + 3));
normals[1].set(...normalArray.slice((indices[1] * 3), (indices[1] * 3) + 3));
normals[2].set(...normalArray.slice((indices[2] * 3), (indices[2] * 3) + 3));
centroid.set(
(vertices[0].x + vertices[1].x + vertices[2].x) / 3,
(vertices[0].y + vertices[1].y + vertices[2].y) / 3,
(vertices[0].z + vertices[1].z + vertices[2].z) / 3
);
faceNormal.set(
(normals[0].x + normals[1].x + normals[2].x) / 3,
(normals[0].y + normals[1].y + normals[2].y) / 3,
(normals[0].z + normals[1].z + normals[2].z) / 3
);
faceNormal.normalize();
normalArrow = new THREE.ArrowHelper(
faceNormal,
origin,
1 * scale,
color,
0.2 * scale,
0.1 * scale
);
normalArrow.position.copy(centroid);
this.fNormals.push(normalArrow);
this.parent.add(normalArrow);
}
};
THREE.ColorCube.prototype.clearAllNormals = function () {
THREE.ColorCube.prototype.clearVertexNormals();
THREE.ColorCube.prototype.clearFaceNormals();
}
THREE.ColorCube.prototype.drawWireframe = function (color) {
if (this.wireframe === undefined) {
color = (color === undefined) ? 0 : color;
this.wireframe = new THREE.WireframeHelper(this, color);
this.parent.add(this.wireframe);
}
}
THREE.ColorCube.prototype.clearWireframe = function () {
if (this.wireframe) {
this.parent.remove(this.wireframe);
delete this.wireframe;
}
}
})();
var cc = new THREE.ColorCube(25, 25, 25);
scene.add(cc);
cc.drawVertexNormals(25);
cc.drawFaceNormals(25);
cc.drawWireframe(0xffffff);
draw();
You are setting indices wrong. You have 1 index per vertex. However your code shows 3 index per vertex which does not make sense.
if you change
cubeGeometry.setIndex(new THREE.BufferAttribute(idx, 3));
to
cubeGeometry.setIndex(new THREE.BufferAttribute(idx, 1));
your problem is solved.
Here is the working jsfiddle

Resources