Three.js自定义着色器与纹理
我想写一个自定义着色器,它用three.js操作我的图像。 为此,我想创建一个与图像作为纹理的平面。之后我想移动顶点以扭曲图像。Three.js自定义着色器与纹理
(如果这是一个绝对错误的方式来做到这一点,请告诉我)。
首先我有我的着色器:
<script type="x-shader/x-vertex" id="vertexshader">
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
// Pass the texcoord to the fragment shader.
v_texCoord = a_texCoord;
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position,1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform sampler2D u_texture;
varying vec2 v_texCoord;
void main() {
vec4 color = texture2D(u_texture, v_texCoord);
gl_FragColor = color;
}
</script>
在哪里我真的不明白什么的Texture2D是干什么的,但我发现,在其他的代码片段。 我想要的是这个示例:只需使用“底层”图像(=纹理)中的颜色对顶点(gl_FracColor)进行着色即可。
在我的代码,我已经建立了正常的3个场景飞机:
// set some camera attributes
var VIEW_ANGLE = 45,
ASPECT = window.innerWidth/window.innerHeight,
NEAR = 0.1,
FAR = 1000;
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.set(0, 0, 15);
var vertShader = document.getElementById('vertexshader').innerHTML;
var fragShader = document.getElementById('fragmentshader').innerHTML;
var texloader = new THREE.TextureLoader();
var texture = texloader.load("img/color.jpeg");
var uniforms = {
u_texture: {type: 't', value: 0, texture: texture},
};
var attributes = {
a_texCoord: {type: 'v2', value: new THREE.Vector2()}
};
// create the final material
var shaderMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertShader,
fragmentShader: fragShader
});
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var plane = {
width: 5,
height: 5,
widthSegments: 10,
heightSegments: 15
}
var geometry = new THREE.PlaneBufferGeometry(plane.width, plane.height, plane.widthSegments, plane.heightSegments)
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var plane = new THREE.Mesh(geometry, shaderMaterial);
scene.add(plane);
plane.rotation.y += 0.2;
var render = function() {
requestAnimationFrame(render);
// plane.rotation.x += 0.1;
renderer.render(scene, camera);
};
render();
不幸的是,在运行该代码后,我只看到一个黑色窗口。虽然我知道如果在创建网格时使用material
作为材质,我可以清楚地看到它。 所以它必须是着色器材质或着色器。
问题:
- 我必须定义统一
u_texture
,在我的着色材料的制服和属性的属性a_texCoord
?并且做 他们必须有完全相同的名字? - 无论如何有多少个顶点?我会得到图像中每个像素的顶点吗?或者这架飞机的每个角落只有4个?
-
a_texCoord有什么价值?什么也没有发生,如果我写:
var attributes = { a_texCoord: {type: 'v2', value: new THREE.Vector2(1,1)} };
还是我必须使用一些映射(内置地图的东西从三个)?但是,我将如何改变顶点位置?
难道有人会对此事有所了解吗?
我把它通过改变这个工作:
var uniforms = {
u_texture: {type: 't', value: 0, texture: texture},
};
要这样:
var uniforms = {
u_texture: {type: 't', value: texture},
};
反正所有其他的问题仍然是开放和答案的高度赞赏。 (顺便说一句:为什么别人的降级)
我必须定义统一u_texture和属性a_texCoord在我的着色材料的制服和属性 ?他们是否有 具有完全相同的名称?
是的,是的。这些制服被定义为着色器材质的一部分,而属性在版本72中已经从着色器材质移动到BufferGeometry-class(我假设你使用的是最新版本,所以这里是你如何做到这一点今天):
var geometry = new THREE.PlaneBufferGeometry(...);
// first, create an array to hold the a_texCoord-values per vertex
var numVertices = (plane.widthSegments + 1) * (plane.heightSegments + 1);
var texCoordBuffer = new Float32Array(2 * numVertices);
// now register it as a new attribute (the 2 here indicates that there are
// two values per element (vec2))
geometry.addAttribute('a_texCoord', new THREE.BufferAttribute(texCoordBuffer, 2));
正如你看到的,属性将只如果有在你的shader代码指定的确切名称相同的工作。
我不确切知道你打算如何使用它,但它听起来很像你想要的uv坐标。如果是这样的话,如果你看看THREE.PlaneBufferGeometry
-class,你可以节省很多工作。它已经提供了一个名为uv
的属性,它可能正是您正在寻找的。所以,你只需要在你的shader代码更改属性名称
attribute vec2 uv;
反正有多少顶点有哪些?我会为图像中的每个 像素获取一个顶点吗?或者这架飞机的每个角落只有4个?
根据参数heightSegments
和widthSegments
创建顶点。所以如果你设置为5,那么将会有(5 + 1)*(5 + 1)= 36个顶点(+1,因为只有1个线段的线有两个顶点等)和5 * 5 * 2 = 50个三角形(有150个指数)。
另一件需要注意的是,PlaneBufferGeometry是一个索引几何。这意味着每个顶点(和其他每个属性值)只存储一次,尽管它被多个三角形使用。有一个特殊的索引属性,其中包含哪些顶点用于创建哪些三角形的信息。
a_texCoord有什么价值?如果我写:
我希望以上内容有助于回答这个问题。
还是我必须使用一些映射(内置三个地图的东西)?
我建议你使用uv
属性如上所述。但你绝对不需要。
但是,我将如何改变顶点位置?
至少有两种方法可以做到这一点:在顶点着色器或通过JavaScript。后者可以在这里看到:http://codepen.io/usefulthink/pen/vKzRKr?editors=1010 (更新几何的相关部分从第84行开始)。