Home Game Development 3d – Shade a box different colors for two ends with one material in Three.js

3d – Shade a box different colors for two ends with one material in Three.js

0
3d – Shade a box different colors for two ends with one material in Three.js

[ad_1]

First, I knew the following basic knowledges,

Then, I can use shader to render 2D graphics on the Shadertoy or GLSL Sandbox Gallery cross-browser online editor through WebGL or with the cross-platform SHADERed IDE. It’s easy to use GLSL to draw 2D objects because 2D coordinates correspond to gl_Position. But I failed to use ShaderMaterial with the GLSL code to render a BoxGeometry I created in three.js. See the following code for my case.

/** @type {HTMLElement} */ var container;
var camera, scene, renderer;
/** @type {THREE.Mesh} */ var mesh;
var uniforms;
/** @type {THREE.TrackballControls} */ var controls;
/** @type {THREE.LineSegments} */ var wireframe;

var clock = new THREE.Clock();

try {
    init();
    animate();
} catch (err) {
    alert(err);
}
function init() {
    container = document.getElementById('container');

    camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 3000);
    camera.position.z = 2.0;
    camera.position.y = 1.0;
    camera.rotation.x = -0.45;

    scene = new THREE.Scene();

    //var boxGeometry = new THREE.PlaneGeometry(0.75, 0.75, 1);
    var boxGeometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);

    uniforms = { u_time: { type: "f", value: 0.0 } };

    var material = new THREE.ShaderMaterial({
        uniforms: uniforms,
        side: THREE.DoubleSide,
        transparent: true,
        vertexShader: document.getElementById('vertexShader').textContent,
        fragmentShader: document.getElementById('fragmentShader').textContent
    });

    mesh = new THREE.Mesh(boxGeometry, material);

    var geo, lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });
    // lineMaterial.depthTest = false;
    // lineMaterial.polygonOffset = true;
    // lineMaterial.depthTest = true;
    // lineMaterial.polygonOffsetFactor = -2;
    // lineMaterial.polygonOffsetUnits = 0.1;
    if (0) {
        geo = new THREE.EdgesGeometry(mesh.geometry);
    } else {
        geo = new THREE.WireframeGeometry(boxGeometry);
    }
    wireframe = new THREE.LineSegments(geo, lineMaterial);
    mesh.add(wireframe); // wireframe.material === lineMaterial

    scene.add(mesh);

    var axesHelper = new THREE.AxesHelper();
    mesh.add(axesHelper);

    renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0xffffff, 1);
    container.appendChild(renderer.domElement);

    onWindowResize();

    window.addEventListener('resize', onWindowResize, false);

    initControls();
    initDatGui();
}

function onWindowResize(event) {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    // requestAnimationFrame(animate);
    try {
        render();
    } catch (err) {
        if (confirm("An error occured:\n" + err.message)) {
            return;
        }
    }
    requestAnimationFrame(animate);
}

function render() {
    if (controls) controls.update();
    var delta = clock.getDelta();
    uniforms.u_time.value += delta;
    mesh.rotation.y += delta * 0.5;
    renderer.render(scene, camera);
}

function initControls() {
    if (!THREE.TrackballControls) return

    controls = new THREE.TrackballControls(camera, renderer.domElement);

    // controls.enabled = true; // default is true
    // controls.target = new THREE.Vector3(); // default is new Vector3()

    // controls.rotateSpeed = 3.0; // default is 1.0
    // controls.zoomSpeed = 1.2; // default is 1.2
    // controls.panSpeed = 0.3; // default is 0.3

    // controls.noRotate = false; // default is false
    // controls.noZoom = false; // default is false
    // controls.noPan = false; // default is false

    // controls.staticMoving = false; // default is false
    // controls.dynamicDampingFactor = 0.2; // default is 0.2

    // controls.minDistance = 0;
    // controls.maxDistance = Infinity;
}

