Ive tried many different options but still can’t understand why the red plane is visible always while i want it to be visible through green planes only.
const renderer = new THREE.WebGLRenderer({
antialias: false,
precision: 'highp',
reverseDepthBuffer: false,
stencil: true,
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = 0xffffff;
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(-20, 20.5, 5);
const controls = new PointerLockControls(camera, renderer.domElement);
const floorSize = 100;
const floorGeometry = new THREE.PlaneGeometry(floorSize, floorSize);
const floorMaterial = new THREE.MeshStandardMaterial({
color: 0xff0000,
stencilWrite: true,
stencilFunc: THREE.NotEqualStencilFunc,
stencilZPass: THREE.KeepStencilOp,
stencilRef: 1,
});
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);
floor.renderOrder = 5;
const grassParams = {
count: 20,
width: 12.05,
height: { min: 12.0, max: 12.5 },
areaSize: floorSize - 10,
density: 0.1,
scaleVariation: 0.3,
color: 0x4a6b2a,
};
const grassGeometry = new THREE.PlaneGeometry(grassParams.width, 1);
const grassMaterial = new THREE.MeshStandardMaterial({
color: grassParams.color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.5,
stencilWrite: true,
stencilFunc: THREE.AlwaysStencilFunc,
stencilZPass: THREE.ReplaceStencilOp,
stencilRef: 1,
depthWrite: false,
});
const grassMesh = new THREE.InstancedMesh(
grassGeometry,
grassMaterial,
grassParams.count
);
grassMesh.castShadow = true;
grassMesh.receiveShadow = true;
scene.add(grassMesh);
grassMesh.renderOrder = 1;
const matrix = new THREE.Matrix4();
const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3();
for (let i = 0; i < grassParams.count; i++) {
const radius =
Math.pow(Math.random(), grassParams.density) * (grassParams.areaSize / 2);
const angle = Math.random() * Math.PI * 2;
position.x = radius * Math.cos(angle);
position.z = radius * Math.sin(angle);
position.y = 0;
const height = THREE.MathUtils.lerp(
grassParams.height.min,
grassParams.height.max,
Math.random()
);
const widthScale = 1 + (Math.random() - 0.5) * grassParams.scaleVariation;
const heightScale =
height * (1 + (Math.random() - 0.5) * grassParams.scaleVariation);
scale.set(widthScale, heightScale, 1);
quaternion.setFromEuler(
new THREE.Euler(
(Math.random() - 0.5) * 0.2,
Math.random() * Math.PI * 2,
0
)
);
position.y = height / 2;
matrix.compose(position, quaternion, scale);
grassMesh.setMatrixAt(i, matrix);
}
grassMesh.instanceMatrix.needsUpdate = true;
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
const moveSpeed = 0.075;
const moveState = {
forward: false,
backward: false,
left: false,
right: false,
up: false,
down: false,
};
document.addEventListener('click', () => controls.lock());
const keyMap = {
KeyW: 'forward',
KeyA: 'left',
KeyS: 'backward',
KeyD: 'right',
Space: 'up',
ShiftLeft: 'down',
};
document.addEventListener('keydown', e => (moveState[keyMap[e.code]] = true));
document.addEventListener('keyup', e => (moveState[keyMap[e.code]] = false));
function animate() {
requestAnimationFrame(animate);
if (controls.isLocked) {
if (moveState.forward) controls.moveForward(moveSpeed);
if (moveState.backward) controls.moveForward(-moveSpeed);
if (moveState.left) controls.moveRight(-moveSpeed);
if (moveState.right) controls.moveRight(moveSpeed);
if (moveState.up) camera.position.y += moveSpeed;
if (moveState.down) camera.position.y -= moveSpeed;
}
renderer.render(scene, camera);
}