这是threejs官方的一个例子webgl_interactive_voxelpainter.html 查看效果 查看效果
红色的正方体随着鼠标的移动而移动,单击时会创建另一个正方体,按住shift单击会删除点击的正方体。
主要用到的知识点
1、设置物体的位置为射线与物体相交的位置,并且把物体的位置设置到网格中心且高度全部在网格的上面
代码语言:javascript复制rollOverMesh.position.copy(intersect.point).add(intersect.face.normal)
rollOverMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25)
完整的代码:
代码语言:javascript复制<script src="../dist/js/three.js"></script>
<script src="../dist/js/WebGL.js"></script>
<script>
if (WEBGL.isWebGLAvailable() === false) {
document.body.appendChild(WEBGL.getWebGLErrorMessage());
}
var camera, scene, renderer;
var plane, cube;
var mouse, raycaster, isShiftDown = false;
var rollOverMesh, rollOverMaterial;
var cubeGeo, cubeMaterial;
var objects = [];
var width, height;
init();
render();
function init() {
var container = document.getElementById('canvasWrap')
width = document.getElementById('canvasWrap').clientWidth;
height = document.getElementById('canvasWrap').clientHeight;
camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
camera.position.set(150, 350, 1000); //position(0,300,1000) 中间的线会不显示
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0);
//roll-over helpers
var rollOverGeo = new THREE.BoxBufferGeometry(50, 50, 50);
rollOverMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.5, transparent: true })
rollOverMesh = new THREE.Mesh(rollOverGeo, rollOverMaterial);
rollOverMesh.position.set(0, 25, 0)
//console.log(rollOverMesh)
scene.add(rollOverMesh);
//cubes
cubeGeo = new THREE.BoxBufferGeometry(50, 50, 50);
cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xfeb74c, map: new THREE.TextureLoader().load("../dist/textures/square-outline-textured.png") });
var voxel = new THREE.Mesh(cubeGeo, cubeMaterial);
voxel.position.set(500, 500, 0)
console.log(voxel)
//grid
var gridHelper = new THREE.GridHelper(1000, 20, "red", "green");
//gridHelper.position.set(0,-50,0)
//console.log(gridHelper)
scene.add(gridHelper)
//raycaster
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
var geometry = new THREE.PlaneBufferGeometry(1000, 1000)
geometry.rotateX(-Math.PI / 2);
plane = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ visible: true }));
//plane.position.set(0,-50,0)
//console.log(plane)
scene.add(plane);
objects.push(plane);
// lights
var ambientLight = new THREE.AmbientLight(0x606060);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight(0xf3821e);
//向量坐标都除于向量的长度
//{1,2,3},长度是√1² 2² 3²=√14
//标准化之后是
//{1/√14,2/√14,3/√14}
//新向量的长度恰好为1
//directionalLight.position.set(1,0.75,0.5); //.normalize()好像不用也没看出啥区别
directionalLight.position.set(100, 300, 300) //.normalize(); //设置平行光方向,normalize()正则化,变为单位向量
scene.add(directionalLight);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
container.appendChild(renderer.domElement);
document.addEventListener("mousemove", onDocumentMouseMove, false);
document.addEventListener("mousedown", onDocumentMouseDown, false);
document.addEventListener("keydown", onDocumentKeyDown, false);
document.addEventListener("keyup", onDocumentKeyUp, false);
window.addEventListener("resize", onWindowResize, false);
}
function onWindowResize(event) {
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
}
function onDocumentMouseMove(event) {
event.preventDefault();
//转换坐标至(-1,1)范围
mouse.set((event.layerX / width) * 2 - 1, -(event.layerY / height) * 2 1);
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0) {
var intersect = intersects[0];
rollOverMesh.position.copy(intersect.point).add(intersect.face.normal)
rollOverMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25)
}
render();
}
function onDocumentMouseDown(event) {
event.preventDefault();
mouse.set((event.layerX / width) * 2 - 1, -(event.layerY / height) * 2 1);
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0) {
var intersect = intersects[0];
//delete cube
if (isShiftDown) {
if (intersect.object !== plane) {
scene.remove(intersect.object);
objects.splice(objects.indexOf(intersect.object), 1)
}
// create cube
} else {
var voxel = new THREE.Mesh(cubeGeo, cubeMaterial);
voxel.position.copy(intersect.point).add(intersect.face.normal);
//.divideScalar ( s : Float )将该向量除以标量S
//.multiplyScalar ( s : Float )将该向量与所传入的标量s进行相乘。
//.floor () 向量的分量向下取整为最接近的整数值。
//addScalar(s:Float)将传入的标量S和这个向量的X值、Y值以及Z值相加
//下面重新设置position的目的是移动的方块的中心在网格的中心,Y轴为25
voxel.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25);
scene.add(voxel);
objects.push(voxel)
}
render()
}
}
function onDocumentKeyDown(event) {
switch (event.keyCode) {
case 16:
isShiftDown = true;
break;
}
}
function onDocumentKeyUp(event) {
switch (event.keyCode) {
case 16:
isShiftDown = false;
break;
}
}
function render() {
renderer.render(scene, camera);
}
</script>
(adsbygoogle = window.adsbygoogle || []).push({});