I am running into a relative simple problem for days, and I didn't find any solving: I have a vtkRenderWindow where I spread up 4 renderers, but on runtime I hide 3 of them, so I could have 1 or 4 renderers at the time ...
On renderer 1 I intend to put a vtkSliderWidget ... to achieve that, I wrote:
vtkSliderRepresentation2D* pSliderRep = vtkSliderRepresentation2D::New();
......
......
pSliderRep->GetPoint1Coordinate()->SetCoordinateSystemToNormalizedViewport();
pSliderRep->GetPoint1Coordinate()->SetValue(0.1, 0.1);
pSliderRep->GetPoint2Coordinate()->SetCoordinateSystemToNormalizedViewport();
pSliderRep->GetPoint2Coordinate()->SetValue(0.9, 0.1);
m_pSlider->SetInteractor(m_pInteractor);
m_pSlider->SetRepresentation(pSliderRep);
where m_pSlider is a vtkSliderWidget object ...
the problem become where I have 4 renderers:
Renderer 1 Renderer 2
Renderer 3 Renderer 4
in this stage, the widget I found over renderer 3, not over renderer 1 where is belong ... why ?
Is there something that I am doing wrong ? I dig in for this issue for days !! Can you help me ?
Later edit:
I made a simple test using this test project:
int main(int, char *[])
{
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
vtkRenderer* renderer[4];
// Define viewport ranges
double xmins[4] = {0, .5, 0, .5};
double xmaxs[4] = {0.5, 1, 0.5, 1};
double ymins[4] = {0, 0, .5, .5};
double ymaxs[4] = {0.5, 0.5, 1, 1};
for(unsigned i = 0; i < 4; i++)
{
renderer[i] = vtkRenderer::New();
renderWindow->AddRenderer(renderer[i]);
CString sTemp;
sTemp.Format("%.1f, %.1f, %.1f, %.1f\n", xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
renderer[i]->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
// Create a sphere
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetCenter(0.0, 0.0, 0.0);
sphereSource->SetRadius(5);
sphereSource->Update();
// Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(sphereSource->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
renderer[i]->AddActor(actor);
renderer[i]->ResetCamera();
renderWindow->Render();
renderWindow->SetWindowName(_T("Multiple ViewPorts"));
}
vtkSliderRepresentation2D* pSliderRep = vtkSliderRepresentation2D::New();
pSliderRep->SetMinimumValue(3.0);
pSliderRep->SetMaximumValue(20.0);
pSliderRep->SetPlaceFactor(1);
pSliderRep->GetSliderProperty()->SetColor(0.65, 0.75, 0.90);
pSliderRep->GetTitleProperty()->SetColor(1, 0, 0);
pSliderRep->SetLabelFormat(_T("%.2g"));
pSliderRep->GetLabelProperty()->SetColor(1, 0, 0);
pSliderRep->GetSelectedProperty()->SetColor(0, 1, 0);
pSliderRep->GetTubeProperty()->SetColor(0.36, 0.5, 0.66);
pSliderRep->GetTubeProperty()->SetDisplayLocationToForeground();
pSliderRep->GetCapProperty()->SetColor(0.36, 0.5, 0.66);
pSliderRep->SetEndCapLength(0);
pSliderRep->SetEndCapWidth(0.025);
pSliderRep->SetSliderWidth(0.025);
pSliderRep->SetSliderLength(0.045);
pSliderRep->SetHandleSize(6);
pSliderRep->SetTubeWidth(0.032);
pSliderRep->GetPoint1Coordinate()->SetCoordinateSystemToNormalizedDisplay();
pSliderRep->GetPoint1Coordinate()->SetValue(0.01, 0.99);
pSliderRep->GetPoint2Coordinate()->SetCoordinateSystemToNormalizedDisplay();
pSliderRep->GetPoint2Coordinate()->SetValue(0.99, 0.99);
vtkSliderWidget* pSlider = vtkSliderWidget::New();
pSlider->SetInteractor(renderWindowInteractor);
pSlider->SetCurrentRenderer(renderer[0]);
pSlider->SetRepresentation(pSliderRep);
pSlider->EnabledOn();
pSlider->SetDefaultRenderer(renderer[0]);
pSlider->SetAnimationModeToAnimate();
renderWindowInteractor->Start();
pSliderRep->Delete();
pSlider->Delete();
for(unsigned i = 0; i < 4; i++)
renderer[i]->Delete();
return EXIT_SUCCESS;
}
But I see no slider ... what I have done wrong ?
[New data] In fact, the problem is reduced on setting up the slider on other renderer than renderer 0:
int main(int, char *[])
{
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
vtkRenderer* renderer[4];
// Define viewport ranges
double xmins[4] = {0, .5, 0, .5};
double xmaxs[4] = {0.5, 1, 0.5, 1};
double ymins[4] = {0, 0, .5, .5};
double ymaxs[4] = {0.5, 0.5, 1, 1};
for(unsigned i = 0; i < 4; i++)
{
renderer[i] = vtkRenderer::New();
renderWindow->AddRenderer(renderer[i]);
CString sTemp;
sTemp.Format("%.1f, %.1f, %.1f, %.1f\n", xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
renderer[i]->SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]);
// Create a sphere
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetCenter(0.0, 0.0, 0.0);
sphereSource->SetRadius(5);
sphereSource->Update();
// Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(sphereSource->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
renderer[i]->AddActor(actor);
renderer[i]->ResetCamera();
renderWindow->Render();
renderWindow->SetWindowName(_T("Multiple ViewPorts"));
}
vtkSliderRepresentation2D* pSliderRep = vtkSliderRepresentation2D::New();
pSliderRep->SetMinimumValue(3.0);
pSliderRep->SetMaximumValue(20.0);
pSliderRep->GetPoint1Coordinate()->SetCoordinateSystemToNormalizedViewport();
pSliderRep->GetPoint1Coordinate()->SetValue(0.1, 0.9);
pSliderRep->GetPoint2Coordinate()->SetCoordinateSystemToNormalizedViewport();
pSliderRep->GetPoint2Coordinate()->SetValue(0.9, 0.9);
vtkSliderWidget* pSlider = vtkSliderWidget::New();
pSlider->SetInteractor(renderWindowInteractor);
pSlider->SetCurrentRenderer(renderer[1]); // <-- not working !!!
pSlider->SetDefaultRenderer(renderer[1]); // <-- not working !!!
pSlider->SetAnimationModeToAnimate();
pSlider->SetRepresentation(pSliderRep);
pSlider->EnabledOn();
pSliderRep->Modified();
renderWindowInteractor->Start();
pSliderRep->Delete();
pSlider->Delete();
for(int i = 0; i < 4; i++)
renderer[i]->Delete();
return EXIT_SUCCESS;
}
the question is, how can I show the slider on renderer 1 (or 2, or 3), but on renderer 0 ?
Might be something simple ...
After applying the representation and all the stuff call CreateDefaultRepresentation() - this should change a lot.
pSlider->SetRepresentation(pSliderRep);
pSlider->EnabledOn();
pSlider->CreateDefaultRepresentation();
Related
Here is a line made up by two triangles in WebGL2: https://codepen.io/Candleout/pen/bGMYpNM
At least on my computer, the line looks a bit weird and is not as smooth as you would expect:
Antialiasing is turned on, and has some effect, but as you can see in the picture above the line is still not entirely smooth.
The code is based on this article, with the same shaders as in the first example: https://wwwtyro.net/2019/11/18/instanced-lines.html
As you can see, the lines looks smoother in that article, maybe because regl is doing something in the background?
Is there something wrong with and/or missing from my setup, that causes the problem?
I'm running WebGL on a Macbook Air from 2013.
// HTML:
<canvas id="canvas"></canvas>
// JS:
// Setup WebGL context
const canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gl = document.getElementById('canvas').getContext('webgl2', { antialias: true } );
// Shaders
const vertexShaderSrc = `
precision highp float;
attribute vec2 position, pointA, pointB;
uniform mat3 projection;
uniform float width;
void main() {
vec2 xBasis = pointB - pointA;
vec2 yBasis = normalize(vec2(-xBasis.y, xBasis.x));
vec2 point = pointA + xBasis * position.x + yBasis * width * position.y;
gl_Position = vec4(projection * vec3(point, 1), 1);
}`;
const fragmentShaderSrc = `
precision highp float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}`;
// Setup program with shaders
const program = gl.createProgram();
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
gl.attachShader(program, vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log(gl.getShaderInfoLog(vertexShader));
console.log(gl.getShaderInfoLog(fragmentShader));
}
gl.useProgram(program);
function main() {
const positionLoc = gl.getAttribLocation(program, 'position');
const pointALoc = gl.getAttribLocation(program, 'pointA');
const pointBLoc = gl.getAttribLocation(program, 'pointB');
const projectionLoc = gl.getUniformLocation(program, 'projection');
const widthLoc = gl.getUniformLocation(program, 'width');
// Line geometry:
const geometryData = new Float32Array([
// position
0.0, -0.5,
1.0, -0.5,
1.0, 0.5,
0.0, -0.5,
1.0, 0.5,
0.0, 0.5
]);
const geometryBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, geometryBuffer);
gl.bufferData(gl.ARRAY_BUFFER, geometryData, gl.STATIC_DRAW);
gl.vertexAttribPointer(
positionLoc, // attribute
2, // size
gl.FLOAT, // type
false, // normalize
8, // stride
0); // offset
gl.enableVertexAttribArray(positionLoc);
// End points:
const pointData = new Float32Array([
// pointA
6.123233995736766e-17,
1,
// pointB
-0.8660254037844387,
0.49999999999999994
]);
const pointsBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pointsBuffer);
gl.bufferData(gl.ARRAY_BUFFER, pointData, gl.STATIC_DRAW);
gl.vertexAttribPointer(
pointALoc, // attribute
2, // size
gl.FLOAT, // type
false, // normalize
16, // stride
0); // offset
gl.vertexAttribDivisor(pointALoc, 1);
gl.enableVertexAttribArray(pointALoc);
gl.vertexAttribPointer(
pointBLoc, // attribute
2, // size
gl.FLOAT, // type
false, // normalize
16, // stride
8); // offset
gl.vertexAttribDivisor(pointBLoc, 1);
gl.enableVertexAttribArray(pointBLoc);
// Projection matrix - for 90 degree angles
let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
gl.uniformMatrix3fv(projectionLoc, false, new Float32Array([
2 / (aspect - -aspect), 0, 0,
0, 1, 0,
0, 0, 1
])
)
gl.uniform1f(
widthLoc, // uniform
0.025) // thickness
gl.drawArraysInstanced(
gl.TRIANGLES, // method
0, // offset
6, // number of vertices per instance
1 // number of instances
);
}
main();
so I'm creating an interactive story, and I want to switch between scenes by clicking buttons (like a standard old pokemon game except there isn't movement, just clicking).
I should probably use a switch statement right? But I don't know how to implement the changing of scenes and loading scenes into the cases. I also don't know if I would need to use 'if' statements within the cases.
This might be confusing, because it is very confusing to me. I'd appreciate any help you guys offer! I am desperate ;)
Code so far is below:
//PImages
PImage startScreen;
PImage[] waves = new PImage[3];
PImage[] scenes = new PImage[1];
int switchVariable;
//Objects
Button play;
void setup() {
size(750, 600);
background(#A3E9EA);
//Initialising Objects
play = new Button(50, 480, 330);
//loading wave images
waves[0] = loadImage("wave1.png");
waves[1] = loadImage("wave2.png");
waves[2] = loadImage("wave3.png");
//loading start image
startScreen = loadImage("start-screen.png");
//loading scenes
scenes[0] = loadImage("scene-one.png");
//setting frame rate
frameRate(6);
}
void draw() {
background(#A3E9EA);
frameCount++;
println (frameCount);
//drawing wave animation
if (frameCount < 5) {
image(waves[0], 0, 0);
}
else {
image(waves[1], 0, 0);
}
if (frameCount < 15 & frameCount > 10) {
background(#A3E9EA);
image(waves[2], 0, 0);
frameCount = 0;
}
//drawing start screen
image(startScreen, 0, 0);
//displaying play button
if (play.visible) play.buttonDisplay();
}
void mousePressed() {
if (play.visible) {
float d = dist(play.x+110, play.y+22, mouseX, mouseY);
if (d <= play.radius){
background(#A3E9EA);
image(scenes[0], 0, 0);
}
}
}
Button Class:
class Button {
float radius;
float x;
float y;
PImage[] buttonImage = new PImage[2];
boolean visible;
Button(float _radius, float _x, float _y) {
radius = _radius;
visible = true;
x = _x;
y = _y;
buttonImage[0] = loadImage("play-game-button.png");
}
void buttonDisplay() {
image(buttonImage[0], x, y);
}
}
The source code below shows one possible approach to your question. It does not rely on ‘switch’ but instead uses a custom control with up and down buttons similar to a Java stepper. The stepper control value corresponds with images in the scenes array and the background() is set accordingly. A separate button class is required and code for this follows the demo.
color BLUE = color(64, 124, 188);
color LTGRAY = color(185, 180, 180);
color YELLOW = color(245, 250, 13);
color RED = color(255, 0, 0);
color BLACK = color(0, 0, 0);
color WHITE = color(255, 255, 255);
color GREEN = color(0, 255, 0);
color ORANGE = color(247, 168, 7);
PFont font;
PImage[] scenes = new PImage[6];
// **** Up/Down Buttons init, min, max values **** //
final int _initValue = 2;
final int _maxValue = 5;
final int _minValue = 0;
int stepperValue = 0;
Button _up;
Button _dwn;
Button _quit;
final int _displayX = 160;
final int _displayY = 30;
final int _displayW = 100;
final int _displayH = 24;
final int _txtSize = 18;
void stepperValueDisplay(int value) {
fill(WHITE); // background color
noStroke();
rect(_displayX, _displayY, _displayW, _displayH, 0);
fill(BLACK); // text color
textSize(_txtSize);
textAlign(CENTER);
String str = String.format("Scene %d", value);
text(str, _displayX, _displayY, _displayW, _displayH);
}
void scene_0(){
background(RED);
save("scene0.png");
}
void scene_1(){
background(GREEN);
save("scene1.png");
}
void scene_2(){
background(BLACK);
save("scene2.png");
}
void scene_3(){
background(YELLOW);
save("scene3.png");
}
void scene_4(){
background(LTGRAY);
save("scene4.png");
}
void scene_5(){
background(ORANGE);
save("scene5.png");
}
void setup() {
size(600, 600);
background(BLUE);
font = createFont("Menlo-Bold", 20);
_dwn = new Button( _displayX - 40, _displayY, 40, 24, "--", LTGRAY, BLACK);
_up = new Button( _displayX + _displayW, _displayY, 40, 24, "++", LTGRAY, BLACK);
stepperValue = _initValue;
_quit = new Button(width - 60, 20, 30, 24, "Q", LTGRAY, BLACK);
scene_0();
scene_1();
scene_2();
scene_3();
scene_4();
scene_5();
scenes[0] = loadImage("scene0.png");
scenes[1] = loadImage("scene1.png");
scenes[2] = loadImage("scene2.png");
scenes[3] = loadImage("scene3.png");
scenes[4] = loadImage("scene4.png");
scenes[5] = loadImage("scene5.png");
}
void draw() {
background(scenes[stepperValue]);
_up.display();
_dwn.display();
_quit.display();
stepperValueDisplay(stepperValue);
}
void mousePressed() {
if (mouseX > _quit.x && mouseX < _quit.x + _quit.w && mouseY > _quit.y && mouseY < _quit.y + _quit.h) {
exit();
}
if (mouseX > _up.x && mouseX < _up.x + _up.w && mouseY > _up.y && mouseY < _up.y + _up.h) {
stepperValue++;
if (stepperValue > _maxValue) {
stepperValue = _maxValue;
}
stepperValueDisplay(stepperValue);
}
if (mouseX > _dwn.x && mouseX < _dwn.x + _dwn.w && mouseY > _dwn.y && mouseY < _dwn.y + _dwn.h) {
stepperValue--;
if (stepperValue < _minValue) {
stepperValue = _minValue;
}
stepperValueDisplay(stepperValue);
}
}
Button Class:
int _btnTxtSize = 18;
class Button {
float x, y, w, h;
String title;
color bkgrndColor;
color txtColor;
// Constructor
Button(int xpos, int ypos, float wt, float ht, String titleStr, color background, color textColor) {
x = xpos;
y = ypos;
w = wt;
h = ht;
title = titleStr;
bkgrndColor = background;
txtColor = textColor;
}
void display(){
fill(bkgrndColor);
noStroke();
rect( x, y, w, h, 0);
fill(txtColor);
textSize(_btnTxtSize);
textAlign(CENTER);
text(title, x, y, w, h);
}
}
Hi guys I been leanring WebGL and trying to make a Tetris game out of it.
I have a couple of questions I'd like to ask:
For this game I wanted to first draw the grid as the background. However I noticed that after I drew the line, if I use gl.clear(gl.COLOR_BUFFER_BIT ); after, it will clear all the lines I drew before. I understand that gl.clear(gl.COLOR_BUFFER_BIT ); is about clearing the color buffer (and you probably will ask why I would want to do that. Just bear with me. ). Then I tried use gl.uniform4f( uColor, 0, 0, 0, 1); to send the color again to the fragment shader but it doesn't help.
The snippet is like this
window.onload = function(){
getGLContext();
initShaders();
drawLines( 0, 0, 400,400 );
gl.clear(gl.COLOR_BUFFER_BIT );
gl.uniform4f( uColor, 0, 0, 0, 1);
}
For the game I need the grid as background and I need requestAnimationFrame for the game loop and will render Tetrominos inside the loop. Therefore after drawing the line I used this draw() to draw other Tetrominos. However it removes the line I drew before. And when I comment out gl.clear(gl.COLOR_BUFFER_BIT ); inside draw(), it will remove the line along with background color.
function draw() {
gl.clear(gl.COLOR_BUFFER_BIT );
gl.drawArrays(gl.TRIANGLES, 0, index*6);
requestAnimationFrame(draw);
}
Here is the demo: https://codepen.io/zhenghaohe/pen/LqxpjB
Hope you could answer these two questions. Thanks!
This is generally the way WebGL works.
WebGL is just draws into a rectangle of pixels. There is no memory of primitives. There is no structure. There is just code and the resulting canvas which is an rectangle of pixels.
Most WebGL programs/pages clear the entire canvas every frame and redraw 100% of the things they want to show every time they draw. For tetris the general code might be something like
function render() {
clear the canvas
draw the grid
draw all the stable pieces
draw the current piece
draw the next piece
draw the effects
draw the score
}
Any knowledge of primitives or other structure is entirely up to your code.
If you want the grid lines to be static then either set a static background with CSS or use another canvas
Using a background:
const gl = document.querySelector('#c').getContext('webgl');
function render(time) {
time *= 0.001;
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
drawBlocks(gl, time);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
// --- below this line not important to the answer
function drawBlocks(gl, time) {
gl.enable(gl.SCISSOR_TEST);
const numBlocks = 5;
for (let i = 0; i < numBlocks; ++i) {
const u = i / numBlocks;
gl.clearColor(i / 5, i / 2 % 1, i / 3 % 1, 1);
const x = 150 + Math.sin(time + u * Math.PI * 2) * 130;
const y = 75 + Math.cos(time + u * Math.PI * 2) * 55;
gl.scissor(x, y, 20, 20);
gl.clear(gl.COLOR_BUFFER_BIT);
}
gl.disable(gl.SCISSOR_TEST);
}
#c {
background-image: url(https://i.imgur.com/ZCfccZh.png);
}
<canvas id="c"></canvas>
Using 2 canvases
// this is the context for the back canvas. It could also be webgl
// using a 2D context just to make the sample simpler
const ctx = document.querySelector('#back').getContext('2d');
drawGrid(ctx);
// this is the context for the front canvas
const gl = document.querySelector('#front').getContext('webgl');
function render(time) {
time *= 0.001;
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
drawBlocks(gl, time);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
// --- below this line not important to the answer
function drawBlocks(gl, time) {
gl.enable(gl.SCISSOR_TEST);
const numBlocks = 5;
for (let i = 0; i < numBlocks; ++i) {
const u = i / numBlocks;
gl.clearColor(i / 5, i / 2 % 1, i / 3 % 1, 1);
const x = 150 + Math.sin(time + u * Math.PI * 2) * 130;
const y = 75 + Math.cos(time + u * Math.PI * 2) * 55;
gl.scissor(x, y, 20, 20);
gl.clear(gl.COLOR_BUFFER_BIT);
}
gl.disable(gl.SCISSOR_TEST);
}
function drawGrid(ctx) {
// draw grid
ctx.translate(-10.5, -5.5);
ctx.beginPath();
for (let i = 0; i < 330; i += 20) {
ctx.moveTo(0, i);
ctx.lineTo(330, i);
ctx.moveTo(i, 0);
ctx.lineTo(i, 300);
}
ctx.strokeStyle = "blue";
ctx.stroke();
}
#container {
position: relative; /* required so we can position child elements */
}
#front {
position: absolute;
left: 0;
top: 0;
}
<div id="container">
<canvas id="back"></canvas>
<canvas id="front"></canvas>
</div>
As for why it clears even if you didn't call clear that's because that's whqt the spec says it's supposed to do
See: Why WebGL 'clear' draw to front buffer?
So I am trying to create circles using the midpoint algorithm. I'm having trouble on how to handle buffers and basically get WebGL properly set up. Using the console I can see that the algorithm is working fine and making the vertex arrray, but I need help understanding what to do with the use.Program, createBuffers, drawArrays. Where should I place them?
Also, should I concat the circle everytime I call it in the START() function?
like: circle(blah blah).concat(circle(blah blah));
var vertexShaderText =
[
'precision mediump float;',
'',
'attribute vec2 vertPosition;',
'attribute vec3 vertColor;',
'varying vec3 fragColor;',
'',
'void main()',
'{',
' fragColor = vertColor;',
' gl_Position = vec4(vertPosition, 0.0, 1.0);',
'}'
].join('\n');
var fragmentShaderText =
[
'precision mediump float;',
'',
'varying vec3 fragColor;',
'void main()',
'{',
' gl_FragColor = vec4(fragColor, 1.0);',
'}'
].join('\n');
var START = function () {
console.log('This is working');
var canvas = document.getElementById('sky');
var gl = canvas.getContext('webgl');
if (!gl) {
console.log('WebGL not supported, falling back on experimental-webgl');
gl = canvas.getContext('experimental-webgl');
}
if (!gl) {
alert('Your browser does not support WebGL');
}
gl.clearColor(.3, .3, .7, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Create shaders
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader =
gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, vertexShaderText);
gl.shaderSource(fragmentShader, fragmentShaderText);
//create a program for the shaders
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
var circle = function (xmid, ymid, r) {
var points = [];
var x = 0;
var y = r;
var pk = 5/4 - r;
while (x < y)
{
if (pk < 0)
{
x++;
pk += 2*x + 1;
}
else
{
x++;
y--;
pk += 2 * (x-y) + 1;
}
points.push(x+xmid, y+ymid);
points.push(x+xmid, -y+ymid);
points.push(-x+xmid, y+ymid);
points.push(-x+xmid, -y+ymid);
points.push(y+xmid, x+ymid);
points.push(y+xmid, -x+ymid);
points.push(-y+xmid, x+ymid);
points.push(-y+xmid, -x+ymid);
}
var cbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cbuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points),
gl.STATIC_DRAW);
gl.drawArrays(gl.POINTS, 0, points.length/2);
var positionAttribLocation = gl.getAttribLocation(program,
'vertPosition');
var colorAttribLocation = gl.getAttribLocation(program,
'vertColor');
gl.vertexAttribPointer(
positionAttribLocation, // Attribute location
2, // Number of elements per attribute
gl.FLOAT, // Type of elements
gl.FALSE,
5 * Float32Array.BYTES_PER_ELEMENT, // Size of an individual vertex
0 // Offset from the beginning of a single vertex to this attribute
);
gl.enableVertexAttribArray(positionAttribLocation);
gl.enableVertexAttribArray(colorAttribLocation);
return points;
}
circle(0.6, 0.6, 0.18);
circle(0.9, 0.6, 0.18);
circle(0.5, 0.4, 0.18);
circle(1.0, 0.4, 0.18);
circle(0.75, 0.4, 0.18);
circle(0.75, 0.4, 0.18);
}
START();
<canvas id="sky"></canvas>
This is what my console log is saying:
6WebGL: INVALID_OPERATION: useProgram: program not
valid
6WebGL: INVALID_OPERATION: drawArrays: no valid shader
program in use
12WebGL: INVALID_OPERATION: getAttribLocation: program
not linked
You can clearly see that I am linking and using the program at the very beginning. So what gives?
There's more than one issue with the code
The shaders are not compiled
After setting the shader source with gl.shaderSource you need
to compile them with gl.compileShader. You should also
be checking for errors by calling gl.getShaderParameter(shader, gl.COMPILE_STATUS)
and you should be checking for errors after linking by calling
gl.getProgramParameter(program, gl.LINK_STATUS)
gl.drawArrays is called before setting the attributes
The code is enabling 2 attributes but only supplying data for 1 attribute.
The code is drawing gl.POINTS but the vertex shader is not setting gl_PointSize
I also don't really understand your circle code but since I don't know what it's really trying to do I can't fix it.
And finally you should probably read some tutorials on WebGL
I'd also suggest you use multiline template literals for your shaders
const vertexShaderText = `
precision mediump float;
attribute vec2 vertPosition;
attribute vec3 vertColor;
varying vec3 fragColor;
void main()
{
fragColor = vertColor;
gl_Position = vec4(vertPosition, 0.0, 1.0);
gl_PointSize = 5.;
}
`;
const fragmentShaderText = `
precision mediump float;
varying vec3 fragColor;
void main()
{
gl_FragColor = vec4(fragColor, 1.0);
}
`;
const start = function () {
console.log('This is working');
const canvas = document.getElementById('sky');
const gl = canvas.getContext('webgl');
if (!gl) {
alert('Your browser does not support WebGL');
return;
}
gl.clearColor(.3, .3, .7, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//create a shader program
const program = createProgram(gl, vertexShaderText, fragmentShaderText);
gl.useProgram(program);
const circle = function (xmid, ymid, r) {
const points = [];
let x = 0;
let y = r;
let pk = 5/4 - r;
while (x < y)
{
if (pk < 0)
{
x++;
pk += 2*x + 1;
}
else
{
x++;
y--;
pk += 2 * (x-y) + 1;
}
points.push(x+xmid, y+ymid);
points.push(x+xmid, -y+ymid);
points.push(-x+xmid, y+ymid);
points.push(-x+xmid, -y+ymid);
points.push(y+xmid, x+ymid);
points.push(y+xmid, -x+ymid);
points.push(-y+xmid, x+ymid);
points.push(-y+xmid, -x+ymid);
}
const cbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cbuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW);
const positionAttribLocation = gl.getAttribLocation(program, 'vertPosition');
const colorAttribLocation = gl.getAttribLocation(program, 'vertColor');
gl.vertexAttribPointer(
positionAttribLocation, // Attribute location
2, // Number of elements per attribute
gl.FLOAT, // Type of elements
gl.FALSE,
0, // Size of an individual vertex
0 // Offset from the beginning of a single vertex to this attribute
);
gl.enableVertexAttribArray(positionAttribLocation);
// you probably meant to supply colors for this attribute
// since if you wanted a constant color you'd have probably
// used a uniform but since you didn't we'll set a constant
// color
gl.vertexAttrib4f(colorAttribLocation, 1, 0, 0, 1);
gl.drawArrays(gl.POINTS, 0, points.length/2);
return points;
}
circle(0.6, 0.6, 0.18);
circle(0.9, 0.6, 0.18);
circle(0.5, 0.4, 0.18);
circle(1.0, 0.4, 0.18);
circle(0.75, 0.4, 0.18);
circle(0.75, 0.4, 0.18);
}
function createProgram(gl, vertexShaderText, fragmentShaderText) {
// Create shaders
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderText);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderText);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
start();
<canvas id="sky"></canvas>
Everyone. I have shown below my code for tracking objects and it shows background subtraction result also. Here I am using frame differencing method. now my problem is that I have to extract that moving object from the color video file. I have done segmentation. But for detection I want to extract the region on which I have drawn bounding box. So can anybody help me in this...please. thank you in advance.
int main(int argc, char* argv[])
{
CvSize imgSize;
//CvCapture *capture = cvCaptureFromFile("S:\\offline object detection database\\video1.avi");
CvCapture *capture = cvCaptureFromFile("S:\\offline object detection database\\SINGLE PERSON Database\\Walk1.avi");
if(!capture){
printf("Capture failure\n");
return -1;
}
IplImage* frame=0;
frame = cvQueryFrame(capture);
if(!frame)
return -1;
imgSize = cvGetSize(frame);
IplImage* greyImage = cvCreateImage( imgSize, IPL_DEPTH_8U, 1);
IplImage* colourImage;
IplImage* movingAverage = cvCreateImage( imgSize, IPL_DEPTH_32F, 3);
IplImage* difference;
IplImage* temp;
IplImage* motionHistory = cvCreateImage( imgSize, IPL_DEPTH_8U, 3);
CvRect bndRect = cvRect(0,0,0,0);
CvPoint pt1, pt2;
CvFont font;
int prevX = 0;
int numPeople = 0;
char wow[65];
int avgX = 0;
bool first = true;
int closestToLeft = 0;
int closestToRight = 320;
for(;;)
{
colourImage = cvQueryFrame(capture);
if( !colourImage )
{
break;
}
if(first)
{
difference = cvCloneImage(colourImage);
temp = cvCloneImage(colourImage);
cvConvertScale(colourImage, movingAverage, 1.0, 0.0);
first = false;
}
else
{
cvRunningAvg(colourImage, movingAverage, 0.020, NULL);
}
cvConvertScale(movingAverage,temp, 1.0, 0.0);
cvAbsDiff(colourImage,temp,difference);
cvCvtColor(difference,greyImage,CV_RGB2GRAY);
cvThreshold(greyImage, greyImage, 80, 250, CV_THRESH_BINARY);
cvSmooth(greyImage, greyImage,2);
cvDilate(greyImage, greyImage, 0, 1);
cvErode(greyImage, greyImage, 0, 1);
cvShowImage("back", greyImage);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contour = 0;
cvFindContours( greyImage, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
for( ; contour != 0; contour = contour->h_next )
{
bndRect = cvBoundingRect(contour, 0);
pt1.x = bndRect.x;
pt1.y = bndRect.y;
pt2.x = bndRect.x + bndRect.width;
pt2.y = bndRect.y + bndRect.height;
avgX = (pt1.x + pt2.x) / 2;
if(avgX > 90 && avgX < 250)
{
if(closestToLeft >= 88 && closestToLeft <= 90)
{
if(avgX > prevX)
{
numPeople++;
closestToLeft = 0;
}
}
else if(closestToRight >= 250 && closestToRight <= 252)
{
if(avgX < prevX)
{
numPeople++;
closestToRight = 220;
}
}
cvRectangle(colourImage, pt1, pt2, CV_RGB(255,0,0), 1);
}
if(avgX > closestToLeft && avgX <= 90)
{
closestToLeft = avgX;
}
if(avgX < closestToRight && avgX >= 250)
{
closestToRight = avgX;
}
prevX = avgX;
}
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.8, 0.8, 0, 2);
cvPutText(colourImage, _itoa(numPeople, wow, 10), cvPoint(60, 200), &font, cvScalar(0, 0, 300));
cvShowImage("My Window", colourImage);
cvShowImage("fore", greyImage);
cvWaitKey(10);
}
cvReleaseImage(&temp);
cvReleaseImage(&difference);
cvReleaseImage(&greyImage);
cvReleaseImage(&movingAverage);
cvDestroyWindow("My Window");
cvReleaseCapture(&capture);
return 0;
}
In OpenCV's legacy C API, you can extract a region of interest from an image with this command. In your code you would simply add this line, and the image would be treated as if it contained only the extracted region, pretty much:
cvSetImageROI(colourImage, bndrect);
In the OpenCV 2.0 API, your old image and "extracted region" image would be stored in separate Mat objects, but point to the same data:
Mat colourImage, extractedregion;
colourImage = imread("test.bmp");
extractedregion = colourImage(bndRect); // Creates only a header, no new image data
Many helpful OpenCV tutorials use the legacy API, but you should privilege the new one.
I know how to do it with the new OpenCV interface, rather than the "legacy" interface you are using.
It would be like this:
cv::Mat frame_m(frame);
...
cv::Mat region_m = frame_m(cv::Rect(bndRect));
IplImage region = region_m; // use &iplimg when an IplImage* is needed.
If you don't want to mix interfaces, it is time to learn the new one.