Sending color data to fragment shader in JavaScript

I've recently started learning webgl and have a query. I'm attempting to construct a triangle and send the color data to the fragment shader from a js file. Below is my js code:

var VSHADER_SOURCE = 
    'attribute vec4 a_Position;\n'+
    'attribute vec4 a_Color;\n'+
    'varying vec4 v_Color;\n'+
    'void main(){\n'+
        'gl_Position = a_Position;\n'+
        'v_Color = a_Color;\n'+
    '}\n';


var FSHADER_SOURCE = 
    'precision highp float;\n'+
    'varying vec4 v_Color;\n'+
    'void main() {\n'+
        'gl_FragColor = v_Color;\n'+
    '}\n';

function main(){
    var canvas = document.getElementById('webgl');
    var gl = getWebGLContext(canvas);
    if(!gl){
        console.log('Error!');
        return;
    }
    //Initialize shaders.
    if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)){
        console.log('Error!');
        return;
    }
    var vertices = new Float32Array([-0.8, -0.8, 0.8, -0.8, 0.0, 0.8]);
    var color = new Float32Array([0.0, 0.0, 1.0, 1.0]);
    var buffer_object = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer_object);
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(a_Position);

    var color_object = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, color_object);
    gl.bufferData(gl.ARRAY_BUFFER, color, gl.STATIC_DRAW);
    var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
    gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(a_Color);

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);


    return 0;
}

My intention was to create a blue triangle, but all I see is a canvas filled with black color. Can someone point out what's missing? I've created two buffer objects, one for vertex and the other for color.

Answer №1

There are several issues with the example provided, particularly concerning specific problems.

The colors are only specified for the first vertex.

Despite having 3 vertices, only 1 color is supplied, which should trigger an error. Have you checked the JavaScript Console for any errors?

Here are 3 options to address this:

  1. Assign a color for each vertex

    new Float32Array([
      0.0, 0.0, 1.0, 1.0,
      0.0, 0.0, 1.0, 1.0,
      0.0, 0.0, 1.0, 1.0,
    ]);
    
  2. Disable the a_Color attribute and set a constant value

    gl.disableVertexAtttibArray(a_Color);
    gl.vertexAttrib4f(a_Color, 0, 0, 1, 1);
    
  3. Utilize a uniform instead of an attribute + varying

    Remove all references to a_Color and v_color, and modify your fragment shader as follows:

    precision highp float;
    uniform vec4 u_Color;
    void main() {
      gl_FragColor = u_Color;
    }
    

    Now, you can set the color using:

    During Initialization

    // Lookup the location
    var u_colorLocation = gl.getUniformLocation(program, "u_Color");
    

    During Rendering

    // Set the uniform
    gl.uniform4f(u_colorLocation, 0, 0, 1, 1);
    

If you opt for #2, you may encounter another issue where you receive a warning that attribute 0 is not enabled because, at least on some systems, a_Color is linked to attribute 0. Disabling it may lead to emulation, resulting in reduced performance. To resolve this, ensure that a_Position is in attribute 0 by calling gl.bindAttribLocation prior to linking the program.

Additional concerns:

Your initShader function seems to create a program and attach it to the WebGLRenderContext (gl.program). Given that most WebGL projects involve multiple shader programs, it would be more advisable to simply return the program. In other words, instead of

initShader(...);
gl.getAttribLocation(gl.program, ...)

You may want to consider:

var program = initShader(...);
gl.getAttribLocation(program, ...)

You will need to update initShader to return the created program rather than attaching it to the WebGLRenderingContext.

Additionally, the use of precision highp float may not be compatible with all devices. Unless highp is specifically required, it is recommended to utilize mediump instead.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to access the image source attribute within a directive?

Here's a straightforward image directive example: (function () { 'use strict'; angular .module('myapp') .directive('imageTest', imageTest); function imageTest() { var directive = { ...

Is it possible to use a '.JS' file downloaded through Node Package Manager (npm) directly in a web browser?

Generally, I am looking to utilize a specific library without relying on Node CMD. For instance: I aim to create a TypeScript playground without having to execute 'tsc.cmd' from "npm\node_modules", instead, I want to directly call the tsc c ...

Set Sprite Canvas Material to match the color of a different element