function initDatGui() {
    if ('object' !== typeof dat && !dat.GUI) return;
    var datGui = new dat.GUI({ closed: true }); // panel is collapsed 
    if (controls) {
        datGui.add(controls, "enabled").name("Enable").onChange(change);
        datGui.add(controls, "rotateSpeed", 1.0, 10.0).onChange(change);
        datGui.add(controls, "zoomSpeed", 1.0, 5).onChange(change);
        datGui.add(controls, "panSpeed", 0.1, 1.0).onChange(change);
        datGui.add(controls, "noRotate").name("Rotate").onChange(change);
        datGui.add(controls, "noZoom").name("Zoom").onChange(change);
        datGui.add(controls, "noPan").name("Pan").onChange(change);
        datGui.add(controls, "staticMoving").name("Static Moving").onChange(change);
        datGui.add(controls, "dynamicDampingFactor", 0.1, 1.0).name("Dynamic Damping Factor").onChange(change);
        datGui.add(controls, "minDistance", 0, 5).name("MinDistance").onChange(change);
        datGui.add(controls, "maxDistance", 5, 10).name("MaxDistance").onChange(change);
        datGui.add(controls, "reset").name("Reset").onChange(function resetTrackballControls() {
            this.object.reset();
        });
    }

    // var gui = { widthSegments: 1 }
    datGui.add(mesh.geometry.parameters, "widthSegments", 1, 66, 1).name("Width Segments").onChange(function updateGeometrySegments(newValue) {
        wireframe.geometry = mesh.geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5, newValue);
    });
    datGui.add(wireframe, "visible").name("Show Wireframe");

    function change(newValue) {
        this.object[this.property] = newValue;
    }
}
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="description" content="WebGL Shader in Three.js">
<title>Shader</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
a { color: #08f; }
b { color: lightgreen; }
html, body, .bespread { margin:0; padding:0; width:100%; height:100%; }
canvas { border: 1px dotted salmon; }
#info { position:absolute; bottom:0; }
</style>
</head>

<body>
<script>
window.onerror = function (msg, url, line, col, error) {
    // Note that col & error are new to the HTML 5 spec and may not be 
    // supported in every browser.  It worked for me in Chrome.
    var extra = !col ? '' : '\ncolumn: ' + col;
    extra += !error ? '' : '\nerror: ' + error;

    // You can view the information in an alert to see things working like this:
    alert("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);

    // TODO: Report this error via ajax so you can keep track of what pages have JS issues

    var suppressErrorAlert = true;
    // If you return true, then error alerts (like in older versions of 
    // Internet Explorer) will be suppressed.
    return suppressErrorAlert;
};
</script>

<script id="fragmentShader" type="x-shader/x-fragment">
varying vec3 v_color;

void main( void ) {
    gl_FragColor = vec4(v_color, 1.);    
}
</script>
<script id="vertexShader" type="x-shader/x-vertex">
varying vec3 v_color;

void main()
{
    v_color = vec3(position.x < 0., 0, position.x >= 0.);
    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
    gl_Position = projectionMatrix * mvPosition;
}
</script>

    <div id="container"></div>
    <div id="info">
        <a href="https://threejs.org/examples/#webgl_postprocessing_outline">WebGL Postprocessing Outline</a>
        <br>
        <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a>- Outline Pass by
        <a href="http://eduperiment.com" target="_blank" rel="noopener">Prashant Sharma</a>
        and <a href="https://clara.io" target="_blank" rel="noopener">Ben Houston</a>
    </div>
</body>
<!-- <script src="https://threejs.org/build/three.min.js"></script> -->
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r121/three.min.js"></script> -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/three@0.130.1/examples/js/controls/TrackballControls.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/build/dat.gui.min.js"></script>
<!-- <script type="module" src="https://gamedev.stackexchange.com/questions/194804/index.js"></script> -->
</html>

I guessed that it was because it could distinguish between vertexes in the same middle position of the +x sides and -x sides for v_color = vec3(position.x < 0.25, 0, position.x >= 0.25);.

Finally, I also knew that I can Split the geometry into groups with different materials, but I just want to use one ShaderMaterial to do this.


var geo = new THREE.BoxGeometry(48, 48, 48, 2);
var magnetMaterial = ['red', 'blue', 'green', 'purple', 'cyan', 'white', 'black', 'pink', 'orange', 'gray'].map(it =>
    new THREE.MeshPhongMaterial({
        color: it, side: THREE.DoubleSide,
        polygonOffset: true, polygonOffsetFactor: 1
    }));

//Initializes the magnetic orientation to +x, red on the left side and blue on the right side.
//faces[].materialIndex: -x,-x, +x,+x, +z,+z,+z,+z, -y,-y,-y,-y, -z,-z,-z,-z, +y,+y,+y,+y
// var faceColors = [1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0];
// console.log('faceColors', geo.faces.map((it, idx) => it.materialIndex = faceColors[idx])); // for Three.js 1.20

// let's regroup materialIndex of five faces of the two ends of the Cuboid (x+,x-,y+,y-,z+,z-)
console.log(geo.getIndex().count, geo.groups.slice(0));
geo.clearGroups();
[0, 1, 1, 0, 1, 0, 1, 0, 0, 1].forEach((val, idx) => geo.addGroup(6 * idx, 6, val));

Anyone could help me to explain and solve this problem because the gradient is not what I want?

[ad_2]

Previous article Anarchy spec — Sirlin.Net — Game Design
Next article Nintendo reveals its Black Friday deals and holiday Switch bundles
Hello there! My name is YoleeTeam, and I am thrilled to welcome you to AmazonianGames.com. As the premier destination for all things related to Amazon Games' universe, we are dedicated to providing you with the most exciting and immersive gaming experiences out there. From captivating visuals to exhilarating gameplay, our website is packed with comprehensive insights, updates, and reviews to keep you ahead of the game. Whether you're a seasoned gamer or new to the scene, I am here to guide you through this virtual frontier. If you have any questions or suggestions, feel free to reach out to me at john@yoleesolutions.com. Embark on your Amazon gaming journey today with AmazonianGames.com and let the adventure begin!