我有一个问题,我有一个着色器在网格的几何边缘周围绘制白色边框(从@prisoner849 借用和修改,在这里参考他的 jsfiddle(https://jsfiddle.net/prisoner849/kmau6591/ )).
我让它使用一种类型的几何体 (
BoxGeometry
) 但不是 BufferGeometry
这是我希望它处理的,因为我需要对顶点进行自定义操作。我创建了一个 JSFiddle 来演示您可以在哪里看到着色器在通过(new BoxGeometry
)创建的盒子上工作,另一个是使用 BufferGeometry
创建并手动设置属性。
我怀疑我一定没有正确设置属性,但我不确定该怎么做,因为我找不到任何关于如何正确设置
BufferGeometry
的信息。
下面附上我的 JSFiddle 演示这个问题。
https://jsfiddle.net/gentleman_goat66/o5wn3bpf/135/
感兴趣的代码行如下:
工作箱代码:
const geometryBox = new THREE.BoxGeometry();
const sample_box = new THREE.Mesh(geometryBox, shader_material);
sample_box.scale.y = 3;
this.heatmap.add(sample_box);
我的自定义邮箱代码(不工作!)
const geometry = new THREE.BufferGeometry();
const vertices = [
-2, 0, 1,//0, floor, bottom left
-1, 0, 1,//1, floor, bottom right
-1, 0, -1,//2, floor, top right
-2, 0, -1,//3 floor, top left
-2, 3, 1,//4 roof, bottom left
-1, 3, 1,//5 roof, bottom right
-1, 3, -1,//6 roof, top right
-2, 3, -1//7 roof, top left
];
const indices = [
0, 1, 2,//floor, first triangle
2, 3, 0,//floor, second triangle
4, 5, 6,//roof, first triangle
6, 7, 4,//roof, second triangle
3, 0, 4,//west wall, first triangle
3, 4, 7,//west wall, second triangle
0, 1, 5,//south wall, first triangle
0, 5, 4,//south wall, first triangle
1, 2, 6,//east wall, first triangle
1, 6, 5,//east wall, second triangle
2, 3, 7,//north wall, first triangle
2, 7, 6,//north wall, second triangle
];
const colors = [
2,0,0, // bottom left
0,2,0, // bottom right
0,2,0, // top right
2,0,0, // top left
2,0,0, // bottom left
0,2,0, // bottom right
0,2,0, // top right
2,0,0 // top left
];
geometry.setIndex(indices);
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
geometry.computeVertexNormals();
const material = new THREE.MeshStandardMaterial({side:THREE.FrontSide,vertexColors:true,color: 0xFFFFFF });
var shader_material = new THREE.ShaderMaterial( {
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
uniforms: {
thickness: {
value: 1.5
}
}
});
const sample_rectangle = new THREE.Mesh(geometry, shader_material);
this.heatmap.add(sample_rectangle);
HTML
<script type="importmap">
{
"imports":
{
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"OrbitControls": "https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js"
}
}
</script>
<script id="vertexShader" type="x-shader/x-vertex">
#include <common>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <shadowmap_pars_vertex>
#include <specularmap_pars_fragment>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
varying vec2 vUv;
void main() {
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <begin_vertex>
#include <morphtarget_vertex>
vUv = uv;
//gl_Position = vec4( transformed, 1.0 );
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
varying vec2 vUv;
uniform float thickness;
float edgeFactor(vec2 p){
vec2 grid = abs(fract(p - 0.5) - 0.5) / fwidth(p) / thickness;
return min(grid.x, grid.y);
}
void main() {
float a = edgeFactor(vUv);
vec3 c = mix(vec3(1), vec3(0), a);
gl_FragColor = vec4(c, 1.0);
}
</script>
<div id="container">
</div>
JS
import * as THREE from 'three';
import { OrbitControls } from 'OrbitControls';
class Heatmap {
constructor(){
console.log("Heatmap - constructor()");
//ThreeJS Variables
this.camera = null;
this.scene = null;
this.renderer = new THREE.WebGLRenderer({antialias: true});
this.orbital_controls = null;
this.ambientLight = null;
this.heatmap = new THREE.Object3D(); //This will hold all the meshes that make up the heatmap
//Animation Related Variables
this.clock = new THREE.Clock();
this.delta = 0;
this.fps = 60; //60 fps
this.interval = 1/this.fps;
this.seconds = 2; //seconds for animation
this.timeSoFar = 0;
this.targetTime = 3;
//Setup
this.scene = new THREE.Scene();
this.setUpCamera();
this.setUpRenderer();
this.setUpLighting();
this.setUpOrbitalControls();
//Add optional GridHelper for Debug
this.scene.add(new THREE.GridHelper());
//TODO: Create the heatmap here
this.createDataRectangle();
//Add the finished heatmap to the scene
this.scene.add(this.heatmap);
this.render();
this.animate();
}
setUpRenderer(){
console.log("Heatmap - setUpRenderer()");
let width = $('#container').width();
let height = $('#container').height();
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(width,height);
this.renderer.setClearColor(0x404040);
$("#container").html(this.renderer.domElement);
window.addEventListener("resize", event => {
this.camera.aspect = innerWidth / innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(innerWidth, innerHeight);
});
}
setUpCamera(){
console.log("Heatmap - setUpCamera()");
this.camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 100);
this.camera.position.z = 4;
}
setUpLighting(){
console.log("Heatmap - setUpLighting()");
this.ambientLight = new THREE.AmbientLight(0xffffff, 1);
this.scene.add(this.ambientLight);
}
setUpOrbitalControls(){
console.log("Heatmap - setUpOrbitalControls()");
this.orbital_controls = new OrbitControls( this.camera, this.renderer.domElement );
this.orbital_controls.target.set(0, 0, 0);
this.orbital_controls.enableDamping = true;
this.orbital_controls.dampingFactor = 0.025;
this.orbital_controls.maxPolarAngle = Math.PI/2.0;
this.orbital_controls.minDistance = 2.0;
this.orbital_controls.maxDistance = 80.0;
this.orbital_controls.update();
this.orbital_controls.addEventListener( 'change', function(){
if (this.target.y < 0){
this.target.y = 0;
/* camera.position.y = -1; */
} else if (this.target.y > 1){
this.target.y = 1;
/* camera.position.y = 1; */
}
});
}
createDataRectangle(){ //TODO: Make this create at a position specified
console.log("Heatmap - createDataRectangle()");
const geometry = new THREE.BufferGeometry();
const vertices = [
-2, 0, 1,//0, floor, bottom left
-1, 0, 1,//1, floor, bottom right
-1, 0, -1,//2, floor, top right
-2, 0, -1,//3 floor, top left
-2, 3, 1,//4 roof, bottom left
-1, 3, 1,//5 roof, bottom right
-1, 3, -1,//6 roof, top right
-2, 3, -1//7 roof, top left
];
const indices = [
0, 1, 2,//floor, first triangle
2, 3, 0,//floor, second triangle
4, 5, 6,//roof, first triangle
6, 7, 4,//roof, second triangle
3, 0, 4,//west wall, first triangle
3, 4, 7,//west wall, second triangle
0, 1, 5,//south wall, first triangle
0, 5, 4,//south wall, first triangle
1, 2, 6,//east wall, first triangle
1, 6, 5,//east wall, second triangle
2, 3, 7,//north wall, first triangle
2, 7, 6,//north wall, second triangle
];
const colors = [
2,0,0, // bottom left
0,2,0, // bottom right
0,2,0, // top right
2,0,0, // top left
2,0,0, // bottom left
0,2,0, // bottom right
0,2,0, // top right
2,0,0 // top left
];
geometry.setIndex(indices);
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
geometry.computeVertexNormals();
const material = new THREE.MeshStandardMaterial({side:THREE.FrontSide,vertexColors:true,color: 0xFFFFFF });
var shader_material = new THREE.ShaderMaterial( {
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
uniforms: {
thickness: {
value: 1.5
}
}
});
const sample_rectangle = new THREE.Mesh(geometry, shader_material);
this.heatmap.add(sample_rectangle);
//Demo showing that the same shader material works on a box geometry!
const geometryBox = new THREE.BoxGeometry();
const sample_box = new THREE.Mesh(geometryBox, shader_material);
sample_box.scale.y = 3;
this.heatmap.add(sample_box);
}
animate(){
requestAnimationFrame(() => {
this.animate()
});
this.orbital_controls.update();//Required for Damping on OrbitControls
this.delta += this.clock.getDelta();
if (this.delta > this.interval) {
//this.timeSoFar = this.timeSoFar + (1 * morphDirection);
this.render();
this.delta = this.delta % this.interval;
}
}
render(){
this.renderer.render(this.scene, this.camera);
}
}
$(document).ready(function(){
console.log("DOM ready!");
new Heatmap();
});
CSS
body,html{
margin: 0;
width: 100%;
height: 100%;
}
#container {
width: 100%;
height: 100%;
background-color: black;
margin: 0;
}