Can someone please guide me on changing the color of the Sprite Canvas Material? var material = new THREE.SpriteCanvasMaterial( { color: 0xffffff, I am trying to make it match the color of another element based on a specific ID or class. However, I' ...

What is the best way to locate a user-provided string within word boundaries using JavaScript regex?

Employing JavaScript, I am currently searching a body of text. Users are given the option to input any string they desire, and then I aim to search for that specific string, ensuring it is considered a "whole word" located between boundaries. All I need i ...

Updating @Html.DisplayFor item following a successful ajax request

Attempting to update a value on my view, I seem to have the correct path, but the update only occurs when I reload the entire view. Here is the HTML: <table class="table"> <tr> <th> @Html.DisplayNameFor(model =&g ...

Why is the lower sub-component positioned above the rest of the page?

I have set up a sandbox environment to demonstrate an issue that I am facing. The main problem is that when I click on "Option 1" in the main menu, a new component appears where a bottom sub-component (named BottomControls.js) is displayed at the top of t ...

Does the organization of files and directories (such as modular programming) impact the speed at which AngularJS loads?

Can breaking code into smaller modules help decrease loading time? Exploring ways to modularize AngularJS applications can lead to a well-structured approach for developing large apps. This approach aims to streamline the development process by organizing ...

Uncovering the Mystery: Extracting a Video Thumbnail from Brightcove Videos

Is there a way to extract the video thumbnail from Brightcove Video? <x:out select="$item/description" escapeXml="false" /> At the moment, the thumbnail is being retrieved within the description. ...

Error in Charts API - [draw function failed to render for one or more participants]

Currently encountering an error on the client side where one or more participants failed to draw. I am able to successfully output data in the drawVisualization call, indicating that the issue lies within the JavaScript code. Despite following examples, I ...

Issue with jQuery DataTable: Unable to use column-level filters at the top and maintain a fixed height simultaneously

I am having an issue displaying data in a jQuery DataTable with a column level filter at the top, fixed height, and scroller enabled. Initially, I was able to display the column level filter at the top and it was functioning properly. However, when I set t ...

Tap on the div nested within another div

Here is the scenario I am dealing with: <div id="main"> <div id="a"></div> <div id="b"></div> </div> On my website, element B is positioned below element A. How can I attach a click event only to those A elements t ...

"Unable to get elements by tag name using the getElementsByTagName method in

function updateLayout() { var para = document.getElementsByTagName("p"); para[0].style.fontSize = 25; para[1].style.color = "red"; } <p>Text in paragraph 1</p> <p>Text in paragraph 2</p> <p>Text in paragraph 3</p& ...

Include the jquery library and embed a Google Map

Hello, I am using jQuery load to refresh my page every second. The problem arises when I add a Google Map to the page - the map appears and disappears every second. Is there a way to fix this issue? $(document).ready(function(){ <?php if( ...

What is the functionality of the remote data source in Jquery Mobile autocomplete feature?

Currently, I am browsing through this page and it appears that there is no clear documentation provided on the expected format or functionality of the remote data source. The example JavaScript code on the website references a remote data source at http:/ ...

The Mongoose framework captures and stores all input parameters from the request body

Currently in the process of setting up a small API, I am handling data validation on the client side of my application. As I go through this process, I am also organizing my data to align with my mongoose schema. My current attempt involves... router.rou ...

Utilize JavaScript to iterate through two sets of numbers

I am currently working on a project that requires me to iterate through two continuous number ranges: 1 to 5 and 10 to 15. This is the code I'm using: var X = []; for (i = 1; i < 6; i++) { X.push(i); } for (i = 10; i < 16; i++) { X.push(i ...

Allow AngularJS to make HTTP POST requests with CORS enabled

I am looking to submit a form to send an HTTP POST request to a server located on a different domain, with CORS enabled in the server script using Node.js. Below is the Angular configuration script: var myApp = angular.module('myApp', ['ng ...

What is the best way to access attributes from a div element?

I am currently working on extracting attributes from within a div tag, specifically the custom attributes of the first child element. I am using web scraping techniques with Node.js and Puppeteer. My goal is to retrieve the custom attributes data-ticker, d ...

Troubleshooting: Issues with HTML page not loading while running a JavaScript server

Currently, I am in the process of developing a game using a combination of HTML, CSS, and JavaScript. I'm exploring the integration of template engines and AJAX into the project. In order to achieve this, I have set up a server that, when executed in ...

What is the best way to change a JavaScript variable into a PHP variable?

I am interested in converting my JavaScript variable to a PHP variable... Currently, I have the following scenario - in the code below there is a variable e, but I would like to utilize e in PHP as $e: <script> function test() { var e = documen ...